diff options
Diffstat (limited to 'libnetutils')
-rw-r--r-- | libnetutils/dhcp_utils.c | 16 | ||||
-rw-r--r-- | libnetutils/dhcpclient.c | 46 | ||||
-rw-r--r-- | libnetutils/ifc_utils.c | 231 | ||||
-rw-r--r-- | libnetutils/ifc_utils.h | 35 |
4 files changed, 231 insertions, 97 deletions
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c index dc71bab..064eb0c 100644 --- a/libnetutils/dhcp_utils.c +++ b/libnetutils/dhcp_utils.c @@ -116,6 +116,14 @@ static void fill_ip_info(const char *interface, } } +static const char *ipaddr_to_string(in_addr_t addr) +{ + struct in_addr in_addr; + + in_addr.s_addr = addr; + return inet_ntoa(in_addr); +} + /* * Start the dhcp client daemon, and wait for it to finish * configuring the interface. @@ -172,7 +180,13 @@ int dhcp_do_request(const char *interface, return -1; } 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 */ + 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); + property_set(dns_prop_name, *dns2 ? ipaddr_to_string(*dns2) : ""); return 0; } else { snprintf(errmsg, sizeof(errmsg), "DHCP result was %s", prop_value); @@ -286,4 +300,4 @@ int dhcp_do_request_renew(const char *interface, snprintf(errmsg, sizeof(errmsg), "DHCP Renew result was %s", prop_value); return -1; } -}
\ No newline at end of file +} diff --git a/libnetutils/dhcpclient.c b/libnetutils/dhcpclient.c index 6755ba1..ff00432 100644 --- a/libnetutils/dhcpclient.c +++ b/libnetutils/dhcpclient.c @@ -36,8 +36,8 @@ #include <dirent.h> +#include <netutils/ifc.h> #include "dhcpmsg.h" -#include "ifc_utils.h" #include "packet.h" #define VERBOSE 2 @@ -85,16 +85,12 @@ int fatal(const char *reason) // exit(1); } -const char *ipaddr(uint32_t addr) +const char *ipaddr(in_addr_t addr) { - static char buf[32]; - - sprintf(buf,"%d.%d.%d.%d", - addr & 255, - ((addr >> 8) & 255), - ((addr >> 16) & 255), - (addr >> 24)); - return buf; + struct in_addr in_addr; + + in_addr.s_addr = addr; + return inet_ntoa(in_addr); } typedef struct dhcp_info dhcp_info; @@ -128,31 +124,11 @@ void get_dhcp_info(uint32_t *ipaddr, uint32_t *gateway, uint32_t *mask, *lease = last_good_info.lease; } -static int ifc_configure(const char *ifname, dhcp_info *info) +static int dhcp_configure(const char *ifname, dhcp_info *info) { - char dns_prop_name[PROPERTY_KEY_MAX]; - - if (ifc_set_addr(ifname, info->ipaddr)) { - printerr("failed to set ipaddr %s: %s\n", ipaddr(info->ipaddr), strerror(errno)); - return -1; - } - if (ifc_set_mask(ifname, info->netmask)) { - printerr("failed to set netmask %s: %s\n", ipaddr(info->netmask), strerror(errno)); - return -1; - } - if (ifc_create_default_route(ifname, info->gateway)) { - printerr("failed to set default route %s: %s\n", ipaddr(info->gateway), strerror(errno)); - return -1; - } - - snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns1", ifname); - property_set(dns_prop_name, info->dns1 ? ipaddr(info->dns1) : ""); - snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns2", ifname); - property_set(dns_prop_name, info->dns2 ? ipaddr(info->dns2) : ""); - last_good_info = *info; - - return 0; + return ifc_configure(ifname, info->ipaddr, info->netmask, info->gateway, + info->dns1, info->dns2); } static const char *dhcp_type_to_name(uint32_t type) @@ -449,7 +425,7 @@ int dhcp_init_ifc(const char *ifname) printerr("timed out\n"); if ( info.type == DHCPOFFER ) { printerr("no acknowledgement from DHCP server\nconfiguring %s with offered parameters\n", ifname); - return ifc_configure(ifname, &info); + return dhcp_configure(ifname, &info); } errno = ETIME; close(s); @@ -530,7 +506,7 @@ int dhcp_init_ifc(const char *ifname) if (info.type == DHCPACK) { printerr("configuring %s\n", ifname); close(s); - return ifc_configure(ifname, &info); + return dhcp_configure(ifname, &info); } else if (info.type == DHCPNAK) { printerr("configuration request denied\n"); close(s); diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c index bde336f..0ca5fe6 100644 --- a/libnetutils/ifc_utils.c +++ b/libnetutils/ifc_utils.c @@ -27,8 +27,12 @@ #include <arpa/inet.h> #include <linux/if.h> +#include <linux/if_ether.h> +#include <linux/if_arp.h> #include <linux/sockios.h> #include <linux/route.h> +#include <linux/ipv6_route.h> +#include <netdb.h> #include <linux/wireless.h> #ifdef ANDROID @@ -43,9 +47,10 @@ #endif static int ifc_ctl_sock = -1; +static int ifc_ctl_sock6 = -1; void printerr(char *fmt, ...); -static const char *ipaddr_to_string(uint32_t addr) +static const char *ipaddr_to_string(in_addr_t addr) { struct in_addr in_addr; @@ -64,6 +69,17 @@ int ifc_init(void) return ifc_ctl_sock < 0 ? -1 : 0; } +int ifc_init6(void) +{ + if (ifc_ctl_sock6 == -1) { + ifc_ctl_sock6 = socket(AF_INET6, SOCK_DGRAM, 0); + if (ifc_ctl_sock6 < 0) { + printerr("socket() failed: %s\n", strerror(errno)); + } + } + return ifc_ctl_sock6 < 0 ? -1 : 0; +} + void ifc_close(void) { if (ifc_ctl_sock != -1) { @@ -72,6 +88,14 @@ void ifc_close(void) } } +void ifc_close6(void) +{ + if (ifc_ctl_sock6 != -1) { + (void)close(ifc_ctl_sock6); + ifc_ctl_sock6 = -1; + } +} + static void ifc_init_ifr(const char *name, struct ifreq *ifr) { memset(ifr, 0, sizeof(struct ifreq)); @@ -88,7 +112,7 @@ int ifc_get_hwaddr(const char *name, void *ptr) r = ioctl(ifc_ctl_sock, SIOCGIFHWADDR, &ifr); if(r < 0) return -1; - memcpy(ptr, &ifr.ifr_hwaddr.sa_data, 6); + memcpy(ptr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN); return 0; } @@ -143,6 +167,17 @@ int ifc_set_addr(const char *name, in_addr_t addr) return ioctl(ifc_ctl_sock, SIOCSIFADDR, &ifr); } +int ifc_set_hwaddr(const char *name, const void *ptr) +{ + int r; + struct ifreq ifr; + ifc_init_ifr(name, &ifr); + + ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; + memcpy(&ifr.ifr_hwaddr.sa_data, ptr, ETH_ALEN); + return ioctl(ifc_ctl_sock, SIOCSIFHWADDR, &ifr); +} + int ifc_set_mask(const char *name, in_addr_t mask) { struct ifreq ifr; @@ -185,45 +220,80 @@ int ifc_get_info(const char *name, in_addr_t *addr, in_addr_t *mask, unsigned *f return 0; } - -int ifc_create_default_route(const char *name, in_addr_t addr) +in_addr_t get_ipv4_netmask(int prefix_length) { - struct rtentry rt; + in_addr_t mask = 0; - memset(&rt, 0, sizeof(rt)); - - rt.rt_dst.sa_family = AF_INET; - rt.rt_flags = RTF_UP | RTF_GATEWAY; - rt.rt_dev = (void*) name; - init_sockaddr_in(&rt.rt_genmask, 0); - init_sockaddr_in(&rt.rt_gateway, addr); - - return ioctl(ifc_ctl_sock, SIOCADDRT, &rt); + mask = ~mask << (32 - prefix_length); + mask = htonl(mask); + + return mask; } -int ifc_add_host_route(const char *name, in_addr_t addr) +int ifc_add_ipv4_route(const char *ifname, struct in_addr dst, int prefix_length, + struct in_addr gw) { struct rtentry rt; int result; + in_addr_t netmask; memset(&rt, 0, sizeof(rt)); - + rt.rt_dst.sa_family = AF_INET; - rt.rt_flags = RTF_UP | RTF_HOST; - rt.rt_dev = (void*) name; - init_sockaddr_in(&rt.rt_dst, addr); - init_sockaddr_in(&rt.rt_genmask, 0); - init_sockaddr_in(&rt.rt_gateway, 0); - + rt.rt_dev = (void*) ifname; + + netmask = get_ipv4_netmask(prefix_length); + init_sockaddr_in(&rt.rt_genmask, netmask); + init_sockaddr_in(&rt.rt_dst, dst.s_addr); + rt.rt_flags = RTF_UP; + + if (prefix_length == 32) { + rt.rt_flags |= RTF_HOST; + } + + if (gw.s_addr != 0) { + rt.rt_flags |= RTF_GATEWAY; + init_sockaddr_in(&rt.rt_gateway, gw.s_addr); + } + ifc_init(); + + if (ifc_ctl_sock < 0) { + return -errno; + } + result = ioctl(ifc_ctl_sock, SIOCADDRT, &rt); - if (result < 0 && errno == EEXIST) { - result = 0; + if (result < 0) { + if (errno == EEXIST) { + result = 0; + } else { + result = -errno; + } } ifc_close(); return result; } +int ifc_create_default_route(const char *name, in_addr_t gw) +{ + struct in_addr in_dst, in_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); +} + int ifc_enable(const char *ifname) { int result; @@ -429,10 +499,119 @@ ifc_configure(const char *ifname, ifc_close(); - snprintf(dns_prop_name, sizeof(dns_prop_name), "dhcp.%s.dns1", ifname); + snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns1", ifname); property_set(dns_prop_name, dns1 ? ipaddr_to_string(dns1) : ""); - snprintf(dns_prop_name, sizeof(dns_prop_name), "dhcp.%s.dns2", ifname); + snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns2", ifname); property_set(dns_prop_name, dns2 ? ipaddr_to_string(dns2) : ""); return 0; } + +int ifc_add_ipv6_route(const char *ifname, struct in6_addr dst, int prefix_length, + struct in6_addr gw) +{ + struct in6_rtmsg rtmsg; + int result; + int ifindex; + + memset(&rtmsg, 0, sizeof(rtmsg)); + + ifindex = if_nametoindex(ifname); + if (ifindex == 0) { + printerr("if_nametoindex() failed: interface %s\n", ifname); + return -ENXIO; + } + + rtmsg.rtmsg_ifindex = ifindex; + rtmsg.rtmsg_dst = dst; + rtmsg.rtmsg_dst_len = prefix_length; + rtmsg.rtmsg_flags = RTF_UP; + + if (prefix_length == 128) { + rtmsg.rtmsg_flags |= RTF_HOST; + } + + if (memcmp(&gw, &in6addr_any, sizeof(in6addr_any))) { + rtmsg.rtmsg_flags |= RTF_GATEWAY; + rtmsg.rtmsg_gateway = gw; + } + + ifc_init6(); + + if (ifc_ctl_sock6 < 0) { + return -errno; + } + + result = ioctl(ifc_ctl_sock6, SIOCADDRT, &rtmsg); + if (result < 0) { + if (errno == EEXIST) { + result = 0; + } else { + result = -errno; + } + } + ifc_close6(); + return result; +} + +int ifc_add_route(const char *ifname, const char *dst, int prefix_length, + const char *gw) +{ + int ret = 0; + struct sockaddr_in ipv4_dst, ipv4_gw; + struct sockaddr_in6 ipv6_dst, ipv6_gw; + struct addrinfo hints, *addr_ai, *gw_ai; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_flags = AI_NUMERICHOST; + + ret = getaddrinfo(dst, NULL, &hints, &addr_ai); + + if (ret != 0) { + printerr("getaddrinfo failed: invalid address %s\n", dst); + return -EINVAL; + } + + if (gw == NULL) { + if (addr_ai->ai_family == AF_INET6) { + gw = "::"; + } else if (addr_ai->ai_family == AF_INET) { + gw = "0.0.0.0"; + } + } + + ret = getaddrinfo(gw, NULL, &hints, &gw_ai); + if (ret != 0) { + printerr("getaddrinfo failed: invalid gateway %s\n", gw); + freeaddrinfo(addr_ai); + return -EINVAL; + } + + if (addr_ai->ai_family != gw_ai->ai_family) { + printerr("ifc_add_route: different address families: %s and %s\n", dst, gw); + freeaddrinfo(addr_ai); + freeaddrinfo(gw_ai); + return -EINVAL; + } + + 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); + } 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); + } else { + printerr("ifc_add_route: getaddrinfo returned un supported address family %d\n", + addr_ai->ai_family); + ret = -EAFNOSUPPORT; + } + + freeaddrinfo(addr_ai); + freeaddrinfo(gw_ai); + return ret; +} diff --git a/libnetutils/ifc_utils.h b/libnetutils/ifc_utils.h deleted file mode 100644 index 49b8747..0000000 --- a/libnetutils/ifc_utils.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2008, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _IFC_UTILS_H_ -#define _IFC_UTILS_H_ - -int ifc_init(void); - -int ifc_get_ifindex(const char *name, int *if_indexp); -int ifc_get_hwaddr(const char *name, void *ptr); - -int ifc_up(const char *name); -int ifc_down(const char *name); - -int ifc_set_addr(const char *name, unsigned addr); -int ifc_set_mask(const char *name, unsigned mask); - -int ifc_create_default_route(const char *name, unsigned addr); - -int ifc_get_info(const char *name, unsigned *addr, unsigned *mask, unsigned *flags); - -#endif |