do_interface then becomes do_address and also uses getifaddrs.
Binary size is a little smaller, code size is now a lot smaller.
}
}
}
-
-static void
-discover_link(struct interface **ifs, int argc, char * const *argv,
- struct ifreq *ifr)
-{
- struct interface *ifp, *ifl = NULL;
- struct sockaddr_dl *sdl;
- int n;
-
- if (ifr->ifr_addr.sa_family != AF_LINK)
- return;
- for (ifp = *ifs; ifp; ifp = ifp->next) {
- if (strcmp(ifp->name, ifr->ifr_name) == 0)
- return;
- ifl = ifp;
- }
- if (argc > 0) {
- for (n = 0; n < argc; n++)
- if (strcmp(ifr->ifr_name, argv[n]) == 0)
- break;
- if (n == argc)
- return;
- } else {
- for (n = 0; n < ifdc; n++)
- if (fnmatch(ifdv[n], ifr->ifr_name, 0) == 0)
- return;
- for (n = 0; n < ifac; n++)
- if (fnmatch(ifav[n], ifr->ifr_name, 0) == 0)
- break;
- if (ifac && n == ifac)
- return;
- }
- if (!(ifp = init_interface(ifr->ifr_name)))
- return;
- sdl = (struct sockaddr_dl *)(void *)&ifr->ifr_addr;
- switch(sdl->sdl_type) {
- case IFT_ETHER:
- ifp->family = ARPHRD_ETHER;
- ifp->hwlen = sdl->sdl_alen;
- break;
- case IFT_IEEE1394:
- ifp->family = ARPHRD_IEEE1394;
- ifp->hwlen = sdl->sdl_alen;
- break;
- case IFT_LOOP:
- /* We don't allow loopback unless requested */
- if (argc == 0 && ifac == 0) {
- free(ifp);
- ifp = NULL;
- }
- break;
- }
- if (ifp && ifp->hwlen)
- memcpy(ifp->hwaddr, LLADDR(sdl), ifp->hwlen);
- if (ifl)
- ifl->next = ifp;
- else
- *ifs = ifp;
-}
-
-struct interface *
-discover_interfaces(int argc, char * const *argv)
-{
- struct interface *ifs = NULL;
-
- do_interface(NULL, discover_link, &ifs, argc, argv,
- NULL, NULL, NULL, 2);
- return ifs;
-}
#include <sys/types.h>
#include <sys/socket.h>
-#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/param.h>
# define IFLA_WIRELESS (IFLA_MASTER + 1)
#endif
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <netinet/ether.h>
-#include <netpacket/packet.h>
-
#include <errno.h>
#include <ctype.h>
-#include <fnmatch.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
free(nlm);
return retval;
}
-
-struct interface *
-discover_interfaces(int argc, char * const *argv)
-{
- FILE *f;
- char ifn[IF_NAMESIZE];
- char *p, *c;
- size_t ln = 0, n;
- int i;
- struct interface *ifs = NULL, *ifp, *ifl;
-
- if ((f = fopen("/proc/net/dev", "r"))) {
- while ((p = get_line(f))) {
- if (++ln < 2)
- continue;
- n = strcspn(p, ": \t");
- p[n]= '\0';
- ifl = NULL;
- for (ifp = ifs; ifp; ifp = ifp->next) {
- if (strcmp(ifp->name, p) == 0)
- break;
- ifl = ifp;
- }
- if (ifp)
- continue;
- if (argc > 0) {
- for (i = 0; i < argc; i++) {
- /* Check the real interface name */
- strlcpy(ifn, argv[i], sizeof(ifn));
- c = strchr(ifn, ':');
- if (c)
- *c = '\0';
- if (strcmp(ifn, p) == 0)
- break;
- }
- if (i == argc)
- continue;
- p = argv[i];
- } else {
- for (i = 0; i < ifdc; i++)
- if (!fnmatch(ifdv[i], p, 0))
- break;
- if (i < ifdc)
- continue;
- for (i = 0; i < ifac; i++)
- if (!fnmatch(ifav[i], p, 0))
- break;
- if (ifac && i == ifac)
- continue;
- }
- if ((ifp = init_interface(p))) {
- /* Don't allow loopback unless explicit */
- if (ifp->flags & IFF_LOOPBACK &&
- (argc != 0 || ifdc != 0))
- {
- free_interface(ifp);
- continue;
- }
- if (ifl)
- ifl->next = ifp;
- else
- ifs = ifp;
- }
- }
- fclose(f);
- }
- return ifs;
-}
#define __FAVOR_BSD /* Nasty glibc hack so we can use BSD semantics for UDP */
#include <netinet/udp.h>
#undef __FAVOR_BSD
+#ifdef AF_PACKET
+# include <netpacket/packet.h>
+#endif
#ifdef SIOCGIFMEDIA
-# include <net/if_media.h>
+# include <net/if_media.h>
#endif
#include <ctype.h>
#include <errno.h>
+#include <ifaddrs.h>
+#include <fnmatch.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
iface->metric += 100;
}
-#ifdef SIOCGIFHWADDR
- strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
- if (ioctl(s, SIOCGIFHWADDR, &ifr) == -1)
- goto eexit;
-
- switch (ifr.ifr_hwaddr.sa_family) {
- case ARPHRD_ETHER:
- case ARPHRD_IEEE802:
- iface->hwlen = ETHER_ADDR_LEN;
- break;
- case ARPHRD_IEEE1394:
- iface->hwlen = EUI64_ADDR_LEN;
- case ARPHRD_INFINIBAND:
- iface->hwlen = INFINIBAND_ADDR_LEN;
- break;
- default:
- iface->hwlen = 0;
- }
- iface->family = ifr.ifr_hwaddr.sa_family;
- if (iface->hwlen != 0)
- memcpy(iface->hwaddr, ifr.ifr_hwaddr.sa_data, iface->hwlen);
-#endif
-
if (ioctl(s, SIOCGIFMTU, &ifr) == -1)
goto eexit;
/* Ensure that the MTU is big enough for DHCP */
free(iface);
}
-int
-do_interface(const char *ifname,
- void (*do_link)(struct interface **, int, char * const *, struct ifreq *),
- struct interface **ifs, int argc, char * const *argv,
- struct in_addr *addr, struct in_addr *net, struct in_addr *dst, int act)
+struct interface *
+discover_interfaces(int argc, char * const *argv)
{
- int s;
- struct ifconf ifc;
- int retval = 0, found = 0;
- int len = 10 * sizeof(struct ifreq);
- int lastlen = 0;
- char *p, *e;
- in_addr_t address, netmask;
- struct ifreq *ifr;
- struct sockaddr_in *sin;
+ struct ifaddrs *ifaddrs, *ifa;
+ char *p;
+ int i;
+ struct interface *ifp, *ifs, *ifl;
+#ifdef __linux__
+ char ifn[IF_NAMESIZE];
+#endif
+#ifdef AF_LINK
+ const struct sockaddr_dl *sdl;
+#elif AF_PACKET
+ const struct sockaddr_ll *sll;
+#endif
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
- return -1;
+ if (getifaddrs(&ifaddrs) == -1)
+ return NULL;
- /* Not all implementations return the needed buffer size for
- * SIOGIFCONF so we loop like so for all until it works */
- memset(&ifc, 0, sizeof(ifc));
- for (;;) {
- ifc.ifc_len = len;
- ifc.ifc_buf = xmalloc((size_t)len);
- if (ioctl(s, SIOCGIFCONF, &ifc) == -1) {
- if (errno != EINVAL || lastlen != 0) {
- close(s);
- free(ifc.ifc_buf);
- return -1;
+ ifs = ifl = NULL;
+ for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
+#ifdef AF_LINK
+ if (ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+#elif AF_PACKET
+ if (ifa->ifa_addr->sa_family != AF_PACKET)
+ continue;
+#endif
+ if (argc > 0) {
+ for (i = 0; i < argc; i++) {
+#ifdef __linux__
+ /* Check the real interface name */
+ strlcpy(ifn, argv[i], sizeof(ifn));
+ p = strchr(ifn, ':');
+ if (p)
+ *p = '\0';
+ if (strcmp(ifn, ifa->ifa_name) == 0)
+ break;
+#else
+ if (strcmp(argv[i], ifa->ifa_name) == 0)
+ break;
+#endif
+ }
+ if (i == argc)
+ continue;
+ p = argv[i];
+ } else {
+ for (i = 0; i < ifdc; i++)
+ if (!fnmatch(ifdv[i], ifa->ifa_name, 0))
+ break;
+ if (i < ifdc)
+ continue;
+ for (i = 0; i < ifac; i++)
+ if (!fnmatch(ifav[i], ifa->ifa_name, 0))
+ break;
+ if (ifac && i == ifac)
+ continue;
+ p = ifa->ifa_name;
+ }
+ if ((ifp = init_interface(p)) == NULL)
+ continue;
+ /* Don't allow loopback unless explicit */
+ if (ifp->flags & IFF_LOOPBACK) {
+ if (argc == 0 && ifdc == 0) {
+ free_interface(ifp);
+ continue;
}
} else {
- if (ifc.ifc_len == lastlen)
+#ifdef AF_LINK
+ sdl = (const struct sockaddr_dl *)(void *)ifa->ifa_addr;
+ switch(sdl->sdl_type) {
+ case IFT_ETHER:
+ ifp->family = ARPHRD_ETHER;
+ break;
+ case IFT_IEEE1394:
+ ifp->family = ARPHRD_IEEE1394;
break;
- lastlen = ifc.ifc_len;
+ }
+ ifp->hwlen = sdl->sdl_alen;
+ memcpy(ifp->hwaddr, LLADDR(sdl), ifp->hwlen);
+#elif AF_PACKET
+ sll = (const struct sockaddr_ll *)(void *)ifa->ifa_addr;
+ ifp->family = sll->sll_hatype;
+ ifp->hwlen = sll->sll_halen;
+ if (ifp->hwlen != 0)
+ memcpy(ifp->hwaddr, sll->sll_addr, ifp->hwlen);
+#endif
}
-
- free(ifc.ifc_buf);
- ifc.ifc_buf = NULL;
- len *= 2;
- }
-
- e = (char *)ifc.ifc_buf + ifc.ifc_len;
- for (p = ifc.ifc_buf; p < e;) {
- ifr = (struct ifreq *)(void *)p;
-
-#ifndef __linux__
- if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_ifru))
- p += offsetof(struct ifreq, ifr_ifru) +
- ifr->ifr_addr.sa_len;
+ if (ifl)
+ ifl->next = ifp;
else
-#endif
- p += sizeof(*ifr);
+ ifs = ifp;
+ ifl = ifp;
+ }
+ freeifaddrs(ifaddrs);
+ return ifs;
+}
- if (ifname && strcmp(ifname, ifr->ifr_name) != 0)
- continue;
+int
+do_address(const char *ifname,
+ struct in_addr *addr, struct in_addr *net, struct in_addr *dst, int act)
+{
+ struct ifaddrs *ifaddrs, *ifa;
+ const struct sockaddr_in *a, *n, *d;
+ int retval;
- found = 1;
+ if (getifaddrs(&ifaddrs) == -1)
+ return -1;
- /* Interface discovery for BSD's */
- if (act == 2 && do_link) {
- do_link(ifs, argc, argv, ifr);
+ retval = 0;
+ for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_INET ||
+ strcmp(ifa->ifa_name, ifname) != 0)
continue;
+ a = (const struct sockaddr_in *)(void *)&ifa->ifa_addr;
+ n = (const struct sockaddr_in *)(void *)&ifa->ifa_netmask;
+ if (ifa->ifa_flags & IFF_POINTOPOINT)
+ d = (const struct sockaddr_in *)
+ (void *)&ifa->ifa_ifu.ifu_dstaddr;
+ else
+ d = NULL;
+ if (act == 1) {
+ addr->s_addr = a->sin_addr.s_addr;
+ net->s_addr = n->sin_addr.s_addr;
+ if (dst && ifa->ifa_flags & IFF_POINTOPOINT)
+ dst->s_addr = d->sin_addr.s_addr;
+ retval = 1;
+ break;
}
-
- if (ifr->ifr_addr.sa_family == AF_INET && addr) {
- sin = (struct sockaddr_in *)(void *)&ifr->ifr_addr;
- address = sin->sin_addr.s_addr;
- /* Some platforms only partially fill the bits
- * set by the netmask, so we need to zero it now. */
- sin->sin_addr.s_addr = 0;
- if (ioctl(s, SIOCGIFNETMASK, ifr) == -1)
- continue;
- netmask = sin->sin_addr.s_addr;
- if (act == 1) {
- if (dst) {
- sin = (struct sockaddr_in *)
- (void *)&ifr->ifr_dstaddr;
- if (ioctl(s, SIOCGIFDSTADDR, ifr)
- == -1)
- dst->s_addr = INADDR_ANY;
- else
- dst->s_addr =
- sin->sin_addr.s_addr;
- }
- addr->s_addr = address;
- net->s_addr = netmask;
- retval = 1;
- break;
- } else {
- if (address == addr->s_addr &&
- (!net || netmask == net->s_addr))
- {
- retval = 1;
- break;
- }
- }
+ if (addr->s_addr == a->sin_addr.s_addr &&
+ (net == NULL || net->s_addr == n->sin_addr.s_addr))
+ {
+ retval = 1;
+ break;
}
-
}
-
- if (!found)
- errno = ENXIO;
- close(s);
- free(ifc.ifc_buf);
+ freeifaddrs(ifaddrs);
return retval;
}
-
+
int
up_interface(const char *ifname)
{
* 192.168/16
*/
#ifndef IN_PRIVATE
-# define IN_PRIVATE(addr) (((addr & IN_CLASSA_NET) == 0x0a000000) || \
- ((addr & 0xfff00000) == 0xac100000) || \
+# define IN_PRIVATE(addr) (((addr & IN_CLASSA_NET) == 0x0a000000) || \
+ ((addr & 0xfff00000) == 0xac100000) || \
((addr & IN_CLASSB_NET) == 0xc0a80000))
#endif
int inet_cidrtoaddr(int, struct in_addr *);
int up_interface(const char *);
-int do_interface(const char *,
- void (*)(struct interface **, int, char * const *, struct ifreq *),
- struct interface **, int, char * const *,
+int do_address(const char *,
struct in_addr *, struct in_addr *, struct in_addr *, int);
int if_address(const struct interface *,
const struct in_addr *, const struct in_addr *,
const struct in_addr *, int);
-#define add_address(iface, addr, net, brd) \
+#define add_address(iface, addr, net, brd) \
if_address(iface, addr, net, brd, 1)
-#define del_address(iface, addr, net) \
+#define del_address(iface, addr, net) \
if_address(iface, addr, net, NULL, -1)
-#define has_address(iface, addr, net) \
- do_interface(iface, NULL, NULL, 0, NULL, addr, net, NULL, 0)
-#define get_address(iface, addr, net, dst) \
- do_interface(iface, NULL, NULL, 0, NULL, addr, net, dst, 1)
+#define has_address(iface, addr, net) \
+ do_address(iface, addr, net, NULL, 0)
+#define get_address(iface, addr, net, dst) \
+ do_address(iface, addr, net, dst, 1)
int if_route(const struct interface *, const struct in_addr *,
const struct in_addr *, const struct in_addr *, int, int);
-#define add_route(iface, dest, mask, gate, metric) \
+#define add_route(iface, dest, mask, gate, metric) \
if_route(iface, dest, mask, gate, metric, 1)
-#define change_route(iface, dest, mask, gate, metric) \
+#define change_route(iface, dest, mask, gate, metric) \
if_route(iface, dest, mask, gate, metric, 0)
-#define del_route(iface, dest, mask, gate, metric) \
+#define del_route(iface, dest, mask, gate, metric) \
if_route(iface, dest, mask, gate, metric, -1)
-#define del_src_route(iface, dest, mask, gate, metric) \
+#define del_src_route(iface, dest, mask, gate, metric) \
if_route(iface, dest, mask, gate, metric, -2)
void free_routes(struct rt *);