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