toybox/toys/pending/dhcp.c
<<
>>
Prefs
   1/* dhcp.c - DHCP client for dynamic network configuration.
   2 *
   3 * Copyright 2012 Madhur Verma <mad.flexi@gmail.com>
   4 * Copyright 2013 Kyungwan Han <asura321@gmail.com>
   5 *
   6 * Not in SUSv4.
   7USE_DHCP(NEWTOY(dhcp, "V:H:F:x*r:O*A#<0=20T#<0=3t#<0=3s:p:i:SBRCaovqnbf", TOYFLAG_SBIN|TOYFLAG_ROOTONLY))
   8
   9config 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
  59GLOBALS(
  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
 135static void (*dbg)(char *format, ...);
 136static void dummy(char *format, ...){
 137  return;
 138}
 139
 140typedef 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
 149typedef 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
 168typedef struct __attribute__((packed)) dhcp_raw_s {
 169  struct iphdr iph;
 170  struct udphdr udph;
 171  dhcp_msg_t dhcp;
 172} dhcp_raw_t;
 173
 174typedef 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
 187typedef struct option_val_s {
 188  char *key;
 189  uint16_t code;
 190  void *val;
 191  size_t len;
 192} option_val_t;
 193
 194struct fd_pair { int rd; int wr; };
 195static uint32_t xid;
 196static dhcpc_state_t *state;
 197static struct fd_pair sigfd;
 198uint8_t bmacaddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 199 int set = 1;
 200uint8_t infomode = LOG_CONSOLE;
 201uint8_t raw_opt[29];
 202int raw_optcount = 0;
 203struct arg_list *x_opt;
 204in_addr_t server = 0;
 205
 206static option_val_t *msgopt_list = NULL;
 207static 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
 239static  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
 249static  struct sock_fprog filter_prog = {
 250    .len = ARRAY_LEN(filter_instr), 
 251    .filter = (struct sock_filter *) filter_instr,
 252};
 253
 254// calculate options size.
 255static 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.
 263static 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
 281static 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 */
 319static 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 */
 347static 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
 360static 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.
 376static 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
 387static 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 formatted 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
 504static 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.
 527static 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
 566static 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.
 578static 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
 611static 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
 650static 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
 702static 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.
 719static 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.
 769static 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);
 802error_fd:
 803  close(fd);
 804  return ret;
 805}
 806
 807// Generic signal handler real handling is done in main funcrion.
 808static 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
 815static 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
 833static 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
 843static 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
 852static 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
 860static 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.
 869static 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.
 878static 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.
 887static 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
 901static 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
 924static 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.
 931static 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
 945static 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
 959static 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
 970static 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
 985static 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 */
