📄 ifaddrs.c
字号:
/* $Id: ifaddrs.c,v 1.4 2003/04/22 18:05:33 shemminger Exp $ *//* from USAGI: ifaddrs.c,v 1.20.2.1 2002/12/08 08:22:23 yoshfuji Exp *//* * Copyright (C)2000 YOSHIFUJI Hideaki * * This 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. * * This 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <string.h>#include <time.h>#include <malloc.h>#include <errno.h>#include <unistd.h>#define __set_errno(x) errno = (x)#include <sys/socket.h>#include <asm/types.h>#include <linux/netlink.h>#include <linux/rtnetlink.h>#include <sys/types.h>#include <sys/socket.h>#include <netpacket/packet.h>#include <net/ethernet.h> /* the L2 protocols */#include <sys/uio.h>#include <net/if.h>#include <net/if_arp.h>#include <ifaddrs.h>#include <netinet/in.h>#ifdef _USAGI_LIBINET6#include "libc-compat.h"#endif/* ====================================================================== */struct nlmsg_list{ struct nlmsg_list *nlm_next; struct nlmsghdr *nlh; int size; time_t seq;};struct rtmaddr_ifamap{ void *address; void *local;#ifdef IFA_NETMASK void *netmask;#endif void *broadcast;#ifdef HAVE_IFADDRS_IFA_ANYCAST void *anycast;#endif int address_len; int local_len;#ifdef IFA_NETMASK int netmask_len;#endif int broadcast_len;#ifdef HAVE_IFADDRS_IFA_ANYCAST int anycast_len;#endif};/* ====================================================================== */static size_tifa_sa_len (sa_family_t family, int len){ size_t size; switch (family) { case AF_INET: size = sizeof (struct sockaddr_in); break; case AF_INET6: size = sizeof (struct sockaddr_in6); break; case AF_PACKET: size = (size_t) (((struct sockaddr_ll *) NULL)->sll_addr) + len; if (size < sizeof (struct sockaddr_ll)) size = sizeof (struct sockaddr_ll); break; default: size = (size_t) (((struct sockaddr *) NULL)->sa_data) + len; if (size < sizeof (struct sockaddr)) size = sizeof (struct sockaddr); } return size;}static voidifa_make_sockaddr (sa_family_t family, struct sockaddr *sa, void *p, size_t len, uint32_t scope, uint32_t scopeid){ if (sa == NULL) return; switch (family) { case AF_INET: memcpy (&((struct sockaddr_in *) sa)->sin_addr, (char *) p, len); break; case AF_INET6: memcpy (&((struct sockaddr_in6 *) sa)->sin6_addr, (char *) p, len); if (IN6_IS_ADDR_LINKLOCAL (p) || IN6_IS_ADDR_MC_LINKLOCAL (p)) { ((struct sockaddr_in6 *) sa)->sin6_scope_id = scopeid; } break; case AF_PACKET: memcpy (((struct sockaddr_ll *) sa)->sll_addr, (char *) p, len); ((struct sockaddr_ll *) sa)->sll_halen = len; break; default: memcpy (sa->sa_data, p, len); /*XXX*/ break; } sa->sa_family = family;#ifdef HAVE_SOCKADDR_SA_LEN sa->sa_len = ifa_sa_len (family, len);#endif}static struct sockaddr *ifa_make_sockaddr_mask (sa_family_t family, struct sockaddr *sa, uint32_t prefixlen){ int i; char *p = NULL, c; uint32_t max_prefixlen = 0; if (sa == NULL) return NULL; switch (family) { case AF_INET: memset (&((struct sockaddr_in *) sa)->sin_addr, 0, sizeof (((struct sockaddr_in *) sa)->sin_addr)); p = (char *) &((struct sockaddr_in *) sa)->sin_addr; max_prefixlen = 32; break; case AF_INET6: memset (&((struct sockaddr_in6 *) sa)->sin6_addr, 0, sizeof (((struct sockaddr_in6 *) sa)->sin6_addr)); p = (char *) &((struct sockaddr_in6 *) sa)->sin6_addr;#if 0 /* XXX: fill scope-id? */ if (IN6_IS_ADDR_LINKLOCAL (p) || IN6_IS_ADDR_MC_LINKLOCAL (p)) { ((struct sockaddr_in6 *) sa)->sin6_scope_id = scopeid; }#endif max_prefixlen = 128; break; default: return NULL; } sa->sa_family = family;#ifdef HAVE_SOCKADDR_SA_LEN sa->sa_len = ifa_sa_len (family, len);#endif if (p) { if (prefixlen > max_prefixlen) prefixlen = max_prefixlen; for (i = 0; i < (prefixlen / 8); i++) *p++ = 0xff; c = 0xff; c <<= (8 - (prefixlen % 8)); *p = c; } return sa;}/* ====================================================================== */static intnl_sendreq (int sd, int request, int flags, int *seq){ char reqbuf[NLMSG_ALIGN (sizeof (struct nlmsghdr)) + NLMSG_ALIGN (sizeof (struct rtgenmsg))]; struct sockaddr_nl nladdr; struct nlmsghdr *req_hdr; struct rtgenmsg *req_msg; time_t t = time (NULL); if (seq) *seq = t; memset (&reqbuf, 0, sizeof (reqbuf)); req_hdr = (struct nlmsghdr *) reqbuf; req_msg = (struct rtgenmsg *) NLMSG_DATA (req_hdr); req_hdr->nlmsg_len = NLMSG_LENGTH (sizeof (*req_msg)); req_hdr->nlmsg_type = request; req_hdr->nlmsg_flags = flags | NLM_F_REQUEST; req_hdr->nlmsg_pid = 0; req_hdr->nlmsg_seq = t; req_msg->rtgen_family = AF_UNSPEC; memset (&nladdr, 0, sizeof (nladdr)); nladdr.nl_family = AF_NETLINK; return (sendto (sd, (void *) req_hdr, req_hdr->nlmsg_len, 0, (struct sockaddr *) &nladdr, sizeof (nladdr)));}static intnl_recvmsg (int sd, int request, int seq, void *buf, size_t buflen, int *flags){ struct msghdr msg; struct iovec iov = { buf, buflen }; struct sockaddr_nl nladdr; int read_len; for (;;) { msg.msg_name = (void *) &nladdr; msg.msg_namelen = sizeof (nladdr); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = 0; read_len = recvmsg (sd, &msg, 0); if ((read_len < 0 && errno == EINTR) || (msg.msg_flags & MSG_TRUNC)) continue; if (flags) *flags = msg.msg_flags; break; } return read_len;}static intnl_getmsg (int sd, int request, int seq, struct nlmsghdr **nlhp, int *done){ struct nlmsghdr *nh; size_t bufsize = 65536, lastbufsize = 0; void *buff = NULL; int result = 0, read_size; int msg_flags; pid_t pid = getpid (); for (;;) { void *newbuff = realloc (buff, bufsize); if (newbuff == NULL || bufsize < lastbufsize) { result = -1; break; } buff = newbuff; result = read_size = nl_recvmsg (sd, request, seq, buff, bufsize, &msg_flags); if (read_size < 0 || (msg_flags & MSG_TRUNC)) { lastbufsize = bufsize; bufsize *= 2; continue; } if (read_size == 0) break; nh = (struct nlmsghdr *) buff; for (nh = (struct nlmsghdr *) buff; NLMSG_OK (nh, read_size); nh = (struct nlmsghdr *) NLMSG_NEXT (nh, read_size)) { if (nh->nlmsg_pid != pid || nh->nlmsg_seq != seq) continue; if (nh->nlmsg_type == NLMSG_DONE) { (*done)++; break; /* ok */ } if (nh->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *nlerr = (struct nlmsgerr *) NLMSG_DATA (nh); result = -1; if (nh->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr))) __set_errno (EIO); else __set_errno (-nlerr->error); break; } } break; } if (result < 0) if (buff) { int saved_errno = errno; free (buff); __set_errno (saved_errno); } *nlhp = (struct nlmsghdr *) buff; return result;}static intnl_getlist (int sd, int seq, int request, struct nlmsg_list **nlm_list, struct nlmsg_list **nlm_end){ struct nlmsghdr *nlh = NULL; int status; int done = 0; status = nl_sendreq (sd, request, NLM_F_ROOT | NLM_F_MATCH, &seq); if (status < 0) return status; if (seq == 0) seq = (int) time (NULL); while (!done) { status = nl_getmsg (sd, request, seq, &nlh, &done); if (status < 0) return status; if (nlh) { struct nlmsg_list *nlm_next = (struct nlmsg_list *) malloc (sizeof (struct nlmsg_list)); if (nlm_next == NULL) { int saved_errno = errno; free (nlh); __set_errno (saved_errno); status = -1; } else { nlm_next->nlm_next = NULL; nlm_next->nlh = (struct nlmsghdr *) nlh; nlm_next->size = status; nlm_next->seq = seq; if (*nlm_list == NULL) { *nlm_list = nlm_next; *nlm_end = nlm_next; } else { (*nlm_end)->nlm_next = nlm_next; *nlm_end = nlm_next; } } } } return status >= 0 ? seq : status;}/* ---------------------------------------------------------------------- */static voidfree_nlmsglist (struct nlmsg_list *nlm0){ struct nlmsg_list *nlm, *nlm_next; int saved_errno; if (!nlm0) return; saved_errno = errno; nlm = nlm0; while (nlm) { if (nlm->nlh) free (nlm->nlh); nlm_next = nlm->nlm_next; free(nlm); nlm = nlm_next; } __set_errno (saved_errno);}static voidfree_data (void *data, void *ifdata){ int saved_errno = errno; if (data != NULL) free (data); if (ifdata != NULL) free (ifdata); __set_errno (saved_errno);}/* ---------------------------------------------------------------------- */static voidnl_close (int sd){ int saved_errno = errno; if (sd >= 0) __close (sd); __set_errno (saved_errno);}/* ---------------------------------------------------------------------- */static intnl_open (void){ struct sockaddr_nl nladdr; int sd; sd = socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (sd < 0) return -1; memset (&nladdr, 0, sizeof (nladdr)); nladdr.nl_family = AF_NETLINK; if (bind (sd, (struct sockaddr *) &nladdr, sizeof (nladdr)) < 0) { nl_close (sd); return -1; } return sd;}/* ====================================================================== */intgetifaddrs (struct ifaddrs **ifap){ int sd; struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm; /* - - - - - - - - - - - - - - - */ int icnt; size_t dlen, xlen, nlen; uint32_t max_ifindex = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -