xref: /aosp_15_r20/external/toybox/toys/pending/dhcp.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
1 /* dhcp.c - DHCP client for dynamic network configuration.
2  *
3  * Copyright 2012 Madhur Verma <[email protected]>
4  * Copyright 2013 Kyungwan Han <[email protected]>
5  *
6  * See RFC 2132, and 3442 (option 121)
7 
8 USE_DHCP(NEWTOY(dhcp, "V:H:F:x*r:O*A#<0=20T#<0=3t#<0=3s:p:i:SBRCaovqnbf", TOYFLAG_SBIN|TOYFLAG_ROOTONLY))
9 
10 config DHCP
11   bool "dhcp"
12   default n
13   help
14    usage: dhcp [-fbnqvoCRB] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]
15                [-H HOSTNAME] [-V VENDOR] [-x OPT:VAL] [-O OPT]
16 
17         Configure network dynamically using DHCP.
18 
19       -i Interface to use (default eth0)
20       -p Create pidfile
21       -s Run PROG at DHCP events (default /usr/share/dhcp/default.script)
22       -B Request broadcast replies
23       -t Send up to N discover packets
24       -T Pause between packets (default 3 seconds)
25       -A Wait N seconds after failure (default 20)
26       -f Run in foreground
27       -b Background if lease is not obtained
28       -n Exit if lease is not obtained
29       -q Exit after obtaining lease
30       -R Release IP on exit
31       -S Log to syslog too
32       -a Use arping to validate offered address
33       -O Request option OPT from server (cumulative)
34       -o Don't request any options (unless -O is given)
35       -r Request this IP address
36       -x OPT:VAL  Include option OPT in sent packets (cumulative)
37       -F Ask server to update DNS mapping for NAME
38       -H Send NAME as client hostname (default none)
39       -V VENDOR Vendor identifier (default 'toybox VERSION')
40       -C Don't send MAC as client identifier
41       -v Verbose
42 
43       Signals:
44       USR1  Renew current lease
45       USR2  Release current lease
46 
47 */
48 
49 #define FOR_dhcp
50 #include "toys.h"
51 
52 // TODO: headers not in posix:
53 #include <netinet/ip.h>
54 #include <netinet/udp.h>
55 #include <netpacket/packet.h>
56 
57 #include <linux/filter.h> //FIXME: linux specific. fix for other OS ports
58 #include <linux/if_ether.h>
59 
60 GLOBALS(
61     char *iface;
62     char *pidfile;
63     char *script;
64     long retries;
65     long timeout;
66     long tryagain;
67     struct arg_list *req_opt;
68     char *req_ip;
69     struct arg_list *pkt_opt;
70     char *fdn_name;
71     char *hostname;
72     char *vendor_cls;
73 )
74 
75 #define STATE_INIT            0
76 #define STATE_REQUESTING      1
77 #define STATE_BOUND           2
78 #define STATE_RENEWING        3
79 #define STATE_REBINDING       4
80 #define STATE_RENEW_REQUESTED 5
81 #define STATE_RELEASED        6
82 
83 #define BOOTP_BROADCAST   0x8000
84 #define DHCP_MAGIC        0x63825363
85 
86 #define DHCP_REQUEST          1
87 #define DHCP_REPLY            2
88 #define DHCP_HTYPE_ETHERNET   1
89 
90 #define DHCPC_SERVER_PORT     67
91 #define DHCPC_CLIENT_PORT     68
92 
93 #define DHCPDISCOVER      1
94 #define DHCPOFFER         2
95 #define DHCPREQUEST       3
96 #define DHCPACK           5
97 #define DHCPNAK           6
98 #define DHCPRELEASE       7
99 
100 #define DHCP_OPTION_PADDING     0x00
101 #define DHCP_OPTION_SUBNET_MASK 0x01
102 #define DHCP_OPTION_ROUTER      0x03
103 #define DHCP_OPTION_DNS_SERVER  0x06
104 #define DHCP_OPTION_HOST_NAME   0x0c
105 #define DHCP_OPTION_BROADCAST   0x1c
106 #define DHCP_OPTION_REQ_IPADDR  0x32
107 #define DHCP_OPTION_LEASE_TIME  0x33
108 #define DHCP_OPTION_OVERLOAD    0x34
109 #define DHCP_OPTION_MSG_TYPE    0x35
110 #define DHCP_OPTION_SERVER_ID   0x36
111 #define DHCP_OPTION_REQ_LIST    0x37
112 #define DHCP_OPTION_MAX_SIZE    0x39
113 #define DHCP_OPTION_CLIENTID    0x3D
114 #define DHCP_OPTION_VENDOR      0x3C
115 #define DHCP_OPTION_FQDN        0x51
116 #define DHCP_OPTION_END         0xFF
117 
118 #define DHCP_NUM8           (1<<8)
119 #define DHCP_NUM16          (1<<9)
120 #define DHCP_NUM32          DHCP_NUM16 | DHCP_NUM8
121 #define DHCP_STRING         (1<<10)
122 #define DHCP_STRLST         (1<<11)
123 #define DHCP_IP             (1<<12)
124 #define DHCP_IPLIST         (1<<13)
125 #define DHCP_IPPLST         (1<<14)
126 #define DHCP_STCRTS         (1<<15)
127 
128 #define LOG_SILENT          0x0
129 #define LOG_CONSOLE         0x1
130 #define LOG_SYSTEM          0x2
131 
132 #define MODE_OFF        0
133 #define MODE_RAW        1
134 #define MODE_APP        2
135 
136 static void (*dbg)(char *format, ...);
dummy(char * format,...)137 static void dummy(char *format, ...){
138   return;
139 }
140 
141 typedef struct dhcpc_result_s {
142   struct in_addr serverid;
143   struct in_addr ipaddr;
144   struct in_addr netmask;
145   struct in_addr dnsaddr;
146   struct in_addr default_router;
147   uint32_t lease_time;
148 } dhcpc_result_t;
149 
150 typedef struct __attribute__((packed)) dhcp_msg_s {
151   uint8_t op;
152   uint8_t htype;
153   uint8_t hlen;
154   uint8_t hops;
155   uint32_t xid;
156   uint16_t secs;
157   uint16_t flags;
158   uint32_t ciaddr;
159   uint32_t yiaddr;
160   uint32_t nsiaddr;
161   uint32_t ngiaddr;
162   uint8_t chaddr[16];
163   uint8_t sname[64];
164   uint8_t file[128];
165   uint32_t cookie;
166   uint8_t options[308];
167 } dhcp_msg_t;
168 
169 typedef struct __attribute__((packed)) dhcp_raw_s {
170   struct iphdr iph;
171   struct udphdr udph;
172   dhcp_msg_t dhcp;
173 } dhcp_raw_t;
174 
175 typedef struct dhcpc_state_s {
176   uint8_t macaddr[6];
177    char *iface;
178   int ifindex;
179   int sockfd;
180   int status;
181   int mode;
182   uint32_t mask;
183   struct in_addr ipaddr;
184   struct in_addr serverid;
185   dhcp_msg_t pdhcp;
186 } dhcpc_state_t;
187 
188 typedef struct option_val_s {
189   char *key;
190   uint16_t code;
191   void *val;
192   size_t len;
193 } option_val_t;
194 
195 struct fd_pair { int rd; int wr; };
196 static uint32_t xid;
197 static dhcpc_state_t *state;
198 static struct fd_pair sigfd;
199 uint8_t bmacaddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
200  int set = 1;
201 uint8_t infomode = LOG_CONSOLE;
202 uint8_t raw_opt[29];
203 int raw_optcount = 0;
204 struct arg_list *x_opt;
205 in_addr_t server = 0;
206 
207 static option_val_t *msgopt_list = NULL;
208 static option_val_t options_list[] = {
209     {"lease"          , DHCP_NUM32  | 0x33, NULL, 0},
210     {"subnet"         , DHCP_IP     | 0x01, NULL, 0},
211     {"broadcast"      , DHCP_IP     | 0x1c, NULL, 0},
212     {"router"         , DHCP_IP     | 0x03, NULL, 0},
213     {"ipttl"          , DHCP_NUM8   | 0x17, NULL, 0},
214     {"mtu"            , DHCP_NUM16  | 0x1a, NULL, 0},
215     {"hostname"       , DHCP_STRING | 0x0c, NULL, 0},
216     {"domain"         , DHCP_STRING | 0x0f, NULL, 0},
217     {"search"         , DHCP_STRLST | 0x77, NULL, 0},
218     {"nisdomain"      , DHCP_STRING | 0x28, NULL, 0},
219     {"timezone"       , DHCP_NUM32  | 0x02, NULL, 0},
220     {"tftp"           , DHCP_STRING | 0x42, NULL, 0},
221     {"bootfile"       , DHCP_STRING | 0x43, NULL, 0},
222     {"bootsize"       , DHCP_NUM16  | 0x0d, NULL, 0},
223     {"rootpath"       , DHCP_STRING | 0x11, NULL, 0},
224     {"wpad"           , DHCP_STRING | 0xfc, NULL, 0},
225     {"serverid"       , DHCP_IP     | 0x36, NULL, 0},
226     {"message"        , DHCP_STRING | 0x38, NULL, 0},
227     {"vlanid"         , DHCP_NUM32  | 0x84, NULL, 0},
228     {"vlanpriority"   , DHCP_NUM32  | 0x85, NULL, 0},
229     {"dns"            , DHCP_IPLIST | 0x06, NULL, 0},
230     {"wins"           , DHCP_IPLIST | 0x2c, NULL, 0},
231     {"nissrv"         , DHCP_IPLIST | 0x29, NULL, 0},
232     {"ntpsrv"         , DHCP_IPLIST | 0x2a, NULL, 0},
233     {"lprsrv"         , DHCP_IPLIST | 0x09, NULL, 0},
234     {"swapsrv"        , DHCP_IP     | 0x10, NULL, 0},
235     {"routes"         , DHCP_STCRTS | 0x21, NULL, 0},
236     {"staticroutes"   , DHCP_STCRTS | 0x79, NULL, 0},
237     {"msstaticroutes" , DHCP_STCRTS | 0xf9, NULL, 0},
238 };
239 
240 static  struct sock_filter filter_instr[] = {
241     BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
242     BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6),
243     BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6),
244     BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0),
245     BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2),
246     BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1),
247     BPF_STMT(BPF_RET|BPF_K, 0xffffffff), BPF_STMT(BPF_RET|BPF_K, 0),
248 };
249 
250 static  struct sock_fprog filter_prog = {
251     .len = ARRAY_LEN(filter_instr),
252     .filter = (struct sock_filter *) filter_instr,
253 };
254 
255 // calculate options size.
dhcp_opt_size(uint8_t * optionptr)256 static int dhcp_opt_size(uint8_t *optionptr)
257 {
258   int i = 0;
259   for(;optionptr[i] != 0xff; i++) if(optionptr[i] != 0x00) i += optionptr[i + 1] + 2 -1;
260   return i;
261 }
262 
263 // calculates checksum for dhcp messages.
dhcp_checksum(void * addr,int count)264 static uint16_t dhcp_checksum(void *addr, int count)
265 {
266   int32_t sum = 0;
267   uint16_t tmp = 0, *source = (uint16_t *)addr;
268 
269   while (count > 1)  {
270     sum += *source++;
271     count -= 2;
272   }
273   if (count > 0) {
274     *(uint8_t*)&tmp = *(uint8_t*)source;
275     sum += tmp;
276   }
277   while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
278   return ~sum;
279 }
280 
281 // gets information of INTERFACE and updates IFINDEX, MAC and IP
get_interface(char * interface,int * ifindex,uint32_t * oip,uint8_t * mac)282 static int get_interface( char *interface, int *ifindex, uint32_t *oip, uint8_t *mac)
283 {
284   struct ifreq req;
285   struct sockaddr_in *ip;
286   int fd = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW);
287 
288   req.ifr_addr.sa_family = AF_INET;
289   xstrncpy(req.ifr_name, interface, IFNAMSIZ);
290   req.ifr_name[IFNAMSIZ-1] = '\0';
291 
292   xioctl(fd, SIOCGIFFLAGS, &req);
293   if (!(req.ifr_flags & IFF_UP)) return -1;
294 
295   if (oip) {
296     xioctl(fd, SIOCGIFADDR, &req);
297     ip = (struct sockaddr_in*) &req.ifr_addr;
298     dbg("IP %s\n", inet_ntoa(ip->sin_addr));
299     *oip = ntohl(ip->sin_addr.s_addr);
300   }
301   if (ifindex) {
302     xioctl(fd, SIOCGIFINDEX, &req);
303     dbg("Adapter index %d\n", req.ifr_ifindex);
304     *ifindex = req.ifr_ifindex;
305   }
306   if (mac) {
307     xioctl(fd, SIOCGIFHWADDR, &req);
308     memcpy(mac, req.ifr_hwaddr.sa_data, 6);
309     dbg("MAC %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
310   }
311   close(fd);
312   return 0;
313 }
314 
315 /*
316  *logs messeges to syslog or console
317  *opening the log is still left with applet.
318  *FIXME: move to more relevent lib. probably libc.c
319  */
infomsg(uint8_t infomode,char * s,...)320 static void infomsg(uint8_t infomode,  char *s, ...)
321 {
322   int used;
323   char *msg;
324   va_list p, t;
325 
326   if (infomode == LOG_SILENT) return;
327   va_start(p, s);
328   va_copy(t, p);
329   used = vsnprintf(NULL, 0, s, t);
330   used++;
331   va_end(t);
332 
333   msg = xmalloc(used);
334   vsnprintf(msg, used, s, p);
335   va_end(p);
336 
337   if (infomode & LOG_SYSTEM) syslog(LOG_INFO, "%s", msg);
338   if (infomode & LOG_CONSOLE) printf("%s\n", msg);
339   free(msg);
340 }
341 
342 /*
343  * Writes self PID in file PATH
344  * FIXME: libc implementation only writes in /var/run
345  * this is more generic as some implemenation may provide
346  * arguments to write in specific file. as dhcpd does.
347  */
write_pid(char * path)348 static void write_pid(char *path)
349 {
350   int pidfile = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0666);
351   if (pidfile > 0) {
352     char pidbuf[12];
353 
354     sprintf(pidbuf, "%u", (unsigned)getpid());
355     write(pidfile, pidbuf, strlen(pidbuf));
356     close(pidfile);
357   }
358 }
359 
360 // String STR to UINT32 conversion strored in VAR
strtou32(char * str)361 static long strtou32( char *str)
362 {
363   char *endptr = NULL;
364   int base = 10;
365   errno=0;
366   if (str[0]=='0' && (str[1]=='x' || str[1]=='X')) {
367     base = 16;
368     str+=2;
369   }
370   long ret_val = strtol(str, &endptr, base);
371   if (errno) return -1;
372   else if (endptr && (*endptr!='\0'||endptr == str)) return -1;
373   return ret_val;
374 }
375 
376 // IP String STR to binary data.
striptovar(char * str,void * var)377 static int striptovar( char *str, void *var)
378 {
379   in_addr_t addr;
380   if(!str) error_exit("NULL address string.");
381   addr = inet_addr(str);
382   if(addr == -1) error_exit("Wrong address %s.",str );
383   *((uint32_t*)(var)) = (uint32_t)addr;
384   return 0;
385 }
386 
387 // String to dhcp option conversion
strtoopt(char * str,uint8_t optonly)388 static int strtoopt( char *str, uint8_t optonly)
389 {
390   char *option, *valstr, *grp, *tp;
391   long optcode = 0, convtmp;
392   uint16_t flag = 0;
393   uint32_t mask, nip, router;
394   int count, size = ARRAY_LEN(options_list);
395 
396   if (!*str) return 0;
397   option = strtok((char*)str, ":");
398   if (!option) return -1;
399 
400   dbg("-x option : %s ", option);
401   optcode = strtou32(option);
402 
403   if (optcode > 0 && optcode < 256) {         // raw option
404     for (count = 0; count < size; count++) {
405       if ((options_list[count].code & 0X00FF) == optcode) {
406         flag = (options_list[count].code & 0XFF00);
407         break;
408       }
409     }
410     if (count == size) error_exit("Obsolete OR Unknown Option : %s", option);
411   } else {    // string option
412     for (count = 0; count < size; count++) {
413       if (!strcmp(options_list[count].key, option)) {
414         flag = (options_list[count].code & 0XFF00);
415         optcode = (options_list[count].code & 0X00FF);
416         break;
417       }
418     }
419     if (count == size) error_exit("Obsolete OR Unknown Option : %s", option);
420   }
421   if (!flag || !optcode) return -1;
422   if (optonly) return optcode;
423 
424   valstr = strtok(NULL, "\n");
425   if (!valstr) error_exit("option %s has no value defined.\n", option);
426   dbg(" value : %-20s \n ", valstr);
427   switch (flag) {
428   case DHCP_NUM32:
429     options_list[count].len = sizeof(uint32_t);
430     options_list[count].val = xmalloc(sizeof(uint32_t));
431     convtmp = strtou32(valstr);
432     if (convtmp < 0) error_exit("Invalid/wrong formatted number %s", valstr);
433     convtmp = htonl(convtmp);
434     memcpy(options_list[count].val, &convtmp, sizeof(uint32_t));
435     break;
436   case DHCP_NUM16:
437     options_list[count].len = sizeof(uint16_t);
438     options_list[count].val = xmalloc(sizeof(uint16_t));
439     convtmp = strtou32(valstr);
440     if (convtmp < 0) error_exit("Invalid/malformed number %s", valstr);
441     convtmp = htons(convtmp);
442     memcpy(options_list[count].val, &convtmp, sizeof(uint16_t));
443     break;
444   case DHCP_NUM8:
445     options_list[count].len = sizeof(uint8_t);
446     options_list[count].val = xmalloc(sizeof(uint8_t));
447     convtmp = strtou32(valstr);
448     if (convtmp < 0) error_exit("Invalid/malformed number %s", valstr);
449     memcpy(options_list[count].val, &convtmp, sizeof(uint8_t));
450     break;
451   case DHCP_IP:
452     options_list[count].len = sizeof(uint32_t);
453     options_list[count].val = xmalloc(sizeof(uint32_t));
454     striptovar(valstr, options_list[count].val);
455     break;
456   case DHCP_STRING:
457     options_list[count].len = strlen(valstr);
458     options_list[count].val = strdup(valstr);
459     break;
460   case DHCP_IPLIST:
461     while(valstr){
462       options_list[count].val = xrealloc(options_list[count].val, options_list[count].len + sizeof(uint32_t));
463       striptovar(valstr, ((uint8_t*)options_list[count].val)+options_list[count].len);
464       options_list[count].len += sizeof(uint32_t);
465       valstr = strtok(NULL," \t");
466     }
467     break;
468   case DHCP_STRLST:
469   case DHCP_IPPLST:
470     break;
471   case DHCP_STCRTS:
472     /* Option binary format:
473      * mask [one byte, 0..32]
474      * ip [0..4 bytes depending on mask]
475      * router [4 bytes]
476      * may be repeated
477      * staticroutes 10.0.0.0/8 10.127.0.1, 10.11.12.0/24 10.11.12.1
478      */
479     grp = strtok(valstr, ",");;
480     while(grp){
481       while(*grp == ' ' || *grp == '\t') grp++;
482       tp = strchr(grp, '/');
483       if (!tp) error_exit("malformed static route option");
484       *tp = '\0';
485       mask = strtol(++tp, &tp, 10);
486       if (striptovar(grp, (uint8_t*)&nip) < 0) error_exit("malformed static route option");
487       while(*tp == ' ' || *tp == '\t' || *tp == '-') tp++;
488       if (striptovar(tp, (uint8_t*)&router) < 0) error_exit("malformed static route option");
489       options_list[count].val = xrealloc(options_list[count].val, options_list[count].len + 1 + mask/8 + 4);
490       memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &mask, 1);
491       options_list[count].len += 1;
492       memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &nip, mask/8);
493       options_list[count].len += mask/8;
494       memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &router, 4);
495       options_list[count].len += 4;
496       tp = NULL;
497       grp = strtok(NULL, ",");
498     }
499     break;
500   }
501   return 0;
502 }
503 
504 // Creates environment pointers from RES to use in script
fill_envp(dhcpc_result_t * res)505 static int fill_envp(dhcpc_result_t *res)
506 {
507   struct in_addr temp;
508   int size = ARRAY_LEN(options_list), count, ret = -1;
509 
510   ret = setenv("interface", state->iface, 1);
511   if (!res) return ret;
512   if (res->ipaddr.s_addr) {
513       temp.s_addr = htonl(res->ipaddr.s_addr);
514       ret = setenv("ip", inet_ntoa(temp), 1);
515       if (ret) return ret;
516   }
517   if (msgopt_list) {
518     for (count = 0; count < size; count++) {
519         if ((msgopt_list[count].len == 0) || (msgopt_list[count].val == NULL)) continue;
520         ret = setenv(msgopt_list[count].key, (char*)msgopt_list[count].val, 1);
521         if (ret) return ret;
522       }
523   }
524   return ret;
525 }
526 
527 // Executes Script NAME.
run_script(dhcpc_result_t * res,char * name)528 static void run_script(dhcpc_result_t *res,  char *name)
529 {
530   volatile int error = 0;
531   pid_t pid;
532   char *argv[3];
533   struct stat sts;
534   char *script = (toys.optflags & FLAG_s) ? TT.script
535     : "/usr/share/dhcp/default.script";
536 
537   if (stat(script, &sts) == -1 && errno == ENOENT) return;
538   if (fill_envp(res)) {
539     dbg("Failed to create environment variables.");
540     return;
541   }
542   dbg("Executing %s %s\n", script, name);
543   argv[0] = (char*) script;
544   argv[1] = (char*) name;
545   argv[2] = NULL;
546   fflush(NULL);
547 
548   pid = vfork();
549   if (pid < 0) {
550     dbg("Fork failed.\n");
551     return;
552   }
553   if (!pid) {
554     execvp(argv[0], argv);
555     error = errno;
556     _exit(111);
557   }
558   if (error) {
559     waitpid(pid, NULL,0);
560     errno = error;
561     perror_msg("script exec failed");
562   }
563   dbg("script complete.\n");
564 }
565 
566 // returns a randome ID
getxid(void)567 static uint32_t getxid(void)
568 {
569   uint32_t randnum;
570   int fd = xopenro("/dev/urandom");
571 
572 // TODO xreadfile
573   xreadall(fd, &randnum, sizeof(randnum));
574   xclose(fd);
575   return randnum;
576 }
577 
578 // opens socket in raw mode.
mode_raw(void)579 static int mode_raw(void)
580 {
581   state->mode = MODE_OFF;
582   struct sockaddr_ll sock;
583 
584   if (state->sockfd > 0) close(state->sockfd);
585   dbg("Opening raw socket on ifindex %d\n", state->ifindex);
586 
587   state->sockfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
588   if (state->sockfd < 0) {
589     dbg("MODE RAW : socket fail ERROR : %d\n", state->sockfd);
590     return -1;
591   }
592   dbg("Got raw socket fd %d\n", state->sockfd);
593   memset(&sock, 0, sizeof(sock));
594   sock.sll_family = AF_PACKET;
595   sock.sll_protocol = htons(ETH_P_IP);
596   sock.sll_ifindex = state->ifindex;
597 
598   if (bind(state->sockfd, (struct sockaddr *) &sock, sizeof(sock))) {
599     dbg("MODE RAW : bind fail.\n");
600     close(state->sockfd);
601     return -1;
602   }
603   state->mode = MODE_RAW;
604   if (setsockopt(state->sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, sizeof(filter_prog)) < 0)
605     dbg("MODE RAW : filter attach fail.\n");
606 
607   dbg("MODE RAW : success\n");
608   return 0;
609 }
610 
611 // opens UDP socket
mode_app(void)612 static int mode_app(void)
613 {
614   struct sockaddr_in addr;
615   struct ifreq ifr;
616 
617   state->mode = MODE_OFF;
618   if (state->sockfd > 0) close(state->sockfd);
619 
620   dbg("Opening listen socket on *:%d %s\n", DHCPC_CLIENT_PORT, state->iface);
621   state->sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
622   if (state->sockfd < 0) {
623     dbg("MODE APP : socket fail ERROR: %d\n", state->sockfd);
624     return -1;
625   }
626   setsockopt(state->sockfd, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set));
627   if (setsockopt(state->sockfd, SOL_SOCKET, SO_BROADCAST, &set, sizeof(set)) == -1) {
628     dbg("MODE APP : brodcast failed.\n");
629     close(state->sockfd);
630     return -1;
631   }
632   xstrncpy(ifr.ifr_name, state->iface, IFNAMSIZ);
633   ifr.ifr_name[IFNAMSIZ -1] = '\0';
634   setsockopt(state->sockfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
635 
636   memset(&addr, 0, sizeof(addr));
637   addr.sin_family = AF_INET;
638   addr.sin_port = htons(DHCPC_CLIENT_PORT);
639   addr.sin_addr.s_addr = INADDR_ANY ;
640 
641   if (bind(state->sockfd, (struct sockaddr *) &addr, sizeof(addr))) {
642     close(state->sockfd);
643     dbg("MODE APP : bind failed.\n");
644     return -1;
645   }
646   state->mode = MODE_APP;
647   dbg("MODE APP : success\n");
648   return 0;
649 }
650 
read_raw(void)651 static int read_raw(void)
652 {
653   dhcp_raw_t packet;
654   int bytes = 0;
655 
656   memset(&packet, 0, sizeof(packet));
657   if ((bytes = read(state->sockfd, &packet, sizeof(packet))) < 0) {
658     dbg("\tPacket read error, ignoring\n");
659     return bytes;
660   }
661   if (bytes < (int) (sizeof(packet.iph) + sizeof(packet.udph))) {
662     dbg("\tPacket is too short, ignoring\n");
663     return -2;
664   }
665   if (bytes < ntohs(packet.iph.tot_len)) {
666     dbg("\tOversized packet, ignoring\n");
667     return -2;
668   }
669   // ignore any extra garbage bytes
670   bytes = ntohs(packet.iph.tot_len);
671   // make sure its the right packet for us, and that it passes sanity checks
672   if (packet.iph.protocol != IPPROTO_UDP || packet.iph.version != IPVERSION
673    || packet.iph.ihl != (sizeof(packet.iph) >> 2)
674    || packet.udph.dest != htons(DHCPC_CLIENT_PORT)
675    || ntohs(packet.udph.len) != (uint16_t)(bytes - sizeof(packet.iph))) {
676     dbg("\tUnrelated/bogus packet, ignoring\n");
677     return -2;
678   }
679   // Verify IP checksum.
680   if (dhcp_checksum(&packet.iph, sizeof(packet.iph)) != 0) {
681     dbg("\tBad IP header checksum, ignoring\n");
682     return -2;
683   }
684   // Verify UDP checksum. From RFC 768, the UDP checksum is done over the IPv4
685   // pseudo header, the UDP header and the UDP data. The IPv4 pseudo header
686   // includes saddr, daddr, protocol, and UDP length. The IP header has to be
687   // modified for this.
688   memset(&packet.iph, 0, ((size_t) &((struct iphdr *)0)->protocol));
689   packet.iph.check = 0;
690   packet.iph.tot_len = packet.udph.len;
691   if (packet.udph.check != 0 && dhcp_checksum(&packet, bytes) != 0) {
692     dbg("\tPacket with bad UDP checksum received, ignoring\n");
693     return -2;
694   }
695   memcpy(&state->pdhcp, &packet.dhcp, bytes - (sizeof(packet.iph) + sizeof(packet.udph)));
696   if (state->pdhcp.cookie != htonl(DHCP_MAGIC)) {
697     dbg("\tPacket with bad magic, ignoring\n");
698     return -2;
699   }
700   return bytes - sizeof(packet.iph) - sizeof(packet.udph);
701 }
702 
read_app(void)703 static int read_app(void)
704 {
705   int ret;
706 
707   memset(&state->pdhcp, 0, sizeof(dhcp_msg_t));
708   if ((ret = read(state->sockfd, &state->pdhcp, sizeof(dhcp_msg_t))) < 0) {
709     dbg("Packet read error, ignoring\n");
710     return ret; /* returns -1 */
711   }
712   if (state->pdhcp.cookie != htonl(DHCP_MAGIC)) {
713     dbg("Packet with bad magic, ignoring\n");
714     return -2;
715   }
716   return ret;
717 }
718 
719 // Sends data through raw socket.
send_raw(void)720 static int send_raw(void)
721 {
722   struct sockaddr_ll dest_sll;
723   dhcp_raw_t packet;
724   unsigned padding;
725   int fd, result = -1;
726 
727   memset(&packet, 0, sizeof(dhcp_raw_t));
728   memcpy(&packet.dhcp, &state->pdhcp, sizeof(dhcp_msg_t));
729 
730   if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
731     dbg("SEND RAW: socket failed\n");
732     return result;
733   }
734   memset(&dest_sll, 0, sizeof(dest_sll));
735   dest_sll.sll_family = AF_PACKET;
736   dest_sll.sll_protocol = htons(ETH_P_IP);
737   dest_sll.sll_ifindex = state->ifindex;
738   dest_sll.sll_halen = 6;
739   memcpy(dest_sll.sll_addr, bmacaddr , 6);
740 
741   if (bind(fd, (struct sockaddr *) &dest_sll, sizeof(dest_sll)) < 0) {
742     dbg("SEND RAW: bind failed\n");
743     close(fd);
744     return result;
745   }
746   padding = 308 - 1 - dhcp_opt_size(state->pdhcp.options);
747   packet.iph.protocol = IPPROTO_UDP;
748   packet.iph.saddr = INADDR_ANY;
749   packet.iph.daddr = INADDR_BROADCAST;
750   packet.udph.source = htons(DHCPC_CLIENT_PORT);
751   packet.udph.dest = htons(DHCPC_SERVER_PORT);
752   packet.udph.len = htons(sizeof(dhcp_raw_t) - sizeof(struct iphdr) - padding);
753   packet.iph.tot_len = packet.udph.len;
754   packet.udph.check = dhcp_checksum(&packet, sizeof(dhcp_raw_t) - padding);
755   packet.iph.tot_len = htons(sizeof(dhcp_raw_t) - padding);
756   packet.iph.ihl = sizeof(packet.iph) >> 2;
757   packet.iph.version = IPVERSION;
758   packet.iph.ttl = IPDEFTTL;
759   packet.iph.check = dhcp_checksum(&packet.iph, sizeof(packet.iph));
760 
761   result = sendto(fd, &packet, sizeof(dhcp_raw_t) - padding, 0,
762       (struct sockaddr *) &dest_sll, sizeof(dest_sll));
763 
764   close(fd);
765   if (result < 0) dbg("SEND RAW: PACKET send error\n");
766   return result;
767 }
768 
769 // Sends data through UDP socket.
send_app(void)770 static int send_app(void)
771 {
772   struct sockaddr_in cli;
773   int fd, ret = -1;
774 
775   if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
776     dbg("SEND APP: sock failed.\n");
777     return ret;
778   }
779   setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set));
780 
781   memset(&cli, 0, sizeof(cli));
782   cli.sin_family = AF_INET;
783   cli.sin_port = htons(DHCPC_CLIENT_PORT);
784   cli.sin_addr.s_addr = state->pdhcp.ciaddr;
785   if (bind(fd, (struct sockaddr *)&cli, sizeof(cli)) == -1) {
786     dbg("SEND APP: bind failed.\n");
787     goto error_fd;
788   }
789   memset(&cli, 0, sizeof(cli));
790   cli.sin_family = AF_INET;
791   cli.sin_port = htons(DHCPC_SERVER_PORT);
792   cli.sin_addr.s_addr = state->serverid.s_addr;
793   if (connect(fd, (struct sockaddr *)&cli, sizeof(cli)) == -1) {
794     dbg("SEND APP: connect failed.\n");
795     goto error_fd;
796   }
797   int padding = 308 - 1 - dhcp_opt_size(state->pdhcp.options);
798   if((ret = write(fd, &state->pdhcp, sizeof(dhcp_msg_t) - padding)) < 0) {
799     dbg("SEND APP: write failed error %d\n", ret);
800     goto error_fd;
801   }
802   dbg("SEND APP: write success wrote %d\n", ret);
803 error_fd:
804   close(fd);
805   return ret;
806 }
807 
808 // Generic signal handler real handling is done in main funcrion.
signal_handler(int sig)809 static void signal_handler(int sig)
810 {
811   unsigned char ch = sig;
812   if (write(sigfd.wr, &ch, 1) != 1) dbg("can't send signal\n");
813 }
814 
815 // signal setup for SIGUSR1 SIGUSR2 SIGTERM
setup_signal()816 static int setup_signal()
817 {
818   if (pipe((int *)&sigfd) < 0) {
819     dbg("signal pipe failed\n");
820     return -1;
821   }
822   fcntl(sigfd.wr , F_SETFD, FD_CLOEXEC);
823   fcntl(sigfd.rd , F_SETFD, FD_CLOEXEC);
824   int flags = fcntl(sigfd.wr, F_GETFL);
825   fcntl(sigfd.wr, F_SETFL, flags | O_NONBLOCK);
826   signal(SIGUSR1, signal_handler);
827   signal(SIGUSR2, signal_handler);
828   signal(SIGTERM, signal_handler);
829 
830   return 0;
831 }
832 
833 // adds client id to dhcp packet
dhcpc_addclientid(uint8_t * optptr)834 static uint8_t *dhcpc_addclientid(uint8_t *optptr)
835 {
836   *optptr++ = DHCP_OPTION_CLIENTID;
837   *optptr++ = 7;
838   *optptr++ = 1;
839   memcpy(optptr, &state->macaddr, 6);
840   return optptr + 6;
841 }
842 
843 // adds messege type to dhcp packet
dhcpc_addmsgtype(uint8_t * optptr,uint8_t type)844 static uint8_t *dhcpc_addmsgtype(uint8_t *optptr, uint8_t type)
845 {
846   *optptr++ = DHCP_OPTION_MSG_TYPE;
847   *optptr++ = 1;
848   *optptr++ = type;
849   return optptr;
850 }
851 
852 // adds max size to dhcp packet
dhcpc_addmaxsize(uint8_t * optptr,uint16_t size)853 static uint8_t *dhcpc_addmaxsize(uint8_t *optptr, uint16_t size)
854 {
855   *optptr++ = DHCP_OPTION_MAX_SIZE;
856   *optptr++ = 2;
857   memcpy(optptr, &size, 2);
858   return optptr + 2;
859 }
860 
dhcpc_addstropt(uint8_t * optptr,uint8_t opcode,char * str,int len)861 static uint8_t *dhcpc_addstropt(uint8_t *optptr, uint8_t opcode, char* str, int len)
862 {
863   *optptr++ = opcode;
864   *optptr++ = len;
865   memcpy(optptr, str, len);
866   return optptr + len;
867 }
868 
869 // adds server id to dhcp packet.
dhcpc_addserverid(struct in_addr * serverid,uint8_t * optptr)870 static uint8_t *dhcpc_addserverid(struct in_addr *serverid, uint8_t *optptr)
871 {
872   *optptr++ = DHCP_OPTION_SERVER_ID;
873   *optptr++ = 4;
874   memcpy(optptr, &serverid->s_addr, 4);
875   return optptr + 4;
876 }
877 
878 // adds requested ip address to dhcp packet.
dhcpc_addreqipaddr(struct in_addr * ipaddr,uint8_t * optptr)879 static uint8_t *dhcpc_addreqipaddr(struct in_addr *ipaddr, uint8_t *optptr)
880 {
881   *optptr++ = DHCP_OPTION_REQ_IPADDR;
882   *optptr++ = 4;
883   memcpy(optptr, &ipaddr->s_addr, 4);
884   return optptr + 4;
885 }
886 
887 // adds hostname to dhcp packet.
dhcpc_addfdnname(uint8_t * optptr,char * hname)888 static uint8_t *dhcpc_addfdnname(uint8_t *optptr, char *hname)
889 {
890   int size = strlen(hname);
891 
892   *optptr++ = DHCP_OPTION_FQDN;
893   *optptr++ = size + 3;
894   *optptr++ = 0x1;  //flags
895   optptr += 2;      // two blank bytes
896   strcpy((char*)optptr, hname); // name
897 
898   return optptr + size;
899 }
900 
901 // adds request options using -o,-O flag to dhcp packet
dhcpc_addreqoptions(uint8_t * optptr)902 static uint8_t *dhcpc_addreqoptions(uint8_t *optptr)
903 {
904   uint8_t *len;
905 
906   *optptr++ = DHCP_OPTION_REQ_LIST;
907   len = optptr;
908   *len = 0;
909   optptr++;
910 
911   if (!(toys.optflags & FLAG_o)) {
912     *len = 4;
913     *optptr++ = DHCP_OPTION_SUBNET_MASK;
914     *optptr++ = DHCP_OPTION_ROUTER;
915     *optptr++ = DHCP_OPTION_DNS_SERVER;
916     *optptr++ = DHCP_OPTION_BROADCAST;
917   }
918   if (toys.optflags & FLAG_O) {
919     memcpy(optptr++, raw_opt, raw_optcount);
920     *len += raw_optcount;
921   }
922   return optptr;
923 }
924 
dhcpc_addend(uint8_t * optptr)925 static uint8_t *dhcpc_addend(uint8_t *optptr)
926 {
927   *optptr++ = DHCP_OPTION_END;
928   return optptr;
929 }
930 
931 // Sets values of -x options in dhcp discover and request packet.
set_xopt(uint8_t * optptr)932 static uint8_t* set_xopt(uint8_t *optptr)
933 {
934   int count;
935   int size = ARRAY_LEN(options_list);
936   for (count = 0; count < size; count++) {
937     if ((options_list[count].len == 0) || (options_list[count].val == NULL)) continue;
938     *optptr++ = (uint8_t) (options_list[count].code & 0x00FF);
939     *optptr++ = (uint8_t) options_list[count].len;
940     memcpy(optptr, options_list[count].val, options_list[count].len);
941     optptr += options_list[count].len;
942   }
943   return optptr;
944 }
945 
get_option_serverid(uint8_t * opt,dhcpc_result_t * presult)946 static uint32_t get_option_serverid (uint8_t *opt, dhcpc_result_t *presult)
947 {
948   uint32_t var = 0;
949   while (*opt != DHCP_OPTION_SERVER_ID) {
950     if (*opt == DHCP_OPTION_END) return var;
951     opt += opt[1] + 2;
952   }
953   memcpy(&var, opt+2, sizeof(uint32_t));
954   state->serverid.s_addr = var;
955   presult->serverid.s_addr = state->serverid.s_addr;
956   presult->serverid.s_addr = ntohl(presult->serverid.s_addr);
957   return var;
958 }
959 
get_option_msgtype(uint8_t * opt)960 static uint8_t get_option_msgtype(uint8_t *opt)
961 {
962   uint32_t var = 0;
963   while (*opt != DHCP_OPTION_MSG_TYPE) {
964     if (*opt == DHCP_OPTION_END) return var;
965     opt += opt[1] + 2;
966   }
967   memcpy(&var, opt+2, sizeof(uint8_t));
968   return var;
969 }
970 
get_option_lease(uint8_t * opt,dhcpc_result_t * presult)971 static uint8_t get_option_lease(uint8_t *opt, dhcpc_result_t *presult)
972 {
973   uint32_t var = 0;
974   while (*opt != DHCP_OPTION_LEASE_TIME) {
975     if (*opt == DHCP_OPTION_END) return var;
976     opt += opt[1] + 2;
977   }
978   memcpy(&var, opt+2, sizeof(uint32_t));
979   var = htonl(var);
980   presult->lease_time = var;
981   return var;
982 }
983 
984 
985 // sends dhcp msg of MSGTYPE
dhcpc_sendmsg(int msgtype)986 static int dhcpc_sendmsg(int msgtype)
987 {
988   uint8_t *pend;
989   struct in_addr rqsd;
990   char *vendor;
991 
992   // Create the common message header settings
993   memset(&state->pdhcp, 0, sizeof(dhcp_msg_t));
994   state->pdhcp.op = DHCP_REQUEST;
995   state->pdhcp.htype = DHCP_HTYPE_ETHERNET;
996   state->pdhcp.hlen = 6;
997   state->pdhcp.xid = xid;
998   memcpy(state->pdhcp.chaddr, state->macaddr, 6);
999   memset(&state->pdhcp.chaddr[6], 0, 10);
1000   state->pdhcp.cookie = htonl(DHCP_MAGIC);;
1001 
1002   // Add the common header options
1003   pend = state->pdhcp.options;
1004   pend = dhcpc_addmsgtype(pend, msgtype);
1005 
1006   if (!(toys.optflags & FLAG_C)) pend = dhcpc_addclientid(pend);
1007   // Handle the message specific settings
1008   switch (msgtype) {
1009   case DHCPDISCOVER: // Broadcast DISCOVER message to all servers
1010     state->pdhcp.flags = htons(BOOTP_BROADCAST); //  Broadcast bit.
1011     if (toys.optflags & FLAG_r) {
1012       inet_aton(TT.req_ip, &rqsd);
1013       pend = dhcpc_addreqipaddr(&rqsd, pend);
1014     }
1015     pend = dhcpc_addmaxsize(pend, htons(sizeof(dhcp_raw_t)));
1016     vendor = (toys.optflags & FLAG_V) ? TT.vendor_cls : "toybox\0";
1017     pend = dhcpc_addstropt(pend, DHCP_OPTION_VENDOR, vendor, strlen(vendor));
1018     if (toys.optflags & FLAG_H) pend = dhcpc_addstropt(pend, DHCP_OPTION_HOST_NAME, TT.hostname, strlen(TT.hostname));
1019     if (toys.optflags & FLAG_F) pend = dhcpc_addfdnname(pend, TT.fdn_name);
1020     if (!(toys.optflags & FLAG_o) || (toys.optflags & FLAG_O))
1021       pend = dhcpc_addreqoptions(pend);
1022     if (toys.optflags & FLAG_x) pend = set_xopt(pend);
1023     break;
1024   case DHCPREQUEST: // Send REQUEST message to the server that sent the *first* OFFER
1025     state->pdhcp.flags = htons(BOOTP_BROADCAST); //  Broadcast bit.
1026     if (state->status == STATE_RENEWING) memcpy(&state->pdhcp.ciaddr, &state->ipaddr.s_addr, 4);
1027     pend = dhcpc_addmaxsize(pend, htons(sizeof(dhcp_raw_t)));
1028     rqsd.s_addr = htonl(server);
1029     pend = dhcpc_addserverid(&rqsd, pend);
1030     pend = dhcpc_addreqipaddr(&state->ipaddr, pend);
1031     vendor = (toys.optflags & FLAG_V) ? TT.vendor_cls : "toybox\0";
1032     pend = dhcpc_addstropt(pend, DHCP_OPTION_VENDOR, vendor, strlen(vendor));
1033     if (toys.optflags & FLAG_H) pend = dhcpc_addstropt(pend, DHCP_OPTION_HOST_NAME, TT.hostname, strlen(TT.hostname));
1034     if (toys.optflags & FLAG_F) pend = dhcpc_addfdnname(pend, TT.fdn_name);
1035     if (!(toys.optflags & FLAG_o) || (toys.optflags & FLAG_O))
1036       pend = dhcpc_addreqoptions(pend);
1037     if (toys.optflags & FLAG_x) pend = set_xopt(pend);
1038     break;
1039   case DHCPRELEASE: // Send RELEASE message to the server.
1040     memcpy(&state->pdhcp.ciaddr, &state->ipaddr.s_addr, 4);
1041     rqsd.s_addr = htonl(server);
1042     pend = dhcpc_addserverid(&rqsd, pend);
1043     break;
1044   default:
1045     return -1;
1046   }
1047   pend = dhcpc_addend(pend);
1048 
1049   if (state->mode == MODE_APP) return send_app();
1050   return send_raw();
1051 }
1052 
1053 /*
1054  * parses options from received dhcp packet at OPTPTR and
1055  * stores result in PRESULT or MSGOPT_LIST
1056  */
dhcpc_parseoptions(dhcpc_result_t * presult,uint8_t * optptr)1057 static uint8_t dhcpc_parseoptions(dhcpc_result_t *presult, uint8_t *optptr)
1058 {
1059   uint8_t type = 0, *options, overloaded = 0;;
1060   uint16_t flag = 0;
1061   char *dest, *pfx;
1062   int count, optlen, size = ARRAY_LEN(options_list);
1063 
1064   if (toys.optflags & FLAG_x) {
1065     if(msgopt_list){
1066       for (count = 0; count < size; count++){
1067         if(msgopt_list[count].val) free(msgopt_list[count].val);
1068         msgopt_list[count].val = NULL;
1069         msgopt_list[count].len = 0;
1070       }
1071     } else {
1072      msgopt_list = xmalloc(sizeof(options_list));
1073      memcpy(msgopt_list, options_list, sizeof(options_list));
1074      for (count = 0; count < size; count++) {
1075          msgopt_list[count].len = 0;
1076          msgopt_list[count].val = NULL;
1077      }
1078     }
1079   } else {
1080     msgopt_list = options_list;
1081     for (count = 0; count < size; count++) {
1082       msgopt_list[count].len = 0;
1083       if(msgopt_list[count].val) free(msgopt_list[count].val);
1084       msgopt_list[count].val = NULL;
1085     }
1086   }
1087 
1088   while (*optptr != DHCP_OPTION_END) {
1089     if (*optptr == DHCP_OPTION_PADDING) {
1090       optptr++;
1091       continue;
1092     }
1093     if (*optptr == DHCP_OPTION_OVERLOAD) {
1094       overloaded = optptr[2];
1095       optptr += optptr[1] + 2;
1096       continue;
1097     }
1098     for (count = 0, flag = 0; count < size; count++) {
1099       if ((msgopt_list[count].code & 0X00FF) == *optptr) {
1100         flag = (msgopt_list[count].code & 0XFF00);
1101         break;
1102       }
1103     }
1104     msgopt_list[count].val = 0;
1105     msgopt_list[count].len = 0;
1106     switch (flag) {
1107     case DHCP_NUM32:
1108       msgopt_list[count].val = xmprintf("%llu", peek_be(optptr+2, 4));
1109       break;
1110     case DHCP_NUM16:
1111       msgopt_list[count].val = xmprintf("%llu", peek_be(optptr+2, 2));
1112       break;
1113     case DHCP_NUM8:
1114       msgopt_list[count].val = xmprintf("%llu", peek_be(optptr+2, 1));
1115       break;
1116     case DHCP_IP:
1117       msgopt_list[count].val = xstrdup(inet_ntoa((struct in_addr){peek(optptr+2, 4)}));
1118       break;
1119     case DHCP_STRING:
1120       msgopt_list[count].val = xmprintf("%.*s", optptr[1], optptr+2);
1121       break;
1122     case DHCP_IPLIST:
1123       options = &optptr[2];
1124       optlen = optptr[1];
1125       dest = toybuf;
1126       while (optlen) {
1127         dest += sprintf(dest, "%s ", inet_ntoa((struct in_addr){peek(options, 4)}));
1128         options += 4;
1129         optlen -= 4;
1130       }
1131       *(dest - 1) = '\0';
1132       msgopt_list[count].val = strdup(toybuf);
1133       break;
1134     case DHCP_STRLST: //FIXME: do smthing.
1135     case DHCP_IPPLST:
1136       break;
1137     case DHCP_STCRTS:
1138       pfx = "";
1139       dest = toybuf;
1140       options = &optptr[2];
1141       optlen = optptr[1];
1142 
1143       while (optlen >= 1 + 4) {
1144         uint32_t nip = 0;
1145         int bytes;
1146         uint8_t *p_tmp;
1147         unsigned mask = *options;
1148 
1149         if (mask > 32) break;
1150         optlen--;
1151         p_tmp = (void*) &nip;
1152         bytes = (mask + 7) / 8;
1153         while (--bytes >= 0) {
1154           *p_tmp++ = *options++;
1155           optlen--;
1156         }
1157         if (optlen < 4) break;
1158         dest += sprintf(dest, "%s%u.%u.%u.%u", pfx, ((uint8_t*) &nip)[0],
1159             ((uint8_t*) &nip)[1], ((uint8_t*) &nip)[2], ((uint8_t*) &nip)[3]);
1160         pfx = " ";
1161         dest += sprintf(dest, "/%u ", mask);
1162         dest += sprintf(dest, "%u.%u.%u.%u", options[0], options[1], options[2], options[3]);
1163         options += 4;
1164         optlen -= 4;
1165       }
1166       msgopt_list[count].val = strdup(toybuf);
1167       break;
1168     default: break;
1169     }
1170     if (msgopt_list[count].val)
1171       msgopt_list[count].len = strlen(msgopt_list[count].val);
1172 
1173     optptr += optptr[1] + 2;
1174   }
1175   if ((overloaded == 1) || (overloaded == 3)) dhcpc_parseoptions(presult, optptr);
1176   if ((overloaded == 2) || (overloaded == 3)) dhcpc_parseoptions(presult, optptr);
1177   return type;
1178 }
1179 
1180 // parses recvd messege to check that it was for us.
dhcpc_parsemsg(dhcpc_result_t * presult)1181 static uint8_t dhcpc_parsemsg(dhcpc_result_t *presult)
1182 {
1183   if (state->pdhcp.op == DHCP_REPLY
1184       && !memcmp(state->pdhcp.chaddr, state->macaddr, 6)
1185       && !memcmp(&state->pdhcp.xid, &xid, sizeof(xid))) {
1186     memcpy(&presult->ipaddr.s_addr, &state->pdhcp.yiaddr, 4);
1187     presult->ipaddr.s_addr = ntohl(presult->ipaddr.s_addr);
1188     return get_option_msgtype(state->pdhcp.options);
1189   }
1190   return 0;
1191 }
1192 
1193 // Sends a IP renew request.
renew(void)1194 static void renew(void)
1195 {
1196   infomsg(infomode, "Performing a DHCP renew");
1197   switch (state->status) {
1198   case STATE_INIT:
1199     break;
1200   case STATE_BOUND:
1201     mode_raw();
1202   case STATE_RENEWING:    // FALLTHROUGH
1203   case STATE_REBINDING:   // FALLTHROUGH
1204     state->status = STATE_RENEW_REQUESTED;
1205     break;
1206   case STATE_RENEW_REQUESTED:
1207     run_script(NULL, "deconfig");
1208   case STATE_REQUESTING:           // FALLTHROUGH
1209   case STATE_RELEASED:             // FALLTHROUGH
1210     mode_raw();
1211     state->status = STATE_INIT;
1212     break;
1213   default: break;
1214   }
1215 }
1216 
1217 // Sends a IP release request.
release(void)1218 static void release(void)
1219 {
1220   char buffer[sizeof("255.255.255.255\0")];
1221   struct in_addr temp_addr;
1222 
1223   mode_app();
1224   // send release packet
1225   if (state->status == STATE_BOUND || state->status == STATE_RENEWING || state->status == STATE_REBINDING) {
1226     temp_addr.s_addr = htonl(server);
1227     xstrncpy(buffer, inet_ntoa(temp_addr), sizeof(buffer));
1228     temp_addr.s_addr = state->ipaddr.s_addr;
1229     infomsg( infomode, "Unicasting a release of %s to %s", inet_ntoa(temp_addr), buffer);
1230     dhcpc_sendmsg(DHCPRELEASE);
1231     run_script(NULL, "deconfig");
1232   }
1233   infomsg(infomode, "Entering released state");
1234   close(state->sockfd);
1235   state->sockfd = -1;
1236   state->mode = MODE_OFF;
1237   state->status = STATE_RELEASED;
1238 }
1239 
free_option_stores(void)1240 static void free_option_stores(void)
1241 {
1242   int count, size = ARRAY_LEN(options_list);
1243   for (count = 0; count < size; count++)
1244     if (options_list[count].val) free(options_list[count].val);
1245   if (toys.optflags & FLAG_x) {
1246     for (count = 0; count < size; count++)
1247         if (msgopt_list[count].val) free(msgopt_list[count].val);
1248     free(msgopt_list);
1249   }
1250 }
1251 
dhcp_main(void)1252 void dhcp_main(void)
1253 {
1254   struct timeval tv;
1255   int retval, bufflen = 0;
1256   dhcpc_result_t result;
1257   uint8_t packets = 0, retries = 0;
1258   uint32_t timeout = 0, waited = 0;
1259   fd_set rfds;
1260 
1261   xid = 0;
1262   setlinebuf(stdout);
1263   dbg = dummy;
1264   if (toys.optflags & FLAG_v) dbg = xprintf;
1265   if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
1266   retries = TT.retries;
1267   if (toys.optflags & FLAG_S) {
1268       openlog("UDHCPC :", LOG_PID, LOG_DAEMON);
1269       infomode |= LOG_SYSTEM;
1270   }
1271   infomsg(infomode, "dhcp started");
1272   if (toys.optflags & FLAG_O) {
1273     while (TT.req_opt) {
1274       raw_opt[raw_optcount] = (uint8_t) strtoopt(TT.req_opt->arg, 1);
1275       raw_optcount++;
1276       TT.req_opt = TT.req_opt->next;
1277     }
1278   }
1279   if (toys.optflags & FLAG_x) {
1280     while (TT.pkt_opt) {
1281       (void) strtoopt(TT.pkt_opt->arg, 0);
1282       TT.pkt_opt = TT.pkt_opt->next;
1283     }
1284   }
1285   memset(&result, 0, sizeof(dhcpc_result_t));
1286   state = (dhcpc_state_t*) xmalloc(sizeof(dhcpc_state_t));
1287   memset(state, 0, sizeof(dhcpc_state_t));
1288   state->iface = (toys.optflags & FLAG_i) ? TT.iface : "eth0";
1289 
1290   if (get_interface(state->iface, &state->ifindex, NULL, state->macaddr))
1291     perror_exit("Failed to get interface %s", state->iface);
1292 
1293   run_script(NULL, "deconfig");
1294   setup_signal();
1295   state->status = STATE_INIT;
1296   mode_raw();
1297   fcntl(state->sockfd, F_SETFD, FD_CLOEXEC);
1298 
1299   for (;;) {
1300     FD_ZERO(&rfds);
1301     if (state->sockfd >= 0) FD_SET(state->sockfd, &rfds);
1302     FD_SET(sigfd.rd, &rfds);
1303     tv.tv_sec = timeout - waited;
1304     tv.tv_usec = 0;
1305     retval = 0;
1306 
1307     int maxfd = (sigfd.rd > state->sockfd)? sigfd.rd : state->sockfd;
1308     dbg("select wait ....\n");
1309     uint32_t timestmp = time(NULL);
1310     if((retval = select(maxfd + 1, &rfds, NULL, NULL, &tv)) < 0) {
1311       if (errno == EINTR) {
1312         waited += (unsigned) time(NULL) - timestmp;
1313         continue;
1314       }
1315       perror_exit("Error in select");
1316     }
1317     if (!retval) { // Timed out
1318       if (get_interface(state->iface, &state->ifindex, NULL, state->macaddr))
1319         error_exit("Interface lost %s\n", state->iface);
1320 
1321       switch (state->status) {
1322       case STATE_INIT:
1323         if (packets < retries) {
1324           if (!packets) xid = getxid();
1325           run_script(NULL, "deconfig");
1326           infomsg(infomode, "Sending discover...");
1327           dhcpc_sendmsg(DHCPDISCOVER);
1328           server = 0;
1329           timeout = TT.timeout;
1330           waited = 0;
1331           packets++;
1332           continue;
1333         }
1334 lease_fail:
1335         run_script(NULL,"leasefail");
1336         if (toys.optflags & FLAG_n) {
1337           infomsg(infomode, "Lease failed. Exiting");
1338           goto ret_with_sockfd;
1339         }
1340         if (toys.optflags & FLAG_b) {
1341           infomsg(infomode, "Lease failed. Going Daemon mode");
1342           daemon(0, 0);
1343           if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
1344           toys.optflags &= ~FLAG_b;
1345           toys.optflags |= FLAG_f;
1346         }
1347         timeout = TT.tryagain;
1348         waited = 0;
1349         packets = 0;
1350         continue;
1351       case STATE_REQUESTING:
1352         if (packets < retries) {
1353           memcpy(&state->ipaddr.s_addr,&state->pdhcp.yiaddr, 4);
1354           dhcpc_sendmsg(DHCPREQUEST);
1355           infomsg(infomode, "Sending select for %d.%d.%d.%d...",
1356               (result.ipaddr.s_addr >> 24) & 0xff, (result.ipaddr.s_addr >> 16) & 0xff, (result.ipaddr.s_addr >> 8) & 0xff, (result.ipaddr.s_addr) & 0xff);
1357           timeout = TT.timeout;
1358           waited = 0;
1359           packets++;
1360           continue;
1361         }
1362         mode_raw();
1363         state->status = STATE_INIT;
1364         goto lease_fail;
1365       case STATE_BOUND:
1366         state->status = STATE_RENEWING;
1367         dbg("Entering renew state\n");
1368         // FALLTHROUGH
1369       case STATE_RENEW_REQUESTED:   // FALLTHROUGH
1370       case STATE_RENEWING:
1371 renew_requested:
1372         if (timeout > 60) {
1373           dhcpc_sendmsg(DHCPREQUEST);
1374           timeout >>= 1;
1375           waited = 0;
1376           continue;
1377         }
1378         dbg("Entering rebinding state\n");
1379         state->status = STATE_REBINDING;
1380         // FALLTHROUGH
1381       case STATE_REBINDING:
1382         mode_raw();
1383         if (timeout > 0) {
1384           dhcpc_sendmsg(DHCPREQUEST);
1385           timeout >>= 1;
1386           waited = 0;
1387           continue;
1388         }
1389         infomsg(infomode, "Lease lost, entering INIT state");
1390         run_script(NULL, "deconfig");
1391         state->status = STATE_INIT;
1392         timeout = 0;
1393         waited = 0;
1394         packets = 0;
1395         continue;
1396       default: break;
1397       }
1398       timeout = INT_MAX;
1399       waited = 0;
1400       continue;
1401     }
1402     if (FD_ISSET(sigfd.rd, &rfds)) { // Some Activity on RDFDs : is signal
1403       unsigned char sig;
1404       if (read(sigfd.rd, &sig, 1) != 1) {
1405         dbg("signal read failed.\n");
1406         continue;
1407       }
1408       switch (sig) {
1409       case SIGUSR1:
1410         infomsg(infomode, "Received SIGUSR1");
1411         renew();
1412         packets = 0;
1413         waited = 0;
1414         if (state->status == STATE_RENEW_REQUESTED) goto renew_requested;
1415         if (state->status == STATE_INIT) timeout = 0;
1416         continue;
1417       case SIGUSR2:
1418         infomsg(infomode, "Received SIGUSR2");
1419         release();
1420         timeout = INT_MAX;
1421         waited = 0;
1422         packets = 0;
1423         continue;
1424       case SIGTERM:
1425         infomsg(infomode, "Received SIGTERM");
1426         if (toys.optflags & FLAG_R) release();
1427         goto ret_with_sockfd;
1428       default: break;
1429       }
1430     }
1431     if (FD_ISSET(state->sockfd, &rfds)) { // Some Activity on RDFDs : is socket
1432       dbg("main sock read\n");
1433       uint8_t msgType;
1434       if (state->mode == MODE_RAW) bufflen = read_raw();
1435       if (state->mode == MODE_APP) bufflen = read_app();
1436       if (bufflen < 0) {
1437         if (state->mode == MODE_RAW) mode_raw();
1438         if (state->mode == MODE_APP) mode_app();
1439         continue;
1440       }
1441       waited += time(NULL) - timestmp;
1442       memset(&result, 0, sizeof(dhcpc_result_t));
1443       msgType = dhcpc_parsemsg(&result);
1444       if (msgType != DHCPNAK && result.ipaddr.s_addr == 0 ) continue;       // no ip for me ignore
1445       if (!msgType || !get_option_serverid(state->pdhcp.options, &result)) continue; //no server id ignore
1446       if (msgType == DHCPOFFER && server == 0) server = result.serverid.s_addr; // select the server
1447       if (result.serverid.s_addr != server) continue; // not from the server we requested ignore
1448       dhcpc_parseoptions(&result, state->pdhcp.options);
1449       get_option_lease(state->pdhcp.options, &result);
1450 
1451       switch (state->status) {
1452       case STATE_INIT:
1453         if (msgType == DHCPOFFER) {
1454           state->status = STATE_REQUESTING;
1455           mode_raw();
1456           timeout = 0;
1457           waited = 0;
1458           packets = 0;
1459         }
1460         continue;
1461       case STATE_REQUESTING:         // FALLTHROUGH
1462       case STATE_RENEWING:           // FALLTHROUGH
1463       case STATE_RENEW_REQUESTED:    // FALLTHROUGH
1464       case STATE_REBINDING:
1465         if (msgType == DHCPACK) {
1466           timeout = result.lease_time / 2;
1467           run_script(&result, state->status == STATE_REQUESTING ? "bound" : "renew");
1468           state->status = STATE_BOUND;
1469           infomsg(infomode, "Lease of %d.%d.%d.%d obtained, lease time %d from server %d.%d.%d.%d",
1470               (result.ipaddr.s_addr >> 24) & 0xff, (result.ipaddr.s_addr >> 16) & 0xff, (result.ipaddr.s_addr >> 8) & 0xff, (result.ipaddr.s_addr) & 0xff,
1471               result.lease_time,
1472               (result.serverid.s_addr >> 24) & 0xff, (result.serverid.s_addr >> 16) & 0xff, (result.serverid.s_addr >> 8) & 0xff, (result.serverid.s_addr) & 0xff);
1473           if (toys.optflags & FLAG_q) {
1474             if (toys.optflags & FLAG_R) release();
1475             goto ret_with_sockfd;
1476           }
1477           toys.optflags &= ~FLAG_n;
1478           if (!(toys.optflags & FLAG_f)) {
1479             daemon(0, 0);
1480             toys.optflags |= FLAG_f;
1481             if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
1482           }
1483           waited = 0;
1484           continue;
1485         } else if (msgType == DHCPNAK) {
1486           dbg("NACK received.\n");
1487           run_script(&result, "nak");
1488           if (state->status != STATE_REQUESTING) run_script(NULL, "deconfig");
1489           mode_raw();
1490           sleep(3);
1491           state->status = STATE_INIT;
1492           state->ipaddr.s_addr = 0;
1493           server = 0;
1494           timeout = 0;
1495           packets = 0;
1496           waited = 0;
1497         }
1498         continue;
1499       default: break;
1500       }
1501     }
1502   }
1503 ret_with_sockfd:
1504   if (CFG_TOYBOX_FREE) {
1505     free_option_stores();
1506     if (state->sockfd > 0) close(state->sockfd);
1507     free(state);
1508   }
1509 }
1510