From 7eb51cba2c747a3ee7a6d1e7c25632468213b76c Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Sun, 24 Feb 2013 15:35:25 +0100 Subject: Workaround to add IPv6 support to getifaddrs ifreq only contains sockaddr structures, which are not big enough for IPv6 addresses. This takes another, ugly, approach, by parsing fsysopts /servers/socket/2 options... --- .topdeps | 2 +- .topmsg | 20 +-- sysdeps/mach/hurd/ifaddrs.c | 295 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 302 insertions(+), 15 deletions(-) create mode 100644 sysdeps/mach/hurd/ifaddrs.c diff --git a/.topdeps b/.topdeps index cd7d38c927..180b47c18b 100644 --- a/.topdeps +++ b/.topdeps @@ -1 +1 @@ -fbeafedeea37e0af1984a6511018d159f5ceed6a +baseline diff --git a/.topmsg b/.topmsg index dd6634c886..2b9a564d64 100644 --- a/.topmsg +++ b/.topmsg @@ -1,16 +1,8 @@ -Subject: Baseline for our topic branches. +From: Samuel Thibault +Subject: [PATCH] Workaround to add IPv6 support to getifaddrs ---- +ifreq only contains sockaddr structures, which are not big enough for +IPv6 addresses. This takes another, ugly, approach, by parsing fsysopts +/servers/socket/2 options... -This need not strictly be a TopGit branch, but it is for easy synchronization -between different machines. - -As the baseline is merged into the topic branches, it is forward-only. - -To advance it: - - $ echo [SHA1] > .topdeps - $ git commit -m Advance. -- .topdeps - $ tg update - ---- +Signed-off-by: Samuel Thibault diff --git a/sysdeps/mach/hurd/ifaddrs.c b/sysdeps/mach/hurd/ifaddrs.c new file mode 100644 index 0000000000..31ec85c29e --- /dev/null +++ b/sysdeps/mach/hurd/ifaddrs.c @@ -0,0 +1,295 @@ +/* getifaddrs -- get names and addresses of all network interfaces + Copyright (C) 2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Create a linked list of `struct ifaddrs' structures, one for each + network interface on the host machine. If successful, store the + list in *IFAP and return 0. On errors, return -1 and set `errno'. */ +int +getifaddrs (struct ifaddrs **ifap) +{ + /* XXX: Hackish. This assumes pfinet parameter style, and that the same + pfinet is on /servers/socket/2 and /servers/socket/26. + + To be replaced by something like a netlink protocol, or fix ifreq into + using sockaddr_storage (but break existing compiled programs using it). */ + + file_t node; + char *argz = 0, *cur; + size_t argz_len = 0; + unsigned naddrs; + const char *ifa_name = NULL; + char *addr, *cidr_a; + int cidr; + + node = __file_name_lookup (_SERVERS_SOCKET "/2", 0, 0666); + + if (node == MACH_PORT_NULL) + return -1; + + __file_get_fs_options (node, &argz, &argz_len); + + __mach_port_deallocate (__mach_task_self (), node); + + /* XXX: Two hardcoded for lo */ + naddrs = 2; + + for (cur = argz; cur < argz + argz_len; cur = cur + strlen (cur) + 1) + { + if (!strncmp (cur, "--address=", 10)) + naddrs++; + else if (!strncmp (cur, "--address6=", 11)) + naddrs++; + } + + { + struct + { + struct ifaddrs ia; + struct sockaddr_storage addr, netmask, broadaddr; + char name[IF_NAMESIZE]; + } *storage; + int i; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + + storage = malloc (naddrs * sizeof storage[0]); + if (storage == NULL) + { + __munmap (argz, argz_len); + return -1; + } + + i = 0; + + /* XXX: Hardcoded lo interface */ + ifa_name = "lo"; + + /* 127.0.0.1/8 */ + storage[i].ia.ifa_next = &storage[i + 1].ia; + storage[i].ia.ifa_name = strncpy (storage[i].name, ifa_name, sizeof (storage[i].name)); + + storage[i].ia.ifa_addr = (struct sockaddr *) &storage[i].addr; + sin = ((struct sockaddr_in *) &storage[i].addr); + sin->sin_family = AF_INET; + sin->sin_port = 0; + sin->sin_addr.s_addr = htonl (INADDR_LOOPBACK); + + storage[i].ia.ifa_netmask = (struct sockaddr *) &storage[i].netmask; + sin = ((struct sockaddr_in *) &storage[i].netmask); + sin->sin_family = AF_INET; + sin->sin_port = 0; + sin->sin_addr.s_addr = htonl (IN_CLASSA_NET); + + storage[i].ia.ifa_broadaddr = (struct sockaddr *) &storage[i].addr; + + storage[i].ia.ifa_flags = IFF_UP | IFF_LOOPBACK | IFF_RUNNING; + + storage[i].ia.ifa_data = NULL; /* Nothing here for now. */ + + i++; + + /* ::1/128 */ + storage[i].ia.ifa_next = &storage[i + 1].ia; + storage[i].ia.ifa_name = strncpy (storage[i].name, ifa_name, sizeof (storage[i].name)); + + storage[i].ia.ifa_addr = (struct sockaddr *) &storage[i].addr; + sin6 = ((struct sockaddr_in6 *) &storage[i].addr); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = 0; + sin6->sin6_flowinfo = 0; + inet_pton (AF_INET6, "::1", &sin6->sin6_addr); + sin6->sin6_scope_id = 0; + + storage[i].ia.ifa_netmask = (struct sockaddr *) &storage[i].netmask; + sin6 = ((struct sockaddr_in6 *) &storage[i].netmask); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = 0; + sin6->sin6_flowinfo = 0; + inet_pton (AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", &sin6->sin6_addr); + sin6->sin6_scope_id = 0; + + storage[i].ia.ifa_broadaddr = NULL; + + storage[i].ia.ifa_flags = IFF_UP | IFF_LOOPBACK | IFF_RUNNING; + + storage[i].ia.ifa_data = NULL; /* Nothing here for now. */ + + for (cur = argz; cur < argz + argz_len; cur = cur + strlen (cur) + 1) + { + if (!strncmp (cur, "--interface=", 12)) + { + ifa_name = cur + 12; + continue; + } + + else if (!strncmp (cur, "--address=", 10)) + { + i++; + /* IPv4 address */ + addr = cur + 10; + + storage[i].ia.ifa_next = &storage[i + 1].ia; + storage[i].ia.ifa_name = strncpy (storage[i].name, ifa_name, sizeof (storage[i].name)); + + storage[i].ia.ifa_addr = (struct sockaddr *) &storage[i].addr; + sin = ((struct sockaddr_in *) &storage[i].addr); + sin->sin_family = AF_INET; + sin->sin_port = 0; + inet_pton (AF_INET, addr, &sin->sin_addr); + + storage[i].ia.ifa_netmask = NULL; + storage[i].ia.ifa_broadaddr = NULL; + + storage[i].ia.ifa_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_MULTICAST; + storage[i].ia.ifa_data = NULL; /* Nothing here for now. */ + } + + else if (!strncmp (cur, "--netmask=", 10)) + { + /* IPv4 netmask */ + addr = cur + 10; + + storage[i].ia.ifa_netmask = (struct sockaddr *) &storage[i].netmask; + sin = ((struct sockaddr_in *) &storage[i].netmask); + sin->sin_family = AF_INET; + sin->sin_port = 0; + inet_pton (AF_INET, addr, &sin->sin_addr); + + storage[i].ia.ifa_broadaddr = (struct sockaddr *) &storage[i].broadaddr; + sin = ((struct sockaddr_in *) &storage[i].broadaddr); + sin->sin_family = AF_INET; + sin->sin_port = 0; + sin->sin_addr.s_addr = + ((struct sockaddr_in *) &storage[i].addr)->sin_addr.s_addr + | ~(((struct sockaddr_in *) &storage[i].netmask)->sin_addr.s_addr); + } + + else if (!strncmp (cur, "--peer=", 7)) + { + /* IPv4 peer */ + addr = cur + 7; + + storage[i].ia.ifa_dstaddr = (struct sockaddr *) &storage[i].broadaddr; + sin = ((struct sockaddr_in *) &storage[i].broadaddr); + sin->sin_family = AF_INET; + sin->sin_port = 0; + inet_pton (AF_INET, addr, &sin->sin_addr); + + storage[i].ia.ifa_flags &= ~IFF_BROADCAST; + storage[i].ia.ifa_flags |= IFF_POINTOPOINT; + } + + else if (!strncmp (cur, "--address6=", 11)) + { + i++; + /* IPv6 address */ + addr = cur + 11; + cidr_a = strchr (addr, '/'); + if (!cidr_a) + { + /* No CIDR length?! Assume 64. */ + addr = strdup (addr); + cidr = 64; + } + else + { + addr = strndup (addr, cidr_a - addr); + cidr = atoi (cidr_a + 1); + } + + storage[i].ia.ifa_next = &storage[i + 1].ia; + storage[i].ia.ifa_name = strncpy (storage[i].name, ifa_name, sizeof (storage[i].name)); + + storage[i].ia.ifa_addr = (struct sockaddr *) &storage[i].addr; + sin6 = ((struct sockaddr_in6 *) &storage[i].addr); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = 0; + sin6->sin6_flowinfo = 0; + inet_pton (AF_INET6, addr, &sin6->sin6_addr); + sin6->sin6_scope_id = 0; + + storage[i].ia.ifa_netmask = (struct sockaddr *) &storage[i].netmask; + sin6 = ((struct sockaddr_in6 *) &storage[i].netmask); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = 0; + sin6->sin6_flowinfo = 0; + sin6->sin6_addr.s6_addr32[0] = htonl (cidr >= 32 ? 0xffffffffUL : cidr <= 0 ? 0 : ~((1UL << ( 32 - cidr)) - 1)); + sin6->sin6_addr.s6_addr32[1] = htonl (cidr >= 64 ? 0xffffffffUL : cidr <= 32 ? 0 : ~((1UL << ( 64 - cidr)) - 1)); + sin6->sin6_addr.s6_addr32[2] = htonl (cidr >= 96 ? 0xffffffffUL : cidr <= 64 ? 0 : ~((1UL << ( 96 - cidr)) - 1)); + sin6->sin6_addr.s6_addr32[3] = htonl (cidr >= 128 ? 0xffffffffUL : cidr <= 96 ? 0 : ~((1UL << (128 - cidr)) - 1)); + sin6->sin6_scope_id = 0; + + storage[i].ia.ifa_broadaddr = NULL; + storage[i].ia.ifa_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_MULTICAST; + storage[i].ia.ifa_data = NULL; /* Nothing here for now. */ + free (addr); + } + + else if (!strncmp (cur, "--peer6=", 8)) + { + /* IPv6 peer */ + addr = cur + 8; + + storage[i].ia.ifa_dstaddr = (struct sockaddr *) &storage[i].broadaddr; + sin6 = ((struct sockaddr_in6 *) &storage[i].broadaddr); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = 0; + sin6->sin6_flowinfo = 0; + inet_pton (AF_INET6, addr, &sin6->sin6_addr); + sin6->sin6_scope_id = 0; + + storage[i].ia.ifa_flags &= ~IFF_BROADCAST; + storage[i].ia.ifa_flags |= IFF_POINTOPOINT; + } + } + + storage[i].ia.ifa_next = NULL; + + *ifap = &storage[0].ia; + } + + __munmap (argz, argz_len); + + return 0; +} +#ifndef getifaddrs +libc_hidden_def (getifaddrs) +#endif + +void +freeifaddrs (struct ifaddrs *ifa) +{ + free (ifa); +} +libc_hidden_def (freeifaddrs) -- cgit v1.2.3 From 1d55673fff6b6cdaa6e48eb8f1ebf9a2ef6abcf8 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Thu, 30 Jan 2014 04:46:00 +0100 Subject: Also initialize sa_len --- sysdeps/mach/hurd/ifaddrs.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sysdeps/mach/hurd/ifaddrs.c b/sysdeps/mach/hurd/ifaddrs.c index 31ec85c29e..4afc749464 100644 --- a/sysdeps/mach/hurd/ifaddrs.c +++ b/sysdeps/mach/hurd/ifaddrs.c @@ -102,12 +102,14 @@ getifaddrs (struct ifaddrs **ifap) storage[i].ia.ifa_addr = (struct sockaddr *) &storage[i].addr; sin = ((struct sockaddr_in *) &storage[i].addr); sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); sin->sin_port = 0; sin->sin_addr.s_addr = htonl (INADDR_LOOPBACK); storage[i].ia.ifa_netmask = (struct sockaddr *) &storage[i].netmask; sin = ((struct sockaddr_in *) &storage[i].netmask); sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); sin->sin_port = 0; sin->sin_addr.s_addr = htonl (IN_CLASSA_NET); @@ -126,6 +128,7 @@ getifaddrs (struct ifaddrs **ifap) storage[i].ia.ifa_addr = (struct sockaddr *) &storage[i].addr; sin6 = ((struct sockaddr_in6 *) &storage[i].addr); sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(*sin6); sin6->sin6_port = 0; sin6->sin6_flowinfo = 0; inet_pton (AF_INET6, "::1", &sin6->sin6_addr); @@ -134,6 +137,7 @@ getifaddrs (struct ifaddrs **ifap) storage[i].ia.ifa_netmask = (struct sockaddr *) &storage[i].netmask; sin6 = ((struct sockaddr_in6 *) &storage[i].netmask); sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(*sin6); sin6->sin6_port = 0; sin6->sin6_flowinfo = 0; inet_pton (AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", &sin6->sin6_addr); @@ -165,6 +169,7 @@ getifaddrs (struct ifaddrs **ifap) storage[i].ia.ifa_addr = (struct sockaddr *) &storage[i].addr; sin = ((struct sockaddr_in *) &storage[i].addr); sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); sin->sin_port = 0; inet_pton (AF_INET, addr, &sin->sin_addr); @@ -183,12 +188,14 @@ getifaddrs (struct ifaddrs **ifap) storage[i].ia.ifa_netmask = (struct sockaddr *) &storage[i].netmask; sin = ((struct sockaddr_in *) &storage[i].netmask); sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); sin->sin_port = 0; inet_pton (AF_INET, addr, &sin->sin_addr); storage[i].ia.ifa_broadaddr = (struct sockaddr *) &storage[i].broadaddr; sin = ((struct sockaddr_in *) &storage[i].broadaddr); sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); sin->sin_port = 0; sin->sin_addr.s_addr = ((struct sockaddr_in *) &storage[i].addr)->sin_addr.s_addr @@ -203,6 +210,7 @@ getifaddrs (struct ifaddrs **ifap) storage[i].ia.ifa_dstaddr = (struct sockaddr *) &storage[i].broadaddr; sin = ((struct sockaddr_in *) &storage[i].broadaddr); sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); sin->sin_port = 0; inet_pton (AF_INET, addr, &sin->sin_addr); @@ -234,6 +242,7 @@ getifaddrs (struct ifaddrs **ifap) storage[i].ia.ifa_addr = (struct sockaddr *) &storage[i].addr; sin6 = ((struct sockaddr_in6 *) &storage[i].addr); sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(*sin6); sin6->sin6_port = 0; sin6->sin6_flowinfo = 0; inet_pton (AF_INET6, addr, &sin6->sin6_addr); @@ -242,6 +251,7 @@ getifaddrs (struct ifaddrs **ifap) storage[i].ia.ifa_netmask = (struct sockaddr *) &storage[i].netmask; sin6 = ((struct sockaddr_in6 *) &storage[i].netmask); sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(*sin6); sin6->sin6_port = 0; sin6->sin6_flowinfo = 0; sin6->sin6_addr.s6_addr32[0] = htonl (cidr >= 32 ? 0xffffffffUL : cidr <= 0 ? 0 : ~((1UL << ( 32 - cidr)) - 1)); @@ -264,6 +274,7 @@ getifaddrs (struct ifaddrs **ifap) storage[i].ia.ifa_dstaddr = (struct sockaddr *) &storage[i].broadaddr; sin6 = ((struct sockaddr_in6 *) &storage[i].broadaddr); sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(*sin6); sin6->sin6_port = 0; sin6->sin6_flowinfo = 0; inet_pton (AF_INET6, addr, &sin6->sin6_addr); -- cgit v1.2.3 From 2bfa087aa11717761246f52b96c50454c3e4004e Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Tue, 3 Feb 2015 00:42:01 +0100 Subject: Update copyright years --- sysdeps/mach/hurd/ifaddrs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sysdeps/mach/hurd/ifaddrs.c b/sysdeps/mach/hurd/ifaddrs.c index 4afc749464..d2f8978673 100644 --- a/sysdeps/mach/hurd/ifaddrs.c +++ b/sysdeps/mach/hurd/ifaddrs.c @@ -1,5 +1,5 @@ /* getifaddrs -- get names and addresses of all network interfaces - Copyright (C) 2013 Free Software Foundation, Inc. + Copyright (C) 2013-2015 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or -- cgit v1.2.3