summaryrefslogtreecommitdiffstats
path: root/libnetutils
diff options
context:
space:
mode:
Diffstat (limited to 'libnetutils')
-rw-r--r--libnetutils/dhcp_utils.c132
-rw-r--r--libnetutils/dhcpclient.c15
-rw-r--r--libnetutils/ifc_utils.c251
3 files changed, 217 insertions, 181 deletions
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
index 064eb0c..8496725 100644
--- a/libnetutils/dhcp_utils.c
+++ b/libnetutils/dhcp_utils.c
@@ -18,6 +18,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
@@ -28,9 +29,9 @@ static const char DAEMON_NAME[] = "dhcpcd";
static const char DAEMON_PROP_NAME[] = "init.svc.dhcpcd";
static const char HOSTNAME_PROP_NAME[] = "net.hostname";
static const char DHCP_PROP_NAME_PREFIX[] = "dhcp";
-static const char DAEMON_NAME_RENEW[] = "iprenew";
-static const int NAP_TIME = 1; /* wait for 1 second at a time */
+static const int NAP_TIME = 200; /* wait for 200ms at a time */
/* when polling for property values */
+static const char DAEMON_NAME_RENEW[] = "iprenew";
static char errmsg[100];
/*
@@ -42,14 +43,14 @@ static char errmsg[100];
static int wait_for_property(const char *name, const char *desired_value, int maxwait)
{
char value[PROPERTY_VALUE_MAX] = {'\0'};
- int maxnaps = maxwait / NAP_TIME;
+ int maxnaps = (maxwait * 1000) / NAP_TIME;
if (maxnaps < 1) {
maxnaps = 1;
}
while (maxnaps-- > 0) {
- usleep(1000000);
+ usleep(NAP_TIME * 1000);
if (property_get(name, value, NULL)) {
if (desired_value == NULL ||
strcmp(value, desired_value) == 0) {
@@ -60,60 +61,66 @@ static int wait_for_property(const char *name, const char *desired_value, int ma
return -1; /* failure */
}
-static void fill_ip_info(const char *interface,
- in_addr_t *ipaddr,
- in_addr_t *gateway,
- in_addr_t *mask,
- in_addr_t *dns1,
- in_addr_t *dns2,
- in_addr_t *server,
+static int fill_ip_info(const char *interface,
+ char *ipaddr,
+ char *gateway,
+ uint32_t *prefixLength,
+ char *dns1,
+ char *dns2,
+ char *server,
uint32_t *lease)
{
char prop_name[PROPERTY_KEY_MAX];
char prop_value[PROPERTY_VALUE_MAX];
- struct in_addr addr;
- in_addr_t iaddr;
snprintf(prop_name, sizeof(prop_name), "%s.%s.ipaddress", DHCP_PROP_NAME_PREFIX, interface);
- if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
- *ipaddr = addr.s_addr;
- } else {
- *ipaddr = 0;
- }
+ property_get(prop_name, ipaddr, NULL);
+
snprintf(prop_name, sizeof(prop_name), "%s.%s.gateway", DHCP_PROP_NAME_PREFIX, interface);
- if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
- *gateway = addr.s_addr;
- } else {
- *gateway = 0;
+ property_get(prop_name, gateway, NULL);
+
+ snprintf(prop_name, sizeof(prop_name), "%s.%s.server", DHCP_PROP_NAME_PREFIX, interface);
+ property_get(prop_name, server, NULL);
+
+ //TODO: Handle IPv6 when we change system property usage
+ if (strcmp(gateway, "0.0.0.0") == 0) {
+ //DHCP server is our best bet as gateway
+ strncpy(gateway, server, PROPERTY_VALUE_MAX);
}
+
snprintf(prop_name, sizeof(prop_name), "%s.%s.mask", DHCP_PROP_NAME_PREFIX, interface);
- if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
- *mask = addr.s_addr;
- } else {
- *mask = 0;
+ if (property_get(prop_name, prop_value, NULL)) {
+ int p;
+ // this conversion is v4 only, but this dhcp client is v4 only anyway
+ in_addr_t mask = ntohl(inet_addr(prop_value));
+ // Check netmask is a valid IP address. ntohl gives NONE response (all 1's) for
+ // non 255.255.255.255 inputs. if we get that value check if it is legit..
+ if (mask == INADDR_NONE && strcmp(prop_value, "255.255.255.255") != 0) {
+ snprintf(errmsg, sizeof(errmsg), "DHCP gave invalid net mask %s", prop_value);
+ return -1;
+ }
+ for (p = 0; p < 32; p++) {
+ if (mask == 0) break;
+ // check for non-contiguous netmask, e.g., 255.254.255.0
+ if ((mask & 0x80000000) == 0) {
+ snprintf(errmsg, sizeof(errmsg), "DHCP gave invalid net mask %s", prop_value);
+ return -1;
+ }
+ mask = mask << 1;
+ }
+ *prefixLength = p;
}
snprintf(prop_name, sizeof(prop_name), "%s.%s.dns1", DHCP_PROP_NAME_PREFIX, interface);
- if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
- *dns1 = addr.s_addr;
- } else {
- *dns1 = 0;
- }
+ property_get(prop_name, dns1, NULL);
+
snprintf(prop_name, sizeof(prop_name), "%s.%s.dns2", DHCP_PROP_NAME_PREFIX, interface);
- if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
- *dns2 = addr.s_addr;
- } else {
- *dns2 = 0;
- }
- snprintf(prop_name, sizeof(prop_name), "%s.%s.server", DHCP_PROP_NAME_PREFIX, interface);
- if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
- *server = addr.s_addr;
- } else {
- *server = 0;
- }
+ property_get(prop_name, dns2, NULL);
+
snprintf(prop_name, sizeof(prop_name), "%s.%s.leasetime", DHCP_PROP_NAME_PREFIX, interface);
if (property_get(prop_name, prop_value, NULL)) {
*lease = atol(prop_value);
}
+ return 0;
}
static const char *ipaddr_to_string(in_addr_t addr)
@@ -129,12 +136,12 @@ static const char *ipaddr_to_string(in_addr_t addr)
* configuring the interface.
*/
int dhcp_do_request(const char *interface,
- in_addr_t *ipaddr,
- in_addr_t *gateway,
- in_addr_t *mask,
- in_addr_t *dns1,
- in_addr_t *dns2,
- in_addr_t *server,
+ char *ipaddr,
+ char *gateway,
+ uint32_t *prefixLength,
+ char *dns1,
+ char *dns2,
+ char *server,
uint32_t *lease)
{
char result_prop_name[PROPERTY_KEY_MAX];
@@ -181,8 +188,13 @@ int dhcp_do_request(const char *interface,
}
if (strcmp(prop_value, "ok") == 0) {
char dns_prop_name[PROPERTY_KEY_MAX];
- fill_ip_info(interface, ipaddr, gateway, mask, dns1, dns2, server, lease);
- /* copy the dhcp.XXX.dns properties to net.XXX.dns */
+ if (fill_ip_info(interface, ipaddr, gateway, prefixLength, dns1, dns2, server, lease)
+ == -1) {
+ return -1;
+ }
+
+ /* copy dns data to system properties - TODO - remove this after we have async
+ * notification of renewal's */
snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns1", interface);
property_set(dns_prop_name, *dns1 ? ipaddr_to_string(*dns1) : "");
snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns2", interface);
@@ -253,16 +265,15 @@ char *dhcp_get_errmsg() {
}
/**
- * Run WiMAX dhcp renew service.
- * "wimax_renew" service shoud be included in init.rc.
+ * DHCP renewal request
*/
int dhcp_do_request_renew(const char *interface,
- in_addr_t *ipaddr,
- in_addr_t *gateway,
- in_addr_t *mask,
- in_addr_t *dns1,
- in_addr_t *dns2,
- in_addr_t *server,
+ char *ipaddr,
+ char *gateway,
+ uint32_t *prefixLength,
+ char *dns1,
+ char *dns2,
+ char *server,
uint32_t *lease)
{
char result_prop_name[PROPERTY_KEY_MAX];
@@ -294,7 +305,10 @@ int dhcp_do_request_renew(const char *interface,
return -1;
}
if (strcmp(prop_value, "ok") == 0) {
- fill_ip_info(interface, ipaddr, gateway, mask, dns1, dns2, server, lease);
+ if(fill_ip_info(interface, ipaddr, gateway, prefixLength, dns1, dns2, server, lease)
+ == -1) {
+ return -1;
+ }
return 0;
} else {
snprintf(errmsg, sizeof(errmsg), "DHCP Renew result was %s", prop_value);
diff --git a/libnetutils/dhcpclient.c b/libnetutils/dhcpclient.c
index ff00432..5039e26 100644
--- a/libnetutils/dhcpclient.c
+++ b/libnetutils/dhcpclient.c
@@ -93,6 +93,8 @@ const char *ipaddr(in_addr_t addr)
return inet_ntoa(in_addr);
}
+extern int ipv4NetmaskToPrefixLength(in_addr_t mask);
+
typedef struct dhcp_info dhcp_info;
struct dhcp_info {
@@ -100,7 +102,7 @@ struct dhcp_info {
uint32_t ipaddr;
uint32_t gateway;
- uint32_t netmask;
+ uint32_t prefixLength;
uint32_t dns1;
uint32_t dns2;
@@ -111,13 +113,13 @@ struct dhcp_info {
dhcp_info last_good_info;
-void get_dhcp_info(uint32_t *ipaddr, uint32_t *gateway, uint32_t *mask,
+void get_dhcp_info(uint32_t *ipaddr, uint32_t *gateway, uint32_t *prefixLength,
uint32_t *dns1, uint32_t *dns2, uint32_t *server,
uint32_t *lease)
{
*ipaddr = last_good_info.ipaddr;
*gateway = last_good_info.gateway;
- *mask = last_good_info.netmask;
+ *prefixLength = last_good_info.prefixLength;
*dns1 = last_good_info.dns1;
*dns2 = last_good_info.dns2;
*server = last_good_info.serveraddr;
@@ -127,7 +129,7 @@ void get_dhcp_info(uint32_t *ipaddr, uint32_t *gateway, uint32_t *mask,
static int dhcp_configure(const char *ifname, dhcp_info *info)
{
last_good_info = *info;
- return ifc_configure(ifname, info->ipaddr, info->netmask, info->gateway,
+ return ifc_configure(ifname, info->ipaddr, info->prefixLength, info->gateway,
info->dns1, info->dns2);
}
@@ -153,8 +155,7 @@ void dump_dhcp_info(dhcp_info *info)
dhcp_type_to_name(info->type), info->type);
strcpy(addr, ipaddr(info->ipaddr));
strcpy(gway, ipaddr(info->gateway));
- strcpy(mask, ipaddr(info->netmask));
- LOGD("ip %s gw %s mask %s", addr, gway, mask);
+ LOGD("ip %s gw %s prefixLength %d", addr, gway, info->prefixLength);
if (info->dns1) LOGD("dns1: %s", ipaddr(info->dns1));
if (info->dns2) LOGD("dns2: %s", ipaddr(info->dns2));
LOGD("server %s, lease %d seconds",
@@ -196,7 +197,7 @@ int decode_dhcp_msg(dhcp_msg *msg, int len, dhcp_info *info)
}
switch(opt) {
case OPT_SUBNET_MASK:
- if (optlen >= 4) memcpy(&info->netmask, x, 4);
+ if (optlen >= 4) info->prefixLength = ipv4NetmaskToPrefixLength((int)x);
break;
case OPT_GATEWAY:
if (optlen >= 4) memcpy(&info->gateway, x, 4);
diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c
index 0ca5fe6..c9d6ed2 100644
--- a/libnetutils/ifc_utils.c
+++ b/libnetutils/ifc_utils.c
@@ -25,6 +25,7 @@
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <net/if.h>
#include <linux/if.h>
#include <linux/if_ether.h>
@@ -50,6 +51,33 @@ static int ifc_ctl_sock = -1;
static int ifc_ctl_sock6 = -1;
void printerr(char *fmt, ...);
+in_addr_t prefixLengthToIpv4Netmask(int prefix_length)
+{
+ in_addr_t mask = 0;
+
+ // C99 (6.5.7): shifts of 32 bits have undefined results
+ if (prefix_length <= 0 || prefix_length > 32) {
+ return 0;
+ }
+
+ mask = ~mask << (32 - prefix_length);
+ mask = htonl(mask);
+
+ return mask;
+}
+
+int ipv4NetmaskToPrefixLength(in_addr_t mask)
+{
+ mask = ntohl(mask);
+ int prefixLength = 0;
+ uint32_t m = (uint32_t)mask;
+ while (m & 0x80000000) {
+ prefixLength++;
+ m = m << 1;
+ }
+ return prefixLength;
+}
+
static const char *ipaddr_to_string(in_addr_t addr)
{
struct in_addr in_addr;
@@ -126,7 +154,7 @@ int ifc_get_ifindex(const char *name, int *if_indexp)
if(r < 0) return -1;
*if_indexp = ifr.ifr_ifindex;
- return 0;
+ return 0;
}
static int ifc_set_flags(const char *name, unsigned set, unsigned clr)
@@ -163,7 +191,7 @@ int ifc_set_addr(const char *name, in_addr_t addr)
ifc_init_ifr(name, &ifr);
init_sockaddr_in(&ifr.ifr_addr, addr);
-
+
return ioctl(ifc_ctl_sock, SIOCSIFADDR, &ifr);
}
@@ -178,17 +206,37 @@ int ifc_set_hwaddr(const char *name, const void *ptr)
return ioctl(ifc_ctl_sock, SIOCSIFHWADDR, &ifr);
}
-int ifc_set_mask(const char *name, in_addr_t mask)
+int ifc_set_prefixLength(const char *name, int prefixLength)
{
struct ifreq ifr;
+ // TODO - support ipv6
+ if (prefixLength > 32 || prefixLength < 0) return -1;
+ in_addr_t mask = prefixLengthToIpv4Netmask(prefixLength);
ifc_init_ifr(name, &ifr);
init_sockaddr_in(&ifr.ifr_addr, mask);
-
+
return ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &ifr);
}
-int ifc_get_info(const char *name, in_addr_t *addr, in_addr_t *mask, unsigned *flags)
+int ifc_get_addr(const char *name, in_addr_t *addr)
+{
+ struct ifreq ifr;
+ int ret = 0;
+
+ ifc_init_ifr(name, &ifr);
+ if (addr != NULL) {
+ ret = ioctl(ifc_ctl_sock, SIOCGIFADDR, &ifr);
+ if (ret < 0) {
+ *addr = 0;
+ } else {
+ *addr = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
+ }
+ }
+ return ret;
+}
+
+int ifc_get_info(const char *name, in_addr_t *addr, int *prefixLength, unsigned *flags)
{
struct ifreq ifr;
ifc_init_ifr(name, &ifr);
@@ -200,12 +248,13 @@ int ifc_get_info(const char *name, in_addr_t *addr, in_addr_t *mask, unsigned *f
*addr = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
}
}
-
- if (mask != NULL) {
+
+ if (prefixLength != NULL) {
if(ioctl(ifc_ctl_sock, SIOCGIFNETMASK, &ifr) < 0) {
- *mask = 0;
+ *prefixLength = 0;
} else {
- *mask = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
+ *prefixLength = ipv4NetmaskToPrefixLength((int)
+ ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr);
}
}
@@ -220,17 +269,7 @@ int ifc_get_info(const char *name, in_addr_t *addr, in_addr_t *mask, unsigned *f
return 0;
}
-in_addr_t get_ipv4_netmask(int prefix_length)
-{
- in_addr_t mask = 0;
-
- mask = ~mask << (32 - prefix_length);
- mask = htonl(mask);
-
- return mask;
-}
-
-int ifc_add_ipv4_route(const char *ifname, struct in_addr dst, int prefix_length,
+int ifc_act_on_ipv4_route(int action, const char *ifname, struct in_addr dst, int prefix_length,
struct in_addr gw)
{
struct rtentry rt;
@@ -242,7 +281,7 @@ int ifc_add_ipv4_route(const char *ifname, struct in_addr dst, int prefix_length
rt.rt_dst.sa_family = AF_INET;
rt.rt_dev = (void*) ifname;
- netmask = get_ipv4_netmask(prefix_length);
+ netmask = prefixLengthToIpv4Netmask(prefix_length);
init_sockaddr_in(&rt.rt_genmask, netmask);
init_sockaddr_in(&rt.rt_dst, dst.s_addr);
rt.rt_flags = RTF_UP;
@@ -262,7 +301,7 @@ int ifc_add_ipv4_route(const char *ifname, struct in_addr dst, int prefix_length
return -errno;
}
- result = ioctl(ifc_ctl_sock, SIOCADDRT, &rt);
+ result = ioctl(ifc_ctl_sock, action, &rt);
if (result < 0) {
if (errno == EEXIST) {
result = 0;
@@ -281,17 +320,7 @@ int ifc_create_default_route(const char *name, in_addr_t gw)
in_dst.s_addr = 0;
in_gw.s_addr = gw;
- return ifc_add_ipv4_route(name, in_dst, 0, in_gw);
-}
-
-int ifc_add_host_route(const char *name, in_addr_t dst)
-{
- struct in_addr in_dst, in_gw;
-
- in_dst.s_addr = dst;
- in_gw.s_addr = 0;
-
- return ifc_add_ipv4_route(name, in_dst, 32, in_gw);
+ return ifc_act_on_route(SIOCADDRT, name, in_dst, 0, in_gw);
}
int ifc_enable(const char *ifname)
@@ -306,29 +335,65 @@ int ifc_enable(const char *ifname)
int ifc_disable(const char *ifname)
{
+ unsigned addr, count;
int result;
ifc_init();
result = ifc_down(ifname);
+
ifc_set_addr(ifname, 0);
+ for (count=0, addr=1;((addr != 0) && (count < 255)); count++) {
+ if (ifc_get_addr(ifname, &addr) < 0)
+ break;
+ if (addr)
+ ifc_set_addr(ifname, 0);
+ }
+
ifc_close();
return result;
}
-int ifc_reset_connections(const char *ifname)
+#define RESET_IPV4_ADDRESSES 0x01
+#define RESET_IPV6_ADDRESSES 0x02
+#define RESET_ALL_ADDRESSES (RESET_IPV4_ADDRESSES | RESET_IPV6_ADDRESSES)
+
+int ifc_reset_connections(const char *ifname, const int reset_mask)
{
#ifdef HAVE_ANDROID_OS
- int result;
+ int result, success;
in_addr_t myaddr;
struct ifreq ifr;
+ struct in6_ifreq ifr6;
+
+ if (reset_mask & RESET_IPV4_ADDRESSES) {
+ /* IPv4. Clear connections on the IP address. */
+ ifc_init();
+ ifc_get_info(ifname, &myaddr, NULL, NULL);
+ ifc_init_ifr(ifname, &ifr);
+ init_sockaddr_in(&ifr.ifr_addr, myaddr);
+ result = ioctl(ifc_ctl_sock, SIOCKILLADDR, &ifr);
+ ifc_close();
+ } else {
+ result = 0;
+ }
+
+ if (reset_mask & RESET_IPV6_ADDRESSES) {
+ /*
+ * IPv6. On Linux, when an interface goes down it loses all its IPv6
+ * addresses, so we don't know which connections belonged to that interface
+ * So we clear all unused IPv6 connections on the device by specifying an
+ * empty IPv6 address.
+ */
+ ifc_init6();
+ // This implicitly specifies an address of ::, i.e., kill all IPv6 sockets.
+ memset(&ifr6, 0, sizeof(ifr6));
+ success = ioctl(ifc_ctl_sock6, SIOCKILLADDR, &ifr6);
+ if (result == 0) {
+ result = success;
+ }
+ ifc_close6();
+ }
- ifc_init();
- ifc_get_info(ifname, &myaddr, NULL, NULL);
- ifc_init_ifr(ifname, &ifr);
- init_sockaddr_in(&ifr.ifr_addr, myaddr);
- result = ioctl(ifc_ctl_sock, SIOCKILLADDR, &ifr);
- ifc_close();
-
return result;
#else
return 0;
@@ -384,67 +449,6 @@ int ifc_remove_host_routes(const char *name)
}
/*
- * Return the address of the default gateway
- *
- * TODO: factor out common code from this and remove_host_routes()
- * so that we only scan /proc/net/route in one place.
- */
-int ifc_get_default_route(const char *ifname)
-{
- char name[64];
- in_addr_t dest, gway, mask;
- int flags, refcnt, use, metric, mtu, win, irtt;
- int result;
- FILE *fp;
-
- fp = fopen("/proc/net/route", "r");
- if (fp == NULL)
- return 0;
- /* Skip the header line */
- if (fscanf(fp, "%*[^\n]\n") < 0) {
- fclose(fp);
- return 0;
- }
- ifc_init();
- result = 0;
- for (;;) {
- int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n",
- name, &dest, &gway, &flags, &refcnt, &use, &metric, &mask,
- &mtu, &win, &irtt);
- if (nread != 11) {
- break;
- }
- if ((flags & (RTF_UP|RTF_GATEWAY)) == (RTF_UP|RTF_GATEWAY)
- && dest == 0
- && strcmp(ifname, name) == 0) {
- result = gway;
- break;
- }
- }
- fclose(fp);
- ifc_close();
- return result;
-}
-
-/*
- * Sets the specified gateway as the default route for the named interface.
- */
-int ifc_set_default_route(const char *ifname, in_addr_t gateway)
-{
- struct in_addr addr;
- int result;
-
- ifc_init();
- addr.s_addr = gateway;
- if ((result = ifc_create_default_route(ifname, gateway)) < 0) {
- LOGD("failed to add %s as default route for %s: %s",
- inet_ntoa(addr), ifname, strerror(errno));
- }
- ifc_close();
- return result;
-}
-
-/*
* Removes the default route for the named interface.
*/
int ifc_remove_default_route(const char *ifname)
@@ -467,7 +471,7 @@ int ifc_remove_default_route(const char *ifname)
int
ifc_configure(const char *ifname,
in_addr_t address,
- in_addr_t netmask,
+ uint32_t prefixLength,
in_addr_t gateway,
in_addr_t dns1,
in_addr_t dns2) {
@@ -486,8 +490,8 @@ ifc_configure(const char *ifname,
ifc_close();
return -1;
}
- if (ifc_set_mask(ifname, netmask)) {
- printerr("failed to set netmask %s: %s\n", ipaddr_to_string(netmask), strerror(errno));
+ if (ifc_set_prefixLength(ifname, prefixLength)) {
+ printerr("failed to set prefixLength %d: %s\n", prefixLength, strerror(errno));
ifc_close();
return -1;
}
@@ -507,7 +511,7 @@ ifc_configure(const char *ifname,
return 0;
}
-int ifc_add_ipv6_route(const char *ifname, struct in6_addr dst, int prefix_length,
+int ifc_act_on_ipv6_route(int action, const char *ifname, struct in6_addr dst, int prefix_length,
struct in6_addr gw)
{
struct in6_rtmsg rtmsg;
@@ -542,7 +546,7 @@ int ifc_add_ipv6_route(const char *ifname, struct in6_addr dst, int prefix_lengt
return -errno;
}
- result = ioctl(ifc_ctl_sock6, SIOCADDRT, &rtmsg);
+ result = ioctl(ifc_ctl_sock6, action, &rtmsg);
if (result < 0) {
if (errno == EEXIST) {
result = 0;
@@ -554,8 +558,8 @@ int ifc_add_ipv6_route(const char *ifname, struct in6_addr dst, int prefix_lengt
return result;
}
-int ifc_add_route(const char *ifname, const char *dst, int prefix_length,
- const char *gw)
+int ifc_act_on_route(int action, const char *ifname, const char *dst, int prefix_length,
+ const char *gw)
{
int ret = 0;
struct sockaddr_in ipv4_dst, ipv4_gw;
@@ -573,7 +577,7 @@ int ifc_add_route(const char *ifname, const char *dst, int prefix_length,
return -EINVAL;
}
- if (gw == NULL) {
+ if (gw == NULL || (strlen(gw) == 0)) {
if (addr_ai->ai_family == AF_INET6) {
gw = "::";
} else if (addr_ai->ai_family == AF_INET) {
@@ -581,6 +585,13 @@ int ifc_add_route(const char *ifname, const char *dst, int prefix_length,
}
}
+ if (((addr_ai->ai_family == AF_INET6) && (prefix_length < 0 || prefix_length > 128)) ||
+ ((addr_ai->ai_family == AF_INET) && (prefix_length < 0 || prefix_length > 32))) {
+ printerr("ifc_add_route: invalid prefix length");
+ freeaddrinfo(addr_ai);
+ return -EINVAL;
+ }
+
ret = getaddrinfo(gw, NULL, &hints, &gw_ai);
if (ret != 0) {
printerr("getaddrinfo failed: invalid gateway %s\n", gw);
@@ -598,13 +609,13 @@ int ifc_add_route(const char *ifname, const char *dst, int prefix_length,
if (addr_ai->ai_family == AF_INET6) {
memcpy(&ipv6_dst, addr_ai->ai_addr, sizeof(struct sockaddr_in6));
memcpy(&ipv6_gw, gw_ai->ai_addr, sizeof(struct sockaddr_in6));
- ret = ifc_add_ipv6_route(ifname, ipv6_dst.sin6_addr, prefix_length,
- ipv6_gw.sin6_addr);
+ ret = ifc_act_on_ipv6_route(action, ifname, ipv6_dst.sin6_addr,
+ prefix_length, ipv6_gw.sin6_addr);
} else if (addr_ai->ai_family == AF_INET) {
memcpy(&ipv4_dst, addr_ai->ai_addr, sizeof(struct sockaddr_in));
memcpy(&ipv4_gw, gw_ai->ai_addr, sizeof(struct sockaddr_in));
- ret = ifc_add_ipv4_route(ifname, ipv4_dst.sin_addr, prefix_length,
- ipv4_gw.sin_addr);
+ ret = ifc_act_on_ipv4_route(action, ifname, ipv4_dst.sin_addr,
+ prefix_length, ipv4_gw.sin_addr);
} else {
printerr("ifc_add_route: getaddrinfo returned un supported address family %d\n",
addr_ai->ai_family);
@@ -615,3 +626,13 @@ int ifc_add_route(const char *ifname, const char *dst, int prefix_length,
freeaddrinfo(gw_ai);
return ret;
}
+
+int ifc_add_route(const char *ifname, const char *dst, int prefix_length, const char *gw)
+{
+ return ifc_act_on_route(SIOCADDRT, ifname, dst, prefix_length, gw);
+}
+
+int ifc_remove_route(const char *ifname, const char*dst, int prefix_length, const char *gw)
+{
+ return ifc_act_on_route(SIOCDELRT, ifname, dst, prefix_length, gw);
+}