Clean up the DHCP packet sending functions and make them more RFC-compliant.
Rename cs->requestedIP to cs->clientAddr. Move the IFS_* defines into netlink.c. Cosmetic cleanups.
This commit is contained in:
parent
a68c8cb64c
commit
38ad2399ed
@ -204,12 +204,12 @@ static void arp_failed(struct client_state_t *cs)
|
||||
{
|
||||
log_line("arp: Offered address is in use -- declining");
|
||||
arp_close_fd(cs);
|
||||
send_decline(cs->xid, cs->serverAddr, arp_dhcp_packet.yiaddr);
|
||||
send_decline(cs, arp_dhcp_packet.yiaddr);
|
||||
|
||||
if (cs->arpPrevState != DS_REQUESTING)
|
||||
ifchange(NULL, IFCHANGE_DECONFIG);
|
||||
cs->dhcpState = DS_SELECTING;
|
||||
cs->requestedIP = 0;
|
||||
cs->clientAddr = 0;
|
||||
cs->timeout = 0;
|
||||
cs->packetNum = 0;
|
||||
set_listen_raw(cs);
|
||||
@ -224,7 +224,7 @@ void arp_gw_failed(struct client_state_t *cs)
|
||||
cs->dhcpState = DS_SELECTING;
|
||||
cs->oldTimeout = 0;
|
||||
cs->timeout = 0;
|
||||
cs->requestedIP = 0;
|
||||
cs->clientAddr = 0;
|
||||
cs->packetNum = 0;
|
||||
set_listen_raw(cs);
|
||||
}
|
||||
@ -237,7 +237,7 @@ void arp_success(struct client_state_t *cs)
|
||||
struct in_addr temp_addr = {.s_addr = arp_dhcp_packet.yiaddr};
|
||||
log_line("arp: Lease of %s obtained, lease time %ld",
|
||||
inet_ntoa(temp_addr), cs->lease);
|
||||
cs->requestedIP = arp_dhcp_packet.yiaddr;
|
||||
cs->clientAddr = arp_dhcp_packet.yiaddr;
|
||||
cs->dhcpState = DS_BOUND;
|
||||
cs->init = 0;
|
||||
ifchange(&arp_dhcp_packet,
|
||||
|
@ -23,14 +23,6 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum {
|
||||
IFS_NONE = 0,
|
||||
IFS_UP,
|
||||
IFS_DOWN,
|
||||
IFS_SHUT,
|
||||
IFS_REMOVED
|
||||
};
|
||||
|
||||
struct client_state_t {
|
||||
unsigned long long leaseStartTime;
|
||||
int dhcpState;
|
||||
@ -40,7 +32,7 @@ struct client_state_t {
|
||||
int packetNum;
|
||||
int epollFd, signalFd, listenFd, arpFd, nlFd;
|
||||
int timeout, oldTimeout;
|
||||
uint32_t requestedIP, serverAddr, routerAddr;
|
||||
uint32_t clientAddr, serverAddr, routerAddr;
|
||||
uint32_t lease, renewTime, rebindTime, xid;
|
||||
int using_dhcp_bpf;
|
||||
uint8_t routerArp[6];
|
||||
|
@ -60,9 +60,6 @@
|
||||
#define VERSION "1.0"
|
||||
|
||||
struct client_state_t cs = {
|
||||
.dhcpState = DS_SELECTING,
|
||||
.arpPrevState = DS_SELECTING,
|
||||
.ifsPrevState = IFS_NONE,
|
||||
.init = 1,
|
||||
.epollFd = -1,
|
||||
.signalFd = -1,
|
||||
@ -75,8 +72,6 @@ struct client_state_t cs = {
|
||||
struct client_config_t client_config = {
|
||||
/* Default options. */
|
||||
.interface = "eth0",
|
||||
.clientid = NULL,
|
||||
.hostname = NULL,
|
||||
.arp = "\0\0\0\0\0\0",
|
||||
};
|
||||
|
||||
@ -252,7 +247,7 @@ int main(int argc, char **argv)
|
||||
client_config.quit_after_lease = 1;
|
||||
break;
|
||||
case 'r':
|
||||
cs.requestedIP = inet_addr(optarg);
|
||||
cs.clientAddr = inet_addr(optarg);
|
||||
break;
|
||||
case 'u':
|
||||
pwd = getpwnam(optarg);
|
||||
|
@ -42,6 +42,14 @@
|
||||
|
||||
#define NLMSG_RECVSIZE 8192
|
||||
|
||||
enum {
|
||||
IFS_NONE = 0,
|
||||
IFS_UP,
|
||||
IFS_DOWN,
|
||||
IFS_SHUT,
|
||||
IFS_REMOVED
|
||||
};
|
||||
|
||||
static unsigned int nl_seq;
|
||||
|
||||
/* internal callback handling */
|
||||
@ -115,7 +123,7 @@ static void takedown_if(struct client_state_t *cs)
|
||||
ifchange(NULL, IFCHANGE_DECONFIG);
|
||||
cs->dhcpState = DS_SELECTING;
|
||||
cs->timeout = 0;
|
||||
cs->requestedIP = 0;
|
||||
cs->clientAddr = 0;
|
||||
cs->packetNum = 0;
|
||||
set_listen_raw(cs);
|
||||
}
|
||||
|
@ -308,3 +308,14 @@ void add_option_request_list(struct dhcpmsg *packet)
|
||||
reqdata[1] = j - 2;
|
||||
add_option_string(packet, reqdata);
|
||||
}
|
||||
|
||||
void add_option_vendor_string(struct dhcpmsg *packet)
|
||||
{
|
||||
struct vendor {
|
||||
char vendor;
|
||||
char length;
|
||||
char str[sizeof "ndhc"];
|
||||
} vendor_id = { DHCP_VENDOR, sizeof "ndhc" - 1, "ndhc"};
|
||||
add_option_string(packet, (uint8_t *)&vendor_id);
|
||||
}
|
||||
|
||||
|
@ -92,5 +92,6 @@ ssize_t get_end_option_idx(struct dhcpmsg *packet);
|
||||
size_t add_option_string(struct dhcpmsg *packet, uint8_t *optstr);
|
||||
size_t add_u32_option(struct dhcpmsg *packet, uint8_t code, uint32_t data);
|
||||
void add_option_request_list(struct dhcpmsg *packet);
|
||||
void add_option_vendor_string(struct dhcpmsg *packet);
|
||||
|
||||
#endif
|
||||
|
@ -2,7 +2,6 @@
|
||||
* Time-stamp: <2011-06-11 11:15:09 njk>
|
||||
*
|
||||
* (c) 2004-2011 Nicholas J. Kain <njkain at gmail dot com>
|
||||
* (c) 2001 Russ Dill <Russ.Dill@asu.edu>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -32,7 +31,6 @@
|
||||
#include <features.h>
|
||||
#include <netpacket/packet.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <linux/filter.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
@ -353,7 +351,8 @@ static int create_raw_listen_socket(struct client_state_t *cs, int ifindex)
|
||||
// Verify that the UDP client and server ports match that of the
|
||||
// IANA-assigned DHCP ports.
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_IND, 0),
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (67 << 16) + 68, 1, 0),
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K,
|
||||
(DHCP_SERVER_PORT << 16) + DHCP_CLIENT_PORT, 1, 0),
|
||||
BPF_STMT(BPF_RET + BPF_K, 0),
|
||||
// Get the UDP length field and store it in X.
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_IND, 4),
|
||||
@ -489,7 +488,7 @@ static int validate_dhcp_packet(struct client_state_t *cs, int len,
|
||||
{
|
||||
ssize_t optlen;
|
||||
if (len < sizeof *packet - sizeof packet->options) {
|
||||
log_line("Packet is too short to contain magic cookie. Ignoring.");
|
||||
log_line("Packet is too short to contain magic cookie. Ignoring.");
|
||||
return 0;
|
||||
}
|
||||
if (ntohl(packet->cookie) != DHCP_MAGIC) {
|
||||
@ -502,7 +501,7 @@ static int validate_dhcp_packet(struct client_state_t *cs, int len,
|
||||
return 0;
|
||||
}
|
||||
if (!(*msg = get_option_data(packet, DHCP_MESSAGE_TYPE, &optlen))) {
|
||||
log_line("Packet does not specify a DHCP message type. Ignoring.");
|
||||
log_line("Packet does not specify a DHCP message type. Ignoring.");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@ -550,73 +549,77 @@ static struct dhcpmsg init_packet(char type, uint32_t xid)
|
||||
add_option_string(&packet, client_config.clientid);
|
||||
if (client_config.hostname)
|
||||
add_option_string(&packet, client_config.hostname);
|
||||
struct vendor {
|
||||
char vendor;
|
||||
char length;
|
||||
char str[sizeof "ndhc"];
|
||||
} vendor_id = { DHCP_VENDOR, sizeof "ndhc" - 1, "ndhc"};
|
||||
add_option_string(&packet, (uint8_t *)&vendor_id);
|
||||
return packet;
|
||||
}
|
||||
|
||||
// Broadcast a DHCP discover packet to the network, with an optionally
|
||||
// requested IP
|
||||
int send_discover(uint32_t xid, uint32_t requested)
|
||||
int send_discover(struct client_state_t *cs)
|
||||
{
|
||||
struct dhcpmsg packet = init_packet(DHCPDISCOVER, xid);
|
||||
if (requested)
|
||||
add_u32_option(&packet, DHCP_REQUESTED_IP, requested);
|
||||
// Request a RFC-specified max size to work around buggy servers.
|
||||
add_u32_option(&packet, DHCP_MAX_SIZE, htons(576));
|
||||
struct dhcpmsg packet = init_packet(DHCPDISCOVER, cs->xid);
|
||||
if (cs->clientAddr)
|
||||
add_u32_option(&packet, DHCP_REQUESTED_IP, cs->clientAddr);
|
||||
add_u32_option(&packet, DHCP_MAX_SIZE,
|
||||
htons(sizeof(struct ip_udp_dhcp_packet)));
|
||||
add_option_request_list(&packet);
|
||||
add_option_vendor_string(&packet);
|
||||
log_line("Sending discover...");
|
||||
return send_dhcp_raw(&packet);
|
||||
}
|
||||
|
||||
// Broadcasts a DHCP request message
|
||||
int send_selecting(uint32_t xid, uint32_t server, uint32_t requested)
|
||||
int send_selecting(struct client_state_t *cs)
|
||||
{
|
||||
struct dhcpmsg packet = init_packet(DHCPREQUEST, xid);
|
||||
add_u32_option(&packet, DHCP_REQUESTED_IP, requested);
|
||||
add_u32_option(&packet, DHCP_SERVER_ID, server);
|
||||
struct dhcpmsg packet = init_packet(DHCPREQUEST, cs->xid);
|
||||
add_u32_option(&packet, DHCP_REQUESTED_IP, cs->clientAddr);
|
||||
add_u32_option(&packet, DHCP_SERVER_ID, cs->serverAddr);
|
||||
add_u32_option(&packet, DHCP_MAX_SIZE,
|
||||
htons(sizeof(struct ip_udp_dhcp_packet)));
|
||||
add_option_request_list(&packet);
|
||||
add_option_vendor_string(&packet);
|
||||
log_line("Sending select for %s...",
|
||||
inet_ntoa((struct in_addr){.s_addr = requested}));
|
||||
inet_ntoa((struct in_addr){.s_addr = cs->clientAddr}));
|
||||
return send_dhcp_raw(&packet);
|
||||
}
|
||||
|
||||
// Unicasts or broadcasts a DHCP renew message
|
||||
int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
|
||||
int send_renew(struct client_state_t *cs)
|
||||
{
|
||||
struct dhcpmsg packet = init_packet(DHCPREQUEST, xid);
|
||||
packet.ciaddr = ciaddr;
|
||||
struct dhcpmsg packet = init_packet(DHCPREQUEST, cs->xid);
|
||||
packet.ciaddr = cs->clientAddr;
|
||||
add_u32_option(&packet, DHCP_MAX_SIZE,
|
||||
htons(sizeof(struct ip_udp_dhcp_packet)));
|
||||
add_option_request_list(&packet);
|
||||
add_option_vendor_string(&packet);
|
||||
log_line("Sending renew...");
|
||||
if (server)
|
||||
return send_dhcp_cooked(&packet, ciaddr, server);
|
||||
else
|
||||
return send_dhcp_raw(&packet);
|
||||
return send_dhcp_cooked(&packet, cs->clientAddr, cs->serverAddr);
|
||||
}
|
||||
|
||||
// Broadcast a DHCP decline message
|
||||
int send_decline(uint32_t xid, uint32_t server, uint32_t requested)
|
||||
int send_rebind(struct client_state_t *cs)
|
||||
{
|
||||
struct dhcpmsg packet = init_packet(DHCPDECLINE, xid);
|
||||
// DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP
|
||||
add_u32_option(&packet, DHCP_REQUESTED_IP, requested);
|
||||
struct dhcpmsg packet = init_packet(DHCPREQUEST, cs->xid);
|
||||
packet.ciaddr = cs->clientAddr;
|
||||
add_u32_option(&packet, DHCP_REQUESTED_IP, cs->clientAddr);
|
||||
add_u32_option(&packet, DHCP_MAX_SIZE,
|
||||
htons(sizeof(struct ip_udp_dhcp_packet)));
|
||||
add_option_request_list(&packet);
|
||||
add_option_vendor_string(&packet);
|
||||
log_line("Sending rebind...");
|
||||
return send_dhcp_raw(&packet);
|
||||
}
|
||||
|
||||
int send_decline(struct client_state_t *cs, uint32_t server)
|
||||
{
|
||||
struct dhcpmsg packet = init_packet(DHCPDECLINE, cs->xid);
|
||||
add_u32_option(&packet, DHCP_REQUESTED_IP, cs->clientAddr);
|
||||
add_u32_option(&packet, DHCP_SERVER_ID, server);
|
||||
log_line("Sending decline...");
|
||||
return send_dhcp_raw(&packet);
|
||||
}
|
||||
|
||||
// Unicasts a DHCP release message
|
||||
int send_release(uint32_t server, uint32_t ciaddr)
|
||||
int send_release(struct client_state_t *cs)
|
||||
{
|
||||
struct dhcpmsg packet = init_packet(DHCPRELEASE, libc_random_u32());
|
||||
packet.ciaddr = ciaddr;
|
||||
add_u32_option(&packet, DHCP_REQUESTED_IP, ciaddr);
|
||||
add_u32_option(&packet, DHCP_SERVER_ID, server);
|
||||
packet.ciaddr = cs->clientAddr;
|
||||
add_u32_option(&packet, DHCP_REQUESTED_IP, cs->clientAddr);
|
||||
add_u32_option(&packet, DHCP_SERVER_ID, cs->serverAddr);
|
||||
log_line("Sending release...");
|
||||
return send_dhcp_cooked(&packet, ciaddr, server);
|
||||
return send_dhcp_cooked(&packet, cs->clientAddr, cs->serverAddr);
|
||||
}
|
||||
|
||||
|
@ -79,10 +79,11 @@ void set_listen_raw(struct client_state_t *cs);
|
||||
void set_listen_cooked(struct client_state_t *cs);
|
||||
void set_listen_none(struct client_state_t *cs);
|
||||
void handle_packet(struct client_state_t *cs);
|
||||
int send_discover(uint32_t xid, uint32_t requested);
|
||||
int send_selecting(uint32_t xid, uint32_t server, uint32_t requested);
|
||||
int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr);
|
||||
int send_decline(uint32_t xid, uint32_t server, uint32_t requested);
|
||||
int send_release(uint32_t server, uint32_t ciaddr);
|
||||
int send_discover(struct client_state_t *cs);
|
||||
int send_selecting(struct client_state_t *cs);
|
||||
int send_renew(struct client_state_t *cs);
|
||||
int send_rebind(struct client_state_t *cs);
|
||||
int send_decline(struct client_state_t *cs, uint32_t server);
|
||||
int send_release(struct client_state_t *cs);
|
||||
|
||||
#endif
|
||||
|
20
ndhc/state.c
20
ndhc/state.c
@ -63,7 +63,7 @@ static int delay_timeout(int numpackets)
|
||||
static void requesting_timeout(struct client_state_t *cs)
|
||||
{
|
||||
if (cs->packetNum < 5) {
|
||||
send_selecting(cs->xid, cs->serverAddr, cs->requestedIP);
|
||||
send_selecting(cs);
|
||||
cs->timeout = delay_timeout(cs->packetNum);
|
||||
cs->packetNum++;
|
||||
} else {
|
||||
@ -107,7 +107,7 @@ static void renewing_timeout(struct client_state_t *cs)
|
||||
if (ct < rbt) {
|
||||
long long wt = (rbt - ct) / 2;
|
||||
if (wt >= 30000)
|
||||
send_renew(cs->xid, cs->serverAddr, cs->requestedIP);
|
||||
send_renew(cs);
|
||||
else
|
||||
wt = rbt - ct;
|
||||
cs->timeout = wt;
|
||||
@ -133,7 +133,7 @@ static void rebinding_timeout(struct client_state_t *cs)
|
||||
if (ct < elt) {
|
||||
long long wt = (elt - ct) / 2;
|
||||
if (wt >= 30000)
|
||||
send_renew(cs->xid, 0, cs->requestedIP);
|
||||
send_rebind(cs);
|
||||
else
|
||||
wt = elt - ct;
|
||||
cs->timeout = wt;
|
||||
@ -176,7 +176,7 @@ static void an_packet(struct client_state_t *cs, struct dhcpmsg *packet,
|
||||
ifchange(NULL, IFCHANGE_DECONFIG);
|
||||
cs->dhcpState = DS_SELECTING;
|
||||
cs->timeout = 30000;
|
||||
cs->requestedIP = 0;
|
||||
cs->clientAddr = 0;
|
||||
cs->packetNum = 0;
|
||||
set_listen_raw(cs);
|
||||
}
|
||||
@ -188,7 +188,7 @@ static void an_packet(struct client_state_t *cs, struct dhcpmsg *packet,
|
||||
ifchange(NULL, IFCHANGE_DECONFIG);
|
||||
cs->dhcpState = DS_SELECTING;
|
||||
cs->timeout = 3000;
|
||||
cs->requestedIP = 0;
|
||||
cs->clientAddr = 0;
|
||||
cs->packetNum = 0;
|
||||
set_listen_raw(cs);
|
||||
}
|
||||
@ -203,7 +203,7 @@ static void selecting_packet(struct client_state_t *cs, struct dhcpmsg *packet,
|
||||
if ((temp = get_option_data(packet, DHCP_SERVER_ID, &optlen))) {
|
||||
memcpy(&cs->serverAddr, temp, 4);
|
||||
cs->xid = packet->xid;
|
||||
cs->requestedIP = packet->yiaddr;
|
||||
cs->clientAddr = packet->yiaddr;
|
||||
cs->dhcpState = DS_REQUESTING;
|
||||
cs->timeout = 0;
|
||||
cs->packetNum = 0;
|
||||
@ -221,7 +221,7 @@ static void selecting_timeout(struct client_state_t *cs)
|
||||
{
|
||||
if (cs->packetNum == 0)
|
||||
cs->xid = libc_random_u32();
|
||||
send_discover(cs->xid, cs->requestedIP);
|
||||
send_discover(cs);
|
||||
cs->timeout = delay_timeout(cs->packetNum);
|
||||
cs->packetNum++;
|
||||
if (cs->init && cs->packetNum >= 2) {
|
||||
@ -245,9 +245,9 @@ static void anfrelease(struct client_state_t *cs)
|
||||
static void nfrelease(struct client_state_t *cs)
|
||||
{
|
||||
log_line("Unicasting a release of %s to %s.",
|
||||
inet_ntoa((struct in_addr){.s_addr=cs->requestedIP}),
|
||||
inet_ntoa((struct in_addr){.s_addr=cs->clientAddr}),
|
||||
inet_ntoa((struct in_addr){.s_addr=cs->serverAddr}));
|
||||
send_release(cs->serverAddr, cs->requestedIP);
|
||||
send_release(cs);
|
||||
ifchange(NULL, IFCHANGE_DECONFIG);
|
||||
frelease(cs);
|
||||
}
|
||||
@ -270,7 +270,7 @@ static void frenew(struct client_state_t *cs)
|
||||
arp_close_fd(cs);
|
||||
cs->dhcpState = DS_RENEWING;
|
||||
set_listen_cooked(cs);
|
||||
send_renew(cs->xid, cs->serverAddr, cs->requestedIP);
|
||||
send_renew(cs);
|
||||
break;
|
||||
case DS_ARP_CHECK:
|
||||
// Cancel arp ping in progress and treat as previous state.
|
||||
|
Loading…
Reference in New Issue
Block a user