diff options
Diffstat (limited to 'libnetutils/ifc_utils.c')
| -rw-r--r-- | libnetutils/ifc_utils.c | 96 | 
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;      } | 
