ifc_utils.c revision 6f49d5f266dffee103a3af07a7f6266f405d2924
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#include <stdio.h> 18#include <stdlib.h> 19#include <unistd.h> 20#include <string.h> 21#include <errno.h> 22 23#include <sys/socket.h> 24#include <sys/select.h> 25#include <sys/types.h> 26#include <netinet/in.h> 27#include <arpa/inet.h> 28#include <net/if.h> 29 30#include <linux/if.h> 31#include <linux/if_ether.h> 32#include <linux/if_arp.h> 33#include <linux/sockios.h> 34#include <linux/route.h> 35#include <linux/ipv6_route.h> 36#include <netdb.h> 37#include <linux/wireless.h> 38 39#ifdef ANDROID 40#define LOG_TAG "NetUtils" 41#include <cutils/log.h> 42#include <cutils/properties.h> 43#else 44#include <stdio.h> 45#include <string.h> 46#define LOGD printf 47#define LOGW printf 48#endif 49 50static int ifc_ctl_sock = -1; 51static int ifc_ctl_sock6 = -1; 52void printerr(char *fmt, ...); 53 54in_addr_t prefixLengthToIpv4Netmask(int prefix_length) 55{ 56 in_addr_t mask = 0; 57 58 // C99 (6.5.7): shifts of 32 bits have undefined results 59 if (prefix_length <= 0 || prefix_length > 32) { 60 return 0; 61 } 62 63 mask = ~mask << (32 - prefix_length); 64 mask = htonl(mask); 65 66 return mask; 67} 68 69int ipv4NetmaskToPrefixLength(in_addr_t mask) 70{ 71 mask = ntohl(mask); 72 int prefixLength = 0; 73 uint32_t m = (uint32_t)mask; 74 while (m & 0x80000000) { 75 prefixLength++; 76 m = m << 1; 77 } 78 return prefixLength; 79} 80 81static const char *ipaddr_to_string(in_addr_t addr) 82{ 83 struct in_addr in_addr; 84 85 in_addr.s_addr = addr; 86 return inet_ntoa(in_addr); 87} 88 89int ifc_init(void) 90{ 91 if (ifc_ctl_sock == -1) { 92 ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM, 0); 93 if (ifc_ctl_sock < 0) { 94 printerr("socket() failed: %s\n", strerror(errno)); 95 } 96 } 97 return ifc_ctl_sock < 0 ? -1 : 0; 98} 99 100int ifc_init6(void) 101{ 102 if (ifc_ctl_sock6 == -1) { 103 ifc_ctl_sock6 = socket(AF_INET6, SOCK_DGRAM, 0); 104 if (ifc_ctl_sock6 < 0) { 105 printerr("socket() failed: %s\n", strerror(errno)); 106 } 107 } 108 return ifc_ctl_sock6 < 0 ? -1 : 0; 109} 110 111void ifc_close(void) 112{ 113 if (ifc_ctl_sock != -1) { 114 (void)close(ifc_ctl_sock); 115 ifc_ctl_sock = -1; 116 } 117} 118 119void ifc_close6(void) 120{ 121 if (ifc_ctl_sock6 != -1) { 122 (void)close(ifc_ctl_sock6); 123 ifc_ctl_sock6 = -1; 124 } 125} 126 127static void ifc_init_ifr(const char *name, struct ifreq *ifr) 128{ 129 memset(ifr, 0, sizeof(struct ifreq)); 130 strncpy(ifr->ifr_name, name, IFNAMSIZ); 131 ifr->ifr_name[IFNAMSIZ - 1] = 0; 132} 133 134int ifc_get_hwaddr(const char *name, void *ptr) 135{ 136 int r; 137 struct ifreq ifr; 138 ifc_init_ifr(name, &ifr); 139 140 r = ioctl(ifc_ctl_sock, SIOCGIFHWADDR, &ifr); 141 if(r < 0) return -1; 142 143 memcpy(ptr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN); 144 return 0; 145} 146 147int ifc_get_ifindex(const char *name, int *if_indexp) 148{ 149 int r; 150 struct ifreq ifr; 151 ifc_init_ifr(name, &ifr); 152 153 r = ioctl(ifc_ctl_sock, SIOCGIFINDEX, &ifr); 154 if(r < 0) return -1; 155 156 *if_indexp = ifr.ifr_ifindex; 157 return 0; 158} 159 160static int ifc_set_flags(const char *name, unsigned set, unsigned clr) 161{ 162 struct ifreq ifr; 163 ifc_init_ifr(name, &ifr); 164 165 if(ioctl(ifc_ctl_sock, SIOCGIFFLAGS, &ifr) < 0) return -1; 166 ifr.ifr_flags = (ifr.ifr_flags & (~clr)) | set; 167 return ioctl(ifc_ctl_sock, SIOCSIFFLAGS, &ifr); 168} 169 170int ifc_up(const char *name) 171{ 172 return ifc_set_flags(name, IFF_UP, 0); 173} 174 175int ifc_down(const char *name) 176{ 177 return ifc_set_flags(name, 0, IFF_UP); 178} 179 180static void init_sockaddr_in(struct sockaddr *sa, in_addr_t addr) 181{ 182 struct sockaddr_in *sin = (struct sockaddr_in *) sa; 183 sin->sin_family = AF_INET; 184 sin->sin_port = 0; 185 sin->sin_addr.s_addr = addr; 186} 187 188int ifc_set_addr(const char *name, in_addr_t addr) 189{ 190 struct ifreq ifr; 191 192 ifc_init_ifr(name, &ifr); 193 init_sockaddr_in(&ifr.ifr_addr, addr); 194 195 return ioctl(ifc_ctl_sock, SIOCSIFADDR, &ifr); 196} 197 198int ifc_set_hwaddr(const char *name, const void *ptr) 199{ 200 int r; 201 struct ifreq ifr; 202 ifc_init_ifr(name, &ifr); 203 204 ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; 205 memcpy(&ifr.ifr_hwaddr.sa_data, ptr, ETH_ALEN); 206 return ioctl(ifc_ctl_sock, SIOCSIFHWADDR, &ifr); 207} 208 209int ifc_set_mask(const char *name, in_addr_t mask) 210{ 211 struct ifreq ifr; 212 213 ifc_init_ifr(name, &ifr); 214 init_sockaddr_in(&ifr.ifr_addr, mask); 215 216 return ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &ifr); 217} 218 219int ifc_set_prefixLength(const char *name, int prefixLength) 220{ 221 struct ifreq ifr; 222 // TODO - support ipv6 223 if (prefixLength > 32 || prefixLength < 0) return -1; 224 225 in_addr_t mask = prefixLengthToIpv4Netmask(prefixLength); 226 ifc_init_ifr(name, &ifr); 227 init_sockaddr_in(&ifr.ifr_addr, mask); 228 229 return ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &ifr); 230} 231 232int ifc_get_addr(const char *name, in_addr_t *addr) 233{ 234 struct ifreq ifr; 235 int ret = 0; 236 237 ifc_init_ifr(name, &ifr); 238 if (addr != NULL) { 239 ret = ioctl(ifc_ctl_sock, SIOCGIFADDR, &ifr); 240 if (ret < 0) { 241 *addr = 0; 242 } else { 243 *addr = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr; 244 } 245 } 246 return ret; 247} 248 249int ifc_get_info(const char *name, in_addr_t *addr, int *prefixLength, unsigned *flags) 250{ 251 struct ifreq ifr; 252 ifc_init_ifr(name, &ifr); 253 254 if (addr != NULL) { 255 if(ioctl(ifc_ctl_sock, SIOCGIFADDR, &ifr) < 0) { 256 *addr = 0; 257 } else { 258 *addr = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr; 259 } 260 } 261 262 if (prefixLength != NULL) { 263 if(ioctl(ifc_ctl_sock, SIOCGIFNETMASK, &ifr) < 0) { 264 *prefixLength = 0; 265 } else { 266 *prefixLength = ipv4NetmaskToPrefixLength((int) 267 ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr); 268 } 269 } 270 271 if (flags != NULL) { 272 if(ioctl(ifc_ctl_sock, SIOCGIFFLAGS, &ifr) < 0) { 273 *flags = 0; 274 } else { 275 *flags = ifr.ifr_flags; 276 } 277 } 278 279 return 0; 280} 281 282int ifc_add_ipv4_route(const char *ifname, struct in_addr dst, int prefix_length, 283 struct in_addr gw) 284{ 285 struct rtentry rt; 286 int result; 287 in_addr_t netmask; 288 289 memset(&rt, 0, sizeof(rt)); 290 291 rt.rt_dst.sa_family = AF_INET; 292 rt.rt_dev = (void*) ifname; 293 294 netmask = prefixLengthToIpv4Netmask(prefix_length); 295 init_sockaddr_in(&rt.rt_genmask, netmask); 296 init_sockaddr_in(&rt.rt_dst, dst.s_addr); 297 rt.rt_flags = RTF_UP; 298 299 if (prefix_length == 32) { 300 rt.rt_flags |= RTF_HOST; 301 } 302 303 if (gw.s_addr != 0) { 304 rt.rt_flags |= RTF_GATEWAY; 305 init_sockaddr_in(&rt.rt_gateway, gw.s_addr); 306 } 307 308 ifc_init(); 309 310 if (ifc_ctl_sock < 0) { 311 return -errno; 312 } 313 314 result = ioctl(ifc_ctl_sock, SIOCADDRT, &rt); 315 if (result < 0) { 316 if (errno == EEXIST) { 317 result = 0; 318 } else { 319 result = -errno; 320 } 321 } 322 ifc_close(); 323 return result; 324} 325 326int ifc_create_default_route(const char *name, in_addr_t gw) 327{ 328 struct in_addr in_dst, in_gw; 329 330 in_dst.s_addr = 0; 331 in_gw.s_addr = gw; 332 333 return ifc_add_ipv4_route(name, in_dst, 0, in_gw); 334} 335 336int ifc_add_host_route(const char *name, in_addr_t dst) 337{ 338 struct in_addr in_dst, in_gw; 339 340 in_dst.s_addr = dst; 341 in_gw.s_addr = 0; 342 343 return ifc_add_ipv4_route(name, in_dst, 32, in_gw); 344} 345 346int ifc_enable(const char *ifname) 347{ 348 int result; 349 350 ifc_init(); 351 result = ifc_up(ifname); 352 ifc_close(); 353 return result; 354} 355 356int ifc_disable(const char *ifname) 357{ 358 unsigned addr, count; 359 int result; 360 361 ifc_init(); 362 result = ifc_down(ifname); 363 364 ifc_set_addr(ifname, 0); 365 for (count=0, addr=1;((addr != 0) && (count < 255)); count++) { 366 if (ifc_get_addr(ifname, &addr) < 0) 367 break; 368 if (addr) 369 ifc_set_addr(ifname, 0); 370 } 371 372 ifc_close(); 373 return result; 374} 375 376int ifc_reset_connections(const char *ifname) 377{ 378#ifdef HAVE_ANDROID_OS 379 int result, success; 380 in_addr_t myaddr; 381 struct ifreq ifr; 382 struct in6_ifreq ifr6; 383 384 /* IPv4. Clear connections on the IP address. */ 385 ifc_init(); 386 ifc_get_info(ifname, &myaddr, NULL, NULL); 387 ifc_init_ifr(ifname, &ifr); 388 init_sockaddr_in(&ifr.ifr_addr, myaddr); 389 result = ioctl(ifc_ctl_sock, SIOCKILLADDR, &ifr); 390 ifc_close(); 391 392 /* 393 * IPv6. On Linux, when an interface goes down it loses all its IPv6 394 * addresses, so we don't know which connections belonged to that interface 395 * So we clear all unused IPv6 connections on the device by specifying an 396 * empty IPv6 address. 397 */ 398 ifc_init6(); 399 // This implicitly specifies an address of ::, i.e., kill all IPv6 sockets. 400 memset(&ifr6, 0, sizeof(ifr6)); 401 success = ioctl(ifc_ctl_sock6, SIOCKILLADDR, &ifr6); 402 if (result == 0) { 403 result = success; 404 } 405 ifc_close6(); 406 407 return result; 408#else 409 return 0; 410#endif 411} 412 413/* 414 * Remove the routes associated with the named interface. 415 */ 416int ifc_remove_host_routes(const char *name) 417{ 418 char ifname[64]; 419 in_addr_t dest, gway, mask; 420 int flags, refcnt, use, metric, mtu, win, irtt; 421 struct rtentry rt; 422 FILE *fp; 423 struct in_addr addr; 424 425 fp = fopen("/proc/net/route", "r"); 426 if (fp == NULL) 427 return -1; 428 /* Skip the header line */ 429 if (fscanf(fp, "%*[^\n]\n") < 0) { 430 fclose(fp); 431 return -1; 432 } 433 ifc_init(); 434 for (;;) { 435 int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n", 436 ifname, &dest, &gway, &flags, &refcnt, &use, &metric, &mask, 437 &mtu, &win, &irtt); 438 if (nread != 11) { 439 break; 440 } 441 if ((flags & (RTF_UP|RTF_HOST)) != (RTF_UP|RTF_HOST) 442 || strcmp(ifname, name) != 0) { 443 continue; 444 } 445 memset(&rt, 0, sizeof(rt)); 446 rt.rt_dev = (void *)name; 447 init_sockaddr_in(&rt.rt_dst, dest); 448 init_sockaddr_in(&rt.rt_gateway, gway); 449 init_sockaddr_in(&rt.rt_genmask, mask); 450 addr.s_addr = dest; 451 if (ioctl(ifc_ctl_sock, SIOCDELRT, &rt) < 0) { 452 LOGD("failed to remove route for %s to %s: %s", 453 ifname, inet_ntoa(addr), strerror(errno)); 454 } 455 } 456 fclose(fp); 457 ifc_close(); 458 return 0; 459} 460 461/* 462 * Return the address of the default gateway 463 * 464 * TODO: factor out common code from this and remove_host_routes() 465 * so that we only scan /proc/net/route in one place. 466 */ 467int ifc_get_default_route(const char *ifname) 468{ 469 char name[64]; 470 in_addr_t dest, gway, mask; 471 int flags, refcnt, use, metric, mtu, win, irtt; 472 int result; 473 FILE *fp; 474 475 fp = fopen("/proc/net/route", "r"); 476 if (fp == NULL) 477 return 0; 478 /* Skip the header line */ 479 if (fscanf(fp, "%*[^\n]\n") < 0) { 480 fclose(fp); 481 return 0; 482 } 483 ifc_init(); 484 result = 0; 485 for (;;) { 486 int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n", 487 name, &dest, &gway, &flags, &refcnt, &use, &metric, &mask, 488 &mtu, &win, &irtt); 489 if (nread != 11) { 490 break; 491 } 492 if ((flags & (RTF_UP|RTF_GATEWAY)) == (RTF_UP|RTF_GATEWAY) 493 && dest == 0 494 && strcmp(ifname, name) == 0) { 495 result = gway; 496 break; 497 } 498 } 499 fclose(fp); 500 ifc_close(); 501 return result; 502} 503 504/* 505 * Sets the specified gateway as the default route for the named interface. 506 */ 507int ifc_set_default_route(const char *ifname, in_addr_t gateway) 508{ 509 struct in_addr addr; 510 int result; 511 512 ifc_init(); 513 addr.s_addr = gateway; 514 if ((result = ifc_create_default_route(ifname, gateway)) < 0) { 515 LOGD("failed to add %s as default route for %s: %s", 516 inet_ntoa(addr), ifname, strerror(errno)); 517 } 518 ifc_close(); 519 return result; 520} 521 522/* 523 * Removes the default route for the named interface. 524 */ 525int ifc_remove_default_route(const char *ifname) 526{ 527 struct rtentry rt; 528 int result; 529 530 ifc_init(); 531 memset(&rt, 0, sizeof(rt)); 532 rt.rt_dev = (void *)ifname; 533 rt.rt_flags = RTF_UP|RTF_GATEWAY; 534 init_sockaddr_in(&rt.rt_dst, 0); 535 if ((result = ioctl(ifc_ctl_sock, SIOCDELRT, &rt)) < 0) { 536 LOGD("failed to remove default route for %s: %s", ifname, strerror(errno)); 537 } 538 ifc_close(); 539 return result; 540} 541 542int 543ifc_configure(const char *ifname, 544 in_addr_t address, 545 uint32_t prefixLength, 546 in_addr_t gateway, 547 in_addr_t dns1, 548 in_addr_t dns2) { 549 550 char dns_prop_name[PROPERTY_KEY_MAX]; 551 552 ifc_init(); 553 554 if (ifc_up(ifname)) { 555 printerr("failed to turn on interface %s: %s\n", ifname, strerror(errno)); 556 ifc_close(); 557 return -1; 558 } 559 if (ifc_set_addr(ifname, address)) { 560 printerr("failed to set ipaddr %s: %s\n", ipaddr_to_string(address), strerror(errno)); 561 ifc_close(); 562 return -1; 563 } 564 if (ifc_set_prefixLength(ifname, prefixLength)) { 565 printerr("failed to set prefixLength %d: %s\n", prefixLength, strerror(errno)); 566 ifc_close(); 567 return -1; 568 } 569 if (ifc_create_default_route(ifname, gateway)) { 570 printerr("failed to set default route %s: %s\n", ipaddr_to_string(gateway), strerror(errno)); 571 ifc_close(); 572 return -1; 573 } 574 575 ifc_close(); 576 577 snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns1", ifname); 578 property_set(dns_prop_name, dns1 ? ipaddr_to_string(dns1) : ""); 579 snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns2", ifname); 580 property_set(dns_prop_name, dns2 ? ipaddr_to_string(dns2) : ""); 581 582 return 0; 583} 584 585int ifc_add_ipv6_route(const char *ifname, struct in6_addr dst, int prefix_length, 586 struct in6_addr gw) 587{ 588 struct in6_rtmsg rtmsg; 589 int result; 590 int ifindex; 591 592 memset(&rtmsg, 0, sizeof(rtmsg)); 593 594 ifindex = if_nametoindex(ifname); 595 if (ifindex == 0) { 596 printerr("if_nametoindex() failed: interface %s\n", ifname); 597 return -ENXIO; 598 } 599 600 rtmsg.rtmsg_ifindex = ifindex; 601 rtmsg.rtmsg_dst = dst; 602 rtmsg.rtmsg_dst_len = prefix_length; 603 rtmsg.rtmsg_flags = RTF_UP; 604 605 if (prefix_length == 128) { 606 rtmsg.rtmsg_flags |= RTF_HOST; 607 } 608 609 if (memcmp(&gw, &in6addr_any, sizeof(in6addr_any))) { 610 rtmsg.rtmsg_flags |= RTF_GATEWAY; 611 rtmsg.rtmsg_gateway = gw; 612 } 613 614 ifc_init6(); 615 616 if (ifc_ctl_sock6 < 0) { 617 return -errno; 618 } 619 620 result = ioctl(ifc_ctl_sock6, SIOCADDRT, &rtmsg); 621 if (result < 0) { 622 if (errno == EEXIST) { 623 result = 0; 624 } else { 625 result = -errno; 626 } 627 } 628 ifc_close6(); 629 return result; 630} 631 632int ifc_add_route(const char *ifname, const char *dst, int prefix_length, 633 const char *gw) 634{ 635 int ret = 0; 636 struct sockaddr_in ipv4_dst, ipv4_gw; 637 struct sockaddr_in6 ipv6_dst, ipv6_gw; 638 struct addrinfo hints, *addr_ai, *gw_ai; 639 640 memset(&hints, 0, sizeof(hints)); 641 hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ 642 hints.ai_flags = AI_NUMERICHOST; 643 644 ret = getaddrinfo(dst, NULL, &hints, &addr_ai); 645 646 if (ret != 0) { 647 printerr("getaddrinfo failed: invalid address %s\n", dst); 648 return -EINVAL; 649 } 650 651 if (gw == NULL) { 652 if (addr_ai->ai_family == AF_INET6) { 653 gw = "::"; 654 } else if (addr_ai->ai_family == AF_INET) { 655 gw = "0.0.0.0"; 656 } 657 } 658 659 ret = getaddrinfo(gw, NULL, &hints, &gw_ai); 660 if (ret != 0) { 661 printerr("getaddrinfo failed: invalid gateway %s\n", gw); 662 freeaddrinfo(addr_ai); 663 return -EINVAL; 664 } 665 666 if (addr_ai->ai_family != gw_ai->ai_family) { 667 printerr("ifc_add_route: different address families: %s and %s\n", dst, gw); 668 freeaddrinfo(addr_ai); 669 freeaddrinfo(gw_ai); 670 return -EINVAL; 671 } 672 673 if (addr_ai->ai_family == AF_INET6) { 674 memcpy(&ipv6_dst, addr_ai->ai_addr, sizeof(struct sockaddr_in6)); 675 memcpy(&ipv6_gw, gw_ai->ai_addr, sizeof(struct sockaddr_in6)); 676 ret = ifc_add_ipv6_route(ifname, ipv6_dst.sin6_addr, prefix_length, 677 ipv6_gw.sin6_addr); 678 } else if (addr_ai->ai_family == AF_INET) { 679 memcpy(&ipv4_dst, addr_ai->ai_addr, sizeof(struct sockaddr_in)); 680 memcpy(&ipv4_gw, gw_ai->ai_addr, sizeof(struct sockaddr_in)); 681 ret = ifc_add_ipv4_route(ifname, ipv4_dst.sin_addr, prefix_length, 682 ipv4_gw.sin_addr); 683 } else { 684 printerr("ifc_add_route: getaddrinfo returned un supported address family %d\n", 685 addr_ai->ai_family); 686 ret = -EAFNOSUPPORT; 687 } 688 689 freeaddrinfo(addr_ai); 690 freeaddrinfo(gw_ai); 691 return ret; 692} 693