int main(int argc, char **argv) { int sockfd; char *buf; pid_t pid; ssize_t n; struct rt_msghdr *rtm; struct sockaddr *sa, *rti_info[RTAX_MAX]; struct sockaddr_in *sin; if (argc != 2) err_quit("usage: getrt <IPaddress>"); sockfd = Socket(AF_ROUTE, SOCK_RAW, 0); /* need superuser privileges */ buf = Calloc(1, BUFLEN); /* and initialized to 0 */ rtm = (struct rt_msghdr *) buf; rtm->rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in); rtm->rtm_version = RTM_VERSION; rtm->rtm_type = RTM_GET; rtm->rtm_addrs = RTA_DST; rtm->rtm_pid = pid = getpid(); rtm->rtm_seq = SEQ; sin = (struct sockaddr_in *) (rtm + 1); sin->sin_len = sizeof(struct sockaddr_in); sin->sin_family = AF_INET; Inet_pton(AF_INET, argv[1], &sin->sin_addr); Write(sockfd, rtm, rtm->rtm_msglen); do { n = Read(sockfd, rtm, BUFLEN); } while (rtm->rtm_type != RTM_GET || rtm->rtm_seq != SEQ || rtm->rtm_pid != pid); /* end getrt1 */ /* include getrt2 */ rtm = (struct rt_msghdr *) buf; sa = (struct sockaddr *) (rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); if ( (sa = rti_info[RTAX_DST]) != NULL) printf("dest: %s\n", Sock_ntop_host(sa, sa->sa_len)); if ( (sa = rti_info[RTAX_GATEWAY]) != NULL) printf("gateway: %s\n", Sock_ntop_host(sa, sa->sa_len)); if ( (sa = rti_info[RTAX_NETMASK]) != NULL) printf("netmask: %s\n", Sock_masktop(sa, sa->sa_len)); if ( (sa = rti_info[RTAX_GENMASK]) != NULL) printf("genmask: %s\n", Sock_masktop(sa, sa->sa_len)); exit(0); }
struct in6_addr * get_addr(char *buf) { struct rt_msghdr *rtm = (struct rt_msghdr *)buf; struct sockaddr *sa, *rti_info[RTAX_MAX]; sa = (struct sockaddr *)(rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); return (&SIN6(rti_info[RTAX_DST])->sin6_addr); }
struct sockaddr_dl * if_nametosdl(char *name) { int mib[6] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; char *buf, *next, *lim; size_t len; struct if_msghdr *ifm; struct sockaddr *sa, *rti_info[RTAX_MAX]; struct sockaddr_dl *sdl = NULL, *ret_sdl; if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) return(NULL); if ((buf = malloc(len)) == NULL) return(NULL); if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { free(buf); return (NULL); } lim = buf + len; for (next = buf; next < lim; next += ifm->ifm_msglen) { ifm = (struct if_msghdr *)next; if (ifm->ifm_type == RTM_IFINFO) { sa = (struct sockaddr *)(ifm + 1); get_rtaddrs(ifm->ifm_addrs, sa, rti_info); if ((sa = rti_info[RTAX_IFP]) != NULL) { if (sa->sa_family == AF_LINK) { sdl = (struct sockaddr_dl *)sa; if (strlen(name) != sdl->sdl_nlen) continue; /* not same len */ if (strncmp(&sdl->sdl_data[0], name, sdl->sdl_nlen) == 0) { break; } } } } } if (next == lim) { /* search failed */ free(buf); return (NULL); } if ((ret_sdl = malloc(sdl->sdl_len)) == NULL) { free(buf); return (NULL); } memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len); free(buf); return (ret_sdl); }
int get_rtm_ifindex(char *buf) { struct rt_msghdr *rtm = (struct rt_msghdr *)buf; struct sockaddr *sa, *rti_info[RTAX_MAX]; sa = (struct sockaddr *)(rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); return (((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index); }
int get_prefixlen(char *buf) { struct rt_msghdr *rtm = (struct rt_msghdr *)buf; struct sockaddr *sa, *rti_info[RTAX_MAX]; char *p, *lim; sa = (struct sockaddr *)(rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); sa = rti_info[RTAX_NETMASK]; p = (char *)(&SIN6(sa)->sin6_addr); lim = (char *)sa + sa->sa_len; return prefixlen(p, lim); }
unsigned int if_nametoindex(const char *name) { unsigned int idx, namelen; char *buf, *next, *lim; size_t len; struct if_msghdr *ifm; struct sockaddr *sa, *rti_info[RTAX_MAX]; struct sockaddr_dl *sdl; // 获取接口列表 if ((buf = net_rt_iflist(0, 0, &len)) == NULL) { return(0); } // 查找符合给定名称的接口,并返回其索引 namelen = strlen(name); lim = buf + len; for (next = buf; next < lim; next += ifm->ifm_msglen) { ifm = (struct if_msghdr *) next; if (ifm->ifm_type == RTM_IFINFO) { sa = (struct sockaddr *) (ifm + 1); get_rtaddrs(ifm->ifm_addrs, sa, rti_info); if ((sa = rti_info[RTAX_IFP]) != NULL) { if (sa->sa_family == AF_LINK) { sdl = (struct sockaddr_d *) sa; if (sdl->sdl_nlen == namelen && strncmp(&sdl->sdl_data[0], name, sdl->sdl_nlen) == 0) { idx = sdl->sdl_index; // save before free() free(buf); return(idx); } } } } } free(buf); return(0); // no match for name }
// interface name to index unsigned int if_nametoindex(const char *name) { unsigned int index; char *buf, *next, *lim; size_t len; struct if_msghdr *ifm; struct sockaddr *sa, *rti_info[RTAX_MAX]; struct sockaddr_dl *sdl; if ((buf = net_rt_iflist(0, 0, &len)) == NULL) return 0; lim = buf + len; for (next = buf; next < lim; next += ifm->ifm_msglen) { ifm = (struct if_msghdr *) next; if (ifm->ifm_type == RTM_IFINFO) { sa = (struct sockaddr *) (ifm + 1); get_rtaddrs(ifm->ifm_addrs, sa, rti_info); if ((sa = rti_info[RTAX_IFP]) != NULL) { if (sa->sa_family == AF_LINK) { sdl = (struct sockaddr_dl *) sa; if (strncmp(&sdl->sdl_data[0], name, sdl->sdl_nlen) == 0) { index = sdl->sdl_index; free(buf); return index; } } } } } free(buf); return 0; }
char * if_indextoname(unsigned int idx, char *name) { char *buf, *next, *lim; size_t len; struct if_msghdr *ifm; struct sockaddr *sa, *rti_info[RTAX_MAX]; struct sockaddr_dl *sdl; if ( (buf = net_rt_iflist(0, idx, &len)) == NULL) return(NULL); lim = buf + len; for (next = buf; next < lim; next += ifm->ifm_msglen) { ifm = (struct if_msghdr *) next; if (ifm->ifm_type == RTM_IFINFO) { sa = (struct sockaddr *) (ifm + 1); get_rtaddrs(ifm->ifm_addrs, sa, rti_info); if ( (sa = rti_info[RTAX_IFP]) != NULL) { if (sa->sa_family == AF_LINK) { sdl = (struct sockaddr_dl *) sa; if (sdl->sdl_index == idx) { int slen = min(IFNAMSIZ - 1, sdl->sdl_nlen); strncpy(name, sdl->sdl_data, slen); name[slen] = 0; /* null terminate */ free(buf); return(name); } } } } } free(buf); return(NULL); /* no match for index */ }
struct sockaddr_in *default_gw() { int mib[6]; size_t needed; char *buf, *next, *lim; struct rt_msghdr2 *rtm; struct sockaddr *sa; struct sockaddr *rti_info[RTAX_MAX]; struct sockaddr_in *sin; bool found = false; mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = 0; mib[4] = NET_RT_DUMP2; mib[5] = 0; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { err(1, "sysctl: net.route.0.0.dump estimate"); } buf = malloc(needed); if (buf == 0) { err(2, "malloc"); } if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { err(1, "sysctl: net.route.0.0.dump"); } lim = buf + needed; for (next = buf; next < lim; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr2 *)next; sa = (struct sockaddr *)(rtm + 1); if (sa->sa_family == AF_INET) { sin = (struct sockaddr_in *)sa; struct sockaddr addr, mask; get_rtaddrs(rtm->rtm_addrs, sa, rti_info); bzero(&addr, sizeof(addr)); if (rtm->rtm_addrs & RTA_DST) bcopy(rti_info[RTAX_DST], &addr, rti_info[RTAX_DST]->sa_len); bzero(&mask, sizeof(mask)); if (rtm->rtm_addrs & RTA_NETMASK) bcopy(rti_info[RTAX_NETMASK], &mask, rti_info[RTAX_NETMASK]->sa_len); if (rtm->rtm_addrs & RTA_GATEWAY && is_default_route(&addr, &mask)) { if (rti_info[RTAX_GATEWAY]) { struct sockaddr_in *rti_sin = (struct sockaddr_in *)rti_info[RTAX_GATEWAY]; sin = (struct sockaddr_in *)(malloc(sizeof(struct sockaddr_in))); sin->sin_family = rti_sin->sin_family; sin->sin_port = rti_sin->sin_port; sin->sin_addr.s_addr = rti_sin->sin_addr.s_addr; memcpy(sin, rti_info[RTAX_GATEWAY], sizeof(struct sockaddr_in)); found = true; break; } } } rtm = (struct rt_msghdr2 *)next; } free(buf); return (found ? sin : NULL); }
void print_routing(char *proto) { int mib[6]; int i = 0; int rt_len; int if_len; int if_num; char *rt_buf; char *if_buf; char *next; char *lim; struct rt_msghdr *rtm; struct if_msghdr *ifm; struct if_msghdr **ifm_table; struct ifa_msghdr *ifam; struct sockaddr *sa; struct sockaddr *sa1; struct sockaddr *rti_info[RTAX_MAX]; struct sockaddr **if_table; struct rt_metrics rm; char fbuf[50]; /* keep a copy of statistics here for future use */ static unsigned *base_stats = NULL ; static unsigned base_len = 0 ; /* Get the routing table */ mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = 0; mib[4] = NET_RT_DUMP; mib[5] = 0; /*Estimate the size of table */ if (sysctl(mib, 6, NULL, &rt_len, NULL, 0) == -1) { perror("sysctl size"); exit(-1); } if ((rt_buf = (char *)malloc(rt_len)) == NULL) { perror("malloc"); exit(-1); } /* Now get it. */ if (sysctl(mib, 6, rt_buf, &rt_len, NULL, 0) == -1) { perror("sysctl get"); exit(-1); } /* Get the interfaces table */ mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = 0; mib[4] = NET_RT_IFLIST; mib[5] = 0; /* Estimate the size of table */ if (sysctl(mib, 6, NULL, &if_len, NULL, 0) == -1) { perror("sysctl size"); exit(-1); } if ((if_buf = (char *)malloc(if_len)) == NULL) { perror("malloc"); exit(-1); } /* Now get it. */ if (sysctl(mib, 6, if_buf, &if_len, NULL, 0) == -1) { perror("sysctl get"); exit(-1); } lim = if_buf + if_len; i = 0; for (next = if_buf, i = 0; next < lim; next += ifm->ifm_msglen) { ifm = (struct if_msghdr *)next; i++; } if_num = i; if_table = (struct sockaddr **)calloc(i, sizeof(struct sockaddr)); ifm_table = (struct if_msghdr **)calloc(i, sizeof(struct if_msghdr)); if (iflag) { printf("\nInterface table:\n"); printf("----------------\n"); printf("Name Mtu Network Address " "Ipkts Ierrs Opkts Oerrs Coll\n"); } /* scan the list and store base values */ i = 0 ; for (next = if_buf; next < lim; next += ifm->ifm_msglen) { ifm = (struct if_msghdr *)next; i++ ; } if (base_stats == NULL || i != base_len) { base_stats = calloc(i*5, sizeof(unsigned)); base_len = i ; } i = 0; for (next = if_buf; next < lim; next += ifm->ifm_msglen) { ifm = (struct if_msghdr *)next; if_table[i] = (struct sockaddr *)(ifm + 1); ifm_table[i] = ifm; sa = if_table[i]; if (iflag && sa->sa_family == AF_LINK) { struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; unsigned *bp = &base_stats[i*5]; printf("%-4s %-5d <Link> ", sock_ntop(if_table[i], if_table[i]->sa_len), ifm->ifm_data.ifi_mtu); if (sdl->sdl_alen == 6) { unsigned char *p = sdl->sdl_data + sdl->sdl_nlen; printf("%02x:%02x:%02x:%02x:%02x:%02x ", p[0], p[1], p[2], p[3], p[4], p[5]); } else printf(" "); printf("%9d%6d%9d%6d%6d\n", ifm->ifm_data.ifi_ipackets - bp[0], ifm->ifm_data.ifi_ierrors - bp[1], ifm->ifm_data.ifi_opackets - bp[2], ifm->ifm_data.ifi_oerrors - bp[3], ifm->ifm_data.ifi_collisions -bp[4]); if (delta > 0) { bp[0] = ifm->ifm_data.ifi_ipackets ; bp[1] = ifm->ifm_data.ifi_ierrors ; bp[2] = ifm->ifm_data.ifi_opackets ; bp[3] = ifm->ifm_data.ifi_oerrors ; bp[4] = ifm->ifm_data.ifi_collisions ; } } i++; } if (!rflag) { free(rt_buf); free(if_buf); free(if_table); free(ifm_table); return; } /* Now dump the routing table */ printf("\nRouting table:\n"); printf("--------------\n"); printf ("Destination Gateway Flags Netif Use\n"); lim = rt_buf + rt_len; for (next = rt_buf; next < lim; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; sa = (struct sockaddr *)(rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); if ((sa = rti_info[RTAX_DST]) != NULL) { sprintf(fbuf, "%s", sock_ntop(sa, sa->sa_len)); if (((sa1 = rti_info[RTAX_NETMASK]) != NULL) && sa1->sa_family == 255) { strcat(fbuf, sock_ntop(sa1, sa1->sa_len)); } printf("%-19s", fbuf); } if ((sa = rti_info[RTAX_GATEWAY]) != NULL) { printf("%-19s", sock_ntop(sa, sa->sa_len)); } memset(fbuf, 0, sizeof(fbuf)); get_flags(fbuf, rtm->rtm_flags); printf("%-10s", fbuf); for (i = 0; i < if_num; i++) { ifm = ifm_table[i]; if ((ifm->ifm_index == rtm->rtm_index) && (ifm->ifm_data.ifi_type > 0)) { sa = if_table[i]; break; } } if (ifm->ifm_type == RTM_IFINFO) { get_rtaddrs(ifm->ifm_addrs, sa, rti_info); printf(" %s", Sock_ntop(sa, sa->sa_len)); } else if (ifm->ifm_type == RTM_NEWADDR) { ifam = (struct ifa_msghdr *)ifm_table[rtm->rtm_index - 1]; sa = (struct sockaddr *)(ifam + 1); get_rtaddrs(ifam->ifam_addrs, sa, rti_info); printf(" %s", Sock_ntop(sa, sa->sa_len)); } /* printf(" %u", rtm->rtm_use); */ printf("\n"); } free(rt_buf); free(if_buf); free(if_table); free(ifm_table); }
int fetchifs(int ifindex) { size_t len; int mib[6]; char *buf, *next, *lim; struct if_msghdr ifm; struct kif_node *kif; struct sockaddr *sa, *rti_info[RTAX_MAX]; struct sockaddr_dl *sdl; mib[0] = CTL_NET; mib[1] = AF_ROUTE; mib[2] = 0; mib[3] = AF_INET; mib[4] = NET_RT_IFLIST; mib[5] = ifindex; if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) { log_warn("sysctl"); return (-1); } if ((buf = malloc(len)) == NULL) { log_warn("fetchif"); return (-1); } if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) { log_warn("sysctl"); free(buf); return (-1); } lim = buf + len; for (next = buf; next < lim; next += ifm.ifm_msglen) { memcpy(&ifm, next, sizeof(ifm)); if (ifm.ifm_version != RTM_VERSION) continue; if (ifm.ifm_type != RTM_IFINFO) continue; sa = (struct sockaddr *)(next + sizeof(ifm)); get_rtaddrs(ifm.ifm_addrs, sa, rti_info); if ((kif = calloc(1, sizeof(struct kif_node))) == NULL) { log_warn("fetchifs"); free(buf); return (-1); } kif->k.ifindex = ifm.ifm_index; kif->k.flags = ifm.ifm_flags; kif->k.link_state = ifm.ifm_data.ifi_link_state; kif->k.media_type = ifm.ifm_data.ifi_type; kif->k.baudrate = ifm.ifm_data.ifi_baudrate; kif->k.mtu = ifm.ifm_data.ifi_mtu; if ((sa = rti_info[RTAX_IFP]) != NULL) if (sa->sa_family == AF_LINK) { sdl = (struct sockaddr_dl *)sa; if (sdl->sdl_nlen >= sizeof(kif->k.ifname)) memcpy(kif->k.ifname, sdl->sdl_data, sizeof(kif->k.ifname) - 1); else if (sdl->sdl_nlen > 0) memcpy(kif->k.ifname, sdl->sdl_data, sdl->sdl_nlen); /* string already terminated via calloc() */ } kif_insert(kif); } free(buf); return (0); }
int get_bind_addr(bin_addr *dest, struct addrinfo *ba) { /* list interface name/address * fixed size buffer limits number of recognizable interfaces. * buf size = sizeof(struct ifreq) * 256 interface = 8192 */ int i, ent, sockfd, len; char *ptr, buf[sizeof(struct ifreq) * MAXNUM_IF]; struct ifconf ifc; struct ifreq *ifr; struct sockaddr_in *sinptr; struct if_list ifl[MAXNUM_IF]; pid_t pid; ssize_t n; struct rt_msghdr *rtm; struct sockaddr *sa, *rti_info[RTAX_MAX]; struct sockaddr_in *sin; struct sockaddr_dl *sdl; struct in_addr ia; struct addrinfo hints, *res, *res0; int error; char host[256]; int found = 0; /* IPv6 routing is not implemented yet */ switch (dest->atype) { case S5ATIPV4: memcpy(&ia, &(dest->v4_addr), 4); break; case S5ATIPV6: return -1; case S5ATFQDN: memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_INET; memcpy(host, &dest->fqdn, dest->len_fqdn); host[dest->len_fqdn] = '\0'; error = getaddrinfo(host, NULL, &hints, &res0); if (error) { return -1; } for (res = res0; res; res = res->ai_next) { if (res->ai_family != AF_INET) continue; sin = (struct sockaddr_in *)res->ai_addr; memcpy(&ia, &(sin->sin_addr), sizeof(ia)); found++; break; } freeaddrinfo(res0); if (!found) return -1; break; default: return -1; } sockfd = socket(AF_INET, SOCK_DGRAM, 0); ifc.ifc_len = sizeof(buf); ifc.ifc_req = (struct ifreq *) buf; ioctl(sockfd, SIOCGIFCONF, &ifc); close(sockfd); i = ent = 0; for (ptr = buf; ptr < buf + ifc.ifc_len; ) { ifr = (struct ifreq *) ptr; len = sizeof(struct sockaddr); #ifdef HAVE_SOCKADDR_SA_LEN if (ifr->ifr_addr.sa_len > len) len = ifr->ifr_addr.sa_len; /* length > 16 */ #endif ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */ switch (ifr->ifr_addr.sa_family) { case AF_INET: strncpy(ifl[i].if_name, ifr->ifr_name, IFNAMSIZ); sinptr = (struct sockaddr_in *) &ifr->ifr_addr; memcpy(&ifl[i].if_addr, &sinptr->sin_addr, sizeof(struct in_addr)); i++; break; default: break; } } ent = i; /* number of interfaces */ /* get routing */ setreuid(PROCUID, 0); sockfd = socket(AF_ROUTE, SOCK_RAW, 0); /* need superuser privileges */ setreuid(0, PROCUID); if (sockfd < 0) { /* socket error */ return(-1); } memset(buf, 0, sizeof buf); rtm = (struct rt_msghdr *) buf; rtm->rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in) + sizeof(struct sockaddr_dl); rtm->rtm_version = RTM_VERSION; rtm->rtm_type = RTM_GET; rtm->rtm_addrs = RTA_DST|RTA_IFP; rtm->rtm_pid = pid = getpid(); rtm->rtm_seq = SEQ; sin = (struct sockaddr_in *) (buf + sizeof(struct rt_msghdr)); sin->sin_family = AF_INET; #ifdef HAVE_SOCKADDR_SA_LEN sin->sin_len = sizeof(struct sockaddr_in); #endif memcpy(&(sin->sin_addr), &ia, sizeof(struct in_addr)); #ifdef HAVE_SOCKADDR_SA_LEN sa = (struct sockaddr *)sin; NEXT_SA(sa); sdl = (struct sockaddr_dl *)sa; sdl->sdl_len = sizeof(struct sockaddr_dl); #else sdl = (struct sockaddr_dl *) (buf + ROUNDUP(sizeof(struct rt_msghdr), sizeof(u_long)) + ROUNDUP(sizeof(struct sockaddr_in), sizeof(u_long))); #endif sdl->sdl_family = AF_LINK; write(sockfd, rtm, rtm->rtm_msglen); do { n = read(sockfd, rtm, sizeof buf); } while (rtm->rtm_type != RTM_GET || rtm->rtm_seq != SEQ || rtm->rtm_pid != pid); close(sockfd); rtm = (struct rt_msghdr *) buf; sa = (struct sockaddr *) (rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); ba->ai_family = AF_INET; /* IPv4 */ ba->ai_socktype = SOCK_STREAM; ba->ai_protocol = IPPROTO_TCP; sin = (struct sockaddr_in *)ba->ai_addr; sin->sin_family = AF_INET; #ifdef HAVE_SOCKADDR_SA_LEN sin->sin_len = sizeof(struct sockaddr_in); #endif ba->ai_addrlen = sizeof(struct sockaddr_in); if ( (sa = rti_info[RTAX_IFP]) != NULL) { sdl = (struct sockaddr_dl *)sa; if (sdl->sdl_nlen > 0) { for (i=0; i<ent; i++) { if (memcmp(ifl[i].if_name, sdl->sdl_data, sdl->sdl_nlen) == 0) { memcpy(&sin->sin_addr, &ifl[i].if_addr, sizeof(struct in_addr)); return(0); } } } } return(-1); }
void refresh_netif_metrics(void) { int sts; static int name[] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; u_int namelen = sizeof(name) / sizeof(name[0]); static size_t buflen = 0; static char *buf = NULL; char *bufend; char *next; size_t new_buflen; struct rt_msghdr *rtm; struct if_msghdr *ifm; struct if_data *ifd = NULL; struct sockaddr *sa; struct sockaddr *rti_info[RTAX_MAX]; struct sockaddr_dl *sdl; char if_name[IF_NAMESIZE]; if (valid == -1) { /* one-trip reload */ pmdaCacheOp(indomtab[NETIF_INDOM].it_indom, PMDA_CACHE_LOAD); } else { /* * Not sure that the order of chained netif structs is invariant, * especially if interfaces are added to the configuration after * initial system boot ... so mark all the instances as inactive * and re-match based on the interface name */ pmdaCacheOp(indomtab[NETIF_INDOM].it_indom, PMDA_CACHE_INACTIVE); } valid = 0; /* get number of if_data structs available */ if ((sts = sysctl(name, namelen, NULL, &new_buflen, NULL, 0)) != 0) { fprintf(stderr, "refresh_netif_metrics: new_buflen sysctl(): %s\n", strerror(errno)); return; } if (new_buflen != buflen) { /* * one trip ... not sure if it can change thereafter, but just * in case */ if (buf != NULL) free(buf); buf = (char *)malloc(new_buflen); if (buf == NULL) { __pmNoMem("refresh_disk_metrics: stats", new_buflen, PM_FATAL_ERR); /* NOTREACHED */ } buflen = new_buflen; } if ((sts = sysctl(name, namelen, buf, &buflen, NULL, 0)) != 0) { fprintf(stderr, "refresh_netif_metrics: buf sysctl(): %s\n", strerror(errno)); return; } bufend = buf + buflen; for (next = buf; next < bufend; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; if (rtm->rtm_version != RTM_VERSION) continue; switch (rtm->rtm_type) { case RTM_IFINFO: ifm = (struct if_msghdr *)next; ifd = &ifm->ifm_data; sa = (struct sockaddr *)(ifm + 1); get_rtaddrs(ifm->ifm_addrs, sa, rti_info); sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; if (sdl == NULL || sdl->sdl_family != AF_LINK) continue; if (sdl->sdl_nlen < IF_NAMESIZE) { memcpy(if_name, sdl->sdl_data, sdl->sdl_nlen); if_name[sdl->sdl_nlen] = '\0'; } else { memcpy(if_name, sdl->sdl_data, IF_NAMESIZE-1); if_name[IF_NAMESIZE-1] = '\0'; } /* skip network interfaces that are not interesting ... */ if (strcmp(if_name, "lo0") == 0) continue; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { sts = pmdaCacheLookupName(indomtab[NETIF_INDOM].it_indom, if_name, NULL, NULL); if (sts < 0) fprintf(stderr, "Info: found network interface %s\n", if_name); } #endif if ((sts = pmdaCacheStore(indomtab[NETIF_INDOM].it_indom, PMDA_CACHE_ADD, if_name, (void *)ifm)) < 0) { fprintf(stderr, "refresh_netif_metrics: pmdaCacheStore(%s) failed: %s\n", if_name, pmErrStr(sts)); continue; } valid++; break; } } if (valid) pmdaCacheOp(indomtab[NETIF_INDOM].it_indom, PMDA_CACHE_SAVE); }
static void fetchifs(void) { struct if_msghdr ifm; int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; struct rt_msghdr *rtm; struct if_data *ifd; struct sockaddr *sa, *rti_info[RTAX_MAX]; struct sockaddr_dl *sdl; char *buf, *next, *lim; char name[IFNAMSIZ]; size_t len; int takeit = 0; int foundone = 0; if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) err(1, "sysctl"); if ((buf = malloc(len)) == NULL) err(1, NULL); if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) err(1, "sysctl"); memset(&ip_cur, 0, sizeof(ip_cur)); lim = buf + len; for (next = buf; next < lim; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; if (rtm->rtm_version != RTM_VERSION) continue; switch (rtm->rtm_type) { case RTM_IFINFO: bcopy(next, &ifm, sizeof ifm); ifd = &ifm.ifm_data; sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); get_rtaddrs(ifm.ifm_addrs, sa, rti_info); sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; if (sdl == NULL || sdl->sdl_family != AF_LINK) continue; bzero(name, sizeof(name)); if (sdl->sdl_nlen >= IFNAMSIZ) memcpy(name, sdl->sdl_data, IFNAMSIZ - 1); else if (sdl->sdl_nlen > 0) memcpy(name, sdl->sdl_data, sdl->sdl_nlen); if (interface != NULL && !strcmp(name, interface)) { takeit = 1; } else if (interface == NULL && foundone == 0 && isegress(name)) { takeit = 1; foundone = 1; } else takeit = 0; if (takeit) { strlcpy(ip_cur.ift_name, name, sizeof(ip_cur.ift_name)); ip_cur.ift_ip = ifd->ifi_ipackets; ip_cur.ift_ib = ifd->ifi_ibytes; ip_cur.ift_ie = ifd->ifi_ierrors; ip_cur.ift_op = ifd->ifi_opackets; ip_cur.ift_ob = ifd->ifi_obytes; ip_cur.ift_oe = ifd->ifi_oerrors; ip_cur.ift_co = ifd->ifi_collisions; ip_cur.ift_dr = 0; /* XXX ifnet.if_snd.ifq_drops */ } sum_cur.ift_ip += ifd->ifi_ipackets; sum_cur.ift_ib += ifd->ifi_ibytes; sum_cur.ift_ie += ifd->ifi_ierrors; sum_cur.ift_op += ifd->ifi_opackets; sum_cur.ift_ob += ifd->ifi_obytes; sum_cur.ift_oe += ifd->ifi_oerrors; sum_cur.ift_co += ifd->ifi_collisions; sum_cur.ift_dr += 0; /* XXX ifnet.if_snd.ifq_drops */ break; } } if (interface == NULL && foundone == 0) { strlcpy(ip_cur.ift_name, name, sizeof(ip_cur.ift_name)); ip_cur.ift_ip = ifd->ifi_ipackets; ip_cur.ift_ib = ifd->ifi_ibytes; ip_cur.ift_ie = ifd->ifi_ierrors; ip_cur.ift_op = ifd->ifi_opackets; ip_cur.ift_ob = ifd->ifi_obytes; ip_cur.ift_oe = ifd->ifi_oerrors; ip_cur.ift_co = ifd->ifi_collisions; ip_cur.ift_dr = 0; /* XXX ifnet.if_snd.ifq_drops */ } free(buf); }
/* * Print a description of the network interfaces. * NOTE: ifnetaddr is the location of the kernel global "ifnet", * which is a TAILQ_HEAD. */ void intpr(int interval, int repeatcount) { struct if_msghdr ifm; int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; char name[IFNAMSIZ + 1]; /* + 1 for the '*' */ char *buf, *next, *lim, *cp; struct rt_msghdr *rtm; struct ifa_msghdr *ifam; struct if_data *ifd; struct sockaddr *sa, *rti_info[RTAX_MAX]; struct sockaddr_dl *sdl; u_int64_t total = 0; size_t len; if (interval) { sidewaysintpr((unsigned)interval, repeatcount); return; } if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) err(1, "sysctl"); if ((buf = malloc(len)) == NULL) err(1, NULL); if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) err(1, "sysctl"); printf("%-7.7s %-5.5s %-11.11s %-17.17s ", "Name", "Mtu", "Network", "Address"); if (bflag) printf("%10.10s %10.10s", "Ibytes", "Obytes"); else printf("%8.8s %5.5s %8.8s %5.5s %5.5s", "Ipkts", "Ierrs", "Opkts", "Oerrs", "Colls"); if (tflag) printf(" %s", "Time"); if (dflag) printf(" %s", "Drop"); putchar('\n'); lim = buf + len; for (next = buf; next < lim; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; if (rtm->rtm_version != RTM_VERSION) continue; switch (rtm->rtm_type) { case RTM_IFINFO: total = 0; bcopy(next, &ifm, sizeof ifm); ifd = &ifm.ifm_data; sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); get_rtaddrs(ifm.ifm_addrs, sa, rti_info); sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; if (sdl == NULL || sdl->sdl_family != AF_LINK) continue; bzero(name, sizeof(name)); if (sdl->sdl_nlen >= IFNAMSIZ) memcpy(name, sdl->sdl_data, IFNAMSIZ - 1); else if (sdl->sdl_nlen > 0) memcpy(name, sdl->sdl_data, sdl->sdl_nlen); if (interface != 0 && strcmp(name, interface) != 0) continue; /* mark inactive interfaces with a '*' */ cp = strchr(name, '\0'); if ((ifm.ifm_flags & IFF_UP) == 0) *cp++ = '*'; *cp = '\0'; if (qflag) { total = ifd->ifi_ibytes + ifd->ifi_obytes + ifd->ifi_ipackets + ifd->ifi_ierrors + ifd->ifi_opackets + ifd->ifi_oerrors + ifd->ifi_collisions; if (tflag) total += 0; // XXX ifnet.if_timer; if (dflag) total += 0; // XXX ifnet.if_snd.ifq_drops; if (total == 0) continue; } printf("%-7s %-5d ", name, ifd->ifi_mtu); print_addr(rti_info[RTAX_IFP], rti_info, ifd); break; case RTM_NEWADDR: if (qflag && total == 0) continue; if (interface != 0 && strcmp(name, interface) != 0) continue; ifam = (struct ifa_msghdr *)next; if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA | RTA_BRD)) == 0) break; sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); get_rtaddrs(ifam->ifam_addrs, sa, rti_info); printf("%-7s %-5d ", name, ifd->ifi_mtu); print_addr(rti_info[RTAX_IFA], rti_info, ifd); break; } } free(buf); }
/* include get_ifi_info1 */ struct ifi_info * get_ifi_info(int family, int doaliases) { int flags; char *buf, *next, *lim; size_t len; struct if_msghdr *ifm; struct ifa_msghdr *ifam; struct sockaddr *sa, *rti_info[RTAX_MAX]; struct sockaddr_dl *sdl; struct ifi_info *ifi, *ifisave, *ifihead, **ifipnext; buf = Net_rt_iflist(family, 0, &len); ifihead = NULL; ifipnext = &ifihead; lim = buf + len; for (next = buf; next < lim; next += ifm->ifm_msglen) { ifm = (struct if_msghdr *) next; if (ifm->ifm_type == RTM_IFINFO) { if ( ((flags = ifm->ifm_flags) & IFF_UP) == 0) continue; /* ignore if interface not up */ sa = (struct sockaddr *) (ifm + 1); get_rtaddrs(ifm->ifm_addrs, sa, rti_info); if ( (sa = rti_info[RTAX_IFP]) != NULL) { ifi = Calloc(1, sizeof(struct ifi_info)); *ifipnext = ifi; /* prev points to this new one */ ifipnext = &ifi->ifi_next; /* ptr to next one goes here */ ifi->ifi_flags = flags; if (sa->sa_family == AF_LINK) { sdl = (struct sockaddr_dl *) sa; ifi->ifi_index = sdl->sdl_index; if (sdl->sdl_nlen > 0) snprintf(ifi->ifi_name, IFI_NAME, "%*s", sdl->sdl_nlen, &sdl->sdl_data[0]); else snprintf(ifi->ifi_name, IFI_NAME, "index %d", sdl->sdl_index); if ( (ifi->ifi_hlen = sdl->sdl_alen) > 0) memcpy(ifi->ifi_haddr, LLADDR(sdl), min(IFI_HADDR, sdl->sdl_alen)); } } /* end get_ifi_info1 */ /* include get_ifi_info3 */ } else if (ifm->ifm_type == RTM_NEWADDR) { if (ifi->ifi_addr) { /* already have an IP addr for i/f */ if (doaliases == 0) continue; /* 4we have a new IP addr for existing interface */ ifisave = ifi; ifi = Calloc(1, sizeof(struct ifi_info)); *ifipnext = ifi; /* prev points to this new one */ ifipnext = &ifi->ifi_next; /* ptr to next one goes here */ ifi->ifi_flags = ifisave->ifi_flags; ifi->ifi_index = ifisave->ifi_index; ifi->ifi_hlen = ifisave->ifi_hlen; memcpy(ifi->ifi_name, ifisave->ifi_name, IFI_NAME); memcpy(ifi->ifi_haddr, ifisave->ifi_haddr, IFI_HADDR); } ifam = (struct ifa_msghdr *) next; sa = (struct sockaddr *) (ifam + 1); get_rtaddrs(ifam->ifam_addrs, sa, rti_info); if ( (sa = rti_info[RTAX_IFA]) != NULL) { ifi->ifi_addr = Calloc(1, sa->sa_len); memcpy(ifi->ifi_addr, sa, sa->sa_len); } if ((flags & IFF_BROADCAST) && (sa = rti_info[RTAX_BRD]) != NULL) { ifi->ifi_brdaddr = Calloc(1, sa->sa_len); memcpy(ifi->ifi_brdaddr, sa, sa->sa_len); } if ((flags & IFF_POINTOPOINT) && (sa = rti_info[RTAX_BRD]) != NULL) { ifi->ifi_dstaddr = Calloc(1, sa->sa_len); memcpy(ifi->ifi_dstaddr, sa, sa->sa_len); } } else err_quit("unexpected message type %d", ifm->ifm_type); } /* "ifihead" points to the first structure in the linked list */ return(ifihead); /* ptr to first structure in linked list */ }
struct ifinfo * update_ifinfo(struct ifilist_head_t *ifi_head, int ifindex) { struct if_msghdr *ifm; struct ifinfo *ifi = NULL; struct sockaddr *sa; struct sockaddr *rti_info[RTAX_MAX]; char *msg; size_t len; char *lim; int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_IFLIST, 0 }; int error; syslog(LOG_DEBUG, "<%s> enter", __func__); if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), NULL, &len, NULL, 0) < 0) { syslog(LOG_ERR, "<%s> sysctl: NET_RT_IFLIST size get failed", __func__); exit(1); } if ((msg = malloc(len)) == NULL) { syslog(LOG_ERR, "<%s> malloc failed", __func__); exit(1); } if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), msg, &len, NULL, 0) < 0) { syslog(LOG_ERR, "<%s> sysctl: NET_RT_IFLIST get failed", __func__); exit(1); } lim = msg + len; for (ifm = (struct if_msghdr *)msg; ifm != NULL && ifm < (struct if_msghdr *)lim; ifm = get_next_msghdr(ifm,(struct if_msghdr *)lim)) { int ifi_new; syslog(LOG_DEBUG, "<%s> ifm = %p, lim = %p, diff = %zu", __func__, ifm, lim, (char *)lim - (char *)ifm); if (ifm->ifm_version != RTM_VERSION) { syslog(LOG_ERR, "<%s> ifm_vesrion mismatch", __func__); exit(1); } if (ifm->ifm_msglen == 0) { syslog(LOG_WARNING, "<%s> ifm_msglen is 0", __func__); free(msg); return (NULL); } ifi_new = 0; if (ifm->ifm_type == RTM_IFINFO) { struct ifreq ifr; int s; char ifname[IFNAMSIZ]; syslog(LOG_DEBUG, "<%s> RTM_IFINFO found. " "ifm_index = %d, ifindex = %d", __func__, ifm->ifm_index, ifindex); /* when ifindex is specified */ if (ifindex != UPDATE_IFINFO_ALL && ifindex != ifm->ifm_index) continue; /* ifname */ if (if_indextoname(ifm->ifm_index, ifname) == NULL) { syslog(LOG_WARNING, "<%s> ifname not found (idx=%d)", __func__, ifm->ifm_index); continue; } /* lookup an entry with the same ifindex */ TAILQ_FOREACH(ifi, ifi_head, ifi_next) { if (ifm->ifm_index == ifi->ifi_ifindex) break; if (strncmp(ifname, ifi->ifi_ifname, sizeof(ifname)) == 0) break; } if (ifi == NULL) { syslog(LOG_DEBUG, "<%s> new entry for idx=%d", __func__, ifm->ifm_index); ELM_MALLOC(ifi, exit(1)); ifi->ifi_rainfo = NULL; ifi->ifi_state = IFI_STATE_UNCONFIGURED; ifi->ifi_persist = 0; ifi_new = 1; } /* ifindex */ ifi->ifi_ifindex = ifm->ifm_index; /* ifname */ strlcpy(ifi->ifi_ifname, ifname, IFNAMSIZ); if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { syslog(LOG_ERR, "<%s> socket() failed.", __func__); if (ifi_new) free(ifi); continue; } /* MTU */ ifi->ifi_phymtu = ifm->ifm_data.ifi_mtu; if (ifi->ifi_phymtu == 0) { memset(&ifr, 0, sizeof(ifr)); ifr.ifr_addr.sa_family = AF_INET6; strlcpy(ifr.ifr_name, ifi->ifi_ifname, sizeof(ifr.ifr_name)); error = ioctl(s, SIOCGIFMTU, (caddr_t)&ifr); if (error) { close(s); syslog(LOG_ERR, "<%s> ioctl() failed.", __func__); if (ifi_new) free(ifi); continue; } ifi->ifi_phymtu = ifr.ifr_mtu; if (ifi->ifi_phymtu == 0) { syslog(LOG_WARNING, "<%s> no interface mtu info" " on %s. %d will be used.", __func__, ifi->ifi_ifname, IPV6_MMTU); ifi->ifi_phymtu = IPV6_MMTU; } } close(s); /* ND flags */ error = update_ifinfo_nd_flags(ifi); if (error) { if (ifi_new) free(ifi); continue; } /* SDL */ sa = (struct sockaddr *)(ifm + 1); get_rtaddrs(ifm->ifm_addrs, sa, rti_info); if ((sa = rti_info[RTAX_IFP]) != NULL) { if (sa->sa_family == AF_LINK) { memcpy(&ifi->ifi_sdl, (struct sockaddr_dl *)sa, sizeof(ifi->ifi_sdl)); } } else memset(&ifi->ifi_sdl, 0, sizeof(ifi->ifi_sdl)); /* flags */ ifi->ifi_flags = ifm->ifm_flags; /* type */ ifi->ifi_type = ifm->ifm_type; } else { syslog(LOG_ERR, "out of sync parsing NET_RT_IFLIST\n" "expected %d, got %d\n msglen = %d\n", RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen); exit(1); } if (ifi_new) { syslog(LOG_DEBUG, "<%s> adding %s(idx=%d) to ifilist", __func__, ifi->ifi_ifname, ifi->ifi_ifindex); TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next); } }
char * get_next_msg(char *buf, char *lim, size_t *lenp) { struct rt_msghdr *rtm; struct ifa_msghdr *ifam; struct sockaddr *sa, *dst, *ifa, *rti_info[RTAX_MAX]; *lenp = 0; for (rtm = (struct rt_msghdr *)buf; rtm < (struct rt_msghdr *)lim; rtm = (struct rt_msghdr *)((char *)rtm + rtm->rtm_msglen)) { /* just for safety */ if (!rtm->rtm_msglen) { log_warnx("rtm_msglen is 0 (buf=%p lim=%p rtm=%p)", buf, lim, rtm); break; } if (rtm->rtm_version != RTM_VERSION) continue; switch (rtm->rtm_type) { case RTM_ADD: case RTM_DELETE: if (rtm->rtm_tableid != 0) continue; /* address related checks */ sa = (struct sockaddr *)((char *)rtm + rtm->rtm_hdrlen); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); if ((dst = rti_info[RTAX_DST]) == NULL || dst->sa_family != AF_INET6) continue; if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) || IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr)) continue; if (rti_info[RTAX_NETMASK] == NULL) continue; /* found */ *lenp = rtm->rtm_msglen; return (char *)rtm; /* NOTREACHED */ case RTM_NEWADDR: case RTM_DELADDR: ifam = (struct ifa_msghdr *)rtm; /* address related checks */ sa = (struct sockaddr *)((char *)rtm + rtm->rtm_hdrlen); get_rtaddrs(ifam->ifam_addrs, sa, rti_info); if ((ifa = rti_info[RTAX_IFA]) == NULL || (ifa->sa_family != AF_INET && ifa->sa_family != AF_INET6)) continue; if (ifa->sa_family == AF_INET6 && (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) || IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr))) continue; /* found */ *lenp = rtm->rtm_msglen; return (char *)rtm; /* NOTREACHED */ case RTM_IFINFO: /* found */ *lenp = rtm->rtm_msglen; return (char *)rtm; /* NOTREACHED */ } } return (char *)rtm; }
static void np_rtentry(struct rt_msghdr* rtm) { char ifname[IFNAMSIZ + 1]; struct sockaddr *rti_info[RTAX_MAX]; struct sockaddr_in* dest = NULL; struct sockaddr_in* mask = NULL; struct sockaddr* sa; char flags[33]; char* bp = flags; char rbuf[18]; char workbuf[20]; int len; sa = (struct sockaddr*)(rtm + 1); if (sa->sa_family != AF_INET) return; if (rtm->rtm_flags & RTF_UP) *bp++ = 'U'; if (rtm->rtm_flags & RTF_GATEWAY) *bp++ = 'G'; if (rtm->rtm_flags & RTF_HOST) *bp++ = 'H'; if (rtm->rtm_flags & RTF_STATIC) *bp++ = 'S'; if (bp == flags) return; *bp = '\0'; get_rtaddrs(rtm->rtm_addrs, sa, rti_info); if ((rtm->rtm_addrs & RTA_DST) && rti_info[RTAX_DST]->sa_family == AF_INET) { dest = (struct sockaddr_in*)rti_info[RTAX_DST]; } if ((rtm->rtm_addrs & RTA_NETMASK) && rti_info[RTAX_NETMASK]->sa_len != 0) { mask = (struct sockaddr_in*)rti_info[RTAX_NETMASK]; } memset(workbuf, 0, sizeof(workbuf)); if (rtm->rtm_addrs & RTA_GATEWAY) { len = so_getnameinfo(rti_info[RTAX_GATEWAY], rti_info[RTAX_GATEWAY]->sa_len, workbuf, sizeof(workbuf), NULL, 0, NI_NUMERICHOST, NULL); if (len < 0) { strcpy(workbuf, "invalid"); } } so_ifindextoname(rtm->rtm_index, ifname); printf("%-16s ", dest != NULL ? inet_ntop(AF_INET, &dest->sin_addr, rbuf, sizeof(rbuf)) : "-"); printf("%-16s ", mask != NULL ? inet_ntop(AF_INET, &mask->sin_addr, rbuf, sizeof(rbuf)) : "-"); printf("%-18s ", workbuf[0] != '\0' ? workbuf : "-"); printf(" %-8s ", flags); printf(" %-6s ", ifname); printf(" %d ", rtm->rtm_index); printf("\n"); }
char * get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter) { struct rt_msghdr *rtm; struct ifa_msghdr *ifam; struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX]; *lenp = 0; for (rtm = (struct rt_msghdr *)buf; rtm < (struct rt_msghdr *)lim; rtm = (struct rt_msghdr *)(((char *)rtm) + rtm->rtm_msglen)) { /* just for safety */ if (!rtm->rtm_msglen) { syslog(LOG_WARNING, "<%s> rtm_msglen is 0 " "(buf=%p lim=%p rtm=%p)", __func__, buf, lim, rtm); break; } if (((struct rt_msghdr *)buf)->rtm_version != RTM_VERSION) { syslog(LOG_WARNING, "<%s> routing message version mismatch " "(buf=%p lim=%p rtm=%p)", __func__, buf, lim, rtm); continue; } if (FILTER_MATCH(rtm->rtm_type, filter) == 0) continue; switch (rtm->rtm_type) { case RTM_GET: case RTM_ADD: case RTM_DELETE: /* address related checks */ sa = (struct sockaddr *)(rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); if ((dst = rti_info[RTAX_DST]) == NULL || dst->sa_family != AF_INET6) continue; if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) || IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr)) continue; if ((gw = rti_info[RTAX_GATEWAY]) == NULL || gw->sa_family != AF_LINK) continue; if (ifindex && SDL(gw)->sdl_index != ifindex) continue; if (rti_info[RTAX_NETMASK] == NULL) continue; /* found */ *lenp = rtm->rtm_msglen; return (char *)rtm; /* NOTREACHED */ case RTM_NEWADDR: case RTM_DELADDR: ifam = (struct ifa_msghdr *)rtm; /* address related checks */ sa = (struct sockaddr *)(ifam + 1); get_rtaddrs(ifam->ifam_addrs, sa, rti_info); if ((ifa = rti_info[RTAX_IFA]) == NULL || (ifa->sa_family != AF_INET && ifa->sa_family != AF_INET6)) continue; if (ifa->sa_family == AF_INET6 && (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) || IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr))) continue; if (ifindex && ifam->ifam_index != ifindex) continue; /* found */ *lenp = ifam->ifam_msglen; return (char *)rtm; /* NOTREACHED */ case RTM_IFINFO: case RTM_IFANNOUNCE: /* found */ *lenp = rtm->rtm_msglen; return (char *)rtm; /* NOTREACHED */ } } return ((char *)rtm); }
// function used to configure a route to "daddr" by specifying either // the gateway address "gaddr" or the interface name "ifname"; // a mask given by "maddr" can also be specified // the command codes "cmd" indicate the type of operation // Note: addresses are given as 4-byte words (c.f. rtctl) int rtctl2(uint32_t *daddr, /* destination IP address */ uint32_t *gaddr, /* gateway IP address */ uint32_t *maddr, /* subnet mask */ char *ifname, /* network interface name */ u_char cmd) /* RTM_ADD RTM_DELETE RTM_CHANGE */ { int sockfd, mib[6], len; char *buf, rta_cmd[RTCTL_CMD_LEN], *ifbuf; char dstaddr[16], gateaddr[16], maskaddr[16]; u_char flag; pid_t pid; struct rt_msghdr *rtm; struct sockaddr_in *dst, *gate, *mask; struct sockaddr_dl *ifp, *sdl; struct if_msghdr *ifm; #ifdef RTCTL_PRINT_RESPONSE ssize_t n; struct sockaddr *sa, *rti_info[RTAX_MAX]; #endif /* check the arguments */ if (daddr == NULL) { fprintf(stderr, "Invalid destination IP address\n"); return -1; } flag = 0; if (cmd == RTM_ADD) { flag |= RTCTL_ADD; strncpy(rta_cmd, "add", sizeof("add")); if (gaddr == NULL) { if (ifname == NULL) flag |= RTCTL_UNKNOWN; else if (maddr != NULL) flag |= RTCTL_UNKNOWN; else flag |= RTCTL_IF; } else { flag |= RTCTL_GATEWAY; if (ifname != NULL) flag |= RTCTL_UNKNOWN; else if (maddr != NULL) flag |= RTCTL_NETMASK; } } else if (cmd == RTM_DELETE) { flag |= RTCTL_DELETE; strncpy(rta_cmd, "delete", sizeof("delete")); if ((ifname != NULL) | (gaddr != NULL) | (maddr != NULL)) flag |= RTCTL_UNKNOWN; } else if (cmd == RTM_CHANGE) { flag |= RTCTL_CHANGE; strncpy(rta_cmd, "change", sizeof("change")); if (gaddr == NULL) { if (ifname == NULL) flag |= RTCTL_UNKNOWN; else if (maddr != NULL) flag |= RTCTL_UNKNOWN; else flag |= RTCTL_IF; } else { flag |= RTCTL_GATEWAY; if (ifname != NULL) flag |= RTCTL_UNKNOWN; else if (maddr != NULL) flag |= RTCTL_NETMASK; } } else { fprintf(stderr, "Invalid command name\n"); return -1; } if (flag & RTCTL_UNKNOWN) { fprintf(stderr, "Unknown arguments are inputed.\n"); return -1; } if ((buf = calloc(1, BUFLEN)) == NULL) { perror("calloc"); return -1; } /* set address of rt messages */ rtm = (struct rt_msghdr *) buf; rtm->rtm_version = RTM_VERSION; rtm->rtm_type = cmd; rtm->rtm_pid = pid = getpid(); rtm->rtm_seq = ++rtm_seq; rtm->rtm_errno = 0; if ((flag & RTCTL_ADD) | (flag & RTCTL_CHANGE)) { if (flag & RTCTL_IF) { rtm->rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in) + sizeof(struct sockaddr_dl); rtm->rtm_addrs = RTA_DST | RTA_GATEWAY; rtm->rtm_flags = RTF_UP | RTF_HOST | RTF_LLINFO | RTF_STATIC; } else if (flag & RTCTL_NETMASK) { rtm->rtm_msglen = sizeof(struct rt_msghdr) + 3 * sizeof(struct sockaddr_in); rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; rtm->rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; } else { rtm->rtm_msglen = sizeof(struct rt_msghdr) + 2 * sizeof(struct sockaddr_in); rtm->rtm_addrs = RTA_DST | RTA_GATEWAY; rtm->rtm_flags = RTF_UP | RTF_HOST | RTF_GATEWAY | RTF_STATIC; } } else if (flag & RTCTL_DELETE) { rtm->rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in); rtm->rtm_addrs = RTA_DST; } /* set destination RTA_GATEWAY */ dst = (struct sockaddr_in *) (rtm + 1); dst->sin_len = sizeof(struct sockaddr_in); dst->sin_family = AF_INET; fflush(stderr); dst->sin_addr.s_addr = *daddr; if (flag & RTCTL_GATEWAY) { /* set gateway */ gate = (struct sockaddr_in *) (dst + 1); gate->sin_len = sizeof(struct sockaddr_in); gate->sin_family = AF_INET; gate->sin_addr.s_addr = *gaddr; if (flag & RTCTL_NETMASK) { mask = (struct sockaddr_in *) (gate + 1); mask->sin_len = sizeof(struct sockaddr_in); mask->sin_family = AF_INET; mask->sin_addr.s_addr = *maddr; } } else if (flag & RTCTL_IF) { /* get sockaddr_dl info */ mib[0] = CTL_NET; mib[1] = AF_ROUTE; mib[2] = 0; mib[3] = AF_LINK; mib[4] = NET_RT_IFLIST; if ((mib[5] = if_nametoindex(ifname)) == 0) { perror("if_nametoindex"); return -1; } if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { perror("sysctl"); return -1; } if ((ifbuf = calloc(1, len)) == NULL) { perror("calloc"); return -1; } if (sysctl(mib, 6, ifbuf, &len, NULL, 0) < 0) { perror("sysctl2"); return -1; } ifm = (struct if_msghdr *) ifbuf; sdl = (struct sockaddr_dl *) (ifm + 1); /* set network interface */ ifp = (struct sockaddr_dl *) (dst + 1); bcopy(sdl, ifp, sizeof(struct sockaddr_dl)); ifp->sdl_len = sizeof(struct sockaddr_dl); } if ((sockfd = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { perror("socket"); return -1; } if (write(sockfd, rtm, rtm->rtm_msglen) < 0) { perror("write"); //return -1; } else { strncpy(dstaddr, "", sizeof(dstaddr)); strncpy(gateaddr, "", sizeof(gateaddr)); strncpy(maskaddr, "", sizeof(maskaddr)); strncpy(dstaddr, inet_ntoa(dst->sin_addr), sizeof(dstaddr)); if (gaddr != NULL) strncpy(gateaddr, inet_ntoa(gate->sin_addr), sizeof(gateaddr)); if (maddr != NULL) strncpy(maskaddr, inet_ntoa(mask->sin_addr), sizeof(maskaddr)); fprintf(stderr, "\troute %s dst:%s gate:%s mask:%s ifp:%s\n", rta_cmd, dstaddr, gateaddr, maskaddr, ifname); /* A chunk of lines like this: */ /* strncpy(dstaddr, "", sizeof(dstaddr)); */ /* strncpy(gateaddr, "", sizeof(gateaddr)); */ /* strncpy(maskaddr, "", sizeof(maskaddr)); */ /* strncpy(dstaddr, inet_ntoa(dst->sin_addr), sizeof(dstaddr)); */ /* if (gaddr != NULL) */ /* strncpy(gateaddr, inet_ntoa(gate->sin_addr), */ /* sizeof(gateaddr)); */ /* if (maddr != NULL) */ /* strncpy(maskaddr, inet_ntoa(mask->sin_addr), */ /* sizeof(maskaddr)); */ /* fprintf(stderr, "\troute %s dst:%s gate:%s mask:%s ifp:%s\n", */ /* rta_cmd, dstaddr, gateaddr, maskaddr, ifname); */ /* can be rewritten as: */ /* fprintf(stderr, "\troute %s dst:%s gate:%s ", rta_cmd, dstaddr, */ /* (gaddr != NULL) : inet_ntoa(gate->sin_addr) ? ""); */ /* fprintf(stderr, "mask:%s ifp:%s\n", */ /* (maddr != NULL) : inet_ntoa(mask->sin_addr) ? "", ifname); */ } #ifdef RTCTL_PRINT_RESPONSE fprintf(stderr, "---print response\n"); do { n = read(sockfd, rtm, BUFLEN); } while (rtm->rtm_seq != rtm_seq || rtm->rtm_pid != pid); /* handle response */ rtm = (struct rt_msghdr *) buf; sa = (struct sockaddr *) (rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); if ((sa = rti_info[RTAX_DST]) != NULL) fprintf(stderr, "dest: %s\n", sock_ntop_host(sa, sa->sa_len)); if ((sa = rti_info[RTAX_GATEWAY]) != NULL) fprintf(stderr, "gateway: %s\n", sock_ntop_host(sa, sa->sa_len)); if ((sa = rti_info[RTAX_NETMASK]) != NULL) fprintf(stderr, "netmask: %s\n", sock_masktop(sa, sa->sa_len)); if ((sa = rti_info[RTAX_GENMASK]) != NULL) fprintf(stderr, "genmask: %s\n", sock_masktop(sa, sa->sa_len)); if ((sa = rti_info[RTAX_IFP]) != NULL) fprintf(stderr, "ifp: len:%d fami:%d data:%s\n", sa->sa_len, sa->sa_family, sa->sa_data); if ((sa = rti_info[RTAX_IFA]) != NULL) fprintf(stderr, "ifa: len:%d fami:%d data:%s\n", sa->sa_len, sa->sa_family, sa->sa_data); if ((sa = rti_info[RTAX_AUTHOR]) != NULL) fprintf(stderr, "author: len:%d fami:%d data:%s\n", sa->sa_len, sa->sa_family, sa->sa_data); if ((sa = rti_info[RTAX_BRD]) != NULL) fprintf(stderr, "brd: len:%d fami:%d data:%s\n", sa->sa_len, sa->sa_family, sa->sa_data); #endif free(buf); if (flag & RTCTL_IF) free(ifbuf); return 0; }
int getrt(char *ipaddr) { int sockfd; char *buf; pid_t pid; ssize_t n; struct rt_msghdr *rtm; struct sockaddr *sa, *rti_info[RTAX_MAX]; struct sockaddr_in *sin; if (ipaddr == NULL) { fprintf(stderr, "getrt: IP address.\n"); return -1; } if ((sockfd = socket(AF_ROUTE, SOCK_RAW, 0)) < 0) { perror("socket"); return -1; } buf = calloc(1, BUFLEN); rtm = (struct rt_msghdr *) buf; rtm->rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in); rtm->rtm_version = RTM_VERSION; rtm->rtm_type = RTM_GET; rtm->rtm_addrs = RTA_DST; rtm->rtm_pid = pid = getpid(); rtm->rtm_seq = SEQ; sin = (struct sockaddr_in *) (rtm + 1); sin->sin_len = sizeof(struct sockaddr_in); sin->sin_family = AF_INET; inet_pton(AF_INET, ipaddr, &sin->sin_addr); if (write(sockfd, rtm, rtm->rtm_msglen) < 0) { perror("write"); exit(1); } do { n = read(sockfd, rtm, BUFLEN); } while (rtm->rtm_type != RTM_GET || rtm->rtm_seq != SEQ || rtm->rtm_pid != pid); /* handle response */ rtm = (struct rt_msghdr *) buf; sa = (struct sockaddr *) (rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); if ((sa = rti_info[RTAX_DST]) != NULL) fprintf(stderr, "dest: %s\n", sock_ntop_host(sa, sa->sa_len)); if ((sa = rti_info[RTAX_GATEWAY]) != NULL) fprintf(stderr, "gateway: %s\n", sock_ntop_host(sa, sa->sa_len)); if ((sa = rti_info[RTAX_NETMASK]) != NULL) fprintf(stderr, "netmask: %s\n", sock_masktop(sa, sa->sa_len)); if ((sa = rti_info[RTAX_GENMASK]) != NULL) fprintf(stderr, "genmask: %s\n", sock_masktop(sa, sa->sa_len)); if ((sa = rti_info[RTAX_IFP]) != NULL) fprintf(stderr, "ifp: len:%d fami:%d data:%s\n", sa->sa_len, sa->sa_family, sa->sa_data); if ((sa = rti_info[RTAX_IFA]) != NULL) fprintf(stderr, "ifa: len:%d fami:%d data:%s\n", sa->sa_len, sa->sa_family, sa->sa_data); return 0; }