Make static in packet.c: checksum(), raw_packet(), and kernel_packet().

Rename raw_packet() to send_dhcp_raw() and strip of unnecessary arguments.
Rename kernel_packet() to send_dhcp_cooked() and strip of unnecessary
arguments.
Remove the ugly bcast_raw_packet() wrapper hack.
This commit is contained in:
Nicholas J. Kain 2011-06-25 16:55:00 -04:00
parent 5b3aee93ab
commit f43b656673
2 changed files with 62 additions and 80 deletions

View File

@ -202,6 +202,32 @@ static int get_packet(struct dhcpMessage *packet, int fd)
return bytes; return bytes;
} }
// Compute Internet Checksum for @count bytes beginning at location @addr.
static uint16_t checksum(void *addr, int count)
{
register int32_t sum = 0;
uint16_t *source = (uint16_t *)addr;
while (count > 1) {
sum += *source++;
count -= 2;
}
/* Add left-over byte, if any */
if (count > 0) {
/* Make sure that the left-over byte is added correctly both
* with little and big endian hosts */
uint16_t tmp = 0;
*(uint8_t *)&tmp = *(uint8_t *)source;
sum += tmp;
}
/* Fold 32-bit sum to 16 bits */
while (sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
return ~sum;
}
// Read a packet from a raw socket. Returns -1 on fatal error, -2 on // Read a packet from a raw socket. Returns -1 on fatal error, -2 on
// transient error. // transient error.
static int get_raw_packet(struct dhcpMessage *payload, int fd) static int get_raw_packet(struct dhcpMessage *payload, int fd)
@ -271,63 +297,35 @@ static int get_raw_packet(struct dhcpMessage *payload, int fd)
return len - sizeof packet.ip - sizeof packet.udp; return len - sizeof packet.ip - sizeof packet.udp;
} }
/* Compute Internet Checksum for @count bytes beginning at location @addr. */ // Broadcast a DHCP message using a raw socket.
uint16_t checksum(void *addr, int count) static int send_dhcp_raw(struct dhcpMessage *payload)
{
register int32_t sum = 0;
uint16_t *source = (uint16_t *)addr;
while (count > 1) {
sum += *source++;
count -= 2;
}
/* Add left-over byte, if any */
if (count > 0) {
/* Make sure that the left-over byte is added correctly both
* with little and big endian hosts */
uint16_t tmp = 0;
*(uint8_t *)&tmp = *(uint8_t *)source;
sum += tmp;
}
/* Fold 32-bit sum to 16 bits */
while (sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
return ~sum;
}
/* Constuct a ip/udp header for a packet, and specify the source and dest
* hardware address */
int raw_packet(struct dhcpMessage *payload, uint32_t source_ip,
int source_port, uint32_t dest_ip, int dest_port,
uint8_t *dest_arp, int ifindex)
{ {
int fd, r = -1; int fd, r = -1;
if ((fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) { if ((fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
log_error("raw_packet: socket failed: %s", strerror(errno)); log_error("send_dhcp_raw: socket failed: %s", strerror(errno));
goto out; goto out;
} }
int opt = 1; int opt = 1;
if (setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &opt, sizeof opt) == -1) { if (setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &opt, sizeof opt) == -1) {
log_error("raw_packet: failed to set don't route: %s", log_error("send_dhcp_raw: failed to set don't route: %s",
strerror(errno)); strerror(errno));
goto out_fd; goto out_fd;
} }
if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) == -1) { if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) == -1) {
log_error("raw_packet: set non-blocking failed: %s", strerror(errno)); log_error("send_dhcp_raw: set non-blocking failed: %s",
strerror(errno));
goto out_fd; goto out_fd;
} }
struct sockaddr_ll dest = { struct sockaddr_ll dest = {
.sll_family = AF_PACKET, .sll_family = AF_PACKET,
.sll_protocol = htons(ETH_P_IP), .sll_protocol = htons(ETH_P_IP),
.sll_ifindex = ifindex, .sll_ifindex = client_config.ifindex,
.sll_halen = 6, .sll_halen = 6,
}; };
memcpy(dest.sll_addr, dest_arp, 6); memcpy(dest.sll_addr, "\xff\xff\xff\xff\xff\xff", 6);
if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) { if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) {
log_error("raw_packet: bind failed: %s", strerror(errno)); log_error("send_dhcp_raw: bind failed: %s", strerror(errno));
goto out_fd; goto out_fd;
} }
@ -339,15 +337,15 @@ int raw_packet(struct dhcpMessage *payload, uint32_t source_ip,
ssize_t endloc = get_end_option_idx(packet.data.options, ssize_t endloc = get_end_option_idx(packet.data.options,
DHCP_OPTIONS_BUFSIZE); DHCP_OPTIONS_BUFSIZE);
if (endloc == -1) { if (endloc == -1) {
log_error("raw_packet: attempt to send packet with no DHCP_END"); log_error("send_dhcp_raw: attempt to send packet with no DHCP_END");
goto out_fd; goto out_fd;
} }
unsigned int padding = DHCP_OPTIONS_BUFSIZE - 1 - endloc; unsigned int padding = DHCP_OPTIONS_BUFSIZE - 1 - endloc;
packet.ip.protocol = IPPROTO_UDP; packet.ip.protocol = IPPROTO_UDP;
packet.ip.saddr = source_ip; packet.ip.saddr = INADDR_ANY;
packet.ip.daddr = dest_ip; packet.ip.daddr = INADDR_BROADCAST;
packet.udp.source = htons(source_port); packet.udp.source = htons(DHCP_CLIENT_PORT);
packet.udp.dest = htons(dest_port); packet.udp.dest = htons(DHCP_SERVER_PORT);
packet.udp.len = htons(UPD_DHCP_SIZE - padding); packet.udp.len = htons(UPD_DHCP_SIZE - padding);
// UDP checksumming needs a temporary pseudoheader with a fake length. // UDP checksumming needs a temporary pseudoheader with a fake length.
packet.ip.tot_len = packet.udp.len; packet.ip.tot_len = packet.udp.len;
@ -362,32 +360,32 @@ int raw_packet(struct dhcpMessage *payload, uint32_t source_ip,
r = safe_sendto(fd, (const char *)&packet, IP_UPD_DHCP_SIZE - padding, r = safe_sendto(fd, (const char *)&packet, IP_UPD_DHCP_SIZE - padding,
0, (struct sockaddr *)&dest, sizeof dest); 0, (struct sockaddr *)&dest, sizeof dest);
if (r == -1) if (r == -1)
log_error("raw_packet: sendto failed: %s", strerror(errno)); log_error("send_dhcp_raw: sendto failed: %s", strerror(errno));
out_fd: out_fd:
close(fd); close(fd);
out: out:
return r; return r;
} }
/* Let the kernel do all the work for packet generation */ // Broadcast a DHCP message using a UDP socket.
int kernel_packet(struct dhcpMessage *payload, uint32_t source_ip, static int send_dhcp_cooked(struct dhcpMessage *payload, uint32_t source_ip,
int source_port, uint32_t dest_ip, int dest_port) uint32_t dest_ip)
{ {
int fd, result = -1; int fd, result = -1;
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
log_error("kernel_packet: socket failed: %s", strerror(errno)); log_error("send_dhcp_cooked: socket failed: %s", strerror(errno));
goto out; goto out;
} }
int opt = 1; int opt = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt) == -1) { if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt) == -1) {
log_error("kernel_packet: set reuse addr failed: %s", log_error("send_dhcp_cooked: set reuse addr failed: %s",
strerror(errno)); strerror(errno));
goto out_fd; goto out_fd;
} }
if (setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &opt, sizeof opt) == -1) { if (setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &opt, sizeof opt) == -1) {
log_error("kernel_packet: failed to set don't route: %s", log_error("send_dhcp_cooked: failed to set don't route: %s",
strerror(errno)); strerror(errno));
goto out_fd; goto out_fd;
} }
@ -395,46 +393,46 @@ int kernel_packet(struct dhcpMessage *payload, uint32_t source_ip,
memset(&ifr, 0, sizeof (struct ifreq)); memset(&ifr, 0, sizeof (struct ifreq));
strlcpy(ifr.ifr_name, client_config.interface, IFNAMSIZ); strlcpy(ifr.ifr_name, client_config.interface, IFNAMSIZ);
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof ifr) < 0) { if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof ifr) < 0) {
log_error("kernel_packet: set bind to device failed: %s", log_error("send_dhcp_cooked: set bind to device failed: %s",
strerror(errno)); strerror(errno));
goto out_fd; goto out_fd;
} }
if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) == -1) { if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) == -1) {
log_error("kernel_packet: set non-blocking failed: %s", log_error("send_dhcp_cooked: set non-blocking failed: %s",
strerror(errno)); strerror(errno));
goto out_fd; goto out_fd;
} }
struct sockaddr_in laddr = { struct sockaddr_in laddr = {
.sin_family = AF_INET, .sin_family = AF_INET,
.sin_port = htons(source_port), .sin_port = htons(DHCP_CLIENT_PORT),
.sin_addr.s_addr = source_ip, .sin_addr.s_addr = source_ip,
}; };
if (bind(fd, (struct sockaddr *)&laddr, sizeof(struct sockaddr)) == -1) { if (bind(fd, (struct sockaddr *)&laddr, sizeof(struct sockaddr)) == -1) {
log_error("kernel_packet: bind failed: %s", strerror(errno)); log_error("send_dhcp_cooked: bind failed: %s", strerror(errno));
goto out_fd; goto out_fd;
} }
struct sockaddr_in raddr = { struct sockaddr_in raddr = {
.sin_family = AF_INET, .sin_family = AF_INET,
.sin_port = htons(dest_port), .sin_port = htons(DHCP_SERVER_PORT),
.sin_addr.s_addr = dest_ip, .sin_addr.s_addr = dest_ip,
}; };
if (connect(fd, (struct sockaddr *)&raddr, sizeof(struct sockaddr)) == -1) { if (connect(fd, (struct sockaddr *)&raddr, sizeof(struct sockaddr)) == -1) {
log_error("kernel_packet: connect failed: %s", strerror(errno)); log_error("send_dhcp_cooked: connect failed: %s", strerror(errno));
goto out_fd; goto out_fd;
} }
ssize_t endloc = get_end_option_idx(payload->options, ssize_t endloc = get_end_option_idx(payload->options,
DHCP_OPTIONS_BUFSIZE); DHCP_OPTIONS_BUFSIZE);
if (endloc == -1) { if (endloc == -1) {
log_error("kernel_packet: attempt to send packet with no DHCP_END"); log_error("send_dhcp_cooked: attempt to send packet with no DHCP_END");
goto out_fd; goto out_fd;
} }
unsigned int padding = DHCP_OPTIONS_BUFSIZE - 1 - endloc; unsigned int padding = DHCP_OPTIONS_BUFSIZE - 1 - endloc;
result = safe_write(fd, (const char *)payload, DHCP_SIZE - padding); result = safe_write(fd, (const char *)payload, DHCP_SIZE - padding);
if (result == -1) if (result == -1)
log_error("kernel_packet: write failed: %s", strerror(errno)); log_error("send_dhcp_cooked: write failed: %s", strerror(errno));
out_fd: out_fd:
close(fd); close(fd);
out: out:
@ -660,15 +658,6 @@ static void init_packet(struct dhcpMessage *packet, char type)
(uint8_t *)&vendor_id); (uint8_t *)&vendor_id);
} }
#define MAC_BCAST_ADDR (uint8_t *)"\xff\xff\xff\xff\xff\xff"
/* Wrapper that broadcasts a raw dhcp packet on the bound interface. */
static int bcast_raw_packet(struct dhcpMessage *packet)
{
return raw_packet(packet, INADDR_ANY, DHCP_CLIENT_PORT, INADDR_BROADCAST,
DHCP_SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
}
#undef MAC_BCAST_ADDR
/* Broadcast a DHCP discover packet to the network, with an optionally /* Broadcast a DHCP discover packet to the network, with an optionally
* requested IP */ * requested IP */
int send_discover(uint32_t xid, uint32_t requested) int send_discover(uint32_t xid, uint32_t requested)
@ -686,7 +675,7 @@ int send_discover(uint32_t xid, uint32_t requested)
DHCP_MAX_SIZE, htons(576)); DHCP_MAX_SIZE, htons(576));
add_option_request_list(packet.options, DHCP_OPTIONS_BUFSIZE); add_option_request_list(packet.options, DHCP_OPTIONS_BUFSIZE);
log_line("Sending discover..."); log_line("Sending discover...");
return bcast_raw_packet(&packet); return send_dhcp_raw(&packet);
} }
/* Broadcasts a DHCP request message */ /* Broadcasts a DHCP request message */
@ -705,7 +694,7 @@ int send_selecting(uint32_t xid, uint32_t server, uint32_t requested)
add_option_request_list(packet.options, DHCP_OPTIONS_BUFSIZE); add_option_request_list(packet.options, DHCP_OPTIONS_BUFSIZE);
addr.s_addr = requested; addr.s_addr = requested;
log_line("Sending select for %s...", inet_ntoa(addr)); log_line("Sending select for %s...", inet_ntoa(addr));
return bcast_raw_packet(&packet); return send_dhcp_raw(&packet);
} }
/* Unicasts or broadcasts a DHCP renew message */ /* Unicasts or broadcasts a DHCP renew message */
@ -720,10 +709,9 @@ int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
add_option_request_list(packet.options, DHCP_OPTIONS_BUFSIZE); add_option_request_list(packet.options, DHCP_OPTIONS_BUFSIZE);
log_line("Sending renew..."); log_line("Sending renew...");
if (server) if (server)
return kernel_packet(&packet, ciaddr, DHCP_CLIENT_PORT, server, return send_dhcp_cooked(&packet, ciaddr, server);
DHCP_SERVER_PORT);
else else
return bcast_raw_packet(&packet); return send_dhcp_raw(&packet);
} }
/* Broadcast a DHCP decline message */ /* Broadcast a DHCP decline message */
@ -748,7 +736,7 @@ int send_decline(uint32_t xid, uint32_t server, uint32_t requested)
add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE, DHCP_SERVER_ID, server); add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE, DHCP_SERVER_ID, server);
log_line("Sending decline..."); log_line("Sending decline...");
return bcast_raw_packet(&packet); return send_dhcp_raw(&packet);
} }
/* Unicasts a DHCP release message */ /* Unicasts a DHCP release message */
@ -765,6 +753,6 @@ int send_release(uint32_t server, uint32_t ciaddr)
add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE, DHCP_SERVER_ID, server); add_u32_option(packet.options, DHCP_OPTIONS_BUFSIZE, DHCP_SERVER_ID, server);
log_line("Sending release..."); log_line("Sending release...");
return kernel_packet(&packet, ciaddr, DHCP_CLIENT_PORT, server, return send_dhcp_cooked(&packet, ciaddr, server);
DHCP_SERVER_PORT);
} }

View File

@ -81,12 +81,6 @@ enum {
DHCP_SIZE = sizeof(struct dhcpMessage), DHCP_SIZE = sizeof(struct dhcpMessage),
}; };
uint16_t checksum(void *addr, int count);
int raw_packet(struct dhcpMessage *payload, uint32_t source_ip,
int source_port, uint32_t dest_ip, int dest_port,
uint8_t *dest_arp, int ifindex);
int kernel_packet(struct dhcpMessage *payload, uint32_t source_ip,
int source_port, uint32_t dest_ip, int dest_port);
void change_listen_mode(struct client_state_t *cs, int new_mode); void change_listen_mode(struct client_state_t *cs, int new_mode);
void handle_packet(struct client_state_t *cs); void handle_packet(struct client_state_t *cs);
uint32_t random_xid(void); uint32_t random_xid(void);