1 /* 2 * Copyright 2008, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "DHCP" 18 19 #include <dirent.h> 20 #include <errno.h> 21 #include <poll.h> 22 #include <netinet/in.h> 23 #include <stdarg.h> 24 #include <stdlib.h> 25 #include <stdio.h> 26 #include <string.h> 27 #include <sys/select.h> 28 #include <sys/socket.h> 29 #include <sys/time.h> 30 #include <sys/types.h> 31 #include <time.h> 32 #include <unistd.h> 33 34 #include <cutils/properties.h> 35 #include <log/log.h> 36 37 #include <netutils/ifc.h> 38 #include "dhcpmsg.h" 39 #include "packet.h" 40 41 #define VERBOSE 2 42 43 static int verbose = 1; 44 static char errmsg[2048]; 45 46 typedef unsigned long long msecs_t; 47 #if VERBOSE 48 void dump_dhcp_msg(); 49 #endif 50 51 msecs_t get_msecs(void) 52 { 53 struct timespec ts; 54 55 if (clock_gettime(CLOCK_MONOTONIC, &ts)) { 56 return 0; 57 } else { 58 return (((msecs_t) ts.tv_sec) * ((msecs_t) 1000)) + 59 (((msecs_t) ts.tv_nsec) / ((msecs_t) 1000000)); 60 } 61 } 62 63 void printerr(char *fmt, ...) 64 { 65 va_list ap; 66 67 va_start(ap, fmt); 68 vsnprintf(errmsg, sizeof(errmsg), fmt, ap); 69 va_end(ap); 70 71 ALOGD("%s", errmsg); 72 } 73 74 const char *dhcp_lasterror() 75 { 76 return errmsg; 77 } 78 79 int fatal(const char *reason) 80 { 81 printerr("%s: %s\n", reason, strerror(errno)); 82 return -1; 83 // exit(1); 84 } 85 86 const char *ipaddr(in_addr_t addr) 87 { 88 struct in_addr in_addr; 89 90 in_addr.s_addr = addr; 91 return inet_ntoa(in_addr); 92 } 93 94 extern int ipv4NetmaskToPrefixLength(in_addr_t mask); 95 96 typedef struct dhcp_info dhcp_info; 97 98 struct dhcp_info { 99 uint32_t type; 100 101 uint32_t ipaddr; 102 uint32_t gateway; 103 uint32_t prefixLength; 104 105 uint32_t dns1; 106 uint32_t dns2; 107 108 uint32_t serveraddr; 109 uint32_t lease; 110 }; 111 112 dhcp_info last_good_info; 113 114 void get_dhcp_info(uint32_t *ipaddr, uint32_t *gateway, uint32_t *prefixLength, 115 uint32_t *dns1, uint32_t *dns2, uint32_t *server, 116 uint32_t *lease) 117 { 118 *ipaddr = last_good_info.ipaddr; 119 *gateway = last_good_info.gateway; 120 *prefixLength = last_good_info.prefixLength; 121 *dns1 = last_good_info.dns1; 122 *dns2 = last_good_info.dns2; 123 *server = last_good_info.serveraddr; 124 *lease = last_good_info.lease; 125 } 126 127 static int dhcp_configure(const char *ifname, dhcp_info *info) 128 { 129 last_good_info = *info; 130 return ifc_configure(ifname, info->ipaddr, info->prefixLength, info->gateway, 131 info->dns1, info->dns2); 132 } 133 134 static const char *dhcp_type_to_name(uint32_t type) 135 { 136 switch(type) { 137 case DHCPDISCOVER: return "discover"; 138 case DHCPOFFER: return "offer"; 139 case DHCPREQUEST: return "request"; 140 case DHCPDECLINE: return "decline"; 141 case DHCPACK: return "ack"; 142 case DHCPNAK: return "nak"; 143 case DHCPRELEASE: return "release"; 144 case DHCPINFORM: return "inform"; 145 default: return "???"; 146 } 147 } 148 149 void dump_dhcp_info(dhcp_info *info) 150 { 151 char addr[20], gway[20]; 152 ALOGD("--- dhcp %s (%d) ---", 153 dhcp_type_to_name(info->type), info->type); 154 strcpy(addr, ipaddr(info->ipaddr)); 155 strcpy(gway, ipaddr(info->gateway)); 156 ALOGD("ip %s gw %s prefixLength %d", addr, gway, info->prefixLength); 157 if (info->dns1) ALOGD("dns1: %s", ipaddr(info->dns1)); 158 if (info->dns2) ALOGD("dns2: %s", ipaddr(info->dns2)); 159 ALOGD("server %s, lease %d seconds", 160 ipaddr(info->serveraddr), info->lease); 161 } 162 163 164 int decode_dhcp_msg(dhcp_msg *msg, int len, dhcp_info *info) 165 { 166 uint8_t *x; 167 unsigned int opt; 168 int optlen; 169 170 memset(info, 0, sizeof(dhcp_info)); 171 if (len < (DHCP_MSG_FIXED_SIZE + 4)) return -1; 172 173 len -= (DHCP_MSG_FIXED_SIZE + 4); 174 175 if (msg->options[0] != OPT_COOKIE1) return -1; 176 if (msg->options[1] != OPT_COOKIE2) return -1; 177 if (msg->options[2] != OPT_COOKIE3) return -1; 178 if (msg->options[3] != OPT_COOKIE4) return -1; 179 180 x = msg->options + 4; 181 182 while (len > 2) { 183 opt = *x++; 184 if (opt == OPT_PAD) { 185 len--; 186 continue; 187 } 188 if (opt == OPT_END) { 189 break; 190 } 191 optlen = *x++; 192 len -= 2; 193 if (optlen > len) { 194 break; 195 } 196 switch(opt) { 197 case OPT_SUBNET_MASK: 198 if (optlen >= 4) { 199 in_addr_t mask; 200 memcpy(&mask, x, 4); 201 info->prefixLength = ipv4NetmaskToPrefixLength(mask); 202 } 203 break; 204 case OPT_GATEWAY: 205 if (optlen >= 4) memcpy(&info->gateway, x, 4); 206 break; 207 case OPT_DNS: 208 if (optlen >= 4) memcpy(&info->dns1, x + 0, 4); 209 if (optlen >= 8) memcpy(&info->dns2, x + 4, 4); 210 break; 211 case OPT_LEASE_TIME: 212 if (optlen >= 4) { 213 memcpy(&info->lease, x, 4); 214 info->lease = ntohl(info->lease); 215 } 216 break; 217 case OPT_SERVER_ID: 218 if (optlen >= 4) memcpy(&info->serveraddr, x, 4); 219 break; 220 case OPT_MESSAGE_TYPE: 221 info->type = *x; 222 break; 223 default: 224 break; 225 } 226 x += optlen; 227 len -= optlen; 228 } 229 230 info->ipaddr = msg->yiaddr; 231 232 return 0; 233 } 234 235 #if VERBOSE 236 237 static void hex2str(char *buf, size_t buf_size, const unsigned char *array, int len) 238 { 239 int i; 240 char *cp = buf; 241 char *buf_end = buf + buf_size; 242 for (i = 0; i < len; i++) { 243 cp += snprintf(cp, buf_end - cp, " %02x ", array[i]); 244 } 245 } 246 247 void dump_dhcp_msg(dhcp_msg *msg, int len) 248 { 249 unsigned char *x; 250 unsigned int n,c; 251 int optsz; 252 const char *name; 253 char buf[2048]; 254 255 ALOGD("===== DHCP message:"); 256 if (len < DHCP_MSG_FIXED_SIZE) { 257 ALOGD("Invalid length %d, should be %d", len, DHCP_MSG_FIXED_SIZE); 258 return; 259 } 260 261 len -= DHCP_MSG_FIXED_SIZE; 262 263 if (msg->op == OP_BOOTREQUEST) 264 name = "BOOTREQUEST"; 265 else if (msg->op == OP_BOOTREPLY) 266 name = "BOOTREPLY"; 267 else 268 name = "????"; 269 ALOGD("op = %s (%d), htype = %d, hlen = %d, hops = %d", 270 name, msg->op, msg->htype, msg->hlen, msg->hops); 271 ALOGD("xid = 0x%08x secs = %d, flags = 0x%04x optlen = %d", 272 ntohl(msg->xid), ntohs(msg->secs), ntohs(msg->flags), len); 273 ALOGD("ciaddr = %s", ipaddr(msg->ciaddr)); 274 ALOGD("yiaddr = %s", ipaddr(msg->yiaddr)); 275 ALOGD("siaddr = %s", ipaddr(msg->siaddr)); 276 ALOGD("giaddr = %s", ipaddr(msg->giaddr)); 277 278 c = msg->hlen > 16 ? 16 : msg->hlen; 279 hex2str(buf, sizeof(buf), msg->chaddr, c); 280 ALOGD("chaddr = {%s}", buf); 281 282 for (n = 0; n < 64; n++) { 283 unsigned char x = msg->sname[n]; 284 if ((x < ' ') || (x > 127)) { 285 if (x == 0) break; 286 msg->sname[n] = '.'; 287 } 288 } 289 msg->sname[63] = 0; 290 291 for (n = 0; n < 128; n++) { 292 unsigned char x = msg->file[n]; 293 if ((x < ' ') || (x > 127)) { 294 if (x == 0) break; 295 msg->file[n] = '.'; 296 } 297 } 298 msg->file[127] = 0; 299 300 ALOGD("sname = '%s'", msg->sname); 301 ALOGD("file = '%s'", msg->file); 302 303 if (len < 4) return; 304 len -= 4; 305 x = msg->options + 4; 306 307 while (len > 2) { 308 if (*x == 0) { 309 x++; 310 len--; 311 continue; 312 } 313 if (*x == OPT_END) { 314 break; 315 } 316 len -= 2; 317 optsz = x[1]; 318 if (optsz > len) break; 319 if (x[0] == OPT_DOMAIN_NAME || x[0] == OPT_MESSAGE) { 320 if ((unsigned int)optsz < sizeof(buf) - 1) { 321 n = optsz; 322 } else { 323 n = sizeof(buf) - 1; 324 } 325 memcpy(buf, &x[2], n); 326 buf[n] = '\0'; 327 } else { 328 hex2str(buf, sizeof(buf), &x[2], optsz); 329 } 330 if (x[0] == OPT_MESSAGE_TYPE) 331 name = dhcp_type_to_name(x[2]); 332 else 333 name = NULL; 334 ALOGD("op %d len %d {%s} %s", x[0], optsz, buf, name == NULL ? "" : name); 335 len -= optsz; 336 x = x + optsz + 2; 337 } 338 } 339 340 #endif 341 342 static int send_message(int sock, int if_index, dhcp_msg *msg, int size) 343 { 344 #if VERBOSE > 1 345 dump_dhcp_msg(msg, size); 346 #endif 347 return send_packet(sock, if_index, msg, size, INADDR_ANY, INADDR_BROADCAST, 348 PORT_BOOTP_CLIENT, PORT_BOOTP_SERVER); 349 } 350 351 static int is_valid_reply(dhcp_msg *msg, dhcp_msg *reply, int sz) 352 { 353 if (sz < DHCP_MSG_FIXED_SIZE) { 354 if (verbose) ALOGD("Wrong size %d != %d\n", sz, DHCP_MSG_FIXED_SIZE); 355 return 0; 356 } 357 if (reply->op != OP_BOOTREPLY) { 358 if (verbose) ALOGD("Wrong Op %d != %d\n", reply->op, OP_BOOTREPLY); 359 return 0; 360 } 361 if (reply->xid != msg->xid) { 362 if (verbose) ALOGD("Wrong Xid 0x%x != 0x%x\n", ntohl(reply->xid), 363 ntohl(msg->xid)); 364 return 0; 365 } 366 if (reply->htype != msg->htype) { 367 if (verbose) ALOGD("Wrong Htype %d != %d\n", reply->htype, msg->htype); 368 return 0; 369 } 370 if (reply->hlen != msg->hlen) { 371 if (verbose) ALOGD("Wrong Hlen %d != %d\n", reply->hlen, msg->hlen); 372 return 0; 373 } 374 if (memcmp(msg->chaddr, reply->chaddr, msg->hlen)) { 375 if (verbose) ALOGD("Wrong chaddr %x != %x\n", *(reply->chaddr),*(msg->chaddr)); 376 return 0; 377 } 378 return 1; 379 } 380 381 #define STATE_SELECTING 1 382 #define STATE_REQUESTING 2 383 384 #define TIMEOUT_INITIAL 4000 385 #define TIMEOUT_MAX 32000 386 387 int dhcp_init_ifc(const char *ifname) 388 { 389 dhcp_msg discover_msg; 390 dhcp_msg request_msg; 391 dhcp_msg reply; 392 dhcp_msg *msg; 393 dhcp_info info; 394 int s, r, size; 395 int valid_reply; 396 uint32_t xid; 397 unsigned char hwaddr[6]; 398 struct pollfd pfd; 399 unsigned int state; 400 unsigned int timeout; 401 int if_index; 402 403 xid = (uint32_t) get_msecs(); 404 405 if (ifc_get_hwaddr(ifname, hwaddr)) { 406 return fatal("cannot obtain interface address"); 407 } 408 if (ifc_get_ifindex(ifname, &if_index)) { 409 return fatal("cannot obtain interface index"); 410 } 411 412 s = open_raw_socket(ifname, hwaddr, if_index); 413 414 timeout = TIMEOUT_INITIAL; 415 state = STATE_SELECTING; 416 info.type = 0; 417 goto transmit; 418 419 for (;;) { 420 pfd.fd = s; 421 pfd.events = POLLIN; 422 pfd.revents = 0; 423 r = poll(&pfd, 1, timeout); 424 425 if (r == 0) { 426 #if VERBOSE 427 printerr("TIMEOUT\n"); 428 #endif 429 if (timeout >= TIMEOUT_MAX) { 430 printerr("timed out\n"); 431 if ( info.type == DHCPOFFER ) { 432 printerr("no acknowledgement from DHCP server\nconfiguring %s with offered parameters\n", ifname); 433 return dhcp_configure(ifname, &info); 434 } 435 errno = ETIME; 436 close(s); 437 return -1; 438 } 439 timeout = timeout * 2; 440 441 transmit: 442 size = 0; 443 msg = NULL; 444 switch(state) { 445 case STATE_SELECTING: 446 msg = &discover_msg; 447 size = init_dhcp_discover_msg(msg, hwaddr, xid); 448 break; 449 case STATE_REQUESTING: 450 msg = &request_msg; 451 size = init_dhcp_request_msg(msg, hwaddr, xid, info.ipaddr, info.serveraddr); 452 break; 453 default: 454 r = 0; 455 } 456 if (size != 0) { 457 r = send_message(s, if_index, msg, size); 458 if (r < 0) { 459 printerr("error sending dhcp msg: %s\n", strerror(errno)); 460 } 461 } 462 continue; 463 } 464 465 if (r < 0) { 466 if ((errno == EAGAIN) || (errno == EINTR)) { 467 continue; 468 } 469 return fatal("poll failed"); 470 } 471 472 errno = 0; 473 r = receive_packet(s, &reply); 474 if (r < 0) { 475 if (errno != 0) { 476 ALOGD("receive_packet failed (%d): %s", r, strerror(errno)); 477 if (errno == ENETDOWN || errno == ENXIO) { 478 return -1; 479 } 480 } 481 continue; 482 } 483 484 #if VERBOSE > 1 485 dump_dhcp_msg(&reply, r); 486 #endif 487 decode_dhcp_msg(&reply, r, &info); 488 489 if (state == STATE_SELECTING) { 490 valid_reply = is_valid_reply(&discover_msg, &reply, r); 491 } else { 492 valid_reply = is_valid_reply(&request_msg, &reply, r); 493 } 494 if (!valid_reply) { 495 printerr("invalid reply\n"); 496 continue; 497 } 498 499 if (verbose) dump_dhcp_info(&info); 500 501 switch(state) { 502 case STATE_SELECTING: 503 if (info.type == DHCPOFFER) { 504 state = STATE_REQUESTING; 505 timeout = TIMEOUT_INITIAL; 506 xid++; 507 goto transmit; 508 } 509 break; 510 case STATE_REQUESTING: 511 if (info.type == DHCPACK) { 512 printerr("configuring %s\n", ifname); 513 close(s); 514 return dhcp_configure(ifname, &info); 515 } else if (info.type == DHCPNAK) { 516 printerr("configuration request denied\n"); 517 close(s); 518 return -1; 519 } else { 520 printerr("ignoring %s message in state %d\n", 521 dhcp_type_to_name(info.type), state); 522 } 523 break; 524 } 525 } 526 close(s); 527 return 0; 528 } 529 530 int do_dhcp(char *iname) 531 { 532 if (ifc_set_addr(iname, 0)) { 533 printerr("failed to set ip addr for %s to 0.0.0.0: %s\n", iname, strerror(errno)); 534 return -1; 535 } 536 537 if (ifc_up(iname)) { 538 printerr("failed to bring up interface %s: %s\n", iname, strerror(errno)); 539 return -1; 540 } 541 542 return dhcp_init_ifc(iname); 543 } 544