Example #1
0
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;
}