1056static 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      options = &optptr[2];
1140      optlen = optptr[1];
1141      dest = toybuf;
1142      while (optlen) {
1143        memcpy(&convtmp, options, sizeof(uint32_t));
1144        addr.s_addr = convtmp;
1145        dest += sprintf(dest, "%s ", inet_ntoa(addr));
1146        options += 4;
1147        optlen -= 4;
1148      }
1149      *(dest - 1) = '\0';
1150      msgopt_list[count].val = strdup(toybuf);
1151      msgopt_list[count].len = strlen(toybuf);
1152      break;
1153    case DHCP_STRLST: //FIXME: do smthing.
1154    case DHCP_IPPLST:
1155      break;
1156    case DHCP_STCRTS:
1157      pfx = "";
1158      dest = toybuf;
1159      options = &optptr[2];
1160      optlen = optptr[1];
1161
1162      while (optlen >= 1 + 4) {
1163        uint32_t nip = 0;
1164        int bytes;
1165        uint8_t *p_tmp;
1166        unsigned mask = *options;
1167
1168        if (mask > 32) break;
1169        optlen--;
1170        p_tmp = (void*) &nip;
1171        bytes = (mask + 7) / 8;
1172        while (--bytes >= 0) {
1173          *p_tmp++ = *options++;
1174          optlen--;
1175        }
1176        if (optlen < 4) break;
1177        dest += sprintf(dest, "%s%u.%u.%u.%u", pfx, ((uint8_t*) &nip)[0],
1178            ((uint8_t*) &nip)[1], ((uint8_t*) &nip)[2], ((uint8_t*) &nip)[3]);
1179        pfx = " ";
1180        dest += sprintf(dest, "/%u ", mask);
1181        dest += sprintf(dest, "%u.%u.%u.%u", options[0], options[1], options[2], options[3]);
1182        options += 4;
1183        optlen -= 4;
1184      }
1185      msgopt_list[count].val = strdup(toybuf);
1186      msgopt_list[count].len = strlen(toybuf);
1187      break;
1188    default: break;
1189    }
1190    optptr += optptr[1] + 2;
1191  }
1192  if ((overloaded == 1) || (overloaded == 3)) dhcpc_parseoptions(presult, optptr);
1193  if ((overloaded == 2) || (overloaded == 3)) dhcpc_parseoptions(presult, optptr);
1194  return type;
1195}
1196
1197// parses recvd messege to check that it was for us.
1198static uint8_t dhcpc_parsemsg(dhcpc_result_t *presult)
1199{
1200  if (state->pdhcp.op == DHCP_REPLY
1201      && !memcmp(state->pdhcp.chaddr, state->macaddr, 6)
1202      && !memcmp(&state->pdhcp.xid, &xid, sizeof(xid))) {
1203    memcpy(&presult->ipaddr.s_addr, &state->pdhcp.yiaddr, 4);
1204    presult->ipaddr.s_addr = ntohl(presult->ipaddr.s_addr);
1205    return get_option_msgtype(state->pdhcp.options);
1206  }
1207  return 0;
1208}
1209
1210// Sends a IP renew request.
1211static void renew(void)
1212{
1213  infomsg(infomode, "Performing a DHCP renew");
1214  switch (state->status) {
1215  case STATE_INIT:
1216    break;
1217  case STATE_BOUND:
1218    mode_raw();
1219  case STATE_RENEWING:    // FALLTHROUGH 
1220  case STATE_REBINDING:   // FALLTHROUGH 
1221    state->status = STATE_RENEW_REQUESTED;
1222    break;
1223  case STATE_RENEW_REQUESTED:
1224    run_script(NULL, "deconfig");
1225  case STATE_REQUESTING:           // FALLTHROUGH 
1226  case STATE_RELEASED:             // FALLTHROUGH 
1227    mode_raw();
1228    state->status = STATE_INIT;
1229    break;
1230  default: break;
1231  }
1232}
1233
1234// Sends a IP release request.
1235static void release(void)
1236{
1237  char buffer[sizeof("255.255.255.255\0")];
1238  struct in_addr temp_addr;
1239
1240  mode_app();
1241  // send release packet
1242  if (state->status == STATE_BOUND || state->status == STATE_RENEWING || state->status == STATE_REBINDING) {
1243    temp_addr.s_addr = htonl(server);
1244    xstrncpy(buffer, inet_ntoa(temp_addr), sizeof(buffer));
1245    temp_addr.s_addr = state->ipaddr.s_addr;
1246    infomsg( infomode, "Unicasting a release of %s to %s", inet_ntoa(temp_addr), buffer);
1247    dhcpc_sendmsg(DHCPRELEASE);
1248    run_script(NULL, "deconfig");
1249  }
1250  infomsg(infomode, "Entering released state");
1251  close(state->sockfd);
1252  state->sockfd = -1;
1253  state->mode = MODE_OFF;
1254  state->status = STATE_RELEASED;
1255}
1256
1257static void free_option_stores(void)
1258{
1259  int count, size = ARRAY_LEN(options_list);
1260  for (count = 0; count < size; count++)
1261    if (options_list[count].val) free(options_list[count].val);
1262  if (toys.optflags & FLAG_x) {
1263    for (count = 0; count < size; count++)
1264        if (msgopt_list[count].val) free(msgopt_list[count].val);
1265    free(msgopt_list);
1266  }
1267}
1268
1269void dhcp_main(void)
1270{
1271  struct timeval tv;
1272  int retval, bufflen = 0;
1273  dhcpc_result_t result;
1274  uint8_t packets = 0, retries = 0;
1275  uint32_t timeout = 0, waited = 0;
1276  fd_set rfds;
1277
1278  xid = 0;
1279  setlinebuf(stdout);
1280  dbg = dummy;
1281  if (toys.optflags & FLAG_v) dbg = xprintf;
1282  if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
1283  retries = TT.retries;
1284  if (toys.optflags & FLAG_S) {
1285      openlog("UDHCPC :", LOG_PID, LOG_DAEMON);
1286      infomode |= LOG_SYSTEM;
1287  }
1288  infomsg(infomode, "dhcp started");
1289  if (toys.optflags & FLAG_O) {
1290    while (TT.req_opt) {
1291      raw_opt[raw_optcount] = (uint8_t) strtoopt(TT.req_opt->arg, 1);
1292      raw_optcount++;
1293      TT.req_opt = TT.req_opt->next;
1294    }
1295  }
1296  if (toys.optflags & FLAG_x) {
1297    while (TT.pkt_opt) {
1298      (void) strtoopt(TT.pkt_opt->arg, 0);
1299      TT.pkt_opt = TT.pkt_opt->next;
1300    }
1301  }
1302  memset(&result, 0, sizeof(dhcpc_result_t));
1303  state = (dhcpc_state_t*) xmalloc(sizeof(dhcpc_state_t));
1304  memset(state, 0, sizeof(dhcpc_state_t));
1305  state->iface = (toys.optflags & FLAG_i) ? TT.iface : "eth0";
1306
1307  if (get_interface(state->iface, &state->ifindex, NULL, state->macaddr))
1308    perror_exit("Failed to get interface %s", state->iface);
1309
1310  run_script(NULL, "deconfig");
1311  setup_signal();
1312  state->status = STATE_INIT;
1313  mode_raw();
1314  fcntl(state->sockfd, F_SETFD, FD_CLOEXEC);
1315
1316  for (;;) {
1317    FD_ZERO(&rfds);
1318    if (state->sockfd >= 0) FD_SET(state->sockfd, &rfds);
1319    FD_SET(sigfd.rd, &rfds);
1320    tv.tv_sec = timeout - waited;
1321    tv.tv_usec = 0;
1322    retval = 0;
1323
1324    int maxfd = (sigfd.rd > state->sockfd)? sigfd.rd : state->sockfd;
1325    dbg("select wait ....\n");
1326    uint32_t timestmp = time(NULL);
1327    if((retval = select(maxfd + 1, &rfds, NULL, NULL, &tv)) < 0) {
1328      if (errno == EINTR) {
1329        waited += (unsigned) time(NULL) - timestmp;
1330        continue;
1331      }
1332      perror_exit("Error in select");
1333    }
1334    if (!retval) { // Timed out
1335      if (get_interface(state->iface, &state->ifindex, NULL, state->macaddr))
1336        error_exit("Interface lost %s\n", state->iface);
1337
1338      switch (state->status) {
1339      case STATE_INIT:
1340        if (packets < retries) {
1341          if (!packets) xid = getxid();
1342          run_script(NULL, "deconfig");
1343          infomsg(infomode, "Sending discover...");
1344          dhcpc_sendmsg(DHCPDISCOVER);
1345          server = 0;
1346          timeout = TT.timeout;
1347          waited = 0;
1348          packets++;
1349          continue;
1350        }
1351lease_fail:
1352        run_script(NULL,"leasefail");
1353        if (toys.optflags & FLAG_n) {
1354          infomsg(infomode, "Lease failed. Exiting");
1355          goto ret_with_sockfd;
1356        }
1357        if (toys.optflags & FLAG_b) {
1358          infomsg(infomode, "Lease failed. Going Daemon mode");
1359          daemon(0, 0);
1360          if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
1361          toys.optflags &= ~FLAG_b;
1362          toys.optflags |= FLAG_f;
1363        }
1364        timeout = TT.tryagain;
1365        waited = 0;
1366        packets = 0;
1367        continue;
1368      case STATE_REQUESTING:
1369        if (packets < retries) {
1370          memcpy(&state->ipaddr.s_addr,&state->pdhcp.yiaddr, 4);
1371          dhcpc_sendmsg(DHCPREQUEST);
1372          infomsg(infomode, "Sending select for %d.%d.%d.%d...",
1373              (result.ipaddr.s_addr >> 24) & 0xff, (result.ipaddr.s_addr >> 16) & 0xff, (result.ipaddr.s_addr >> 8) & 0xff, (result.ipaddr.s_addr) & 0xff);
1374          timeout = TT.timeout;
1375          waited = 0;
1376          packets++;
1377          continue;
1378        }
1379        mode_raw();
1380        state->status = STATE_INIT;
1381        goto lease_fail;
1382      case STATE_BOUND:
1383        state->status = STATE_RENEWING;
1384        dbg("Entering renew state\n");
1385        // FALLTHROUGH
1386      case STATE_RENEW_REQUESTED:   // FALLTHROUGH
1387      case STATE_RENEWING:
1388renew_requested:
1389        if (timeout > 60) {
1390          dhcpc_sendmsg(DHCPREQUEST);
1391          timeout >>= 1;
1392          waited = 0;
1393          continue;
1394        }
1395        dbg("Entering rebinding state\n");
1396        state->status = STATE_REBINDING;
1397        // FALLTHROUGH
1398      case STATE_REBINDING:
1399        mode_raw();
1400        if (timeout > 0) {
1401          dhcpc_sendmsg(DHCPREQUEST);
1402          timeout >>= 1;
1403          waited = 0;
1404          continue;
1405        }
1406        infomsg(infomode, "Lease lost, entering INIT state");
1407        run_script(NULL, "deconfig");
1408        state->status = STATE_INIT;
1409        timeout = 0;
1410        waited = 0;
1411        packets = 0;
1412        continue;
1413      default: break;
1414      }
1415      timeout = INT_MAX;
1416      waited = 0;
1417      continue;
1418    }
1419    if (FD_ISSET(sigfd.rd, &rfds)) { // Some Activity on RDFDs : is signal
1420      unsigned char sig;
1421      if (read(sigfd.rd, &sig, 1) != 1) {
1422        dbg("signal read failed.\n");
1423        continue;
1424      }
1425      switch (sig) {
1426      case SIGUSR1:
1427        infomsg(infomode, "Received SIGUSR1");
1428        renew();
1429        packets = 0;
1430        waited = 0;
1431        if (state->status == STATE_RENEW_REQUESTED) goto renew_requested;
1432        if (state->status == STATE_INIT) timeout = 0;
1433        continue;
1434      case SIGUSR2:
1435        infomsg(infomode, "Received SIGUSR2");
1436        release();
1437        timeout = INT_MAX;
1438        waited = 0;
1439        packets = 0;
1440        continue;
1441      case SIGTERM:
1442        infomsg(infomode, "Received SIGTERM");
1443        if (toys.optflags & FLAG_R) release();
1444        goto ret_with_sockfd;
1445      default: break;
1446      }
1447    }
1448    if (FD_ISSET(state->sockfd, &rfds)) { // Some Activity on RDFDs : is socket
1449      dbg("main sock read\n");
1450      uint8_t msgType;
1451      if (state->mode == MODE_RAW) bufflen = read_raw();
1452      if (state->mode == MODE_APP) bufflen = read_app();
1453      if (bufflen < 0) {
1454        if (state->mode == MODE_RAW) mode_raw();
1455        if (state->mode == MODE_APP) mode_app();
1456        continue;
1457      }
1458      waited += time(NULL) - timestmp;
1459      memset(&result, 0, sizeof(dhcpc_result_t));
1460      msgType = dhcpc_parsemsg(&result);
1461      if (msgType != DHCPNAK && result.ipaddr.s_addr == 0 ) continue;       // no ip for me ignore
1462      if (!msgType || !get_option_serverid(state->pdhcp.options, &result)) continue; //no server id ignore
1463      if (msgType == DHCPOFFER && server == 0) server = result.serverid.s_addr; // select the server
1464      if (result.serverid.s_addr != server) continue; // not from the server we requested ignore
1465      dhcpc_parseoptions(&result, state->pdhcp.options);
1466      get_option_lease(state->pdhcp.options, &result);
1467
1468      switch (state->status) {
1469      case STATE_INIT:
1470        if (msgType == DHCPOFFER) {
1471          state->status = STATE_REQUESTING;
1472          mode_raw();
1473          timeout = 0;
1474          waited = 0;
1475          packets = 0;
1476        }
1477        continue;
1478      case STATE_REQUESTING:         // FALLTHROUGH
1479      case STATE_RENEWING:           // FALLTHROUGH
1480      case STATE_RENEW_REQUESTED:    // FALLTHROUGH
1481      case STATE_REBINDING:
1482        if (msgType == DHCPACK) {
1483          timeout = result.lease_time / 2;
1484          run_script(&result, state->status == STATE_REQUESTING ? "bound" : "renew");
1485          state->status = STATE_BOUND;
1486          infomsg(infomode, "Lease of %d.%d.%d.%d obtained, lease time %d from server %d.%d.%d.%d",
1487              (result.ipaddr.s_addr >> 24) & 0xff, (result.ipaddr.s_addr >> 16) & 0xff, (result.ipaddr.s_addr >> 8) & 0xff, (result.ipaddr.s_addr) & 0xff,
1488              result.lease_time,
1489              (result.serverid.s_addr >> 24) & 0xff, (result.serverid.s_addr >> 16) & 0xff, (result.serverid.s_addr >> 8) & 0xff, (result.serverid.s_addr) & 0xff);
1490          if (toys.optflags & FLAG_q) {
1491            if (toys.optflags & FLAG_R) release();
1492            goto ret_with_sockfd;
1493          }
1494          toys.optflags &= ~FLAG_n;
1495          if (!(toys.optflags & FLAG_f)) {
1496            daemon(0, 0);
1497            toys.optflags |= FLAG_f;
1498            if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
1499          }
1500          waited = 0;
1501          continue;
1502        } else if (msgType == DHCPNAK) {
1503          dbg("NACK received.\n");
1504          run_script(&result, "nak");
1505          if (state->status != STATE_REQUESTING) run_script(NULL, "deconfig");
1506          mode_raw();
1507          sleep(3);
1508          state->status = STATE_INIT;
1509          state->ipaddr.s_addr = 0;
1510          server = 0;
1511          timeout = 0;
1512          packets = 0;
1513          waited = 0;
1514        }
1515        continue;
1516      default: break;
1517      }
1518    }
1519  }
1520ret_with_sockfd:
1521  if (CFG_TOYBOX_FREE) {
1522    free_option_stores();
1523    if (state->sockfd > 0) close(state->sockfd);
1524    free(state);
1525  }
1526}
1527