int add_route(const char *name, const char *address, int prefix) { int rc = 0; int inet4 = socket(AF_INET, SOCK_DGRAM, 0); struct rtentry rt4; memset(&rt4, 0, sizeof(rt4)); rt4.rt_dev = (char *)name; rt4.rt_flags = RTF_UP; rt4.rt_dst.sa_family = AF_INET; rt4.rt_genmask.sa_family = AF_INET; if (inet_pton(AF_INET, address, as_in_addr(&rt4.rt_dst)) != 1 || prefix < 0 || prefix > 32) { rc = 1; } in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0x80000000; *as_in_addr(&rt4.rt_genmask) = htonl(mask); if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) { rc = 1; } if (!prefix) { // Split the route instead of replacing the default route. *as_in_addr(&rt4.rt_dst) ^= htonl(0x80000000); if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) { rc = 1; } } close(inet4); return rc; }
static int set_routes(const char *name, const char *routes) { int index = get_interface_index(name); if (index < 0) { return index; } rtentry rt4; memset(&rt4, 0, sizeof(rt4)); rt4.rt_dev = (char *)name; rt4.rt_flags = RTF_UP; rt4.rt_dst.sa_family = AF_INET; rt4.rt_genmask.sa_family = AF_INET; in6_rtmsg rt6; memset(&rt6, 0, sizeof(rt6)); rt6.rtmsg_ifindex = index; rt6.rtmsg_flags = RTF_UP; char address[65]; int prefix; int chars; int count = 0; while (sscanf(routes, " %64[^/]/%d %n", address, &prefix, &chars) == 2) { routes += chars; if (strchr(address, ':')) { // Add an IPv6 route. if (inet_pton(AF_INET6, address, &rt6.rtmsg_dst) != 1 || prefix < 0 || prefix > 128) { count = BAD_ARGUMENT; break; } rt6.rtmsg_dst_len = prefix ? prefix : 1; if (ioctl(inet6, SIOCADDRT, &rt6) && errno != EEXIST) { count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR; break; } if (!prefix) { // Split the route instead of replacing the default route. rt6.rtmsg_dst.s6_addr[0] ^= 0x80; if (ioctl(inet6, SIOCADDRT, &rt6) && errno != EEXIST) { count = SYSTEM_ERROR; break; } } } else { // Add an IPv4 route. if (inet_pton(AF_INET, address, as_in_addr(&rt4.rt_dst)) != 1 || prefix < 0 || prefix > 32) { count = BAD_ARGUMENT; break; } in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0x80000000; *as_in_addr(&rt4.rt_genmask) = htonl(mask); if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) { count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR; break; } if (!prefix) { // Split the route instead of replacing the default route. *as_in_addr(&rt4.rt_dst) ^= htonl(0x80000000); if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) { count = SYSTEM_ERROR; break; } } } ALOGD("Route added on %s: %s/%d", name, address, prefix); ++count; } if (count == BAD_ARGUMENT) { ALOGE("Invalid route: %s/%d", address, prefix); } else if (count == SYSTEM_ERROR) { ALOGE("Cannot add route: %s/%d: %s", address, prefix, strerror(errno)); } else if (*routes) { ALOGE("Invalid route: %s", routes); count = BAD_ARGUMENT; } return count; }
static int set_addresses(const char *name, const char *addresses) { int index = get_interface_index(name); if (index < 0) { return index; } ifreq ifr4; memset(&ifr4, 0, sizeof(ifr4)); strncpy(ifr4.ifr_name, name, IFNAMSIZ); ifr4.ifr_addr.sa_family = AF_INET; ifr4.ifr_netmask.sa_family = AF_INET; in6_ifreq ifr6; memset(&ifr6, 0, sizeof(ifr6)); ifr6.ifr6_ifindex = index; char address[65]; int prefix; int chars; int count = 0; while (sscanf(addresses, " %64[^/]/%d %n", address, &prefix, &chars) == 2) { addresses += chars; if (strchr(address, ':')) { // Add an IPv6 address. if (inet_pton(AF_INET6, address, &ifr6.ifr6_addr) != 1 || prefix < 0 || prefix > 128) { count = BAD_ARGUMENT; break; } ifr6.ifr6_prefixlen = prefix; if (ioctl(inet6, SIOCSIFADDR, &ifr6)) { count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR; break; } } else { // Add an IPv4 address. if (inet_pton(AF_INET, address, as_in_addr(&ifr4.ifr_addr)) != 1 || prefix < 0 || prefix > 32) { count = BAD_ARGUMENT; break; } if (count) { sprintf(ifr4.ifr_name, "%s:%d", name, count); } if (ioctl(inet4, SIOCSIFADDR, &ifr4)) { count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR; break; } in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0; *as_in_addr(&ifr4.ifr_netmask) = htonl(mask); if (ioctl(inet4, SIOCSIFNETMASK, &ifr4)) { count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR; break; } } ALOGD("Address added on %s: %s/%d", name, address, prefix); ++count; } if (count == BAD_ARGUMENT) { ALOGE("Invalid address: %s/%d", address, prefix); } else if (count == SYSTEM_ERROR) { ALOGE("Cannot add address: %s/%d: %s", address, prefix, strerror(errno)); } else if (*addresses) { ALOGE("Invalid address: %s", addresses); count = BAD_ARGUMENT; } return count; }