static void get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) { int i; for (i = 0; i < RTAX_MAX; i++) { if (addrs & (1 << i)) { rti_info[i] = sa; sa = (struct sockaddr *)((char *)(sa) + RT_ROUNDUP(sa->sa_len)); } else rti_info[i] = NULL; } }
void iface_ParseHdr(struct ifa_msghdr *ifam, struct sockaddr *sa[RTAX_MAX]) { char *wp; int rtax; wp = (char *)(ifam + 1); for (rtax = 0; rtax < RTAX_MAX; rtax++) if (ifam->ifam_addrs & (1 << rtax)) { sa[rtax] = (struct sockaddr *)wp; wp += RT_ROUNDUP(sa[rtax]->sa_len); } else sa[rtax] = NULL; }
/* * Set an individual neighbor cache entry */ int set(int argc, char **argv) { struct sockaddr_in6 *sin = &sin_m; struct sockaddr_dl *sdl; struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); struct addrinfo hints, *res; int gai_error; u_char *ea; char *host = argv[0], *eaddr = argv[1]; getsocket(); argc -= 2; argv += 2; sdl_m = blank_sdl; sin_m = blank_sin; bzero(&hints, sizeof(hints)); hints.ai_family = AF_INET6; gai_error = getaddrinfo(host, NULL, &hints, &res); if (gai_error) { fprintf(stderr, "ndp: %s: %s\n", host, gai_strerror(gai_error)); return 1; } sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; #ifdef __KAME__ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id); } #endif ea = (u_char *)LLADDR(&sdl_m); if (ndp_ether_aton(eaddr, ea) == 0) sdl_m.sdl_alen = 6; flags = 0; expire_time = 0; while (argc-- > 0) { if (strncmp(argv[0], "temp", 4) == 0) { struct timespec sp; clock_gettime(CLOCK_MONOTONIC, &sp); expire_time = sp.tv_sec + 20 * 60; } else if (strncmp(argv[0], "proxy", 5) == 0) flags |= RTF_ANNOUNCE; argv++; } if (rtmsg(RTM_GET) < 0) { perror(host); return (1); } sin = (struct sockaddr_in6 *)(rtm + 1); sdl = (struct sockaddr_dl *)(RT_ROUNDUP(sin->sin6_len) + (char *)sin); if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { if (sdl->sdl_family == AF_LINK && (rtm->rtm_flags & RTF_LLINFO) && !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) { case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: case IFT_ISO88024: case IFT_ISO88025: goto overwrite; } /* * IPv4 arp command retries with sin_other = SIN_PROXY here. */ fprintf(stderr, "set: cannot configure a new entry\n"); return 1; } overwrite: if (sdl->sdl_family != AF_LINK) { printf("cannot intuit interface index and type for %s\n", host); return (1); } sdl_m.sdl_type = sdl->sdl_type; sdl_m.sdl_index = sdl->sdl_index; return (rtmsg(RTM_ADD)); }
/** * * @retval 0 no errors * @retval !0 errors */ static int _load_defaultrouter_from_sysctl(netsnmp_container *container, int family) { netsnmp_defaultrouter_entry *entry; struct rt_msghdr *rtm; struct sockaddr *dst_sa, *gw_sa; char *buf, *lim, *newbuf, *next; char address[NETSNMP_ACCESS_DEFAULTROUTER_BUF_SIZE + 1]; int mib[6]; size_t address_len, needed; int address_type, err, preference, st; netsnmp_assert(NULL != container); mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = family; mib[4] = NET_RT_DUMP; mib[5] = 0; err = 0; buf = newbuf = NULL; if (family == AF_INET) { address_len = 4; address_type = INETADDRESSTYPE_IPV4; #ifdef NETSNMP_ENABLE_IPV6 } else if (family == AF_INET6) { address_len = 16; address_type = INETADDRESSTYPE_IPV6; #endif } else { err = EINVAL; goto out; } if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { err = errno; goto out; } /* Empty arp table. */ if (needed == 0) goto out; for (;;) { newbuf = realloc(buf, needed); if (newbuf == NULL) { err = ENOMEM; goto out; } buf = newbuf; st = sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &needed, NULL, 0); if (st == 0 || errno != ENOMEM) break; else needed += needed / 8; /* XXX: why 8? */ } if (st == -1) { err = errno; goto out; } lim = buf + needed; for (next = buf; next < lim; next += rtm->rtm_msglen) { #ifdef NETSNMP_ENABLE_IPV6 struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; #endif rtm = (struct rt_msghdr *)next; if (!(rtm->rtm_addrs & RTA_GATEWAY)) continue; dst_sa = (struct sockaddr*)(rtm + 1); #ifdef SA_SIZE gw_sa = (struct sockaddr*)(SA_SIZE(dst_sa) + (char*)dst_sa); #else gw_sa = (struct sockaddr*)(RT_ROUNDUP(dst_sa->sa_len) + (char*)dst_sa); #endif switch (family) { case AF_INET: if (((struct sockaddr_in*)dst_sa)->sin_addr.s_addr != INADDR_ANY) continue; memcpy(address, &((struct sockaddr_in*)gw_sa)->sin_addr.s_addr, address_len); break; #ifdef NETSNMP_ENABLE_IPV6 case AF_INET6: if (memcmp(((struct sockaddr_in6*)dst_sa)->sin6_addr.s6_addr, &in6addr_any, sizeof in6addr_any) != 0) continue; /* XXX: need to determine qualifying criteria for * default gateways in IPv6. */ memcpy(address, &((struct sockaddr_in6*)dst_sa)->sin6_addr.s6_addr, address_len); break; #endif default: break; } entry = netsnmp_access_defaultrouter_entry_create(); if (NULL == entry) { err = ENOMEM; break; } /* XXX: this is wrong (hardcoding the router preference to medium). */ preference = 0; entry->ns_dr_index = ++idx_offset; entry->dr_addresstype = address_type; entry->dr_address_len = address_len; memcpy(entry->dr_address, address, sizeof(address)); entry->dr_if_index = rtm->rtm_index; entry->dr_lifetime = rtm->rtm_rmx.rmx_expire; entry->dr_preference = preference; if (CONTAINER_INSERT(container, entry) < 0) { DEBUGMSGTL(("access:arp:container", "error with defaultrouter_entry: " "insert into container failed.\n")); netsnmp_access_defaultrouter_entry_free(entry); goto out; } } out: free(buf); return err; }
/* * Set an individual neighbor cache entry */ static int set(int argc, char **argv) { register struct sockaddr_in6 *mysin = &sin_m; register struct sockaddr_dl *sdl; register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); struct addrinfo hints, *res; int gai_error; u_char *ea; char *host = argv[0], *eaddr = argv[1]; getsocket(); argc -= 2; argv += 2; sdl_m = blank_sdl; sin_m = blank_sin; (void)memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; gai_error = getaddrinfo(host, NULL, &hints, &res); if (gai_error) { warnx("%s: %s\n", host, gai_strerror(gai_error)); return 1; } mysin->sin6_addr = ((struct sockaddr_in6 *)(void *)res->ai_addr)->sin6_addr; inet6_putscopeid(mysin, INET6_IS_ADDR_LINKLOCAL); ea = (u_char *)LLADDR(&sdl_m); if (ndp_ether_aton(eaddr, ea) == 0) sdl_m.sdl_alen = 6; flags = expire_time = 0; while (argc-- > 0) { if (strncmp(argv[0], "temp", 4) == 0) { struct timeval tim; (void)gettimeofday(&tim, 0); expire_time = tim.tv_sec + 20 * 60; } else if (strncmp(argv[0], "proxy", 5) == 0) flags |= RTF_ANNOUNCE; argv++; } if (rtmsg(RTM_GET) < 0) { errx(1, "RTM_GET(%s) failed", host); /* NOTREACHED */ } mysin = (struct sockaddr_in6 *)(void *)(rtm + 1); sdl = (struct sockaddr_dl *)(void *)(RT_ROUNDUP(mysin->sin6_len) + (char *)(void *)mysin); if (IN6_ARE_ADDR_EQUAL(&mysin->sin6_addr, &sin_m.sin6_addr)) { if (sdl->sdl_family == AF_LINK && (rtm->rtm_flags & RTF_LLINFO) && !(rtm->rtm_flags & RTF_GATEWAY)) { switch (sdl->sdl_type) { case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: case IFT_ISO88024: case IFT_ISO88025: goto overwrite; } } /* * IPv4 arp command retries with sin_other = SIN_PROXY here. */ (void)fprintf(stderr, "set: cannot configure a new entry\n"); return 1; } overwrite: if (sdl->sdl_family != AF_LINK) { warnx("cannot intuit interface index and type for %s", host); return (1); } sdl_m.sdl_type = sdl->sdl_type; sdl_m.sdl_index = sdl->sdl_index; return (rtmsg(RTM_ADD)); }
static int _load_ndp_table_from_sysctl(netsnmp_arp_access *access) { #if 1 netsnmp_arp_entry *entry; struct rt_msghdr *rtm; struct sockaddr_in6 *sin2; struct sockaddr_dl *sdl; size_t needed; int err, mib[6], st; char *buf, *lim, *newbuf, *next; netsnmp_assert(NULL != access); mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = AF_INET6; mib[4] = NET_RT_FLAGS; mib[5] = RTF_LLINFO; err = 0; buf = newbuf = NULL; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { err = errno; goto out; } /* Empty arp table. */ if (needed == 0) goto out; for (;;) { newbuf = realloc(buf, needed); if (newbuf == NULL) { err = ENOMEM; goto out; } buf = newbuf; st = sysctl(mib, 6, buf, &needed, NULL, 0); if (st == 0 || errno != ENOMEM) break; else needed += needed / 8; /* XXX: why 8? */ } if (st == -1) { err = errno; goto out; } lim = buf + needed; for (next = buf; next < lim; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; sin2 = (struct sockaddr_in6*)(rtm + 1); #ifdef SA_SIZE sdl = (struct sockaddr_dl*)((char *)sin2 + SA_SIZE(sin2)); #else sdl = (struct sockaddr_dl*)(void *)(RT_ROUNDUP(sin2->sin6_len) + (char *)(void *)sin2); #endif if (!(rtm->rtm_flags & RTF_HOST) || IN6_IS_ADDR_MULTICAST(&sin2->sin6_addr)) continue; entry = netsnmp_access_arp_entry_create(); if (NULL == entry) { err = ENOMEM; break; } entry->generation = access->generation; entry->if_index = rtm->rtm_index; entry->arp_ipaddress_len = 16; memcpy(entry->arp_ipaddress, &sin2->sin6_addr.s6_addr, entry->arp_ipaddress_len); /* HW Address */ entry->arp_physaddress_len = sdl->sdl_alen; if (0 < sdl->sdl_alen && sdl->sdl_alen <= NETSNMP_ACCESS_ARP_PHYSADDR_BUF_SIZE) { memcpy(entry->arp_physaddress, LLADDR(sdl), sdl->sdl_alen); /* Process status */ /* XXX: setting this value for all states is wrong. */ entry->arp_state = INETNETTOMEDIASTATE_REACHABLE; } else { entry->arp_physaddress[0] = '\0'; entry->arp_state = INETNETTOMEDIASTATE_INCOMPLETE; } /* Process type */ /* XXX: more states should be handled here, probably.. */ if (rtm->rtm_rmx.rmx_expire == 0) entry->arp_type = INETNETTOMEDIATYPE_STATIC; else entry->arp_type = INETNETTOMEDIATYPE_DYNAMIC; access->update_hook(access, entry); } out: free(buf); return err; #else return 0; #endif }
/* * Set an individual arp entry */ static int set(int argc, char **argv) { struct sockaddr_inarp *sina; struct sockaddr_dl *sdl; struct rt_msghdr *rtm; char *host = argv[0], *eaddr; struct sockaddr_inarp sin_m = blank_sin; /* struct copy */ struct sockaddr_dl sdl_m = blank_sdl; /* struct copy */ int s; eaddr = argv[1]; s = getsocket(); argc -= 2; argv += 2; if (getinetaddr(host, &sin_m.sin_addr) == -1) return (1); if (atosdl(eaddr, &sdl_m)) warnx("invalid link-level address '%s'", eaddr); doing_proxy = flags = export_only = expire_time = 0; for (; argc-- > 0; argv++) { if (strncmp(argv[0], "temp", 4) == 0) { struct timeval timev; (void)gettimeofday(&timev, 0); expire_time = timev.tv_sec + 20 * 60; } else if (strncmp(argv[0], "pub", 3) == 0) { flags |= RTF_ANNOUNCE; doing_proxy = SIN_PROXY; if (argc && strncmp(argv[1], "pro", 3) == 0) { export_only = 1; argc--; argv++; } } else if (strncmp(argv[0], "trail", 5) == 0) { warnx("%s: Sending trailers is no longer supported", host); } else if (strcmp(argv[0], "ifscope") == 0) { if (argc == 0) { warnx("missing interface for ifscope"); continue; } argc--; argv++; if (!getlink(argv[0], &sdl_m)) warnx("cannot get link address for %s", argv[0]); } } if (memcmp(&sdl_m, &blank_sdl, sizeof(blank_sdl))) goto out; tryagain: rtm = rtmsg(s, RTM_GET, &sin_m, &sdl_m); if (rtm == NULL) { warn("%s", host); return (1); } sina = (struct sockaddr_inarp *)(void *)(rtm + 1); sdl = (struct sockaddr_dl *)(void *)(RT_ROUNDUP(sina->sin_len) + (char *)(void *)sina); if (sina->sin_addr.s_addr == sin_m.sin_addr.s_addr) { if (is_llinfo(sdl, rtm->rtm_flags)) goto overwrite; if (doing_proxy == 0) { warnx("set: can only proxy for %s", host); return (1); } if (sin_m.sin_other & SIN_PROXY) { warnx("set: proxy entry exists for non 802 device"); return (1); } sin_m.sin_other = SIN_PROXY; export_only = 1; goto tryagain; } overwrite: if (sdl->sdl_family != AF_LINK) { warnx("cannot intuit interface index and type for %s", host); return (1); } sdl_m.sdl_type = sdl->sdl_type; sdl_m.sdl_index = sdl->sdl_index; out: sin_m.sin_other = 0; if (doing_proxy && export_only) sin_m.sin_other = SIN_PROXY; rtm = rtmsg(s, RTM_ADD, &sin_m, &sdl_m); if (vflag) (void)printf("%s (%s) added\n", host, eaddr); return (rtm == NULL) ? 1 : 0; }
/* * Issue a modifying routing command, which must be one of RTM_ADD, RTM_CHANGE, * RTM_DELETE, or RTM_LOCK. The destination address (IPv4 or IPv6) and netmask * prefix are required. The flags (RTF_), interface name, and gateway are * optional depending on the command (and flags) being issued. Return 0 on * success, and -1 with errno set on failure. */ static int test93_route_cmd(int cmd, const struct sockaddr * dest, socklen_t dest_len, unsigned int prefix, int flags, const char * ifname, const struct sockaddr * gw, socklen_t gw_len) { static unsigned int seq = 0; struct sockaddr_storage destss, maskss, ifpss, gwss; struct sockaddr_in mask4; struct sockaddr_in6 mask6; struct sockaddr_dl ifp; struct rt_msghdr rtm; struct iovec iov[5]; struct msghdr msg; unsigned int i, iovlen; int r, fd, err; memset(&rtm, 0, sizeof(rtm)); rtm.rtm_version = RTM_VERSION; rtm.rtm_type = cmd; rtm.rtm_flags = flags; rtm.rtm_addrs = RTA_DST | RTA_NETMASK; rtm.rtm_seq = ++seq; iovlen = 0; iov[iovlen].iov_base = &rtm; iov[iovlen++].iov_len = sizeof(rtm); memset(&destss, 0, sizeof(destss)); memcpy(&destss, dest, dest_len); destss.ss_len = dest_len; iov[iovlen].iov_base = &destss; iov[iovlen++].iov_len = RT_ROUNDUP(dest_len); /* Do this in RTA order. */ memset(&gwss, 0, sizeof(gwss)); if (gw != NULL) { memcpy(&gwss, gw, gw_len); gwss.ss_len = gw_len; rtm.rtm_addrs |= RTA_GATEWAY; iov[iovlen].iov_base = &gwss; iov[iovlen++].iov_len = RT_ROUNDUP(gwss.ss_len); } memset(&maskss, 0, sizeof(maskss)); switch (dest->sa_family) { case AF_INET: if (prefix > 32) e(0); memset(&mask4, 0, sizeof(mask4)); mask4.sin_family = AF_INET; if (prefix < 32) mask4.sin_addr.s_addr = htonl(0xffffffffUL << prefix); memcpy(&maskss, &mask4, sizeof(mask4)); maskss.ss_len = sizeof(mask4); break; case AF_INET6: test93_make_netmask6(&mask6, prefix); memcpy(&maskss, &mask6, sizeof(mask6)); maskss.ss_len = sizeof(mask6); break; default: e(0); } iov[iovlen].iov_base = &maskss; iov[iovlen++].iov_len = RT_ROUNDUP(maskss.ss_len); if (ifname != NULL) { memset(&ifp, 0, sizeof(ifp)); ifp.sdl_nlen = strlen(ifname); ifp.sdl_len = offsetof(struct sockaddr_dl, sdl_data) + ifp.sdl_nlen; ifp.sdl_family = AF_LINK; memset(&ifpss, 0, sizeof(ifpss)); memcpy(&ifpss, &ifp, ifp.sdl_len); memcpy(&((struct sockaddr_dl *)&ifpss)->sdl_data, ifname, ifp.sdl_nlen); rtm.rtm_addrs |= RTA_IFP; iov[iovlen].iov_base = &ifpss; iov[iovlen++].iov_len = RT_ROUNDUP(ifpss.ss_len); }