aboutsummaryrefslogtreecommitdiff
path: root/networking/udhcp/dhcpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'networking/udhcp/dhcpc.c')
-rw-r--r--networking/udhcp/dhcpc.c121
1 files changed, 73 insertions, 48 deletions
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 8dee916d9..7dfc160e2 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -976,56 +976,13 @@ static int udhcp_raw_socket(int ifindex)
976 int fd; 976 int fd;
977 struct sockaddr_ll sock; 977 struct sockaddr_ll sock;
978 978
979 /*
980 * Comment:
981 *
982 * I've selected not to see LL header, so BPF doesn't see it, too.
983 * The filter may also pass non-IP and non-ARP packets, but we do
984 * a more complete check when receiving the message in userspace.
985 *
986 * and filter shamelessly stolen from:
987 *
988 * http://www.flamewarmaster.de/software/dhcpclient/
989 *
990 * There are a few other interesting ideas on that page (look under
991 * "Motivation"). Use of netlink events is most interesting. Think
992 * of various network servers listening for events and reconfiguring.
993 * That would obsolete sending HUP signals and/or make use of restarts.
994 *
995 * Copyright: 2006, 2007 Stefan Rompf <sux@loplof.de>.
996 * License: GPL v2.
997 *
998 * TODO: make conditional?
999 */
1000 static const struct sock_filter filter_instr[] = {
1001 /* load 9th byte (protocol) */
1002 BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
1003 /* jump to L1 if it is IPPROTO_UDP, else to L4 */
1004 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6),
1005 /* L1: load halfword from offset 6 (flags and frag offset) */
1006 BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6),
1007 /* jump to L4 if any bits in frag offset field are set, else to L2 */
1008 BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0),
1009 /* L2: skip IP header (load index reg with header len) */
1010 BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0),
1011 /* load udp destination port from halfword[header_len + 2] */
1012 BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2),
1013 /* jump to L3 if udp dport is CLIENT_PORT, else to L4 */
1014 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1),
1015 /* L3: accept packet */
1016 BPF_STMT(BPF_RET|BPF_K, 0xffffffff),
1017 /* L4: discard packet */
1018 BPF_STMT(BPF_RET|BPF_K, 0),
1019 };
1020 static const struct sock_fprog filter_prog = {
1021 .len = sizeof(filter_instr) / sizeof(filter_instr[0]),
1022 /* casting const away: */
1023 .filter = (struct sock_filter *) filter_instr,
1024 };
1025
1026 log1("Opening raw socket on ifindex %d", ifindex); //log2? 979 log1("Opening raw socket on ifindex %d", ifindex); //log2?
1027 980
1028 fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); 981 fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
982 /* ^^^^^
983 * SOCK_DGRAM: remove link-layer headers on input (SOCK_RAW keeps them)
984 * ETH_P_IP: want to receive only packets with IPv4 eth type
985 */
1029 log1("Got raw socket fd"); //log2? 986 log1("Got raw socket fd"); //log2?
1030 987
1031 sock.sll_family = AF_PACKET; 988 sock.sll_family = AF_PACKET;
@@ -1033,13 +990,58 @@ static int udhcp_raw_socket(int ifindex)
1033 sock.sll_ifindex = ifindex; 990 sock.sll_ifindex = ifindex;
1034 xbind(fd, (struct sockaddr *) &sock, sizeof(sock)); 991 xbind(fd, (struct sockaddr *) &sock, sizeof(sock));
1035 992
993#if 0 /* Several users reported breakage when BPF filter is used */
1036 if (CLIENT_PORT == 68) { 994 if (CLIENT_PORT == 68) {
1037 /* Use only if standard port is in use */ 995 /* Use only if standard port is in use */
996 /*
997 * I've selected not to see LL header, so BPF doesn't see it, too.
998 * The filter may also pass non-IP and non-ARP packets, but we do
999 * a more complete check when receiving the message in userspace.
1000 *
1001 * and filter shamelessly stolen from:
1002 *
1003 * http://www.flamewarmaster.de/software/dhcpclient/
1004 *
1005 * There are a few other interesting ideas on that page (look under
1006 * "Motivation"). Use of netlink events is most interesting. Think
1007 * of various network servers listening for events and reconfiguring.
1008 * That would obsolete sending HUP signals and/or make use of restarts.
1009 *
1010 * Copyright: 2006, 2007 Stefan Rompf <sux@loplof.de>.
1011 * License: GPL v2.
1012 */
1013 static const struct sock_filter filter_instr[] = {
1014 /* load 9th byte (protocol) */
1015 BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
1016 /* jump to L1 if it is IPPROTO_UDP, else to L4 */
1017 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6),
1018 /* L1: load halfword from offset 6 (flags and frag offset) */
1019 BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6),
1020 /* jump to L4 if any bits in frag offset field are set, else to L2 */
1021 BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0),
1022 /* L2: skip IP header (load index reg with header len) */
1023 BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0),
1024 /* load udp destination port from halfword[header_len + 2] */
1025 BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2),
1026 /* jump to L3 if udp dport is CLIENT_PORT, else to L4 */
1027 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1),
1028 /* L3: accept packet ("accept 0x7fffffff bytes") */
1029 /* Accepting 0xffffffff works too but kernel 2.6.19 is buggy */
1030 BPF_STMT(BPF_RET|BPF_K, 0x7fffffff),
1031 /* L4: discard packet ("accept zero bytes") */
1032 BPF_STMT(BPF_RET|BPF_K, 0),
1033 };
1034 static const struct sock_fprog filter_prog = {
1035 .len = sizeof(filter_instr) / sizeof(filter_instr[0]),
1036 /* casting const away: */
1037 .filter = (struct sock_filter *) filter_instr,
1038 };
1038 /* Ignoring error (kernel may lack support for this) */ 1039 /* Ignoring error (kernel may lack support for this) */
1039 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, 1040 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog,
1040 sizeof(filter_prog)) >= 0) 1041 sizeof(filter_prog)) >= 0)
1041 log1("Attached filter to raw socket fd"); // log? 1042 log1("Attached filter to raw socket fd"); // log?
1042 } 1043 }
1044#endif
1043 1045
1044 if (setsockopt(fd, SOL_PACKET, PACKET_AUXDATA, 1046 if (setsockopt(fd, SOL_PACKET, PACKET_AUXDATA,
1045 &const_int_1, sizeof(int)) < 0 1047 &const_int_1, sizeof(int)) < 0
@@ -1230,7 +1232,7 @@ static void client_background(void)
1230int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1232int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1231int udhcpc_main(int argc UNUSED_PARAM, char **argv) 1233int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1232{ 1234{
1233 uint8_t *temp, *message; 1235 uint8_t *message;
1234 const char *str_V, *str_h, *str_F, *str_r; 1236 const char *str_V, *str_h, *str_F, *str_r;
1235 IF_FEATURE_UDHCP_PORT(char *str_P;) 1237 IF_FEATURE_UDHCP_PORT(char *str_P;)
1236 void *clientid_mac_ptr; 1238 void *clientid_mac_ptr;
@@ -1638,6 +1640,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1638 case INIT_SELECTING: 1640 case INIT_SELECTING:
1639 /* Must be a DHCPOFFER */ 1641 /* Must be a DHCPOFFER */
1640 if (*message == DHCPOFFER) { 1642 if (*message == DHCPOFFER) {
1643 uint8_t *temp;
1644
1641/* What exactly is server's IP? There are several values. 1645/* What exactly is server's IP? There are several values.
1642 * Example DHCP offer captured with tchdump: 1646 * Example DHCP offer captured with tchdump:
1643 * 1647 *
@@ -1687,6 +1691,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1687 if (*message == DHCPACK) { 1691 if (*message == DHCPACK) {
1688 uint32_t lease_seconds; 1692 uint32_t lease_seconds;
1689 struct in_addr temp_addr; 1693 struct in_addr temp_addr;
1694 uint8_t *temp;
1690 1695
1691 temp = udhcp_get_option(&packet, DHCP_LEASE_TIME); 1696 temp = udhcp_get_option(&packet, DHCP_LEASE_TIME);
1692 if (!temp) { 1697 if (!temp) {
@@ -1764,6 +1769,26 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1764 continue; /* back to main loop */ 1769 continue; /* back to main loop */
1765 } 1770 }
1766 if (*message == DHCPNAK) { 1771 if (*message == DHCPNAK) {
1772 /* If network has more than one DHCP server,
1773 * "wrong" server can reply first, with a NAK.
1774 * Do not interpret it as a NAK from "our" server.
1775 */
1776 if (server_addr != 0) {
1777 uint32_t svid;
1778 uint8_t *temp;
1779
1780 temp = udhcp_get_option(&packet, DHCP_SERVER_ID);
1781 if (!temp) {
1782 non_matching_svid:
1783 log1("%s with wrong server ID, ignoring packet",
1784 "Received DHCP NAK"
1785 );
1786 continue;
1787 }
1788 move_from_unaligned32(svid, temp);
1789 if (svid != server_addr)
1790 goto non_matching_svid;
1791 }
1767 /* return to init state */ 1792 /* return to init state */
1768 bb_info_msg("Received DHCP NAK"); 1793 bb_info_msg("Received DHCP NAK");
1769 udhcp_run_script(&packet, "nak"); 1794 udhcp_run_script(&packet, "nak");