diff --git a/ChangeLog b/ChangeLog index afbcda6e1..5fd0c7526 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2004-12-15 Dan Williams + + * Rework the DHCP code again to revert to sending full ethernet frames + rather then relying on the kernel to do the right thing with our + packets. + 2004-12-06 Dan Williams * dhcpcd/client.c diff --git a/dhcpcd/Makefile.am b/dhcpcd/Makefile.am index 4d44c8310..2d89513d0 100644 --- a/dhcpcd/Makefile.am +++ b/dhcpcd/Makefile.am @@ -15,7 +15,9 @@ libdhcpc_a_SOURCES= \ client.c \ client.h \ dhcpcd.c \ - dhcpcd.h + dhcpcd.h \ + udpipgen.c \ + udpipgen.h bin_PROGRAMS = dhcp_test dhcp_test_SOURCES = dhcp_test.c diff --git a/dhcpcd/arp.c b/dhcpcd/arp.c index d21783c1e..76248b09d 100644 --- a/dhcpcd/arp.c +++ b/dhcpcd/arp.c @@ -28,13 +28,6 @@ #include "client.h" #include "arp.h" -struct packed_ether_header -{ - u_int8_t ether_dhost[ETH_ALEN]; /* destination eth addr */ - u_int8_t ether_shost[ETH_ALEN]; /* source ether addr */ - u_int16_t ether_type; /* packet type ID field */ -} __attribute__((packed)); - typedef struct arpMessage { struct packed_ether_header ethhdr; diff --git a/dhcpcd/buildmsg.c b/dhcpcd/buildmsg.c index 7ccaa22e6..b343d0bfd 100644 --- a/dhcpcd/buildmsg.c +++ b/dhcpcd/buildmsg.c @@ -27,13 +27,20 @@ #include #include "client.h" #include "buildmsg.h" +#include "udpipgen.h" extern int DebugFlag; /*****************************************************************************/ -void fill_common_fields (dhcp_interface *iface, dhcpMessage *dhcp_msg, int bcast_resp) +void fill_common_fields (dhcp_interface *iface, udpipMessage *msg, unsigned char dhost_addr[6], int bcast_resp) { - int magic_cookie = htonl (MAGIC_COOKIE); + dhcpMessage *dhcp_msg = (dhcpMessage *)&(msg->udpipmsg[sizeof(udpiphdr)]); + int magic_cookie = htonl (MAGIC_COOKIE); + + /* build Ethernet header */ + memcpy (msg->ethhdr.ether_dhost, dhost_addr, ETH_ALEN); + memcpy (msg->ethhdr.ether_shost, iface->chaddr, ETH_ALEN); + msg->ethhdr.ether_type = htons (ETHERTYPE_IP); dhcp_msg->op = DHCP_BOOTREQUEST; dhcp_msg->htype = ARPHRD_ETHER; @@ -41,7 +48,7 @@ void fill_common_fields (dhcp_interface *iface, dhcpMessage *dhcp_msg, int bcast dhcp_msg->xid = iface->xid; dhcp_msg->secs = htons (10); - if ( bcast_resp && iface->client_options->do_broadcast_response ) + if (bcast_resp && iface->client_options->do_broadcast_response) dhcp_msg->flags = htons (BROADCAST_FLAG); memcpy (dhcp_msg->chaddr, iface->chaddr, ETH_ALEN); @@ -65,6 +72,9 @@ unsigned char *fill_host_and_class_id (dhcp_interface *iface, unsigned char *p) *p++ = iface->cls_id_len; memcpy (p, iface->cls_id, iface->cls_id_len); p += iface->cls_id_len; + + *p++ = dhcpClientIdentifier; + *p++ = iface->cli_id_len; memcpy (p, iface->cli_id, iface->cli_id_len); p += iface->cli_id_len; @@ -75,18 +85,13 @@ unsigned char *fill_host_and_class_id (dhcp_interface *iface, unsigned char *p) unsigned char *fill_param_request (unsigned char *p) { *p++ = dhcpParamRequest; - *p++ = 14; + *p++ = 9; *p++ = subnetMask; *p++ = routersOnSubnet; *p++ = dns; *p++ = hostName; *p++ = domainName; - *p++ = rootPath; - *p++ = defaultIPTTL; *p++ = broadcastAddr; - *p++ = performMaskDiscovery; - *p++ = performRouterDiscovery; - *p++ = staticRoute; *p++ = nisDomainName; *p++ = nisServers; *p++ = ntpServers; @@ -138,26 +143,15 @@ unsigned char *fill_message_type (unsigned char request, unsigned char *p) return p; } /*****************************************************************************/ -void construct_dest_address (struct sockaddr_in *dest_addr, unsigned int in_addr) +udpipMessage *build_dhcp_discover (dhcp_interface *iface, int *msg_len) { - if (!dest_addr) - return; - - memset (dest_addr, 0, sizeof (struct sockaddr_in)); - dest_addr->sin_family = AF_INET; - dest_addr->sin_port = htons (DHCP_SERVER_PORT); - memcpy (&dest_addr->sin_addr, &in_addr, sizeof (dest_addr->sin_addr)); -} -/*****************************************************************************/ -dhcpMessage *build_dhcp_discover (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr) -{ - dhcpMessage *dhcp_msg = calloc (1, sizeof (dhcpMessage)); + udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); + dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); register unsigned char *p = dhcp_msg->options + 4; unsigned int lease_time = htonl (iface->default_lease_time); + int dhcp_msg_len; - construct_dest_address (dest_addr, IP_BCAST_ADDR); - - fill_common_fields (iface, dhcp_msg, 1); + fill_common_fields (iface, udp_msg, MAC_BCAST_ADDR, 1); p = fill_message_type (DHCP_DISCOVER, p); if ( iface->ciaddr ) { @@ -169,20 +163,24 @@ dhcpMessage *build_dhcp_discover (dhcp_interface *iface, int *msg_len, struct so p = fill_lease_time (&lease_time, p); p = fill_param_request (p); p = fill_host_and_class_id (iface, p); - *p = endOption; + *p++ = endOption; - *msg_len = (char *)(++p) - (char *)dhcp_msg; - return (dhcp_msg); + /* build UDP/IP header */ + p++; + dhcp_msg_len = (char *)p - (char *)dhcp_msg; + udpipgen ((udpiphdr *)(udp_msg->udpipmsg), 0, INADDR_BROADCAST, &iface->ip_id, dhcp_msg_len); + *msg_len = (char *)p - (char *)udp_msg; + return (udp_msg); } /*****************************************************************************/ -dhcpMessage *build_dhcp_request (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr) +udpipMessage *build_dhcp_request (dhcp_interface *iface, int *msg_len) { - dhcpMessage *dhcp_msg = calloc (1, sizeof (dhcpMessage)); + udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); + dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); register unsigned char *p = dhcp_msg->options + 4; + int dhcp_msg_len; - construct_dest_address (dest_addr, IP_BCAST_ADDR); - - fill_common_fields (iface, dhcp_msg, 1); + fill_common_fields (iface, udp_msg, MAC_BCAST_ADDR, 1); p = fill_message_type (DHCP_REQUEST, p); p = fill_server_id (iface->dhcp_options.val[dhcpServerIdentifier], p); if ( iface->client_options->do_rfc1541 ) @@ -195,18 +193,22 @@ dhcpMessage *build_dhcp_request (dhcp_interface *iface, int *msg_len, struct soc p = fill_host_and_class_id (iface, p); *p = endOption; - *msg_len = (char *)(++p) - (char *)dhcp_msg; - return (dhcp_msg); + /* build UDP/IP header */ + p++; + dhcp_msg_len = (char *)p - (char *)dhcp_msg; + udpipgen ((udpiphdr *)(udp_msg->udpipmsg), 0, INADDR_BROADCAST, &iface->ip_id, dhcp_msg_len); + *msg_len = (char *)(p++) - (char *)udp_msg; + return udp_msg; } /*****************************************************************************/ -dhcpMessage *build_dhcp_renew (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr) +udpipMessage *build_dhcp_renew (dhcp_interface *iface, int *msg_len) { - dhcpMessage *dhcp_msg = calloc (1, sizeof (dhcpMessage)); + udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); + dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); register unsigned char *p = dhcp_msg->options + 4; + int dhcp_msg_len; - construct_dest_address (dest_addr, iface->siaddr); - - fill_common_fields (iface, dhcp_msg, 1); + fill_common_fields (iface, udp_msg, iface->shaddr, 1); dhcp_msg->ciaddr = iface->ciaddr; p = fill_message_type (DHCP_REQUEST, p); #if 0 @@ -217,18 +219,21 @@ dhcpMessage *build_dhcp_renew (dhcp_interface *iface, int *msg_len, struct socka p = fill_host_and_class_id (iface, p); *p = endOption; - *msg_len = (char *)(++p) - (char *)dhcp_msg; - return (dhcp_msg); + p++; + dhcp_msg_len = (char *)p - (char *)dhcp_msg; + udpipgen ((udpiphdr *)(udp_msg->udpipmsg), iface->ciaddr, iface->siaddr, &iface->ip_id, dhcp_msg_len); + *msg_len = (char *)(p++) - (char *)udp_msg; + return (udp_msg); } /*****************************************************************************/ -dhcpMessage *build_dhcp_rebind (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr) +udpipMessage *build_dhcp_rebind (dhcp_interface *iface, int *msg_len) { - dhcpMessage *dhcp_msg = calloc (1, sizeof (dhcpMessage)); + udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); + dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); register unsigned char *p = dhcp_msg->options + 4; + int dhcp_msg_len; - construct_dest_address (dest_addr, IP_BCAST_ADDR); - - fill_common_fields (iface, dhcp_msg, 1); + fill_common_fields (iface, udp_msg, MAC_BCAST_ADDR, 1); dhcp_msg->ciaddr = iface->ciaddr; p = fill_message_type (DHCP_REQUEST, p); if ( iface->dhcp_options.val[dhcpIPaddrLeaseTime] ) @@ -237,19 +242,23 @@ dhcpMessage *build_dhcp_rebind (dhcp_interface *iface, int *msg_len, struct sock p = fill_host_and_class_id (iface, p); *p = endOption; - *msg_len = (char *)(++p) - (char *)dhcp_msg; - return (dhcp_msg); + /* build UDP/IP header */ + p++; + dhcp_msg_len = (char *)p - (char *)dhcp_msg; + udpipgen ((udpiphdr *)(udp_msg->udpipmsg), iface->ciaddr, INADDR_BROADCAST, &iface->ip_id, dhcp_msg_len); + *msg_len = (char *)(p++) - (char *)udp_msg; + return udp_msg; } /*****************************************************************************/ -dhcpMessage *build_dhcp_reboot (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr) +udpipMessage *build_dhcp_reboot (dhcp_interface *iface, int *msg_len) { - dhcpMessage *dhcp_msg = calloc (1, sizeof (dhcpMessage)); + udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); + dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); register unsigned char *p = dhcp_msg->options + 4; unsigned int lease_time = htonl (iface->default_lease_time); + int dhcp_msg_len; - construct_dest_address (dest_addr, IP_BCAST_ADDR); - - fill_common_fields (iface, dhcp_msg, 1); + fill_common_fields (iface, udp_msg, MAC_BCAST_ADDR, 1); p = fill_message_type (DHCP_REQUEST, p); if ( iface->client_options->do_rfc1541 ) dhcp_msg->ciaddr = iface->ciaddr; @@ -260,18 +269,22 @@ dhcpMessage *build_dhcp_reboot (dhcp_interface *iface, int *msg_len, struct sock p = fill_host_and_class_id (iface, p); *p = endOption; - *msg_len = (char *)(++p) - (char *)dhcp_msg; - return (dhcp_msg); + /* build UDP/IP header */ + p++; + dhcp_msg_len = (char *)p - (char *)dhcp_msg; + udpipgen ((udpiphdr *)(udp_msg->udpipmsg), 0, INADDR_BROADCAST, &iface->ip_id, dhcp_msg_len); + *msg_len = (char *)(p++) - (char *)udp_msg; + return (udp_msg); } /*****************************************************************************/ -dhcpMessage *build_dhcp_release (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr) +udpipMessage *build_dhcp_release (dhcp_interface *iface, int *msg_len) { - dhcpMessage *dhcp_msg = calloc (1, sizeof (dhcpMessage)); + udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); + dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); register unsigned char *p = dhcp_msg->options + 4; + int dhcp_msg_len; - construct_dest_address (dest_addr, iface->siaddr); - - fill_common_fields (iface, dhcp_msg, 1); + fill_common_fields (iface, udp_msg, iface->shaddr, 1); dhcp_msg->ciaddr = iface->ciaddr; *p++ = dhcpMessageType; *p++ = 1; @@ -281,19 +294,23 @@ dhcpMessage *build_dhcp_release (dhcp_interface *iface, int *msg_len, struct soc p += iface->cli_id_len; *p = endOption; - *msg_len = (char *)(++p) - (char *)dhcp_msg; - return (dhcp_msg); + /* build UDP/IP header */ + p++; + dhcp_msg_len = (char *)p - (char *)dhcp_msg; + udpipgen ((udpiphdr *)(udp_msg->udpipmsg), iface->ciaddr, iface->siaddr, &iface->ip_id, dhcp_msg_len); + *msg_len = (char *)(p++) - (char *)udp_msg; + return (udp_msg); } /*****************************************************************************/ #ifdef ARPCHECK -dhcpMessage *build_dhcp_decline (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr) +udpipMessage *build_dhcp_decline (dhcp_interface *iface, int *msg_len) { - dhcpMessage *dhcp_msg = calloc (1, sizeof (dhcpMessage)); + udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); + dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); register unsigned char *p = dhcp_msg->options + 4; + int dhcp_msg_len; - construct_dest_address (dest_addr, iface->siaddr); - - fill_common_fields (iface, udp_msg, 1); + fill_common_fields (iface, udp_msg, iface->shaddr, 1); *p++ = dhcpMessageType; *p++ = 1; *p++ = DHCP_DECLINE; @@ -306,25 +323,33 @@ dhcpMessage *build_dhcp_decline (dhcp_interface *iface, int *msg_len, struct soc p += iface->cli_id_len; *p = endOption; - *msg_len = (char *)(++p) - (char *)dhcp_msg; - return (dhcp_msg); + /* build UDP/IP header */ + p++; + dhcp_msg_len = (char *)p - (char *)dhcp_msg; + udpipgen ((udpiphdr *)(udp_msg->udpipmsg), 0, iface->siaddr, &iface->ip_id, dhcp_msg_len); + *msg_len = (char *)(p++) - (char *)udp_msg; + return (udp_msg); } #endif /*****************************************************************************/ -dhcpMessage *build_dhcp_inform (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr) +udpipMessage *build_dhcp_inform (dhcp_interface *iface, int *msg_len) { - dhcpMessage *dhcp_msg = calloc (1, sizeof (dhcpMessage)); + udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); + dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); register unsigned char *p = dhcp_msg->options + 4; + int dhcp_msg_len; - construct_dest_address (dest_addr, IP_BCAST_ADDR); - - fill_common_fields (iface, dhcp_msg, 1); + fill_common_fields (iface, udp_msg, iface->shaddr, 1); dhcp_msg->ciaddr = iface->ciaddr; p = fill_message_type (DHCP_INFORM, p); p = fill_param_request (p); p = fill_host_and_class_id (iface, p); *p = endOption; - *msg_len = (char *)(++p) - (char *)dhcp_msg; - return (dhcp_msg); + /* build UDP/IP header */ + p++; + dhcp_msg_len = (char *)p - (char *)dhcp_msg; + udpipgen((udpiphdr *)(udp_msg->udpipmsg), 0, INADDR_BROADCAST, &iface->ip_id, dhcp_msg_len); + *msg_len = (char *)(p++) - (char *)udp_msg; + return (udp_msg); } diff --git a/dhcpcd/buildmsg.h b/dhcpcd/buildmsg.h index ea314452a..b5c1e884b 100644 --- a/dhcpcd/buildmsg.h +++ b/dhcpcd/buildmsg.h @@ -23,15 +23,17 @@ #ifndef BUILDMSG_H #define BUILDMSG_H -dhcpMessage *build_dhcp_discover (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr); -dhcpMessage *build_dhcp_request (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr); -dhcpMessage *build_dhcp_renew (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr); -dhcpMessage *build_dhcp_rebind (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr); -dhcpMessage *build_dhcp_reboot (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr); -dhcpMessage *build_dhcp_release (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr); +#include "client.h" + +udpipMessage *build_dhcp_discover (dhcp_interface *iface, int *msg_len); +udpipMessage *build_dhcp_request (dhcp_interface *iface, int *msg_len); +udpipMessage *build_dhcp_renew (dhcp_interface *iface, int *msg_len); +udpipMessage *build_dhcp_rebind (dhcp_interface *iface, int *msg_len); +udpipMessage *build_dhcp_reboot (dhcp_interface *iface, int *msg_len); +udpipMessage *build_dhcp_release (dhcp_interface *iface, int *msg_len); #ifdef ARPCHECK -dhcpMessage *build_dhcp_decline (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr); +udpipMessage *build_dhcp_decline (dhcp_interface *iface, int *msg_len); #endif -dhcpMessage *build_dhcp_inform (dhcp_interface *iface, int *msg_len, struct sockaddr_in *dest_addr); +udpipMessage *build_dhcp_inform (dhcp_interface *iface, int *msg_len); #endif diff --git a/dhcpcd/client.c b/dhcpcd/client.c index d8f7a2ccb..8868fe49a 100644 --- a/dhcpcd/client.c +++ b/dhcpcd/client.c @@ -46,6 +46,7 @@ #include "client.h" #include "buildmsg.h" #include "arp.h" +#include "udpipgen.h" int DebugFlag = 1; #define DEBUG @@ -282,6 +283,8 @@ void class_id_setup (dhcp_interface *iface, const char *g_cls_id) if (!iface) return; + memset (iface->cls_id, 0, DHCP_CLASS_ID_MAX_LEN); + if (g_cls_id) g_cls_id_len = strlen (g_cls_id); @@ -297,33 +300,34 @@ void class_id_setup (dhcp_interface *iface, const char *g_cls_id) syslog (LOG_ERR,"classIDsetup: uname: %m\n"); snprintf (iface->cls_id, DHCP_CLASS_ID_MAX_LEN, "%s %s %s", sname.sysname, sname.release, sname.machine); + iface->cls_id_len = strlen (iface->cls_id); } } /*****************************************************************************/ void client_id_setup (dhcp_interface *iface, const char *g_cli_id) { unsigned int g_cli_id_len = 0; - unsigned char *c = iface->cli_id; + char *c; if (!iface) return; + memset (iface->cli_id, 0, DHCP_CLIENT_ID_MAX_LEN); + c = iface->cli_id; + if (g_cli_id) g_cli_id_len = strlen (g_cli_id); - *c++ = dhcpClientIdentifier; if ( g_cli_id_len ) { - *c++ = g_cli_id_len + 1; /* 1 for the field below */ - *c++ = 0; /* type: string */ + *c++ = 0; /* type: string */ memcpy (c, g_cli_id, g_cli_id_len); - iface->cli_id_len = g_cli_id_len + 3; + iface->cli_id_len = g_cli_id_len + 1; } else { - *c++ = ETH_ALEN + 1; /* length: 6 (MAC Addr) + 1 (# field) */ *c++ = ARPHRD_ETHER; /* type: Ethernet address */ memcpy (c, iface->chaddr, ETH_ALEN); - iface->cli_id_len = ETH_ALEN + 3; + iface->cli_id_len = ETH_ALEN + 1; } } /*****************************************************************************/ @@ -438,9 +442,9 @@ int dhcp_handle_transaction (dhcp_interface *iface, unsigned int expected_reply_ int recv_sk = -1; struct sockaddr_in addr; int tries = 0; - int dhcp_send_len, err = RET_DHCP_TIMEOUT; - dhcpMessage *dhcp_send = NULL; + int err = RET_DHCP_TIMEOUT; struct timeval recv_timeout, overall_end, diff, current; + udpipMessage *udp_send = NULL; if (!dhcp_return) return RET_DHCP_ERROR; @@ -450,13 +454,6 @@ int dhcp_handle_transaction (dhcp_interface *iface, unsigned int expected_reply_ if (!pkt_recv) return RET_DHCP_ERROR; - /* Call the specific DHCP message building routine for this request */ - if (!(dhcp_send = build_dhcp_msg (iface, &dhcp_send_len, &addr))) - { - err = RET_DHCP_ERROR; - goto out; - } - recv_sk = socket (AF_PACKET, SOCK_DGRAM, ntohs (ETH_P_IP)); if (recv_sk < 0) { @@ -476,6 +473,7 @@ int dhcp_handle_transaction (dhcp_interface *iface, unsigned int expected_reply_ syslog (LOG_INFO, "DHCP: Starting request loop"); do { + udpipMessage *udp_msg_recv = NULL; struct iphdr *ip_hdr; struct udphdr *udp_hdr; char *tmp_ip; @@ -494,7 +492,19 @@ int dhcp_handle_transaction (dhcp_interface *iface, unsigned int expected_reply_ syslog (LOG_INFO, "DHCP: Sending request packet..."); do { - err = sendto (iface->sk, dhcp_send, dhcp_send_len, MSG_DONTWAIT, (struct sockaddr *)&addr, sizeof (struct sockaddr)); + int udp_send_len = 0; + struct sockaddr addr; + + /* Call the specific DHCP message building routine for this request */ + if (!(udp_send = build_dhcp_msg (iface, &udp_send_len))) + { + err = RET_DHCP_ERROR; + goto out; + } + + memset (&addr, 0, sizeof (struct sockaddr)); + memcpy (addr.sa_data, iface->iface, strlen (iface->iface)); + err = sendto (iface->sk, udp_send, udp_send_len, MSG_DONTWAIT, (struct sockaddr *)&addr, sizeof (struct sockaddr)); if (iface->cease || ((err == -1) && (errno != EAGAIN))) { syslog (LOG_INFO, "DHCP: error sending, cease = %d, err = %d, errno = %d", iface->cease, err, errno); @@ -657,7 +667,7 @@ int dhcp_handle_transaction (dhcp_interface *iface, unsigned int expected_reply_ } while (timeval_subtract (&diff, &overall_end, ¤t) == 0); out: - free (dhcp_send); + free (udp_send); if (err != RET_DHCP_SUCCESS) free (pkt_recv); if (recv_sk >= 0) @@ -868,16 +878,16 @@ int dhcp_rebind(dhcp_interface *iface) /*****************************************************************************/ int dhcp_release(dhcp_interface *iface) { - struct sockaddr_in addr; - socklen_t addr_len = sizeof (struct sockaddr_in); - int len; - dhcpMessage *msg; + udpipMessage *msg; + struct sockaddr addr; + socklen_t addr_len = sizeof (struct sockaddr); + int len; if ( iface->ciaddr == 0 ) return RET_DHCP_ERROR; iface->xid = random(); - if (!(msg = build_dhcp_release (iface, &len, &addr))) + if (!(msg = build_dhcp_release (iface, &len))) return RET_DHCP_ERROR; if (DebugFlag) @@ -889,7 +899,9 @@ int dhcp_release(dhcp_interface *iface) ((unsigned char *)&(iface->siaddr))[2], ((unsigned char *)&(iface->siaddr))[3]); } - if (sendto (iface->sk, msg, sizeof (dhcpMessage), 0, (struct sockaddr *)&addr, addr_len)) + memset (&addr, 0, sizeof (struct sockaddr)); + memcpy (addr.sa_data, iface->iface, strlen (iface->iface)); + if (sendto (iface->sk, msg, len, 0, (struct sockaddr *)&addr, addr_len)) syslog (LOG_ERR, "dhcpRelease: sendto: %m\n"); free (msg); @@ -902,19 +914,21 @@ int dhcp_release(dhcp_interface *iface) #ifdef ARPCHECK int dhcp_decline(dhcp_interface *iface) { - struct sockaddr_in addr; - socklen_t addr_len = sizeof (struct sockaddr_in); - int len; - dhcpMessage *msg; + udpipMessage *msg; + struct sockaddr addr; + socklen_t addr_len = sizeof (struct sockaddr); + int len; iface->xid = random (); - if (!(msg = build_dhcp_decline (iface, &len, &addr))) + if (!(msg = build_dhcp_decline (iface, &len))) return RET_DHCP_ERROR; if (DebugFlag) syslog (LOG_INFO, "Broadcasting DHCP_DECLINE\n"); - if (sendto (iface->sk, msg, sizeof (dhcpMessage), 0, &addr, addr_len)) + memset (&addr, 0, sizeof (struct sockaddr)); + memcpy (addr.sa_data, iface->iface, strlen (iface->iface)); + if (sendto (iface->sk, msg, len, 0, &addr, addr_len)) syslog (LOG_ERR,"dhcpDecline: sendto: %m\n"); free (msg); diff --git a/dhcpcd/client.h b/dhcpcd/client.h index f2f17baac..d96964324 100644 --- a/dhcpcd/client.h +++ b/dhcpcd/client.h @@ -88,6 +88,21 @@ typedef struct dhcpOptions void *val[256]; } __attribute__((packed)) dhcpOptions; +struct packed_ether_header +{ + u_int8_t ether_dhost[ETH_ALEN]; /* destination eth addr */ + u_int8_t ether_shost[ETH_ALEN]; /* source ether addr */ + u_int16_t ether_type; /* packet type ID field */ +} __attribute__((packed)); + +#define TOKEN_RING_HEADER_PAD sizeof(struct trh_hdr) + sizeof(struct trllc) +typedef struct udpipMessage +{ + struct packed_ether_header ethhdr; + char udpipmsg[IPPACKET_SIZE]; + char pad_for_tokenring_header[TOKEN_RING_HEADER_PAD]; +} __attribute__((packed)) udpipMessage; + typedef struct dhcp_interface { @@ -105,6 +120,7 @@ typedef struct dhcp_interface int siaddr; unsigned char shaddr[ETH_ALEN]; unsigned int xid; + unsigned short ip_id; unsigned char cls_id[DHCP_CLASS_ID_MAX_LEN]; int cls_id_len; unsigned char cli_id[DHCP_CLIENT_ID_MAX_LEN]; @@ -186,7 +202,7 @@ static dhcp_option_table dhcp_opt_table[] = { -1, NULL, -1 } }; -typedef dhcpMessage *(*dhcp_msg_build_proc)(dhcp_interface *, int *msg_len, struct sockaddr_in *dest_addr); +typedef udpipMessage *(*dhcp_msg_build_proc)(dhcp_interface *, int *msg_len); int dhcp_reboot(dhcp_interface *iface); int dhcp_init(dhcp_interface *iface); diff --git a/dhcpcd/dhcpcd.c b/dhcpcd/dhcpcd.c index afd9f8f54..ec47718bb 100644 --- a/dhcpcd/dhcpcd.c +++ b/dhcpcd/dhcpcd.c @@ -60,7 +60,6 @@ dhcp_interface *dhcp_interface_init (const char *if_name, dhcp_client_options *i dhcp_interface *iface = NULL; dhcp_client_options *opts = NULL; struct rtentry route; - struct sockaddr_in *addrp; if (!if_name || !in_opts) return NULL; @@ -78,12 +77,9 @@ dhcp_interface *dhcp_interface_init (const char *if_name, dhcp_client_options *i memcpy (opts, in_opts, sizeof (dhcp_client_options)); iface->client_options = opts; - class_id_setup (iface, iface->client_options->class_id); - client_id_setup (iface, iface->client_options->client_id); - memset (&ifr, 0, sizeof(struct ifreq)); memcpy (ifr.ifr_name, iface->iface, strlen (iface->iface)); - iface->sk = socket (AF_INET, SOCK_DGRAM, 0); + iface->sk = socket (AF_PACKET, SOCK_PACKET, htons(ETH_P_ALL)); if (iface->sk == -1) { syslog (LOG_ERR,"dhcp_interface_init: socket: %m\n"); @@ -103,6 +99,9 @@ dhcp_interface *dhcp_interface_init (const char *if_name, dhcp_client_options *i */ do { + struct sockaddr_pkt sap; + struct sockaddr_in *addrp; + if ( ioctl (iface->sk, SIOCGIFHWADDR, &ifr) ) { syslog(LOG_ERR,"dhcp_interface_init: ioctl SIOCGIFHWADDR: %m\n"); @@ -148,10 +147,11 @@ dhcp_interface *dhcp_interface_init (const char *if_name, dhcp_client_options *i syslog (LOG_ERR, "dhcp_interface_init: SO_BINDTODEVICE %s (%d) failed: %s", iface->iface, strlen (iface->iface), strerror (errno)); } - memset (&addr, 0, sizeof (addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons (DHCP_CLIENT_PORT); - if (bind (iface->sk, (struct sockaddr *)&addr, sizeof(addr)) != 0) + memset (&sap, 0, sizeof(sap)); + sap.spkt_protocol = htons (ETH_P_ALL); + memcpy (sap.spkt_device, iface->iface, strlen (iface->iface)); + sap.spkt_family = AF_PACKET; + if ( bind (iface->sk, (void*)&sap, sizeof(struct sockaddr)) == -1 ) syslog (LOG_ERR,"dhcp_interface_init: bind: %m\n"); if (ioctl (iface->sk, SIOCGIFHWADDR, &ifr)) @@ -175,6 +175,9 @@ dhcp_interface *dhcp_interface_init (const char *if_name, dhcp_client_options *i if (setsockopt (iface->foo_sk, SOL_SOCKET, SO_BROADCAST, &o, sizeof(o))) syslog (LOG_ERR,"dhcp_interface_init: setsockopt: %m\n"); + memset (&addr, 0, sizeof (addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons (DHCP_CLIENT_PORT); if ( bind (iface->foo_sk, (struct sockaddr *)&addr, sizeof(addr)) ) { if (errno != EADDRINUSE) @@ -210,6 +213,14 @@ dhcp_interface *dhcp_interface_init (const char *if_name, dhcp_client_options *i goto err_out; } + i = time (NULL) + iface->chaddr[5] + 4*iface->chaddr[4] + 8*iface->chaddr[3] + + 16*iface->chaddr[2] + 32*iface->chaddr[1] + 64*iface->chaddr[0]; + srandom (i); + iface->ip_id = i & 0xffff; + + class_id_setup (iface, iface->client_options->class_id); + client_id_setup (iface, iface->client_options->client_id); + return iface; err_out: diff --git a/dhcpcd/udpipgen.c b/dhcpcd/udpipgen.c new file mode 100644 index 000000000..7101d751f --- /dev/null +++ b/dhcpcd/udpipgen.c @@ -0,0 +1,119 @@ +/* + * dhcpcd - DHCP client daemon - + * Copyright (C) January, 1998 Sergei Viznyuk + * + * dhcpcd is an RFC2131 and RFC1541 compliant DHCP client daemon. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "udpipgen.h" +#include "client.h" + +/*****************************************************************************/ +unsigned short in_cksum(unsigned short *addr, int len) +{ + register int sum = 0; + register u_short *w = addr; + register int nleft = len; + while ( nleft > 1 ) + { + sum += *w++; + nleft -= 2; + } + if ( nleft == 1 ) + { + u_char a = 0; + memcpy(&a,w,1); + sum += a; + } + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + return ~sum; +} +/*****************************************************************************/ +void udpipgen (udpiphdr *udpip, unsigned int saddr, unsigned int daddr, unsigned short *ip_id, int dhcp_msg_len) +{ + /* Use local copy because udpip->ip is not aligned. */ + struct ip ip_local; + struct ip *ip = &ip_local; + struct ipovly *io = (struct ipovly *)udpip->ip; + struct udphdr *udp = (struct udphdr *)udpip->udp; + + io->ih_next = io->ih_prev = 0; + io->ih_x1 = 0; + io->ih_pr = IPPROTO_UDP; + io->ih_len = htons (dhcp_msg_len + sizeof (struct udphdr)); + io->ih_src.s_addr = saddr; + io->ih_dst.s_addr = daddr; + udp->source = htons (DHCP_CLIENT_PORT); + udp->dest = htons (DHCP_SERVER_PORT); + udp->len = io->ih_len; + udp->check = 0; + udp->check = in_cksum ((unsigned short *)udpip, dhcp_msg_len + sizeof (udpiphdr)); + if (udp->check == 0) + udp->check = 0xffff; + memcpy (ip,(struct ip *)udpip->ip, sizeof (ip_local)); + ip->ip_hl = 5; + ip->ip_v = IPVERSION; + ip->ip_tos = 0; /* normal service */ + ip->ip_len = htons (dhcp_msg_len + sizeof (udpiphdr)); + ip->ip_id = htons (*ip_id); *ip_id++; + ip->ip_off = 0; + ip->ip_ttl = IPDEFTTL; /* time to live, 64 by default */ + ip->ip_p = IPPROTO_UDP; + ip->ip_src.s_addr = saddr; + ip->ip_dst.s_addr = daddr; + ip->ip_sum = 0; + memcpy (udpip->ip, ip, sizeof (ip_local)); + ip->ip_sum = in_cksum ((unsigned short *)&ip_local, sizeof (struct ip)); + memcpy (udpip->ip, ip, sizeof (ip_local)); +} +/*****************************************************************************/ +int udpipchk(udpiphdr *udpip) +{ + int hl; + struct ip save_ip; + struct ip *ip = (struct ip *)udpip->ip; + struct ipovly *io = (struct ipovly *)udpip->ip; + struct udphdr *udp = (struct udphdr *)udpip->udp; + udpiphdr *nudpip = udpip; + + hl = ip->ip_hl<<2; + if (in_cksum ((unsigned short *)udpip, hl)) + return -1; + memcpy (&save_ip, udpip->ip, sizeof (struct ip)); + hl -= sizeof (struct ip); + if (hl) + { + /* thrash IP options */ + nudpip = (udpiphdr *)((char *)udpip + hl); + memmove ((char *)nudpip, udpip, sizeof (struct ip)); + io = (struct ipovly *)nudpip->ip; + ip = (struct ip *)nudpip->ip; + udp = (struct udphdr *)nudpip->udp; + } + if (udp->check == 0) + return 0; /* no checksum has been done by sender */ + io->ih_next = io->ih_prev = 0; + io->ih_x1 = 0; + io->ih_len = udp->len; + hl = ntohs (udp->len) + sizeof (struct ip); + if (in_cksum ((unsigned short *)nudpip, hl)) + return -2; + memcpy (udpip->ip, &save_ip, sizeof(struct ip)); + return 0; +} diff --git a/dhcpcd/udpipgen.h b/dhcpcd/udpipgen.h new file mode 100644 index 000000000..9f6210046 --- /dev/null +++ b/dhcpcd/udpipgen.h @@ -0,0 +1,51 @@ +/* + * dhcpcd - DHCP client daemon - + * Copyright (C) January, 1998 Sergei Viznyuk + * + * dhcpcd is an RFC2131 and RFC1541 compliant DHCP client daemon. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef UDPIPGEN_H +#define UDPIPGEN_H + +#include +#include + +#ifndef IPDEFTTL +#define IPDEFTTL 64 +#endif + +struct ipovly +{ + int ih_next,ih_prev; + u_char ih_x1; + u_char ih_pr; + u_short ih_len; + struct in_addr ih_src; + struct in_addr ih_dst; +} __attribute__((packed)); + +typedef struct udpiphdr +{ + char ip[sizeof(struct ip)]; + char udp[sizeof(struct udphdr)]; +} __attribute__((packed)) udpiphdr; + +void udpipgen (udpiphdr *udpip, unsigned int saddr, unsigned int daddr, unsigned short *ip_id, int dhcp_msg_len); +int udpipchk (udpiphdr *udpip); + +#endif