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