Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/networking/udhcp
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- Location:
- branches/2.2.9/mindi-busybox/networking/udhcp
- Files:
-
- 2 added
- 18 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/networking/udhcp/Config.in
r1765 r2725 1 # DO NOT EDIT. This file is generated from Config.src 1 2 # 2 3 # For a description of the syntax of this configuration file, … … 4 5 # 5 6 6 config APP_UDHCPD 7 bool "udhcp Server (udhcpd)" 8 default n 7 8 9 config UDHCPD 10 bool "udhcp server (udhcpd)" 11 default y 12 depends on PLATFORM_LINUX 9 13 help 10 u DHCPd is a DHCP server geared primarily toward embedded systems,14 udhcpd is a DHCP server geared primarily toward embedded systems, 11 15 while striving to be fully functional and RFC compliant. 12 16 13 See http://udhcp.busybox.net for further details. 14 15 config APP_DHCPRELAY 17 config DHCPRELAY 16 18 bool "dhcprelay" 17 default n18 depends on APP_UDHCPD19 default y 20 depends on UDHCPD 19 21 help 20 22 dhcprelay listens for dhcp requests on one or more interfaces … … 22 24 server. 23 25 24 config APP_DUMPLEASES26 config DUMPLEASES 25 27 bool "Lease display utility (dumpleases)" 26 default n27 depends on APP_UDHCPD28 default y 29 depends on UDHCPD 28 30 help 29 31 dumpleases displays the leases written out by the udhcpd server. … … 31 33 by the absolute time that it expires in seconds from epoch. 32 34 33 See http://udhcp.busybox.net for further details.34 35 35 config FEATURE_UDHCPD_WRITE_LEASES_EARLY 36 36 bool "Rewrite the lease file at every new acknowledge" 37 default n38 depends on APP_UDHCPD37 default y 38 depends on UDHCPD 39 39 help 40 40 If selected, udhcpd will write a new file with leases every 41 time a new lease has been accepted, thus el eminating the need42 to send SIGUSR1 for the initial writing ,or updating. Any timed41 time a new lease has been accepted, thus eliminating the need 42 to send SIGUSR1 for the initial writing or updating. Any timed 43 43 rewriting remains undisturbed 44 44 45 config APP_UDHCPC 46 bool "udhcp Client (udhcpc)" 47 default n 45 config DHCPD_LEASES_FILE 46 string "Absolute path to lease file" 47 default "/var/lib/misc/udhcpd.leases" 48 depends on UDHCPD 48 49 help 49 uDHCPc is a DHCP client geared primarily toward embedded systems, 50 udhcpd stores addresses in a lease file. This is the absolute path 51 of the file. Normally it is safe to leave it untouched. 52 53 config UDHCPC 54 bool "udhcp client (udhcpc)" 55 default y 56 depends on PLATFORM_LINUX 57 help 58 udhcpc is a DHCP client geared primarily toward embedded systems, 50 59 while striving to be fully functional and RFC compliant. 51 60 52 61 The udhcp client negotiates a lease with the DHCP server and 53 notifies a set of scriptswhen a lease is obtained or lost.62 runs a script when a lease is obtained or lost. 54 63 55 See http://udhcp.busybox.net for further details. 64 config FEATURE_UDHCPC_ARPING 65 bool "Verify that the offered address is free, using ARP ping" 66 default y 67 depends on UDHCPC 68 help 69 If selected, udhcpc will send ARP probes and make sure 70 the offered address is really not in use by anyone. The client 71 will DHCPDECLINE the offer if the address is in use, 72 and restart the discover process. 56 73 57 config FEATURE_UDHCP_ DEBUG58 bool " Compile udhcp with noisy debugging messages"59 default n60 depends on APP_UDHCPD || APP_UDHCPC74 config FEATURE_UDHCP_PORT 75 bool "Enable '-P port' option for udhcpd and udhcpc" 76 default y 77 depends on UDHCPD || UDHCPC 61 78 help 62 If selected, udhcpd will output extra debugging output. If using 63 this option, compile uDHCP with "-g", and do not fork the daemon to 64 the background. 79 At the cost of ~300 bytes, enables -P port option. 80 This feature is typically not needed. 65 81 66 See http://udhcp.busybox.net for further details. 82 config UDHCP_DEBUG 83 int "Maximum verbosity level for udhcp applets (0..9)" 84 default 9 85 range 0 9 86 depends on UDHCPD || UDHCPC || DHCPRELAY 87 help 88 Verbosity can be increased with multiple -v options. 89 This option controls how high it can be cranked up. 67 90 68 config FEATURE_RFC3397 91 Bigger values result in bigger code. Levels above 1 92 are very verbose and useful for debugging only. 93 94 config FEATURE_UDHCP_RFC3397 69 95 bool "Support for RFC3397 domain search (experimental)" 70 default n71 depends on APP_UDHCPD || APP_UDHCPC96 default y 97 depends on UDHCPD || UDHCPC 72 98 help 73 99 If selected, both client and server will support passing of domain 74 search lists via option 119, specified in RFC3397. 100 search lists via option 119, specified in RFC 3397, 101 and SIP servers option 120, specified in RFC 3361. 102 103 config UDHCPC_DEFAULT_SCRIPT 104 string "Absolute path to config script" 105 default "/usr/share/udhcpc/default.script" 106 depends on UDHCPC 107 help 108 This script is called after udhcpc receives an answer. See 109 examples/udhcp for a working example. Normally it is safe 110 to leave this untouched. 111 112 config UDHCPC_SLACK_FOR_BUGGY_SERVERS 113 int "DHCP options slack buffer size" 114 default 80 115 range 0 924 116 depends on UDHCPD || UDHCPC 117 help 118 Some buggy DHCP servers send DHCP offer packets with option 119 field larger than we expect (which might also be considered a 120 buffer overflow attempt). These packets are normally discarded. 121 If circumstances beyond your control force you to support such 122 servers, this may help. The upper limit (924) makes dhcpc accept 123 even 1500 byte packets (maximum-sized ethernet packets). 124 125 This option does not make dhcp[cd] emit non-standard 126 sized packets. 127 128 Known buggy DHCP servers: 129 3Com OfficeConnect Remote 812 ADSL Router: 130 seems to confuse maximum allowed UDP packet size with 131 maximum size of entire IP packet, and sends packets which are 132 28 bytes too large. 133 Seednet (ISP) VDSL: sends packets 2 bytes too large. -
branches/2.2.9/mindi-busybox/networking/udhcp/Kbuild
r1765 r2725 1 # DO NOT EDIT. This file is generated from Kbuild.src 1 2 # Makefile for busybox 2 3 # 3 4 # Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 4 5 # 5 # Licensed under the GPL v2 or later, see the file LICENSE in this tarball.6 # Licensed under GPLv2 or later, see file LICENSE in this source tree. 6 7 # 7 8 8 9 lib-y:= 9 lib-$(CONFIG_APP_UDHCPC) += common.o options.o packet.o \ 10 signalpipe.o socket.o 11 lib-$(CONFIG_APP_UDHCPD) += common.o options.o packet.o \ 12 signalpipe.o socket.o 13 lib-$(CONFIG_APP_UDHCPC) += dhcpc.o clientpacket.o clientsocket.o \ 14 script.o 15 lib-$(CONFIG_APP_UDHCPD) += dhcpd.o arpping.o files.o leases.o \ 16 serverpacket.o static_leases.o 17 lib-$(CONFIG_APP_DUMPLEASES) += dumpleases.o 18 lib-$(CONFIG_APP_DHCPRELAY) += dhcprelay.o 19 lib-$(CONFIG_FEATURE_RFC3397) += domain_codec.o 10 11 12 13 lib-$(CONFIG_UDHCPC) += common.o packet.o signalpipe.o socket.o 14 lib-$(CONFIG_UDHCPD) += common.o packet.o signalpipe.o socket.o 15 16 lib-$(CONFIG_UDHCPC) += dhcpc.o 17 lib-$(CONFIG_UDHCPD) += dhcpd.o arpping.o files.o leases.o static_leases.o 18 lib-$(CONFIG_DUMPLEASES) += dumpleases.o 19 lib-$(CONFIG_DHCPRELAY) += dhcprelay.o 20 21 lib-$(CONFIG_FEATURE_UDHCPC_ARPING) += arpping.o 22 lib-$(CONFIG_FEATURE_UDHCP_RFC3397) += domain_codec.o -
branches/2.2.9/mindi-busybox/networking/udhcp/arpping.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * arpping.c4 *5 3 * Mostly stolen from: dhcpcd - DHCP client daemon 6 4 * by Yoichi Hariguchi <yoichi@fore.com> 5 * 6 * Licensed under GPLv2, see file LICENSE in this source tree. 7 7 */ 8 9 8 #include <netinet/if_ether.h> 10 9 #include <net/if_arp.h> … … 12 11 #include "common.h" 13 12 #include "dhcpd.h" 14 15 13 16 14 struct arpMsg { … … 31 29 uint8_t tInaddr[4]; /* 26 target's IP address */ 32 30 uint8_t pad[18]; /* 2a pad for min. ethernet payload (60 bytes) */ 33 } ATTRIBUTE_PACKED;31 } PACKED; 34 32 33 enum { 34 ARP_MSG_SIZE = 0x2a 35 }; 35 36 36 37 /* Returns 1 if no reply received */ 37 38 int arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface) 38 int FAST_FUNC arpping(uint32_t test_nip, 39 const uint8_t *safe_mac, 40 uint32_t from_ip, 41 uint8_t *from_mac, 42 const char *interface) 39 43 { 40 int timeout = 2; 41 int s; /* socket */ 44 int timeout_ms; 45 struct pollfd pfd[1]; 46 #define s (pfd[0].fd) /* socket */ 42 47 int rv = 1; /* "no reply received" yet */ 43 48 struct sockaddr addr; /* for interface name */ 44 49 struct arpMsg arp; 45 fd_set fdset;46 struct timeval tm;47 unsigned prevTime;48 50 49 51 s = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP)); … … 54 56 55 57 if (setsockopt_broadcast(s) == -1) { 56 bb_perror_msg("can not setsocketopt on raw socket");58 bb_perror_msg("can't enable bcast on raw socket"); 57 59 goto ret; 58 60 } … … 70 72 memcpy(arp.sHaddr, from_mac, 6); /* source hardware address */ 71 73 memcpy(arp.sInaddr, &from_ip, sizeof(from_ip)); /* source IP address */ 72 /* tHaddr *//* target hardware address */73 memcpy(arp.tInaddr, &test_ ip, sizeof(test_ip));/* target IP address */74 /* tHaddr is zero-filled */ /* target hardware address */ 75 memcpy(arp.tInaddr, &test_nip, sizeof(test_nip));/* target IP address */ 74 76 75 77 memset(&addr, 0, sizeof(addr)); 76 78 safe_strncpy(addr.sa_data, interface, sizeof(addr.sa_data)); 77 if (sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0) 79 if (sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0) { 80 // TODO: error message? caller didn't expect us to fail, 81 // just returning 1 "no reply received" misleads it. 78 82 goto ret; 83 } 79 84 80 85 /* wait for arp reply, and check it */ 86 timeout_ms = 2000; 81 87 do { 88 typedef uint32_t aliased_uint32_t FIX_ALIASING; 82 89 int r; 83 prevTime = monotonic_sec();84 FD_ZERO(&fdset); 85 FD_SET(s, &fdset);86 tm.tv_sec = timeout;87 tm.tv_usec = 0;88 r = select(s + 1, &fdset, NULL, NULL, &tm);89 if (r < 0) {90 bb_perror_msg("error on ARPING request");91 if ( errno != EINTR)90 unsigned prevTime = monotonic_ms(); 91 92 pfd[0].events = POLLIN; 93 r = safe_poll(pfd, 1, timeout_ms); 94 if (r < 0) 95 break; 96 if (r) { 97 r = safe_read(s, &arp, sizeof(arp)); 98 if (r < 0) 92 99 break; 93 } else if (r) { 94 if (recv(s, &arp, sizeof(arp), 0) < 0) 95 break; 96 if (arp.operation == htons(ARPOP_REPLY) 97 && memcmp(arp.tHaddr, from_mac, 6) == 0 98 && *((uint32_t *) arp.sInaddr) == test_ip 100 101 //log3("sHaddr %02x:%02x:%02x:%02x:%02x:%02x", 102 // arp.sHaddr[0], arp.sHaddr[1], arp.sHaddr[2], 103 // arp.sHaddr[3], arp.sHaddr[4], arp.sHaddr[5]); 104 105 if (r >= ARP_MSG_SIZE 106 && arp.operation == htons(ARPOP_REPLY) 107 /* don't check it: Linux doesn't return proper tHaddr (fixed in 2.6.24?) */ 108 /* && memcmp(arp.tHaddr, from_mac, 6) == 0 */ 109 && *(aliased_uint32_t*)arp.sInaddr == test_nip 99 110 ) { 100 rv = 0; 111 /* if ARP source MAC matches safe_mac 112 * (which is client's MAC), then it's not a conflict 113 * (client simply already has this IP and replies to ARPs!) 114 */ 115 if (!safe_mac || memcmp(safe_mac, arp.sHaddr, 6) != 0) 116 rv = 0; 117 //else log2("sHaddr == safe_mac"); 101 118 break; 102 119 } 103 120 } 104 timeout -= monotonic_sec() - prevTime;105 } while (timeout > 0);121 timeout_ms -= (unsigned)monotonic_ms() - prevTime; 122 } while (timeout_ms > 0); 106 123 107 124 ret: 108 125 close(s); 109 DEBUG("%srp reply received for this address", rv ? "No a" : "A");126 log1("%srp reply received for this address", rv ? "No a" : "A"); 110 127 return rv; 111 128 } -
branches/2.2.9/mindi-busybox/networking/udhcp/common.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 /* common.c 2 /* 3 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001 3 4 * 4 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.5 * Licensed under GPLv2, see file LICENSE in this source tree. 5 6 */ 6 7 7 #include "common.h" 8 9 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 10 unsigned dhcp_verbose; 11 #endif 8 12 9 13 const uint8_t MAC_BCAST_ADDR[6] ALIGN2 = { 10 14 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 11 15 }; 16 17 /* Supported options are easily added here. 18 * See RFC2132 for more options. 19 * OPTION_REQ: these options are requested by udhcpc (unless -o). 20 */ 21 const struct dhcp_optflag dhcp_optflags[] = { 22 /* flags code */ 23 { OPTION_IP | OPTION_REQ, 0x01 }, /* DHCP_SUBNET */ 24 { OPTION_S32 , 0x02 }, /* DHCP_TIME_OFFSET */ 25 { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x03 }, /* DHCP_ROUTER */ 26 // { OPTION_IP | OPTION_LIST , 0x04 }, /* DHCP_TIME_SERVER */ 27 // { OPTION_IP | OPTION_LIST , 0x05 }, /* DHCP_NAME_SERVER */ 28 { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x06 }, /* DHCP_DNS_SERVER */ 29 // { OPTION_IP | OPTION_LIST , 0x07 }, /* DHCP_LOG_SERVER */ 30 // { OPTION_IP | OPTION_LIST , 0x08 }, /* DHCP_COOKIE_SERVER */ 31 { OPTION_IP | OPTION_LIST , 0x09 }, /* DHCP_LPR_SERVER */ 32 { OPTION_STRING | OPTION_REQ, 0x0c }, /* DHCP_HOST_NAME */ 33 { OPTION_U16 , 0x0d }, /* DHCP_BOOT_SIZE */ 34 { OPTION_STRING | OPTION_REQ, 0x0f }, /* DHCP_DOMAIN_NAME */ 35 { OPTION_IP , 0x10 }, /* DHCP_SWAP_SERVER */ 36 { OPTION_STRING , 0x11 }, /* DHCP_ROOT_PATH */ 37 { OPTION_U8 , 0x17 }, /* DHCP_IP_TTL */ 38 { OPTION_U16 , 0x1a }, /* DHCP_MTU */ 39 { OPTION_IP | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST */ 40 { OPTION_IP_PAIR | OPTION_LIST , 0x21 }, /* DHCP_ROUTES */ 41 { OPTION_STRING , 0x28 }, /* DHCP_NIS_DOMAIN */ 42 { OPTION_IP | OPTION_LIST , 0x29 }, /* DHCP_NIS_SERVER */ 43 { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x2a }, /* DHCP_NTP_SERVER */ 44 { OPTION_IP | OPTION_LIST , 0x2c }, /* DHCP_WINS_SERVER */ 45 { OPTION_U32 , 0x33 }, /* DHCP_LEASE_TIME */ 46 { OPTION_IP , 0x36 }, /* DHCP_SERVER_ID */ 47 { OPTION_STRING , 0x38 }, /* DHCP_ERR_MESSAGE */ 48 //TODO: must be combined with 'sname' and 'file' handling: 49 { OPTION_STRING , 0x42 }, /* DHCP_TFTP_SERVER_NAME */ 50 { OPTION_STRING , 0x43 }, /* DHCP_BOOT_FILE */ 51 //TODO: not a string, but a set of LASCII strings: 52 // { OPTION_STRING , 0x4D }, /* DHCP_USER_CLASS */ 53 #if ENABLE_FEATURE_UDHCP_RFC3397 54 { OPTION_DNS_STRING | OPTION_LIST , 0x77 }, /* DHCP_DOMAIN_SEARCH */ 55 { OPTION_SIP_SERVERS , 0x78 }, /* DHCP_SIP_SERVERS */ 56 #endif 57 { OPTION_STATIC_ROUTES , 0x79 }, /* DHCP_STATIC_ROUTES */ 58 { OPTION_STATIC_ROUTES , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */ 59 { OPTION_STRING , 0xfc }, /* DHCP_WPAD */ 60 61 /* Options below have no match in dhcp_option_strings[], 62 * are not passed to dhcpc scripts, and cannot be specified 63 * with "option XXX YYY" syntax in dhcpd config file. 64 * These entries are only used internally by udhcp[cd] 65 * to correctly encode options into packets. 66 */ 67 68 { OPTION_IP , 0x32 }, /* DHCP_REQUESTED_IP */ 69 { OPTION_U8 , 0x35 }, /* DHCP_MESSAGE_TYPE */ 70 { OPTION_U16 , 0x39 }, /* DHCP_MAX_SIZE */ 71 //looks like these opts will work just fine even without these defs: 72 // { OPTION_STRING , 0x3c }, /* DHCP_VENDOR */ 73 // /* not really a string: */ 74 // { OPTION_STRING , 0x3d }, /* DHCP_CLIENT_ID */ 75 { 0, 0 } /* zeroed terminating entry */ 76 }; 77 78 /* Used for converting options from incoming packets to env variables 79 * for udhcpc stript, and for setting options for udhcpd via 80 * "opt OPTION_NAME OPTION_VALUE" directives in udhcpd.conf file. 81 */ 82 /* Must match dhcp_optflags[] order */ 83 const char dhcp_option_strings[] ALIGN1 = 84 "subnet" "\0" /* DHCP_SUBNET */ 85 "timezone" "\0" /* DHCP_TIME_OFFSET */ 86 "router" "\0" /* DHCP_ROUTER */ 87 // "timesrv" "\0" /* DHCP_TIME_SERVER */ 88 // "namesrv" "\0" /* DHCP_NAME_SERVER */ 89 "dns" "\0" /* DHCP_DNS_SERVER */ 90 // "logsrv" "\0" /* DHCP_LOG_SERVER */ 91 // "cookiesrv" "\0" /* DHCP_COOKIE_SERVER */ 92 "lprsrv" "\0" /* DHCP_LPR_SERVER */ 93 "hostname" "\0" /* DHCP_HOST_NAME */ 94 "bootsize" "\0" /* DHCP_BOOT_SIZE */ 95 "domain" "\0" /* DHCP_DOMAIN_NAME */ 96 "swapsrv" "\0" /* DHCP_SWAP_SERVER */ 97 "rootpath" "\0" /* DHCP_ROOT_PATH */ 98 "ipttl" "\0" /* DHCP_IP_TTL */ 99 "mtu" "\0" /* DHCP_MTU */ 100 "broadcast" "\0" /* DHCP_BROADCAST */ 101 "routes" "\0" /* DHCP_ROUTES */ 102 "nisdomain" "\0" /* DHCP_NIS_DOMAIN */ 103 "nissrv" "\0" /* DHCP_NIS_SERVER */ 104 "ntpsrv" "\0" /* DHCP_NTP_SERVER */ 105 "wins" "\0" /* DHCP_WINS_SERVER */ 106 "lease" "\0" /* DHCP_LEASE_TIME */ 107 "serverid" "\0" /* DHCP_SERVER_ID */ 108 "message" "\0" /* DHCP_ERR_MESSAGE */ 109 "tftp" "\0" /* DHCP_TFTP_SERVER_NAME */ 110 "bootfile" "\0" /* DHCP_BOOT_FILE */ 111 // "userclass" "\0" /* DHCP_USER_CLASS */ 112 #if ENABLE_FEATURE_UDHCP_RFC3397 113 "search" "\0" /* DHCP_DOMAIN_SEARCH */ 114 // doesn't work in udhcpd.conf since OPTION_SIP_SERVERS 115 // is not handled yet by "string->option" conversion code: 116 "sipsrv" "\0" /* DHCP_SIP_SERVERS */ 117 #endif 118 // doesn't work in udhcpd.conf since OPTION_STATIC_ROUTES 119 // is not handled yet by "string->option" conversion code: 120 "staticroutes" "\0"/* DHCP_STATIC_ROUTES */ 121 "msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */ 122 "wpad" "\0" /* DHCP_WPAD */ 123 ; 124 125 /* Lengths of the option types in binary form. 126 * Used by: 127 * udhcp_str2optset: to determine how many bytes to allocate. 128 * xmalloc_optname_optval: to estimate string length 129 * from binary option length: (option[LEN] / dhcp_option_lengths[opt_type]) 130 * is the number of elements, multiply in by one element's string width 131 * (len_of_option_as_string[opt_type]) and you know how wide string you need. 132 */ 133 const uint8_t dhcp_option_lengths[] ALIGN1 = { 134 [OPTION_IP] = 4, 135 [OPTION_IP_PAIR] = 8, 136 // [OPTION_BOOLEAN] = 1, 137 [OPTION_STRING] = 1, /* ignored by udhcp_str2optset */ 138 #if ENABLE_FEATURE_UDHCP_RFC3397 139 [OPTION_DNS_STRING] = 1, /* ignored by both udhcp_str2optset and xmalloc_optname_optval */ 140 [OPTION_SIP_SERVERS] = 1, 141 #endif 142 [OPTION_U8] = 1, 143 [OPTION_U16] = 2, 144 // [OPTION_S16] = 2, 145 [OPTION_U32] = 4, 146 [OPTION_S32] = 4, 147 /* Just like OPTION_STRING, we use minimum length here */ 148 [OPTION_STATIC_ROUTES] = 5, 149 }; 150 151 152 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2 153 static void log_option(const char *pfx, const uint8_t *opt) 154 { 155 if (dhcp_verbose >= 2) { 156 char buf[256 * 2 + 2]; 157 *bin2hex(buf, (void*) (opt + OPT_DATA), opt[OPT_LEN]) = '\0'; 158 bb_info_msg("%s: 0x%02x %s", pfx, opt[OPT_CODE], buf); 159 } 160 } 161 #else 162 # define log_option(pfx, opt) ((void)0) 163 #endif 164 165 unsigned FAST_FUNC udhcp_option_idx(const char *name) 166 { 167 int n = index_in_strings(dhcp_option_strings, name); 168 if (n >= 0) 169 return n; 170 171 { 172 char buf[sizeof(dhcp_option_strings)]; 173 char *d = buf; 174 const char *s = dhcp_option_strings; 175 while (s < dhcp_option_strings + sizeof(dhcp_option_strings) - 2) { 176 *d++ = (*s == '\0' ? ' ' : *s); 177 s++; 178 } 179 *d = '\0'; 180 bb_error_msg_and_die("unknown option '%s', known options: %s", name, buf); 181 } 182 } 183 184 /* Get an option with bounds checking (warning, result is not aligned) */ 185 uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code) 186 { 187 uint8_t *optionptr; 188 int len; 189 int rem; 190 int overload = 0; 191 enum { 192 FILE_FIELD101 = FILE_FIELD * 0x101, 193 SNAME_FIELD101 = SNAME_FIELD * 0x101, 194 }; 195 196 /* option bytes: [code][len][data1][data2]..[dataLEN] */ 197 optionptr = packet->options; 198 rem = sizeof(packet->options); 199 while (1) { 200 if (rem <= 0) { 201 bb_error_msg("bad packet, malformed option field"); 202 return NULL; 203 } 204 if (optionptr[OPT_CODE] == DHCP_PADDING) { 205 rem--; 206 optionptr++; 207 continue; 208 } 209 if (optionptr[OPT_CODE] == DHCP_END) { 210 if ((overload & FILE_FIELD101) == FILE_FIELD) { 211 /* can use packet->file, and didn't look at it yet */ 212 overload |= FILE_FIELD101; /* "we looked at it" */ 213 optionptr = packet->file; 214 rem = sizeof(packet->file); 215 continue; 216 } 217 if ((overload & SNAME_FIELD101) == SNAME_FIELD) { 218 /* can use packet->sname, and didn't look at it yet */ 219 overload |= SNAME_FIELD101; /* "we looked at it" */ 220 optionptr = packet->sname; 221 rem = sizeof(packet->sname); 222 continue; 223 } 224 break; 225 } 226 len = 2 + optionptr[OPT_LEN]; 227 rem -= len; 228 if (rem < 0) 229 continue; /* complain and return NULL */ 230 231 if (optionptr[OPT_CODE] == code) { 232 log_option("Option found", optionptr); 233 return optionptr + OPT_DATA; 234 } 235 236 if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) { 237 overload |= optionptr[OPT_DATA]; 238 /* fall through */ 239 } 240 optionptr += len; 241 } 242 243 /* log3 because udhcpc uses it a lot - very noisy */ 244 log3("Option 0x%02x not found", code); 245 return NULL; 246 } 247 248 /* Return the position of the 'end' option (no bounds checking) */ 249 int FAST_FUNC udhcp_end_option(uint8_t *optionptr) 250 { 251 int i = 0; 252 253 while (optionptr[i] != DHCP_END) { 254 if (optionptr[i] != DHCP_PADDING) 255 i += optionptr[i + OPT_LEN] + OPT_DATA-1; 256 i++; 257 } 258 return i; 259 } 260 261 /* Add an option (supplied in binary form) to the options. 262 * Option format: [code][len][data1][data2]..[dataLEN] 263 */ 264 void FAST_FUNC udhcp_add_binary_option(struct dhcp_packet *packet, uint8_t *addopt) 265 { 266 unsigned len; 267 uint8_t *optionptr = packet->options; 268 unsigned end = udhcp_end_option(optionptr); 269 270 len = OPT_DATA + addopt[OPT_LEN]; 271 /* end position + (option code/length + addopt length) + end option */ 272 if (end + len + 1 >= DHCP_OPTIONS_BUFSIZE) { 273 //TODO: learn how to use overflow option if we exhaust packet->options[] 274 bb_error_msg("option 0x%02x did not fit into the packet", 275 addopt[OPT_CODE]); 276 return; 277 } 278 log_option("Adding option", addopt); 279 memcpy(optionptr + end, addopt, len); 280 optionptr[end + len] = DHCP_END; 281 } 282 283 /* Add an one to four byte option to a packet */ 284 void FAST_FUNC udhcp_add_simple_option(struct dhcp_packet *packet, uint8_t code, uint32_t data) 285 { 286 const struct dhcp_optflag *dh; 287 288 for (dh = dhcp_optflags; dh->code; dh++) { 289 if (dh->code == code) { 290 uint8_t option[6], len; 291 292 option[OPT_CODE] = code; 293 len = dhcp_option_lengths[dh->flags & OPTION_TYPE_MASK]; 294 option[OPT_LEN] = len; 295 if (BB_BIG_ENDIAN) 296 data <<= 8 * (4 - len); 297 /* Assignment is unaligned! */ 298 move_to_unaligned32(&option[OPT_DATA], data); 299 udhcp_add_binary_option(packet, option); 300 return; 301 } 302 } 303 304 bb_error_msg("can't add option 0x%02x", code); 305 } 306 307 /* Find option 'code' in opt_list */ 308 struct option_set* FAST_FUNC udhcp_find_option(struct option_set *opt_list, uint8_t code) 309 { 310 while (opt_list && opt_list->data[OPT_CODE] < code) 311 opt_list = opt_list->next; 312 313 if (opt_list && opt_list->data[OPT_CODE] == code) 314 return opt_list; 315 return NULL; 316 } 317 318 /* Parse string to IP in network order */ 319 int FAST_FUNC udhcp_str2nip(const char *str, void *arg) 320 { 321 len_and_sockaddr *lsa; 322 323 lsa = host_and_af2sockaddr(str, 0, AF_INET); 324 if (!lsa) 325 return 0; 326 *(uint32_t*)arg = lsa->u.sin.sin_addr.s_addr; 327 free(lsa); 328 return 1; 329 } 330 331 /* udhcp_str2optset: 332 * Parse string option representation to binary form and add it to opt_list. 333 * Called to parse "udhcpc -x OPTNAME:OPTVAL" 334 * and to parse udhcpd.conf's "opt OPTNAME OPTVAL" directives. 335 */ 336 /* helper for the helper */ 337 static char *allocate_tempopt_if_needed( 338 const struct dhcp_optflag *optflag, 339 char *buffer, 340 int *length_p) 341 { 342 char *allocated = NULL; 343 if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_BIN) { 344 const char *end; 345 allocated = xstrdup(buffer); /* more than enough */ 346 end = hex2bin(allocated, buffer, 255); 347 if (errno) 348 bb_error_msg_and_die("malformed hex string '%s'", buffer); 349 *length_p = end - allocated; 350 } 351 return allocated; 352 } 353 /* helper: add an option to the opt_list */ 354 static NOINLINE void attach_option( 355 struct option_set **opt_list, 356 const struct dhcp_optflag *optflag, 357 char *buffer, 358 int length) 359 { 360 struct option_set *existing, *new, **curr; 361 char *allocated = NULL; 362 363 existing = udhcp_find_option(*opt_list, optflag->code); 364 if (!existing) { 365 log2("Attaching option %02x to list", optflag->code); 366 allocated = allocate_tempopt_if_needed(optflag, buffer, &length); 367 #if ENABLE_FEATURE_UDHCP_RFC3397 368 if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) { 369 /* reuse buffer and length for RFC1035-formatted string */ 370 allocated = buffer = (char *)dname_enc(NULL, 0, buffer, &length); 371 } 372 #endif 373 /* make a new option */ 374 new = xmalloc(sizeof(*new)); 375 new->data = xmalloc(length + OPT_DATA); 376 new->data[OPT_CODE] = optflag->code; 377 new->data[OPT_LEN] = length; 378 memcpy(new->data + OPT_DATA, (allocated ? allocated : buffer), length); 379 380 curr = opt_list; 381 while (*curr && (*curr)->data[OPT_CODE] < optflag->code) 382 curr = &(*curr)->next; 383 384 new->next = *curr; 385 *curr = new; 386 goto ret; 387 } 388 389 if (optflag->flags & OPTION_LIST) { 390 unsigned old_len; 391 392 /* add it to an existing option */ 393 log2("Attaching option %02x to existing member of list", optflag->code); 394 allocated = allocate_tempopt_if_needed(optflag, buffer, &length); 395 old_len = existing->data[OPT_LEN]; 396 #if ENABLE_FEATURE_UDHCP_RFC3397 397 if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) { 398 /* reuse buffer and length for RFC1035-formatted string */ 399 allocated = buffer = (char *)dname_enc(existing->data + OPT_DATA, old_len, buffer, &length); 400 } 401 #endif 402 if (old_len + length < 255) { 403 /* actually 255 is ok too, but adding a space can overlow it */ 404 405 existing->data = xrealloc(existing->data, OPT_DATA + 1 + old_len + length); 406 if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_STRING) { 407 /* add space separator between STRING options in a list */ 408 existing->data[OPT_DATA + old_len] = ' '; 409 old_len++; 410 } 411 memcpy(existing->data + OPT_DATA + old_len, buffer, length); 412 existing->data[OPT_LEN] = old_len + length; 413 } /* else, ignore the data, we could put this in a second option in the future */ 414 } /* else, ignore the new data */ 415 416 ret: 417 free(allocated); 418 } 419 420 int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg) 421 { 422 struct option_set **opt_list = arg; 423 char *opt, *val, *endptr; 424 char *str; 425 const struct dhcp_optflag *optflag; 426 struct dhcp_optflag bin_optflag; 427 unsigned optcode; 428 int retval, length; 429 char buffer[8] ALIGNED(4); 430 uint16_t *result_u16 = (uint16_t *) buffer; 431 uint32_t *result_u32 = (uint32_t *) buffer; 432 433 /* Cheat, the only *const* str possible is "" */ 434 str = (char *) const_str; 435 opt = strtok(str, " \t="); 436 if (!opt) 437 return 0; 438 439 optcode = bb_strtou(opt, NULL, 0); 440 if (!errno && optcode < 255) { 441 /* Raw (numeric) option code */ 442 bin_optflag.flags = OPTION_BIN; 443 bin_optflag.code = optcode; 444 optflag = &bin_optflag; 445 } else { 446 optflag = &dhcp_optflags[udhcp_option_idx(opt)]; 447 } 448 449 retval = 0; 450 do { 451 val = strtok(NULL, ", \t"); 452 if (!val) 453 break; 454 length = dhcp_option_lengths[optflag->flags & OPTION_TYPE_MASK]; 455 retval = 0; 456 opt = buffer; /* new meaning for variable opt */ 457 switch (optflag->flags & OPTION_TYPE_MASK) { 458 case OPTION_IP: 459 retval = udhcp_str2nip(val, buffer); 460 break; 461 case OPTION_IP_PAIR: 462 retval = udhcp_str2nip(val, buffer); 463 val = strtok(NULL, ", \t/-"); 464 if (!val) 465 retval = 0; 466 if (retval) 467 retval = udhcp_str2nip(val, buffer + 4); 468 break; 469 case OPTION_STRING: 470 #if ENABLE_FEATURE_UDHCP_RFC3397 471 case OPTION_DNS_STRING: 472 #endif 473 length = strnlen(val, 254); 474 if (length > 0) { 475 opt = val; 476 retval = 1; 477 } 478 break; 479 // case OPTION_BOOLEAN: { 480 // static const char no_yes[] ALIGN1 = "no\0yes\0"; 481 // buffer[0] = retval = index_in_strings(no_yes, val); 482 // retval++; /* 0 - bad; 1: "no" 2: "yes" */ 483 // break; 484 // } 485 case OPTION_U8: 486 buffer[0] = strtoul(val, &endptr, 0); 487 retval = (endptr[0] == '\0'); 488 break; 489 /* htonX are macros in older libc's, using temp var 490 * in code below for safety */ 491 /* TODO: use bb_strtoX? */ 492 case OPTION_U16: { 493 unsigned long tmp = strtoul(val, &endptr, 0); 494 *result_u16 = htons(tmp); 495 retval = (endptr[0] == '\0' /*&& tmp < 0x10000*/); 496 break; 497 } 498 // case OPTION_S16: { 499 // long tmp = strtol(val, &endptr, 0); 500 // *result_u16 = htons(tmp); 501 // retval = (endptr[0] == '\0'); 502 // break; 503 // } 504 case OPTION_U32: { 505 unsigned long tmp = strtoul(val, &endptr, 0); 506 *result_u32 = htonl(tmp); 507 retval = (endptr[0] == '\0'); 508 break; 509 } 510 case OPTION_S32: { 511 long tmp = strtol(val, &endptr, 0); 512 *result_u32 = htonl(tmp); 513 retval = (endptr[0] == '\0'); 514 break; 515 } 516 case OPTION_BIN: /* handled in attach_option() */ 517 opt = val; 518 retval = 1; 519 default: 520 break; 521 } 522 if (retval) 523 attach_option(opt_list, optflag, opt, length); 524 } while (retval && optflag->flags & OPTION_LIST); 525 526 return retval; 527 } -
branches/2.2.9/mindi-busybox/networking/udhcp/common.h
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 /* common.h 3 * 2 /* 4 3 * Russ Dill <Russ.Dill@asu.edu> September 2001 5 4 * Rewritten by Vladimir Oleynik <dzo@simtreas.ru> (C) 2003 6 5 * 7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.6 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 8 7 */ 9 10 #ifndef _COMMON_H 11 #define _COMMON_H 8 #ifndef UDHCP_COMMON_H 9 #define UDHCP_COMMON_H 1 12 10 13 11 #include "libbb.h" 14 15 #define DEFAULT_SCRIPT "/usr/share/udhcpc/default.script"16 17 extern const uint8_t MAC_BCAST_ADDR[6]; /* six all-ones */18 19 /*** packet.h ***/20 21 12 #include <netinet/udp.h> 22 13 #include <netinet/ip.h> 23 14 24 struct dhcpMessage { 25 uint8_t op; 26 uint8_t htype; 27 uint8_t hlen; 28 uint8_t hops; 29 uint32_t xid; 30 uint16_t secs; 31 uint16_t flags; 32 uint32_t ciaddr; 33 uint32_t yiaddr; 34 uint32_t siaddr; 35 uint32_t giaddr; 36 uint8_t chaddr[16]; 37 uint8_t sname[64]; 38 uint8_t file[128]; 39 uint32_t cookie; 40 uint8_t options[308]; /* 312 - cookie */ 41 }; 42 43 struct udp_dhcp_packet { 15 PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 16 17 extern const uint8_t MAC_BCAST_ADDR[6]; /* six all-ones */ 18 19 20 /*** DHCP packet ***/ 21 22 /* DHCP protocol. See RFC 2131 */ 23 #define DHCP_MAGIC 0x63825363 24 #define DHCP_OPTIONS_BUFSIZE 308 25 #define BOOTREQUEST 1 26 #define BOOTREPLY 2 27 28 //TODO: rename ciaddr/yiaddr/chaddr 29 struct dhcp_packet { 30 uint8_t op; /* BOOTREQUEST or BOOTREPLY */ 31 uint8_t htype; /* hardware address type. 1 = 10mb ethernet */ 32 uint8_t hlen; /* hardware address length */ 33 uint8_t hops; /* used by relay agents only */ 34 uint32_t xid; /* unique id */ 35 uint16_t secs; /* elapsed since client began acquisition/renewal */ 36 uint16_t flags; /* only one flag so far: */ 37 #define BROADCAST_FLAG 0x8000 /* "I need broadcast replies" */ 38 uint32_t ciaddr; /* client IP (if client is in BOUND, RENEW or REBINDING state) */ 39 uint32_t yiaddr; /* 'your' (client) IP address */ 40 /* IP address of next server to use in bootstrap, returned in DHCPOFFER, DHCPACK by server */ 41 uint32_t siaddr_nip; 42 uint32_t gateway_nip; /* relay agent IP address */ 43 uint8_t chaddr[16]; /* link-layer client hardware address (MAC) */ 44 uint8_t sname[64]; /* server host name (ASCIZ) */ 45 uint8_t file[128]; /* boot file name (ASCIZ) */ 46 uint32_t cookie; /* fixed first four option bytes (99,130,83,99 dec) */ 47 uint8_t options[DHCP_OPTIONS_BUFSIZE + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS]; 48 } PACKED; 49 #define DHCP_PKT_SNAME_LEN 64 50 #define DHCP_PKT_FILE_LEN 128 51 #define DHCP_PKT_SNAME_LEN_STR "64" 52 #define DHCP_PKT_FILE_LEN_STR "128" 53 54 struct ip_udp_dhcp_packet { 44 55 struct iphdr ip; 45 56 struct udphdr udp; 46 struct dhcpMessage data; 47 }; 48 49 void udhcp_init_header(struct dhcpMessage *packet, char type); 50 int udhcp_get_packet(struct dhcpMessage *packet, int fd); 51 uint16_t udhcp_checksum(void *addr, int count); 52 int udhcp_raw_packet(struct dhcpMessage *payload, 53 uint32_t source_ip, int source_port, 54 uint32_t dest_ip, int dest_port, 55 const uint8_t *dest_arp, int ifindex); 56 int udhcp_kernel_packet(struct dhcpMessage *payload, 57 uint32_t source_ip, int source_port, 58 uint32_t dest_ip, int dest_port); 59 60 61 /**/ 62 63 void udhcp_run_script(struct dhcpMessage *packet, const char *name); 64 65 // Still need to clean these up... 66 67 /* from options.h */ 68 #define get_option udhcp_get_option 69 #define end_option udhcp_end_option 70 #define add_option_string udhcp_add_option_string 71 #define add_simple_option udhcp_add_simple_option 72 #define option_lengths udhcp_option_lengths 73 /* from socket.h */ 74 #define listen_socket udhcp_listen_socket 75 #define read_interface udhcp_read_interface 76 /* from dhcpc.h */ 77 #define client_config udhcp_client_config 78 /* from dhcpd.h */ 79 #define server_config udhcp_server_config 80 81 void udhcp_sp_setup(void); 82 int udhcp_sp_fd_set(fd_set *rfds, int extra_fd); 83 int udhcp_sp_read(fd_set *rfds); 84 int raw_socket(int ifindex); 85 int read_interface(const char *interface, int *ifindex, uint32_t *addr, uint8_t *arp); 86 int listen_socket(/*uint32_t ip,*/ int port, const char *inf); 57 struct dhcp_packet data; 58 } PACKED; 59 60 struct udp_dhcp_packet { 61 struct udphdr udp; 62 struct dhcp_packet data; 63 } PACKED; 64 65 enum { 66 IP_UDP_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, 67 UDP_DHCP_SIZE = sizeof(struct udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, 68 DHCP_SIZE = sizeof(struct dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, 69 }; 70 71 /* Let's see whether compiler understood us right */ 72 struct BUG_bad_sizeof_struct_ip_udp_dhcp_packet { 73 char c[IP_UDP_DHCP_SIZE == 576 ? 1 : -1]; 74 }; 75 76 77 /*** Options ***/ 78 79 enum { 80 OPTION_IP = 1, 81 OPTION_IP_PAIR, 82 OPTION_STRING, 83 // OPTION_BOOLEAN, 84 OPTION_U8, 85 OPTION_U16, 86 // OPTION_S16, 87 OPTION_U32, 88 OPTION_S32, 89 OPTION_BIN, 90 OPTION_STATIC_ROUTES, 91 #if ENABLE_FEATURE_UDHCP_RFC3397 92 OPTION_DNS_STRING, /* RFC1035 compressed domain name list */ 93 OPTION_SIP_SERVERS, 94 #endif 95 96 OPTION_TYPE_MASK = 0x0f, 97 /* Client requests this option by default */ 98 OPTION_REQ = 0x10, 99 /* There can be a list of 1 or more of these */ 100 OPTION_LIST = 0x20, 101 }; 102 103 /* DHCP option codes (partial list). See RFC 2132 and 104 * http://www.iana.org/assignments/bootp-dhcp-parameters/ 105 * Commented out options are handled by common option machinery, 106 * uncommented ones have spacial cases (grep for them to see). 107 */ 108 #define DHCP_PADDING 0x00 109 #define DHCP_SUBNET 0x01 110 //#define DHCP_TIME_OFFSET 0x02 /* (localtime - UTC_time) in seconds. signed */ 111 //#define DHCP_ROUTER 0x03 112 //#define DHCP_TIME_SERVER 0x04 /* RFC 868 time server (32-bit, 0 = 1.1.1900) */ 113 //#define DHCP_NAME_SERVER 0x05 /* IEN 116 _really_ ancient kind of NS */ 114 //#define DHCP_DNS_SERVER 0x06 115 //#define DHCP_LOG_SERVER 0x07 /* port 704 UDP log (not syslog) 116 //#define DHCP_COOKIE_SERVER 0x08 /* "quote of the day" server */ 117 //#define DHCP_LPR_SERVER 0x09 118 #define DHCP_HOST_NAME 0x0c /* either client informs server or server gives name to client */ 119 //#define DHCP_BOOT_SIZE 0x0d 120 //#define DHCP_DOMAIN_NAME 0x0f /* server gives domain suffix */ 121 //#define DHCP_SWAP_SERVER 0x10 122 //#define DHCP_ROOT_PATH 0x11 123 //#define DHCP_IP_TTL 0x17 124 //#define DHCP_MTU 0x1a 125 //#define DHCP_BROADCAST 0x1c 126 //#define DHCP_ROUTES 0x21 127 //#define DHCP_NIS_DOMAIN 0x28 128 //#define DHCP_NIS_SERVER 0x29 129 //#define DHCP_NTP_SERVER 0x2a 130 //#define DHCP_WINS_SERVER 0x2c 131 #define DHCP_REQUESTED_IP 0x32 /* sent by client if specific IP is wanted */ 132 #define DHCP_LEASE_TIME 0x33 133 #define DHCP_OPTION_OVERLOAD 0x34 134 #define DHCP_MESSAGE_TYPE 0x35 135 #define DHCP_SERVER_ID 0x36 /* by default server's IP */ 136 #define DHCP_PARAM_REQ 0x37 /* list of options client wants */ 137 //#define DHCP_ERR_MESSAGE 0x38 /* error message when sending NAK etc */ 138 #define DHCP_MAX_SIZE 0x39 139 #define DHCP_VENDOR 0x3c /* client's vendor (a string) */ 140 #define DHCP_CLIENT_ID 0x3d /* by default client's MAC addr, but may be arbitrarily long */ 141 //#define DHCP_TFTP_SERVER_NAME 0x42 /* same as 'sname' field */ 142 //#define DHCP_BOOT_FILE 0x43 /* same as 'file' field */ 143 //#define DHCP_USER_CLASS 0x4d /* RFC 3004. set of LASCII strings. "I am a printer" etc */ 144 #define DHCP_FQDN 0x51 /* client asks to update DNS to map its FQDN to its new IP */ 145 //#define DHCP_DOMAIN_SEARCH 0x77 /* RFC 3397. set of ASCIZ string, DNS-style compressed */ 146 //#define DHCP_SIP_SERVERS 0x78 /* RFC 3361. flag byte, then: 0: domain names, 1: IP addrs */ 147 //#define DHCP_STATIC_ROUTES 0x79 /* RFC 3442. (mask,ip,router) tuples */ 148 //#define DHCP_MS_STATIC_ROUTES 0xf9 /* Microsoft's pre-RFC 3442 code for 0x79? */ 149 //#define DHCP_WPAD 0xfc /* MSIE's Web Proxy Autodiscovery Protocol */ 150 #define DHCP_END 0xff 151 152 /* Offsets in option byte sequence */ 153 #define OPT_CODE 0 154 #define OPT_LEN 1 155 #define OPT_DATA 2 156 /* Bits in "overload" option */ 157 #define OPTION_FIELD 0 158 #define FILE_FIELD 1 159 #define SNAME_FIELD 2 160 161 /* DHCP_MESSAGE_TYPE values */ 162 #define DHCPDISCOVER 1 /* client -> server */ 163 #define DHCPOFFER 2 /* client <- server */ 164 #define DHCPREQUEST 3 /* client -> server */ 165 #define DHCPDECLINE 4 /* client -> server */ 166 #define DHCPACK 5 /* client <- server */ 167 #define DHCPNAK 6 /* client <- server */ 168 #define DHCPRELEASE 7 /* client -> server */ 169 #define DHCPINFORM 8 /* client -> server */ 170 #define DHCP_MINTYPE DHCPDISCOVER 171 #define DHCP_MAXTYPE DHCPINFORM 172 173 struct dhcp_optflag { 174 uint8_t flags; 175 uint8_t code; 176 }; 177 178 struct option_set { 179 uint8_t *data; 180 struct option_set *next; 181 }; 182 183 extern const struct dhcp_optflag dhcp_optflags[]; 184 extern const char dhcp_option_strings[]; 185 extern const uint8_t dhcp_option_lengths[]; 186 187 unsigned FAST_FUNC udhcp_option_idx(const char *name); 188 189 uint8_t *udhcp_get_option(struct dhcp_packet *packet, int code) FAST_FUNC; 190 int udhcp_end_option(uint8_t *optionptr) FAST_FUNC; 191 void udhcp_add_binary_option(struct dhcp_packet *packet, uint8_t *addopt) FAST_FUNC; 192 void udhcp_add_simple_option(struct dhcp_packet *packet, uint8_t code, uint32_t data) FAST_FUNC; 193 #if ENABLE_FEATURE_UDHCP_RFC3397 194 char *dname_dec(const uint8_t *cstr, int clen, const char *pre) FAST_FUNC; 195 uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen) FAST_FUNC; 196 #endif 197 struct option_set *udhcp_find_option(struct option_set *opt_list, uint8_t code) FAST_FUNC; 198 199 200 // RFC 2131 Table 5: Fields and options used by DHCP clients 201 // 202 // Fields 'hops', 'yiaddr', 'siaddr', 'giaddr' are always zero 203 // 204 // Field DHCPDISCOVER DHCPINFORM DHCPREQUEST DHCPDECLINE DHCPRELEASE 205 // ----- ------------ ------------ ----------- ----------- ----------- 206 // 'xid' selected by client selected by client 'xid' from server selected by client selected by client 207 // DHCPOFFER message 208 // 'secs' 0 or seconds since 0 or seconds since 0 or seconds since 0 0 209 // DHCP process started DHCP process started DHCP process started 210 // 'flags' Set 'BROADCAST' Set 'BROADCAST' Set 'BROADCAST' 0 0 211 // flag if client flag if client flag if client 212 // requires broadcast requires broadcast requires broadcast 213 // reply reply reply 214 // 'ciaddr' 0 client's IP 0 or client's IP 0 client's IP 215 // (BOUND/RENEW/REBIND) 216 // 'chaddr' client's MAC client's MAC client's MAC client's MAC client's MAC 217 // 'sname' options or sname options or sname options or sname (unused) (unused) 218 // 'file' options or file options or file options or file (unused) (unused) 219 // 'options' options options options message type opt message type opt 220 // 221 // Option DHCPDISCOVER DHCPINFORM DHCPREQUEST DHCPDECLINE DHCPRELEASE 222 // ------ ------------ ---------- ----------- ----------- ----------- 223 // Requested IP address MAY MUST NOT MUST (in MUST MUST NOT 224 // SELECTING or 225 // INIT-REBOOT) 226 // MUST NOT (in 227 // BOUND or 228 // RENEWING) 229 // IP address lease time MAY MUST NOT MAY MUST NOT MUST NOT 230 // Use 'file'/'sname' fields MAY MAY MAY MAY MAY 231 // Client identifier MAY MAY MAY MAY MAY 232 // Vendor class identifier MAY MAY MAY MUST NOT MUST NOT 233 // Server identifier MUST NOT MUST NOT MUST (after MUST MUST 234 // SELECTING) 235 // MUST NOT (after 236 // INIT-REBOOT, 237 // BOUND, RENEWING 238 // or REBINDING) 239 // Parameter request list MAY MAY MAY MUST NOT MUST NOT 240 // Maximum message size MAY MAY MAY MUST NOT MUST NOT 241 // Message SHOULD NOT SHOULD NOT SHOULD NOT SHOULD SHOULD 242 // Site-specific MAY MAY MAY MUST NOT MUST NOT 243 // All others MAY MAY MAY MUST NOT MUST NOT 244 245 246 /*** Logging ***/ 247 248 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 249 extern unsigned dhcp_verbose; 250 # define log1(...) do { if (dhcp_verbose >= 1) bb_info_msg(__VA_ARGS__); } while (0) 251 # if CONFIG_UDHCP_DEBUG >= 2 252 void udhcp_dump_packet(struct dhcp_packet *packet) FAST_FUNC; 253 # define log2(...) do { if (dhcp_verbose >= 2) bb_info_msg(__VA_ARGS__); } while (0) 254 # else 255 # define udhcp_dump_packet(...) ((void)0) 256 # define log2(...) ((void)0) 257 # endif 258 # if CONFIG_UDHCP_DEBUG >= 3 259 # define log3(...) do { if (dhcp_verbose >= 3) bb_info_msg(__VA_ARGS__); } while (0) 260 # else 261 # define log3(...) ((void)0) 262 # endif 263 #else 264 # define udhcp_dump_packet(...) ((void)0) 265 # define log1(...) ((void)0) 266 # define log2(...) ((void)0) 267 # define log3(...) ((void)0) 268 #endif 269 270 271 /*** Other shared functions ***/ 272 273 /* 2nd param is "uint32_t*" */ 274 int FAST_FUNC udhcp_str2nip(const char *str, void *arg); 275 /* 2nd param is "struct option_set**" */ 276 int FAST_FUNC udhcp_str2optset(const char *str, void *arg); 277 278 uint16_t udhcp_checksum(void *addr, int count) FAST_FUNC; 279 280 void udhcp_init_header(struct dhcp_packet *packet, char type) FAST_FUNC; 281 282 int udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) FAST_FUNC; 283 284 int udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, 285 uint32_t source_nip, int source_port, 286 uint32_t dest_nip, int dest_port, const uint8_t *dest_arp, 287 int ifindex) FAST_FUNC; 288 289 int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, 290 uint32_t source_nip, int source_port, 291 uint32_t dest_nip, int dest_port) FAST_FUNC; 292 293 void udhcp_sp_setup(void) FAST_FUNC; 294 int udhcp_sp_fd_set(fd_set *rfds, int extra_fd) FAST_FUNC; 295 int udhcp_sp_read(const fd_set *rfds) FAST_FUNC; 296 297 int udhcp_read_interface(const char *interface, int *ifindex, uint32_t *nip, uint8_t *mac) FAST_FUNC; 298 299 int udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf) FAST_FUNC; 300 87 301 /* Returns 1 if no reply received */ 88 int arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface); 89 90 #if ENABLE_FEATURE_UDHCP_DEBUG 91 # define DEBUG(str, args...) bb_info_msg(str, ## args) 92 #else 93 # define DEBUG(str, args...) do {;} while (0) 302 int arpping(uint32_t test_nip, 303 const uint8_t *safe_mac, 304 uint32_t from_ip, 305 uint8_t *from_mac, 306 const char *interface) FAST_FUNC; 307 308 POP_SAVED_FUNCTION_VISIBILITY 309 94 310 #endif 95 96 #endif -
branches/2.2.9/mindi-busybox/networking/udhcp/dhcpc.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 /* dhcpc.c 3 * 4 * udhcp DHCP client 2 /* 3 * udhcp client 5 4 * 6 5 * Russ Dill <Russ.Dill@asu.edu> July 2001 7 6 * 8 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 9 20 */ 10 11 #include <getopt.h>12 21 #include <syslog.h> 13 14 22 /* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */ 15 23 #define WANT_PIDFILE 1 … … 17 25 #include "dhcpd.h" 18 26 #include "dhcpc.h" 19 #include "options.h" 20 21 22 /* Something is definitely wrong here. IPv4 addresses 23 * in variables of type long?? BTW, we use inet_ntoa() 24 * in the code. Manpage says that struct in_addr has a member of type long (!) 25 * which holds IPv4 address, and the struct is passed by value (!!) 27 28 #include <asm/types.h> 29 #if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION) 30 # include <netpacket/packet.h> 31 # include <net/ethernet.h> 32 #else 33 # include <linux/if_packet.h> 34 # include <linux/if_ether.h> 35 #endif 36 #include <linux/filter.h> 37 38 /* struct client_config_t client_config is in bb_common_bufsiz1 */ 39 40 41 /*** Script execution code ***/ 42 43 /* get a rough idea of how long an option will be (rounding up...) */ 44 static const uint8_t len_of_option_as_string[] = { 45 [OPTION_IP ] = sizeof("255.255.255.255 "), 46 [OPTION_IP_PAIR ] = sizeof("255.255.255.255 ") * 2, 47 [OPTION_STATIC_ROUTES ] = sizeof("255.255.255.255/32 255.255.255.255 "), 48 [OPTION_STRING ] = 1, 49 #if ENABLE_FEATURE_UDHCP_RFC3397 50 [OPTION_DNS_STRING ] = 1, /* unused */ 51 /* Hmmm, this severely overestimates size if SIP_SERVERS option 52 * is in domain name form: N-byte option in binary form 53 * mallocs ~16*N bytes. But it is freed almost at once. 54 */ 55 [OPTION_SIP_SERVERS ] = sizeof("255.255.255.255 "), 56 #endif 57 // [OPTION_BOOLEAN ] = sizeof("yes "), 58 [OPTION_U8 ] = sizeof("255 "), 59 [OPTION_U16 ] = sizeof("65535 "), 60 // [OPTION_S16 ] = sizeof("-32768 "), 61 [OPTION_U32 ] = sizeof("4294967295 "), 62 [OPTION_S32 ] = sizeof("-2147483684 "), 63 }; 64 65 /* note: ip is a pointer to an IP in network order, possibly misaliged */ 66 static int sprint_nip(char *dest, const char *pre, const uint8_t *ip) 67 { 68 return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]); 69 } 70 71 /* really simple implementation, just count the bits */ 72 static int mton(uint32_t mask) 73 { 74 int i = 0; 75 mask = ntohl(mask); /* 111110000-like bit pattern */ 76 while (mask) { 77 i++; 78 mask <<= 1; 79 } 80 return i; 81 } 82 83 /* Create "opt_name=opt_value" string */ 84 static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_optflag *optflag, const char *opt_name) 85 { 86 unsigned upper_length; 87 int len, type, optlen; 88 char *dest, *ret; 89 90 /* option points to OPT_DATA, need to go back and get OPT_LEN */ 91 len = option[OPT_LEN - OPT_DATA]; 92 93 type = optflag->flags & OPTION_TYPE_MASK; 94 optlen = dhcp_option_lengths[type]; 95 upper_length = len_of_option_as_string[type] * ((unsigned)len / (unsigned)optlen); 96 97 dest = ret = xmalloc(upper_length + strlen(opt_name) + 2); 98 dest += sprintf(ret, "%s=", opt_name); 99 100 while (len >= optlen) { 101 unsigned ip_ofs = 0; 102 103 switch (type) { 104 case OPTION_IP_PAIR: 105 dest += sprint_nip(dest, "", option); 106 *dest++ = '/'; 107 ip_ofs = 4; 108 /* fall through */ 109 case OPTION_IP: 110 dest += sprint_nip(dest, "", option + ip_ofs); 111 break; 112 // case OPTION_BOOLEAN: 113 // dest += sprintf(dest, *option ? "yes" : "no"); 114 // break; 115 case OPTION_U8: 116 dest += sprintf(dest, "%u", *option); 117 break; 118 // case OPTION_S16: 119 case OPTION_U16: { 120 uint16_t val_u16; 121 move_from_unaligned16(val_u16, option); 122 dest += sprintf(dest, "%u", ntohs(val_u16)); 123 break; 124 } 125 case OPTION_S32: 126 case OPTION_U32: { 127 uint32_t val_u32; 128 move_from_unaligned32(val_u32, option); 129 dest += sprintf(dest, type == OPTION_U32 ? "%lu" : "%ld", (unsigned long) ntohl(val_u32)); 130 break; 131 } 132 case OPTION_STRING: 133 memcpy(dest, option, len); 134 dest[len] = '\0'; 135 return ret; /* Short circuit this case */ 136 case OPTION_STATIC_ROUTES: { 137 /* Option binary format: 138 * mask [one byte, 0..32] 139 * ip [big endian, 0..4 bytes depending on mask] 140 * router [big endian, 4 bytes] 141 * may be repeated 142 * 143 * We convert it to a string "IP/MASK ROUTER IP2/MASK2 ROUTER2" 144 */ 145 const char *pfx = ""; 146 147 while (len >= 1 + 4) { /* mask + 0-byte ip + router */ 148 uint32_t nip; 149 uint8_t *p; 150 unsigned mask; 151 int bytes; 152 153 mask = *option++; 154 if (mask > 32) 155 break; 156 len--; 157 158 nip = 0; 159 p = (void*) &nip; 160 bytes = (mask + 7) / 8; /* 0 -> 0, 1..8 -> 1, 9..16 -> 2 etc */ 161 while (--bytes >= 0) { 162 *p++ = *option++; 163 len--; 164 } 165 if (len < 4) 166 break; 167 168 /* print ip/mask */ 169 dest += sprint_nip(dest, pfx, (void*) &nip); 170 pfx = " "; 171 dest += sprintf(dest, "/%u ", mask); 172 /* print router */ 173 dest += sprint_nip(dest, "", option); 174 option += 4; 175 len -= 4; 176 } 177 178 return ret; 179 } 180 #if ENABLE_FEATURE_UDHCP_RFC3397 181 case OPTION_DNS_STRING: 182 /* unpack option into dest; use ret for prefix (i.e., "optname=") */ 183 dest = dname_dec(option, len, ret); 184 if (dest) { 185 free(ret); 186 return dest; 187 } 188 /* error. return "optname=" string */ 189 return ret; 190 case OPTION_SIP_SERVERS: 191 /* Option binary format: 192 * type: byte 193 * type=0: domain names, dns-compressed 194 * type=1: IP addrs 195 */ 196 option++; 197 len--; 198 if (option[-1] == 0) { 199 dest = dname_dec(option, len, ret); 200 if (dest) { 201 free(ret); 202 return dest; 203 } 204 } else 205 if (option[-1] == 1) { 206 const char *pfx = ""; 207 while (1) { 208 len -= 4; 209 if (len < 0) 210 break; 211 dest += sprint_nip(dest, pfx, option); 212 pfx = " "; 213 option += 4; 214 } 215 } 216 return ret; 217 #endif 218 } /* switch */ 219 option += optlen; 220 len -= optlen; 221 // TODO: it can be a list only if (optflag->flags & OPTION_LIST). 222 // Should we bail out/warn if we see multi-ip option which is 223 // not allowed to be such (for example, DHCP_BROADCAST)? - 224 if (len <= 0 /* || !(optflag->flags & OPTION_LIST) */) 225 break; 226 *dest++ = ' '; 227 *dest = '\0'; 228 } 229 return ret; 230 } 231 232 /* put all the parameters into the environment */ 233 static char **fill_envp(struct dhcp_packet *packet) 234 { 235 int envc; 236 int i; 237 char **envp, **curr; 238 const char *opt_name; 239 uint8_t *temp; 240 uint8_t overload = 0; 241 242 /* We need 6 elements for: 243 * "interface=IFACE" 244 * "ip=N.N.N.N" from packet->yiaddr 245 * "siaddr=IP" from packet->siaddr_nip (unless 0) 246 * "boot_file=FILE" from packet->file (unless overloaded) 247 * "sname=SERVER_HOSTNAME" from packet->sname (unless overloaded) 248 * terminating NULL 249 */ 250 envc = 6; 251 /* +1 element for each option, +2 for subnet option: */ 252 if (packet) { 253 for (i = 0; dhcp_optflags[i].code; i++) { 254 if (udhcp_get_option(packet, dhcp_optflags[i].code)) { 255 if (dhcp_optflags[i].code == DHCP_SUBNET) 256 envc++; /* for mton */ 257 envc++; 258 } 259 } 260 temp = udhcp_get_option(packet, DHCP_OPTION_OVERLOAD); 261 if (temp) 262 overload = *temp; 263 } 264 curr = envp = xzalloc(sizeof(char *) * envc); 265 266 *curr = xasprintf("interface=%s", client_config.interface); 267 putenv(*curr++); 268 269 if (!packet) 270 return envp; 271 272 *curr = xmalloc(sizeof("ip=255.255.255.255")); 273 sprint_nip(*curr, "ip=", (uint8_t *) &packet->yiaddr); 274 putenv(*curr++); 275 276 opt_name = dhcp_option_strings; 277 i = 0; 278 while (*opt_name) { 279 temp = udhcp_get_option(packet, dhcp_optflags[i].code); 280 if (!temp) 281 goto next; 282 *curr = xmalloc_optname_optval(temp, &dhcp_optflags[i], opt_name); 283 putenv(*curr++); 284 if (dhcp_optflags[i].code == DHCP_SUBNET) { 285 /* Subnet option: make things like "$ip/$mask" possible */ 286 uint32_t subnet; 287 move_from_unaligned32(subnet, temp); 288 *curr = xasprintf("mask=%d", mton(subnet)); 289 putenv(*curr++); 290 } 291 next: 292 opt_name += strlen(opt_name) + 1; 293 i++; 294 } 295 if (packet->siaddr_nip) { 296 *curr = xmalloc(sizeof("siaddr=255.255.255.255")); 297 sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip); 298 putenv(*curr++); 299 } 300 if (!(overload & FILE_FIELD) && packet->file[0]) { 301 /* watch out for invalid packets */ 302 *curr = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file); 303 putenv(*curr++); 304 } 305 if (!(overload & SNAME_FIELD) && packet->sname[0]) { 306 /* watch out for invalid packets */ 307 *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname); 308 putenv(*curr++); 309 } 310 return envp; 311 } 312 313 /* Call a script with a par file and env vars */ 314 static void udhcp_run_script(struct dhcp_packet *packet, const char *name) 315 { 316 char **envp, **curr; 317 char *argv[3]; 318 319 if (client_config.script == NULL) 320 return; 321 322 envp = fill_envp(packet); 323 324 /* call script */ 325 log1("Executing %s %s", client_config.script, name); 326 argv[0] = (char*) client_config.script; 327 argv[1] = (char*) name; 328 argv[2] = NULL; 329 spawn_and_wait(argv); 330 331 for (curr = envp; *curr; curr++) { 332 log2(" %s", *curr); 333 bb_unsetenv_and_free(*curr); 334 } 335 free(envp); 336 } 337 338 339 /*** Sending/receiving packets ***/ 340 341 static ALWAYS_INLINE uint32_t random_xid(void) 342 { 343 return rand(); 344 } 345 346 /* Initialize the packet with the proper defaults */ 347 static void init_packet(struct dhcp_packet *packet, char type) 348 { 349 /* Fill in: op, htype, hlen, cookie fields; message type option: */ 350 udhcp_init_header(packet, type); 351 352 packet->xid = random_xid(); 353 354 memcpy(packet->chaddr, client_config.client_mac, 6); 355 if (client_config.clientid) 356 udhcp_add_binary_option(packet, client_config.clientid); 357 } 358 359 static void add_client_options(struct dhcp_packet *packet) 360 { 361 uint8_t c; 362 int i, end, len; 363 364 udhcp_add_simple_option(packet, DHCP_MAX_SIZE, htons(IP_UDP_DHCP_SIZE)); 365 366 /* Add a "param req" option with the list of options we'd like to have 367 * from stubborn DHCP servers. Pull the data from the struct in common.c. 368 * No bounds checking because it goes towards the head of the packet. */ 369 end = udhcp_end_option(packet->options); 370 len = 0; 371 for (i = 0; (c = dhcp_optflags[i].code) != 0; i++) { 372 if (( (dhcp_optflags[i].flags & OPTION_REQ) 373 && !client_config.no_default_options 374 ) 375 || (client_config.opt_mask[c >> 3] & (1 << (c & 7))) 376 ) { 377 packet->options[end + OPT_DATA + len] = c; 378 len++; 379 } 380 } 381 if (len) { 382 packet->options[end + OPT_CODE] = DHCP_PARAM_REQ; 383 packet->options[end + OPT_LEN] = len; 384 packet->options[end + OPT_DATA + len] = DHCP_END; 385 } 386 387 if (client_config.vendorclass) 388 udhcp_add_binary_option(packet, client_config.vendorclass); 389 if (client_config.hostname) 390 udhcp_add_binary_option(packet, client_config.hostname); 391 if (client_config.fqdn) 392 udhcp_add_binary_option(packet, client_config.fqdn); 393 394 /* Add -x options if any */ 395 { 396 struct option_set *curr = client_config.options; 397 while (curr) { 398 udhcp_add_binary_option(packet, curr->data); 399 curr = curr->next; 400 } 401 // if (client_config.sname) 402 // strncpy((char*)packet->sname, client_config.sname, sizeof(packet->sname) - 1); 403 // if (client_config.boot_file) 404 // strncpy((char*)packet->file, client_config.boot_file, sizeof(packet->file) - 1); 405 } 406 } 407 408 /* RFC 2131 409 * 4.4.4 Use of broadcast and unicast 410 * 411 * The DHCP client broadcasts DHCPDISCOVER, DHCPREQUEST and DHCPINFORM 412 * messages, unless the client knows the address of a DHCP server. 413 * The client unicasts DHCPRELEASE messages to the server. Because 414 * the client is declining the use of the IP address supplied by the server, 415 * the client broadcasts DHCPDECLINE messages. 416 * 417 * When the DHCP client knows the address of a DHCP server, in either 418 * INIT or REBOOTING state, the client may use that address 419 * in the DHCPDISCOVER or DHCPREQUEST rather than the IP broadcast address. 420 * The client may also use unicast to send DHCPINFORM messages 421 * to a known DHCP server. If the client receives no response to DHCP 422 * messages sent to the IP address of a known DHCP server, the DHCP 423 * client reverts to using the IP broadcast address. 26 424 */ 27 static unsigned timeout; 28 static uint32_t requested_ip; /* = 0 */ 29 static uint32_t server_addr; 30 static int packet_num; /* = 0 */ 425 426 static int raw_bcast_from_client_config_ifindex(struct dhcp_packet *packet) 427 { 428 return udhcp_send_raw_packet(packet, 429 /*src*/ INADDR_ANY, CLIENT_PORT, 430 /*dst*/ INADDR_BROADCAST, SERVER_PORT, MAC_BCAST_ADDR, 431 client_config.ifindex); 432 } 433 434 /* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ 435 /* NOINLINE: limit stack usage in caller */ 436 static NOINLINE int send_discover(uint32_t xid, uint32_t requested) 437 { 438 struct dhcp_packet packet; 439 440 /* Fill in: op, htype, hlen, cookie, chaddr fields, 441 * random xid field (we override it below), 442 * client-id option (unless -C), message type option: 443 */ 444 init_packet(&packet, DHCPDISCOVER); 445 446 packet.xid = xid; 447 if (requested) 448 udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); 449 450 /* Add options: maxsize, 451 * optionally: hostname, fqdn, vendorclass, 452 * "param req" option according to -O, options specified with -x 453 */ 454 add_client_options(&packet); 455 456 bb_info_msg("Sending discover..."); 457 return raw_bcast_from_client_config_ifindex(&packet); 458 } 459 460 /* Broadcast a DHCP request message */ 461 /* RFC 2131 3.1 paragraph 3: 462 * "The client _broadcasts_ a DHCPREQUEST message..." 463 */ 464 /* NOINLINE: limit stack usage in caller */ 465 static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requested) 466 { 467 struct dhcp_packet packet; 468 struct in_addr addr; 469 470 /* 471 * RFC 2131 4.3.2 DHCPREQUEST message 472 * ... 473 * If the DHCPREQUEST message contains a 'server identifier' 474 * option, the message is in response to a DHCPOFFER message. 475 * Otherwise, the message is a request to verify or extend an 476 * existing lease. If the client uses a 'client identifier' 477 * in a DHCPREQUEST message, it MUST use that same 'client identifier' 478 * in all subsequent messages. If the client included a list 479 * of requested parameters in a DHCPDISCOVER message, it MUST 480 * include that list in all subsequent messages. 481 */ 482 /* Fill in: op, htype, hlen, cookie, chaddr fields, 483 * random xid field (we override it below), 484 * client-id option (unless -C), message type option: 485 */ 486 init_packet(&packet, DHCPREQUEST); 487 488 packet.xid = xid; 489 udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); 490 491 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); 492 493 /* Add options: maxsize, 494 * optionally: hostname, fqdn, vendorclass, 495 * "param req" option according to -O, and options specified with -x 496 */ 497 add_client_options(&packet); 498 499 addr.s_addr = requested; 500 bb_info_msg("Sending select for %s...", inet_ntoa(addr)); 501 return raw_bcast_from_client_config_ifindex(&packet); 502 } 503 504 /* Unicast or broadcast a DHCP renew message */ 505 /* NOINLINE: limit stack usage in caller */ 506 static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) 507 { 508 struct dhcp_packet packet; 509 510 /* 511 * RFC 2131 4.3.2 DHCPREQUEST message 512 * ... 513 * DHCPREQUEST generated during RENEWING state: 514 * 515 * 'server identifier' MUST NOT be filled in, 'requested IP address' 516 * option MUST NOT be filled in, 'ciaddr' MUST be filled in with 517 * client's IP address. In this situation, the client is completely 518 * configured, and is trying to extend its lease. This message will 519 * be unicast, so no relay agents will be involved in its 520 * transmission. Because 'giaddr' is therefore not filled in, the 521 * DHCP server will trust the value in 'ciaddr', and use it when 522 * replying to the client. 523 */ 524 /* Fill in: op, htype, hlen, cookie, chaddr fields, 525 * random xid field (we override it below), 526 * client-id option (unless -C), message type option: 527 */ 528 init_packet(&packet, DHCPREQUEST); 529 530 packet.xid = xid; 531 packet.ciaddr = ciaddr; 532 533 /* Add options: maxsize, 534 * optionally: hostname, fqdn, vendorclass, 535 * "param req" option according to -O, and options specified with -x 536 */ 537 add_client_options(&packet); 538 539 bb_info_msg("Sending renew..."); 540 if (server) 541 return udhcp_send_kernel_packet(&packet, 542 ciaddr, CLIENT_PORT, 543 server, SERVER_PORT); 544 return raw_bcast_from_client_config_ifindex(&packet); 545 } 546 547 #if ENABLE_FEATURE_UDHCPC_ARPING 548 /* Broadcast a DHCP decline message */ 549 /* NOINLINE: limit stack usage in caller */ 550 static NOINLINE int send_decline(uint32_t xid, uint32_t server, uint32_t requested) 551 { 552 struct dhcp_packet packet; 553 554 /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields, 555 * client-id option (unless -C), message type option: 556 */ 557 init_packet(&packet, DHCPDECLINE); 558 559 /* RFC 2131 says DHCPDECLINE's xid is randomly selected by client, 560 * but in case the server is buggy and wants DHCPDECLINE's xid 561 * to match the xid which started entire handshake, 562 * we use the same xid we used in initial DHCPDISCOVER: 563 */ 564 packet.xid = xid; 565 /* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */ 566 udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); 567 568 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); 569 570 bb_info_msg("Sending decline..."); 571 return raw_bcast_from_client_config_ifindex(&packet); 572 } 573 #endif 574 575 /* Unicast a DHCP release message */ 576 static int send_release(uint32_t server, uint32_t ciaddr) 577 { 578 struct dhcp_packet packet; 579 580 /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields, 581 * client-id option (unless -C), message type option: 582 */ 583 init_packet(&packet, DHCPRELEASE); 584 585 /* DHCPRELEASE uses ciaddr, not "requested ip", to store IP being released */ 586 packet.ciaddr = ciaddr; 587 588 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); 589 590 bb_info_msg("Sending release..."); 591 return udhcp_send_kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT); 592 } 593 594 /* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */ 595 /* NOINLINE: limit stack usage in caller */ 596 static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) 597 { 598 int bytes; 599 struct ip_udp_dhcp_packet packet; 600 uint16_t check; 601 602 memset(&packet, 0, sizeof(packet)); 603 bytes = safe_read(fd, &packet, sizeof(packet)); 604 if (bytes < 0) { 605 log1("Packet read error, ignoring"); 606 /* NB: possible down interface, etc. Caller should pause. */ 607 return bytes; /* returns -1 */ 608 } 609 610 if (bytes < (int) (sizeof(packet.ip) + sizeof(packet.udp))) { 611 log1("Packet is too short, ignoring"); 612 return -2; 613 } 614 615 if (bytes < ntohs(packet.ip.tot_len)) { 616 /* packet is bigger than sizeof(packet), we did partial read */ 617 log1("Oversized packet, ignoring"); 618 return -2; 619 } 620 621 /* ignore any extra garbage bytes */ 622 bytes = ntohs(packet.ip.tot_len); 623 624 /* make sure its the right packet for us, and that it passes sanity checks */ 625 if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION 626 || packet.ip.ihl != (sizeof(packet.ip) >> 2) 627 || packet.udp.dest != htons(CLIENT_PORT) 628 /* || bytes > (int) sizeof(packet) - can't happen */ 629 || ntohs(packet.udp.len) != (uint16_t)(bytes - sizeof(packet.ip)) 630 ) { 631 log1("Unrelated/bogus packet, ignoring"); 632 return -2; 633 } 634 635 /* verify IP checksum */ 636 check = packet.ip.check; 637 packet.ip.check = 0; 638 if (check != udhcp_checksum(&packet.ip, sizeof(packet.ip))) { 639 log1("Bad IP header checksum, ignoring"); 640 return -2; 641 } 642 643 /* verify UDP checksum. IP header has to be modified for this */ 644 memset(&packet.ip, 0, offsetof(struct iphdr, protocol)); 645 /* ip.xx fields which are not memset: protocol, check, saddr, daddr */ 646 packet.ip.tot_len = packet.udp.len; /* yes, this is needed */ 647 check = packet.udp.check; 648 packet.udp.check = 0; 649 if (check && check != udhcp_checksum(&packet, bytes)) { 650 log1("Packet with bad UDP checksum received, ignoring"); 651 return -2; 652 } 653 654 memcpy(dhcp_pkt, &packet.data, bytes - (sizeof(packet.ip) + sizeof(packet.udp))); 655 656 if (dhcp_pkt->cookie != htonl(DHCP_MAGIC)) { 657 bb_info_msg("Packet with bad magic, ignoring"); 658 return -2; 659 } 660 log1("Got valid DHCP packet"); 661 udhcp_dump_packet(dhcp_pkt); 662 return bytes - (sizeof(packet.ip) + sizeof(packet.udp)); 663 } 664 665 666 /*** Main ***/ 667 31 668 static int sockfd = -1; 32 669 33 #define LISTEN_NONE 0670 #define LISTEN_NONE 0 34 671 #define LISTEN_KERNEL 1 35 #define LISTEN_RAW 2672 #define LISTEN_RAW 2 36 673 static smallint listen_mode; 37 674 675 /* initial state: (re)start DHCP negotiation */ 676 #define INIT_SELECTING 0 677 /* discover was sent, DHCPOFFER reply received */ 678 #define REQUESTING 1 679 /* select/renew was sent, DHCPACK reply received */ 680 #define BOUND 2 681 /* half of lease passed, want to renew it by sending unicast renew requests */ 682 #define RENEWING 3 683 /* renew requests were not answered, lease is almost over, send broadcast renew */ 684 #define REBINDING 4 685 /* manually requested renew (SIGUSR1) */ 686 #define RENEW_REQUESTED 5 687 /* release, possibly manually requested (SIGUSR2) */ 688 #define RELEASED 6 38 689 static smallint state; 39 690 40 struct client_config_t client_config; 41 42 43 /* just a little helper */ 44 static void change_mode(int new_mode) 45 { 46 DEBUG("entering %s listen mode", 47 new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none"); 691 static int udhcp_raw_socket(int ifindex) 692 { 693 int fd; 694 struct sockaddr_ll sock; 695 696 /* 697 * Comment: 698 * 699 * I've selected not to see LL header, so BPF doesn't see it, too. 700 * The filter may also pass non-IP and non-ARP packets, but we do 701 * a more complete check when receiving the message in userspace. 702 * 703 * and filter shamelessly stolen from: 704 * 705 * http://www.flamewarmaster.de/software/dhcpclient/ 706 * 707 * There are a few other interesting ideas on that page (look under 708 * "Motivation"). Use of netlink events is most interesting. Think 709 * of various network servers listening for events and reconfiguring. 710 * That would obsolete sending HUP signals and/or make use of restarts. 711 * 712 * Copyright: 2006, 2007 Stefan Rompf <sux@loplof.de>. 713 * License: GPL v2. 714 * 715 * TODO: make conditional? 716 */ 717 #define SERVER_AND_CLIENT_PORTS ((67 << 16) + 68) 718 static const struct sock_filter filter_instr[] = { 719 /* check for udp */ 720 BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9), 721 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 2, 0), /* L5, L1, is UDP? */ 722 /* ugly check for arp on ethernet-like and IPv4 */ 723 BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2), /* L1: */ 724 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x08000604, 3, 4), /* L3, L4 */ 725 /* skip IP header */ 726 BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), /* L5: */ 727 /* check udp source and destination ports */ 728 BPF_STMT(BPF_LD|BPF_W|BPF_IND, 0), 729 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SERVER_AND_CLIENT_PORTS, 0, 1), /* L3, L4 */ 730 /* returns */ 731 BPF_STMT(BPF_RET|BPF_K, 0x0fffffff ), /* L3: pass */ 732 BPF_STMT(BPF_RET|BPF_K, 0), /* L4: reject */ 733 }; 734 static const struct sock_fprog filter_prog = { 735 .len = sizeof(filter_instr) / sizeof(filter_instr[0]), 736 /* casting const away: */ 737 .filter = (struct sock_filter *) filter_instr, 738 }; 739 740 log1("Opening raw socket on ifindex %d", ifindex); //log2? 741 742 fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); 743 log1("Got raw socket fd %d", fd); //log2? 744 745 if (SERVER_PORT == 67 && CLIENT_PORT == 68) { 746 /* Use only if standard ports are in use */ 747 /* Ignoring error (kernel may lack support for this) */ 748 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, 749 sizeof(filter_prog)) >= 0) 750 log1("Attached filter to raw socket fd %d", fd); // log? 751 } 752 753 sock.sll_family = AF_PACKET; 754 sock.sll_protocol = htons(ETH_P_IP); 755 sock.sll_ifindex = ifindex; 756 xbind(fd, (struct sockaddr *) &sock, sizeof(sock)); 757 log1("Created raw socket"); 758 759 return fd; 760 } 761 762 static void change_listen_mode(int new_mode) 763 { 764 log1("Entering listen mode: %s", 765 new_mode != LISTEN_NONE 766 ? (new_mode == LISTEN_KERNEL ? "kernel" : "raw") 767 : "none" 768 ); 769 770 listen_mode = new_mode; 48 771 if (sockfd >= 0) { 49 772 close(sockfd); 50 773 sockfd = -1; 51 774 } 52 listen_mode = new_mode; 53 } 54 55 56 /* perform a renew */ 775 if (new_mode == LISTEN_KERNEL) 776 sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_config.interface); 777 else if (new_mode != LISTEN_NONE) 778 sockfd = udhcp_raw_socket(client_config.ifindex); 779 /* else LISTEN_NONE: sockfd stays closed */ 780 } 781 57 782 static void perform_renew(void) 58 783 { … … 60 785 switch (state) { 61 786 case BOUND: 62 change_ mode(LISTEN_KERNEL);787 change_listen_mode(LISTEN_KERNEL); 63 788 case RENEWING: 64 789 case REBINDING: … … 69 794 case REQUESTING: 70 795 case RELEASED: 71 change_ mode(LISTEN_RAW);796 change_listen_mode(LISTEN_RAW); 72 797 state = INIT_SELECTING; 73 798 break; … … 75 800 break; 76 801 } 77 78 /* start things over */ 79 packet_num = 0; 80 81 /* Kill any timeouts because the user wants this to hurry along */ 82 timeout = 0; 83 } 84 85 86 /* perform a release */ 87 static void perform_release(void) 802 } 803 804 static void perform_release(uint32_t requested_ip, uint32_t server_addr) 88 805 { 89 806 char buffer[sizeof("255.255.255.255")]; … … 102 819 bb_info_msg("Entering released state"); 103 820 104 change_ mode(LISTEN_NONE);821 change_listen_mode(LISTEN_NONE); 105 822 state = RELEASED; 106 timeout = INT_MAX; 107 } 108 109 110 static void client_background(void) 111 { 112 #if !BB_MMU 113 bb_error_msg("cannot background in uclinux (yet)"); 114 /* ... mainly because udhcpc calls client_background() 115 * in _the _middle _of _udhcpc _run_, not at the start! 116 * If that will be properly disabled for NOMMU, client_background() 117 * will work on NOMMU too */ 118 #else 119 bb_daemonize(0); 120 logmode &= ~LOGMODE_STDIO; 121 /* rewrite pidfile, as our pid is different now */ 122 write_pidfile(client_config.pidfile); 123 #endif 124 /* Do not fork again. */ 125 client_config.foreground = 1; 126 client_config.background_if_no_lease = 0; 127 } 128 823 } 129 824 130 825 static uint8_t* alloc_dhcp_option(int code, const char *str, int extra) 131 826 { 132 827 uint8_t *storage; 133 int len = strlen(str); 134 if (len > 255) len = 255; 828 int len = strnlen(str, 255); 135 829 storage = xzalloc(len + extra + OPT_DATA); 136 830 storage[OPT_CODE] = code; … … 140 834 } 141 835 142 143 int udhcpc_main(int argc, char **argv); 144 int udhcpc_main(int argc, char **argv) 836 #if BB_MMU 837 static void client_background(void) 838 { 839 bb_daemonize(0); 840 logmode &= ~LOGMODE_STDIO; 841 /* rewrite pidfile, as our pid is different now */ 842 write_pidfile(client_config.pidfile); 843 } 844 #endif 845 846 //usage:#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 847 //usage:# define IF_UDHCP_VERBOSE(...) __VA_ARGS__ 848 //usage:#else 849 //usage:# define IF_UDHCP_VERBOSE(...) 850 //usage:#endif 851 //usage:#define udhcpc_trivial_usage 852 //usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"oCR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n" 853 //usage: " [-H HOSTNAME] [-V VENDOR] [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]") 854 //usage:#define udhcpc_full_usage "\n" 855 //usage: IF_LONG_OPTS( 856 //usage: "\n -i,--interface IFACE Interface to use (default eth0)" 857 //usage: "\n -p,--pidfile FILE Create pidfile" 858 //usage: "\n -s,--script PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" 859 //usage: "\n -t,--retries N Send up to N discover packets" 860 //usage: "\n -T,--timeout N Pause between packets (default 3 seconds)" 861 //usage: "\n -A,--tryagain N Wait N seconds after failure (default 20)" 862 //usage: "\n -f,--foreground Run in foreground" 863 //usage: USE_FOR_MMU( 864 //usage: "\n -b,--background Background if lease is not obtained" 865 //usage: ) 866 //usage: "\n -n,--now Exit if lease is not obtained" 867 //usage: "\n -q,--quit Exit after obtaining lease" 868 //usage: "\n -R,--release Release IP on exit" 869 //usage: "\n -S,--syslog Log to syslog too" 870 //usage: IF_FEATURE_UDHCP_PORT( 871 //usage: "\n -P,--client-port N Use port N (default 68)" 872 //usage: ) 873 //usage: IF_FEATURE_UDHCPC_ARPING( 874 //usage: "\n -a,--arping Use arping to validate offered address" 875 //usage: ) 876 //usage: "\n -O,--request-option OPT Request option OPT from server (cumulative)" 877 //usage: "\n -o,--no-default-options Don't request any options (unless -O is given)" 878 //usage: "\n -r,--request IP Request this IP address" 879 //usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" 880 //usage: "\n Examples of string, numeric, and hex byte opts:" 881 //usage: "\n -x hostname:bbox - option 12" 882 //usage: "\n -x lease:3600 - option 51 (lease time)" 883 //usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" 884 //usage: "\n -F,--fqdn NAME Ask server to update DNS mapping for NAME" 885 //usage: "\n -H,-h,--hostname NAME Send NAME as client hostname (default none)" 886 //usage: "\n -V,--vendorclass VENDOR Vendor identifier (default 'udhcp VERSION')" 887 //usage: "\n -C,--clientid-none Don't send MAC as client identifier" 888 //usage: IF_UDHCP_VERBOSE( 889 //usage: "\n -v Verbose" 890 //usage: ) 891 //usage: ) 892 //usage: IF_NOT_LONG_OPTS( 893 //usage: "\n -i IFACE Interface to use (default eth0)" 894 //usage: "\n -p FILE Create pidfile" 895 //usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" 896 //usage: "\n -t N Send up to N discover packets" 897 //usage: "\n -T N Pause between packets (default 3 seconds)" 898 //usage: "\n -A N Wait N seconds (default 20) after failure" 899 //usage: "\n -f Run in foreground" 900 //usage: USE_FOR_MMU( 901 //usage: "\n -b Background if lease is not obtained" 902 //usage: ) 903 //usage: "\n -n Exit if lease is not obtained" 904 //usage: "\n -q Exit after obtaining lease" 905 //usage: "\n -R Release IP on exit" 906 //usage: "\n -S Log to syslog too" 907 //usage: IF_FEATURE_UDHCP_PORT( 908 //usage: "\n -P N Use port N (default 68)" 909 //usage: ) 910 //usage: IF_FEATURE_UDHCPC_ARPING( 911 //usage: "\n -a Use arping to validate offered address" 912 //usage: ) 913 //usage: "\n -O OPT Request option OPT from server (cumulative)" 914 //usage: "\n -o Don't request any options (unless -O is given)" 915 //usage: "\n -r IP Request this IP address" 916 //usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" 917 //usage: "\n Examples of string, numeric, and hex byte opts:" 918 //usage: "\n -x hostname:bbox - option 12" 919 //usage: "\n -x lease:3600 - option 51 (lease time)" 920 //usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" 921 //usage: "\n -F NAME Ask server to update DNS mapping for NAME" 922 //usage: "\n -H,-h NAME Send NAME as client hostname (default none)" 923 //usage: "\n -V VENDOR Vendor identifier (default 'udhcp VERSION')" 924 //usage: "\n -C Don't send MAC as client identifier" 925 //usage: IF_UDHCP_VERBOSE( 926 //usage: "\n -v Verbose" 927 //usage: ) 928 //usage: ) 929 930 int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 931 int udhcpc_main(int argc UNUSED_PARAM, char **argv) 145 932 { 146 933 uint8_t *temp, *message; 147 char *str_c, *str_V, *str_h, *str_F, *str_r, *str_T, *str_t; 934 const char *str_V, *str_h, *str_F, *str_r; 935 IF_FEATURE_UDHCP_PORT(char *str_P;) 936 void *clientid_mac_ptr; 937 llist_t *list_O = NULL; 938 llist_t *list_x = NULL; 939 int tryagain_timeout = 20; 940 int discover_timeout = 3; 941 int discover_retries = 3; 942 uint32_t server_addr = server_addr; /* for compiler */ 943 uint32_t requested_ip = 0; 148 944 uint32_t xid = 0; 149 uint32_t lease = 0; /* can be given as 32-bit quantity */150 unsigned t1 = 0, t2 = 0; /* what a wonderful names */151 unsigned start = 0;152 unsigned now;945 uint32_t lease_seconds = 0; /* can be given as 32-bit quantity */ 946 int packet_num; 947 int timeout; /* must be signed */ 948 unsigned already_waited_sec; 153 949 unsigned opt; 154 950 int max_fd; 155 951 int retval; 156 int len;157 952 struct timeval tv; 158 struct in_addr temp_addr; 159 struct dhcpMessage packet; 953 struct dhcp_packet packet; 160 954 fd_set rfds; 161 955 162 enum { 163 OPT_c = 1 << 0, 164 OPT_C = 1 << 1, 165 OPT_V = 1 << 2, 166 OPT_f = 1 << 3, 167 OPT_b = 1 << 4, 168 OPT_H = 1 << 5, 169 OPT_h = 1 << 6, 170 OPT_F = 1 << 7, 171 OPT_i = 1 << 8, 172 OPT_n = 1 << 9, 173 OPT_p = 1 << 10, 174 OPT_q = 1 << 11, 175 OPT_R = 1 << 12, 176 OPT_r = 1 << 13, 177 OPT_s = 1 << 14, 178 OPT_T = 1 << 15, 179 OPT_t = 1 << 16, 180 OPT_v = 1 << 17, 181 OPT_S = 1 << 18, 182 }; 183 #if ENABLE_GETOPT_LONG 956 #if ENABLE_LONG_OPTS 184 957 static const char udhcpc_longopts[] ALIGN1 = 185 "clientid\0" Required_argument "c" 186 "clientid-none\0" No_argument "C" 187 "vendorclass\0" Required_argument "V" 188 "foreground\0" No_argument "f" 189 "background\0" No_argument "b" 190 "hostname\0" Required_argument "H" 191 "hostname\0" Required_argument "h" 192 "fqdn\0" Required_argument "F" 193 "interface\0" Required_argument "i" 194 "now\0" No_argument "n" 195 "pidfile\0" Required_argument "p" 196 "quit\0" No_argument "q" 197 "release\0" No_argument "R" 198 "request\0" Required_argument "r" 199 "script\0" Required_argument "s" 200 "timeout\0" Required_argument "T" 201 "version\0" No_argument "v" 202 "retries\0" Required_argument "t" 203 "syslog\0" No_argument "S" 958 "clientid-none\0" No_argument "C" 959 "vendorclass\0" Required_argument "V" 960 "hostname\0" Required_argument "H" 961 "fqdn\0" Required_argument "F" 962 "interface\0" Required_argument "i" 963 "now\0" No_argument "n" 964 "pidfile\0" Required_argument "p" 965 "quit\0" No_argument "q" 966 "release\0" No_argument "R" 967 "request\0" Required_argument "r" 968 "script\0" Required_argument "s" 969 "timeout\0" Required_argument "T" 970 "version\0" No_argument "v" 971 "retries\0" Required_argument "t" 972 "tryagain\0" Required_argument "A" 973 "syslog\0" No_argument "S" 974 "request-option\0" Required_argument "O" 975 "no-default-options\0" No_argument "o" 976 "foreground\0" No_argument "f" 977 "background\0" No_argument "b" 978 IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument "a") 979 IF_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P") 204 980 ; 205 981 #endif 206 /* Default options. */ 982 enum { 983 OPT_C = 1 << 0, 984 OPT_V = 1 << 1, 985 OPT_H = 1 << 2, 986 OPT_h = 1 << 3, 987 OPT_F = 1 << 4, 988 OPT_i = 1 << 5, 989 OPT_n = 1 << 6, 990 OPT_p = 1 << 7, 991 OPT_q = 1 << 8, 992 OPT_R = 1 << 9, 993 OPT_r = 1 << 10, 994 OPT_s = 1 << 11, 995 OPT_T = 1 << 12, 996 OPT_t = 1 << 13, 997 OPT_S = 1 << 14, 998 OPT_A = 1 << 15, 999 OPT_O = 1 << 16, 1000 OPT_o = 1 << 17, 1001 OPT_x = 1 << 18, 1002 OPT_f = 1 << 19, 1003 /* The rest has variable bit positions, need to be clever */ 1004 OPTBIT_f = 19, 1005 USE_FOR_MMU( OPTBIT_b,) 1006 IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) 1007 IF_FEATURE_UDHCP_PORT( OPTBIT_P,) 1008 USE_FOR_MMU( OPT_b = 1 << OPTBIT_b,) 1009 IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,) 1010 IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,) 1011 }; 1012 1013 /* Default options */ 1014 IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;) 1015 IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;) 207 1016 client_config.interface = "eth0"; 208 client_config.script = DEFAULT_SCRIPT; 209 client_config.retries = 3; 210 client_config.timeout = 3; 1017 client_config.script = CONFIG_UDHCPC_DEFAULT_SCRIPT; 1018 str_V = "udhcp "BB_VER; 211 1019 212 1020 /* Parse command line */ 213 opt_complementary = "c--C:C--c" // mutually exclusive214 ":hH:Hh"; // -h and -H are the same215 #if ENABLE_GETOPT_LONG216 applet_long_options = udhcpc_longopts;1021 /* O,x: list; -T,-t,-A take numeric param */ 1022 opt_complementary = "O::x::T+:t+:A+" 1023 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 1024 ":vv" 217 1025 #endif 218 opt = getopt32(argv, "c:CV:fbH:h:F:i:np:qRr:s:T:t:vS", 219 &str_c, &str_V, &str_h, &str_h, &str_F, 220 &client_config.interface, &client_config.pidfile, &str_r, 221 &client_config.script, &str_T, &str_t 1026 ; 1027 IF_LONG_OPTS(applet_long_options = udhcpc_longopts;) 1028 opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:f" 1029 USE_FOR_MMU("b") 1030 IF_FEATURE_UDHCPC_ARPING("a") 1031 IF_FEATURE_UDHCP_PORT("P:") 1032 "v" 1033 , &str_V, &str_h, &str_h, &str_F 1034 , &client_config.interface, &client_config.pidfile, &str_r /* i,p */ 1035 , &client_config.script /* s */ 1036 , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */ 1037 , &list_O 1038 , &list_x 1039 IF_FEATURE_UDHCP_PORT(, &str_P) 1040 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 1041 , &dhcp_verbose 1042 #endif 222 1043 ); 223 224 if (opt & OPT_c) 225 client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, str_c, 0); 226 //if (opt & OPT_C) 227 if (opt & OPT_V) 228 client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0); 229 if (opt & OPT_f) 230 client_config.foreground = 1; 231 if (opt & OPT_b) 232 client_config.background_if_no_lease = 1; 233 if (opt & OPT_h) 1044 if (opt & (OPT_h|OPT_H)) 234 1045 client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0); 235 1046 if (opt & OPT_F) { 1047 /* FQDN option format: [0x51][len][flags][0][0]<fqdn> */ 236 1048 client_config.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3); 237 /* Flags: 0000NEOS 238 S: 1 => Client requests Server to update A RR in DNS as well as PTR 239 O: 1 => Server indicates to client that DNS has been updated regardless 240 E: 1 => Name data is DNS format, i.e. <4>host<6>domain<4>com<0> not "host.domain.com" 241 N: 1 => Client requests Server to not update DNS 242 */ 1049 /* Flag bits: 0000NEOS 1050 * S: 1 = Client requests server to update A RR in DNS as well as PTR 1051 * O: 1 = Server indicates to client that DNS has been updated regardless 1052 * E: 1 = Name is in DNS format, i.e. <4>host<6>domain<3>com<0>, 1053 * not "host.domain.com". Format 0 is obsolete. 1054 * N: 1 = Client requests server to not update DNS (S must be 0 then) 1055 * Two [0] bytes which follow are deprecated and must be 0. 1056 */ 243 1057 client_config.fqdn[OPT_DATA + 0] = 0x1; 244 /* client_config.fqdn[OPT_DATA + 1] = 0; - redundant */ 245 /* client_config.fqdn[OPT_DATA + 2] = 0; - redundant */ 246 } 247 // if (opt & OPT_i) client_config.interface = ... 248 if (opt & OPT_n) 249 client_config.abort_if_no_lease = 1; 250 // if (opt & OPT_p) client_config.pidfile = ... 251 if (opt & OPT_q) 252 client_config.quit_after_lease = 1; 253 if (opt & OPT_R) 254 client_config.release_on_quit = 1; 1058 /*client_config.fqdn[OPT_DATA + 1] = 0; - xzalloc did it */ 1059 /*client_config.fqdn[OPT_DATA + 2] = 0; */ 1060 } 255 1061 if (opt & OPT_r) 256 1062 requested_ip = inet_addr(str_r); 257 // if (opt & OPT_s) client_config.script = ... 258 if (opt & OPT_T) 259 client_config.timeout = xatoi_u(str_T); 260 if (opt & OPT_t) 261 client_config.retries = xatoi_u(str_t); 262 if (opt & OPT_v) { 263 printf("version %s\n", BB_VER); 264 return 0; 265 } 266 1063 #if ENABLE_FEATURE_UDHCP_PORT 1064 if (opt & OPT_P) { 1065 CLIENT_PORT = xatou16(str_P); 1066 SERVER_PORT = CLIENT_PORT - 1; 1067 } 1068 #endif 1069 if (opt & OPT_o) 1070 client_config.no_default_options = 1; 1071 while (list_O) { 1072 char *optstr = llist_pop(&list_O); 1073 unsigned n = udhcp_option_idx(optstr); 1074 n = dhcp_optflags[n].code; 1075 client_config.opt_mask[n >> 3] |= 1 << (n & 7); 1076 } 1077 while (list_x) { 1078 char *optstr = llist_pop(&list_x); 1079 char *colon = strchr(optstr, ':'); 1080 if (colon) 1081 *colon = ' '; 1082 /* now it looks similar to udhcpd's config file line: 1083 * "optname optval", using the common routine: */ 1084 udhcp_str2optset(optstr, &client_config.options); 1085 } 1086 1087 if (udhcp_read_interface(client_config.interface, 1088 &client_config.ifindex, 1089 NULL, 1090 client_config.client_mac) 1091 ) { 1092 return 1; 1093 } 1094 1095 clientid_mac_ptr = NULL; 1096 if (!(opt & OPT_C) && !udhcp_find_option(client_config.options, DHCP_CLIENT_ID)) { 1097 /* not suppressed and not set, set the default client ID */ 1098 client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7); 1099 client_config.clientid[OPT_DATA] = 1; /* type: ethernet */ 1100 clientid_mac_ptr = client_config.clientid + OPT_DATA+1; 1101 memcpy(clientid_mac_ptr, client_config.client_mac, 6); 1102 } 1103 if (str_V[0] != '\0') 1104 client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0); 1105 #if !BB_MMU 1106 /* on NOMMU reexec (i.e., background) early */ 1107 if (!(opt & OPT_f)) { 1108 bb_daemonize_or_rexec(0 /* flags */, argv); 1109 logmode = LOGMODE_NONE; 1110 } 1111 #endif 267 1112 if (opt & OPT_S) { 268 openlog(applet_name, LOG_PID, LOG_ LOCAL0);1113 openlog(applet_name, LOG_PID, LOG_DAEMON); 269 1114 logmode |= LOGMODE_SYSLOG; 270 1115 } 271 272 if (read_interface(client_config.interface, &client_config.ifindex,273 NULL, client_config.arp))274 return 1;275 1116 276 1117 /* Make sure fd 0,1,2 are open */ … … 278 1119 /* Equivalent of doing a fflush after every \n */ 279 1120 setlinebuf(stdout); 280 281 1121 /* Create pidfile */ 282 1122 write_pidfile(client_config.pidfile); 283 /* if (!..) bb_perror_msg("cannot create pidfile %s", pidfile); */ 284 285 /* Goes to stdout and possibly syslog */ 286 bb_info_msg("%s (v%s) started", applet_name, BB_VER); 287 288 /* if not set, and not suppressed, setup the default client ID */ 289 if (!client_config.clientid && !(opt & OPT_C)) { 290 client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7); 291 client_config.clientid[OPT_DATA] = 1; 292 memcpy(client_config.clientid + OPT_DATA+1, client_config.arp, 6); 293 } 294 295 if (!client_config.vendorclass) 296 client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, "udhcp "BB_VER, 0); 297 298 /* setup the signal pipe */ 1123 /* Goes to stdout (unless NOMMU) and possibly syslog */ 1124 bb_info_msg("%s (v"BB_VER") started", applet_name); 1125 /* Set up the signal pipe */ 299 1126 udhcp_sp_setup(); 1127 /* We want random_xid to be random... */ 1128 srand(monotonic_us()); 300 1129 301 1130 state = INIT_SELECTING; 302 1131 udhcp_run_script(NULL, "deconfig"); 303 change_mode(LISTEN_RAW); 304 tv.tv_sec = 0; 305 goto jump_in; 306 1132 change_listen_mode(LISTEN_RAW); 1133 packet_num = 0; 1134 timeout = 0; 1135 already_waited_sec = 0; 1136 1137 /* Main event loop. select() waits on signal pipe and possibly 1138 * on sockfd. 1139 * "continue" statements in code below jump to the top of the loop. 1140 */ 307 1141 for (;;) { 308 tv.tv_sec = timeout - monotonic_sec(); 309 jump_in: 1142 /* silence "uninitialized!" warning */ 1143 unsigned timestamp_before_wait = timestamp_before_wait; 1144 1145 //bb_error_msg("sockfd:%d, listen_mode:%d", sockfd, listen_mode); 1146 1147 /* Was opening raw or udp socket here 1148 * if (listen_mode != LISTEN_NONE && sockfd < 0), 1149 * but on fast network renew responses return faster 1150 * than we open sockets. Thus this code is moved 1151 * to change_listen_mode(). Thus we open listen socket 1152 * BEFORE we send renew request (see "case BOUND:"). */ 1153 1154 max_fd = udhcp_sp_fd_set(&rfds, sockfd); 1155 1156 tv.tv_sec = timeout - already_waited_sec; 310 1157 tv.tv_usec = 0; 311 312 if (listen_mode != LISTEN_NONE && sockfd < 0) { 313 if (listen_mode == LISTEN_KERNEL) 314 sockfd = listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_config.interface); 315 else 316 sockfd = raw_socket(client_config.ifindex); 317 } 318 max_fd = udhcp_sp_fd_set(&rfds, sockfd); 319 320 retval = 0; /* If we already timed out, fall through, else... */ 321 if (tv.tv_sec > 0) { 322 DEBUG("Waiting on select..."); 1158 retval = 0; 1159 /* If we already timed out, fall through with retval = 0, else... */ 1160 if ((int)tv.tv_sec > 0) { 1161 timestamp_before_wait = (unsigned)monotonic_sec(); 1162 log1("Waiting on select..."); 323 1163 retval = select(max_fd + 1, &rfds, NULL, NULL, &tv); 324 }325 326 now = monotonic_sec();327 if (retval < 0) {328 /* EINTR? signal was caught, don't panic */329 if (errno != EINTR) {1164 if (retval < 0) { 1165 /* EINTR? A signal was caught, don't panic */ 1166 if (errno == EINTR) { 1167 already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait; 1168 continue; 1169 } 330 1170 /* Else: an error occured, panic! */ 331 1171 bb_perror_msg_and_die("select"); 332 1172 } 333 } else if (retval == 0) { 334 /* timeout dropped to zero */ 1173 } 1174 1175 /* If timeout dropped to zero, time to become active: 1176 * resend discover/renew/whatever 1177 */ 1178 if (retval == 0) { 1179 /* When running on a bridge, the ifindex may have changed 1180 * (e.g. if member interfaces were added/removed 1181 * or if the status of the bridge changed). 1182 * Refresh ifindex and client_mac: 1183 */ 1184 if (udhcp_read_interface(client_config.interface, 1185 &client_config.ifindex, 1186 NULL, 1187 client_config.client_mac) 1188 ) { 1189 return 1; /* iface is gone? */ 1190 } 1191 if (clientid_mac_ptr) 1192 memcpy(clientid_mac_ptr, client_config.client_mac, 6); 1193 1194 /* We will restart the wait in any case */ 1195 already_waited_sec = 0; 1196 335 1197 switch (state) { 336 1198 case INIT_SELECTING: 337 if (packet_num < client_config.retries) {1199 if (packet_num < discover_retries) { 338 1200 if (packet_num == 0) 339 1201 xid = random_xid(); 340 341 /* send discover packet */ 342 send_discover(xid, requested_ip); /* broadcast */ 343 344 timeout = now + client_config.timeout; 1202 /* broadcast */ 1203 send_discover(xid, requested_ip); 1204 timeout = discover_timeout; 345 1205 packet_num++; 1206 continue; 1207 } 1208 leasefail: 1209 udhcp_run_script(NULL, "leasefail"); 1210 #if BB_MMU /* -b is not supported on NOMMU */ 1211 if (opt & OPT_b) { /* background if no lease */ 1212 bb_info_msg("No lease, forking to background"); 1213 client_background(); 1214 /* do not background again! */ 1215 opt = ((opt & ~OPT_b) | OPT_f); 1216 } else 1217 #endif 1218 if (opt & OPT_n) { /* abort if no lease */ 1219 bb_info_msg("No lease, failing"); 1220 retval = 1; 1221 goto ret; 1222 } 1223 /* wait before trying again */ 1224 timeout = tryagain_timeout; 1225 packet_num = 0; 1226 continue; 1227 case REQUESTING: 1228 if (packet_num < discover_retries) { 1229 /* send broadcast select packet */ 1230 send_select(xid, server_addr, requested_ip); 1231 timeout = discover_timeout; 1232 packet_num++; 1233 continue; 1234 } 1235 /* Timed out, go back to init state. 1236 * "discover...select...discover..." loops 1237 * were seen in the wild. Treat them similarly 1238 * to "no response to discover" case */ 1239 change_listen_mode(LISTEN_RAW); 1240 state = INIT_SELECTING; 1241 goto leasefail; 1242 case BOUND: 1243 /* 1/2 lease passed, enter renewing state */ 1244 state = RENEWING; 1245 change_listen_mode(LISTEN_KERNEL); 1246 log1("Entering renew state"); 1247 /* fall right through */ 1248 case RENEW_REQUESTED: /* manual (SIGUSR1) renew */ 1249 case_RENEW_REQUESTED: 1250 case RENEWING: 1251 if (timeout > 60) { 1252 /* send an unicast renew request */ 1253 /* Sometimes observed to fail (EADDRNOTAVAIL) to bind 1254 * a new UDP socket for sending inside send_renew. 1255 * I hazard to guess existing listening socket 1256 * is somehow conflicting with it, but why is it 1257 * not deterministic then?! Strange. 1258 * Anyway, it does recover by eventually failing through 1259 * into INIT_SELECTING state. 1260 */ 1261 send_renew(xid, server_addr, requested_ip); 1262 timeout >>= 1; 1263 continue; 1264 } 1265 /* Timed out, enter rebinding state */ 1266 log1("Entering rebinding state"); 1267 state = REBINDING; 1268 /* fall right through */ 1269 case REBINDING: 1270 /* Switch to bcast receive */ 1271 change_listen_mode(LISTEN_RAW); 1272 /* Lease is *really* about to run out, 1273 * try to find DHCP server using broadcast */ 1274 if (timeout > 0) { 1275 /* send a broadcast renew request */ 1276 send_renew(xid, 0 /*INADDR_ANY*/, requested_ip); 1277 timeout >>= 1; 1278 continue; 1279 } 1280 /* Timed out, enter init state */ 1281 bb_info_msg("Lease lost, entering init state"); 1282 udhcp_run_script(NULL, "deconfig"); 1283 state = INIT_SELECTING; 1284 /*timeout = 0; - already is */ 1285 packet_num = 0; 1286 continue; 1287 /* case RELEASED: */ 1288 } 1289 /* yah, I know, *you* say it would never happen */ 1290 timeout = INT_MAX; 1291 continue; /* back to main loop */ 1292 } /* if select timed out */ 1293 1294 /* select() didn't timeout, something happened */ 1295 1296 /* Is it a signal? */ 1297 /* note: udhcp_sp_read checks FD_ISSET before reading */ 1298 switch (udhcp_sp_read(&rfds)) { 1299 case SIGUSR1: 1300 perform_renew(); 1301 if (state == RENEW_REQUESTED) 1302 goto case_RENEW_REQUESTED; 1303 /* Start things over */ 1304 packet_num = 0; 1305 /* Kill any timeouts, user wants this to hurry along */ 1306 timeout = 0; 1307 continue; 1308 case SIGUSR2: 1309 perform_release(requested_ip, server_addr); 1310 timeout = INT_MAX; 1311 continue; 1312 case SIGTERM: 1313 bb_info_msg("Received SIGTERM"); 1314 if (opt & OPT_R) /* release on quit */ 1315 perform_release(requested_ip, server_addr); 1316 goto ret0; 1317 } 1318 1319 /* Is it a packet? */ 1320 if (listen_mode == LISTEN_NONE || !FD_ISSET(sockfd, &rfds)) 1321 continue; /* no */ 1322 1323 { 1324 int len; 1325 1326 /* A packet is ready, read it */ 1327 if (listen_mode == LISTEN_KERNEL) 1328 len = udhcp_recv_kernel_packet(&packet, sockfd); 1329 else 1330 len = udhcp_recv_raw_packet(&packet, sockfd); 1331 if (len == -1) { 1332 /* Error is severe, reopen socket */ 1333 bb_info_msg("Read error: %s, reopening socket", strerror(errno)); 1334 sleep(discover_timeout); /* 3 seconds by default */ 1335 change_listen_mode(listen_mode); /* just close and reopen */ 1336 } 1337 /* If this packet will turn out to be unrelated/bogus, 1338 * we will go back and wait for next one. 1339 * Be sure timeout is properly decreased. */ 1340 already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait; 1341 if (len < 0) 1342 continue; 1343 } 1344 1345 if (packet.xid != xid) { 1346 log1("xid %x (our is %x), ignoring packet", 1347 (unsigned)packet.xid, (unsigned)xid); 1348 continue; 1349 } 1350 1351 /* Ignore packets that aren't for us */ 1352 if (packet.hlen != 6 1353 || memcmp(packet.chaddr, client_config.client_mac, 6) != 0 1354 ) { 1355 //FIXME: need to also check that last 10 bytes are zero 1356 log1("chaddr does not match, ignoring packet"); // log2? 1357 continue; 1358 } 1359 1360 message = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE); 1361 if (message == NULL) { 1362 bb_error_msg("no message type option, ignoring packet"); 1363 continue; 1364 } 1365 1366 switch (state) { 1367 case INIT_SELECTING: 1368 /* Must be a DHCPOFFER to one of our xid's */ 1369 if (*message == DHCPOFFER) { 1370 /* TODO: why we don't just fetch server's IP from IP header? */ 1371 temp = udhcp_get_option(&packet, DHCP_SERVER_ID); 1372 if (!temp) { 1373 bb_error_msg("no server ID, ignoring packet"); 1374 continue; 1375 /* still selecting - this server looks bad */ 1376 } 1377 /* it IS unaligned sometimes, don't "optimize" */ 1378 move_from_unaligned32(server_addr, temp); 1379 /*xid = packet.xid; - already is */ 1380 requested_ip = packet.yiaddr; 1381 1382 /* enter requesting state */ 1383 state = REQUESTING; 1384 timeout = 0; 1385 packet_num = 0; 1386 already_waited_sec = 0; 1387 } 1388 continue; 1389 case REQUESTING: 1390 case RENEWING: 1391 case RENEW_REQUESTED: 1392 case REBINDING: 1393 if (*message == DHCPACK) { 1394 temp = udhcp_get_option(&packet, DHCP_LEASE_TIME); 1395 if (!temp) { 1396 bb_error_msg("no lease time with ACK, using 1 hour lease"); 1397 lease_seconds = 60 * 60; 346 1398 } else { 347 udhcp_run_script(NULL, "leasefail"); 348 if (client_config.background_if_no_lease) { 349 bb_info_msg("No lease, forking to background"); 350 client_background(); 351 } else if (client_config.abort_if_no_lease) { 352 bb_info_msg("No lease, failing"); 353 retval = 1; 354 goto ret; 355 } 356 /* wait to try again */ 357 packet_num = 0; 358 timeout = now + 60; 1399 /* it IS unaligned sometimes, don't "optimize" */ 1400 move_from_unaligned32(lease_seconds, temp); 1401 lease_seconds = ntohl(lease_seconds); 1402 lease_seconds &= 0x0fffffff; /* paranoia: must not be prone to overflows */ 1403 if (lease_seconds < 10) /* and not too small */ 1404 lease_seconds = 10; 359 1405 } 360 break; 361 case RENEW_REQUESTED: 362 case REQUESTING: 363 if (packet_num < client_config.retries) { 364 /* send request packet */ 365 if (state == RENEW_REQUESTED) 366 send_renew(xid, server_addr, requested_ip); /* unicast */ 367 else send_selecting(xid, server_addr, requested_ip); /* broadcast */ 368 369 timeout = now + ((packet_num == 2) ? 10 : 2); 370 packet_num++; 371 } else { 372 /* timed out, go back to init state */ 373 if (state == RENEW_REQUESTED) 374 udhcp_run_script(NULL, "deconfig"); 375 state = INIT_SELECTING; 376 timeout = now; 377 packet_num = 0; 378 change_mode(LISTEN_RAW); 379 } 380 break; 381 case BOUND: 382 /* Lease is starting to run out, time to enter renewing state */ 383 state = RENEWING; 384 change_mode(LISTEN_KERNEL); 385 DEBUG("Entering renew state"); 386 /* fall right through */ 387 case RENEWING: 388 /* Either set a new T1, or enter REBINDING state */ 389 if ((t2 - t1) <= (lease / 14400 + 1)) { 390 /* timed out, enter rebinding state */ 391 state = REBINDING; 392 timeout = now + (t2 - t1); 393 DEBUG("Entering rebinding state"); 394 } else { 395 /* send a request packet */ 396 send_renew(xid, server_addr, requested_ip); /* unicast */ 397 t1 = (t2 - t1) / 2 + t1; 398 timeout = start + t1; 399 } 400 break; 401 case REBINDING: 402 /* Either set a new T2, or enter INIT state */ 403 if ((lease - t2) <= (lease / 14400 + 1)) { 404 /* timed out, enter init state */ 405 state = INIT_SELECTING; 406 bb_info_msg("Lease lost, entering init state"); 407 udhcp_run_script(NULL, "deconfig"); 408 timeout = now; 409 packet_num = 0; 410 change_mode(LISTEN_RAW); 411 } else { 412 /* send a request packet */ 413 send_renew(xid, 0, requested_ip); /* broadcast */ 414 t2 = (lease - t2) / 2 + t2; 415 timeout = start + t2; 416 } 417 break; 418 case RELEASED: 419 /* yah, I know, *you* say it would never happen */ 420 timeout = INT_MAX; 421 break; 422 } 423 } else if (listen_mode != LISTEN_NONE && FD_ISSET(sockfd, &rfds)) { 424 /* a packet is ready, read it */ 425 426 if (listen_mode == LISTEN_KERNEL) 427 len = udhcp_get_packet(&packet, sockfd); 428 else len = get_raw_packet(&packet, sockfd); 429 430 if (len == -1 && errno != EINTR) { 431 DEBUG("error on read, %s, reopening socket", strerror(errno)); 432 change_mode(listen_mode); /* just close and reopen */ 433 } 434 if (len < 0) continue; 435 436 if (packet.xid != xid) { 437 DEBUG("Ignoring XID %x (our xid is %x)", 438 (unsigned)packet.xid, (unsigned)xid); 439 continue; 440 } 441 442 /* Ignore packets that aren't for us */ 443 if (memcmp(packet.chaddr, client_config.arp, 6)) { 444 DEBUG("Packet does not have our chaddr - ignoring"); 445 continue; 446 } 447 448 message = get_option(&packet, DHCP_MESSAGE_TYPE); 449 if (message == NULL) { 450 bb_error_msg("cannot get option from packet - ignoring"); 451 continue; 452 } 453 454 switch (state) { 455 case INIT_SELECTING: 456 /* Must be a DHCPOFFER to one of our xid's */ 457 if (*message == DHCPOFFER) { 458 temp = get_option(&packet, DHCP_SERVER_ID); 459 if (temp) { 460 /* can be misaligned, thus memcpy */ 461 memcpy(&server_addr, temp, 4); 462 xid = packet.xid; 463 requested_ip = packet.yiaddr; 464 465 /* enter requesting state */ 466 state = REQUESTING; 467 timeout = now; 1406 #if ENABLE_FEATURE_UDHCPC_ARPING 1407 if (opt & OPT_a) { 1408 /* RFC 2131 3.1 paragraph 5: 1409 * "The client receives the DHCPACK message with configuration 1410 * parameters. The client SHOULD perform a final check on the 1411 * parameters (e.g., ARP for allocated network address), and notes 1412 * the duration of the lease specified in the DHCPACK message. At this 1413 * point, the client is configured. If the client detects that the 1414 * address is already in use (e.g., through the use of ARP), 1415 * the client MUST send a DHCPDECLINE message to the server and restarts 1416 * the configuration process..." */ 1417 if (!arpping(packet.yiaddr, 1418 NULL, 1419 (uint32_t) 0, 1420 client_config.client_mac, 1421 client_config.interface) 1422 ) { 1423 bb_info_msg("Offered address is in use " 1424 "(got ARP reply), declining"); 1425 send_decline(xid, server_addr, packet.yiaddr); 1426 1427 if (state != REQUESTING) 1428 udhcp_run_script(NULL, "deconfig"); 1429 change_listen_mode(LISTEN_RAW); 1430 state = INIT_SELECTING; 1431 requested_ip = 0; 1432 timeout = tryagain_timeout; 468 1433 packet_num = 0; 469 } else {470 bb_error_msg("no server ID in message");1434 already_waited_sec = 0; 1435 continue; /* back to main loop */ 471 1436 } 472 1437 } 473 break; 474 case RENEW_REQUESTED: 475 case REQUESTING: 476 case RENEWING: 477 case REBINDING: 478 if (*message == DHCPACK) { 479 temp = get_option(&packet, DHCP_LEASE_TIME); 480 if (!temp) { 481 bb_error_msg("no lease time with ACK, using 1 hour lease"); 482 lease = 60 * 60; 483 } else { 484 /* can be misaligned, thus memcpy */ 485 memcpy(&lease, temp, 4); 486 lease = ntohl(lease); 487 } 488 489 /* enter bound state */ 490 t1 = lease / 2; 491 492 /* little fixed point for n * .875 */ 493 t2 = (lease * 7) >> 3; 1438 #endif 1439 /* enter bound state */ 1440 timeout = lease_seconds / 2; 1441 { 1442 struct in_addr temp_addr; 494 1443 temp_addr.s_addr = packet.yiaddr; 495 1444 bb_info_msg("Lease of %s obtained, lease time %u", 496 inet_ntoa(temp_addr), (unsigned)lease); 497 start = now; 498 timeout = start + t1; 499 requested_ip = packet.yiaddr; 500 udhcp_run_script(&packet, 501 ((state == RENEWING || state == REBINDING) ? "renew" : "bound")); 502 503 state = BOUND; 504 change_mode(LISTEN_NONE); 505 if (client_config.quit_after_lease) { 506 if (client_config.release_on_quit) 507 perform_release(); 508 goto ret0; 509 } 510 if (!client_config.foreground) 511 client_background(); 512 513 } else if (*message == DHCPNAK) { 514 /* return to init state */ 515 bb_info_msg("Received DHCP NAK"); 516 udhcp_run_script(&packet, "nak"); 517 if (state != REQUESTING) 518 udhcp_run_script(NULL, "deconfig"); 519 state = INIT_SELECTING; 520 timeout = now; 521 requested_ip = 0; 522 packet_num = 0; 523 change_mode(LISTEN_RAW); 524 sleep(3); /* avoid excessive network traffic */ 1445 inet_ntoa(temp_addr), (unsigned)lease_seconds); 525 1446 } 526 break; 527 /* case BOUND, RELEASED: - ignore all packets */ 1447 requested_ip = packet.yiaddr; 1448 udhcp_run_script(&packet, state == REQUESTING ? "bound" : "renew"); 1449 1450 state = BOUND; 1451 change_listen_mode(LISTEN_NONE); 1452 if (opt & OPT_q) { /* quit after lease */ 1453 if (opt & OPT_R) /* release on quit */ 1454 perform_release(requested_ip, server_addr); 1455 goto ret0; 1456 } 1457 /* future renew failures should not exit (JM) */ 1458 opt &= ~OPT_n; 1459 #if BB_MMU /* NOMMU case backgrounded earlier */ 1460 if (!(opt & OPT_f)) { 1461 client_background(); 1462 /* do not background again! */ 1463 opt = ((opt & ~OPT_b) | OPT_f); 1464 } 1465 #endif 1466 already_waited_sec = 0; 1467 continue; /* back to main loop */ 528 1468 } 529 } else { 530 int signo = udhcp_sp_read(&rfds); 531 switch (signo) { 532 case SIGUSR1: 533 perform_renew(); 534 break; 535 case SIGUSR2: 536 perform_release(); 537 break; 538 case SIGTERM: 539 bb_info_msg("Received SIGTERM"); 540 if (client_config.release_on_quit) 541 perform_release(); 542 goto ret0; 1469 if (*message == DHCPNAK) { 1470 /* return to init state */ 1471 bb_info_msg("Received DHCP NAK"); 1472 udhcp_run_script(&packet, "nak"); 1473 if (state != REQUESTING) 1474 udhcp_run_script(NULL, "deconfig"); 1475 change_listen_mode(LISTEN_RAW); 1476 sleep(3); /* avoid excessive network traffic */ 1477 state = INIT_SELECTING; 1478 requested_ip = 0; 1479 timeout = 0; 1480 packet_num = 0; 1481 already_waited_sec = 0; 543 1482 } 1483 continue; 1484 /* case BOUND: - ignore all packets */ 1485 /* case RELEASED: - ignore all packets */ 544 1486 } 545 } /* for (;;) */ 1487 /* back to main loop */ 1488 } /* for (;;) - main loop ends */ 1489 546 1490 ret0: 547 1491 retval = 0; 548 1492 ret: 549 /*if (client_config.pidfile) - remove_pidfile has it 's own check */1493 /*if (client_config.pidfile) - remove_pidfile has its own check */ 550 1494 remove_pidfile(client_config.pidfile); 551 1495 return retval; -
branches/2.2.9/mindi-busybox/networking/udhcp/dhcpc.h
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 /* dhcpc.h */ 3 #ifndef _DHCPC_H 4 #define _DHCPC_H 2 /* 3 * Licensed under GPLv2, see file LICENSE in this source tree. 4 */ 5 #ifndef UDHCP_DHCPC_H 6 #define UDHCP_DHCPC_H 1 5 7 6 #define INIT_SELECTING 0 7 #define REQUESTING 1 8 #define BOUND 2 9 #define RENEWING 3 10 #define REBINDING 4 11 #define INIT_REBOOT 5 12 #define RENEW_REQUESTED 6 13 #define RELEASED 7 8 PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 14 9 15 10 struct client_config_t { 16 /* TODO: combine flag fields into single "unsigned opt" */ 17 /* (can be set directly to the result of getopt32) */ 18 char foreground; /* Do not fork */ 19 char quit_after_lease; /* Quit after obtaining lease */ 20 char release_on_quit; /* Perform release on quit */ 21 char abort_if_no_lease; /* Abort if no lease */ 22 char background_if_no_lease; /* Fork to background if no lease */ 11 uint8_t client_mac[6]; /* Our mac address */ 12 char no_default_options; /* Do not include default options in request */ 13 IF_FEATURE_UDHCP_PORT(uint16_t port;) 14 int ifindex; /* Index number of the interface to use */ 15 uint8_t opt_mask[256 / 8]; /* Bitmask of options to send (-O option) */ 23 16 const char *interface; /* The name of the interface to use */ 24 17 char *pidfile; /* Optionally store the process ID */ 25 18 const char *script; /* User script to run at dhcp events */ 19 struct option_set *options; /* list of DHCP options to send to server */ 26 20 uint8_t *clientid; /* Optional client id to use */ 27 21 uint8_t *vendorclass; /* Optional vendor class-id to use */ 28 22 uint8_t *hostname; /* Optional hostname to use */ 29 23 uint8_t *fqdn; /* Optional fully qualified domain name to use */ 30 int ifindex; /* Index number of the interface to use */ 31 int retries; /* Max number of request packets */ 32 int timeout; /* Number of seconds to try to get a lease */ 33 uint8_t arp[6]; /* Our arp address */ 34 }; 24 } FIX_ALIASING; 35 25 36 extern struct client_config_t client_config; 26 /* server_config sits in 1st half of bb_common_bufsiz1 */ 27 #define client_config (*(struct client_config_t*)(&bb_common_bufsiz1[COMMON_BUFSIZE / 2])) 37 28 29 #if ENABLE_FEATURE_UDHCP_PORT 30 #define CLIENT_PORT (client_config.port) 31 #else 32 #define CLIENT_PORT 68 33 #endif 38 34 39 /*** clientpacket.h ***/ 40 41 uint32_t random_xid(void); 42 int send_discover(uint32_t xid, uint32_t requested); 43 int send_selecting(uint32_t xid, uint32_t server, uint32_t requested); 44 int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr); 45 int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr); 46 int send_release(uint32_t server, uint32_t ciaddr); 47 int get_raw_packet(struct dhcpMessage *payload, int fd); 48 35 POP_SAVED_FUNCTION_VISIBILITY 49 36 50 37 #endif -
branches/2.2.9/mindi-busybox/networking/udhcp/dhcpd.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 /* dhcpd.c 3 * 4 * udhcp Server 2 /* 3 * udhcp server 5 4 * Copyright (C) 1999 Matthew Ramsay <matthewr@moreton.com.au> 6 5 * Chris Trew <ctrew@moreton.com.au> … … 8 7 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001 9 8 * 10 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 11 22 */ 12 13 23 #include <syslog.h> 14 24 #include "common.h" 25 #include "dhcpc.h" 15 26 #include "dhcpd.h" 16 #include "options.h" 27 28 29 /* Send a packet to a specific mac address and ip address by creating our own ip packet */ 30 static void send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadcast) 31 { 32 const uint8_t *chaddr; 33 uint32_t ciaddr; 34 35 // Was: 36 //if (force_broadcast) { /* broadcast */ } 37 //else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ } 38 //else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ } 39 //else { /* unicast to dhcp_pkt->yiaddr */ } 40 // But this is wrong: yiaddr is _our_ idea what client's IP is 41 // (for example, from lease file). Client may not know that, 42 // and may not have UDP socket listening on that IP! 43 // We should never unicast to dhcp_pkt->yiaddr! 44 // dhcp_pkt->ciaddr, OTOH, comes from client's request packet, 45 // and can be used. 46 47 if (force_broadcast 48 || (dhcp_pkt->flags & htons(BROADCAST_FLAG)) 49 || dhcp_pkt->ciaddr == 0 50 ) { 51 log1("Broadcasting packet to client"); 52 ciaddr = INADDR_BROADCAST; 53 chaddr = MAC_BCAST_ADDR; 54 } else { 55 log1("Unicasting packet to client ciaddr"); 56 ciaddr = dhcp_pkt->ciaddr; 57 chaddr = dhcp_pkt->chaddr; 58 } 59 60 udhcp_send_raw_packet(dhcp_pkt, 61 /*src*/ server_config.server_nip, SERVER_PORT, 62 /*dst*/ ciaddr, CLIENT_PORT, chaddr, 63 server_config.ifindex); 64 } 65 66 /* Send a packet to gateway_nip using the kernel ip stack */ 67 static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt) 68 { 69 log1("Forwarding packet to relay"); 70 71 udhcp_send_kernel_packet(dhcp_pkt, 72 server_config.server_nip, SERVER_PORT, 73 dhcp_pkt->gateway_nip, SERVER_PORT); 74 } 75 76 static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast) 77 { 78 if (dhcp_pkt->gateway_nip) 79 send_packet_to_relay(dhcp_pkt); 80 else 81 send_packet_to_client(dhcp_pkt, force_broadcast); 82 } 83 84 static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacket, char type) 85 { 86 /* Sets op, htype, hlen, cookie fields 87 * and adds DHCP_MESSAGE_TYPE option */ 88 udhcp_init_header(packet, type); 89 90 packet->xid = oldpacket->xid; 91 memcpy(packet->chaddr, oldpacket->chaddr, sizeof(oldpacket->chaddr)); 92 packet->flags = oldpacket->flags; 93 packet->gateway_nip = oldpacket->gateway_nip; 94 packet->ciaddr = oldpacket->ciaddr; 95 udhcp_add_simple_option(packet, DHCP_SERVER_ID, server_config.server_nip); 96 } 97 98 /* Fill options field, siaddr_nip, and sname and boot_file fields. 99 * TODO: teach this code to use overload option. 100 */ 101 static void add_server_options(struct dhcp_packet *packet) 102 { 103 struct option_set *curr = server_config.options; 104 105 while (curr) { 106 if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) 107 udhcp_add_binary_option(packet, curr->data); 108 curr = curr->next; 109 } 110 111 packet->siaddr_nip = server_config.siaddr_nip; 112 113 if (server_config.sname) 114 strncpy((char*)packet->sname, server_config.sname, sizeof(packet->sname) - 1); 115 if (server_config.boot_file) 116 strncpy((char*)packet->file, server_config.boot_file, sizeof(packet->file) - 1); 117 } 118 119 static uint32_t select_lease_time(struct dhcp_packet *packet) 120 { 121 uint32_t lease_time_sec = server_config.max_lease_sec; 122 uint8_t *lease_time_opt = udhcp_get_option(packet, DHCP_LEASE_TIME); 123 if (lease_time_opt) { 124 move_from_unaligned32(lease_time_sec, lease_time_opt); 125 lease_time_sec = ntohl(lease_time_sec); 126 if (lease_time_sec > server_config.max_lease_sec) 127 lease_time_sec = server_config.max_lease_sec; 128 if (lease_time_sec < server_config.min_lease_sec) 129 lease_time_sec = server_config.min_lease_sec; 130 } 131 return lease_time_sec; 132 } 133 134 /* We got a DHCP DISCOVER. Send an OFFER. */ 135 /* NOINLINE: limit stack usage in caller */ 136 static NOINLINE void send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, struct dyn_lease *lease) 137 { 138 struct dhcp_packet packet; 139 uint32_t lease_time_sec; 140 struct in_addr addr; 141 142 init_packet(&packet, oldpacket, DHCPOFFER); 143 144 /* If it is a static lease, use its IP */ 145 packet.yiaddr = static_lease_nip; 146 /* Else: */ 147 if (!static_lease_nip) { 148 /* We have no static lease for client's chaddr */ 149 uint32_t req_nip; 150 uint8_t *req_ip_opt; 151 const char *p_host_name; 152 153 if (lease) { 154 /* We have a dynamic lease for client's chaddr. 155 * Reuse its IP (even if lease is expired). 156 * Note that we ignore requested IP in this case. 157 */ 158 packet.yiaddr = lease->lease_nip; 159 } 160 /* Or: if client has requested an IP */ 161 else if ((req_ip_opt = udhcp_get_option(oldpacket, DHCP_REQUESTED_IP)) != NULL 162 /* (read IP) */ 163 && (move_from_unaligned32(req_nip, req_ip_opt), 1) 164 /* and the IP is in the lease range */ 165 && ntohl(req_nip) >= server_config.start_ip 166 && ntohl(req_nip) <= server_config.end_ip 167 /* and */ 168 && ( !(lease = find_lease_by_nip(req_nip)) /* is not already taken */ 169 || is_expired_lease(lease) /* or is taken, but expired */ 170 ) 171 ) { 172 packet.yiaddr = req_nip; 173 } 174 else { 175 /* Otherwise, find a free IP */ 176 packet.yiaddr = find_free_or_expired_nip(oldpacket->chaddr); 177 } 178 179 if (!packet.yiaddr) { 180 bb_error_msg("no free IP addresses. OFFER abandoned"); 181 return; 182 } 183 /* Reserve the IP for a short time hoping to get DHCPREQUEST soon */ 184 p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME); 185 lease = add_lease(packet.chaddr, packet.yiaddr, 186 server_config.offer_time, 187 p_host_name, 188 p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0 189 ); 190 if (!lease) { 191 bb_error_msg("no free IP addresses. OFFER abandoned"); 192 return; 193 } 194 } 195 196 lease_time_sec = select_lease_time(oldpacket); 197 udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec)); 198 add_server_options(&packet); 199 200 addr.s_addr = packet.yiaddr; 201 bb_info_msg("Sending OFFER of %s", inet_ntoa(addr)); 202 /* send_packet emits error message itself if it detects failure */ 203 send_packet(&packet, /*force_bcast:*/ 0); 204 } 205 206 /* NOINLINE: limit stack usage in caller */ 207 static NOINLINE void send_NAK(struct dhcp_packet *oldpacket) 208 { 209 struct dhcp_packet packet; 210 211 init_packet(&packet, oldpacket, DHCPNAK); 212 213 log1("Sending NAK"); 214 send_packet(&packet, /*force_bcast:*/ 1); 215 } 216 217 /* NOINLINE: limit stack usage in caller */ 218 static NOINLINE void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr) 219 { 220 struct dhcp_packet packet; 221 uint32_t lease_time_sec; 222 struct in_addr addr; 223 const char *p_host_name; 224 225 init_packet(&packet, oldpacket, DHCPACK); 226 packet.yiaddr = yiaddr; 227 228 lease_time_sec = select_lease_time(oldpacket); 229 udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec)); 230 231 add_server_options(&packet); 232 233 addr.s_addr = yiaddr; 234 bb_info_msg("Sending ACK to %s", inet_ntoa(addr)); 235 send_packet(&packet, /*force_bcast:*/ 0); 236 237 p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME); 238 add_lease(packet.chaddr, packet.yiaddr, 239 lease_time_sec, 240 p_host_name, 241 p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0 242 ); 243 if (ENABLE_FEATURE_UDHCPD_WRITE_LEASES_EARLY) { 244 /* rewrite the file with leases at every new acceptance */ 245 write_leases(); 246 } 247 } 248 249 /* NOINLINE: limit stack usage in caller */ 250 static NOINLINE void send_inform(struct dhcp_packet *oldpacket) 251 { 252 struct dhcp_packet packet; 253 254 /* "If a client has obtained a network address through some other means 255 * (e.g., manual configuration), it may use a DHCPINFORM request message 256 * to obtain other local configuration parameters. Servers receiving a 257 * DHCPINFORM message construct a DHCPACK message with any local 258 * configuration parameters appropriate for the client without: 259 * allocating a new address, checking for an existing binding, filling 260 * in 'yiaddr' or including lease time parameters. The servers SHOULD 261 * unicast the DHCPACK reply to the address given in the 'ciaddr' field 262 * of the DHCPINFORM message. 263 * ... 264 * The server responds to a DHCPINFORM message by sending a DHCPACK 265 * message directly to the address given in the 'ciaddr' field 266 * of the DHCPINFORM message. The server MUST NOT send a lease 267 * expiration time to the client and SHOULD NOT fill in 'yiaddr'." 268 */ 269 //TODO: do a few sanity checks: is ciaddr set? 270 //Better yet: is ciaddr == IP source addr? 271 init_packet(&packet, oldpacket, DHCPACK); 272 add_server_options(&packet); 273 274 send_packet(&packet, /*force_bcast:*/ 0); 275 } 17 276 18 277 19 278 /* globals */ 20 struct d hcpOfferedAddr *leases;21 struct server_config_t server_config; 22 23 24 int udhcpd_main(int argc, char **argv) ;25 int udhcpd_main(int argc , char **argv)279 struct dyn_lease *g_leases; 280 /* struct server_config_t server_config is in bb_common_bufsiz1 */ 281 282 283 int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 284 int udhcpd_main(int argc UNUSED_PARAM, char **argv) 26 285 { 27 286 fd_set rfds; 28 struct timeval tv; 29 int server_socket = -1, bytes, retval, max_sock; 30 struct dhcpMessage packet; 31 uint8_t *state, *server_id, *requested; 32 uint32_t server_id_align, requested_align, static_lease_ip; 287 int server_socket = -1, retval, max_sock; 288 struct dhcp_packet packet; 289 uint8_t *state; 290 uint32_t static_lease_nip; 33 291 unsigned timeout_end; 34 292 unsigned num_ips; 35 293 unsigned opt; 36 294 struct option_set *option; 37 struct dhcpOfferedAddr *lease, static_lease; 38 39 opt = getopt32(argv, "fS"); 40 argv += optind; 41 295 struct dyn_lease *lease, fake_lease; 296 IF_FEATURE_UDHCP_PORT(char *str_P;) 297 298 #if ENABLE_FEATURE_UDHCP_PORT 299 SERVER_PORT = 67; 300 CLIENT_PORT = 68; 301 #endif 302 303 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 304 opt_complementary = "vv"; 305 #endif 306 opt = getopt32(argv, "fSv" 307 IF_FEATURE_UDHCP_PORT("P:", &str_P) 308 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 309 , &dhcp_verbose 310 #endif 311 ); 42 312 if (!(opt & 1)) { /* no -f */ 43 313 bb_daemonize_or_rexec(0, argv); 44 logmode &= ~LOGMODE_STDIO; 45 } 46 314 logmode = LOGMODE_NONE; 315 } 316 /* update argv after the possible vfork+exec in daemonize */ 317 argv += optind; 47 318 if (opt & 2) { /* -S */ 48 openlog(applet_name, LOG_PID, LOG_ LOCAL0);319 openlog(applet_name, LOG_PID, LOG_DAEMON); 49 320 logmode |= LOGMODE_SYSLOG; 50 321 } 51 322 #if ENABLE_FEATURE_UDHCP_PORT 323 if (opt & 8) { /* -P */ 324 SERVER_PORT = xatou16(str_P); 325 CLIENT_PORT = SERVER_PORT + 1; 326 } 327 #endif 52 328 /* Would rather not do read_config before daemonization - 53 329 * otherwise NOMMU machines will parse config twice */ … … 61 337 /* Create pidfile */ 62 338 write_pidfile(server_config.pidfile); 63 /* if (!..) bb_perror_msg("can not create pidfile %s", pidfile); */64 65 bb_info_msg("%s (v %s) started", applet_name, BB_VER);66 67 option = find_option(server_config.options, DHCP_LEASE_TIME);68 server_config. lease =LEASE_TIME;339 /* if (!..) bb_perror_msg("can't create pidfile %s", pidfile); */ 340 341 bb_info_msg("%s (v"BB_VER") started", applet_name); 342 343 option = udhcp_find_option(server_config.options, DHCP_LEASE_TIME); 344 server_config.max_lease_sec = DEFAULT_LEASE_TIME; 69 345 if (option) { 70 m emcpy(&server_config.lease, option->data + 2, 4);71 server_config. lease = ntohl(server_config.lease);346 move_from_unaligned32(server_config.max_lease_sec, option->data + OPT_DATA); 347 server_config.max_lease_sec = ntohl(server_config.max_lease_sec); 72 348 } 73 349 … … 80 356 } 81 357 82 leases = xzalloc(server_config.max_leases * sizeof(*leases));358 g_leases = xzalloc(server_config.max_leases * sizeof(g_leases[0])); 83 359 read_leases(server_config.lease_file); 84 360 85 if (read_interface(server_config.interface, &server_config.ifindex, 86 &server_config.server, server_config.arp)) { 361 if (udhcp_read_interface(server_config.interface, 362 &server_config.ifindex, 363 &server_config.server_nip, 364 server_config.server_mac) 365 ) { 87 366 retval = 1; 88 367 goto ret; … … 94 373 timeout_end = monotonic_sec() + server_config.auto_time; 95 374 while (1) { /* loop until universe collapses */ 375 int bytes; 376 struct timeval tv; 377 uint8_t *server_id_opt; 378 uint8_t *requested_opt; 379 uint32_t requested_nip = requested_nip; /* for compiler */ 96 380 97 381 if (server_socket < 0) { 98 server_socket = listen_socket(/*INADDR_ANY,*/ SERVER_PORT,382 server_socket = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, 99 383 server_config.interface); 100 384 } … … 116 400 } 117 401 if (retval < 0 && errno != EINTR) { 118 DEBUG("error on select");402 log1("Error on select"); 119 403 continue; 120 404 } … … 122 406 switch (udhcp_sp_read(&rfds)) { 123 407 case SIGUSR1: 124 bb_info_msg("Received aSIGUSR1");408 bb_info_msg("Received SIGUSR1"); 125 409 write_leases(); 126 410 /* why not just reset the timeout, eh */ … … 128 412 continue; 129 413 case SIGTERM: 130 bb_info_msg("Received aSIGTERM");414 bb_info_msg("Received SIGTERM"); 131 415 goto ret0; 132 case 0: break; /* no signal */ 133 default: continue; /* signal or error (probably EINTR) */ 134 } 135 136 bytes = udhcp_get_packet(&packet, server_socket); /* this waits for a packet - idle */ 416 case 0: /* no signal: read a packet */ 417 break; 418 default: /* signal or error (probably EINTR): back to select */ 419 continue; 420 } 421 422 bytes = udhcp_recv_kernel_packet(&packet, server_socket); 137 423 if (bytes < 0) { 424 /* bytes can also be -2 ("bad packet data") */ 138 425 if (bytes == -1 && errno != EINTR) { 139 DEBUG("error on read,%s, reopening socket", strerror(errno));426 log1("Read error: %s, reopening socket", strerror(errno)); 140 427 close(server_socket); 141 428 server_socket = -1; … … 143 430 continue; 144 431 } 145 146 state = get_option(&packet, DHCP_MESSAGE_TYPE); 147 if (state == NULL) { 148 bb_error_msg("cannot get option from packet, ignoring"); 149 continue; 150 } 151 152 /* Look for a static lease */ 153 static_lease_ip = getIpByMac(server_config.static_leases, &packet.chaddr); 154 155 if (static_lease_ip) { 156 bb_info_msg("Found static lease: %x", static_lease_ip); 157 158 memcpy(&static_lease.chaddr, &packet.chaddr, 16); 159 static_lease.yiaddr = static_lease_ip; 160 static_lease.expires = 0; 161 162 lease = &static_lease; 432 if (packet.hlen != 6) { 433 bb_error_msg("MAC length != 6, ignoring packet"); 434 continue; 435 } 436 if (packet.op != BOOTREQUEST) { 437 bb_error_msg("not a REQUEST, ignoring packet"); 438 continue; 439 } 440 state = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE); 441 if (state == NULL || state[0] < DHCP_MINTYPE || state[0] > DHCP_MAXTYPE) { 442 bb_error_msg("no or bad message type option, ignoring packet"); 443 continue; 444 } 445 446 /* Look for a static/dynamic lease */ 447 static_lease_nip = get_static_nip_by_mac(server_config.static_leases, &packet.chaddr); 448 if (static_lease_nip) { 449 bb_info_msg("Found static lease: %x", static_lease_nip); 450 memcpy(&fake_lease.lease_mac, &packet.chaddr, 6); 451 fake_lease.lease_nip = static_lease_nip; 452 fake_lease.expires = 0; 453 lease = &fake_lease; 163 454 } else { 164 lease = find_lease_by_chaddr(packet.chaddr); 455 lease = find_lease_by_mac(packet.chaddr); 456 } 457 458 /* Get REQUESTED_IP and SERVER_ID if present */ 459 server_id_opt = udhcp_get_option(&packet, DHCP_SERVER_ID); 460 if (server_id_opt) { 461 uint32_t server_id_net; 462 move_from_unaligned32(server_id_net, server_id_opt); 463 if (server_id_net != server_config.server_nip) { 464 /* client talks to somebody else */ 465 log1("server ID doesn't match, ignoring"); 466 continue; 467 } 468 } 469 requested_opt = udhcp_get_option(&packet, DHCP_REQUESTED_IP); 470 if (requested_opt) { 471 move_from_unaligned32(requested_nip, requested_opt); 165 472 } 166 473 167 474 switch (state[0]) { 475 168 476 case DHCPDISCOVER: 169 DEBUG("Received DISCOVER"); 170 171 if (sendOffer(&packet) < 0) { 172 bb_error_msg("send OFFER failed"); 477 log1("Received DISCOVER"); 478 479 send_offer(&packet, static_lease_nip, lease); 480 break; 481 482 case DHCPREQUEST: 483 log1("Received REQUEST"); 484 /* RFC 2131: 485 486 o DHCPREQUEST generated during SELECTING state: 487 488 Client inserts the address of the selected server in 'server 489 identifier', 'ciaddr' MUST be zero, 'requested IP address' MUST be 490 filled in with the yiaddr value from the chosen DHCPOFFER. 491 492 Note that the client may choose to collect several DHCPOFFER 493 messages and select the "best" offer. The client indicates its 494 selection by identifying the offering server in the DHCPREQUEST 495 message. If the client receives no acceptable offers, the client 496 may choose to try another DHCPDISCOVER message. Therefore, the 497 servers may not receive a specific DHCPREQUEST from which they can 498 decide whether or not the client has accepted the offer. 499 500 o DHCPREQUEST generated during INIT-REBOOT state: 501 502 'server identifier' MUST NOT be filled in, 'requested IP address' 503 option MUST be filled in with client's notion of its previously 504 assigned address. 'ciaddr' MUST be zero. The client is seeking to 505 verify a previously allocated, cached configuration. Server SHOULD 506 send a DHCPNAK message to the client if the 'requested IP address' 507 is incorrect, or is on the wrong network. 508 509 Determining whether a client in the INIT-REBOOT state is on the 510 correct network is done by examining the contents of 'giaddr', the 511 'requested IP address' option, and a database lookup. If the DHCP 512 server detects that the client is on the wrong net (i.e., the 513 result of applying the local subnet mask or remote subnet mask (if 514 'giaddr' is not zero) to 'requested IP address' option value 515 doesn't match reality), then the server SHOULD send a DHCPNAK 516 message to the client. 517 518 If the network is correct, then the DHCP server should check if 519 the client's notion of its IP address is correct. If not, then the 520 server SHOULD send a DHCPNAK message to the client. If the DHCP 521 server has no record of this client, then it MUST remain silent, 522 and MAY output a warning to the network administrator. This 523 behavior is necessary for peaceful coexistence of non- 524 communicating DHCP servers on the same wire. 525 526 If 'giaddr' is 0x0 in the DHCPREQUEST message, the client is on 527 the same subnet as the server. The server MUST broadcast the 528 DHCPNAK message to the 0xffffffff broadcast address because the 529 client may not have a correct network address or subnet mask, and 530 the client may not be answering ARP requests. 531 532 If 'giaddr' is set in the DHCPREQUEST message, the client is on a 533 different subnet. The server MUST set the broadcast bit in the 534 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the 535 client, because the client may not have a correct network address 536 or subnet mask, and the client may not be answering ARP requests. 537 538 o DHCPREQUEST generated during RENEWING state: 539 540 'server identifier' MUST NOT be filled in, 'requested IP address' 541 option MUST NOT be filled in, 'ciaddr' MUST be filled in with 542 client's IP address. In this situation, the client is completely 543 configured, and is trying to extend its lease. This message will 544 be unicast, so no relay agents will be involved in its 545 transmission. Because 'giaddr' is therefore not filled in, the 546 DHCP server will trust the value in 'ciaddr', and use it when 547 replying to the client. 548 549 A client MAY choose to renew or extend its lease prior to T1. The 550 server may choose not to extend the lease (as a policy decision by 551 the network administrator), but should return a DHCPACK message 552 regardless. 553 554 o DHCPREQUEST generated during REBINDING state: 555 556 'server identifier' MUST NOT be filled in, 'requested IP address' 557 option MUST NOT be filled in, 'ciaddr' MUST be filled in with 558 client's IP address. In this situation, the client is completely 559 configured, and is trying to extend its lease. This message MUST 560 be broadcast to the 0xffffffff IP broadcast address. The DHCP 561 server SHOULD check 'ciaddr' for correctness before replying to 562 the DHCPREQUEST. 563 564 The DHCPREQUEST from a REBINDING client is intended to accommodate 565 sites that have multiple DHCP servers and a mechanism for 566 maintaining consistency among leases managed by multiple servers. 567 A DHCP server MAY extend a client's lease only if it has local 568 administrative authority to do so. 569 */ 570 if (!requested_opt) { 571 requested_nip = packet.ciaddr; 572 if (requested_nip == 0) { 573 log1("no requested IP and no ciaddr, ignoring"); 574 break; 575 } 576 } 577 if (lease && requested_nip == lease->lease_nip) { 578 /* client requested or configured IP matches the lease. 579 * ACK it, and bump lease expiration time. */ 580 send_ACK(&packet, lease->lease_nip); 581 break; 582 } 583 if (server_id_opt) { 584 /* client was talking specifically to us. 585 * "No, we don't have this IP for you". */ 586 send_NAK(&packet); 173 587 } 174 588 break; 175 case DHCPREQUEST: 176 DEBUG("received REQUEST"); 177 178 requested = get_option(&packet, DHCP_REQUESTED_IP); 179 server_id = get_option(&packet, DHCP_SERVER_ID); 180 181 if (requested) memcpy(&requested_align, requested, 4); 182 if (server_id) memcpy(&server_id_align, server_id, 4); 183 184 if (lease) { 185 if (server_id) { 186 /* SELECTING State */ 187 DEBUG("server_id = %08x", ntohl(server_id_align)); 188 if (server_id_align == server_config.server && requested 189 && requested_align == lease->yiaddr 190 ) { 191 sendACK(&packet, lease->yiaddr); 192 } 193 } else if (requested) { 194 /* INIT-REBOOT State */ 195 if (lease->yiaddr == requested_align) 196 sendACK(&packet, lease->yiaddr); 197 else 198 sendNAK(&packet); 199 } else if (lease->yiaddr == packet.ciaddr) { 200 /* RENEWING or REBINDING State */ 201 sendACK(&packet, lease->yiaddr); 202 } else { 203 /* don't know what to do!!!! */ 204 sendNAK(&packet); 205 } 206 207 /* what to do if we have no record of the client */ 208 } else if (server_id) { 209 /* SELECTING State */ 210 211 } else if (requested) { 212 /* INIT-REBOOT State */ 213 lease = find_lease_by_yiaddr(requested_align); 214 if (lease) { 215 if (lease_expired(lease)) { 216 /* probably best if we drop this lease */ 217 memset(lease->chaddr, 0, 16); 218 /* make some contention for this address */ 219 } else 220 sendNAK(&packet); 221 } else { 222 uint32_t r = ntohl(requested_align); 223 if (r < server_config.start_ip 224 || r > server_config.end_ip 225 ) { 226 sendNAK(&packet); 227 } 228 /* else remain silent */ 229 } 230 231 } else { 232 /* RENEWING or REBINDING State */ 589 590 case DHCPDECLINE: 591 /* RFC 2131: 592 * "If the server receives a DHCPDECLINE message, 593 * the client has discovered through some other means 594 * that the suggested network address is already 595 * in use. The server MUST mark the network address 596 * as not available and SHOULD notify the local 597 * sysadmin of a possible configuration problem." 598 * 599 * SERVER_ID must be present, 600 * REQUESTED_IP must be present, 601 * chaddr must be filled in, 602 * ciaddr must be 0 (we do not check this) 603 */ 604 log1("Received DECLINE"); 605 if (server_id_opt 606 && requested_opt 607 && lease /* chaddr matches this lease */ 608 && requested_nip == lease->lease_nip 609 ) { 610 memset(lease->lease_mac, 0, sizeof(lease->lease_mac)); 611 lease->expires = time(NULL) + server_config.decline_time; 233 612 } 234 613 break; 235 case DHCPDECLINE: 236 DEBUG("Received DECLINE"); 237 if (lease) { 238 memset(lease->chaddr, 0, 16); 239 lease->expires = time(0) + server_config.decline_time; 614 615 case DHCPRELEASE: 616 /* "Upon receipt of a DHCPRELEASE message, the server 617 * marks the network address as not allocated." 618 * 619 * SERVER_ID must be present, 620 * REQUESTED_IP must not be present (we do not check this), 621 * chaddr must be filled in, 622 * ciaddr must be filled in 623 */ 624 log1("Received RELEASE"); 625 if (server_id_opt 626 && lease /* chaddr matches this lease */ 627 && packet.ciaddr == lease->lease_nip 628 ) { 629 lease->expires = time(NULL); 240 630 } 241 631 break; 242 case DHCPRELEASE: 243 DEBUG("Received RELEASE"); 244 if (lease) 245 lease->expires = time(0); 246 break; 632 247 633 case DHCPINFORM: 248 DEBUG("Received INFORM");634 log1("Received INFORM"); 249 635 send_inform(&packet); 250 636 break; 251 default:252 bb_info_msg("Unsupported DHCP message (%02x) - ignoring", state[0]);253 637 } 254 638 } -
branches/2.2.9/mindi-busybox/networking/udhcp/dhcpd.h
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 /* dhcpd.h */ 3 #ifndef _DHCPD_H 4 #define _DHCPD_H 2 /* 3 * Licensed under GPLv2, see file LICENSE in this source tree. 4 */ 5 #ifndef UDHCP_DHCPD_H 6 #define UDHCP_DHCPD_H 1 5 7 6 /************************************/ 7 /* Defaults _you_ may want to tweak */ 8 /************************************/ 8 PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 9 9 10 /* the period of time the client is allowed to use that address*/11 #define LEASE_TIME (60*60*24*10) /* 10 days of seconds*/12 #define LEASES_FILE "/var/lib/misc/udhcpd.leases"13 14 /* where to find the DHCP server configuration file */10 /* Defaults you may want to tweak */ 11 /* Default max_lease_sec */ 12 #define DEFAULT_LEASE_TIME (60*60*24 * 10) 13 #define LEASES_FILE CONFIG_DHCPD_LEASES_FILE 14 /* Where to find the DHCP server configuration file */ 15 15 #define DHCPD_CONF_FILE "/etc/udhcpd.conf" 16 16 17 struct option_set {18 uint8_t *data;19 struct option_set *next;20 };21 17 22 18 struct static_lease { 23 19 struct static_lease *next; 24 uint 8_t *mac;25 uint 32_t *ip;20 uint32_t nip; 21 uint8_t mac[6]; 26 22 }; 27 23 28 24 struct server_config_t { 29 uint32_t server; /* Our IP, in network order */ 25 char *interface; /* interface to use */ 26 //TODO: ifindex, server_nip, server_mac 27 // are obtained from interface name. 28 // Instead of querying them *once*, create update_server_network_data_cache() 29 // and call it before any usage of these fields. 30 // update_server_network_data_cache() must re-query data 31 // if more than N seconds have passed after last use. 32 int ifindex; 33 uint32_t server_nip; 34 #if ENABLE_FEATURE_UDHCP_PORT 35 uint16_t port; 36 #endif 37 uint8_t server_mac[6]; /* our MAC address (used only for ARP probing) */ 38 struct option_set *options; /* list of DHCP options loaded from the config file */ 30 39 /* start,end are in host order: we need to compare start <= ip <= end */ 31 uint32_t start_ip; /* Start address of leases, in host order */ 32 uint32_t end_ip; /* End of leases, in host order */ 33 struct option_set *options; /* List of DHCP options loaded from the config file */ 34 char *interface; /* The name of the interface to use */ 35 int ifindex; /* Index number of the interface to use */ 36 uint8_t arp[6]; /* Our arp address */ 37 char remaining; /* should the lease file be interpreted as lease time remaining, or 38 * as the time the lease expires */ 39 uint32_t lease; /* lease time in seconds (host order) */ 40 uint32_t max_leases; /* maximum number of leases (including reserved address) */ 40 uint32_t start_ip; /* start address of leases, in host order */ 41 uint32_t end_ip; /* end of leases, in host order */ 42 uint32_t max_lease_sec; /* maximum lease time (host order) */ 43 uint32_t min_lease_sec; /* minimum lease time a client can request */ 44 uint32_t max_leases; /* maximum number of leases (including reserved addresses) */ 41 45 uint32_t auto_time; /* how long should udhcpd wait before writing a config file. 42 46 * if this is zero, it will only write one on SIGUSR1 */ … … 45 49 uint32_t conflict_time; /* how long an arp conflict offender is leased for */ 46 50 uint32_t offer_time; /* how long an offered address is reserved */ 47 uint32_t min_lease; /* minimum lease a client can request*/51 uint32_t siaddr_nip; /* "next server" bootp option */ 48 52 char *lease_file; 49 53 char *pidfile; 50 char *notify_file; /* What to run whenever leases are written */ 51 uint32_t siaddr; /* next server bootp option */ 54 char *notify_file; /* what to run whenever leases are written */ 52 55 char *sname; /* bootp server name */ 53 56 char *boot_file; /* bootp boot file option */ 54 57 struct static_lease *static_leases; /* List of ip/mac pairs to assign static leases */ 55 } ;58 } FIX_ALIASING; 56 59 57 extern struct server_config_t server_config; 58 extern struct dhcpOfferedAddr *leases; 60 #define server_config (*(struct server_config_t*)&bb_common_bufsiz1) 61 /* client_config sits in 2nd half of bb_common_bufsiz1 */ 62 63 #if ENABLE_FEATURE_UDHCP_PORT 64 #define SERVER_PORT (server_config.port) 65 #else 66 #define SERVER_PORT 67 67 #endif 59 68 60 69 61 /*** leases.h ***/ 70 typedef uint32_t leasetime_t; 71 typedef int32_t signed_leasetime_t; 62 72 63 struct dhcpOfferedAddr { 64 uint8_t chaddr[16]; 65 uint32_t yiaddr; /* network order */ 66 uint32_t expires; /* host order */ 67 }; 73 struct dyn_lease { 74 /* Unix time when lease expires. Kept in memory in host order. 75 * When written to file, converted to network order 76 * and adjusted (current time subtracted) */ 77 leasetime_t expires; 78 /* "nip": IP in network order */ 79 uint32_t lease_nip; 80 /* We use lease_mac[6], since e.g. ARP probing uses 81 * only 6 first bytes anyway. We check received dhcp packets 82 * that their hlen == 6 and thus chaddr has only 6 significant bytes 83 * (dhcp packet has chaddr[16], not [6]) 84 */ 85 uint8_t lease_mac[6]; 86 char hostname[20]; 87 uint8_t pad[2]; 88 /* total size is a multiply of 4 */ 89 } PACKED; 68 90 69 struct dhcpOfferedAddr *add_lease(const uint8_t *chaddr, uint32_t yiaddr, unsigned long lease); 70 int lease_expired(struct dhcpOfferedAddr *lease); 71 struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr); 72 struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr); 73 uint32_t find_address(int check_expired); 91 extern struct dyn_lease *g_leases; 92 93 struct dyn_lease *add_lease( 94 const uint8_t *chaddr, uint32_t yiaddr, 95 leasetime_t leasetime, 96 const char *hostname, int hostname_len 97 ) FAST_FUNC; 98 int is_expired_lease(struct dyn_lease *lease) FAST_FUNC; 99 struct dyn_lease *find_lease_by_mac(const uint8_t *mac) FAST_FUNC; 100 struct dyn_lease *find_lease_by_nip(uint32_t nip) FAST_FUNC; 101 uint32_t find_free_or_expired_nip(const uint8_t *safe_mac) FAST_FUNC; 74 102 75 103 76 /*** static_leases.h ***/ 77 78 /* Config file will pass static lease info to this function which will add it 79 * to a data structure that can be searched later */ 80 int addStaticLease(struct static_lease **lease_struct, uint8_t *mac, uint32_t *ip); 81 /* Check to see if a mac has an associated static lease */ 82 uint32_t getIpByMac(struct static_lease *lease_struct, void *arg); 83 /* Check to see if an ip is reserved as a static ip */ 84 uint32_t reservedIp(struct static_lease *lease_struct, uint32_t ip); 104 /* Config file parser will pass static lease info to this function 105 * which will add it to a data structure that can be searched later */ 106 void add_static_lease(struct static_lease **st_lease_pp, uint8_t *mac, uint32_t nip) FAST_FUNC; 107 /* Find static lease IP by mac */ 108 uint32_t get_static_nip_by_mac(struct static_lease *st_lease, void *arg) FAST_FUNC; 109 /* Check to see if an IP is reserved as a static IP */ 110 int is_nip_reserved(struct static_lease *st_lease, uint32_t nip) FAST_FUNC; 85 111 /* Print out static leases just to check what's going on (debug code) */ 86 void printStaticLeases(struct static_lease **lease_struct); 112 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2 113 void log_static_leases(struct static_lease **st_lease_pp) FAST_FUNC; 114 #else 115 # define log_static_leases(st_lease_pp) ((void)0) 116 #endif 87 117 88 118 89 /*** serverpacket.h ***/ 90 91 int sendOffer(struct dhcpMessage *oldpacket); 92 int sendNAK(struct dhcpMessage *oldpacket); 93 int sendACK(struct dhcpMessage *oldpacket, uint32_t yiaddr); 94 int send_inform(struct dhcpMessage *oldpacket); 119 void read_config(const char *file) FAST_FUNC; 120 void write_leases(void) FAST_FUNC; 121 void read_leases(const char *file) FAST_FUNC; 95 122 96 123 97 /*** files.h ***/ 98 99 int read_config(const char *file); 100 void write_leases(void); 101 void read_leases(const char *file); 102 struct option_set *find_option(struct option_set *opt_list, char code); 103 124 POP_SAVED_FUNCTION_VISIBILITY 104 125 105 126 #endif -
branches/2.2.9/mindi-busybox/networking/udhcp/dhcprelay.c
r1765 r2725 2 2 /* Port to Busybox Copyright (C) 2006 Jesse Dutton <jessedutton@gmail.com> 3 3 * 4 * Licensed under GPL v2, see file LICENSE in this tarball for details.4 * Licensed under GPLv2, see file LICENSE in this source tree. 5 5 * 6 6 * DHCP Relay for 'DHCPv4 Configuration of IPSec Tunnel Mode' support … … 10 10 * Upstream has GPL v2 or later 11 11 */ 12 13 12 #include "common.h" 14 #include "dhcpd.h" 15 #include "options.h" 16 17 /* constants */ 18 #define SELECT_TIMEOUT 5 /* select timeout in sec. */ 19 #define MAX_LIFETIME 2*60 /* lifetime of an xid entry in sec. */ 20 #define MAX_INTERFACES 9 21 13 14 #define SERVER_PORT 67 15 16 /* lifetime of an xid entry in sec. */ 17 #define MAX_LIFETIME 2*60 18 /* select timeout in sec. */ 19 #define SELECT_TIMEOUT (MAX_LIFETIME / 8) 22 20 23 21 /* This list holds information about clients. The xid_* functions manipulate this list. */ 24 static struct xid_item { 22 struct xid_item { 23 unsigned timestamp; 24 int client; 25 25 uint32_t xid; 26 26 struct sockaddr_in ip; 27 int client;28 time_t timestamp;29 27 struct xid_item *next; 30 } dhcprelay_xid_list = {0, {0}, 0, 0, NULL}; 31 28 }; 29 30 #define dhcprelay_xid_list (*(struct xid_item*)&bb_common_bufsiz1) 32 31 33 32 static struct xid_item *xid_add(uint32_t xid, struct sockaddr_in *ip, int client) … … 42 41 item->xid = xid; 43 42 item->client = client; 44 item->timestamp = time(NULL);43 item->timestamp = monotonic_sec(); 45 44 item->next = dhcprelay_xid_list.next; 46 45 dhcprelay_xid_list.next = item; … … 53 52 struct xid_item *item = dhcprelay_xid_list.next; 54 53 struct xid_item *last = &dhcprelay_xid_list; 55 time_t current_time = time(NULL);54 unsigned current_time = monotonic_sec(); 56 55 57 56 while (item != NULL) { … … 72 71 while (item != NULL) { 73 72 if (item->xid == xid) { 74 return item;73 break; 75 74 } 76 75 item = item->next; 77 76 } 78 return NULL;77 return item; 79 78 } 80 79 … … 100 99 * returns the message type on success, -1 otherwise 101 100 */ 102 static int get_dhcp_packet_type(struct dhcp Message*p)101 static int get_dhcp_packet_type(struct dhcp_packet *p) 103 102 { 104 103 uint8_t *op; … … 108 107 return -1; 109 108 /* get message type option */ 110 op = get_option(p, DHCP_MESSAGE_TYPE);109 op = udhcp_get_option(p, DHCP_MESSAGE_TYPE); 111 110 if (op != NULL) 112 111 return op[0]; … … 115 114 116 115 /** 117 * signal_handler - handles signals ;-) 118 * sig - sent signal 119 */ 120 static smallint dhcprelay_stopflag; 121 122 static void dhcprelay_signal_handler(int sig) 123 { 124 dhcprelay_stopflag = 1; 125 } 126 127 /** 128 * get_client_devices - parses the devices list 129 * dev_list - comma separated list of devices 116 * make_iface_list - parses client/server interface names 130 117 * returns array 131 118 */ 132 static char ** get_client_devices(char *dev_list, int *client_number)133 { 134 char *s, * list, **client_dev;119 static char **make_iface_list(char **client_and_server_ifaces, int *client_number) 120 { 121 char *s, **iface_list; 135 122 int i, cn; 136 123 137 /* copy list */138 list = xstrdup(dev_list);139 if (list == NULL) return NULL;140 141 124 /* get number of items */ 142 for (s = dev_list, cn = 1; *s; s++) 125 cn = 2; /* 1 server iface + at least 1 client one */ 126 s = client_and_server_ifaces[0]; /* list of client ifaces */ 127 while (*s) { 143 128 if (*s == ',') 144 129 cn++; 145 146 client_dev = xzalloc(cn * sizeof(*client_dev)); 147 148 /* parse list */ 149 s = strtok(list, ","); 150 i = 0; 151 while (s != NULL) { 152 client_dev[i++] = xstrdup(s); 153 s = strtok(NULL, ","); 154 } 155 156 /* free copy and exit */ 157 free(list); 130 s++; 131 } 158 132 *client_number = cn; 159 return client_dev; 160 } 161 162 163 /* Creates listen sockets (in fds) and returns the number allocated. */ 164 static int init_sockets(char **client, int num_clients, 165 char *server, int *fds, int *max_socket) 166 { 167 int i; 168 169 /* talk to real server on bootps */ 170 fds[0] = listen_socket(/*INADDR_ANY,*/ 67, server); 171 *max_socket = fds[0]; 172 173 /* array starts at 1 since server is 0 */ 174 num_clients++; 175 176 for (i = 1; i < num_clients; i++) { 177 /* listen for clients on bootps */ 178 fds[i] = listen_socket(/*NADDR_ANY,*/ 67, client[i-1]); 179 if (fds[i] > *max_socket) 180 *max_socket = fds[i]; 181 } 182 183 return i; 184 } 185 133 134 /* create vector of pointers */ 135 iface_list = xzalloc(cn * sizeof(iface_list[0])); 136 137 iface_list[0] = client_and_server_ifaces[1]; /* server iface */ 138 139 i = 1; 140 s = xstrdup(client_and_server_ifaces[0]); /* list of client ifaces */ 141 goto store_client_iface_name; 142 143 while (i < cn) { 144 if (*s++ == ',') { 145 s[-1] = '\0'; 146 store_client_iface_name: 147 iface_list[i++] = s; 148 } 149 } 150 151 return iface_list; 152 } 153 154 /* Creates listen sockets (in fds) bound to client and server ifaces, 155 * and returns numerically max fd. 156 */ 157 static int init_sockets(char **iface_list, int num_clients, int *fds) 158 { 159 int i, n; 160 161 n = 0; 162 for (i = 0; i < num_clients; i++) { 163 fds[i] = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, iface_list[i]); 164 if (n < fds[i]) 165 n = fds[i]; 166 } 167 return n; 168 } 169 170 static int sendto_ip4(int sock, const void *msg, int msg_len, struct sockaddr_in *to) 171 { 172 int err; 173 174 errno = 0; 175 err = sendto(sock, msg, msg_len, 0, (struct sockaddr*) to, sizeof(*to)); 176 err -= msg_len; 177 if (err) 178 bb_perror_msg("sendto"); 179 return err; 180 } 186 181 187 182 /** 188 * pass_ on() - forwards dhcp packets from client to server183 * pass_to_server() - forwards dhcp packets from client to server 189 184 * p - packet to send 190 185 * client - number of the client 191 186 */ 192 static void pass_ on(struct dhcpMessage*p, int packet_len, int client, int *fds,187 static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, int *fds, 193 188 struct sockaddr_in *client_addr, struct sockaddr_in *server_addr) 194 189 { 195 int res, type; 196 struct xid_item *item; 190 int type; 197 191 198 192 /* check packet_type */ … … 206 200 207 201 /* create new xid entry */ 208 item = xid_add(p->xid, client_addr, client); 209 210 /* forward request to LAN (server) */ 211 res = sendto(fds[0], p, packet_len, 0, (struct sockaddr*)server_addr, 212 sizeof(struct sockaddr_in)); 213 if (res != packet_len) { 214 bb_perror_msg("pass_on"); 215 return; 216 } 202 xid_add(p->xid, client_addr, client); 203 204 /* forward request to server */ 205 /* note that we send from fds[0] which is bound to SERVER_PORT (67). 206 * IOW: we send _from_ SERVER_PORT! Although this may look strange, 207 * RFC 1542 not only allows, but prescribes this for BOOTP relays. 208 */ 209 sendto_ip4(fds[0], p, packet_len, server_addr); 217 210 } 218 211 219 212 /** 220 * pass_ back() - forwards dhcp packets from server to client213 * pass_to_client() - forwards dhcp packets from server to client 221 214 * p - packet to send 222 215 */ 223 static void pass_ back(struct dhcpMessage*p, int packet_len, int *fds)224 { 225 int res,type;216 static void pass_to_client(struct dhcp_packet *p, int packet_len, int *fds) 217 { 218 int type; 226 219 struct xid_item *item; 227 220 … … 238 231 } 239 232 233 //TODO: also do it if (p->flags & htons(BROADCAST_FLAG)) is set! 240 234 if (item->ip.sin_addr.s_addr == htonl(INADDR_ANY)) 241 235 item->ip.sin_addr.s_addr = htonl(INADDR_BROADCAST); 242 if (item->client > MAX_INTERFACES) 243 return; 244 res = sendto(fds[item->client], p, packet_len, 0, (struct sockaddr*)(&item->ip), 245 sizeof(item->ip)); 246 if (res != packet_len) { 247 bb_perror_msg("pass_back"); 248 return; 236 237 if (sendto_ip4(fds[item->client], p, packet_len, &item->ip) != 0) { 238 return; /* send error occurred */ 249 239 } 250 240 … … 253 243 } 254 244 255 static void dhcprelay_loop(int *fds, int num_sockets, int max_socket, char **clients, 256 struct sockaddr_in *server_addr, uint32_t gw_ip) 257 { 258 struct dhcpMessage dhcp_msg; 259 fd_set rfds; 260 size_t packlen; 261 socklen_t addr_size; 262 struct sockaddr_in client_addr; 263 struct timeval tv; 264 int i; 265 266 while (!dhcprelay_stopflag) { 245 int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 246 int dhcprelay_main(int argc, char **argv) 247 { 248 struct sockaddr_in server_addr; 249 char **iface_list; 250 int *fds; 251 int num_sockets, max_socket; 252 uint32_t our_nip; 253 254 server_addr.sin_family = AF_INET; 255 server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); 256 server_addr.sin_port = htons(SERVER_PORT); 257 258 /* dhcprelay CLIENT_IFACE1[,CLIENT_IFACE2...] SERVER_IFACE [SERVER_IP] */ 259 if (argc == 4) { 260 if (!inet_aton(argv[3], &server_addr.sin_addr)) 261 bb_perror_msg_and_die("bad server IP"); 262 } else if (argc != 3) { 263 bb_show_usage(); 264 } 265 266 iface_list = make_iface_list(argv + 1, &num_sockets); 267 268 fds = xmalloc(num_sockets * sizeof(fds[0])); 269 270 /* Create sockets and bind one to every iface */ 271 max_socket = init_sockets(iface_list, num_sockets, fds); 272 273 /* Get our IP on server_iface */ 274 if (udhcp_read_interface(argv[2], NULL, &our_nip, NULL)) 275 return 1; 276 277 /* Main loop */ 278 while (1) { 279 // reinit stuff from time to time? go back to make_iface_list 280 // every N minutes? 281 fd_set rfds; 282 struct timeval tv; 283 int i; 284 267 285 FD_ZERO(&rfds); 268 286 for (i = 0; i < num_sockets; i++) … … 271 289 tv.tv_usec = 0; 272 290 if (select(max_socket + 1, &rfds, NULL, NULL, &tv) > 0) { 291 int packlen; 292 struct dhcp_packet dhcp_msg; 293 273 294 /* server */ 274 295 if (FD_ISSET(fds[0], &rfds)) { 275 packlen = udhcp_ get_packet(&dhcp_msg, fds[0]);296 packlen = udhcp_recv_kernel_packet(&dhcp_msg, fds[0]); 276 297 if (packlen > 0) { 277 pass_ back(&dhcp_msg, packlen, fds);298 pass_to_client(&dhcp_msg, packlen, fds); 278 299 } 279 300 } 301 302 /* clients */ 280 303 for (i = 1; i < num_sockets; i++) { 281 /* clients */ 304 struct sockaddr_in client_addr; 305 socklen_t addr_size; 306 282 307 if (!FD_ISSET(fds[i], &rfds)) 283 308 continue; 284 addr_size = sizeof(struct sockaddr_in); 309 310 addr_size = sizeof(client_addr); 285 311 packlen = recvfrom(fds[i], &dhcp_msg, sizeof(dhcp_msg), 0, 286 312 (struct sockaddr *)(&client_addr), &addr_size); 287 313 if (packlen <= 0) 288 314 continue; 289 if (read_interface(clients[i-1], NULL, &dhcp_msg.giaddr, NULL)) 290 dhcp_msg.giaddr = gw_ip; 291 pass_on(&dhcp_msg, packlen, i, fds, &client_addr, server_addr); 315 316 /* Get our IP on corresponding client_iface */ 317 // RFC 1542 318 // 4.1 General BOOTP Processing for Relay Agents 319 // 4.1.1 BOOTREQUEST Messages 320 // If the relay agent does decide to relay the request, it MUST examine 321 // the 'giaddr' ("gateway" IP address) field. If this field is zero, 322 // the relay agent MUST fill this field with the IP address of the 323 // interface on which the request was received. If the interface has 324 // more than one IP address logically associated with it, the relay 325 // agent SHOULD choose one IP address associated with that interface and 326 // use it consistently for all BOOTP messages it relays. If the 327 // 'giaddr' field contains some non-zero value, the 'giaddr' field MUST 328 // NOT be modified. The relay agent MUST NOT, under any circumstances, 329 // fill the 'giaddr' field with a broadcast address as is suggested in 330 // [1] (Section 8, sixth paragraph). 331 332 // but why? what if server can't route such IP? Client ifaces may be, say, NATed! 333 334 // 4.1.2 BOOTREPLY Messages 335 // BOOTP relay agents relay BOOTREPLY messages only to BOOTP clients. 336 // It is the responsibility of BOOTP servers to send BOOTREPLY messages 337 // directly to the relay agent identified in the 'giaddr' field. 338 // (yeah right, unless it is impossible... see comment above) 339 // Therefore, a relay agent may assume that all BOOTREPLY messages it 340 // receives are intended for BOOTP clients on its directly-connected 341 // networks. 342 // 343 // When a relay agent receives a BOOTREPLY message, it should examine 344 // the BOOTP 'giaddr', 'yiaddr', 'chaddr', 'htype', and 'hlen' fields. 345 // These fields should provide adequate information for the relay agent 346 // to deliver the BOOTREPLY message to the client. 347 // 348 // The 'giaddr' field can be used to identify the logical interface from 349 // which the reply must be sent (i.e., the host or router interface 350 // connected to the same network as the BOOTP client). If the content 351 // of the 'giaddr' field does not match one of the relay agent's 352 // directly-connected logical interfaces, the BOOTREPLY messsage MUST be 353 // silently discarded. 354 if (udhcp_read_interface(iface_list[i], NULL, &dhcp_msg.gateway_nip, NULL)) { 355 /* Fall back to our IP on server iface */ 356 // this makes more sense! 357 dhcp_msg.gateway_nip = our_nip; 358 } 359 // maybe dhcp_msg.hops++? drop packets with too many hops (RFC 1542 says 4 or 16)? 360 pass_to_server(&dhcp_msg, packlen, i, fds, &client_addr, &server_addr); 292 361 } 293 362 } 294 363 xid_expire(); 295 } 296 } 297 298 int dhcprelay_main(int argc, char **argv); 299 int dhcprelay_main(int argc, char **argv) 300 { 301 int i, num_sockets, max_socket, fds[MAX_INTERFACES]; 302 uint32_t gw_ip; 303 char **clients; 304 struct sockaddr_in server_addr; 305 306 server_addr.sin_family = AF_INET; 307 server_addr.sin_port = htons(67); 308 if (argc == 4) { 309 if (!inet_aton(argv[3], &server_addr.sin_addr)) 310 bb_perror_msg_and_die("didn't grok server"); 311 } else if (argc == 3) { 312 server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); 313 } else { 314 bb_show_usage(); 315 } 316 clients = get_client_devices(argv[1], &num_sockets); 317 if (!clients) return 0; 318 319 signal(SIGTERM, dhcprelay_signal_handler); 320 signal(SIGQUIT, dhcprelay_signal_handler); 321 signal(SIGINT, dhcprelay_signal_handler); 322 323 num_sockets = init_sockets(clients, num_sockets, argv[2], fds, &max_socket); 324 325 if (read_interface(argv[2], NULL, &gw_ip, NULL)) 326 return 1; 327 328 dhcprelay_loop(fds, num_sockets, max_socket, clients, &server_addr, gw_ip); 329 330 if (ENABLE_FEATURE_CLEAN_UP) { 331 for (i = 0; i < num_sockets; i++) { 332 close(fds[i]); 333 free(clients[i]); 334 } 335 } 336 337 return 0; 338 } 364 } /* while (1) */ 365 366 /* return 0; - not reached */ 367 } -
branches/2.2.9/mindi-busybox/networking/udhcp/domain_codec.c
r1765 r2725 5 5 * Loosely based on the isc-dhcpd implementation by dhankins@isc.org 6 6 * 7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 8 */ 9 10 #if ENABLE_FEATURE_RFC3397 11 12 #include "common.h" 13 #include "options.h" 7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 8 */ 9 #ifdef DNS_COMPR_TESTING 10 # define FAST_FUNC /* nothing */ 11 # define xmalloc malloc 12 # include <stdlib.h> 13 # include <stdint.h> 14 # include <string.h> 15 # include <stdio.h> 16 #else 17 # include "common.h" 18 #endif 14 19 15 20 #define NS_MAXDNAME 1025 /* max domain name length */ … … 20 25 21 26 22 /* expand a RFC1035-compressed list of domain names "cstr", of length "clen";27 /* Expand a RFC1035-compressed list of domain names "cstr", of length "clen"; 23 28 * returns a newly allocated string containing the space-separated domains, 24 29 * prefixed with the contents of string pre, or NULL if an error occurs. 25 30 */ 26 char *dname_dec(const uint8_t *cstr, int clen, const char *pre) 27 { 28 const uint8_t *c; 29 int crtpos, retpos, depth, plen = 0, len = 0; 31 char* FAST_FUNC dname_dec(const uint8_t *cstr, int clen, const char *pre) 32 { 33 char *ret = ret; /* for compiler */ 30 34 char *dst = NULL; 31 32 if (!cstr)33 return NULL;34 35 if (pre)36 plen = strlen(pre);37 35 38 36 /* We make two passes over the cstr string. First, we compute … … 43 41 * buffer, then having to check if it's sufficiently large, etc. 44 42 */ 45 46 while (!dst) { 47 48 if (len > 0) { /* second pass? allocate dst buffer and copy pre */ 49 dst = xmalloc(len + plen); 50 memcpy(dst, pre, plen); 51 } 43 while (1) { 44 /* note: "return NULL" below are leak-safe since 45 * dst isn't yet allocated */ 46 const uint8_t *c; 47 unsigned crtpos, retpos, depth, len; 52 48 53 49 crtpos = retpos = depth = len = 0; 54 55 50 while (crtpos < clen) { 56 51 c = cstr + crtpos; 57 52 58 if ((*c & NS_CMPRSFLGS) != 0) { /* pointer */ 59 if (crtpos + 2 > clen) /* no offset to jump to? abort */ 53 if ((*c & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 54 /* pointer */ 55 if (crtpos + 2 > clen) /* no offset to jump to? abort */ 60 56 return NULL; 61 if (retpos == 0) 57 if (retpos == 0) /* toplevel? save return spot */ 62 58 retpos = crtpos + 2; 63 59 depth++; 64 crtpos = ((*c & 0x3f) << 8) | (*(c + 1) & 0xff); /* jump */ 65 } else if (*c) { /* label */ 66 if (crtpos + *c + 1 > clen) /* label too long? abort */ 60 crtpos = ((c[0] & 0x3f) << 8) | c[1]; /* jump */ 61 } else if (*c) { 62 /* label */ 63 if (crtpos + *c + 1 > clen) /* label too long? abort */ 67 64 return NULL; 68 65 if (dst) 69 memcpy(dst + plen +len, c + 1, *c);66 memcpy(dst + len, c + 1, *c); 70 67 len += *c + 1; 71 68 crtpos += *c + 1; 72 69 if (dst) 73 *(dst + plen + len - 1) = '.'; 74 } else { /* null: end of current domain name */ 75 if (retpos == 0) { /* toplevel? keep going */ 70 dst[len - 1] = '.'; 71 } else { 72 /* NUL: end of current domain name */ 73 if (retpos == 0) { 74 /* toplevel? keep going */ 76 75 crtpos++; 77 } else { /* return to toplevel saved spot */ 76 } else { 77 /* return to toplevel saved spot */ 78 78 crtpos = retpos; 79 79 retpos = depth = 0; 80 80 } 81 81 if (dst) 82 *(dst + plen + len - 1) = ' '; 83 } 84 85 if (depth > NS_MAXDNSRCH || /* too many jumps? abort, it's a loop */ 86 len > NS_MAXDNAME * NS_MAXDNSRCH) /* result too long? abort */ 82 dst[len - 1] = ' '; 83 } 84 85 if (depth > NS_MAXDNSRCH /* too many jumps? abort, it's a loop */ 86 || len > NS_MAXDNAME * NS_MAXDNSRCH /* result too long? abort */ 87 ) { 87 88 return NULL; 88 } 89 90 if (!len) /* expanded string has 0 length? abort */ 89 } 90 } 91 92 if (!len) /* expanded string has 0 length? abort */ 91 93 return NULL; 92 94 93 if (dst) 94 *(dst + plen + len - 1) = '\0'; 95 } 96 97 return dst; 95 if (!dst) { /* first pass? */ 96 /* allocate dst buffer and copy pre */ 97 unsigned plen = strlen(pre); 98 ret = dst = xmalloc(plen + len); 99 memcpy(dst, pre, plen); 100 dst += plen; 101 } else { 102 dst[len - 1] = '\0'; 103 break; 104 } 105 } 106 107 return ret; 98 108 } 99 109 … … 104 114 static uint8_t *convert_dname(const char *src) 105 115 { 106 uint8_t c, *res, *l p, *rp;116 uint8_t c, *res, *lenptr, *dst; 107 117 int len; 108 118 109 119 res = xmalloc(strlen(src) + 2); 110 rp = lp= res;111 rp++;120 dst = lenptr = res; 121 dst++; 112 122 113 123 for (;;) { 114 124 c = (uint8_t)*src++; 115 if (c == '.' || c == '\0') { 116 len = rp - lp- 1;125 if (c == '.' || c == '\0') { /* end of label */ 126 len = dst - lenptr - 1; 117 127 /* label too long, too short, or two '.'s in a row? abort */ 118 128 if (len > NS_MAXLABEL || len == 0 || (c == '.' && *src == '.')) { … … 120 130 return NULL; 121 131 } 122 *lp = len; 123 lp = rp++; 124 if (c == '\0' || *src == '\0') /* end of dname */ 132 *lenptr = len; 133 if (c == '\0' || *src == '\0') /* "" or ".": end of src */ 125 134 break; 126 } else {127 if (c >= 0x41 && c <= 0x5A) /* uppercase? convert to lower */128 c += 0x20;129 *rp++ = c;130 }131 }132 133 *lp = 0; 134 if ( rp - res > NS_MAXCDNAME) {/* dname too long? abort */135 lenptr = dst++; 136 continue; 137 } 138 if (c >= 'A' && c <= 'Z') /* uppercase? convert to lower */ 139 c += ('a' - 'A'); 140 *dst++ = c; 141 } 142 143 if (dst - res >= NS_MAXCDNAME) { /* dname too long? abort */ 135 144 free(res); 136 145 return NULL; 137 146 } 147 148 *dst = 0; 138 149 return res; 139 150 } 140 151 141 /* returns the offset within cstr at which dname can be found, or -1 142 */ 152 /* Returns the offset within cstr at which dname can be found, or -1 */ 143 153 static int find_offset(const uint8_t *cstr, int clen, const uint8_t *dname) 144 154 { 145 155 const uint8_t *c, *d; 146 int off , inc;156 int off; 147 157 148 158 /* find all labels in cstr */ … … 151 161 c = cstr + off; 152 162 153 if ((*c & NS_CMPRSFLGS) != 0) {/* pointer, skip */163 if ((*c & NS_CMPRSFLGS) == NS_CMPRSFLGS) { /* pointer, skip */ 154 164 off += 2; 155 } else if (*c) { /* label, try matching dname */ 156 inc = *c + 1; 165 continue; 166 } 167 if (*c) { /* label, try matching dname */ 157 168 d = dname; 158 while (*c == *d && memcmp(c + 1, d + 1, *c) == 0) { 159 if (*c == 0) /* match, return offset */ 169 while (1) { 170 unsigned len1 = *c + 1; 171 if (memcmp(c, d, len1) != 0) 172 break; 173 if (len1 == 1) /* at terminating NUL - match, return offset */ 160 174 return off; 161 d += *c + 1; 162 c += *c + 1; 163 if ((*c & NS_CMPRSFLGS) != 0) /* pointer, jump */ 164 c = cstr + (((*c & 0x3f) << 8) | (*(c + 1) & 0xff)); 165 } 166 off += inc; 167 } else { /* null, skip */ 168 off++; 169 } 175 d += len1; 176 c += len1; 177 if ((*c & NS_CMPRSFLGS) == NS_CMPRSFLGS) /* pointer, jump */ 178 c = cstr + (((c[0] & 0x3f) << 8) | c[1]); 179 } 180 off += cstr[off] + 1; 181 continue; 182 } 183 /* NUL, skip */ 184 off++; 170 185 } 171 186 … … 173 188 } 174 189 175 /* computes string to be appended to cstr so that src would be added to190 /* Computes string to be appended to cstr so that src would be added to 176 191 * the compression (best case, it's a 2-byte pointer to some offset within 177 * cstr; worst case, it's all of src, converted to rfc3011format).192 * cstr; worst case, it's all of src, converted to <4>host<3>com<0> format). 178 193 * The computed string is returned directly; its length is returned via retlen; 179 194 * NULL and 0, respectively, are returned if an error occurs. 180 195 */ 181 uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen)196 uint8_t* FAST_FUNC dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen) 182 197 { 183 198 uint8_t *d, *dname; … … 190 205 } 191 206 192 for (d = dname; *d != 0; d += *d + 1) { 193 off = find_offset(cstr, clen, d); 194 if (off >= 0) { /* found a match, add pointer and terminate string */ 195 *d++ = NS_CMPRSFLGS; 196 *d = off; 197 break; 198 } 207 d = dname; 208 while (*d) { 209 if (cstr) { 210 off = find_offset(cstr, clen, d); 211 if (off >= 0) { /* found a match, add pointer and return */ 212 *d++ = NS_CMPRSFLGS | (off >> 8); 213 *d = off; 214 break; 215 } 216 } 217 d += *d + 1; 199 218 } 200 219 … … 203 222 } 204 223 205 #endif /* ENABLE_FEATURE_RFC3397 */ 224 #ifdef DNS_COMPR_TESTING 225 /* gcc -Wall -DDNS_COMPR_TESTING domain_codec.c -o domain_codec && ./domain_codec */ 226 int main(int argc, char **argv) 227 { 228 int len; 229 uint8_t *encoded; 230 231 #define DNAME_DEC(encoded,pre) dname_dec((uint8_t*)(encoded), sizeof(encoded), (pre)) 232 printf("'%s'\n", DNAME_DEC("\4host\3com\0", "test1:")); 233 printf("test2:'%s'\n", DNAME_DEC("\4host\3com\0\4host\3com\0", "")); 234 printf("test3:'%s'\n", DNAME_DEC("\4host\3com\0\xC0\0", "")); 235 printf("test4:'%s'\n", DNAME_DEC("\4host\3com\0\xC0\5", "")); 236 printf("test5:'%s'\n", DNAME_DEC("\4host\3com\0\xC0\5\1z\xC0\xA", "")); 237 238 #define DNAME_ENC(cache,source,lenp) dname_enc((uint8_t*)(cache), sizeof(cache), (source), (lenp)) 239 encoded = dname_enc(NULL, 0, "test.net", &len); 240 printf("test6:'%s' len:%d\n", dname_dec(encoded, len, ""), len); 241 encoded = DNAME_ENC("\3net\0", "test.net", &len); 242 printf("test7:'%s' len:%d\n", dname_dec(encoded, len, ""), len); 243 encoded = DNAME_ENC("\4test\3net\0", "test.net", &len); 244 printf("test8:'%s' len:%d\n", dname_dec(encoded, len, ""), len); 245 return 0; 246 } 247 #endif -
branches/2.2.9/mindi-busybox/networking/udhcp/dumpleases.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.3 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 4 4 */ 5 #include <getopt.h>6 7 5 #include "common.h" 8 6 #include "dhcpd.h" 7 #include "unicode.h" 9 8 10 int dumpleases_main(int argc, char **argv) ;11 int dumpleases_main(int argc , char **argv)9 int dumpleases_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 10 int dumpleases_main(int argc UNUSED_PARAM, char **argv) 12 11 { 13 12 int fd; 14 13 int i; 15 14 unsigned opt; 16 time_t expires;15 int64_t written_at, curr, expires_abs; 17 16 const char *file = LEASES_FILE; 18 struct d hcpOfferedAddrlease;17 struct dyn_lease lease; 19 18 struct in_addr addr; 20 19 21 20 enum { 22 OPT_a = 0x1,// -a23 OPT_r = 0x2,// -r24 OPT_f = 0x4,// -f21 OPT_a = 0x1, // -a 22 OPT_r = 0x2, // -r 23 OPT_f = 0x4, // -f 25 24 }; 26 #if ENABLE_ GETOPT_LONG25 #if ENABLE_LONG_OPTS 27 26 static const char dumpleases_longopts[] ALIGN1 = 28 27 "absolute\0" No_argument "a" … … 33 32 applet_long_options = dumpleases_longopts; 34 33 #endif 34 init_unicode(); 35 35 36 opt_complementary = "=0:a--r:r--a"; 36 37 opt = getopt32(argv, "arf:", &file); … … 38 39 fd = xopen(file, O_RDONLY); 39 40 40 printf("Mac Address IP-Address Expires %s\n", (opt & OPT_a) ? "at" : "in"); 41 /* "00:00:00:00:00:00 255.255.255.255 Wed Jun 30 21:49:08 1993" */ 41 printf("Mac Address IP Address Host Name Expires %s\n", (opt & OPT_a) ? "at" : "in"); 42 /* "00:00:00:00:00:00 255.255.255.255 ABCDEFGHIJKLMNOPQRS Wed Jun 30 21:49:08 1993" */ 43 /* "123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 */ 44 45 xread(fd, &written_at, sizeof(written_at)); 46 written_at = SWAP_BE64(written_at); 47 curr = time(NULL); 48 if (curr < written_at) 49 written_at = curr; /* lease file from future! :) */ 50 42 51 while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) { 43 printf(":%02x"+1, lease.chaddr[0]); 44 for (i = 1; i < 6; i++) { 45 printf(":%02x", lease.chaddr[i]); 52 const char *fmt = ":%02x" + 1; 53 for (i = 0; i < 6; i++) { 54 printf(fmt, lease.lease_mac[i]); 55 fmt = ":%02x"; 46 56 } 47 addr.s_addr = lease.yiaddr; 48 printf(" %-15s ", inet_ntoa(addr)); 49 expires = ntohl(lease.expires); 57 addr.s_addr = lease.lease_nip; 58 #if ENABLE_UNICODE_SUPPORT 59 { 60 char *uni_name = unicode_conv_to_printable_fixedwidth(NULL, lease.hostname, 19); 61 printf(" %-16s%s ", inet_ntoa(addr), uni_name); 62 free(uni_name); 63 } 64 #else 65 /* actually, 15+1 and 19+1, +1 is a space between columns */ 66 /* lease.hostname is char[20] and is always NUL terminated */ 67 printf(" %-16s%-20s", inet_ntoa(addr), lease.hostname); 68 #endif 69 expires_abs = ntohl(lease.expires) + written_at; 70 if (expires_abs <= curr) { 71 puts("expired"); 72 continue; 73 } 50 74 if (!(opt & OPT_a)) { /* no -a */ 51 if (!expires)52 puts("expired");53 else {54 unsigned d, h, m;55 d = expires / (24*60*60); expires %= (24*60*60);56 h = expires / (60*60); expires %= (60*60);57 m = expires / 60; expires %= 60;58 if (d) printf("%u days ", d);59 printf("%02u:%02u:%02u\n", h, m, (unsigned)expires);60 }61 } else /* -a */62 fputs(ctime(&expires), stdout);75 unsigned d, h, m; 76 unsigned expires = expires_abs - curr; 77 d = expires / (24*60*60); expires %= (24*60*60); 78 h = expires / (60*60); expires %= (60*60); 79 m = expires / 60; expires %= 60; 80 if (d) 81 printf("%u days ", d); 82 printf("%02u:%02u:%02u\n", h, m, (unsigned)expires); 83 } else { /* -a */ 84 time_t t = expires_abs; 85 fputs(ctime(&t), stdout); 86 } 63 87 } 64 88 /* close(fd); */ -
branches/2.2.9/mindi-busybox/networking/udhcp/files.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * files.c -- DHCP server file manipulation * 3 * DHCP server config and lease file manipulation 4 * 4 5 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001 6 * 7 * Licensed under GPLv2, see file LICENSE in this source tree. 5 8 */ 6 7 9 #include <netinet/ether.h> 8 10 9 11 #include "common.h" 10 12 #include "dhcpd.h" 11 #include "options.h"12 13 13 14 14 /* on these functions, make sure your datatype matches */ 15 static int read_ip(const char *line, void *arg) 16 { 17 len_and_sockaddr *lsa; 18 19 lsa = host_and_af2sockaddr(line, 0, AF_INET); 20 if (!lsa) 21 return 0; 22 *(uint32_t*)arg = lsa->sin.sin_addr.s_addr; 23 free(lsa); 24 return 1; 25 } 26 27 static int read_mac(const char *line, void *arg) 28 { 29 uint8_t *mac_bytes = arg; 30 struct ether_addr *temp_ether_addr; 31 32 temp_ether_addr = ether_aton(line); 33 if (temp_ether_addr == NULL) 34 return 0; 35 memcpy(mac_bytes, temp_ether_addr, 6); 36 return 1; 37 } 38 39 40 static int read_str(const char *line, void *arg) 15 static int FAST_FUNC read_str(const char *line, void *arg) 41 16 { 42 17 char **dest = arg; … … 47 22 } 48 23 49 50 static int read_u32(const char *line, void *arg) 24 static int FAST_FUNC read_u32(const char *line, void *arg) 51 25 { 52 26 *(uint32_t*)arg = bb_strtou32(line, NULL, 10); … … 54 28 } 55 29 56 57 static int read_yn(const char *line, void *arg) 58 { 59 char *dest = arg; 60 61 if (!strcasecmp("yes", line)) { 62 *dest = 1; 63 return 1; 64 } 65 if (!strcasecmp("no", line)) { 66 *dest = 0; 67 return 1; 68 } 69 return 0; 70 } 71 72 73 /* find option 'code' in opt_list */ 74 struct option_set *find_option(struct option_set *opt_list, char code) 75 { 76 while (opt_list && opt_list->data[OPT_CODE] < code) 77 opt_list = opt_list->next; 78 79 if (opt_list && opt_list->data[OPT_CODE] == code) 80 return opt_list; 81 return NULL; 82 } 83 84 85 /* add an option to the opt_list */ 86 static void attach_option(struct option_set **opt_list, 87 const struct dhcp_option *option, char *buffer, int length) 88 { 89 struct option_set *existing, *new, **curr; 90 91 existing = find_option(*opt_list, option->code); 92 if (!existing) { 93 DEBUG("Attaching option %s to list", option->name); 94 95 #if ENABLE_FEATURE_RFC3397 96 if ((option->flags & TYPE_MASK) == OPTION_STR1035) 97 /* reuse buffer and length for RFC1035-formatted string */ 98 buffer = dname_enc(NULL, 0, buffer, &length); 99 #endif 100 101 /* make a new option */ 102 new = xmalloc(sizeof(*new)); 103 new->data = xmalloc(length + 2); 104 new->data[OPT_CODE] = option->code; 105 new->data[OPT_LEN] = length; 106 memcpy(new->data + 2, buffer, length); 107 108 curr = opt_list; 109 while (*curr && (*curr)->data[OPT_CODE] < option->code) 110 curr = &(*curr)->next; 111 112 new->next = *curr; 113 *curr = new; 114 #if ENABLE_FEATURE_RFC3397 115 if ((option->flags & TYPE_MASK) == OPTION_STR1035 && buffer != NULL) 116 free(buffer); 117 #endif 118 return; 119 } 120 121 /* add it to an existing option */ 122 DEBUG("Attaching option %s to existing member of list", option->name); 123 if (option->flags & OPTION_LIST) { 124 #if ENABLE_FEATURE_RFC3397 125 if ((option->flags & TYPE_MASK) == OPTION_STR1035) 126 /* reuse buffer and length for RFC1035-formatted string */ 127 buffer = dname_enc(existing->data + 2, 128 existing->data[OPT_LEN], buffer, &length); 129 #endif 130 if (existing->data[OPT_LEN] + length <= 255) { 131 existing->data = xrealloc(existing->data, 132 existing->data[OPT_LEN] + length + 3); 133 if ((option->flags & TYPE_MASK) == OPTION_STRING) { 134 /* ' ' can bring us to 256 - bad */ 135 if (existing->data[OPT_LEN] + length >= 255) 136 return; 137 /* add space separator between STRING options in a list */ 138 existing->data[existing->data[OPT_LEN] + 2] = ' '; 139 existing->data[OPT_LEN]++; 140 } 141 memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, length); 142 existing->data[OPT_LEN] += length; 143 } /* else, ignore the data, we could put this in a second option in the future */ 144 #if ENABLE_FEATURE_RFC3397 145 if ((option->flags & TYPE_MASK) == OPTION_STR1035 && buffer != NULL) 146 free(buffer); 147 #endif 148 } /* else, ignore the new data */ 149 } 150 151 152 /* read a dhcp option and add it to opt_list */ 153 static int read_opt(const char *const_line, void *arg) 154 { 155 struct option_set **opt_list = arg; 156 char *opt, *val, *endptr; 157 const struct dhcp_option *option; 158 int retval = 0, length; 159 char buffer[8]; 160 char *line; 161 uint16_t *result_u16 = (uint16_t *) buffer; 162 uint32_t *result_u32 = (uint32_t *) buffer; 163 164 /* Cheat, the only const line we'll actually get is "" */ 165 line = (char *) const_line; 166 opt = strtok(line, " \t="); 167 if (!opt) return 0; 168 169 option = dhcp_options; 170 while (1) { 171 if (!option->code) 172 return 0; 173 if (!strcasecmp(option->name, opt)) 174 break; 175 option++; 176 } 177 178 do { 179 val = strtok(NULL, ", \t"); 180 if (!val) break; 181 length = option_lengths[option->flags & TYPE_MASK]; 182 retval = 0; 183 opt = buffer; /* new meaning for variable opt */ 184 switch (option->flags & TYPE_MASK) { 185 case OPTION_IP: 186 retval = read_ip(val, buffer); 187 break; 188 case OPTION_IP_PAIR: 189 retval = read_ip(val, buffer); 190 val = strtok(NULL, ", \t/-"); 191 if (!val) 192 retval = 0; 193 if (retval) 194 retval = read_ip(val, buffer + 4); 195 break; 196 case OPTION_STRING: 197 #if ENABLE_FEATURE_RFC3397 198 case OPTION_STR1035: 199 #endif 200 length = strlen(val); 201 if (length > 0) { 202 if (length > 254) length = 254; 203 opt = val; 204 retval = 1; 205 } 206 break; 207 case OPTION_BOOLEAN: 208 retval = read_yn(val, buffer); 209 break; 210 case OPTION_U8: 211 buffer[0] = strtoul(val, &endptr, 0); 212 retval = (endptr[0] == '\0'); 213 break; 214 /* htonX are macros in older libc's, using temp var 215 * in code below for safety */ 216 /* TODO: use bb_strtoX? */ 217 case OPTION_U16: { 218 unsigned long tmp = strtoul(val, &endptr, 0); 219 *result_u16 = htons(tmp); 220 retval = (endptr[0] == '\0' /*&& tmp < 0x10000*/); 221 break; 222 } 223 case OPTION_S16: { 224 long tmp = strtol(val, &endptr, 0); 225 *result_u16 = htons(tmp); 226 retval = (endptr[0] == '\0'); 227 break; 228 } 229 case OPTION_U32: { 230 unsigned long tmp = strtoul(val, &endptr, 0); 231 *result_u32 = htonl(tmp); 232 retval = (endptr[0] == '\0'); 233 break; 234 } 235 case OPTION_S32: { 236 long tmp = strtol(val, &endptr, 0); 237 *result_u32 = htonl(tmp); 238 retval = (endptr[0] == '\0'); 239 break; 240 } 241 default: 242 break; 243 } 244 if (retval) 245 attach_option(opt_list, option, opt, length); 246 } while (retval && option->flags & OPTION_LIST); 247 return retval; 248 } 249 250 static int read_staticlease(const char *const_line, void *arg) 30 static int FAST_FUNC read_staticlease(const char *const_line, void *arg) 251 31 { 252 32 char *line; 253 33 char *mac_string; 254 34 char *ip_string; 255 uint8_t *mac_bytes; 256 uint32_t *ip; 257 258 /* Allocate memory for addresses */ 259 mac_bytes = xmalloc(sizeof(unsigned char) * 8); 260 ip = xmalloc(sizeof(uint32_t)); 35 struct ether_addr mac_bytes; /* it's "struct { uint8_t mac[6]; }" */ 36 uint32_t nip; 261 37 262 38 /* Read mac */ 263 39 line = (char *) const_line; 264 mac_string = strtok(line, " \t"); 265 read_mac(mac_string, mac_bytes); 40 mac_string = strtok_r(line, " \t", &line); 41 if (!mac_string || !ether_aton_r(mac_string, &mac_bytes)) 42 return 0; 266 43 267 44 /* Read ip */ 268 ip_string = strtok(NULL, " \t"); 269 read_ip(ip_string, ip); 270 271 addStaticLease(arg, mac_bytes, ip); 272 273 if (ENABLE_FEATURE_UDHCP_DEBUG) printStaticLeases(arg); 45 ip_string = strtok_r(NULL, " \t", &line); 46 if (!ip_string || !udhcp_str2nip(ip_string, &nip)) 47 return 0; 48 49 add_static_lease(arg, (uint8_t*) &mac_bytes, nip); 50 51 log_static_leases(arg); 274 52 275 53 return 1; … … 279 57 struct config_keyword { 280 58 const char *keyword; 281 int (*handler)(const char *line, void *var) ;59 int (*handler)(const char *line, void *var) FAST_FUNC; 282 60 void *var; 283 61 const char *def; … … 285 63 286 64 static const struct config_keyword keywords[] = { 287 /* keyword handler variable address default */ 288 {"start", read_ip, &(server_config.start_ip), "192.168.0.20"}, 289 {"end", read_ip, &(server_config.end_ip), "192.168.0.254"}, 290 {"interface", read_str, &(server_config.interface), "eth0"}, 291 {"option", read_opt, &(server_config.options), ""}, 292 {"opt", read_opt, &(server_config.options), ""}, 65 /* keyword handler variable address default */ 66 {"start" , udhcp_str2nip , &server_config.start_ip , "192.168.0.20"}, 67 {"end" , udhcp_str2nip , &server_config.end_ip , "192.168.0.254"}, 68 {"interface" , read_str , &server_config.interface , "eth0"}, 293 69 /* Avoid "max_leases value not sane" warning by setting default 294 70 * to default_end_ip - default_start_ip + 1: */ 295 {"max_leases", read_u32, &(server_config.max_leases), "235"}, 296 {"remaining", read_yn, &(server_config.remaining), "yes"}, 297 {"auto_time", read_u32, &(server_config.auto_time), "7200"}, 298 {"decline_time", read_u32, &(server_config.decline_time), "3600"}, 299 {"conflict_time",read_u32, &(server_config.conflict_time),"3600"}, 300 {"offer_time", read_u32, &(server_config.offer_time), "60"}, 301 {"min_lease", read_u32, &(server_config.min_lease), "60"}, 302 {"lease_file", read_str, &(server_config.lease_file), LEASES_FILE}, 303 {"pidfile", read_str, &(server_config.pidfile), "/var/run/udhcpd.pid"}, 304 {"notify_file", read_str, &(server_config.notify_file), ""}, 305 {"siaddr", read_ip, &(server_config.siaddr), "0.0.0.0"}, 306 {"sname", read_str, &(server_config.sname), ""}, 307 {"boot_file", read_str, &(server_config.boot_file), ""}, 308 {"static_lease", read_staticlease, &(server_config.static_leases), ""}, 309 /* ADDME: static lease */ 71 {"max_leases" , read_u32 , &server_config.max_leases , "235"}, 72 {"auto_time" , read_u32 , &server_config.auto_time , "7200"}, 73 {"decline_time" , read_u32 , &server_config.decline_time , "3600"}, 74 {"conflict_time", read_u32 , &server_config.conflict_time, "3600"}, 75 {"offer_time" , read_u32 , &server_config.offer_time , "60"}, 76 {"min_lease" , read_u32 , &server_config.min_lease_sec, "60"}, 77 {"lease_file" , read_str , &server_config.lease_file , LEASES_FILE}, 78 {"pidfile" , read_str , &server_config.pidfile , "/var/run/udhcpd.pid"}, 79 {"siaddr" , udhcp_str2nip , &server_config.siaddr_nip , "0.0.0.0"}, 80 /* keywords with no defaults must be last! */ 81 {"option" , udhcp_str2optset, &server_config.options , ""}, 82 {"opt" , udhcp_str2optset, &server_config.options , ""}, 83 {"notify_file" , read_str , &server_config.notify_file , ""}, 84 {"sname" , read_str , &server_config.sname , ""}, 85 {"boot_file" , read_str , &server_config.boot_file , ""}, 86 {"static_lease" , read_staticlease, &server_config.static_leases, ""}, 310 87 }; 311 312 313 /* 314 * Domain names may have 254 chars, and string options can be 254 315 * chars long. However, 80 bytes will be enough for most, and won't 316 * hog up memory. If you have a special application, change it 317 */ 318 #define READ_CONFIG_BUF_SIZE 80 319 320 int read_config(const char *file) 321 { 322 FILE *in; 323 char buffer[READ_CONFIG_BUF_SIZE], *token, *line; 324 int i, lm = 0; 325 326 for (i = 0; i < ARRAY_SIZE(keywords); i++) 327 if (keywords[i].def[0]) 328 keywords[i].handler(keywords[i].def, keywords[i].var); 329 330 in = fopen_or_warn(file, "r"); 331 if (!in) { 332 return 0; 333 } 334 335 while (fgets(buffer, READ_CONFIG_BUF_SIZE, in)) { 336 char debug_orig[READ_CONFIG_BUF_SIZE]; 337 char *p; 338 339 lm++; 340 p = strchr(buffer, '\n'); 341 if (p) *p = '\0'; 342 if (ENABLE_FEATURE_UDHCP_DEBUG) strcpy(debug_orig, buffer); 343 p = strchr(buffer, '#'); 344 if (p) *p = '\0'; 345 346 if (!(token = strtok(buffer, " \t"))) continue; 347 if (!(line = strtok(NULL, ""))) continue; 348 349 /* eat leading whitespace */ 350 line = skip_whitespace(line); 351 /* eat trailing whitespace */ 352 i = strlen(line) - 1; 353 while (i >= 0 && isspace(line[i])) 354 line[i--] = '\0'; 355 356 for (i = 0; i < ARRAY_SIZE(keywords); i++) 357 if (!strcasecmp(token, keywords[i].keyword)) 358 if (!keywords[i].handler(line, keywords[i].var)) { 359 bb_error_msg("cannot parse line %d of %s", lm, file); 360 if (ENABLE_FEATURE_UDHCP_DEBUG) 361 bb_error_msg("cannot parse '%s'", debug_orig); 88 enum { KWS_WITH_DEFAULTS = ARRAY_SIZE(keywords) - 6 }; 89 90 void FAST_FUNC read_config(const char *file) 91 { 92 parser_t *parser; 93 const struct config_keyword *k; 94 unsigned i; 95 char *token[2]; 96 97 for (i = 0; i < KWS_WITH_DEFAULTS; i++) 98 keywords[i].handler(keywords[i].def, keywords[i].var); 99 100 parser = config_open(file); 101 while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) { 102 for (k = keywords, i = 0; i < ARRAY_SIZE(keywords); k++, i++) { 103 if (strcasecmp(token[0], k->keyword) == 0) { 104 if (!k->handler(token[1], k->var)) { 105 bb_error_msg("can't parse line %u in %s", 106 parser->lineno, file); 362 107 /* reset back to the default value */ 363 k eywords[i].handler(keywords[i].def, keywords[i].var);108 k->handler(k->def, k->var); 364 109 } 365 } 366 fclose(in); 110 break; 111 } 112 } 113 } 114 config_close(parser); 367 115 368 116 server_config.start_ip = ntohl(server_config.start_ip); 369 117 server_config.end_ip = ntohl(server_config.end_ip); 370 371 return 1; 372 } 373 374 375 void write_leases(void) 376 { 377 int fp; 118 } 119 120 void FAST_FUNC write_leases(void) 121 { 122 int fd; 378 123 unsigned i; 379 time_t curr = time(0);380 unsigned long tmp_time;381 382 f p = open3_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC, 0666);383 if (f p < 0) {124 leasetime_t curr; 125 int64_t written_at; 126 127 fd = open_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC); 128 if (fd < 0) 384 129 return; 385 } 130 131 curr = written_at = time(NULL); 132 133 written_at = SWAP_BE64(written_at); 134 full_write(fd, &written_at, sizeof(written_at)); 386 135 387 136 for (i = 0; i < server_config.max_leases; i++) { 388 if (leases[i].yiaddr != 0) { 389 390 /* screw with the time in the struct, for easier writing */ 391 tmp_time = leases[i].expires; 392 393 if (server_config.remaining) { 394 if (lease_expired(&(leases[i]))) 395 leases[i].expires = 0; 396 else leases[i].expires -= curr; 397 } /* else stick with the time we got */ 398 leases[i].expires = htonl(leases[i].expires); 399 // FIXME: error check?? 400 full_write(fp, &leases[i], sizeof(leases[i])); 401 402 /* then restore it when done */ 403 leases[i].expires = tmp_time; 404 } 405 } 406 close(fp); 137 leasetime_t tmp_time; 138 139 if (g_leases[i].lease_nip == 0) 140 continue; 141 142 /* Screw with the time in the struct, for easier writing */ 143 tmp_time = g_leases[i].expires; 144 145 g_leases[i].expires -= curr; 146 if ((signed_leasetime_t) g_leases[i].expires < 0) 147 g_leases[i].expires = 0; 148 g_leases[i].expires = htonl(g_leases[i].expires); 149 150 /* No error check. If the file gets truncated, 151 * we lose some leases on restart. Oh well. */ 152 full_write(fd, &g_leases[i], sizeof(g_leases[i])); 153 154 /* Then restore it when done */ 155 g_leases[i].expires = tmp_time; 156 } 157 close(fd); 407 158 408 159 if (server_config.notify_file) { 409 char *cmd = xasprintf("%s %s", server_config.notify_file, server_config.lease_file); 410 system(cmd); 411 free(cmd); 412 } 413 } 414 415 416 void read_leases(const char *file) 417 { 418 int fp; 419 unsigned int i = 0; 420 struct dhcpOfferedAddr lease; 421 422 fp = open_or_warn(file, O_RDONLY); 423 if (fp < 0) { 160 char *argv[3]; 161 argv[0] = server_config.notify_file; 162 argv[1] = server_config.lease_file; 163 argv[2] = NULL; 164 spawn_and_wait(argv); 165 } 166 } 167 168 void FAST_FUNC read_leases(const char *file) 169 { 170 struct dyn_lease lease; 171 int64_t written_at, time_passed; 172 int fd; 173 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 174 unsigned i = 0; 175 #endif 176 177 fd = open_or_warn(file, O_RDONLY); 178 if (fd < 0) 424 179 return; 425 } 426 427 while (i < server_config.max_leases 428 && full_read(fp, &lease, sizeof(lease)) == sizeof(lease) 429 ) { 430 /* ADDME: is it a static lease */ 431 uint32_t y = ntohl(lease.yiaddr); 180 181 if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at)) 182 goto ret; 183 written_at = SWAP_BE64(written_at); 184 185 time_passed = time(NULL) - written_at; 186 /* Strange written_at, or lease file from old version of udhcpd 187 * which had no "written_at" field? */ 188 if ((uint64_t)time_passed > 12 * 60 * 60) 189 goto ret; 190 191 while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) { 192 //FIXME: what if it matches some static lease? 193 uint32_t y = ntohl(lease.lease_nip); 432 194 if (y >= server_config.start_ip && y <= server_config.end_ip) { 433 lease.expires = ntohl(lease.expires); 434 if (!server_config.remaining) 435 lease.expires -= time(0); 436 if (!(add_lease(lease.chaddr, lease.yiaddr, lease.expires))) { 195 signed_leasetime_t expires = ntohl(lease.expires) - (signed_leasetime_t)time_passed; 196 if (expires <= 0) 197 continue; 198 /* NB: add_lease takes "relative time", IOW, 199 * lease duration, not lease deadline. */ 200 if (add_lease(lease.lease_mac, lease.lease_nip, 201 expires, 202 lease.hostname, sizeof(lease.hostname) 203 ) == 0 204 ) { 437 205 bb_error_msg("too many leases while loading %s", file); 438 206 break; 439 207 } 208 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 440 209 i++; 210 #endif 441 211 } 442 212 } 443 DEBUG("Read %d leases", i); 444 close(fp); 445 } 213 log1("Read %d leases", i); 214 ret: 215 close(fd); 216 } -
branches/2.2.9/mindi-busybox/networking/udhcp/leases.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * leases.c -- tools to manage DHCP leases4 3 * Russ Dill <Russ.Dill@asu.edu> July 2001 4 * 5 * Licensed under GPLv2, see file LICENSE in this source tree. 5 6 */ 6 7 7 #include "common.h" 8 8 #include "dhcpd.h" 9 9 10 11 10 /* Find the oldest expired lease, NULL if there are no expired leases */ 12 static struct d hcpOfferedAddr*oldest_expired_lease(void)11 static struct dyn_lease *oldest_expired_lease(void) 13 12 { 14 struct dhcpOfferedAddr *oldest = NULL; 15 // TODO: use monotonic_sec() 16 unsigned long oldest_lease = time(0); 13 struct dyn_lease *oldest_lease = NULL; 14 leasetime_t oldest_time = time(NULL); 17 15 unsigned i; 18 16 19 for (i = 0; i < server_config.max_leases; i++) 20 if (oldest_lease > leases[i].expires) { 21 oldest_lease = leases[i].expires; 22 oldest = &(leases[i]); 17 /* Unexpired leases have g_leases[i].expires >= current time 18 * and therefore can't ever match */ 19 for (i = 0; i < server_config.max_leases; i++) { 20 if (g_leases[i].expires < oldest_time) { 21 oldest_time = g_leases[i].expires; 22 oldest_lease = &g_leases[i]; 23 23 } 24 return oldest; 24 } 25 return oldest_lease; 25 26 } 26 27 28 /* Clear out all leases with matching nonzero chaddr OR yiaddr. 29 * If chaddr == NULL, this is a conflict lease. 30 */ 31 static void clear_leases(const uint8_t *chaddr, uint32_t yiaddr) 32 { 33 unsigned i; 27 34 28 /* clear every lease out that chaddr OR yiaddr matches and is nonzero */ 29 static void clear_lease(const uint8_t *chaddr, uint32_t yiaddr) 30 { 31 unsigned i, j; 32 33 for (j = 0; j < 16 && !chaddr[j]; j++) 34 continue; 35 36 for (i = 0; i < server_config.max_leases; i++) 37 if ((j != 16 && memcmp(leases[i].chaddr, chaddr, 16) == 0) 38 || (yiaddr && leases[i].yiaddr == yiaddr) 35 for (i = 0; i < server_config.max_leases; i++) { 36 if ((chaddr && memcmp(g_leases[i].lease_mac, chaddr, 6) == 0) 37 || (yiaddr && g_leases[i].lease_nip == yiaddr) 39 38 ) { 40 memset(& (leases[i]), 0, sizeof(leases[i]));39 memset(&g_leases[i], 0, sizeof(g_leases[i])); 41 40 } 41 } 42 42 } 43 43 44 45 /* add a lease into the table, clearing out any old ones */ 46 struct dhcpOfferedAddr *add_lease(const uint8_t *chaddr, uint32_t yiaddr, unsigned long lease) 44 /* Add a lease into the table, clearing out any old ones. 45 * If chaddr == NULL, this is a conflict lease. 46 */ 47 struct dyn_lease* FAST_FUNC add_lease( 48 const uint8_t *chaddr, uint32_t yiaddr, 49 leasetime_t leasetime, 50 const char *hostname, int hostname_len) 47 51 { 48 struct d hcpOfferedAddr*oldest;52 struct dyn_lease *oldest; 49 53 50 54 /* clean out any old ones */ 51 clear_lease (chaddr, yiaddr);55 clear_leases(chaddr, yiaddr); 52 56 53 57 oldest = oldest_expired_lease(); 54 58 55 59 if (oldest) { 56 memcpy(oldest->chaddr, chaddr, 16); 57 oldest->yiaddr = yiaddr; 58 oldest->expires = time(0) + lease; 60 memset(oldest, 0, sizeof(*oldest)); 61 if (hostname) { 62 char *p; 63 64 hostname_len++; /* include NUL */ 65 if (hostname_len > sizeof(oldest->hostname)) 66 hostname_len = sizeof(oldest->hostname); 67 p = safe_strncpy(oldest->hostname, hostname, hostname_len); 68 /* sanitization (s/non-ASCII/^/g) */ 69 while (*p) { 70 if (*p < ' ' || *p > 126) 71 *p = '^'; 72 p++; 73 } 74 } 75 if (chaddr) 76 memcpy(oldest->lease_mac, chaddr, 6); 77 oldest->lease_nip = yiaddr; 78 oldest->expires = time(NULL) + leasetime; 59 79 } 60 80 … … 62 82 } 63 83 64 65 /* true if a lease has expired */ 66 int lease_expired(struct dhcpOfferedAddr *lease) 84 /* True if a lease has expired */ 85 int FAST_FUNC is_expired_lease(struct dyn_lease *lease) 67 86 { 68 return (lease->expires < ( unsigned long) time(0));87 return (lease->expires < (leasetime_t) time(NULL)); 69 88 } 70 89 71 72 /* Find the first lease that matches chaddr, NULL if no match */ 73 struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr) 90 /* Find the first lease that matches MAC, NULL if no match */ 91 struct dyn_lease* FAST_FUNC find_lease_by_mac(const uint8_t *mac) 74 92 { 75 93 unsigned i; 76 94 77 95 for (i = 0; i < server_config.max_leases; i++) 78 if ( !memcmp(leases[i].chaddr, chaddr, 16))79 return & (leases[i]);96 if (memcmp(g_leases[i].lease_mac, mac, 6) == 0) 97 return &g_leases[i]; 80 98 81 99 return NULL; 82 100 } 83 101 84 85 /* Find the first lease that matches yiaddr, NULL is no match */ 86 struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr) 102 /* Find the first lease that matches IP, NULL is no match */ 103 struct dyn_lease* FAST_FUNC find_lease_by_nip(uint32_t nip) 87 104 { 88 105 unsigned i; 89 106 90 107 for (i = 0; i < server_config.max_leases; i++) 91 if ( leases[i].yiaddr == yiaddr)92 return & (leases[i]);108 if (g_leases[i].lease_nip == nip) 109 return &g_leases[i]; 93 110 94 111 return NULL; 95 112 } 96 113 97 98 /* check is an IP is taken, if it is, add it to the lease table */ 99 static int nobody_responds_to_arp(uint32_t addr) 114 /* Check if the IP is taken; if it is, add it to the lease table */ 115 static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac) 100 116 { 101 static const uint8_t blank_chaddr[16]; /* 16 zero bytes */102 103 117 struct in_addr temp; 104 118 int r; 105 119 106 r = arpping(addr, server_config.server, server_config.arp, server_config.interface); 120 r = arpping(nip, safe_mac, 121 server_config.server_nip, 122 server_config.server_mac, 123 server_config.interface); 107 124 if (r) 108 125 return r; 109 126 110 temp.s_addr = addr;127 temp.s_addr = nip; 111 128 bb_info_msg("%s belongs to someone, reserving it for %u seconds", 112 129 inet_ntoa(temp), (unsigned)server_config.conflict_time); 113 add_lease( blank_chaddr, addr, server_config.conflict_time);130 add_lease(NULL, nip, server_config.conflict_time, NULL, 0); 114 131 return 0; 115 132 } 116 133 117 118 /* find an assignable address, if check_expired is true, we check all the expired leases as well. 119 * Maybe this should try expired leases by age... */ 120 uint32_t find_address(int check_expired) 134 /* Find a new usable (we think) address */ 135 uint32_t FAST_FUNC find_free_or_expired_nip(const uint8_t *safe_mac) 121 136 { 122 uint32_t addr , ret;123 struct d hcpOfferedAddr *lease = NULL;137 uint32_t addr; 138 struct dyn_lease *oldest_lease = NULL; 124 139 125 140 addr = server_config.start_ip; /* addr is in host order here */ 126 141 for (; addr <= server_config.end_ip; addr++) { 142 uint32_t nip; 143 struct dyn_lease *lease; 144 127 145 /* ie, 192.168.55.0 */ 128 if ( !(addr & 0xFF))146 if ((addr & 0xff) == 0) 129 147 continue; 130 148 /* ie, 192.168.55.255 */ 131 if ((addr & 0x FF) == 0xFF)149 if ((addr & 0xff) == 0xff) 132 150 continue; 133 /* Only do if it isn't assigned as a static lease */ 134 ret = htonl(addr); 135 if (!reservedIp(server_config.static_leases, ret)) { 136 /* lease is not taken */ 137 lease = find_lease_by_yiaddr(ret); 138 /* no lease or it expired and we are checking for expired leases */ 139 if ((!lease || (check_expired && lease_expired(lease))) 140 && nobody_responds_to_arp(ret) /* it isn't used on the network */ 141 ) { 142 return ret; 143 } 151 nip = htonl(addr); 152 /* is this a static lease addr? */ 153 if (is_nip_reserved(server_config.static_leases, nip)) 154 continue; 155 156 lease = find_lease_by_nip(nip); 157 if (!lease) { 158 //TODO: DHCP servers do not always sit on the same subnet as clients: should *ping*, not arp-ping! 159 if (nobody_responds_to_arp(nip, safe_mac)) 160 return nip; 161 } else { 162 if (!oldest_lease || lease->expires < oldest_lease->expires) 163 oldest_lease = lease; 144 164 } 145 165 } 166 167 if (oldest_lease 168 && is_expired_lease(oldest_lease) 169 && nobody_responds_to_arp(oldest_lease->lease_nip, safe_mac) 170 ) { 171 return oldest_lease->lease_nip; 172 } 173 146 174 return 0; 147 175 } -
branches/2.2.9/mindi-busybox/networking/udhcp/packet.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * Packet ops 4 * 5 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001 6 * 7 * Licensed under GPLv2, see file LICENSE in this source tree. 8 */ 3 9 #include <netinet/in.h> 4 10 #if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION 5 # include <netpacket/packet.h>6 # include <net/ethernet.h>11 # include <netpacket/packet.h> 12 # include <net/ethernet.h> 7 13 #else 8 # include <asm/types.h>9 # include <linux/if_packet.h>10 # include <linux/if_ether.h>14 # include <asm/types.h> 15 # include <linux/if_packet.h> 16 # include <linux/if_ether.h> 11 17 #endif 12 18 13 19 #include "common.h" 14 20 #include "dhcpd.h" 15 #include "options.h" 16 17 18 void udhcp_init_header(struct dhcpMessage *packet, char type) 19 { 20 memset(packet, 0, sizeof(struct dhcpMessage)); 21 22 void FAST_FUNC udhcp_init_header(struct dhcp_packet *packet, char type) 23 { 24 memset(packet, 0, sizeof(*packet)); 25 packet->op = BOOTREQUEST; /* if client to a server */ 21 26 switch (type) { 22 case DHCPDISCOVER:23 case DHCPREQUEST:24 case DHCPRELEASE:25 case DHCPINFORM:26 packet->op = BOOTREQUEST;27 break;28 27 case DHCPOFFER: 29 28 case DHCPACK: 30 29 case DHCPNAK: 31 packet->op = BOOTREPLY; 32 } 33 packet->htype = ETH_10MB;34 packet->hlen = ETH_10MB_LEN;30 packet->op = BOOTREPLY; /* if server to client */ 31 } 32 packet->htype = 1; /* ethernet */ 33 packet->hlen = 6; 35 34 packet->cookie = htonl(DHCP_MAGIC); 36 packet->options[0] = DHCP_END; 37 add_simple_option(packet->options, DHCP_MESSAGE_TYPE, type); 38 } 39 40 41 /* read a packet from socket fd, return -1 on read error, -2 on packet error */ 42 int udhcp_get_packet(struct dhcpMessage *packet, int fd) 43 { 44 #if 0 45 static const char broken_vendors[][8] = { 46 "MSFT 98", 47 "" 48 }; 35 if (DHCP_END != 0) 36 packet->options[0] = DHCP_END; 37 udhcp_add_simple_option(packet, DHCP_MESSAGE_TYPE, type); 38 } 39 40 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2 41 void FAST_FUNC udhcp_dump_packet(struct dhcp_packet *packet) 42 { 43 char buf[sizeof(packet->chaddr)*2 + 1]; 44 45 if (dhcp_verbose < 2) 46 return; 47 48 bb_info_msg( 49 //" op %x" 50 //" htype %x" 51 " hlen %x" 52 //" hops %x" 53 " xid %x" 54 //" secs %x" 55 //" flags %x" 56 " ciaddr %x" 57 " yiaddr %x" 58 " siaddr %x" 59 " giaddr %x" 60 //" chaddr %s" 61 //" sname %s" 62 //" file %s" 63 //" cookie %x" 64 //" options %s" 65 //, packet->op 66 //, packet->htype 67 , packet->hlen 68 //, packet->hops 69 , packet->xid 70 //, packet->secs 71 //, packet->flags 72 , packet->ciaddr 73 , packet->yiaddr 74 , packet->siaddr_nip 75 , packet->gateway_nip 76 //, packet->chaddr[16] 77 //, packet->sname[64] 78 //, packet->file[128] 79 //, packet->cookie 80 //, packet->options[] 81 ); 82 *bin2hex(buf, (void *) packet->chaddr, sizeof(packet->chaddr)) = '\0'; 83 bb_info_msg(" chaddr %s", buf); 84 } 49 85 #endif 86 87 /* Read a packet from socket fd, return -1 on read error, -2 on packet error */ 88 int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) 89 { 50 90 int bytes; 51 91 unsigned char *vendor; 52 92 53 93 memset(packet, 0, sizeof(*packet)); 54 bytes = read(fd, packet, sizeof(*packet));94 bytes = safe_read(fd, packet, sizeof(*packet)); 55 95 if (bytes < 0) { 56 DEBUG("cannot read on listening socket, ignoring");57 return -1;58 } 59 60 if ( ntohl(packet->cookie) != DHCP_MAGIC) {61 bb_ error_msg("received bogus message, ignoring");96 log1("Packet read error, ignoring"); 97 return bytes; /* returns -1 */ 98 } 99 100 if (packet->cookie != htonl(DHCP_MAGIC)) { 101 bb_info_msg("Packet with bad magic, ignoring"); 62 102 return -2; 63 103 } 64 DEBUG("Received a packet"); 104 log1("Received a packet"); 105 udhcp_dump_packet(packet); 65 106 66 107 if (packet->op == BOOTREQUEST) { 67 vendor = get_option(packet, DHCP_VENDOR);108 vendor = udhcp_get_option(packet, DHCP_VENDOR); 68 109 if (vendor) { 69 110 #if 0 111 static const char broken_vendors[][8] = { 112 "MSFT 98", 113 "" 114 }; 70 115 int i; 71 116 for (i = 0; broken_vendors[i][0]; i++) { 72 if (vendor[OPT_LEN - 2] == (uint8_t)strlen(broken_vendors[i])73 && !strncmp((char*)vendor, broken_vendors[i], vendor[OPT_LEN - 2])117 if (vendor[OPT_LEN - OPT_DATA] == (uint8_t)strlen(broken_vendors[i]) 118 && strncmp((char*)vendor, broken_vendors[i], vendor[OPT_LEN - OPT_DATA]) == 0 74 119 ) { 75 DEBUG("broken client (%s), forcing broadcast",120 log1("Broken client (%s), forcing broadcast replies", 76 121 broken_vendors[i]); 77 122 packet->flags |= htons(BROADCAST_FLAG); … … 79 124 } 80 125 #else 81 if (vendor[OPT_LEN - 2] == (uint8_t)(sizeof("MSFT 98")-1)126 if (vendor[OPT_LEN - OPT_DATA] == (uint8_t)(sizeof("MSFT 98")-1) 82 127 && memcmp(vendor, "MSFT 98", sizeof("MSFT 98")-1) == 0 83 128 ) { 84 DEBUG("broken client (%s), forcing broadcast", "MSFT 98");129 log1("Broken client (%s), forcing broadcast replies", "MSFT 98"); 85 130 packet->flags |= htons(BROADCAST_FLAG); 86 131 } … … 92 137 } 93 138 94 95 uint16_t udhcp_checksum(void *addr, int count) 139 uint16_t FAST_FUNC udhcp_checksum(void *addr, int count) 96 140 { 97 141 /* Compute Internet Checksum for "count" bytes 98 * 142 * beginning at location "addr". 99 143 */ 100 144 int32_t sum = 0; … … 112 156 * with little and big endian hosts */ 113 157 uint16_t tmp = 0; 114 *(uint8_t *) (&tmp) = * (uint8_t *)source;158 *(uint8_t*)&tmp = *(uint8_t*)source; 115 159 sum += tmp; 116 160 } … … 122 166 } 123 167 124 125 /* Construct a ip/udp header for a packet, and specify the source and dest hardware address */ 126 void BUG_sizeof_struct_udp_dhcp_packet_must_be_576(void); 127 int udhcp_raw_packet(struct dhcpMessage *payload, 128 uint32_t source_ip, int source_port, 129 uint32_t dest_ip, int dest_port, const uint8_t *dest_arp, int ifindex) 130 { 168 /* Construct a ip/udp header for a packet, send packet */ 169 int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, 170 uint32_t source_nip, int source_port, 171 uint32_t dest_nip, int dest_port, const uint8_t *dest_arp, 172 int ifindex) 173 { 174 struct sockaddr_ll dest_sll; 175 struct ip_udp_dhcp_packet packet; 176 unsigned padding; 131 177 int fd; 132 int result; 133 struct sockaddr_ll dest; 134 struct udp_dhcp_packet packet; 178 int result = -1; 179 const char *msg; 135 180 136 181 fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); 137 182 if (fd < 0) { 138 bb_perror_msg("socket"); 139 return -1; 140 } 141 142 memset(&dest, 0, sizeof(dest)); 143 memset(&packet, 0, sizeof(packet)); 144 145 dest.sll_family = AF_PACKET; 146 dest.sll_protocol = htons(ETH_P_IP); 147 dest.sll_ifindex = ifindex; 148 dest.sll_halen = 6; 149 memcpy(dest.sll_addr, dest_arp, 6); 150 if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) { 151 bb_perror_msg("bind"); 152 close(fd); 153 return -1; 154 } 183 msg = "socket(%s)"; 184 goto ret_msg; 185 } 186 187 memset(&dest_sll, 0, sizeof(dest_sll)); 188 memset(&packet, 0, offsetof(struct ip_udp_dhcp_packet, data)); 189 packet.data = *dhcp_pkt; /* struct copy */ 190 191 dest_sll.sll_family = AF_PACKET; 192 dest_sll.sll_protocol = htons(ETH_P_IP); 193 dest_sll.sll_ifindex = ifindex; 194 dest_sll.sll_halen = 6; 195 memcpy(dest_sll.sll_addr, dest_arp, 6); 196 197 if (bind(fd, (struct sockaddr *)&dest_sll, sizeof(dest_sll)) < 0) { 198 msg = "bind(%s)"; 199 goto ret_close; 200 } 201 202 /* We were sending full-sized DHCP packets (zero padded), 203 * but some badly configured servers were seen dropping them. 204 * Apparently they drop all DHCP packets >576 *ethernet* octets big, 205 * whereas they may only drop packets >576 *IP* octets big 206 * (which for typical Ethernet II means 590 octets: 6+6+2 + 576). 207 * 208 * In order to work with those buggy servers, 209 * we truncate packets after end option byte. 210 */ 211 padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(packet.data.options); 155 212 156 213 packet.ip.protocol = IPPROTO_UDP; 157 packet.ip.saddr = source_ ip;158 packet.ip.daddr = dest_ ip;214 packet.ip.saddr = source_nip; 215 packet.ip.daddr = dest_nip; 159 216 packet.udp.source = htons(source_port); 160 217 packet.udp.dest = htons(dest_port); 161 packet.udp.len = htons(sizeof(packet.udp) + sizeof(struct dhcpMessage)); /* cheat on the psuedo-header */ 218 /* size, excluding IP header: */ 219 packet.udp.len = htons(UDP_DHCP_SIZE - padding); 220 /* for UDP checksumming, ip.len is set to UDP packet len */ 162 221 packet.ip.tot_len = packet.udp.len; 163 memcpy(&(packet.data), payload, sizeof(struct dhcpMessage)); 164 packet.udp.check = udhcp_checksum(&packet, sizeof(struct udp_dhcp_packet)); 165 166 packet.ip.tot_len = htons(sizeof(struct udp_dhcp_packet)); 222 packet.udp.check = udhcp_checksum(&packet, IP_UDP_DHCP_SIZE - padding); 223 /* but for sending, it is set to IP packet len */ 224 packet.ip.tot_len = htons(IP_UDP_DHCP_SIZE - padding); 167 225 packet.ip.ihl = sizeof(packet.ip) >> 2; 168 226 packet.ip.version = IPVERSION; 169 227 packet.ip.ttl = IPDEFTTL; 170 packet.ip.check = udhcp_checksum(&(packet.ip), sizeof(packet.ip)); 171 172 if (sizeof(struct udp_dhcp_packet) != 576) 173 BUG_sizeof_struct_udp_dhcp_packet_must_be_576(); 174 175 result = sendto(fd, &packet, sizeof(struct udp_dhcp_packet), 0, 176 (struct sockaddr *) &dest, sizeof(dest)); 177 if (result <= 0) { 178 bb_perror_msg("sendto"); 179 } 228 packet.ip.check = udhcp_checksum(&packet.ip, sizeof(packet.ip)); 229 230 udhcp_dump_packet(dhcp_pkt); 231 result = sendto(fd, &packet, IP_UDP_DHCP_SIZE - padding, /*flags:*/ 0, 232 (struct sockaddr *) &dest_sll, sizeof(dest_sll)); 233 msg = "sendto"; 234 ret_close: 180 235 close(fd); 236 if (result < 0) { 237 ret_msg: 238 bb_perror_msg(msg, "PACKET"); 239 } 181 240 return result; 182 241 } 183 242 184 185 243 /* Let the kernel do all the work for packet generation */ 186 int udhcp_kernel_packet(struct dhcpMessage *payload, 187 uint32_t source_ip, int source_port, 188 uint32_t dest_ip, int dest_port) 189 { 190 int fd, result; 244 int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, 245 uint32_t source_nip, int source_port, 246 uint32_t dest_nip, int dest_port) 247 { 191 248 struct sockaddr_in client; 249 unsigned padding; 250 int fd; 251 int result = -1; 252 const char *msg; 192 253 193 254 fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 194 if (fd < 0) 195 return -1; 196 255 if (fd < 0) { 256 msg = "socket(%s)"; 257 goto ret_msg; 258 } 197 259 setsockopt_reuseaddr(fd); 198 260 … … 200 262 client.sin_family = AF_INET; 201 263 client.sin_port = htons(source_port); 202 client.sin_addr.s_addr = source_ip; 203 264 client.sin_addr.s_addr = source_nip; 204 265 if (bind(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { 205 close(fd);206 return -1;266 msg = "bind(%s)"; 267 goto ret_close; 207 268 } 208 269 … … 210 271 client.sin_family = AF_INET; 211 272 client.sin_port = htons(dest_port); 212 client.sin_addr.s_addr = dest_ip; 213 214 if (connect(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1) { 215 close(fd); 216 return -1; 217 } 218 219 result = write(fd, payload, sizeof(struct dhcpMessage)); 273 client.sin_addr.s_addr = dest_nip; 274 if (connect(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { 275 msg = "connect"; 276 goto ret_close; 277 } 278 279 udhcp_dump_packet(dhcp_pkt); 280 281 padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(dhcp_pkt->options); 282 result = safe_write(fd, dhcp_pkt, DHCP_SIZE - padding); 283 msg = "write"; 284 ret_close: 220 285 close(fd); 286 if (result < 0) { 287 ret_msg: 288 bb_perror_msg(msg, "UDP"); 289 } 221 290 return result; 222 291 } -
branches/2.2.9/mindi-busybox/networking/udhcp/signalpipe.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 /* signalpipe.c 3 * 2 /* 4 3 * Signal pipe infrastructure. A reliable way of delivering signals. 5 4 * … … 20 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 20 */ 22 23 21 #include "common.h" 24 22 25 26 static int signal_pipe[2];23 /* Global variable: we access it from signal handler */ 24 static struct fd_pair signal_pipe; 27 25 28 26 static void signal_handler(int sig) 29 27 { 30 28 unsigned char ch = sig; /* use char, avoid dealing with partial writes */ 31 if (write(signal_pipe [1], &ch, 1) != 1)32 bb_perror_msg("can not send signal");29 if (write(signal_pipe.wr, &ch, 1) != 1) 30 bb_perror_msg("can't send signal"); 33 31 } 34 35 32 36 33 /* Call this before doing anything else. Sets up the socket pair 37 34 * and installs the signal handler */ 38 void udhcp_sp_setup(void)35 void FAST_FUNC udhcp_sp_setup(void) 39 36 { 40 37 /* was socketpair, but it needs AF_UNIX in kernel */ 41 xpipe(signal_pipe); 42 fcntl(signal_pipe[0], F_SETFD, FD_CLOEXEC); 43 fcntl(signal_pipe[1], F_SETFD, FD_CLOEXEC); 44 fcntl(signal_pipe[1], F_SETFL, O_NONBLOCK); 45 signal(SIGUSR1, signal_handler); 46 signal(SIGUSR2, signal_handler); 47 signal(SIGTERM, signal_handler); 38 xpiped_pair(signal_pipe); 39 close_on_exec_on(signal_pipe.rd); 40 close_on_exec_on(signal_pipe.wr); 41 ndelay_on(signal_pipe.wr); 42 bb_signals(0 43 + (1 << SIGUSR1) 44 + (1 << SIGUSR2) 45 + (1 << SIGTERM) 46 , signal_handler); 48 47 } 49 50 48 51 49 /* Quick little function to setup the rfds. Will return the 52 50 * max_fd for use with select. Limited in that you can only pass 53 51 * one extra fd */ 54 int udhcp_sp_fd_set(fd_set *rfds, int extra_fd)52 int FAST_FUNC udhcp_sp_fd_set(fd_set *rfds, int extra_fd) 55 53 { 56 54 FD_ZERO(rfds); 57 FD_SET(signal_pipe [0], rfds);55 FD_SET(signal_pipe.rd, rfds); 58 56 if (extra_fd >= 0) { 59 fcntl(extra_fd, F_SETFD, FD_CLOEXEC);57 close_on_exec_on(extra_fd); 60 58 FD_SET(extra_fd, rfds); 61 59 } 62 return signal_pipe [0] > extra_fd ? signal_pipe[0]: extra_fd;60 return signal_pipe.rd > extra_fd ? signal_pipe.rd : extra_fd; 63 61 } 64 65 62 66 63 /* Read a signal from the signal pipe. Returns 0 if there is 67 64 * no signal, -1 on error (and sets errno appropriately), and 68 65 * your signal on success */ 69 int udhcp_sp_read(fd_set *rfds)66 int FAST_FUNC udhcp_sp_read(const fd_set *rfds) 70 67 { 71 68 unsigned char sig; 72 69 73 if (!FD_ISSET(signal_pipe [0], rfds))70 if (!FD_ISSET(signal_pipe.rd, rfds)) 74 71 return 0; 75 72 76 if ( read(signal_pipe[0], &sig, 1) != 1)73 if (safe_read(signal_pipe.rd, &sig, 1) != 1) 77 74 return -1; 78 75 -
branches/2.2.9/mindi-busybox/networking/udhcp/socket.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * socket.c --DHCP server client/server socket creation3 * DHCP server client/server socket creation 4 4 * 5 5 * udhcp client/server … … 23 23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24 24 */ 25 26 25 #include <net/if.h> 27 #include <features.h>28 26 #if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION 29 # include <netpacket/packet.h>30 # include <net/ethernet.h>27 # include <netpacket/packet.h> 28 # include <net/ethernet.h> 31 29 #else 32 # include <asm/types.h>33 # include <linux/if_packet.h>34 # include <linux/if_ether.h>30 # include <asm/types.h> 31 # include <linux/if_packet.h> 32 # include <linux/if_ether.h> 35 33 #endif 36 34 37 35 #include "common.h" 38 36 39 40 int read_interface(const char *interface, int *ifindex, uint32_t *addr, uint8_t *arp) 37 int FAST_FUNC udhcp_read_interface(const char *interface, int *ifindex, uint32_t *nip, uint8_t *mac) 41 38 { 42 39 int fd; … … 48 45 49 46 ifr.ifr_addr.sa_family = AF_INET; 50 strncpy (ifr.ifr_name, interface, sizeof(ifr.ifr_name));51 if ( addr) {47 strncpy_IFNAMSIZ(ifr.ifr_name, interface); 48 if (nip) { 52 49 if (ioctl_or_perror(fd, SIOCGIFADDR, &ifr, 53 50 "is interface %s up and configured?", interface) … … 57 54 } 58 55 our_ip = (struct sockaddr_in *) &ifr.ifr_addr; 59 * addr= our_ip->sin_addr.s_addr;60 DEBUG("%s (our ip) = %s", ifr.ifr_name, inet_ntoa(our_ip->sin_addr));56 *nip = our_ip->sin_addr.s_addr; 57 log1("IP %s", inet_ntoa(our_ip->sin_addr)); 61 58 } 62 59 … … 66 63 return -1; 67 64 } 68 DEBUG("adapter index %d", ifr.ifr_ifindex);65 log1("Adapter index %d", ifr.ifr_ifindex); 69 66 *ifindex = ifr.ifr_ifindex; 70 67 } 71 68 72 if ( arp) {69 if (mac) { 73 70 if (ioctl_or_warn(fd, SIOCGIFHWADDR, &ifr) != 0) { 74 71 close(fd); 75 72 return -1; 76 73 } 77 memcpy( arp, ifr.ifr_hwaddr.sa_data, 6);78 DEBUG("adapter hardware address%02x:%02x:%02x:%02x:%02x:%02x",79 arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]);74 memcpy(mac, ifr.ifr_hwaddr.sa_data, 6); 75 log1("MAC %02x:%02x:%02x:%02x:%02x:%02x", 76 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 80 77 } 81 78 … … 86 83 /* 1. None of the callers expects it to ever fail */ 87 84 /* 2. ip was always INADDR_ANY */ 88 int listen_socket(/*uint32_t ip,*/ int port, const char *inf)85 int FAST_FUNC udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf) 89 86 { 90 87 int fd; 91 struct ifreq interface;92 88 struct sockaddr_in addr; 93 89 94 DEBUG("Opening listen socket on *:%d %s", port, inf);90 log1("Opening listen socket on *:%d %s", port, inf); 95 91 fd = xsocket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 96 92 … … 99 95 bb_perror_msg_and_die("SO_BROADCAST"); 100 96 101 strncpy(interface.ifr_name, inf, IFNAMSIZ);102 if (setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, &interface, sizeof(interface)) == -1)103 bb_perror_msg_and_die("SO_BINDTODEVICE");97 /* NB: bug 1032 says this doesn't work on ethernet aliases (ethN:M) */ 98 if (setsockopt_bindtodevice(fd, inf)) 99 xfunc_die(); /* warning is already printed */ 104 100 105 101 memset(&addr, 0, sizeof(addr)); -
branches/2.2.9/mindi-busybox/networking/udhcp/static_leases.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * static_leases.c -- Couple of functions to assist with storing and 4 * retrieving data for static leases 3 * Storing and retrieving data for static leases 5 4 * 6 5 * Wade Berrier <wberrier@myrealbox.com> September 2004 7 6 * 7 * Licensed under GPLv2, see file LICENSE in this source tree. 8 8 */ 9 10 9 #include "common.h" 11 10 #include "dhcpd.h" 12 11 12 /* Takes the address of the pointer to the static_leases linked list, 13 * address to a 6 byte mac address, 14 * 4 byte IP address */ 15 void FAST_FUNC add_static_lease(struct static_lease **st_lease_pp, 16 uint8_t *mac, 17 uint32_t nip) 18 { 19 struct static_lease *st_lease; 13 20 14 /* Takes the address of the pointer to the static_leases linked list, 15 * Address to a 6 byte mac address 16 * Address to a 4 byte ip address */ 17 int addStaticLease(struct static_lease **lease_struct, uint8_t *mac, uint32_t *ip) 21 /* Find the tail of the list */ 22 while ((st_lease = *st_lease_pp) != NULL) { 23 st_lease_pp = &st_lease->next; 24 } 25 26 /* Add new node */ 27 *st_lease_pp = st_lease = xzalloc(sizeof(*st_lease)); 28 memcpy(st_lease->mac, mac, 6); 29 st_lease->nip = nip; 30 /*st_lease->next = NULL;*/ 31 } 32 33 /* Find static lease IP by mac */ 34 uint32_t FAST_FUNC get_static_nip_by_mac(struct static_lease *st_lease, void *mac) 35 { 36 while (st_lease) { 37 if (memcmp(st_lease->mac, mac, 6) == 0) 38 return st_lease->nip; 39 st_lease = st_lease->next; 40 } 41 42 return 0; 43 } 44 45 /* Check to see if an IP is reserved as a static IP */ 46 int FAST_FUNC is_nip_reserved(struct static_lease *st_lease, uint32_t nip) 47 { 48 while (st_lease) { 49 if (st_lease->nip == nip) 50 return 1; 51 st_lease = st_lease->next; 52 } 53 54 return 0; 55 } 56 57 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2 58 /* Print out static leases just to check what's going on */ 59 /* Takes the address of the pointer to the static_leases linked list */ 60 void FAST_FUNC log_static_leases(struct static_lease **st_lease_pp) 18 61 { 19 62 struct static_lease *cur; 20 struct static_lease *new_static_lease;21 63 22 /* Build new node */ 23 new_static_lease = xmalloc(sizeof(struct static_lease)); 24 new_static_lease->mac = mac; 25 new_static_lease->ip = ip; 26 new_static_lease->next = NULL; 64 if (dhcp_verbose < 2) 65 return; 27 66 28 /* If it's the first node to be added... */ 29 if (*lease_struct == NULL) { 30 *lease_struct = new_static_lease; 31 } else { 32 cur = *lease_struct; 33 while (cur->next) { 34 cur = cur->next; 35 } 36 37 cur->next = new_static_lease; 38 } 39 40 return 1; 41 } 42 43 /* Check to see if a mac has an associated static lease */ 44 uint32_t getIpByMac(struct static_lease *lease_struct, void *arg) 45 { 46 uint32_t return_ip; 47 struct static_lease *cur = lease_struct; 48 uint8_t *mac = arg; 49 50 return_ip = 0; 51 67 cur = *st_lease_pp; 52 68 while (cur) { 53 /* If the client has the correct mac */ 54 if (memcmp(cur->mac, mac, 6) == 0) { 55 return_ip = *(cur->ip); 56 } 57 58 cur = cur->next; 59 } 60 61 return return_ip; 62 } 63 64 /* Check to see if an ip is reserved as a static ip */ 65 uint32_t reservedIp(struct static_lease *lease_struct, uint32_t ip) 66 { 67 struct static_lease *cur = lease_struct; 68 69 uint32_t return_val = 0; 70 71 while (cur) { 72 /* If the client has the correct ip */ 73 if (*cur->ip == ip) 74 return_val = 1; 75 76 cur = cur->next; 77 } 78 79 return return_val; 80 } 81 82 #if ENABLE_FEATURE_UDHCP_DEBUG 83 /* Print out static leases just to check what's going on */ 84 /* Takes the address of the pointer to the static_leases linked list */ 85 void printStaticLeases(struct static_lease **arg) 86 { 87 /* Get a pointer to the linked list */ 88 struct static_lease *cur = *arg; 89 90 while (cur) { 91 /* printf("PrintStaticLeases: Lease mac Address: %x\n", cur->mac); */ 92 printf("PrintStaticLeases: Lease mac Value: %x\n", *(cur->mac)); 93 /* printf("PrintStaticLeases: Lease ip Address: %x\n", cur->ip); */ 94 printf("PrintStaticLeases: Lease ip Value: %x\n", *(cur->ip)); 95 69 bb_info_msg("static lease: mac:%02x:%02x:%02x:%02x:%02x:%02x nip:%x", 70 cur->mac[0], cur->mac[1], cur->mac[2], 71 cur->mac[3], cur->mac[4], cur->mac[5], 72 cur->nip 73 ); 96 74 cur = cur->next; 97 75 }
Note:
See TracChangeset
for help on using the changeset viewer.