int rx_getAllAddrMaskMtu(afs_uint32 addrBuffer[], afs_uint32 maskBuffer[], afs_uint32 mtuBuffer[], int maxSize) { int s; size_t needed; int mib[6]; struct if_msghdr *ifm, *nextifm; struct ifa_msghdr *ifam; struct sockaddr_dl *sdl; struct rt_addrinfo info; char *buf, *lim, *next; int count = 0, addrcount = 0; mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = AF_INET; /* address family */ mib[4] = NET_RT_IFLIST; mib[5] = 0; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) return 0; if ((buf = malloc(needed)) == NULL) return 0; if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { free(buf); return 0; } #if defined(AFS_OBSD42_ENV) ifm_fixversion(buf, &needed); #endif s = socket(PF_INET, SOCK_DGRAM, 0); if (s < 0) return 0; lim = buf + needed; next = buf; while (next < lim) { ifm = (struct if_msghdr *)next; if (ifm->ifm_type != RTM_IFINFO) { dpf(("out of sync parsing NET_RT_IFLIST\n")); free(buf); return 0; } sdl = (struct sockaddr_dl *)(ifm + 1); next += ifm->ifm_msglen; ifam = NULL; addrcount = 0; while (next < lim) { nextifm = (struct if_msghdr *)next; if (nextifm->ifm_type != RTM_NEWADDR) break; if (ifam == NULL) ifam = (struct ifa_msghdr *)nextifm; addrcount++; next += nextifm->ifm_msglen; } if ((ifm->ifm_flags & IFF_UP) == 0) continue; /* not up */ while (addrcount > 0) { struct sockaddr_in *a; info.rti_addrs = ifam->ifam_addrs; /* Expand the compacted addresses */ rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info); if (info.rti_info[RTAX_IFA]->sa_family != AF_INET) { addrcount--; continue; } a = (struct sockaddr_in *) info.rti_info[RTAX_IFA]; if (a->sin_addr.s_addr != htonl(0x7f000001) ) { if (count >= maxSize) { /* no more space */ dpf(("Too many interfaces..ignoring 0x%x\n", a->sin_addr.s_addr)); } else { struct ifreq ifr; addrBuffer[count] = a->sin_addr.s_addr; a = (struct sockaddr_in *) info.rti_info[RTAX_NETMASK]; if (a) maskBuffer[count] = a->sin_addr.s_addr; else maskBuffer[count] = htonl(0xffffffff); memset(&ifr, 0, sizeof(ifr)); ifr.ifr_addr.sa_family = AF_INET; strncpy(ifr.ifr_name, sdl->sdl_data, sdl->sdl_nlen); if (ioctl(s, SIOCGIFMTU, (caddr_t) & ifr) < 0) mtuBuffer[count] = htonl(1500); else mtuBuffer[count] = htonl(ifr.ifr_mtu); count++; } } addrcount--; ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen); } } free(buf); return count; }
/* * Figure out device configuration and select * networks which deserve status information. */ int configure(int so) { struct neighbor *np; struct if_msghdr *ifm; struct ifa_msghdr *ifam; struct sockaddr_dl *sdl; size_t needed; int mib[6], flags, lflags, len; char *buf, *lim, *next; struct rt_addrinfo info; flags = 0; if (multicast_mode != NO_MULTICAST) { multicast_addr.sin_addr.s_addr = htonl(INADDR_WHOD_GROUP); multicast_addr.sin_port = sp->s_port; } if (multicast_mode == SCOPED_MULTICAST) { struct ip_mreq mreq; unsigned char ttl; mreq.imr_multiaddr.s_addr = htonl(INADDR_WHOD_GROUP); mreq.imr_interface.s_addr = htonl(INADDR_ANY); if (setsockopt(so, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { syslog(LOG_ERR, "setsockopt IP_ADD_MEMBERSHIP: %m"); return (0); } ttl = multicast_scope; if (setsockopt(so, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) { syslog(LOG_ERR, "setsockopt IP_MULTICAST_TTL: %m"); return (0); } return (1); } mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = AF_INET; mib[4] = NET_RT_IFLIST; mib[5] = 0; if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0) quit("route-sysctl-estimate"); if ((buf = malloc(needed)) == NULL) quit("malloc"); if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) quit("actual retrieval of interface table"); lim = buf + needed; sdl = NULL; /* XXX just to keep gcc -Wall happy */ for (next = buf; next < lim; next += ifm->ifm_msglen) { ifm = (struct if_msghdr *)next; if (ifm->ifm_type == RTM_IFINFO) { sdl = (struct sockaddr_dl *)(ifm + 1); flags = ifm->ifm_flags; continue; } if ((flags & IFF_UP) == 0) continue; lflags = IFF_BROADCAST | iff_flag; if (multicast_mode == PER_INTERFACE_MULTICAST) lflags |= IFF_MULTICAST; if ((flags & lflags) == 0) continue; if (ifm->ifm_type != RTM_NEWADDR) quit("out of sync parsing NET_RT_IFLIST"); ifam = (struct ifa_msghdr *)ifm; info.rti_addrs = ifam->ifam_addrs; rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info); /* gag, wish we could get rid of Internet dependencies */ #define dstaddr info.rti_info[RTAX_BRD] #define ifaddr info.rti_info[RTAX_IFA] #define IPADDR_SA(x) ((struct sockaddr_in *)(x))->sin_addr.s_addr #define PORT_SA(x) ((struct sockaddr_in *)(x))->sin_port if (dstaddr == 0 || dstaddr->sa_family != AF_INET) continue; PORT_SA(dstaddr) = sp->s_port; for (np = neighbors; np != NULL; np = np->n_next) { if (memcmp(sdl->sdl_data, np->n_name, sdl->sdl_nlen) == 0 && IPADDR_SA(np->n_addr) == IPADDR_SA(dstaddr)) { break; } } if (np != NULL) continue; len = sizeof(*np) + dstaddr->sa_len + sdl->sdl_nlen + 1; np = malloc(len); if (np == NULL) quit("malloc of neighbor structure"); memset(np, 0, len); np->n_flags = flags; np->n_addr = (struct sockaddr *)(np + 1); np->n_addrlen = dstaddr->sa_len; np->n_name = np->n_addrlen + (char *)np->n_addr; memcpy((char *)np->n_addr, (char *)dstaddr, np->n_addrlen); memcpy(np->n_name, sdl->sdl_data, sdl->sdl_nlen); if (multicast_mode == PER_INTERFACE_MULTICAST && (flags & IFF_MULTICAST) != 0 && (flags & IFF_LOOPBACK) == 0) { struct ip_mreq mreq; memcpy((char *)np->n_addr, (char *)ifaddr, np->n_addrlen); mreq.imr_multiaddr.s_addr = htonl(INADDR_WHOD_GROUP); mreq.imr_interface.s_addr = ((struct sockaddr_in *)np->n_addr)->sin_addr.s_addr; if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { syslog(LOG_ERR, "setsockopt IP_ADD_MEMBERSHIP: %m"); #if 0 /* Fall back to broadcast on this if. */ np->n_flags &= ~IFF_MULTICAST; #else free(np); continue; #endif } } np->n_next = neighbors; neighbors = np; } free(buf); return (1); }
int rx_getAllAddr_internal(afs_uint32 buffer[], int maxSize, int loopbacks) { size_t needed; int mib[6]; struct if_msghdr *ifm, *nextifm; struct ifa_msghdr *ifam; struct sockaddr_dl *sdl; struct rt_addrinfo info; char *buf, *lim, *next; int count = 0, addrcount = 0; mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = AF_INET; /* address family */ mib[4] = NET_RT_IFLIST; mib[5] = 0; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) return 0; if ((buf = malloc(needed)) == NULL) return 0; if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { free(buf); return 0; } #if defined(AFS_OBSD42_ENV) ifm_fixversion(buf, &needed); #endif lim = buf + needed; next = buf; while (next < lim) { ifm = (struct if_msghdr *)next; if (ifm->ifm_type != RTM_IFINFO) { dpf(("out of sync parsing NET_RT_IFLIST\n")); free(buf); return 0; } sdl = (struct sockaddr_dl *)(ifm + 1); next += ifm->ifm_msglen; ifam = NULL; addrcount = 0; while (next < lim) { nextifm = (struct if_msghdr *)next; if (nextifm->ifm_type != RTM_NEWADDR) break; if (ifam == NULL) ifam = (struct ifa_msghdr *)nextifm; addrcount++; next += nextifm->ifm_msglen; } if ((ifm->ifm_flags & IFF_UP) == 0) continue; /* not up */ while (addrcount > 0) { struct sockaddr_in *a; info.rti_addrs = ifam->ifam_addrs; /* Expand the compacted addresses */ rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info); if (info.rti_info[RTAX_IFA]->sa_family != AF_INET) { addrcount--; continue; } a = (struct sockaddr_in *) info.rti_info[RTAX_IFA]; if (count >= maxSize) /* no more space */ dpf(("Too many interfaces..ignoring 0x%x\n", a->sin_addr.s_addr)); else if (!loopbacks && a->sin_addr.s_addr == htonl(0x7f000001)) { addrcount--; continue; /* skip loopback address as well. */ } else if (loopbacks && ifm->ifm_flags & IFF_LOOPBACK) { addrcount--; continue; /* skip aliased loopbacks as well. */ } else buffer[count++] = a->sin_addr.s_addr; addrcount--; ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen); } } free(buf); return count; }
/* * Print the status of the interface. If an address family was * specified, show only it; otherwise, show them all. */ static void status(const struct afswtch *afp, int addrcount, struct sockaddr_dl *sdl, struct if_msghdr *ifm, struct ifa_msghdr *ifam) { struct rt_addrinfo info; int allfamilies, s; struct ifstat ifs; if (afp == NULL) { allfamilies = 1; afp = af_getbyname("inet"); } else allfamilies = 0; ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af; strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0); if (s < 0) err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family); printf("%s: ", name); printb("flags", flags, IFFBITS); if (ifm->ifm_data.ifi_metric) printf(" metric %ld", ifm->ifm_data.ifi_metric); if (ifm->ifm_data.ifi_mtu) printf(" mtu %ld", ifm->ifm_data.ifi_mtu); putchar('\n'); if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) { if (ifr.ifr_curcap != 0) { printb("\toptions", ifr.ifr_curcap, IFCAPBITS); putchar('\n'); } if (supmedia && ifr.ifr_reqcap != 0) { printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS); putchar('\n'); } } tunnel_status(s); while (addrcount > 0) { info.rti_addrs = ifam->ifam_addrs; /* Expand the compacted addresses */ rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info); if (allfamilies) { const struct afswtch *p; p = af_getbyfamily(info.rti_info[RTAX_IFA]->sa_family); if (p != NULL && p->af_status != NULL) p->af_status(s, &info); } else if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family) afp->af_status(s, &info); addrcount--; ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen); } if (allfamilies || afp->af_af == AF_LINK) { const struct afswtch *lafp; /* * Hack; the link level address is received separately * from the routing information so any address is not * handled above. Cobble together an entry and invoke * the status method specially. */ lafp = af_getbyname("lladdr"); if (lafp != NULL) { info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl; lafp->af_status(s, &info); } } if (allfamilies) af_other_status(s); else if (afp->af_other_status != NULL) afp->af_other_status(s); strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name); if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) printf("%s", ifs.ascii); if (flags & IFF_POLLING) { if (ioctl(s, SIOCGIFPOLLCPU, &ifr) == 0 && ifr.ifr_pollcpu >= 0) printf("\tpollcpu: %d\n", ifr.ifr_pollcpu); } close(s); return; }
/* * Print the status of the interface. If an address family was * specified, show it and it only; otherwise, show them all. */ void status(void) { struct afswtch *p = NULL; char *mynext; struct if_msghdr *myifm; printf("%s: ", name); printb("flags", flags, IFFBITS); if (metric) printf(" metric %d", metric); if (mtu) printf(" mtu %d", mtu); putchar('\n'); /* * XXX: Sigh. This is bad, I know. At this point, we may have * *zero* RTM_NEWADDR's, so we have to "feel the water" before * incrementing the loop. One day, I might feel inspired enough * to get the top level loop to pass a count down here so we * dont have to mess with this. -Peter */ myifm = ifm; while (1) { mynext = next + ifm->ifm_msglen; if (mynext >= lim) break; myifm = (struct if_msghdr *)mynext; if (myifm->ifm_type != RTM_NEWADDR) break; next = mynext; ifm = (struct if_msghdr *)next; ifam = (struct ifa_msghdr *)myifm; info.rti_addrs = ifam->ifam_addrs; /* Expand the compacted addresses */ rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info); if (afp) { if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family && afp->af_status != ether_status) { p = afp; if (p->af_status != ether_status) (*p->af_status)(1); } } else for (p = afs; p->af_name; p++) { if (p->af_af == info.rti_info[RTAX_IFA]->sa_family && p->af_status != ether_status) (*p->af_status)(0); } } if (afp == NULL || afp->af_status == ether_status) ether_status(0); else if (afp && !p) { warnx("%s has no %s IFA address!", name, afp->af_name); } phys_status(0); }
/* * Find the network interfaces which have configured themselves. * If the interface is present but not yet up (for example an * ARPANET IMP), set the lookforinterfaces flag so we'll * come back later and look again. */ void ifinit(void) { struct interface ifs, *ifp; size_t needed; int mib[6], no_ipxaddr = 0, flags = 0; char *buf, *cplim, *cp; struct if_msghdr *ifm; struct ifa_msghdr *ifam; struct sockaddr_dl *sdl = NULL; mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = AF_IPX; mib[4] = NET_RT_IFLIST; mib[5] = 0; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) quit("route-sysctl-estimate"); if ((buf = malloc(needed)) == NULL) quit("malloc"); if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) lookforinterfaces = 0; cplim = buf + needed; for (cp = buf; cp < cplim; cp += ifm->ifm_msglen) { ifm = (struct if_msghdr *)cp; if (ifm->ifm_type == RTM_IFINFO) { bzero(&ifs, sizeof(ifs)); ifs.int_flags = flags = ifm->ifm_flags | IFF_INTERFACE; if ((flags & IFF_UP) == 0 || no_ipxaddr) lookforinterfaces = 1; sdl = (struct sockaddr_dl *) (ifm + 1); sdl->sdl_data[sdl->sdl_nlen] = 0; no_ipxaddr = 1; continue; } if (ifm->ifm_type != RTM_NEWADDR) quit("ifinit: out of sync"); if ((flags & IFF_UP) == 0) continue; ifam = (struct ifa_msghdr *)ifm; info.rti_addrs = ifam->ifam_addrs; rt_xaddrs((char *)(ifam + 1), cp + ifam->ifam_msglen, &info); if (ifaaddr == 0) { syslog(LOG_ERR, "%s: (get addr)", sdl->sdl_data); continue; } ifs.int_addr = *ifaaddr; if (ifs.int_addr.sa_family != AF_IPX) continue; no_ipxaddr = 0; if (ifs.int_flags & IFF_POINTOPOINT) { if (brdaddr == 0) { syslog(LOG_ERR, "%s: (get dstaddr)", sdl->sdl_data); continue; } if (brdaddr->sa_family == AF_UNSPEC) { lookforinterfaces = 1; continue; } ifs.int_dstaddr = *brdaddr; } if (ifs.int_flags & IFF_BROADCAST) { if (brdaddr == 0) { syslog(LOG_ERR, "%s: (get broadaddr)", sdl->sdl_data); continue; } ifs.int_dstaddr = *brdaddr; } if (ifs.int_flags & IFF_LOOPBACK) { ifs.int_dstaddr = ifs.int_addr; } /* * already known to us? * what makes a POINTOPOINT if unique is its dst addr, * NOT its source address */ if ( ((ifs.int_flags & IFF_POINTOPOINT) && if_ifwithdstaddr(&ifs.int_dstaddr)) || ( ((ifs.int_flags & IFF_POINTOPOINT) == 0) && if_ifwithaddr(&ifs.int_addr))) continue; ifp = (struct interface *) malloc(sdl->sdl_nlen + 1 + sizeof(ifs)); if (ifp == NULL) { syslog(LOG_ERR, "IPXrouted: out of memory\n"); lookforinterfaces = 1; break; } *ifp = ifs; /* * Count the # of directly connected networks * and point to point links which aren't looped * back to ourself. This is used below to * decide if we should be a routing ``supplier''. */ if ((ifs.int_flags & IFF_POINTOPOINT) == 0 || if_ifwithaddr(&ifs.int_dstaddr) == 0) externalinterfaces++; /* * If we have a point-to-point link, we want to act * as a supplier even if it's our only interface, * as that's the only way our peer on the other end * can tell that the link is up. */ if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0) supplier = 1; ifp->int_name = (char *)(ifp + 1); strcpy(ifp->int_name, sdl->sdl_data); ifp->int_metric = ifam->ifam_metric; ifp->int_next = ifnet; ifnet = ifp; traceinit(ifp); addrouteforif(ifp); } if (externalinterfaces > 1 && supplier < 0) supplier = 1; free(buf); }
PRIVATE_EXTERN void inet6_addrlist_copy(inet6_addrlist_t * addr_list_p, int if_index) { int addr_index = 0; char * buf = NULL; char * buf_end; int buf_len; int count; int error; int i; char ifname[IFNAMSIZ + 1]; inet6_addrinfo_t * linklocal = NULL; inet6_addrinfo_t * list = NULL; char * scan; struct rt_msghdr * rtm; int s = -1; buf = get_if_info(if_index, AF_INET6, &buf_len); if (buf == NULL) { goto done; } buf_end = buf + buf_len; /* figure out how many IPv6 addresses there are */ count = 0; ifname[0] = '\0'; for (scan = buf; scan < buf_end; scan += rtm->rtm_msglen) { struct if_msghdr * ifm; /* ALIGN: buf aligned (from calling get_if_info), scan aligned, * cast ok. */ rtm = (struct rt_msghdr *)(void *)scan; if (rtm->rtm_version != RTM_VERSION) { continue; } switch (rtm->rtm_type) { case RTM_IFINFO: ifm = (struct if_msghdr *)rtm; if (ifm->ifm_addrs & RTA_IFP) { struct sockaddr_dl * dl_p; dl_p = (struct sockaddr_dl *)(ifm + 1); if (dl_p->sdl_nlen == 0 || dl_p->sdl_nlen >= sizeof(ifname)) { goto done; } bcopy(dl_p->sdl_data, ifname, dl_p->sdl_nlen); ifname[dl_p->sdl_nlen] = '\0'; } break; case RTM_NEWADDR: count++; break; default: break; } } if (ifname[0] == '\0') { goto done; } if (count == 0) { goto done; } if (count > INET6_ADDRLIST_N_STATIC) { list = (inet6_addrinfo_t *)malloc(sizeof(*list) * count); if (list == NULL) { goto done; } } else { list = addr_list_p->list_static; } for (scan = buf; scan < buf_end; scan += rtm->rtm_msglen) { boolean_t got_address = FALSE; struct ifa_msghdr * ifam; struct rt_addrinfo info; rtm = (struct rt_msghdr *)(void *)scan; if (rtm->rtm_version != RTM_VERSION) { continue; } if (rtm->rtm_type == RTM_NEWADDR) { ifam = (struct ifa_msghdr *)rtm; info.rti_addrs = ifam->ifam_addrs; error = rt_xaddrs((char *)(ifam + 1), ((char *)ifam) + ifam->ifam_msglen, &info); if (error) { fprintf(stderr, "couldn't extract rt_addrinfo %s (%d)\n", strerror(error), error); goto done; } for (i = 0; i < RTAX_MAX; i++) { struct sockaddr_in6 * sin6_p; /* ALIGN: info.rti_info aligned (sockaddr), cast ok. */ sin6_p = (struct sockaddr_in6 *)(void *)info.rti_info[i]; if (sin6_p == NULL || sin6_p->sin6_len < sizeof(struct sockaddr_in6)) { continue; } switch (i) { case RTAX_NETMASK: list[addr_index].prefix_length = count_prefix_bits(&sin6_p->sin6_addr, sizeof(sin6_p->sin6_addr)); break; case RTAX_IFA: list[addr_index].addr = sin6_p->sin6_addr; got_address = TRUE; break; default: break; } } if (got_address) { if (s < 0) { s = inet6_dgram_socket(); } if (s >= 0) { siocgifaflag_in6(s, ifname, &list[addr_index].addr, &list[addr_index].addr_flags); siocgifalifetime_in6(s, ifname, &list[addr_index].addr, &list[addr_index].valid_lifetime, &list[addr_index].preferred_lifetime); } /* Mask the v6 LL scope id */ if (IN6_IS_ADDR_LINKLOCAL(&list[addr_index].addr)) { list[addr_index].addr.s6_addr16[1] = 0; if (linklocal == NULL) { linklocal = &list[addr_index]; } } addr_index++; } } } if (addr_index == 0) { if (list != addr_list_p->list_static) { free(list); } list = NULL; } done: if (s >= 0) { close(s); } if (buf != NULL) { free(buf); } addr_list_p->list = list; addr_list_p->count = addr_index; addr_list_p->linklocal = linklocal; return; }
int main(int argc, char **argv) { int ch, sflag, rflag, ret, flag6, iflag; int silen = 0; char hostname[MAXHOSTNAMELEN]; char *srflag, *siflag; struct hostent *hst; struct in_addr ia; struct in6_addr ia6; int mib[6]; size_t needed; char *buf, *next, *p; int idx; struct sockaddr_dl *sdl; struct rt_msghdr *rtm; struct if_msghdr *ifm; struct ifa_msghdr *ifam; struct rt_addrinfo info; struct sockaddr_in *sai; struct sockaddr_in6 *sai6; srflag = NULL; siflag = NULL; iflag = sflag = rflag = 0; flag6 = 0; hst = NULL; while ((ch = getopt(argc, argv, "46i:r:s")) != -1) { switch (ch) { case '4': iflag |= HST_IF_V4; break; case '6': iflag |= HST_IF_V6; break; case 'i': siflag = optarg; silen = strlen(siflag); iflag |= HST_IF; break; case 'r': srflag = optarg; rflag = 1; break; case 's': sflag = 1; break; default: usage(); } } argc -= optind; argv += optind; if (argc > 1) usage(); if (iflag && *argv) usage(); if (rflag && *argv) usage(); if (rflag && (iflag & HST_IF)) usage(); if ((iflag & HST_IF_V6) && (iflag & HST_IF_V4)) usage(); if (!(iflag & HST_IF) && ((iflag & HST_IF_V6)||iflag & HST_IF_V4)) usage(); if (iflag & HST_IF) { mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = 0; mib[4] = NET_RT_IFLIST; mib[5] = 0; idx = 0; needed = 1; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) err(1, "sysctl: iflist-sysctl-estimate"); if ((buf = malloc(needed)) == NULL) err(1, "malloc failed"); if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) err(1, "sysctl: retrieval of interface table"); for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)(void *)next; if (rtm->rtm_version != RTM_VERSION) continue; switch (rtm->rtm_type) { case RTM_IFINFO: ifm = (struct if_msghdr *)(void *)rtm; if ((ifm->ifm_addrs & RTA_IFP) == 0) break; sdl = (struct sockaddr_dl *)(ifm + 1); if (silen != sdl->sdl_nlen) break; if (!strncmp(siflag, sdl->sdl_data, silen)) { idx = ifm->ifm_index; } break; case RTM_NEWADDR: ifam = (struct ifa_msghdr *)(void *)rtm; if (ifam->ifam_index == idx) { info.rti_addrs = ifam->ifam_addrs; rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info); sai = (struct sockaddr_in *)info.rti_info[RTAX_IFA]; if (iflag & HST_IF_V6) { if (sai->sin_family == AF_INET6) { sai6 = (struct sockaddr_in6 *)info.rti_info[RTAX_IFA]; hst = gethostbyaddr(&sai6->sin6_addr, sizeof(sai6->sin6_addr),AF_INET6); if (h_errno == NETDB_SUCCESS) { next = buf + needed; continue; } } } else { if ((sai->sin_family == AF_INET)) { hst = gethostbyaddr(&sai->sin_addr, sizeof(sai->sin_addr),AF_INET); if (h_errno == NETDB_SUCCESS) { next = buf + needed; continue; } } } } break; } /* switch */ } /* loop */ free(buf); if (idx == 0) errx(1,"interface not found"); if (hst == NULL) errx(1, "ip not found on interface"); if (h_errno == NETDB_SUCCESS) { if (sethostname(hst->h_name, (int)strlen(hst->h_name))) err(1, "sethostname"); } else if (h_errno == HOST_NOT_FOUND) { errx(1,"hostname not found"); } else { herror("gethostbyaddr"); exit(1); } } else if (rflag) { ret = inet_pton(AF_INET, srflag, &ia); if (ret != 1) { /* check IPV6 */ ret = inet_pton(AF_INET6, srflag, &ia6); if (ret != 1) { errx(1, "invalid ip address"); } flag6 = 1; } if (flag6 == 1) hst = gethostbyaddr(&ia6, sizeof(ia6), AF_INET6); else hst = gethostbyaddr(&ia, sizeof(ia), AF_INET); if (!hst) { if (h_errno == HOST_NOT_FOUND) errx(1,"host not found\n"); } if (sethostname(hst->h_name, (int)strlen(hst->h_name))) err(1, "sethostname"); } else if (*argv) { if (sethostname(*argv, (int)strlen(*argv))) err(1, "sethostname"); } else { if (gethostname(hostname, (int)sizeof(hostname))) err(1, "gethostname"); if (sflag && (p = strchr(hostname, '.'))) *p = '\0'; printf("%s\n", hostname); } exit(0); }
static int get_ifinfo(const char *ifname, ifinfo_t *ifinfo) { uint i; int rc = 0; int ifindex = -1; size_t needed; char *buf = NULL; char *lim = NULL; char *next = NULL; struct if_msghdr *ifm; struct ifa_msghdr *ifam; struct sockaddr_in *sin; struct sockaddr_dl *sdl; struct rt_addrinfo info; char iname[16]; int mib[6]; memset(ifinfo, 0, sizeof(*ifinfo)); /* trim interface name */ for (i = 0; i < sizeof(iname) && ifname[i] && ifname[i] != '/'; i++) iname[i] = ifname[i]; if (i == 0 || i == sizeof(iname)) { report(stderr, GT_("Unable to parse interface name from %s"), ifname); return 0; } iname[i] = 0; /* get list of existing interfaces */ mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = AF_INET; /* Only IP addresses please. */ mib[4] = NET_RT_IFLIST; mib[5] = 0; /* List all interfaces. */ /* Get interface data. */ if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) { report(stderr, GT_("get_ifinfo: sysctl (iflist estimate) failed")); exit(1); } if ((buf = (char *)malloc(needed)) == NULL) { report(stderr, GT_("get_ifinfo: malloc failed")); exit(1); } if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) { report(stderr, GT_("get_ifinfo: sysctl (iflist) failed")); exit(1); } lim = buf+needed; /* first look for the interface information */ next = buf; while (next < lim) { ifm = (struct if_msghdr *)next; next += ifm->ifm_msglen; if (ifm->ifm_version != RTM_VERSION) { report(stderr, GT_("Routing message version %d not understood."), ifm->ifm_version); exit(1); } if (ifm->ifm_type == RTM_IFINFO) { sdl = (struct sockaddr_dl *)(ifm + 1); if (!(strlen(iname) == sdl->sdl_nlen && strncmp(iname, sdl->sdl_data, sdl->sdl_nlen) == 0)) { continue; } if ( !(ifm->ifm_flags & IFF_UP) ) { /* the interface is down */ goto get_ifinfo_end; } ifindex = ifm->ifm_index; ifinfo->rx_packets = ifm->ifm_data.ifi_ipackets; ifinfo->tx_packets = ifm->ifm_data.ifi_opackets; break; } } if (ifindex < 0) { /* we did not find an interface with a matching name */ report(stderr, GT_("No interface found with name %s"), iname); goto get_ifinfo_end; } /* now look for the interface's IP address */ next = buf; while (next < lim) { ifam = (struct ifa_msghdr *)next; next += ifam->ifam_msglen; if (ifindex > 0 && ifam->ifam_type == RTM_NEWADDR && ifam->ifam_index == ifindex) { /* Expand the compacted addresses */ info.rti_addrs = ifam->ifam_addrs; rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info); /* Check for IPv4 address information only */ if (info.rti_info[RTAX_IFA]->sa_family != AF_INET) { continue; } rc = 1; sin = (struct sockaddr_in *)info.rti_info[RTAX_IFA]; if (sin) { ifinfo->addr = sin->sin_addr; } sin = (struct sockaddr_in *)info.rti_info[RTAX_NETMASK]; if (sin) { ifinfo->netmask = sin->sin_addr; } /* note: RTAX_BRD contains the address at the other * end of a point-to-point link or the broadcast address * of non point-to-point link */ sin = (struct sockaddr_in *)info.rti_info[RTAX_BRD]; if (sin) { ifinfo->dstaddr = sin->sin_addr; } break; } } if (rc == 0) { report(stderr, GT_("No IP address found for %s"), iname); } get_ifinfo_end: free(buf); return rc; }
/* * This is the ``callback function'' that is invoked by `sysctl_rtsock' in * order to copy data out. On each invocation, we get a buffer containing: * * + A `struct rt_msghdr'. The `rtm_type' member of this structure should * always be `RTM_GET'. * + A set of zero or more `struct sockaddr's describing the addresses * associated with the route. * * See the function `sysctl_rtsock' for further details. Some of the code * below is modeled after code in the FreeBSD `route' utility; in FreeBSD, see * the file `/usr/src/sbin/route/route.c'. */ static int get_one_ipforward( struct sysctl_req * req, const void * buf, size_t buf_size) { get_ipforward_env_t * env = (get_ipforward_env_t *) req; struct rt_msghdr * rtm = (struct rt_msghdr *) buf; struct rt_addrinfo rtinfo; struct sockaddr_in * sin; oskit_mib_in_addr_t dest; oskit_mib_in_addr_t mask; /* oskit_s32_t policy; */ oskit_mib_in_addr_t next_hop; oskit_s32_t if_index; oskit_u32_t type; oskit_u32_t proto; /* oskit_s32_t age; */ oskit_s32_t next_hop_as; oskit_s32_t metric1; oskit_s32_t metric2; oskit_s32_t metric3; oskit_s32_t metric4; oskit_s32_t metric5; /*********************************************************************/ if (rtm->rtm_version != RTM_VERSION) { /* A message we don't understand? This should never happen. */ assert(!"Received an unknown type of message."); goto done; } if (rtm->rtm_type != RTM_GET) { /* A message we don't understand? This should never happen. */ assert(!"Received an unknown type of message."); goto done; } /* * Figure out what the socket addresses mean; i.e., assign them to the * appropriate elements of the `rtinfo.rti_info' array. */ rtinfo.rti_addrs = rtm->rtm_addrs; rt_xaddrs(((char *) (rtm + 1)), ((char *) rtm) + rtm->rtm_msglen, &rtinfo); /* From `rtinfo', decode the fields of our table row. */ sin = (struct sockaddr_in *) rtinfo.rti_info[RTAX_DST]; if (!sin) /* No destination address?! */ goto done; dest = sin->sin_addr.s_addr; sin = (struct sockaddr_in *) rtinfo.rti_info[RTAX_NETMASK]; if (!sin) /* No network mask?! */ goto done; mask = sin->sin_addr.s_addr; /* * XXX --- RFC 1354 says that this should be an encoding of the IP TOS. * I don't understand how I'm supposed to determine that for a route. * The TOS is associated with a particular socket, not a route, right? */ /* policy = ...; */ if (rtm->rtm_flags & RTF_LOCAL) { next_hop = INADDR_ANY; /* See RFC 1354. */ } else { sin = (struct sockaddr_in *) rtinfo.rti_info[RTAX_GATEWAY]; if (!sin) /* No next hop address?! */ goto done; switch (sin->sin_family) { case AF_INET: next_hop = sin->sin_addr.s_addr; break; case AF_LINK: /* * The gateway address is a link-layer address. This * means that we're talking about one of our own * interfaces. * * RFC 1213 says (for `ipRouteNextHop'): ``In the case * of a route bound to an interface which is realized * via a broadcast media, the value of this field is * the agent's IP address on that interface.'' * * RFC 1354 says (for `ipForwardNextHop'): ``On remote * routes, the address of the next system en route; * Otherwise, 0.0.0.0.'' * * We follow RFC 1354 because we *are* implementing the * `ipForwardTable' after all. Plus, we don't have our * IP address on the interface handy at this point. * (`dest' isn't it. `dest' has had the subnet mask * applied to it, so it's missing parts of our addr.) */ #if 1 next_hop = INADDR_ANY; #else sdl = (struct sockaddr_dl *) sin; switch (sdl->sdl_type) { case IFT_ETHER: /* List other broadcast media here. */ next_hop = /* Our IP address. Not `dest'. */; break; default: next_hop = INADDR_ANY; break; } #endif break; default: assert(!"Received an unrecognized kind of next-hop"); next_hop = INADDR_ANY; break; } } if_index = rtm->rtm_index; type = ((rtm->rtm_flags & RTF_GATEWAY) ? OSKIT_MIB_IP_FORWARD_TYPE_REMOTE : OSKIT_MIB_IP_FORWARD_TYPE_LOCAL); proto = ((rtm->rtm_flags & RTF_LOCAL) ? OSKIT_MIB_IP_FORWARD_PROTO_LOCAL : (rtm->rtm_flags & RTF_DYNAMIC) ? OSKIT_MIB_IP_FORWARD_PROTO_ICMP : (rtm->rtm_flags & RTF_STATIC) ? OSKIT_MIB_IP_FORWARD_PROTO_NETMGMT : OSKIT_MIB_IP_FORWARD_PROTO_OTHER ); /* XXX --- I don't believe that route age is stored anywhere. */ /* age = ...; */ next_hop_as = 0; /* See IETF RFC 1354. */ /* * XXX --- I don't really understand the semantics of these values; * e.g., are they supposed to have well-defined meanings? I've just * picked the most interesting set of metrics from our route info. */ metric1 = (rtm->rtm_flags & RTF_UP); /* Is this route usable? */ metric2 = rtm->rtm_rmx.rmx_hopcount; /* Max hops expected. */ metric3 = rtm->rtm_rmx.rmx_sendpipe; /* Out delay-b'width product */ metric4 = rtm->rtm_rmx.rmx_rtt; /* Estimated round trip time */ metric5 = rtm->rtm_rmx.rmx_rttvar; /* Estimated RTT variance. */ /*********************************************************************/ /* * Process the entry. */ if (ipforward_match(dest, mask, /* policy, */ next_hop, if_index, type, proto, /* age, */ next_hop_as, metric1, metric2, metric3, metric4, metric5, env->args.matching)) { if (env->args.start_row > 0) { /* Skip this row. */ env->args.start_row--; } else if (env->args.want_rows > 0) { /* Accumulate this row. */ #define COPY_OUT(slot_type, slot_name) \ oskit_mib_##slot_type##_set( \ &(env->args.table->ip_forward_##slot_name), \ slot_name) #define CLEAR_OUT(slot_type, slot_name) \ oskit_mib_##slot_type##_clear( \ &(env->args.table->ip_forward_##slot_name)) COPY_OUT(mib_in_addr, dest); COPY_OUT(mib_in_addr, mask); CLEAR_OUT(s32, policy); /* XXX */ COPY_OUT(mib_in_addr, next_hop); COPY_OUT(s32, if_index); COPY_OUT(u32, type); COPY_OUT(u32, proto); CLEAR_OUT(s32, age); /* XXX */ COPY_OUT(s32, next_hop_as); COPY_OUT(s32, metric1); COPY_OUT(s32, metric2); COPY_OUT(s32, metric3); COPY_OUT(s32, metric4); COPY_OUT(s32, metric5); #undef COPY_OUT (*env->args.out_rows)++; env->args.table++; env->args.want_rows--; } else { /* Indicate that the table filled up. */ *env->args.more_rows = 1; } } done: /* Indicate to the `sysctl_rtsock' function that no error occurred. */ return 0; }
/* * This is the ``callback function'' that is invoked by `sysctl_rtsock' in * order to copy data out. See the comments before `get_one_ipaddr' for * general information about the data we receive on each callback. */ static int get_one_ipnettomedia( struct sysctl_req * req, const void * buf, size_t buf_size) { get_ipnettomedia_env_t * env = (get_ipnettomedia_env_t *) req; struct ifa_msghdr * ifam = (struct ifa_msghdr *) buf; struct rt_addrinfo rtinfo; struct sockaddr_in * sin; oskit_u32_t if_index; /* oskit_mib_string_t phys_address; --- not needed. */ oskit_mib_in_addr_t net_address; oskit_u32_t type; /*********************************************************************/ /* * We get physical addresses from `RTM_IFINFO' messages, and we get IP * addresses from subsequent `RTM_NEWADDR' messages. Note that there * may be more than one IP address per interface. * */ if (ifam->ifam_type == RTM_IFINFO) { struct if_msghdr * ifm = (struct if_msghdr *) buf; struct sockaddr_dl * sdl = (struct sockaddr_dl *) (ifm+1); extract_phys_address(sdl, env); DEBUG_SET_STATE((env->state = SEEN_IFINFO)); goto done; } if (ifam->ifam_type != RTM_NEWADDR) { assert(!"Received an unknown type of message."); goto done; } DEBUG_CHECK_STATE((env->state == SEEN_IFINFO)); /*********************************************************************/ /* If we don't have a valid physical address, bail early. */ if (!env->phys_address.str) goto done; /* * Figure out what the socket addresses mean; i.e., assign them to the * appropriate elements of the `rtinfo.rti_info' array. */ rtinfo.rti_addrs = ifam->ifam_addrs; rt_xaddrs(((char *) (ifam + 1)), ((char *) ifam) + ifam->ifam_msglen, &rtinfo); /* * From `env->phys_address' and `rtinfo', decode the fields of our * table row. */ if_index = ifam->ifam_index; /* phys_address = env->phys_address; --- why bother? */ sin = (struct sockaddr_in *) rtinfo.rti_info[RTAX_IFA]; if (!sin) /* No interface address?! */ goto done; net_address = sin->sin_addr.s_addr; /* * XXX --- Perhaps this isn't right, but I'm not sure what is. The * UCD-SNMP code returns `static' for permanent ARP cache entries and * `dynamic' for others. But that doesn't seem right: what exactly is * dynamic about a host's own IP-->Ethernet mappings? */ type = OSKIT_MIB_IP_NET_TO_MEDIA_TYPE_STATIC; /*********************************************************************/ /* * Process the entry. */ if (ipnettomedia_match(if_index, env->phys_address, net_address, type, env->args.matching)) { if (env->args.start_row > 0) { /* Skip this row. */ env->args.start_row--; } else if (env->args.want_rows > 0) { /* Accumulate this row. */ #define COPY_OUT(slot_type, slot_name) \ oskit_mib_##slot_type##_set( \ &(env->args.table->ip_net_to_media_##slot_name), \ slot_name) COPY_OUT(u32, if_index); copy_out_str(&(env->args.table-> ip_net_to_media_phys_address), &(env->phys_address)); COPY_OUT(mib_in_addr, net_address); COPY_OUT(u32, type); #undef COPY_OUT (*env->args.out_rows)++; env->args.table++; env->args.want_rows--; } else { /* Indicate that the table filled up. */ *env->args.more_rows = 1; } } done: /* Indicate to the `sysctl_rtsock' function that no error occurred. */ return 0; }
/* * This is the ``callback function'' that is invoked by `sysctl_rtsock' in * order to copy data out. The data that is given to us is as follows: * * + First, we are called with a buffer containing a `struct if_msghdr', with * the type member set to `RTM_IFINFO'. This signals the start of a group * of callbacks about a particular interface. The `if_msghdr' is followed * by zero of more `struct sockaddr_dl's (in the same buffer). * * + Subsequent callbacks will receive a `struct ifa_msghdr' (with its type * member set to `RTM_NEWADDR') followed immediatley by zero or more * `struct sockaddr_in's. This describes a particular group of (IP) * addresses for an interface. * * These callbacks are performed one for each interface. I.e., for each * interface, we will receive a `RTM_IFINFO' callback followed by zero or more * `RTM_NEWADDR' callbacks. * * See the function `sysctl_rtsock' for further details. Some of the code * below is modeled after code in the FreeBSD `ifconfig' utility; in FreeBSD, * see the file `/usr/src/sbin/ifconfig/ifconfig.c'. */ static int get_one_ipaddr( struct sysctl_req * req, const void * buf, size_t buf_size) { get_ipaddr_env_t * env = (get_ipaddr_env_t *) req; struct ifa_msghdr * ifam = (struct ifa_msghdr *) buf; struct rt_addrinfo rtinfo; struct sockaddr_in * sin; oskit_mib_in_addr_t addr; oskit_u32_t if_index; oskit_mib_in_addr_t net_mask; oskit_u32_t bcast_addr; oskit_u16_t reasm_max_size; /*********************************************************************/ /* * Mainly, we care about `RTM_NEWADDR' messages. Each of these * messages contains a `struct ifa_msghdr' followed by a set of socket * addresses (`struct sockaddr_in's). * * We need `RTM_IFINFO' messages only to set our `env->ifinfo_flags'. * One of these messages contains a `struct if_msghdr' (followed by a * set of `struct sockaddr_dl's, which we don't care about here). */ if (ifam->ifam_type == RTM_IFINFO) { env->ifinfo_flags = ((struct if_msghdr *) buf)->ifm_flags; DEBUG_SET_STATE((env->state = SEEN_IFINFO)); goto done; } if (ifam->ifam_type != RTM_NEWADDR) { assert(!"Received an unknown type of message."); goto done; } DEBUG_CHECK_STATE((env->state == SEEN_IFINFO)); /*********************************************************************/ /* * Figure out what the socket addresses mean; i.e., assign them to the * appropriate elements of the `rtinfo.rti_info' array. */ rtinfo.rti_addrs = ifam->ifam_addrs; rt_xaddrs(((char *) (ifam + 1)), ((char *) ifam) + ifam->ifam_msglen, &rtinfo); /* * From `rtinfo', decode the fields of our table row. */ sin = (struct sockaddr_in *) rtinfo.rti_info[RTAX_IFA]; if (!sin) /* No interface address?! */ goto done; addr = sin->sin_addr.s_addr; if_index = ifam->ifam_index; sin = (struct sockaddr_in *) rtinfo.rti_info[RTAX_NETMASK]; if (!sin) /* No network mask?! */ goto done; net_mask = sin->sin_addr.s_addr; /* XXX --- Default `bcast_addr' to one. */ bcast_addr = 1; /* * For point-to-point links, `rti_info[RTAX_BRD]' holds the destination * address. So, one must check for the `IFF_BROADCAST' flag. */ if (env->ifinfo_flags & IFF_BROADCAST) { sin = (struct sockaddr_in *) rtinfo.rti_info[RTAX_BRD]; if (sin) bcast_addr = (ntohl(sin->sin_addr.s_addr) & 1); } /* * I'm pretty sure that the `reasm_max_size' is `IP_MAXPACKET' for all * interfaces. */ reasm_max_size = IP_MAXPACKET; /*********************************************************************/ /* * Process the entry. */ if (ipaddr_match(addr, if_index, net_mask, bcast_addr, reasm_max_size, env->args.matching)) { if (env->args.start_row > 0) { /* Skip this row. */ env->args.start_row--; } else if (env->args.want_rows > 0) { /* Accumulate this row. */ #define COPY_OUT(slot_type, slot_name) \ oskit_mib_##slot_type##_set( \ &(env->args.table->ip_ad_ent_##slot_name), \ slot_name) COPY_OUT(mib_in_addr, addr); COPY_OUT(u32, if_index); COPY_OUT(mib_in_addr, net_mask); COPY_OUT(u32, bcast_addr); COPY_OUT(u16, reasm_max_size); #undef COPY_OUT (*env->args.out_rows)++; env->args.table++; env->args.want_rows--; } else { /* Indicate that the table filled up. */ *env->args.more_rows = 1; } } done: /* Indicate to the `sysctl_rtsock' function that no error occurred. */ return 0; }