Send connman mailing list submissions to connman@lists.01.org To subscribe or unsubscribe via email, send a message with subject or body 'help' to connman-requ...@lists.01.org
You can reach the person managing the list at connman-ow...@lists.01.org When replying, please edit your Subject line so it is more specific than "Re: Contents of connman digest..." Today's Topics: 1. [PATCH 02/15] inet: Add function for detecting a default route (Jussi Laakkonen) 2. [PATCH 00/15] Support SplitRouting on vpnd, drop vpnd route management (Jussi Laakkonen) 3. [PATCH 01/15] connection: Add getter for the phy index of a VPN transport service (Jussi Laakkonen) 4. [PATCH 03/15] inet: Refactor with getifaddrs() and add network route getter function (Jussi Laakkonen) ---------------------------------------------------------------------- Date: Tue, 8 Dec 2020 12:17:48 +0200 From: Jussi Laakkonen <jussi.laakko...@jolla.com> Subject: [PATCH 02/15] inet: Add function for detecting a default route To: connman@lists.01.org Message-ID: <20201208101801.26715-3-jussi.laakko...@jolla.com> Support checking of network route being as default route. If host and netmask are set as INADDR_ANY then the route is a default route. Gateway can be unset (NULL) or pointing directly to the gateway IP. Check for this is, however, omitted because it would need ipconfig to get the set IP for comparison and ipconfig is different for connmand and vpnd. --- include/inet.h | 2 ++ src/inet.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/include/inet.h b/include/inet.h index fdc2155f..5ac9a474 100644 --- a/include/inet.h +++ b/include/inet.h @@ -78,6 +78,8 @@ int connman_inet_ipv6_get_dest_addr(int index, char **dest); int connman_inet_check_ipaddress(const char *host); bool connman_inet_check_hostname(const char *ptr, size_t len); bool connman_inet_is_ipv6_supported(); +bool connman_inet_is_default_route(int family, const char *host, + const char *gateway, const char *netmask); #ifdef __cplusplus } diff --git a/src/inet.c b/src/inet.c index 4c341438..a537db90 100644 --- a/src/inet.c +++ b/src/inet.c @@ -2835,6 +2835,21 @@ bool connman_inet_is_ipv6_supported() return true; } +/* + * 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) +{ + return __connman_inet_is_any_addr(host, family) && + __connman_inet_is_any_addr(netmask, family); +} + int __connman_inet_get_interface_address(int index, int family, void *address) { struct ifaddrs *ifaddr, *ifa; -- 2.20.1 ------------------------------ Date: Tue, 8 Dec 2020 12:17:46 +0200 From: Jussi Laakkonen <jussi.laakko...@jolla.com> Subject: [PATCH 00/15] Support SplitRouting on vpnd, drop vpnd route management To: connman@lists.01.org Message-ID: <20201208101801.26715-1-jussi.laakko...@jolla.com> SplitRouting is a VPN only setting that was managed by connmand and is also saved along the vpn_*/settings. This change exposes SplitRouting value also to vpnd, making it accessible over VPN D-Bus API as well. This allows to control the split routing value also on VPNs that are not connected yet. And being a VPN only value it seems natural to have it controllable over VPN D-Bus API. This does not affect the service moving, but extends it for internal use. In order to make this happen a lot of changes were required. First of all it is required to have synchronization of the value changes between connmand and vpnd. This is achieved by using service specific property changed signals sent always when the value changes, or is being set (e.g., loading the service), on both sides. This will result in vpnd informing about the change twice when the SplitRouting value is changed over VPN D-Bus API. This happens because VPN changes to connmand are propagated using property changed signals and after connmand has processed the SplitRouting signal connmand will notify the value again with a property changed signal to keep vpnd in sync in case of an error, for instance. Since service moving is utilized here for making the SplitRouting value changes on a connected VPN the route checks in plugins/vpn.c is enhanced to handle the routes better. If a VPN that is being set as a split routed does not have any other than the default route a network route will be attempted to be added. If that fails an error is printed and the resulting property changed signal will contain the current, not affected value of SplitRouting But if a VPN has a default route configured it will be prevented for SplitRouted VPNs. Also to make sure that a non-SplitRouted VPN will have a default route set it will be added if missing. And to make this happen inet.c was amended with new functionality to get route addresses. This resulted in some other changes to clean up the code and fix the issue of getifaddrs() not being able to interpret the destination address if the P-t-P connection has broadcast address also set. Combined many different getifaddrs() uses behind one function to have it a multi-purpose function for different uses. The added, inet.c internal get_interface_addresses() uses struct interface_address that allows AF specific addresses to be retrieved to their respective by copying the struct ifaddrs content that matches the given criteria. Also some minor change to service.c was required in order to propagate the SplitRouting value at all times. When loading a service it is imperative to apply the service settings after registering the D-Bus service because otherwise any signals cannot be sent about the loaded settings, if needed. This boils down to the fact that the internal gdbus implementation does not allow signals to be sent if the path given is not registered. Route management is also dropped from vpnd as a separate commit so it may be reverted easily if need arises. This was deemed to be unnecessary and confusing in discussions with Daniel Wagner on the ConnMan mailing list. Jussi Laakkonen (15): connection: Add getter for the phy index of a VPN transport service inet: Add function for detecting a default route inet: Refactor with getifaddrs() and add network route getter function inet: Do not add broadcast address for P2P/VPNs dbus: Report back the return value of g_dbus_send_message() service: Split service move functionality for internal use service: Expose set_split_routing() for internal use service: Add property changed signal for SplitRouting value service: Load and apply service settings after D-Bus registration provider: Add support for managing SplitRouting vpn: Support SplitRouting in D-Bus variables, improve route code vpn-config: Implement function to get boolean from keyfile vpn-provider: Drop route management from vpnd vpn-provider: Support SplitRouting option from connmand doc: Document VPN connection SplitRouting boolean doc/connman-vpn.8.in | 4 - doc/vpn-connection-api.txt | 9 +- include/inet.h | 10 +- include/ipaddress.h | 4 + include/provider.h | 4 + plugins/dundee.c | 2 +- plugins/ofono.c | 4 +- plugins/vpn.c | 228 +++++++++++-- src/bridge.c | 3 +- src/connection.c | 23 ++ src/connman.h | 10 +- src/dbus.c | 24 +- src/inet.c | 642 ++++++++++++++++++++++--------------- src/ipaddress.c | 10 + src/ipconfig.c | 42 ++- src/peer.c | 2 +- src/provider.c | 101 ++++++ src/service.c | 113 +++++-- src/tethering.c | 3 +- vpn/main.c | 5 +- vpn/plugins/l2tp.c | 2 + vpn/plugins/openconnect.c | 2 + vpn/plugins/openvpn.c | 1 + vpn/plugins/pptp.c | 1 + vpn/plugins/vpnc.c | 1 + vpn/plugins/wireguard.c | 2 + vpn/vpn-config.c | 15 + vpn/vpn-ipconfig.c | 8 +- vpn/vpn-provider.c | 276 +++++++++------- vpn/vpn-provider.h | 3 + vpn/vpn.h | 12 +- 31 files changed, 1096 insertions(+), 470 deletions(-) -- 2.20.1 ------------------------------ Date: Tue, 8 Dec 2020 12:17:47 +0200 From: Jussi Laakkonen <jussi.laakko...@jolla.com> Subject: [PATCH 01/15] connection: Add getter for the phy index of a VPN transport service To: connman@lists.01.org Message-ID: <20201208101801.26715-2-jussi.laakko...@jolla.com> Use same approach as in __connman_connection_get_vpn_index() to get the exact opposite, the physical index of the transport medium used to connect the VPN with the given index. --- src/connection.c | 23 +++++++++++++++++++++++ src/connman.h | 1 + 2 files changed, 24 insertions(+) diff --git a/src/connection.c b/src/connection.c index 303e9922..9d2c6961 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1066,6 +1066,29 @@ int __connman_connection_get_vpn_index(int phy_index) return -1; } +int __connman_connection_get_vpn_phy_index(int vpn_index) +{ + GHashTableIter iter; + gpointer value, key; + + g_hash_table_iter_init(&iter, gateway_hash); + + while (g_hash_table_iter_next(&iter, &key, &value)) { + struct gateway_data *data = value; + + if (data->index != vpn_index) + continue; + + if (data->ipv4_gateway) + return data->ipv4_gateway->vpn_phy_index; + + if (data->ipv6_gateway) + return data->ipv6_gateway->vpn_phy_index; + } + + return -1; +} + int __connman_connection_init(void) { int err; diff --git a/src/connman.h b/src/connman.h index 3bdc0dc7..560ef46c 100644 --- a/src/connman.h +++ b/src/connman.h @@ -502,6 +502,7 @@ int __connman_connection_gateway_add(struct connman_service *service, void __connman_connection_gateway_remove(struct connman_service *service, enum connman_ipconfig_type type); int __connman_connection_get_vpn_index(int phy_index); +int __connman_connection_get_vpn_phy_index(int vpn_index); bool __connman_connection_update_gateway(void); -- 2.20.1 ------------------------------ Date: Tue, 8 Dec 2020 12:17:49 +0200 From: Jussi Laakkonen <jussi.laakko...@jolla.com> Subject: [PATCH 03/15] inet: Refactor with getifaddrs() and add network route getter function To: connman@lists.01.org Message-ID: <20201208101801.26715-4-jussi.laakko...@jolla.com> Create new internal get_interface_addresses() function that utilizes simple structure to get the IP address, netmask, broadcast address and/or P-t-P address using getifaddrs() in a single run. This allows to define whether to accept unspecified addresses (checked with is_addr_unspec()) and to require the IP address to be link local address (checked with is_addr_ll(), in which use htonl() for the constant to get network order for comparison). If the set requirements for unspec/link local are not met, -ENOENT is returned as error and all the pointers in the struct interface_address are NULL. With invalid address family, or missing struct -EINVAL is returned. Or the error of getifaddrs() is returned if the call fails. When get_interface_addressses() is used directly, the pointer array in struct interface_address must have struct in_addr* for AF_INET and struct in6_addr* for AF_INET6 set as family. The types defined in enum ipaddr_type are to be used as a position for the different addresses requested. Cleaned up a lot of existing code to have only one use of getifaddrs() via the get_interface_addresses() by just filling in the structure with the required parameters. Created new functions connman_inet_get_route_addresses() and connman_inet_ipv6_get_route_addresses() for getting the string representation of all the required address for a route. Parameter destination (for P-t-P) is optional. --- include/inet.h | 6 + src/inet.c | 563 ++++++++++++++++++++++++++++--------------------- 2 files changed, 326 insertions(+), 243 deletions(-) diff --git a/include/inet.h b/include/inet.h index 5ac9a474..c76e487d 100644 --- a/include/inet.h +++ b/include/inet.h @@ -81,6 +81,12 @@ bool connman_inet_is_ipv6_supported(); bool connman_inet_is_default_route(int family, const char *host, const char *gateway, const char *netmask); +int connman_inet_get_route_addresses(int index, char **network, char **netmask, + char **destination); +int connman_inet_ipv6_get_route_addresses(int index, char **network, + char **netmask, + char **destination); + #ifdef __cplusplus } #endif diff --git a/src/inet.c b/src/inet.c index a537db90..8cbc3e46 100644 --- a/src/inet.c +++ b/src/inet.c @@ -189,13 +189,46 @@ done: return err; } +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; @@ -208,14 +241,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); } @@ -1066,54 +1092,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) <= 0) + return false; + + if_addr.index = index; + if_addr.family = AF_INET; + if_addr.ipaddrs[ADDR_TYPE_IPADDR] = &iaddr; + if_addr.ipaddrs[ADDR_TYPE_NETMASK] = &imask; - addr = (struct sockaddr_in *)&ifr.ifr_addr; - if_addr = addr->sin_addr.s_addr; + if (get_interface_addresses(&if_addr)) + return false; - return ((if_addr & netmask_addr) == (host_addr & netmask_addr)); + return (iaddr.s_addr & imask.s_addr) == (haddr.s_addr & imask.s_addr); } static bool mem_mask_equal(const void *a, const void *b, @@ -1134,47 +1267,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; + struct interface_address addr = { 0 }; + struct in6_addr iaddr = { 0 }; + struct in6_addr imask = { 0 }; + struct in6_addr haddr = { 0 }; if (inet_pton(AF_INET6, host, &haddr) <= 0) return false; - if (!if_indextoname(index, name)) - 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) @@ -2147,98 +2256,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) @@ -2852,56 +3019,13 @@ bool connman_inet_is_default_route(int family, const char *host, int __connman_inet_get_interface_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); - - if (getifaddrs(&ifaddr) < 0) { - err = -errno; - DBG("Cannot get addresses err %d/%s", err, strerror(-err)); - return err; - } + struct interface_address if_addr = { 0 }; - for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) { - if (!ifa->ifa_addr) - continue; + if_addr.index = index; + if_addr.family = family; + if_addr.ipaddrs[ADDR_TYPE_IPADDR] = address; - 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)); - - } else { - err = -EINVAL; - goto out; - } - - err = 0; - break; - } - } - -out: - freeifaddrs(ifaddr); - return err; + return get_interface_addresses(&if_addr); } int __connman_inet_get_interface_mac_address(int index, uint8_t *mac_address) @@ -3110,61 +3234,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; + struct interface_address if_addr = { 0 }; - DBG("index %d interface %s", index, name); + if_addr.index = index; + if_addr.family = family; + if_addr.require_ll = true; + if_addr.ipaddrs[ADDR_TYPE_IPADDR] = address; - 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; - 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, -- 2.20.1 ------------------------------ Subject: Digest Footer _______________________________________________ connman mailing list -- connman@lists.01.org To unsubscribe send an email to connman-le...@lists.01.org ------------------------------ End of connman Digest, Vol 62, Issue 8 **************************************