diff options
Diffstat (limited to 'src/inet.c')
-rw-r--r-- | src/inet.c | 662 |
1 files changed, 387 insertions, 275 deletions
@@ -79,7 +79,8 @@ int __connman_inet_modify_address(int cmd, int flags, const char *address, const char *peer, unsigned char prefixlen, - const char *broadcast) + const char *broadcast, + bool is_p2p) { uint8_t request[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)) + @@ -94,8 +95,9 @@ int __connman_inet_modify_address(int cmd, int flags, int sk, err; DBG("cmd %#x flags %#x index %d family %d address %s peer %s " - "prefixlen %hhu broadcast %s", cmd, flags, index, family, - address, peer, prefixlen, broadcast); + "prefixlen %hhu broadcast %s p2p %s", cmd, flags, index, + family, address, peer, prefixlen, broadcast, + is_p2p ? "true" : "false"); if (!address) return -EINVAL; @@ -119,17 +121,11 @@ int __connman_inet_modify_address(int cmd, int flags, ifaddrmsg->ifa_index = index; if (family == AF_INET) { - if (inet_pton(AF_INET, address, &ipv4_addr) < 1) + if (inet_pton(AF_INET, address, &ipv4_addr) != 1) return -1; - if (broadcast) - inet_pton(AF_INET, broadcast, &ipv4_bcast); - else - ipv4_bcast.s_addr = ipv4_addr.s_addr | - htonl(0xfffffffflu >> prefixlen); - if (peer) { - if (inet_pton(AF_INET, peer, &ipv4_dest) < 1) + if (inet_pton(AF_INET, peer, &ipv4_dest) != 1) return -1; err = __connman_inet_rtnl_addattr_l(header, @@ -149,16 +145,27 @@ int __connman_inet_modify_address(int cmd, int flags, if (err < 0) return err; - err = __connman_inet_rtnl_addattr_l(header, - sizeof(request), - IFA_BROADCAST, - &ipv4_bcast, - sizeof(ipv4_bcast)); - if (err < 0) - return err; + /* + * Broadcast address must not be added for P2P / VPN as + * getifaddrs() cannot interpret destination address. + */ + if (!is_p2p) { + if (broadcast) + inet_pton(AF_INET, broadcast, &ipv4_bcast); + else + ipv4_bcast.s_addr = ipv4_addr.s_addr | + htonl(0xfffffffflu >> prefixlen); + err = __connman_inet_rtnl_addattr_l(header, + sizeof(request), + IFA_BROADCAST, + &ipv4_bcast, + sizeof(ipv4_bcast)); + if (err < 0) + return err; + } } else if (family == AF_INET6) { - if (inet_pton(AF_INET6, address, &ipv6_addr) < 1) + if (inet_pton(AF_INET6, address, &ipv6_addr) != 1) return -1; err = __connman_inet_rtnl_addattr_l(header, @@ -261,13 +268,46 @@ char *connman_inet_ifname2addr(const char *name) } #endif +static bool is_addr_unspec(int family, struct sockaddr *addr) +{ + struct sockaddr_in *in4; + struct sockaddr_in6 *in6; + + switch (family) { + case AF_INET: + in4 = (struct sockaddr_in*) addr; + return in4->sin_addr.s_addr == INADDR_ANY; + case AF_INET6: + in6 = (struct sockaddr_in6*) addr; + return IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr); + default: + return false; + } +} + +static bool is_addr_ll(int family, struct sockaddr *addr) +{ + struct sockaddr_in *in4; + struct sockaddr_in6 *in6; + + switch (family) { + case AF_INET: + in4 = (struct sockaddr_in*) addr; + return (in4->sin_addr.s_addr & IN_CLASSB_NET) == + ((in_addr_t) htonl(0xa9fe0000)); + case AF_INET6: + in6 = (struct sockaddr_in6*) addr; + return IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr); + default: + return false; + } +} + bool __connman_inet_is_any_addr(const char *address, int family) { bool ret = false; struct addrinfo hints; struct addrinfo *result = NULL; - struct sockaddr_in6 *in6 = NULL; - struct sockaddr_in *in4 = NULL; if (!address || !*address) goto out; @@ -280,14 +320,7 @@ bool __connman_inet_is_any_addr(const char *address, int family) goto out; if (result) { - if (result->ai_family == AF_INET6) { - in6 = (struct sockaddr_in6*)result->ai_addr; - ret = IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr); - } else if (result->ai_family == AF_INET) { - in4 = (struct sockaddr_in*)result->ai_addr; - ret = in4->sin_addr.s_addr == INADDR_ANY; - } - + ret = is_addr_unspec(result->ai_family, result->ai_addr); freeaddrinfo(result); } @@ -521,18 +554,20 @@ int connman_inet_set_ipv6_address(int index, int err; unsigned char prefix_len; const char *address; + bool is_p2p; if (!ipaddress->local) return 0; prefix_len = ipaddress->prefixlen; address = ipaddress->local; + is_p2p = ipaddress->is_p2p; DBG("index %d address %s prefix_len %d", index, address, prefix_len); err = __connman_inet_modify_address(RTM_NEWADDR, NLM_F_REPLACE | NLM_F_ACK, index, AF_INET6, - address, NULL, prefix_len, NULL); + address, NULL, prefix_len, NULL, is_p2p); if (err < 0) { connman_error("%s: %s", __func__, strerror(-err)); return err; @@ -546,6 +581,7 @@ int connman_inet_set_address(int index, struct connman_ipaddress *ipaddress) int err; unsigned char prefix_len; const char *address, *broadcast, *peer; + bool is_p2p; if (!ipaddress->local) return -1; @@ -554,12 +590,13 @@ int connman_inet_set_address(int index, struct connman_ipaddress *ipaddress) address = ipaddress->local; broadcast = ipaddress->broadcast; peer = ipaddress->peer; + is_p2p = ipaddress->is_p2p; DBG("index %d address %s prefix_len %d", index, address, prefix_len); err = __connman_inet_modify_address(RTM_NEWADDR, NLM_F_REPLACE | NLM_F_ACK, index, AF_INET, - address, peer, prefix_len, broadcast); + address, peer, prefix_len, broadcast, is_p2p); if (err < 0) { connman_error("%s: %s", __func__, strerror(-err)); return err; @@ -568,10 +605,17 @@ int connman_inet_set_address(int index, struct connman_ipaddress *ipaddress) return 0; } -int connman_inet_clear_ipv6_address(int index, const char *address, - int prefix_len) +int connman_inet_clear_ipv6_address(int index, + struct connman_ipaddress *ipaddress) { int err; + int prefix_len; + const char *address; + bool is_p2p; + + address = ipaddress->local; + prefix_len = ipaddress->prefixlen; + is_p2p = ipaddress->is_p2p; DBG("index %d address %s prefix_len %d", index, address, prefix_len); @@ -579,7 +623,7 @@ int connman_inet_clear_ipv6_address(int index, const char *address, return -EINVAL; err = __connman_inet_modify_address(RTM_DELADDR, 0, index, AF_INET6, - address, NULL, prefix_len, NULL); + address, NULL, prefix_len, NULL, is_p2p); if (err < 0) { connman_error("%s: %s", __func__, strerror(-err)); return err; @@ -593,11 +637,13 @@ int connman_inet_clear_address(int index, struct connman_ipaddress *ipaddress) int err; unsigned char prefix_len; const char *address, *broadcast, *peer; + bool is_p2p; prefix_len = ipaddress->prefixlen; address = ipaddress->local; broadcast = ipaddress->broadcast; peer = ipaddress->peer; + is_p2p = ipaddress->is_p2p; DBG("index %d address %s prefix_len %d peer %s broadcast %s", index, address, prefix_len, peer, broadcast); @@ -606,7 +652,7 @@ int connman_inet_clear_address(int index, struct connman_ipaddress *ipaddress) return -EINVAL; err = __connman_inet_modify_address(RTM_DELADDR, 0, index, AF_INET, - address, peer, prefix_len, broadcast); + address, peer, prefix_len, broadcast, is_p2p); if (err < 0) { connman_error("%s: %s", __func__, strerror(-err)); return err; @@ -773,7 +819,7 @@ int connman_inet_del_ipv6_network_route(int index, const char *host, rt.rtmsg_dst_len = prefix_len; - if (inet_pton(AF_INET6, host, &rt.rtmsg_dst) < 0) { + if (inet_pton(AF_INET6, host, &rt.rtmsg_dst) != 1) { err = -errno; goto out; } @@ -823,7 +869,7 @@ int connman_inet_add_ipv6_network_route(int index, const char *host, rt.rtmsg_dst_len = prefix_len; - if (inet_pton(AF_INET6, host, &rt.rtmsg_dst) < 0) { + if (inet_pton(AF_INET6, host, &rt.rtmsg_dst) != 1) { err = -errno; goto out; } @@ -839,7 +885,7 @@ int connman_inet_add_ipv6_network_route(int index, const char *host, */ if (gateway && !__connman_inet_is_any_addr(gateway, AF_INET6) && - inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway) > 0) + inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway) == 1) rt.rtmsg_flags |= RTF_GATEWAY; rt.rtmsg_metric = 1; @@ -882,7 +928,7 @@ int connman_inet_clear_ipv6_gateway_address(int index, const char *gateway) memset(&rt, 0, sizeof(rt)); - if (inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway) < 0) { + if (inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway) != 1) { err = -errno; goto out; } @@ -1178,54 +1224,161 @@ out: return err; } -bool connman_inet_compare_subnet(int index, const char *host) +#define ADDR_TYPE_MAX 4 + +struct interface_address { + int index; + int family; + bool allow_unspec; + /* Applies only to ADDR_TYPE_IPADDR in ipaddrs */ + bool require_ll; + /* Real types must be in_addr for AF_INET and in6_addr for AF_INET6 */ + void *ipaddrs[ADDR_TYPE_MAX]; +}; + +enum ipaddr_type { + ADDR_TYPE_IPADDR = 0, + ADDR_TYPE_NETMASK, + ADDR_TYPE_BRDADDR, + ADDR_TYPE_DSTADDR +}; + +static int get_interface_addresses(struct interface_address *if_addr) { - struct ifreq ifr; - struct in_addr _host_addr; - in_addr_t host_addr, netmask_addr, if_addr; - struct sockaddr_in *netmask, *addr; - int sk; + struct ifaddrs *ifaddr; + struct ifaddrs *ifa; + struct sockaddr *addrs[ADDR_TYPE_MAX] = { 0 }; + struct sockaddr_in *addr_in; + struct sockaddr_in6 *addr_in6; + char name[IF_NAMESIZE] = { 0 }; + size_t len; + int err = -ENOENT; + int i; - DBG("host %s", host); + if (!if_addr) + return -EINVAL; - if (!host) - return false; + if (!if_indextoname(if_addr->index, name)) + return -EINVAL; - if (inet_aton(host, &_host_addr) == 0) - return false; - host_addr = _host_addr.s_addr; + DBG("index %d interface %s", if_addr->index, name); - sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); - if (sk < 0) - return false; + if (getifaddrs(&ifaddr) < 0) { + connman_error("Cannot get addresses err %d/%s", errno, + strerror(errno)); + return -errno; + } - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_ifindex = index; + for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) { + if (!ifa->ifa_addr) + continue; - if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) { - close(sk); - return false; + if (g_strcmp0(ifa->ifa_name, name) || + ifa->ifa_addr->sa_family != + if_addr->family) + continue; + + + if (if_addr->ipaddrs[ADDR_TYPE_IPADDR]) { + if (!if_addr->allow_unspec && is_addr_unspec( + if_addr->family, + ifa->ifa_addr)) + continue; + + if (if_addr->require_ll && !is_addr_ll(if_addr->family, + ifa->ifa_addr)) + continue; + + addrs[ADDR_TYPE_IPADDR] = ifa->ifa_addr; + } + + if (if_addr->ipaddrs[ADDR_TYPE_NETMASK]) { + if (!if_addr->allow_unspec && is_addr_unspec( + if_addr->family, + ifa->ifa_netmask)) + continue; + + addrs[ADDR_TYPE_NETMASK] = ifa->ifa_netmask; + } + + if (if_addr->ipaddrs[ADDR_TYPE_BRDADDR] && + (ifa->ifa_flags & IFF_BROADCAST)) { + if (!if_addr->allow_unspec && is_addr_unspec( + if_addr->family, + ifa->ifa_ifu.ifu_broadaddr)) + continue; + + addrs[ADDR_TYPE_BRDADDR] = ifa->ifa_ifu.ifu_broadaddr; + } + + if (if_addr->ipaddrs[ADDR_TYPE_DSTADDR] && + (ifa->ifa_flags & IFF_POINTOPOINT)) { + if (!if_addr->allow_unspec && is_addr_unspec( + if_addr->family, + ifa->ifa_ifu.ifu_dstaddr)) + continue; + + addrs[ADDR_TYPE_DSTADDR] = ifa->ifa_ifu.ifu_dstaddr; + } + + err = 0; + + break; } - if (ioctl(sk, SIOCGIFNETMASK, &ifr) < 0) { - close(sk); - return false; + if (err) + goto out; + + for (i = 0; i < ADDR_TYPE_MAX; i++) { + if (!addrs[i]) + continue; + + switch (if_addr->family) { + case AF_INET: + len = sizeof(struct in_addr); + addr_in = (struct sockaddr_in*) addrs[i]; + memcpy(if_addr->ipaddrs[i], &addr_in->sin_addr, len); + break; + case AF_INET6: + len = sizeof(struct in6_addr); + addr_in6 = (struct sockaddr_in6*) addrs[i]; + memcpy(if_addr->ipaddrs[i], &addr_in6->sin6_addr, len); + break; + default: + err = -EINVAL; + break; + } } - netmask = (struct sockaddr_in *)&ifr.ifr_netmask; - netmask_addr = netmask->sin_addr.s_addr; +out: + freeifaddrs(ifaddr); + return err; +} - if (ioctl(sk, SIOCGIFADDR, &ifr) < 0) { - close(sk); +bool connman_inet_compare_subnet(int index, const char *host) +{ + struct interface_address if_addr = { 0 }; + struct in_addr iaddr = { 0 }; + struct in_addr imask = { 0 }; + struct in_addr haddr = { 0 }; + + DBG("host %s", host); + + if (!host) return false; - } - close(sk); + if (inet_pton(AF_INET, host, &haddr) != 1) + return false; - addr = (struct sockaddr_in *)&ifr.ifr_addr; - if_addr = addr->sin_addr.s_addr; + if_addr.index = index; + if_addr.family = AF_INET; + if_addr.ipaddrs[ADDR_TYPE_IPADDR] = &iaddr; + if_addr.ipaddrs[ADDR_TYPE_NETMASK] = &imask; - return ((if_addr & netmask_addr) == (host_addr & netmask_addr)); + if (get_interface_addresses(&if_addr)) + return false; + + return (iaddr.s_addr & imask.s_addr) == (haddr.s_addr & imask.s_addr); } static bool mem_mask_equal(const void *a, const void *b, @@ -1246,47 +1399,23 @@ static bool mem_mask_equal(const void *a, const void *b, bool connman_inet_compare_ipv6_subnet(int index, const char *host) { - struct ifaddrs *ifaddr, *ifa; - bool rv = false; - char name[IF_NAMESIZE]; - struct in6_addr haddr; - - if (inet_pton(AF_INET6, host, &haddr) <= 0) - return false; + struct interface_address addr = { 0 }; + struct in6_addr iaddr = { 0 }; + struct in6_addr imask = { 0 }; + struct in6_addr haddr = { 0 }; - if (!if_indextoname(index, name)) + if (inet_pton(AF_INET6, host, &haddr) != 1) return false; - DBG("index %d interface %s", index, name); + addr.index = index; + addr.family = AF_INET6; + addr.ipaddrs[ADDR_TYPE_IPADDR] = &iaddr; + addr.ipaddrs[ADDR_TYPE_NETMASK] = &imask; - if (getifaddrs(&ifaddr) < 0) { - DBG("Cannot get addresses err %d/%s", errno, strerror(errno)); + if (get_interface_addresses(&addr)) return false; - } - - for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) { - struct sockaddr_in6 *iaddr; - struct sockaddr_in6 *imask; - - if (!ifa->ifa_addr) - continue; - - if (strncmp(ifa->ifa_name, name, IF_NAMESIZE) != 0 || - ifa->ifa_addr->sa_family != AF_INET6) - continue; - - iaddr = (struct sockaddr_in6 *)ifa->ifa_addr; - imask = (struct sockaddr_in6 *)ifa->ifa_netmask; - - rv = mem_mask_equal(&iaddr->sin6_addr, &haddr, - &imask->sin6_addr, - sizeof(haddr)); - goto out; - } -out: - freeifaddrs(ifaddr); - return rv; + return mem_mask_equal(&iaddr, &haddr, &imask, sizeof(haddr)); } int connman_inet_remove_from_bridge(int index, const char *bridge) @@ -2295,98 +2424,156 @@ GSList *__connman_inet_ipv6_get_prefixes(struct nd_router_advert *hdr, return prefixes; } -static int get_dest_addr(int family, int index, char *buf, int len) +int connman_inet_get_dest_addr(int index, char **dest) { - struct ifreq ifr; - void *addr; - int sk; + struct interface_address if_addr = { 0 }; + struct in_addr dstaddr = { 0 }; + char buf[INET_ADDRSTRLEN] = { 0 }; + int err; - sk = socket(family, SOCK_DGRAM | SOCK_CLOEXEC, 0); - if (sk < 0) - return -errno; + if (!dest) + return -EINVAL; - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_ifindex = index; + if_addr.index = index; + if_addr.family = AF_INET; + if_addr.allow_unspec = true; + if_addr.ipaddrs[ADDR_TYPE_DSTADDR] = &dstaddr; - if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) { - DBG("SIOCGIFNAME (%d/%s)", errno, strerror(errno)); - close(sk); - return -errno; - } + err = get_interface_addresses(&if_addr); + if (err) + return err; - if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0) { - DBG("SIOCGIFFLAGS (%d/%s)", errno, strerror(errno)); - close(sk); - return -errno; - } + if (inet_ntop(AF_INET, &dstaddr, buf, INET_ADDRSTRLEN)) + *dest = g_strdup(buf); - if ((ifr.ifr_flags & IFF_POINTOPOINT) == 0) { - close(sk); - errno = EINVAL; - return -errno; - } + DBG("destination %s", *dest); - DBG("index %d %s", index, ifr.ifr_name); + return *dest && **dest ? 0 : -ENOENT; +} - if (ioctl(sk, SIOCGIFDSTADDR, &ifr) < 0) { - connman_error("Get destination address failed (%s)", - strerror(errno)); - close(sk); - return -errno; - } +int connman_inet_ipv6_get_dest_addr(int index, char **dest) +{ + struct interface_address if_addr = { 0 }; + struct in_addr dstaddr = { 0 }; + char buf[INET6_ADDRSTRLEN] = { 0 }; + int err; - close(sk); + if (!dest) + return -EINVAL; - switch (family) { - case AF_INET: - addr = &((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_addr; - break; - case AF_INET6: - addr = &((struct sockaddr_in6 *)&ifr.ifr_dstaddr)->sin6_addr; - break; - default: - errno = EINVAL; - return -errno; - } + if_addr.index = index; + if_addr.family = AF_INET6; + if_addr.allow_unspec = true; + if_addr.ipaddrs[ADDR_TYPE_DSTADDR] = &dstaddr; - if (!inet_ntop(family, addr, buf, len)) { - DBG("error %d/%s", errno, strerror(errno)); - return -errno; - } + err = get_interface_addresses(&if_addr); + if (err) + return err; - return 0; + if (inet_ntop(AF_INET6, &dstaddr, buf, INET6_ADDRSTRLEN)) + *dest = g_strdup(buf); + + DBG("destination %s", *dest); + + return *dest && **dest ? 0 : -ENOENT; } -int connman_inet_get_dest_addr(int index, char **dest) +/* destination is optional */ +int connman_inet_get_route_addresses(int index, char **network, char **netmask, + char **destination) { - char addr[INET_ADDRSTRLEN]; - int ret; + struct interface_address if_addr = { 0 }; + struct in_addr addr = { 0 }; + struct in_addr mask = { 0 }; + struct in_addr dest = { 0 }; + struct in_addr nw_addr = { 0 }; + char buf[INET_ADDRSTRLEN] = { 0 }; + int err; - ret = get_dest_addr(PF_INET, index, addr, INET_ADDRSTRLEN); - if (ret < 0) - return ret; + if (!network || !netmask) + return -EINVAL; - *dest = g_strdup(addr); + if_addr.index = index; + if_addr.family = AF_INET; + if_addr.ipaddrs[ADDR_TYPE_IPADDR] = &addr; + if_addr.ipaddrs[ADDR_TYPE_NETMASK] = &mask; + if_addr.ipaddrs[ADDR_TYPE_DSTADDR] = &dest; - DBG("destination %s", *dest); + err = get_interface_addresses(&if_addr); + if (err) + return err; - return 0; + nw_addr.s_addr = (addr.s_addr & mask.s_addr); + + if (inet_ntop(AF_INET, &nw_addr, buf, INET_ADDRSTRLEN)) + *network = g_strdup(buf); + + memset(&buf, 0, INET_ADDRSTRLEN); + + if (inet_ntop(AF_INET, &mask, buf, INET_ADDRSTRLEN)) + *netmask = g_strdup(buf); + + if (destination) { + memset(&buf, 0, INET_ADDRSTRLEN); + + if (inet_ntop(AF_INET, &dest, buf, INET_ADDRSTRLEN)) + *destination = g_strdup(buf); + } + + DBG("network %s netmask %s destination %s", *network, *netmask, + destination ? *destination : NULL); + + return *network && **network && *netmask && **netmask ? 0 : -ENOENT; } -int connman_inet_ipv6_get_dest_addr(int index, char **dest) +int connman_inet_ipv6_get_route_addresses(int index, char **network, + char **netmask, char **destination) { - char addr[INET6_ADDRSTRLEN]; - int ret; + struct interface_address if_addr = { 0 }; + struct in6_addr addr = { 0 }; + struct in6_addr mask = { 0 }; + struct in6_addr dest = { 0 }; + struct in6_addr nw_addr = { 0 }; + char buf[INET6_ADDRSTRLEN] = { 0 }; + int err; - ret = get_dest_addr(PF_INET6, index, addr, INET6_ADDRSTRLEN); - if (ret < 0) - return ret; + if (!network) + return -EINVAL; - *dest = g_strdup(addr); + if_addr.index = index; + if_addr.family = AF_INET6; + if_addr.ipaddrs[ADDR_TYPE_IPADDR] = &addr; + if_addr.ipaddrs[ADDR_TYPE_NETMASK] = &mask; + if_addr.ipaddrs[ADDR_TYPE_DSTADDR] = &dest; - DBG("destination %s", *dest); + err = get_interface_addresses(&if_addr); + if (err) + return err; - return 0; + ipv6_addr_set(&nw_addr, addr.s6_addr32[0] & mask.s6_addr32[0], + addr.s6_addr32[1] & mask.s6_addr32[1], + addr.s6_addr32[2] & mask.s6_addr32[2], + addr.s6_addr32[3] & mask.s6_addr32[3]); + + if (inet_ntop(AF_INET6, &nw_addr, buf, INET6_ADDRSTRLEN)) + *network = g_strdup(buf); + + memset(&buf, 0, INET6_ADDRSTRLEN); + + if (inet_ntop(AF_INET6, &mask, buf, INET6_ADDRSTRLEN)) + *netmask = g_strdup(buf); + + if (destination) { + memset(&buf, 0, INET6_ADDRSTRLEN); + + if (inet_ntop(AF_INET6, &dest, buf, INET6_ADDRSTRLEN)) + *destination = g_strdup(buf); + } + + DBG("network %s netmask %s destination %s", *network, *netmask, + destination ? *destination : NULL); + + return *network && **network && *netmask && **netmask ? 0 : -ENOENT; } int __connman_inet_rtnl_open(struct __connman_inet_rtnl_handle *rth) @@ -2983,58 +3170,30 @@ bool connman_inet_is_ipv6_supported() return true; } -int __connman_inet_get_interface_address(int index, int family, void *address) +/* + * Omits checking of the gateway matching the actual gateway IP since both + * connmand and vpnd use inet.c, getting the route is via ipconfig and ipconfig + * is different for both. Gateway is left here for possible future use. + * + * Gateway can be NULL and connection.c then assigns 0.0.0.0 address or ::, + * depending on IP family. + */ +bool connman_inet_is_default_route(int family, const char *host, + const char *gateway, const char *netmask) { - struct ifaddrs *ifaddr, *ifa; - int err = -ENOENT; - char name[IF_NAMESIZE]; - - if (!if_indextoname(index, name)) - return -EINVAL; - - DBG("index %d interface %s", index, name); - - if (getifaddrs(&ifaddr) < 0) { - err = -errno; - DBG("Cannot get addresses err %d/%s", err, strerror(-err)); - return err; - } - - for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) { - if (!ifa->ifa_addr) - continue; - - if (strncmp(ifa->ifa_name, name, IF_NAMESIZE) == 0 && - ifa->ifa_addr->sa_family == family) { - if (family == AF_INET) { - struct sockaddr_in *in4 = (struct sockaddr_in *) - ifa->ifa_addr; - if (in4->sin_addr.s_addr == INADDR_ANY) - continue; - memcpy(address, &in4->sin_addr, - sizeof(struct in_addr)); - } else if (family == AF_INET6) { - struct sockaddr_in6 *in6 = - (struct sockaddr_in6 *)ifa->ifa_addr; - if (memcmp(&in6->sin6_addr, &in6addr_any, - sizeof(struct in6_addr)) == 0) - continue; - memcpy(address, &in6->sin6_addr, - sizeof(struct in6_addr)); + return __connman_inet_is_any_addr(host, family) && + __connman_inet_is_any_addr(netmask, family); +} - } else { - err = -EINVAL; - goto out; - } +int __connman_inet_get_interface_address(int index, int family, void *address) +{ + struct interface_address if_addr = { 0 }; - err = 0; - break; - } - } + if_addr.index = index; + if_addr.family = family; + if_addr.ipaddrs[ADDR_TYPE_IPADDR] = address; -out: - freeifaddrs(ifaddr); - return err; + return get_interface_addresses(&if_addr); } int __connman_inet_get_interface_mac_address(int index, uint8_t *mac_address) @@ -3168,7 +3327,7 @@ static int iproute_default_modify(int cmd, uint32_t table_id, int ifindex, ret = inet_pton(family, dst ? dst : gateway, buf); g_free(dst); - if (ret <= 0) + if (ret != 1) return -EINVAL; memset(&rth, 0, sizeof(rth)); @@ -3243,61 +3402,14 @@ int __connman_inet_del_subnet_from_table(uint32_t table_id, int ifindex, int __connman_inet_get_interface_ll_address(int index, int family, void *address) { - struct ifaddrs *ifaddr, *ifa; - int err = -ENOENT; - char name[IF_NAMESIZE]; - - if (!if_indextoname(index, name)) - return -EINVAL; - - DBG("index %d interface %s", index, name); + struct interface_address if_addr = { 0 }; - if (getifaddrs(&ifaddr) < 0) { - err = -errno; - DBG("Cannot get addresses err %d/%s", err, strerror(-err)); - return err; - } + if_addr.index = index; + if_addr.family = family; + if_addr.require_ll = true; + if_addr.ipaddrs[ADDR_TYPE_IPADDR] = address; - for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) { - if (!ifa->ifa_addr) - continue; - - if (strncmp(ifa->ifa_name, name, IF_NAMESIZE) == 0 && - ifa->ifa_addr->sa_family == family) { - if (family == AF_INET) { - struct sockaddr_in *in4 = (struct sockaddr_in *) - ifa->ifa_addr; - if (in4->sin_addr.s_addr == INADDR_ANY) - continue; - if ((in4->sin_addr.s_addr & IN_CLASSB_NET) != - ((in_addr_t) 0xa9fe0000)) - continue; - memcpy(address, &in4->sin_addr, - sizeof(struct in_addr)); - } else if (family == AF_INET6) { - struct sockaddr_in6 *in6 = - (struct sockaddr_in6 *)ifa->ifa_addr; - if (memcmp(&in6->sin6_addr, &in6addr_any, - sizeof(struct in6_addr)) == 0) - continue; - if (!IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) - continue; - - memcpy(address, &in6->sin6_addr, - sizeof(struct in6_addr)); - } else { - err = -EINVAL; - goto out; - } - - err = 0; - break; - } - } - -out: - freeifaddrs(ifaddr); - return err; + return get_interface_addresses(&if_addr); } int __connman_inet_get_address_netmask(int ifindex, @@ -3451,7 +3563,7 @@ static int get_nfs_server_ip(const char *cmdline_file, const char *pnp_file, addrstr[len] = '\0'; err = inet_pton(AF_INET, addrstr, addr); - if (err <= 0) { + if (err != 1) { connman_error("%s: Cannot convert to numeric addr \"%s\"\n", __func__, addrstr); err = -1; |