#include <arpa/inet.h> /* inet_pton */
#include <unistd.h>
#include <sys/ioctl.h>
+#include <sys/socket.h>
typedef union {
struct sockaddr_in6 v6;
*head = curr;
if(!*list) *list = curr;
}
- out:
return curr;
}
static void ipv6netmask(unsigned prefix_length, struct sockaddr_in6 *sa)
{
- // FIXME: left for bit-wizard rich
- memset(&sa->sin6_addr, -1, sizeof(sa->sin6_addr));
+ unsigned char* hb = sa->sin6_addr.s6_addr;
+ unsigned onebytes = prefix_length / 8;
+ unsigned bits = prefix_length % 8;
+ unsigned nullbytes = 16 - onebytes;
+ memset(hb, -1, onebytes);
+ memset(hb+onebytes, 0, nullbytes);
+ if(bits) {
+ unsigned char x = -1;
+ x <<= 8 - bits;
+ hb[onebytes] = x;
+ }
}
static void dealwithipv6(stor **list, stor** head)
{
- FILE* f = fopen("/proc/net/if_inet6", "r");
+ FILE* f = fopen("/proc/net/if_inet6", "rbe");
/* 00000000000000000000000000000001 01 80 10 80 lo
A B C D E F
all numbers in hex
int getifaddrs(struct ifaddrs **ifap)
{
- FILE* f = fopen("/proc/net/dev", "r");
- if(!f) return -1;
-
- /* the alternative to parsing /proc.. seems to be iterating
- through the interfaces using an index number in ifreq.ifr_ifindex
- until we get some error code back. the kernel will fill ifr_name field
- for valid ifindices (SIOCGIFINDEX) */
stor *list = 0, *head = 0;
-
- char* line; char linebuf[512];
- while((line = fgets(linebuf, sizeof linebuf, f))) {
- while(isspace(*line) && *line) line++;
- char* start = line;
- while(*line && isalnum(*line)) line++;
- if(line > start && *line == ':') {
- // found interface
- *line = 0;
- stor* curr = list_add(&list, &head, start);
- if(!curr) {
- fclose(f);
- goto err2;
- }
+ struct if_nameindex* ii = if_nameindex();
+ if(!ii) return -1;
+ size_t i;
+ for(i = 0; ii[i].if_index || ii[i].if_name; i++) {
+ stor* curr = list_add(&list, &head, ii[i].if_name);
+ if(!curr) {
+ if_freenameindex(ii);
+ goto err2;
}
}
- fclose(f);
+ if_freenameindex(ii);
- int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+ int sock = socket(PF_INET, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_IP);
if(sock == -1) goto err2;
struct ifreq reqs[32]; /* arbitrary chosen boundary */
struct ifconf conf = {.ifc_len = sizeof reqs, .ifc_req = reqs};
if(-1 == ioctl(sock, SIOCGIFCONF, &conf)) goto err;
- else {
- size_t reqitems = conf.ifc_len / sizeof(struct ifreq);
- for(head = list; head; head = (stor*)head->next) {
- size_t i;
- for(i = 0; i < reqitems; i++) {
- // get SIOCGIFADDR of active interfaces.
- if(!strcmp(reqs[i].ifr_name, head->name)) {
- head->addr.v4 = *(struct sockaddr_in*)&reqs[i].ifr_addr;
- head->ifa.ifa_addr = (struct sockaddr*) &head->addr;
- break;
- }
+ size_t reqitems = conf.ifc_len / sizeof(struct ifreq);
+ for(head = list; head; head = (stor*)head->next) {
+ for(i = 0; i < reqitems; i++) {
+ // get SIOCGIFADDR of active interfaces.
+ if(!strcmp(reqs[i].ifr_name, head->name)) {
+ head->addr.v4 = *(struct sockaddr_in*)&reqs[i].ifr_addr;
+ head->ifa.ifa_addr = (struct sockaddr*) &head->addr;
+ break;
}
- struct ifreq req;
- snprintf(req.ifr_name, sizeof req.ifr_name, "%s", head->name);
- if(-1 == ioctl(sock, SIOCGIFFLAGS, &req)) goto err;
+ }
+ struct ifreq req;
+ snprintf(req.ifr_name, sizeof req.ifr_name, "%s", head->name);
+ if(-1 == ioctl(sock, SIOCGIFFLAGS, &req)) goto err;
- head->ifa.ifa_flags = req.ifr_flags;
- if(head->ifa.ifa_addr) {
- /* or'ing flags with IFF_LOWER_UP on active interfaces to mimic glibc */
- head->ifa.ifa_flags |= IFF_LOWER_UP;
- if(-1 == ioctl(sock, SIOCGIFNETMASK, &req)) goto err;
- head->netmask.v4 = *(struct sockaddr_in*)&req.ifr_netmask;
- head->ifa.ifa_netmask = (struct sockaddr*) &head->netmask;
-
- if(head->ifa.ifa_flags & IFF_POINTOPOINT) {
- if(-1 == ioctl(sock, SIOCGIFDSTADDR, &req)) goto err;
- head->dst.v4 = *(struct sockaddr_in*)&req.ifr_dstaddr;
- } else {
- if(-1 == ioctl(sock, SIOCGIFBRDADDR, &req)) goto err;
- head->dst.v4 = *(struct sockaddr_in*)&req.ifr_broadaddr;
- }
- head->ifa.ifa_ifu.ifu_dstaddr = (struct sockaddr*) &head->dst;
+ head->ifa.ifa_flags = req.ifr_flags;
+ if(head->ifa.ifa_addr) {
+ /* or'ing flags with IFF_LOWER_UP on active interfaces to mimic glibc */
+ head->ifa.ifa_flags |= IFF_LOWER_UP;
+ if(-1 == ioctl(sock, SIOCGIFNETMASK, &req)) goto err;
+ head->netmask.v4 = *(struct sockaddr_in*)&req.ifr_netmask;
+ head->ifa.ifa_netmask = (struct sockaddr*) &head->netmask;
+
+ if(head->ifa.ifa_flags & IFF_POINTOPOINT) {
+ if(-1 == ioctl(sock, SIOCGIFDSTADDR, &req)) goto err;
+ head->dst.v4 = *(struct sockaddr_in*)&req.ifr_dstaddr;
+ } else {
+ if(-1 == ioctl(sock, SIOCGIFBRDADDR, &req)) goto err;
+ head->dst.v4 = *(struct sockaddr_in*)&req.ifr_broadaddr;
}
+ head->ifa.ifa_ifu.ifu_dstaddr = (struct sockaddr*) &head->dst;
}
}
close(sock);