summaryrefslogtreecommitdiffstats
path: root/libnetutils/ifc_utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnetutils/ifc_utils.c')
-rw-r--r--libnetutils/ifc_utils.c96
1 files changed, 72 insertions, 24 deletions
diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c
index 0ca5fe6..e5c58b9 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,16 +269,6 @@ 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,
struct in_addr gw)
{
@@ -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;
@@ -306,11 +345,20 @@ 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;
}
@@ -328,7 +376,7 @@ int ifc_reset_connections(const char *ifname)
init_sockaddr_in(&ifr.ifr_addr, myaddr);
result = ioctl(ifc_ctl_sock, SIOCKILLADDR, &ifr);
ifc_close();
-
+
return result;
#else
return 0;
@@ -467,7 +515,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 +534,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;
}