From 580b71ae890adb7840a184fbc4a676cf1ad19465 Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Sat, 31 Dec 2016 23:13:58 +0100 Subject: [PATCH] Add getifaddrs(3) and freeifaddrs(3). --- libc/Makefile | 2 + libc/ifaddrs/freeifaddrs.c | 31 ++++++++++ libc/ifaddrs/getifaddrs.c | 114 +++++++++++++++++++++++++++++++++++++ libc/include/ifaddrs.h | 59 +++++++++++++++++++ share/man/man4/if.4 | 1 + 5 files changed, 207 insertions(+) create mode 100644 libc/ifaddrs/freeifaddrs.c create mode 100644 libc/ifaddrs/getifaddrs.c create mode 100644 libc/include/ifaddrs.h diff --git a/libc/Makefile b/libc/Makefile index 3af132d4..2dcce012 100644 --- a/libc/Makefile +++ b/libc/Makefile @@ -378,6 +378,8 @@ grp/getgrnam.o \ grp/getgrnam_r.o \ grp/opengr.o \ grp/setgrent.o \ +ifaddrs/freeifaddrs.o \ +ifaddrs/getifaddrs.o \ init/init.o \ ioleast/preadall.o \ ioleast/preadleast.o \ diff --git a/libc/ifaddrs/freeifaddrs.c b/libc/ifaddrs/freeifaddrs.c new file mode 100644 index 00000000..41151233 --- /dev/null +++ b/libc/ifaddrs/freeifaddrs.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016 Jonas 'Sortie' Termansen. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * ifaddrs/freeifaddrs.c + * Free list of network interface addresses. + */ + +#include +#include + +void freeifaddrs(struct ifaddrs* ifa) +{ + while ( ifa ) + { + struct ifaddrs* todelete = ifa; + ifa = ifa->ifa_next; + free(todelete); + } +} diff --git a/libc/ifaddrs/getifaddrs.c b/libc/ifaddrs/getifaddrs.c new file mode 100644 index 00000000..58de0e63 --- /dev/null +++ b/libc/ifaddrs/getifaddrs.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2016, 2017 Jonas 'Sortie' Termansen. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * ifaddrs/getifaddrs.c + * List network interface addresses. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +union ifaddrs_addr +{ + struct sockaddr_in in; + struct sockaddr_in6 in6; +}; + +struct ifaddrs_storage +{ + struct ifaddrs pub; + char name[IF_NAMESIZE]; + union ifaddrs_addr addr; + union ifaddrs_addr netmask; + union ifaddrs_addr broadcast; +}; + +int getifaddrs(struct ifaddrs** ifas_ptr) +{ + struct if_nameindex* ifs = if_nameindex(); + if ( !ifs ) + return -1; + size_t ifcount = 0; + while ( ifs[ifcount].if_index ) + ifcount++; + struct ifaddrs* ifas = NULL; + size_t i = ifcount; + while ( i-- ) + { + struct if_nameindex* netif = &ifs[i]; + char path[5 + IF_NAMESIZE]; + snprintf(path, sizeof(path), "/dev/%s", netif->if_name); + int fd = open(path, O_RDONLY); + if ( fd < 0 ) + { + if_freenameindex(ifs); + freeifaddrs(ifas); + return -1; + } + struct if_config cfg; + if ( ioctl(fd, NIOC_GETCONFIG, &cfg) < 0 ) + { + close(fd); + if_freenameindex(ifs); + freeifaddrs(ifas); + return -1; + } + close(fd); + if ( be32toh(cfg.inet.address.s_addr) != INADDR_ANY ) + { + struct ifaddrs_storage* ifa = + calloc(sizeof(struct ifaddrs_storage), 1); + if ( !ifa ) + { + if_freenameindex(ifs); + freeifaddrs(ifas); + return -1; + } + ifa->pub.ifa_next = ifas; + ifas = &ifa->pub; + strlcpy(ifa->name, netif->if_name, sizeof(ifa->name)); + ifa->pub.ifa_name = ifa->name; + ifa->pub.ifa_flags = 0; + ifa->addr.in.sin_family = AF_INET; + memcpy(&ifa->addr.in.sin_addr, &cfg.inet.address, + sizeof(struct in_addr)); + ifa->pub.ifa_addr = (struct sockaddr*) &ifa->addr.in; + ifa->netmask.in.sin_family = AF_INET; + memcpy(&ifa->netmask.in.sin_addr, &cfg.inet.subnet, + sizeof(struct in_addr)); + ifa->pub.ifa_netmask = (struct sockaddr*) &ifa->netmask.in; + ifa->broadcast.in.sin_family = AF_INET; + ifa->broadcast.in.sin_addr.s_addr = + ifa->addr.in.sin_addr.s_addr | + ~ifa->netmask.in.sin_addr.s_addr; + ifa->pub.ifa_dstaddr = (struct sockaddr*) &ifa->broadcast.in; + ifa->pub.ifa_data = NULL; + ifa->pub.ifa_size = sizeof(struct sockaddr_in); + } + // TODO: IPv6 when struct if_config has IPv6 support. + } + if_freenameindex(ifs); + *ifas_ptr = ifas; + return 0; +} diff --git a/libc/include/ifaddrs.h b/libc/include/ifaddrs.h new file mode 100644 index 00000000..44b0b8db --- /dev/null +++ b/libc/include/ifaddrs.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016 Jonas 'Sortie' Termansen. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * ifaddrs.h + * Network interface addresses. + */ + +#ifndef _INCLUDE_IFADDRS_H +#define _INCLUDE_IFADDRS_H + +#include + +#include + +#ifndef __socklen_t_defined +#define __socklen_t_defined +typedef __socklen_t socklen_t; +#endif + +struct ifaddrs +{ + struct ifaddrs* ifa_next; + char* ifa_name; + unsigned int ifa_flags; + struct sockaddr* ifa_addr; + struct sockaddr* ifa_netmask; + struct sockaddr* ifa_dstaddr; + void* ifa_data; + socklen_t ifa_size; +}; + +#ifndef ifa_broadaddr +#define ifa_broadaddr ifa_dstaddr +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +int getifaddrs(struct ifaddrs**); +void freeifaddrs(struct ifaddrs*); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/share/man/man4/if.4 b/share/man/man4/if.4 index 9ccc1d6f..7af4f862 100644 --- a/share/man/man4/if.4 +++ b/share/man/man4/if.4 @@ -330,6 +330,7 @@ temporarily fail with .Xr getsockopt 2 , .Xr ioctl 2 , .Xr setsockopt 2 , +.Xr getifaddrs 3 , .Xr if_nameindex 3 , .Xr arp 4 , .Xr ether 4 ,