int _intf_get_noalias(intf_t *intf, struct intf_entry *entry) { struct lifreq lifr; /* Get interface index. */ entry->intf_index = if_nametoindex(entry->intf_name); if (entry->intf_index == 0) return (-1); strlcpy(lifr.lifr_name, entry->intf_name, sizeof(lifr.lifr_name)); /* Get interface flags. */ if (ioctl(intf->fd, SIOCGLIFFLAGS, &lifr) < 0) return (-1); entry->intf_flags = intf_iff_to_flags(lifr.lifr_flags); _intf_set_type(entry); /* Get interface MTU. */ #ifdef SIOCSIFMTU if (ioctl(intf->fd, SIOCGLIFMTU, &lifr) < 0) #endif return (-1); entry->intf_mtu = lifr.lifr_mtu; entry->intf_addr.addr_type = entry->intf_dst_addr.addr_type = entry->intf_link_addr.addr_type = ADDR_TYPE_NONE; /* Get primary interface address. */ if (ioctl(intf->fd, SIOCGLIFADDR, &lifr) == 0) { addr_ston((struct sockaddr *)&lifr.lifr_addr, &entry->intf_addr); if (ioctl(intf->fd, SIOCGLIFNETMASK, &lifr) < 0) return (-1); addr_stob((struct sockaddr *)&lifr.lifr_addr, &entry->intf_addr.addr_bits); } /* Get other addresses. */ if (entry->intf_type == INTF_TYPE_TUN) { if (ioctl(intf->fd, SIOCGLIFDSTADDR, &lifr) == 0) { if (addr_ston((struct sockaddr *)&lifr.lifr_addr, &entry->intf_dst_addr) < 0) return (-1); } } else if (entry->intf_type == INTF_TYPE_ETH) { eth_t *eth; if ((eth = eth_open(entry->intf_name)) != NULL) { if (!eth_get(eth, &entry->intf_link_addr.addr_eth)) { entry->intf_link_addr.addr_type = ADDR_TYPE_ETH; entry->intf_link_addr.addr_bits = ETH_ADDR_BITS; } eth_close(eth); } } return (0); }
int arp_get(arp_t *a, struct arp_entry *entry) { struct arpreq ar; memset(&ar, 0, sizeof(ar)); if (addr_ntos(&entry->arp_pa, &ar.arp_pa) < 0) return (-1); #ifdef HAVE_ARPREQ_ARP_DEV if (intf_loop(a->intf, _arp_set_dev, &ar) != 1) { errno = ESRCH; return (-1); } #endif if (ioctl(a->fd, SIOCGARP, &ar) < 0) return (-1); if ((ar.arp_flags & ATF_COM) == 0) { errno = ESRCH; return (-1); } return (addr_ston(&ar.arp_ha, &entry->arp_ha)); }
static int _radix_walk(int fd, struct radix_node *rn, arp_handler callback, void *arg) { struct radix_node rnode; struct rtentry rt; struct sockaddr_in sin; struct arptab at; struct arp_entry entry; int ret = 0; again: _kread(fd, rn, &rnode, sizeof(rnode)); if (rnode.rn_b < 0) { if (!(rnode.rn_flags & RNF_ROOT)) { _kread(fd, rn, &rt, sizeof(rt)); _kread(fd, rt_key(&rt), &sin, sizeof(sin)); addr_ston((struct sockaddr *)&sin, &entry.arp_pa); _kread(fd, rt.rt_llinfo, &at, sizeof(at)); if (at.at_flags & ATF_COM) { addr_pack(&entry.arp_ha, ADDR_TYPE_ETH, ETH_ADDR_BITS, at.at_hwaddr, ETH_ADDR_LEN); if ((ret = callback(&entry, arg)) != 0) return (ret); } } if ((rn = rnode.rn_dupedkey)) goto again; } else { rn = rnode.rn_r; if ((ret = _radix_walk(fd, rnode.rn_l, callback, arg)) != 0) return (ret); if ((ret = _radix_walk(fd, rn, callback, arg)) != 0) return (ret); } return (ret); }
int intf_get_src(intf_t *intf, struct intf_entry *entry, struct addr *src) { IP_ADAPTER_ADDRESSES *a; IP_ADAPTER_UNICAST_ADDRESS *addr; if (src->addr_type != ADDR_TYPE_IP) { errno = EINVAL; return (-1); } if (_refresh_tables(intf) < 0) return (-1); for (a = intf->iftable; a != NULL; a = a->Next) { for (addr = a->FirstUnicastAddress; addr != NULL; addr = addr->Next) { struct addr dnet_addr; addr_ston(addr->Address.lpSockaddr, &dnet_addr); if (addr_cmp(&dnet_addr, src) == 0) { _adapter_address_to_entry(intf, a, entry); return (0); } } } errno = ENXIO; return (-1); }
/* XXX - aliases on IRIX don't show up in SIOCGIFCONF */ static int _intf_get_aliases(intf_t *intf, struct intf_entry *entry) { struct dnet_ifaliasreq ifra; struct addr *ap, *lap; strlcpy(ifra.ifra_name, entry->intf_name, sizeof(ifra.ifra_name)); addr_ntos(&entry->intf_addr, &ifra.ifra_addr); addr_btos(entry->intf_addr.addr_bits, &ifra.ifra_mask); memset(&ifra.ifra_brdaddr, 0, sizeof(ifra.ifra_brdaddr)); ifra.ifra_cookie = 1; ap = entry->intf_alias_addrs; lap = (struct addr *)((u_char *)entry + entry->intf_len); while (ioctl(intf->fd, SIOCLIFADDR, &ifra) == 0 && ifra.ifra_cookie > 0 && (ap + 1) < lap) { if (addr_ston(&ifra.ifra_addr, ap) < 0) break; ap++, entry->intf_alias_num++; } entry->intf_len = (u_char *)ap - (u_char *)entry; return (0); }
int intf_get_dst(intf_t *intf, struct intf_entry *entry, struct addr *dst) { struct sockaddr_in sin; int n; if (dst->addr_type != ADDR_TYPE_IP) { errno = EINVAL; return (-1); } addr_ntos(dst, (struct sockaddr *)&sin); sin.sin_port = htons(666); if (connect(intf->fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) return (-1); n = sizeof(sin); if (getsockname(intf->fd, (struct sockaddr *)&sin, &n) < 0) return (-1); addr_ston((struct sockaddr *)&sin, &entry->intf_addr); if (intf_loop(intf, _match_intf_src, entry) != 1) return (-1); return (0); }
int arp_loop(arp_t *arp, arp_handler callback, void *arg) { struct arp_entry entry; struct rt_msghdr *rtm; struct sockaddr_in *sin; struct sockaddr *sa; char *buf, *lim, *next; size_t len; int ret, mib[6] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO }; if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) return (-1); if (len == 0) return (0); if ((buf = malloc(len)) == NULL) return (-1); if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { free(buf); return (-1); } lim = buf + len; ret = 0; for (next = buf; next < lim; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; sin = (struct sockaddr_in *)(rtm + 1); sa = (struct sockaddr *)(sin + 1); if (addr_ston((struct sockaddr *)sin, &entry.arp_pa) < 0 || addr_ston(sa, &entry.arp_ha) < 0) continue; if ((ret = callback(&entry, arg)) != 0) break; } free(buf); return (ret); }
static int _radix_walk(int fd, struct radix_node *rn, route_handler callback, void *arg) { struct radix_node rnode; struct rtentry rt; struct sockaddr_in sin; struct route_entry entry; int ret = 0; again: _kread(fd, rn, &rnode, sizeof(rnode)); if (rnode.rn_b < 0) { if (!(rnode.rn_flags & RNF_ROOT)) { entry.intf_name[0] = '\0'; _kread(fd, rn, &rt, sizeof(rt)); _kread(fd, rt_key(&rt), &sin, sizeof(sin)); addr_ston((struct sockaddr *)&sin, &entry.route_dst); if (!(rt.rt_flags & RTF_HOST)) { _kread(fd, rt_mask(&rt), &sin, sizeof(sin)); addr_stob((struct sockaddr *)&sin, &entry.route_dst.addr_bits); } _kread(fd, rt.rt_gateway, &sin, sizeof(sin)); addr_ston((struct sockaddr *)&sin, &entry.route_gw); entry.metric = 0; if ((ret = callback(&entry, arg)) != 0) return (ret); } if ((rn = rnode.rn_dupedkey)) goto again; } else { rn = rnode.rn_r; if ((ret = _radix_walk(fd, rnode.rn_l, callback, arg)) != 0) return (ret); if ((ret = _radix_walk(fd, rn, callback, arg)) != 0) return (ret); } return (ret); }
int eth_get(eth_t *e, eth_addr_t *ea) { struct addr ha; if (ioctl(e->fd, SIOCGIFHWADDR, &e->ifr) < 0) return (-1); if (addr_ston(&e->ifr.ifr_hwaddr, &ha) < 0) return (-1); memcpy(ea, &ha.addr_eth, sizeof(*ea)); return (0); }
int eth_get(eth_t *e, eth_addr_t *ea) { struct if_msghdr *ifm; struct sockaddr_dl *sdl; struct addr ha; u_char *p, *buf; size_t len; int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 }; if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) return (-1); if ((buf = malloc(len)) == NULL) return (-1); if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { free(buf); return (-1); } for (p = buf; p < buf + len; p += ifm->ifm_msglen) { ifm = (struct if_msghdr *)p; sdl = (struct sockaddr_dl *)(ifm + 1); if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0) continue; if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 || memcmp(sdl->sdl_data, e->device, sdl->sdl_nlen) != 0) continue; if (addr_ston((struct sockaddr *)sdl, &ha) == 0) break; } free(buf); if (p >= buf + len) { errno = ESRCH; return (-1); } memcpy(ea, &ha.addr_eth, sizeof(*ea)); return (0); }
int eth_get(eth_t *e, eth_addr_t *ea) { struct addr ha; if (ioctl(e->fd, SIOCGIFADDR, &e->ifr) < 0) return (-1); if (addr_ston(&e->ifr.ifr_addr, &ha) < 0) return (-1); if (ha.addr_type != ADDR_TYPE_ETH) { errno = EINVAL; return (-1); } memcpy(ea, &ha.addr_eth, sizeof(*ea)); return (0); }
static int _arp_set_dev(const struct intf_entry *entry, void *arg) { struct arpreq *ar = (struct arpreq *)arg; struct addr dst; uint32_t mask; if (entry->intf_type == INTF_TYPE_ETH && entry->intf_addr.addr_type == ADDR_TYPE_IP) { addr_btom(entry->intf_addr.addr_bits, &mask, IP_ADDR_LEN); addr_ston((struct sockaddr *)&ar->arp_pa, &dst); if ((entry->intf_addr.addr_ip & mask) == (dst.addr_ip & mask)) { strlcpy(ar->arp_dev, entry->intf_name, sizeof(ar->arp_dev)); return (1); } } return (0); }
/* This wrapper around addr_ston, on failure, checks for a gateway address * family of AF_LINK, and if it finds one, stores an all-zero address of the * same type as dst. The all-zero address is a convention for same-subnet * routing table entries. */ static int addr_ston_gateway(const struct addr *dst, const struct sockaddr *sa, struct addr *a) { int rc; rc = addr_ston(sa, a); if (rc == 0) return rc; #ifdef HAVE_NET_IF_DL_H # ifdef AF_LINK if (sa->sa_family == AF_LINK) { memset(a, 0, sizeof(*a)); a->addr_type = dst->addr_type; return (0); } # endif #endif return (-1); }
int arp_get(arp_t *arp, struct arp_entry *entry) { struct arpmsg msg; struct sockaddr_in *sin; struct sockaddr *sa; if (entry->arp_pa.addr_type != ADDR_TYPE_IP) { errno = EAFNOSUPPORT; return (-1); } sin = (struct sockaddr_in *)msg.addrs; sa = (struct sockaddr *)(sin + 1); if (addr_ntos(&entry->arp_pa, (struct sockaddr *)sin) < 0) return (-1); memset(&msg.rtm, 0, sizeof(msg.rtm)); msg.rtm.rtm_type = RTM_GET; msg.rtm.rtm_addrs = RTA_DST; msg.rtm.rtm_flags = RTF_LLINFO; msg.rtm.rtm_msglen = sizeof(msg.rtm) + sizeof(*sin); if (arp_msg(arp, &msg) < 0) return (-1); if (msg.rtm.rtm_msglen < (int)sizeof(msg.rtm) + sizeof(*sin) + sizeof(*sa) || sin->sin_addr.s_addr != entry->arp_pa.addr_ip || sa->sa_family != AF_LINK) { errno = ESRCH; return (-1); } if (addr_ston(sa, &entry->arp_ha) < 0) return (-1); return (0); }
int route_loop(route_t *r, route_handler callback, void *arg) { struct route_entry entry; struct strbuf msg; struct T_optmgmt_req *tor; struct T_optmgmt_ack *toa; struct T_error_ack *tea; struct opthdr *opt; u_char buf[8192]; int flags, rc, rtable, ret; tor = (struct T_optmgmt_req *)buf; toa = (struct T_optmgmt_ack *)buf; tea = (struct T_error_ack *)buf; tor->PRIM_type = T_OPTMGMT_REQ; tor->OPT_offset = sizeof(*tor); tor->OPT_length = sizeof(*opt); tor->MGMT_flags = T_CURRENT; opt = (struct opthdr *)(tor + 1); opt->level = MIB2_IP; opt->name = opt->len = 0; msg.maxlen = sizeof(buf); msg.len = sizeof(*tor) + sizeof(*opt); msg.buf = buf; if (putmsg(r->ip_fd, &msg, NULL, 0) < 0) return (-1); opt = (struct opthdr *)(toa + 1); msg.maxlen = sizeof(buf); for (;;) { mib2_ipRouteEntry_t *rt, *rtend; flags = 0; if ((rc = getmsg(r->ip_fd, &msg, NULL, &flags)) < 0) return (-1); /* See if we're finished. */ if (rc == 0 && msg.len >= sizeof(*toa) && toa->PRIM_type == T_OPTMGMT_ACK && toa->MGMT_flags == T_SUCCESS && opt->len == 0) break; if (msg.len >= sizeof(*tea) && tea->PRIM_type == T_ERROR_ACK) return (-1); if (rc != MOREDATA || msg.len < (int)sizeof(*toa) || toa->PRIM_type != T_OPTMGMT_ACK || toa->MGMT_flags != T_SUCCESS) return (-1); rtable = (opt->level == MIB2_IP && opt->name == MIB2_IP_21); msg.maxlen = sizeof(buf) - (sizeof(buf) % sizeof(*rt)); msg.len = 0; flags = 0; do { struct sockaddr_in sin; rc = getmsg(r->ip_fd, NULL, &msg, &flags); if (rc != 0 && rc != MOREDATA) return (-1); if (!rtable) continue; rt = (mib2_ipRouteEntry_t *)msg.buf; rtend = (mib2_ipRouteEntry_t *)(msg.buf + msg.len); sin.sin_family = AF_INET; for ( ; rt < rtend; rt++) { if ((rt->ipRouteInfo.re_ire_type & (IRE_BROADCAST|IRE_ROUTE_REDIRECT| IRE_LOCAL|IRE_ROUTE)) != 0 || rt->ipRouteNextHop == IP_ADDR_ANY) continue; sin.sin_addr.s_addr = rt->ipRouteNextHop; addr_ston((struct sockaddr *)&sin, &entry.route_gw); sin.sin_addr.s_addr = rt->ipRouteDest; addr_ston((struct sockaddr *)&sin, &entry.route_dst); sin.sin_addr.s_addr = rt->ipRouteMask; addr_stob((struct sockaddr *)&sin, &entry.route_dst.addr_bits); if ((ret = callback(&entry, arg)) != 0) return (ret); } } while (rc == MOREDATA); } tor = (struct T_optmgmt_req *)buf; toa = (struct T_optmgmt_ack *)buf; tea = (struct T_error_ack *)buf; tor->PRIM_type = T_OPTMGMT_REQ; tor->OPT_offset = sizeof(*tor); tor->OPT_length = sizeof(*opt); tor->MGMT_flags = T_CURRENT; opt = (struct opthdr *)(tor + 1); opt->level = MIB2_IP6; opt->name = opt->len = 0; msg.maxlen = sizeof(buf); msg.len = sizeof(*tor) + sizeof(*opt); msg.buf = buf; if (putmsg(r->ip_fd, &msg, NULL, 0) < 0) return (-1); opt = (struct opthdr *)(toa + 1); msg.maxlen = sizeof(buf); for (;;) { mib2_ipv6RouteEntry_t *rt, *rtend; flags = 0; if ((rc = getmsg(r->ip_fd, &msg, NULL, &flags)) < 0) return (-1); /* See if we're finished. */ if (rc == 0 && msg.len >= sizeof(*toa) && toa->PRIM_type == T_OPTMGMT_ACK && toa->MGMT_flags == T_SUCCESS && opt->len == 0) break; if (msg.len >= sizeof(*tea) && tea->PRIM_type == T_ERROR_ACK) return (-1); if (rc != MOREDATA || msg.len < (int)sizeof(*toa) || toa->PRIM_type != T_OPTMGMT_ACK || toa->MGMT_flags != T_SUCCESS) return (-1); rtable = (opt->level == MIB2_IP6 && opt->name == MIB2_IP6_ROUTE); msg.maxlen = sizeof(buf) - (sizeof(buf) % sizeof(*rt)); msg.len = 0; flags = 0; do { struct sockaddr_in6 sin6; rc = getmsg(r->ip_fd, NULL, &msg, &flags); if (rc != 0 && rc != MOREDATA) return (-1); if (!rtable) continue; rt = (mib2_ipv6RouteEntry_t *)msg.buf; rtend = (mib2_ipv6RouteEntry_t *)(msg.buf + msg.len); sin6.sin6_family = AF_INET6; for ( ; rt < rtend; rt++) { if ((rt->ipv6RouteInfo.re_ire_type & (IRE_BROADCAST|IRE_ROUTE_REDIRECT| IRE_LOCAL|IRE_ROUTE)) != 0 || memcmp(&rt->ipv6RouteNextHop, IP6_ADDR_UNSPEC, IP6_ADDR_LEN) == 0) continue; sin6.sin6_addr = rt->ipv6RouteNextHop; addr_ston((struct sockaddr *)&sin6, &entry.route_gw); sin6.sin6_addr = rt->ipv6RouteDest; addr_ston((struct sockaddr *)&sin6, &entry.route_dst); entry.route_dst.addr_bits = rt->ipv6RoutePfxLength; if ((ret = callback(&entry, arg)) != 0) return (ret); } } while (rc == MOREDATA); } return (0); }
static int _intf_get_noalias(intf_t *intf, struct intf_entry *entry) { struct ifreq ifr; #ifdef HAVE_GETKERNINFO int size; struct kinfo_ndd *nddp; void *end; #endif /* Get interface index. */ entry->intf_index = if_nametoindex(entry->intf_name); if (entry->intf_index == 0) return (-1); strlcpy(ifr.ifr_name, entry->intf_name, sizeof(ifr.ifr_name)); /* Get interface flags. */ if (ioctl(intf->fd, SIOCGIFFLAGS, &ifr) < 0) return (-1); entry->intf_flags = intf_iff_to_flags(ifr.ifr_flags); _intf_set_type(entry); /* Get interface MTU. */ #ifdef SIOCGIFMTU if (ioctl(intf->fd, SIOCGIFMTU, &ifr) < 0) #endif return (-1); entry->intf_mtu = ifr.ifr_mtu; entry->intf_addr.addr_type = entry->intf_dst_addr.addr_type = entry->intf_link_addr.addr_type = ADDR_TYPE_NONE; /* Get primary interface address. */ if (ioctl(intf->fd, SIOCGIFADDR, &ifr) == 0) { addr_ston(&ifr.ifr_addr, &entry->intf_addr); if (ioctl(intf->fd, SIOCGIFNETMASK, &ifr) < 0) return (-1); addr_stob(&ifr.ifr_addr, &entry->intf_addr.addr_bits); } /* Get other addresses. */ if (entry->intf_type == INTF_TYPE_TUN) { if (ioctl(intf->fd, SIOCGIFDSTADDR, &ifr) == 0) { if (addr_ston(&ifr.ifr_addr, &entry->intf_dst_addr) < 0) return (-1); } } else if (entry->intf_type == INTF_TYPE_ETH) { #if defined(HAVE_GETKERNINFO) /* AIX also defines SIOCGIFHWADDR, but it fails silently? * This is the method IBM recommends here: * http://www-01.ibm.com/support/knowledgecenter/ssw_aix_53/com.ibm.aix.progcomm/doc/progcomc/skt_sndother_ex.htm%23ssqinc2joyc?lang=en */ /* How many bytes will be returned? */ size = getkerninfo(KINFO_NDD, 0, 0, 0); if (size <= 0) { return -1; } nddp = (struct kinfo_ndd *)malloc(size); if (!nddp) { return -1; } /* Get all Network Device Driver (NDD) info */ if (getkerninfo(KINFO_NDD, nddp, &size, 0) < 0) { free(nddp); return -1; } /* Loop over the returned values until we find a match */ end = (void *)nddp + size; while ((void *)nddp < end) { if (!strcmp(nddp->ndd_alias, entry->intf_name) || !strcmp(nddp->ndd_name, entry->intf_name)) { addr_pack(&entry->intf_link_addr, ADDR_TYPE_ETH, ETH_ADDR_BITS, nddp->ndd_addr, ETH_ADDR_LEN); break; } else nddp++; } free(nddp); #elif defined(SIOCGIFHWADDR) if (ioctl(intf->fd, SIOCGIFHWADDR, &ifr) < 0) return (-1); if (addr_ston(&ifr.ifr_addr, &entry->intf_link_addr) < 0) return (-1); #elif defined(SIOCRPHYSADDR) /* Tru64 */ struct ifdevea *ifd = (struct ifdevea *)𝔦 /* XXX */ if (ioctl(intf->fd, SIOCRPHYSADDR, ifd) < 0) return (-1); addr_pack(&entry->intf_link_addr, ADDR_TYPE_ETH, ETH_ADDR_BITS, ifd->current_pa, ETH_ADDR_LEN); #else eth_t *eth; if ((eth = eth_open(entry->intf_name)) != NULL) { if (!eth_get(eth, &entry->intf_link_addr.addr_eth)) { entry->intf_link_addr.addr_type = ADDR_TYPE_ETH; entry->intf_link_addr.addr_bits = ETH_ADDR_BITS; } eth_close(eth); } #endif } return (0); }
static int _intf_get_aliases(intf_t *intf, struct intf_entry *entry) { struct ifreq *ifr, *lifr; struct ifreq tmpifr; struct addr *ap, *lap; char *p; if (intf->ifc.ifc_len < (int)sizeof(*ifr)) { errno = EINVAL; return (-1); } entry->intf_alias_num = 0; ap = entry->intf_alias_addrs; lifr = (struct ifreq *)intf->ifc.ifc_buf + (intf->ifc.ifc_len / sizeof(*lifr)); lap = (struct addr *)((u_char *)entry + entry->intf_len); /* Get addresses for this interface. */ for (ifr = intf->ifc.ifc_req; ifr < lifr && (ap + 1) < lap; ifr = NEXTIFR(ifr)) { /* XXX - Linux, Solaris ifaliases */ if ((p = strchr(ifr->ifr_name, ':')) != NULL) *p = '\0'; if (strcmp(ifr->ifr_name, entry->intf_name) != 0) { if (p) *p = ':'; continue; } if (p) *p = ':'; /* Fix the name back up */ if (addr_ston(&ifr->ifr_addr, ap) < 0) continue; /* XXX */ if (ap->addr_type == ADDR_TYPE_ETH) { memcpy(&entry->intf_link_addr, ap, sizeof(*ap)); continue; } else if (ap->addr_type == ADDR_TYPE_IP) { if (ap->addr_ip == entry->intf_addr.addr_ip || ap->addr_ip == entry->intf_dst_addr.addr_ip) continue; strlcpy(tmpifr.ifr_name, ifr->ifr_name, sizeof(tmpifr.ifr_name)); if (ioctl(intf->fd, SIOCGIFNETMASK, &tmpifr) == 0) addr_stob(&tmpifr.ifr_addr, &ap->addr_bits); } #ifdef SIOCGIFNETMASK_IN6 else if (ap->addr_type == ADDR_TYPE_IP6 && intf->fd6 != -1) { struct in6_ifreq ifr6; /* XXX - sizeof(ifr) < sizeof(ifr6) */ memcpy(&ifr6, ifr, sizeof(ifr6)); if (ioctl(intf->fd6, SIOCGIFNETMASK_IN6, &ifr6) == 0) { addr_stob((struct sockaddr *)&ifr6.ifr_addr, &ap->addr_bits); } else perror("SIOCGIFNETMASK_IN6"); } #endif ap++, entry->intf_alias_num++; } entry->intf_len = (u_char *)ap - (u_char *)entry; return (0); }
int _intf_get_noalias(intf_t *intf, struct intf_entry *entry) { struct lifreq lifr; int fd; /* Get interface index. */ entry->intf_index = if_nametoindex(entry->intf_name); if (entry->intf_index == 0) return (-1); strlcpy(lifr.lifr_name, entry->intf_name, sizeof(lifr.lifr_name)); /* Get interface flags. Here he also check whether we need to use fd or * fd6 in the rest of the function. Using the wrong address family in * the ioctls gives ENXIO on Solaris. */ if (ioctl(intf->fd, SIOCGLIFFLAGS, &lifr) >= 0) fd = intf->fd; else if (intf->fd6 != -1 && ioctl(intf->fd6, SIOCGLIFFLAGS, &lifr) >= 0) fd = intf->fd6; else return (-1); entry->intf_flags = intf_iff_to_flags(lifr.lifr_flags); _intf_set_type(entry); /* Get interface MTU. */ #ifdef SIOCGLIFMTU if (ioctl(fd, SIOCGLIFMTU, &lifr) < 0) #endif return (-1); entry->intf_mtu = lifr.lifr_mtu; entry->intf_addr.addr_type = entry->intf_dst_addr.addr_type = entry->intf_link_addr.addr_type = ADDR_TYPE_NONE; /* Get primary interface address. */ if (ioctl(fd, SIOCGLIFADDR, &lifr) == 0) { addr_ston((struct sockaddr *)&lifr.lifr_addr, &entry->intf_addr); if (ioctl(fd, SIOCGLIFNETMASK, &lifr) < 0) return (-1); addr_stob((struct sockaddr *)&lifr.lifr_addr, &entry->intf_addr.addr_bits); } /* Get other addresses. */ if (entry->intf_type == INTF_TYPE_TUN) { if (ioctl(fd, SIOCGLIFDSTADDR, &lifr) == 0) { if (addr_ston((struct sockaddr *)&lifr.lifr_addr, &entry->intf_dst_addr) < 0) return (-1); } } else if (entry->intf_type == INTF_TYPE_ETH) { eth_t *eth; if ((eth = eth_open(entry->intf_name)) != NULL) { if (!eth_get(eth, &entry->intf_link_addr.addr_eth)) { entry->intf_link_addr.addr_type = ADDR_TYPE_ETH; entry->intf_link_addr.addr_bits = ETH_ADDR_BITS; } eth_close(eth); } } return (0); }
static int _intf_get_noalias(intf_t *intf, struct intf_entry *entry) { struct ifreq ifr; strlcpy(ifr.ifr_name, entry->intf_name, sizeof(ifr.ifr_name)); /* Get interface flags. */ if (ioctl(intf->fd, SIOCGIFFLAGS, &ifr) < 0) return (-1); entry->intf_flags = intf_iff_to_flags(ifr.ifr_flags); _intf_set_type(entry); /* Get interface MTU. */ #ifdef SIOCGIFMTU if (ioctl(intf->fd, SIOCGIFMTU, &ifr) < 0) #endif return (-1); entry->intf_mtu = ifr.ifr_mtu; entry->intf_addr.addr_type = entry->intf_dst_addr.addr_type = entry->intf_link_addr.addr_type = ADDR_TYPE_NONE; /* Get primary interface address. */ if (ioctl(intf->fd, SIOCGIFADDR, &ifr) == 0) { addr_ston(&ifr.ifr_addr, &entry->intf_addr); if (ioctl(intf->fd, SIOCGIFNETMASK, &ifr) < 0) return (-1); addr_stob(&ifr.ifr_addr, &entry->intf_addr.addr_bits); } /* Get other addresses. */ if (entry->intf_type == INTF_TYPE_TUN) { if (ioctl(intf->fd, SIOCGIFDSTADDR, &ifr) == 0) { if (addr_ston(&ifr.ifr_addr, &entry->intf_dst_addr) < 0) return (-1); } } else if (entry->intf_type == INTF_TYPE_ETH) { #if defined(SIOCGIFHWADDR) if (ioctl(intf->fd, SIOCGIFHWADDR, &ifr) < 0) return (-1); if (addr_ston(&ifr.ifr_addr, &entry->intf_link_addr) < 0) return (-1); #elif defined(SIOCRPHYSADDR) /* Tru64 */ struct ifdevea *ifd = (struct ifdevea *)𝔦 /* XXX */ if (ioctl(intf->fd, SIOCRPHYSADDR, ifd) < 0) return (-1); addr_pack(&entry->intf_link_addr, ADDR_TYPE_ETH, ETH_ADDR_BITS, ifd->current_pa, ETH_ADDR_LEN); #else eth_t *eth; if ((eth = eth_open(entry->intf_name)) != NULL) { if (!eth_get(eth, &entry->intf_link_addr.addr_eth)) { entry->intf_link_addr.addr_type = ADDR_TYPE_ETH; entry->intf_link_addr.addr_bits = ETH_ADDR_BITS; } eth_close(eth); } #endif } return (0); }
static int _intf_get_aliases(intf_t *intf, struct intf_entry *entry) { struct ifreq *ifr, *lifr; struct ifreq tmpifr; struct addr *ap, *lap; char *p; if (intf->ifc.ifc_len < (int)sizeof(*ifr)) { errno = EINVAL; return (-1); } entry->intf_alias_num = 0; ap = entry->intf_alias_addrs; lifr = (struct ifreq *)intf->ifc.ifc_buf + (intf->ifc.ifc_len / sizeof(*lifr)); lap = (struct addr *)((u_char *)entry + entry->intf_len); /* Get addresses for this interface. */ for (ifr = intf->ifc.ifc_req; ifr < lifr && (ap + 1) < lap; ifr = NEXTIFR(ifr)) { /* XXX - Linux, Solaris ifaliases */ if ((p = strchr(ifr->ifr_name, ':')) != NULL) *p = '\0'; if (strcmp(ifr->ifr_name, entry->intf_name) != 0) { if (p) *p = ':'; continue; } /* Fix the name back up */ if (p) *p = ':'; if (addr_ston(&ifr->ifr_addr, ap) < 0) continue; /* XXX */ if (ap->addr_type == ADDR_TYPE_ETH) { memcpy(&entry->intf_link_addr, ap, sizeof(*ap)); continue; } else if (ap->addr_type == ADDR_TYPE_IP) { if (ap->addr_ip == entry->intf_addr.addr_ip || ap->addr_ip == entry->intf_dst_addr.addr_ip) continue; strlcpy(tmpifr.ifr_name, ifr->ifr_name, sizeof(tmpifr.ifr_name)); if (ioctl(intf->fd, SIOCGIFNETMASK, &tmpifr) == 0) addr_stob(&tmpifr.ifr_addr, &ap->addr_bits); } #ifdef SIOCGIFNETMASK_IN6 else if (ap->addr_type == ADDR_TYPE_IP6 && intf->fd6 != -1) { struct in6_ifreq ifr6; /* XXX - sizeof(ifr) < sizeof(ifr6) */ memcpy(&ifr6, ifr, sizeof(ifr6)); if (ioctl(intf->fd6, SIOCGIFNETMASK_IN6, &ifr6) == 0) { addr_stob((struct sockaddr *)&ifr6.ifr_addr, &ap->addr_bits); } else perror("SIOCGIFNETMASK_IN6"); } #else #ifdef SIOCGIFNETMASK6 else if (ap->addr_type == ADDR_TYPE_IP6 && intf->fd6 != -1) { struct in6_ifreq ifr6; /* XXX - sizeof(ifr) < sizeof(ifr6) */ memcpy(&ifr6, ifr, sizeof(ifr6)); if (ioctl(intf->fd6, SIOCGIFNETMASK6, &ifr6) == 0) { /* For some reason this is 0 after the ioctl. */ ifr6.ifr_Addr.sin6_family = AF_INET6; addr_stob((struct sockaddr *)&ifr6.ifr_Addr, &ap->addr_bits); } else perror("SIOCGIFNETMASK6"); } #endif #endif ap++, entry->intf_alias_num++; } #ifdef HAVE_LINUX_PROCFS #define PROC_INET6_FILE "/proc/net/if_inet6" { FILE *f; char buf[256], s[8][5], name[INTF_NAME_LEN]; u_int idx, bits, scope, flags; if ((f = fopen(PROC_INET6_FILE, "r")) != NULL) { while (ap < lap && fgets(buf, sizeof(buf), f) != NULL) { sscanf(buf, "%04s%04s%04s%04s%04s%04s%04s%04s %x %02x %02x %02x %32s\n", s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], &idx, &bits, &scope, &flags, name); if (strcmp(name, entry->intf_name) == 0) { snprintf(buf, sizeof(buf), "%s:%s:%s:%s:%s:%s:%s:%s/%d", s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], bits); addr_aton(buf, ap); ap++, entry->intf_alias_num++; } } fclose(f); } } #endif entry->intf_len = (u_char *)ap - (u_char *)entry; return (0); }
static void _adapter_address_to_entry(intf_t *intf, IP_ADAPTER_ADDRESSES *a, struct intf_entry *entry) { struct addr *ap, *lap; int i; int type; IP_ADAPTER_UNICAST_ADDRESS *addr; /* The total length of the entry may be passed inside entry. Remember it and clear the entry. */ u_int intf_len = entry->intf_len; memset(entry, 0, sizeof(*entry)); entry->intf_len = intf_len; type = _if_type_canonicalize(a->IfType); for (i = 0; i < intf->ifcombo[type].cnt; i++) { if (intf->ifcombo[type].idx[i].ipv4 == a->IfIndex && intf->ifcombo[type].idx[i].ipv6 == a->Ipv6IfIndex) { break; } } /* XXX - type matches MIB-II ifType. */ snprintf(entry->intf_name, sizeof(entry->intf_name), "%s%lu", _ifcombo_name(a->IfType), i); entry->intf_type = (uint16_t)type; /* Get interface flags. */ entry->intf_flags = 0; if (a->OperStatus == IfOperStatusUp) entry->intf_flags |= INTF_FLAG_UP; if (a->IfType == IF_TYPE_SOFTWARE_LOOPBACK) entry->intf_flags |= INTF_FLAG_LOOPBACK; else entry->intf_flags |= INTF_FLAG_MULTICAST; /* Get interface MTU. */ entry->intf_mtu = a->Mtu; /* Get hardware address. */ if (a->PhysicalAddressLength == ETH_ADDR_LEN) { entry->intf_link_addr.addr_type = ADDR_TYPE_ETH; entry->intf_link_addr.addr_bits = ETH_ADDR_BITS; memcpy(&entry->intf_link_addr.addr_eth, a->PhysicalAddress, ETH_ADDR_LEN); } /* Get addresses. */ ap = entry->intf_alias_addrs; lap = ap + ((entry->intf_len - sizeof(*entry)) / sizeof(entry->intf_alias_addrs[0])); for (addr = a->FirstUnicastAddress; addr != NULL; addr = addr->Next) { IP_ADAPTER_PREFIX *prefix; unsigned short bits; /* Find the netmask length. This is stored in a parallel list. We just take the first one with a matching address family, but that may not be right. Windows Vista and later has an OnLinkPrefixLength member that is stored right with the unicast address. */ bits = 0; for (prefix = a->FirstPrefix; prefix != NULL; prefix = prefix->Next) { if (prefix->Address.lpSockaddr->sa_family == addr->Address.lpSockaddr->sa_family) { bits = (unsigned short) prefix->PrefixLength; break; } } if (entry->intf_addr.addr_type == ADDR_TYPE_NONE) { /* Set primary address if unset. */ addr_ston(addr->Address.lpSockaddr, &entry->intf_addr); entry->intf_addr.addr_bits = bits; } else if (ap < lap) { /* Set aliases. */ addr_ston(addr->Address.lpSockaddr, ap); ap->addr_bits = bits; ap++; entry->intf_alias_num++; } } entry->intf_len = (u_int) ((u_char *)ap - (u_char *)entry); }
static int route_msg(route_t *r, int type, struct addr *dst, struct addr *gw) { struct addr net; struct rt_msghdr *rtm; struct sockaddr *sa; u_char buf[BUFSIZ]; pid_t pid; int len; memset(buf, 0, sizeof(buf)); rtm = (struct rt_msghdr *)buf; rtm->rtm_version = RTM_VERSION; if ((rtm->rtm_type = type) != RTM_DELETE) rtm->rtm_flags = RTF_UP; rtm->rtm_addrs = RTA_DST; rtm->rtm_seq = ++r->seq; /* Destination */ sa = (struct sockaddr *)(rtm + 1); if (addr_net(dst, &net) < 0 || addr_ntos(&net, sa) < 0) return (-1); sa = NEXTSA(sa); /* Gateway */ if (gw != NULL && type != RTM_GET) { rtm->rtm_flags |= RTF_GATEWAY; rtm->rtm_addrs |= RTA_GATEWAY; if (addr_ntos(gw, sa) < 0) return (-1); sa = NEXTSA(sa); } /* Netmask */ if (dst->addr_ip == IP_ADDR_ANY || dst->addr_bits < IP_ADDR_BITS) { rtm->rtm_addrs |= RTA_NETMASK; if (addr_btos(dst->addr_bits, sa) < 0) return (-1); sa = NEXTSA(sa); } else rtm->rtm_flags |= RTF_HOST; rtm->rtm_msglen = (u_char *)sa - buf; #ifdef DEBUG route_msg_print(rtm); #endif #ifdef HAVE_STREAMS_ROUTE if (ioctl(r->fd, RTSTR_SEND, rtm) < 0) return (-1); #else if (write(r->fd, buf, rtm->rtm_msglen) < 0) return (-1); pid = getpid(); while (type == RTM_GET && (len = read(r->fd, buf, sizeof(buf))) > 0) { if (len < (int)sizeof(*rtm)) { return (-1); } if (rtm->rtm_type == type && rtm->rtm_pid == pid && rtm->rtm_seq == r->seq) { if (rtm->rtm_errno) { errno = rtm->rtm_errno; return (-1); } break; } } #endif if (type == RTM_GET && (rtm->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY)) { sa = (struct sockaddr *)(rtm + 1); sa = NEXTSA(sa); if (addr_ston(sa, gw) < 0 || gw->addr_type != ADDR_TYPE_IP) { errno = ESRCH; return (-1); } } return (0); }
int route_loop(route_t *r, route_handler callback, void *arg) { struct rt_msghdr *rtm; struct route_entry entry; struct sockaddr *sa; char *buf, *lim, *next; int ret; #ifdef HAVE_SYS_SYSCTL_H int mib[6] = { CTL_NET, PF_ROUTE, 0, 0 /* XXX */, NET_RT_DUMP, 0 }; size_t len; if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) return (-1); if (len == 0) return (0); if ((buf = malloc(len)) == NULL) return (-1); if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { free(buf); return (-1); } lim = buf + len; next = buf; #else /* HAVE_STREAMS_ROUTE */ struct rt_giarg giarg, *gp; memset(&giarg, 0, sizeof(giarg)); giarg.gi_op = KINFO_RT_DUMP; if (ioctl(r->fd, RTSTR_GETROUTE, &giarg) < 0) return (-1); if ((buf = malloc(giarg.gi_size)) == NULL) return (-1); gp = (struct rt_giarg *)buf; gp->gi_size = giarg.gi_size; gp->gi_op = KINFO_RT_DUMP; gp->gi_where = buf; gp->gi_arg = RTF_UP | RTF_GATEWAY; if (ioctl(r->fd, RTSTR_GETROUTE, buf) < 0) { free(buf); return (-1); } lim = buf + gp->gi_size; next = buf + sizeof(giarg); #endif for (ret = 0; next < lim; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; sa = (struct sockaddr *)(rtm + 1); if (addr_ston(sa, &entry.route_dst) < 0 || (rtm->rtm_addrs & RTA_GATEWAY) == 0) continue; sa = NEXTSA(sa); if (addr_ston(sa, &entry.route_gw) < 0) continue; if (entry.route_dst.addr_type != entry.route_gw.addr_type || (entry.route_dst.addr_type != ADDR_TYPE_IP && entry.route_dst.addr_type != ADDR_TYPE_IP6)) continue; if (rtm->rtm_addrs & RTA_NETMASK) { sa = NEXTSA(sa); if (addr_stob(sa, &entry.route_dst.addr_bits) < 0) continue; } if ((ret = callback(&entry, arg)) != 0) break; } free(buf); return (ret); }
int route_loop(route_t *r, route_handler callback, void *arg) { struct rt_msghdr *rtm; struct route_entry entry; struct sockaddr *sa; char *buf, *lim, *next; int ret; #ifdef HAVE_SYS_SYSCTL_H int mib[6] = { CTL_NET, PF_ROUTE, 0, 0 /* XXX */, NET_RT_DUMP, 0 }; size_t len; if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) return (-1); if (len == 0) return (0); if ((buf = malloc(len)) == NULL) return (-1); if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { free(buf); return (-1); } lim = buf + len; next = buf; #elif defined(HAVE_GETKERNINFO) int len = getkerninfo(KINFO_RT_DUMP,0,0,0); if (len == 0) return (0); if ((buf = malloc(len)) == NULL) return (-1); if (getkerninfo(KINFO_RT_DUMP,buf,&len,0) < 0) { free(buf); return (-1); } lim = buf + len; next = buf; #else /* HAVE_STREAMS_ROUTE */ struct rt_giarg giarg, *gp; memset(&giarg, 0, sizeof(giarg)); giarg.gi_op = KINFO_RT_DUMP; if (ioctl(r->fd, RTSTR_GETROUTE, &giarg) < 0) return (-1); if ((buf = malloc(giarg.gi_size)) == NULL) return (-1); gp = (struct rt_giarg *)buf; gp->gi_size = giarg.gi_size; gp->gi_op = KINFO_RT_DUMP; gp->gi_where = buf; gp->gi_arg = RTF_UP | RTF_GATEWAY; if (ioctl(r->fd, RTSTR_GETROUTE, buf) < 0) { free(buf); return (-1); } lim = buf + gp->gi_size; next = buf + sizeof(giarg); #endif /* This loop assumes that RTA_DST, RTA_GATEWAY, and RTA_NETMASK have the * values, 1, 2, and 4 respectively. Cf. Unix Network Programming, * p. 494, function get_rtaddrs. */ for (ret = 0; next < lim; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; sa = (struct sockaddr *)(rtm + 1); if ((rtm->rtm_addrs & RTA_DST) == 0) /* Need a destination. */ continue; if (addr_ston(sa, &entry.route_dst) < 0) continue; if ((rtm->rtm_addrs & RTA_GATEWAY) == 0) /* Need a gateway. */ continue; sa = NEXTSA(sa); if (addr_ston_gateway(&entry.route_dst, sa, &entry.route_gw) < 0) continue; if (entry.route_dst.addr_type != entry.route_gw.addr_type || (entry.route_dst.addr_type != ADDR_TYPE_IP && entry.route_dst.addr_type != ADDR_TYPE_IP6)) continue; if (rtm->rtm_addrs & RTA_NETMASK) { sa = NEXTSA(sa); if (addr_stob(sa, &entry.route_dst.addr_bits) < 0) continue; } if ((ret = callback(&entry, arg)) != 0) break; } free(buf); return (ret); }