From mboxrd@z Thu Jan 1 00:00:00 1970 X-Msuck: nntp://news.gmane.org/gmane.linux.lib.musl.general/4853 Path: news.gmane.org!not-for-mail From: Timo Teras Newsgroups: gmane.linux.lib.musl.general Subject: Re: if_nameindex/getifaddrs and dhcpcd issue Date: Wed, 9 Apr 2014 17:02:22 +0300 Message-ID: <20140409170222.786b7bee@vostro> References: <20140408111147.5f79729f@ncopa-desktop.alpinelinux.org> <20140408152559.124030b1@vostro> <20140408154537.GG26358@brightrain.aerifal.cx> <20140408190807.7dc6b184@vostro> Reply-To: musl@lists.openwall.com NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: quoted-printable X-Trace: ger.gmane.org 1397052069 29889 80.91.229.3 (9 Apr 2014 14:01:09 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Wed, 9 Apr 2014 14:01:09 +0000 (UTC) Cc: musl@lists.openwall.com, dalias@aerifal.cx, justin@specialbusservice.com To: Timo Teras Original-X-From: musl-return-4857-gllmg-musl=m.gmane.org@lists.openwall.com Wed Apr 09 16:01:02 2014 Return-path: Envelope-to: gllmg-musl@plane.gmane.org Original-Received: from mother.openwall.net ([195.42.179.200]) by plane.gmane.org with smtp (Exim 4.69) (envelope-from ) id 1WXt3l-0007kY-Gp for gllmg-musl@plane.gmane.org; Wed, 09 Apr 2014 16:01:01 +0200 Original-Received: (qmail 17776 invoked by uid 550); 9 Apr 2014 14:01:00 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: Original-Received: (qmail 17768 invoked from network); 9 Apr 2014 14:01:00 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:date:from:to:cc:subject:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; bh=Z/22Ir4PA5MpGFhUtC2Xps6NffAgXWYQ056z7A6R6fc=; b=VeS77ng7KyZBxoQ4yeqi1lsskNrEuebmZei5t/VFhax21sfRQdvF751Zn22OCqQHsX UPb7sZsk/BWxqj4E8jiPX7BayGutD38zK7vFlmDoopq/C6l5eqgFIp243eknvNfotoL5 UFrCoEKaAD4xv3KMYWxK5FctY9iZwZHjIz4jA+niSkRfsTBVZIFuxhhe+cgTG8eSdPWS cXlnRSuavVqWVhJtbJqr/I17/2paqnu8lRFr/e6f/foAjT5lJITniMAfMF0l8kjZ0/Hs EKy/G8LtK1VLDU5VOjosWveHOY2Rl08tPUb4xr/wNm1xrkNmSvUgV0hPdZTuwfXQi5N6 qzIg== X-Received: by 10.152.116.43 with SMTP id jt11mr1774377lab.41.1397052048730; Wed, 09 Apr 2014 07:00:48 -0700 (PDT) Original-Sender: =?UTF-8?Q?Timo_Ter=C3=A4s?= In-Reply-To: <20140408190807.7dc6b184@vostro> X-Mailer: Claws Mail 3.9.3 (GTK+ 2.24.23; i486-alpine-linux-uclibc) Xref: news.gmane.org gmane.linux.lib.musl.general:4853 Archived-At: On Tue, 8 Apr 2014 19:08:07 +0300 Timo Teras wrote: > > > I'm willing to write an alternative getifaddrs() and > > > if_nameindex() implementations using netlink. Perhaps let's see > > > how they end up? =20 > >=20 > > It wouldn't hurt; if they're not upstreamed they could still be used > > as a separate library for the one application which needs this > > functionality (dhcpcd). >=20 > Yeah. I'll play with this and see what I come up with. I'll also > delete the bad kernel #define's and try to do them a bit better - not > sure how well I succeed that at, though. Posting here the current version of my patch as requested. While it has some corner cases still that need cleaning, it's a good start. It implements the APIs, and is usable in read world. =46rom 4a82a84fb4fbfdae48f14bf86df0fd92086b7556 Mon Sep 17 00:00:00 2001 From: =3D?UTF-8?q?Timo=3D20Ter=3DC3=3DA4s?=3D Date: Tue, 8 Apr 2014 14:03:16 +0000 Subject: [PATCH] reimplement if_nameindex and getifaddrs using netlink --- src/network/__netlink.c | 68 ++++++++++ src/network/__netlink.h | 143 ++++++++++++++++++++ src/network/getifaddrs.c | 322 ++++++++++++++++++++++++-----------------= ---- src/network/if_nameindex.c | 105 +++++++++------ 4 files changed, 451 insertions(+), 187 deletions(-) create mode 100644 src/network/__netlink.c create mode 100644 src/network/__netlink.h diff --git a/src/network/__netlink.c b/src/network/__netlink.c new file mode 100644 index 0000000..d0c9fab --- /dev/null +++ b/src/network/__netlink.c @@ -0,0 +1,68 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include "__netlink.h" + +struct __netlink_handle { + int fd; + unsigned int seq; + size_t bufsize; +}; + +struct __netlink_handle *__netlink_open(int type) +{ + struct __netlink_handle *nh; + int bufsize =3D getpagesize(); + /* required buffer size is MIN(8192,pagesize)-sizeof(struct skb_shared_in= fo) + * the estimate for skb_shared_info size is conservative, but gives enough + * space to fit struct __netlink_handle including malloc overhead in one = page . */ + if (bufsize > 8192) bufsize =3D 8192; + bufsize -=3D 128; + nh =3D malloc(sizeof(struct __netlink_handle) + bufsize); + if (!nh) return 0; + nh->fd =3D socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, type); + if (nh->fd < 0) { free(nh); return 0; } + nh->seq =3D 1; + nh->bufsize =3D bufsize; + return nh; +} + +void __netlink_close(struct __netlink_handle *nh) +{ + close(nh->fd); + free(nh); +} + +int __netlink_enumerate(struct __netlink_handle *nh, int type, int (*cb)(v= oid *ctx, struct nlmsghdr *h), void *ctx) +{ + struct nlmsghdr *h; + void *buf =3D (void*)(nh+1); + struct { + struct nlmsghdr nlh; + struct rtgenmsg g; + } *req =3D buf; + int r, ret =3D 0; + + memset(req, 0, NETLINK_ALIGN(sizeof(*req))); + req->nlh.nlmsg_len =3D sizeof(*req); + req->nlh.nlmsg_type =3D type; + req->nlh.nlmsg_flags =3D NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; + req->nlh.nlmsg_seq =3D nh->seq++; + req->g.rtgen_family =3D AF_UNSPEC; + r =3D send(nh->fd, req, sizeof(*req), 0); + if (r < 0) return r; + + while (1) { + r =3D recv(nh->fd, buf, nh->bufsize, MSG_DONTWAIT); + if (r <=3D 0) return -1; + for (h =3D (struct nlmsghdr*) buf; NLMSG_OK(h, (void*)((uint8_t*)buf+r))= ; h =3D NLMSG_NEXT(h)) { + if (h->nlmsg_type =3D=3D NLMSG_DONE) return ret; + if (h->nlmsg_type =3D=3D NLMSG_ERROR) return -1; + if (!ret) ret =3D cb(ctx, h); + } + } +} diff --git a/src/network/__netlink.h b/src/network/__netlink.h new file mode 100644 index 0000000..94728f3 --- /dev/null +++ b/src/network/__netlink.h @@ -0,0 +1,143 @@ +#include + +/* linux/netlink.h */ + +#define NETLINK_ROUTE 0 + +struct nlmsghdr { + uint32_t nlmsg_len; + uint16_t nlmsg_type; + uint16_t nlmsg_flags; + uint32_t nlmsg_seq; + uint32_t nlmsg_pid; +}; + +#define NLM_F_REQUEST 1 +#define NLM_F_MULTI 2 +#define NLM_F_ACK 4 +#define NLM_F_ECHO 8 +#define NLM_F_DUMP_INTR 16 + +#define NLM_F_ROOT 0x100 +#define NLM_F_MATCH 0x200 +#define NLM_F_ATOMIC 0x400 +#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH) + +#define NLMSG_NOOP 0x1 +#define NLMSG_ERROR 0x2 +#define NLMSG_DONE 0x3 +#define NLMSG_OVERRUN 0x4 + +/* linux/rtnetlink.h */ + +#define RTM_GETLINK 18 +#define RTM_GETADDR 22 + +struct rtattr { + unsigned short rta_len; + unsigned short rta_type; +}; + +struct rtgenmsg { + unsigned char rtgen_family; +}; + +struct ifinfomsg { + unsigned char ifi_family; + unsigned char __ifi_pad; + unsigned short ifi_type; + int ifi_index; + unsigned ifi_flags; + unsigned ifi_change; +}; + +/* linux/if_link.h */ + +enum { + IFLA_UNSPEC, + IFLA_ADDRESS, + IFLA_BROADCAST, + IFLA_IFNAME, + IFLA_MTU, + IFLA_LINK, + IFLA_QDISC, + IFLA_STATS, + IFLA_COST, + IFLA_PRIORITY, + IFLA_MASTER, + IFLA_WIRELESS, + IFLA_PROTINFO, + IFLA_TXQLEN, + IFLA_MAP, + IFLA_WEIGHT, + IFLA_OPERSTATE, + IFLA_LINKMODE, + IFLA_LINKINFO, + IFLA_NET_NS_PID, + IFLA_IFALIAS, + IFLA_NUM_VF, + IFLA_VFINFO_LIST, + IFLA_STATS64, + IFLA_VF_PORTS, + IFLA_PORT_SELF, + IFLA_AF_SPEC, + IFLA_GROUP, + IFLA_NET_NS_FD, + IFLA_EXT_MASK, + IFLA_PROMISCUITY, + IFLA_NUM_TX_QUEUES, + IFLA_NUM_RX_QUEUES, + IFLA_CARRIER, + IFLA_PHYS_PORT_ID, + __IFLA_MAX +}; + +/* linux/if_addr.h */ + +struct ifaddrmsg { + uint8_t ifa_family; + uint8_t ifa_prefixlen; + uint8_t ifa_flags; + uint8_t ifa_scope; + uint32_t ifa_index; +}; + +enum { + IFA_UNSPEC, + IFA_ADDRESS, + IFA_LOCAL, + IFA_LABEL, + IFA_BROADCAST, + IFA_ANYCAST, + IFA_CACHEINFO, + IFA_MULTICAST, + __IFA_MAX +}; + +/* musl */ + +#define NETLINK_ALIGN(len) (((len)+3) & ~3) +#define NLMSG_DATA(nlh) ((void*)((char*)(nlh)+NETLINK_ALIGN(sizeof(struct= nlmsghdr)))) +#define NLMSG_DATALEN(nlh) ((nlh)->nlmsg_len-NETLINK_ALIGN(sizeof(struct n= lmsghdr))) +#define NLMSG_DATAEND(nlh) ((char*)(nlh)+(nlh)->nlmsg_len) +#define NLMSG_NEXT(nlh) (struct nlmsghdr*)((char*)(nlh)+NETLINK_ALIGN((nl= h)->nlmsg_len)) +#define NLMSG_OK(nlh,end) (NLMSG_DATA(nlh) <=3D (end) && \ + (nlh)->nlmsg_len >=3D sizeof(struct nlmsghdr) && \ + (void*)NLMSG_NEXT(nlh) <=3D (end)) + +#define RTA_DATA(rta) ((void*)((char*)(rta)+NETLINK_ALIGN(sizeof(struct r= tattr)))) +#define RTA_DATALEN(rta) ((rta)->rta_len-NETLINK_ALIGN(sizeof(struct rtatt= r))) +#define RTA_DATAEND(rta) ((char*)(rta)+(rta)->rta_len) +#define RTA_NEXT(rta) (struct rtattr*)((char*)(rta)+NETLINK_ALIGN((rta)->= rta_len)) +#define RTA_OK(rta,end) (RTA_DATA(rta) <=3D (void*)(end) && \ + (rta)->rta_len >=3D sizeof(struct rtattr) && \ + (void*)RTA_NEXT(rta) <=3D (void*)(end)) + +#define NLMSG_RTA(nlh,len) ((void*)((char*)(nlh)+NETLINK_ALIGN(sizeof(stru= ct nlmsghdr))+NETLINK_ALIGN(len))) +#define NLMSG_RTAOK(rta,nlh) RTA_OK(rta,NLMSG_DATAEND(nlh)) + +struct __netlink_handle; + +struct __netlink_handle *__netlink_open(int type); +void __netlink_close(struct __netlink_handle *h); +int __netlink_enumerate(struct __netlink_handle *h, int type, int (*cb)(vo= id *ctx, struct nlmsghdr *h), void *ctx); diff --git a/src/network/getifaddrs.c b/src/network/getifaddrs.c index 5a94cc7..5b1ebe7 100644 --- a/src/network/getifaddrs.c +++ b/src/network/getifaddrs.c @@ -1,181 +1,209 @@ -/* (C) 2013 John Spencer. released under musl's standard MIT license. */ -#undef _GNU_SOURCE #define _GNU_SOURCE -#include -#include -#include /* IFNAMSIZ, ifreq, ifconf */ -#include -#include -#include #include -#include /* inet_pton */ +#include +#include #include -#include -#include +#include +#include +#include "__netlink.h" =20 -typedef union { - struct sockaddr_in6 v6; +/* getifaddrs() uses PF_PACKET to relay hardware addresses. + * But Infiniband socket address length is longer, so use this hack + * (like glibc) to return it anyway. */ +struct sockaddr_ll_hack { + unsigned short sll_family, sll_protocol; + int sll_ifindex; + unsigned short sll_hatype; + unsigned char sll_pkttype, sll_halen; + unsigned char sll_addr[24]; +}; + +union sockany { + struct sockaddr sa; + struct sockaddr_ll_hack ll; struct sockaddr_in v4; -} soa; + struct sockaddr_in6 v6; +}; =20 -typedef struct ifaddrs_storage { +struct ifaddrs_storage { struct ifaddrs ifa; - soa addr; - soa netmask; - soa dst; + struct ifaddrs_storage *hash_next; + union sockany addr, netmask, ifu; + unsigned int index; char name[IFNAMSIZ+1]; -} stor; -#define next ifa.ifa_next +}; =20 -static stor* list_add(stor** list, stor** head, char* ifname) +#define IFADDRS_HASH_SIZE 64 +struct ifaddrs_ctx { + struct ifaddrs_storage *first; + struct ifaddrs_storage *last; + struct ifaddrs_storage *hash[IFADDRS_HASH_SIZE]; +}; + +void freeifaddrs(struct ifaddrs *ifp) { - stor* curr =3D calloc(1, sizeof(stor)); - if(curr) { - strcpy(curr->name, ifname); - curr->ifa.ifa_name =3D curr->name; - if(*head) (*head)->next =3D (struct ifaddrs*) curr; - *head =3D curr; - if(!*list) *list =3D curr; + struct ifaddrs *n; + while (ifp) { + n =3D ifp->ifa_next; + free(ifp); + ifp =3D n; } - return curr; } =20 -void freeifaddrs(struct ifaddrs *ifp) +static void addifaddrs(struct ifaddrs_ctx *ctx, struct ifaddrs_storage *ad= d) { - stor *head =3D (stor *) ifp; - while(head) { - void *p =3D head; - head =3D (stor *) head->next; - free(p); + if (!add->ifa.ifa_name) { + free(add); + return; } + if (!ctx->first) ctx->first =3D add; + if (ctx->last) ctx->last->ifa.ifa_next =3D &add->ifa; + ctx->last =3D add; } =20 -static void ipv6netmask(unsigned prefix_length, struct sockaddr_in6 *sa) +static struct sockaddr* copy_lladdr(union sockany *sa, struct rtattr *rta,= struct ifinfomsg *ifi) { - unsigned char* hb =3D sa->sin6_addr.s6_addr; - unsigned onebytes =3D prefix_length / 8; - unsigned bits =3D prefix_length % 8; - unsigned nullbytes =3D 16 - onebytes; - memset(hb, -1, onebytes); - memset(hb+onebytes, 0, nullbytes); - if(bits) { - unsigned char x =3D -1; - x <<=3D 8 - bits; - hb[onebytes] =3D x; + if (RTA_DATALEN(rta) > sizeof(sa->ll.sll_addr)) return 0; + sa->ll.sll_family =3D AF_PACKET; + sa->ll.sll_ifindex =3D ifi->ifi_index; + sa->ll.sll_hatype =3D ifi->ifi_type; + sa->ll.sll_halen =3D RTA_DATALEN(rta); + memcpy(sa->ll.sll_addr, RTA_DATA(rta), RTA_DATALEN(rta)); + return &sa->sa; +} + +static uint8_t *sockany_addr(int af, union sockany *sa, int *len) +{ + switch (af) { + case AF_INET: *len =3D 4; return (uint8_t*) &sa->v4.sin_addr; + case AF_INET6: *len =3D 16; return (uint8_t*) &sa->v6.sin6_addr; } + return 0; } =20 -static void dealwithipv6(stor **list, stor** head) +static struct sockaddr* copy_addr(int af, union sockany *sa, struct rtattr= *rta) { - FILE* f =3D fopen("/proc/net/if_inet6", "rbe"); - /* 00000000000000000000000000000001 01 80 10 80 lo - A B C D E F - all numbers in hex - A =3D addr B=3Dnetlink device#, C=3Dprefix length, - D =3D scope value (ipv6.h) E =3D interface flags (rnetlink.h, addrconf= .c) - F =3D if name */ - char v6conv[32 + 7 + 1], *v6; - char *line, linebuf[512]; - if(!f) return; - while((line =3D fgets(linebuf, sizeof linebuf, f))) { - v6 =3D v6conv; - size_t i =3D 0; - for(; i < 8; i++) { - memcpy(v6, line, 4); - v6+=3D4; - *v6++=3D':'; - line+=3D4; - } - --v6; *v6 =3D 0; - line++; - unsigned b, c, d, e; - char name[IFNAMSIZ+1]; - if(5 =3D=3D sscanf(line, "%x %x %x %x %s", &b, &c, &d, &e, name)) { - struct sockaddr_in6 sa =3D {0}; - if(1 =3D=3D inet_pton(AF_INET6, v6conv, &sa.sin6_addr)) { - sa.sin6_family =3D AF_INET6; - stor* curr =3D list_add(list, head, name); - if(!curr) goto out; - curr->addr.v6 =3D sa; - curr->ifa.ifa_addr =3D (struct sockaddr*) &curr->addr; - ipv6netmask(c, &sa); - curr->netmask.v6 =3D sa; - curr->ifa.ifa_netmask =3D (struct sockaddr*) &curr->netmask; - /* find ipv4 struct with the same interface name to copy flags */ - stor* scan =3D *list; - for(;scan && strcmp(name, scan->name);scan=3D(stor*)scan->next); - if(scan) curr->ifa.ifa_flags =3D scan->ifa.ifa_flags; - else curr->ifa.ifa_flags =3D 0; - } else errno =3D 0; - } + int len; + uint8_t *dst =3D sockany_addr(af, sa, &len); + if (!dst || RTA_DATALEN(rta) !=3D len) return 0; + sa->sa.sa_family =3D af; + memcpy(dst, RTA_DATA(rta), len); + return &sa->sa; +} + +static struct sockaddr *gen_netmask(int af, union sockany *sa, int prefixl= en) +{ + int maxlen, i; + uint8_t *dst =3D sockany_addr(af, sa, &maxlen); + if (!dst) return 0; + sa->sa.sa_family =3D af; + if (prefixlen > 8*maxlen) prefixlen =3D 8*maxlen; + i =3D prefixlen / 8; + memset(dst, 0xff, i); + if (isa; } =20 -int getifaddrs(struct ifaddrs **ifap) +static int __handle_link(void *pctx, struct nlmsghdr *h) { - stor *list =3D 0, *head =3D 0; - struct if_nameindex* ii =3D if_nameindex(); - if(!ii) return -1; - size_t i; - for(i =3D 0; ii[i].if_index || ii[i].if_name; i++) { - stor* curr =3D list_add(&list, &head, ii[i].if_name); - if(!curr) { - if_freenameindex(ii); - goto err2; - } + struct ifaddrs_ctx *ctx =3D pctx; + struct ifaddrs_storage *ifs; + struct ifinfomsg *ifi =3D NLMSG_DATA(h); + struct rtattr *rta; + int stats_len =3D 0; + + for (rta =3D NLMSG_RTA(h, sizeof(*ifi)); NLMSG_RTAOK(rta, h); rta =3D RTA= _NEXT(rta)) { + if (rta->rta_type !=3D IFLA_STATS) continue; + stats_len =3D RTA_DATALEN(rta); + break; } - if_freenameindex(ii); - - int sock =3D socket(PF_INET, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_IP); - if(sock =3D=3D -1) goto err2; - struct ifreq reqs[32]; /* arbitrary chosen boundary */ - struct ifconf conf =3D {.ifc_len =3D sizeof reqs, .ifc_req =3D reqs}; - if(-1 =3D=3D ioctl(sock, SIOCGIFCONF, &conf)) goto err; - size_t reqitems =3D conf.ifc_len / sizeof(struct ifreq); - for(head =3D list; head; head =3D (stor*)head->next) { - for(i =3D 0; i < reqitems; i++) { - // get SIOCGIFADDR of active interfaces. - if(!strcmp(reqs[i].ifr_name, head->name)) { - head->addr.v4 =3D *(struct sockaddr_in*)&reqs[i].ifr_addr; - head->ifa.ifa_addr =3D (struct sockaddr*) &head->addr; - break; + + ifs =3D calloc(1, sizeof(struct ifaddrs_storage) + stats_len); + if (ifs =3D=3D 0) return -1; + + ifs->index =3D ifi->ifi_index; + ifs->ifa.ifa_flags =3D ifi->ifi_flags; + + for (rta =3D NLMSG_RTA(h, sizeof(*ifi)); NLMSG_RTAOK(rta, h); rta =3D RTA= _NEXT(rta)) { + switch (rta->rta_type) { + case IFLA_IFNAME: + if (RTA_DATALEN(rta) <=3D IFNAMSIZ) { + strncpy(ifs->name, RTA_DATA(rta), RTA_DATALEN(rta)); + ifs->ifa.ifa_name =3D ifs->name; } + break; + case IFLA_ADDRESS: + ifs->ifa.ifa_addr =3D copy_lladdr(&ifs->addr, rta, ifi); + break; + case IFLA_BROADCAST: + ifs->ifa.ifa_broadaddr =3D copy_lladdr(&ifs->ifu, rta, ifi); + break; + case IFLA_STATS: + ifs->ifa.ifa_data =3D (void*)(ifs+1); + memcpy(ifs->ifa.ifa_data, RTA_DATA(rta), RTA_DATALEN(rta)); + break; } - struct ifreq req; - snprintf(req.ifr_name, sizeof req.ifr_name, "%s", head->name); - if(-1 =3D=3D ioctl(sock, SIOCGIFFLAGS, &req)) goto err; - - head->ifa.ifa_flags =3D 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 |=3D IFF_LOWER_UP;=20 - if(-1 =3D=3D ioctl(sock, SIOCGIFNETMASK, &req)) goto err; - head->netmask.v4 =3D *(struct sockaddr_in*)&req.ifr_netmask; - head->ifa.ifa_netmask =3D (struct sockaddr*) &head->netmask; -=09 - if(head->ifa.ifa_flags & IFF_POINTOPOINT) { - if(-1 =3D=3D ioctl(sock, SIOCGIFDSTADDR, &req)) goto err; - head->dst.v4 =3D *(struct sockaddr_in*)&req.ifr_dstaddr; - } else { - if(-1 =3D=3D ioctl(sock, SIOCGIFBRDADDR, &req)) goto err; - head->dst.v4 =3D *(struct sockaddr_in*)&req.ifr_broadaddr; - } - head->ifa.ifa_ifu.ifu_dstaddr =3D (struct sockaddr*) &head->dst; + } + if (ifs->ifa.ifa_name) { + ifs->hash_next =3D ctx->hash[ifs->index%IFADDRS_HASH_SIZE]; + ctx->hash[ifs->index%IFADDRS_HASH_SIZE] =3D ifs; + } + addifaddrs(ctx, ifs); + return 0; +} + +static int __handle_addr(void *pctx, struct nlmsghdr *h) +{ + struct ifaddrs_ctx *ctx =3D pctx; + struct ifaddrs_storage *ifs, *ifs0; + struct ifaddrmsg *ifa =3D NLMSG_DATA(h); + struct rtattr *rta; + + ifs =3D calloc(1, sizeof(struct ifaddrs_storage)); + if (ifs =3D=3D 0) return -1; + + for (ifs0 =3D ctx->hash[ifa->ifa_index%IFADDRS_HASH_SIZE]; ifs0; ifs0 =3D= ifs0->hash_next) + if (ifs0->index =3D=3D ifa->ifa_index) + break; + if (!ifs0) return 0; + + ifs->ifa.ifa_name =3D ifs0->ifa.ifa_name; + ifs->ifa.ifa_flags =3D ifs0->ifa.ifa_flags; + for (rta =3D NLMSG_RTA(h, sizeof(*ifa)); NLMSG_RTAOK(rta, h); rta =3D RTA= _NEXT(rta)) { + switch (rta->rta_type) { + case IFA_ADDRESS: + ifs->ifa.ifa_addr =3D copy_addr(ifa->ifa_family, &ifs->addr, rta); + if (ifs->ifa.ifa_addr) + ifs->ifa.ifa_netmask =3D gen_netmask(ifa->ifa_family, &ifs->netmask, i= fa->ifa_prefixlen); + break; + case IFA_BROADCAST: + /* For point-to-point links this is peer, but ifa_broadaddr + * and ifa_dstaddr are union, so this works for both. */ + ifs->ifa.ifa_broadaddr =3D copy_addr(ifa->ifa_family, &ifs->ifu, rta); + break; } } - close(sock); - void* last =3D 0; - for(head =3D list; head; head=3D(stor*)head->next) last=3Dhead; - head =3D last; - dealwithipv6(&list, &head); - *ifap =3D (struct ifaddrs*) list; + + addifaddrs(ctx, ifs); return 0; - err: - close(sock); - err2: - freeifaddrs((struct ifaddrs*) list); - return -1; } =20 +int getifaddrs(struct ifaddrs **ifap) +{ + struct ifaddrs_ctx _ctx, *ctx =3D &_ctx; + struct __netlink_handle *nh; + int r =3D 0; + + nh =3D __netlink_open(NETLINK_ROUTE); + if (!nh) return -1; + memset(ctx, 0, sizeof(*ctx)); + if (__netlink_enumerate(nh, RTM_GETLINK, __handle_link, ctx)) r =3D -1; + if (__netlink_enumerate(nh, RTM_GETADDR, __handle_addr, ctx)) r =3D -1; + __netlink_close(nh); + if (r =3D=3D 0) *ifap =3D &ctx->first->ifa; + else freeifaddrs(&ctx->first->ifa); + return r; +} diff --git a/src/network/if_nameindex.c b/src/network/if_nameindex.c index 53b80b2..d4e8b2d 100644 --- a/src/network/if_nameindex.c +++ b/src/network/if_nameindex.c @@ -1,55 +1,80 @@ #define _GNU_SOURCE #include -#include #include -#include #include -#include "syscall.h" +#include +#include +#include +#include "__netlink.h" + +struct ifnamemap { + unsigned int index; + unsigned char namelen; + char name[IFNAMSIZ]; +}; =20 -static void *do_nameindex(int s, size_t n) +struct ifnameindexctx { + unsigned int num; + unsigned int str_bytes; + struct ifnamemap *list; +}; + +static int __handle_link(void *pctx, struct nlmsghdr *h) { - size_t i, len, k; - struct ifconf conf; - struct if_nameindex *idx; - - idx =3D malloc(n * (sizeof(struct if_nameindex)+sizeof(struct ifreq))); - if (!idx) return 0; - - conf.ifc_buf =3D (void *)&idx[n]; - conf.ifc_len =3D len =3D n * sizeof(struct ifreq); - if (ioctl(s, SIOCGIFCONF, &conf) < 0) { - free(idx); - return 0; - } - if (conf.ifc_len =3D=3D len) { - free(idx); - return (void *)-1; - } + struct ifnameindexctx *ctx =3D pctx; + struct ifinfomsg *ifim =3D NLMSG_DATA(h); + struct rtattr *rta; + struct ifnamemap *e; =20 - n =3D conf.ifc_len / sizeof(struct ifreq); - for (i=3Dk=3D0; irta_type !=3D IFLA_IFNAME) continue; + if (RTA_DATALEN(rta) > IFNAMSIZ) return -ENOBUFS; + + ctx->num++; + ctx->str_bytes +=3D RTA_DATALEN(rta) + 1; + e =3D realloc(ctx->list, sizeof(struct ifnamemap[ctx->num])); + if (e =3D=3D 0) return -ENOMEM; + ctx->list =3D e; + + e =3D &ctx->list[ctx->num-1]; + e->index =3D ifim->ifi_index; + e->namelen =3D RTA_DATALEN(rta); + memcpy(e->name, RTA_DATA(rta), IFNAMSIZ); } - idx[i-k].if_name =3D 0; - idx[i-k].if_index =3D 0; =20 - return idx; + return 0; } =20 struct if_nameindex *if_nameindex() { - size_t n; - void *p =3D 0; - int s =3D socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); - if (s>=3D0) { - for (n=3D0; (p=3Ddo_nameindex(s, n)) =3D=3D (void *)-1; n++); - __syscall(SYS_close, s); + struct ifnameindexctx _ctx, *ctx =3D &_ctx; + struct if_nameindex *ifs =3D NULL; + struct __netlink_handle *nh; + int r, i; + char *p; + + nh =3D __netlink_open(NETLINK_ROUTE); + if (!nh) goto err; + memset(ctx, 0, sizeof(*ctx)); + r =3D __netlink_enumerate(nh, RTM_GETLINK, __handle_link, ctx); + __netlink_close(nh); + if (r < 0) goto err; + + ifs =3D malloc(sizeof(struct if_nameindex[ctx->num+1]) + ctx->str_bytes); + if (ifs =3D=3D 0) goto err; + + p =3D (char*)ifs + sizeof(struct if_nameindex[ctx->num+1]); + for (i =3D 0; i < ctx->num; i++) { + ifs[i].if_index =3D ctx->list[i].index; + ifs[i].if_name =3D p; + memcpy(p, ctx->list[i].name, ctx->list[i].namelen); + p +=3D ctx->list[i].namelen; + *p++ =3D 0; } - errno =3D ENOBUFS; - return p; + ifs[i].if_index =3D 0; + ifs[i].if_name =3D 0; +err: + free(ctx->list); + if (ifs =3D=3D NULL) errno =3D ENOBUFS; + return ifs; } --=20 1.9.1