size_t lldp_packet(uint8_t proto, void *packet, struct netif *netif, struct nhead *netifs, struct my_sysinfo *sysinfo) { struct ether_hdr ether; char *tlv; char *pos = packet; size_t length = ETHER_MAX_LEN; uint16_t cap = 0, cap_active = 0; struct netif *parent, *mgmt, *vlanif = NULL; uint8_t *hwaddr; struct hinv *hinv; char *description; const uint8_t lldp_dst[] = LLDP_MULTICAST_ADDR; // fixup parent netif if (netif->parent != NULL) parent = netif->parent; else parent = netif; // configure managment interface mgmt = sysinfo->mnetif; if (!mgmt) mgmt = parent; // ethernet header memcpy(ether.dst, lldp_dst, ETHER_ADDR_LEN); memcpy(ether.src, netif->hwaddr, ETHER_ADDR_LEN); ether.type = htons(ETHERTYPE_LLDP); memcpy(pos, ðer, sizeof(struct ether_hdr)); pos += sizeof(struct ether_hdr); // update tlv counters length -= VOIDP_DIFF(pos, packet); // chassis id and hinv hwaddr = (options & OPT_CHASSIS_IF) ? netif->hwaddr : sysinfo->hwaddr; hinv = &(sysinfo->hinv); if (!( START_LLDP_TLV(LLDP_TYPE_CHASSIS_ID) && PUSH_UINT8(LLDP_CHASSIS_MAC_ADDR_SUBTYPE) && PUSH_BYTES(hwaddr, ETHER_ADDR_LEN) )) return 0; END_LLDP_TLV; // port id if (!( START_LLDP_TLV(LLDP_TYPE_PORT_ID) && PUSH_UINT8(LLDP_PORT_INTF_NAME_SUBTYPE) && PUSH_BYTES(netif->name, strlen(netif->name)) )) return 0; END_LLDP_TLV; // ttl if (!( START_LLDP_TLV(LLDP_TYPE_TTL) && PUSH_UINT16(LADVD_TTL) )) return 0; END_LLDP_TLV; // port description if (options & OPT_IFDESCR) description = netif->device_name; else if (strlen(netif->description)) description = netif->description; else if (strlen(parent->description)) description = parent->description; else description = netif->device_name; if (strlen(description) > 0) { if (!( START_LLDP_TLV(LLDP_TYPE_PORT_DESCR) && PUSH_BYTES(description, strlen(description)) )) return 0; END_LLDP_TLV; } // system name if (!( START_LLDP_TLV(LLDP_TYPE_SYSTEM_NAME) && PUSH_BYTES(sysinfo->hostname, strlen(sysinfo->hostname)) )) return 0; END_LLDP_TLV; // system description if (!( START_LLDP_TLV(LLDP_TYPE_SYSTEM_DESCR) && PUSH_BYTES(sysinfo->uts_str, strlen(sysinfo->uts_str)) )) return 0; END_LLDP_TLV; // capabilities if (sysinfo->cap == CAP_HOST) { cap = cap_active = LLDP_CAP_STATION_ONLY; } else { cap |= (sysinfo->cap & CAP_BRIDGE) ? LLDP_CAP_BRIDGE : 0; cap_active |= (sysinfo->cap_active & CAP_BRIDGE) ? LLDP_CAP_BRIDGE : 0; cap |= (sysinfo->cap & CAP_ROUTER) ? LLDP_CAP_ROUTER : 0; cap_active |= (sysinfo->cap_active & CAP_ROUTER) ? LLDP_CAP_ROUTER : 0; cap |= (sysinfo->cap & CAP_SWITCH) ? LLDP_CAP_BRIDGE : 0; cap_active |= (sysinfo->cap_active & CAP_SWITCH) ? LLDP_CAP_BRIDGE : 0; cap |= (sysinfo->cap & CAP_WLAN) ? LLDP_CAP_WLAN_AP : 0; cap_active |= (sysinfo->cap_active & CAP_WLAN) ? LLDP_CAP_WLAN_AP : 0; } if (!( START_LLDP_TLV(LLDP_TYPE_SYSTEM_CAP) && PUSH_UINT16(cap) && PUSH_UINT16(cap_active) )) return 0; END_LLDP_TLV; // ipv4 management addr if (mgmt->ipaddr4 != 0) { if (!( START_LLDP_TLV(LLDP_TYPE_MGMT_ADDR) && PUSH_UINT8(1 + sizeof(mgmt->ipaddr4)) && PUSH_UINT8(LLDP_AFNUM_INET) && PUSH_BYTES(&mgmt->ipaddr4, sizeof(mgmt->ipaddr4)) && PUSH_UINT8(LLDP_INTF_NUMB_IFX_SUBTYPE) && PUSH_UINT32(mgmt->index) && PUSH_UINT8(0) )) return 0; END_LLDP_TLV; } // ipv6 management addr if (!IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)mgmt->ipaddr6)) { if (!( START_LLDP_TLV(LLDP_TYPE_MGMT_ADDR) && PUSH_UINT8(1 + sizeof(mgmt->ipaddr6)) && PUSH_UINT8(LLDP_AFNUM_INET6) && PUSH_BYTES(mgmt->ipaddr6, sizeof(mgmt->ipaddr6)) && PUSH_UINT8(LLDP_INTF_NUMB_IFX_SUBTYPE) && PUSH_UINT32(mgmt->index) && PUSH_UINT8(0) )) return 0; END_LLDP_TLV; } // hw management addr if (!( START_LLDP_TLV(LLDP_TYPE_MGMT_ADDR) && PUSH_UINT8(1 + sizeof(mgmt->hwaddr)) && PUSH_UINT8(LLDP_AFNUM_802) && PUSH_BYTES(mgmt->hwaddr, sizeof(mgmt->hwaddr)) && PUSH_UINT8(LLDP_INTF_NUMB_IFX_SUBTYPE) && PUSH_UINT32(mgmt->index) && PUSH_UINT8(0) )) return 0; END_LLDP_TLV; // IEEE 802.1 Organizationally Specific TLV set // vlan names while ((vlanif = netif_iter(vlanif, netifs)) != NULL) { if (vlanif->type != NETIF_VLAN) continue; // skip unless attached to this interface or the parent if ((vlanif->vlan_parent != netif->index) && (vlanif->vlan_parent != parent->index)) continue; if (!( START_LLDP_TLV(LLDP_TYPE_PRIVATE) && PUSH_BYTES(OUI_IEEE_8021_PRIVATE, OUI_LEN) && PUSH_UINT8(LLDP_PRIVATE_8021_SUBTYPE_VLAN_NAME) && PUSH_UINT16(vlanif->vlan_id) && PUSH_UINT8(strlen(vlanif->name)) && PUSH_BYTES(vlanif->name, strlen(vlanif->name)) )) return 0; END_LLDP_TLV; } // IEEE 802.3 Organizationally Specific TLV set // autoneg if (netif->autoneg_supported != -1) { if (!( START_LLDP_TLV(LLDP_TYPE_PRIVATE) && PUSH_BYTES(OUI_IEEE_8023_PRIVATE, OUI_LEN) && PUSH_UINT8(LLDP_PRIVATE_8023_SUBTYPE_MACPHY) && PUSH_UINT8(netif->autoneg_supported + (netif->autoneg_enabled << 1)) && PUSH_UINT16(netif->autoneg_pmd) && PUSH_UINT16(netif->mau) )) return 0; END_LLDP_TLV; } // lacp if (parent->bonding_mode == NETIF_BONDING_LACP) { if (!( START_LLDP_TLV(LLDP_TYPE_PRIVATE) && PUSH_BYTES(OUI_IEEE_8023_PRIVATE, OUI_LEN) && PUSH_UINT8(LLDP_PRIVATE_8023_SUBTYPE_LINKAGGR) && PUSH_UINT8(LLDP_AGGREGATION_CAPABILTIY|LLDP_AGGREGATION_STATUS) && PUSH_UINT32(netif->lacp_index) )) return 0; END_LLDP_TLV; } // mtu if (netif->mtu != 0) { if (!( START_LLDP_TLV(LLDP_TYPE_PRIVATE) && PUSH_BYTES(OUI_IEEE_8023_PRIVATE, OUI_LEN) && PUSH_UINT8(LLDP_PRIVATE_8023_SUBTYPE_MTU) && PUSH_UINT16(netif->mtu + 22) )) return 0; END_LLDP_TLV; } // TIA LLDP-MED Capabilities TLV if (!( START_LLDP_TLV(LLDP_TYPE_PRIVATE) && PUSH_BYTES(OUI_TIA, OUI_LEN) && PUSH_UINT8(LLDP_PRIVATE_TIA_SUBTYPE_CAPABILITIES) && PUSH_UINT16(sysinfo->cap_lldpmed) && PUSH_UINT8(sysinfo->lldpmed_devtype) )) return 0; END_LLDP_TLV; // TIA Location Identification TLv // LOC ("location", CAtype 22): unstructured additional information if ((strlen(sysinfo->country) == 2) && (strlen(sysinfo->location) != 0)) { if (!( START_LLDP_TLV(LLDP_TYPE_PRIVATE) && PUSH_BYTES(OUI_TIA, OUI_LEN) && PUSH_UINT8(LLDP_PRIVATE_TIA_SUBTYPE_LOCAL_ID) && PUSH_UINT8(LLDP_TIA_LOCATION_DATA_FORMAT_CIVIC_ADDRESS) && PUSH_UINT8(5 + strlen(sysinfo->location)) && PUSH_UINT8(LLDP_TIA_LOCATION_LCI_WHAT_CLIENT) && PUSH_BYTES(sysinfo->country, 2) && PUSH_UINT8(LLDP_TIA_LOCATION_LCI_CATYPE_LOC) && PUSH_UINT8(strlen(sysinfo->location)) && PUSH_BYTES(sysinfo->location, strlen(sysinfo->location)) )) return 0; END_LLDP_TLV; } // TIA Inventory Management TLV Set // hardware revision if (strlen(hinv->hw_revision) > 0) { if (!( START_LLDP_TLV(LLDP_TYPE_PRIVATE) && PUSH_BYTES(OUI_TIA, OUI_LEN) && PUSH_UINT8(LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_HARDWARE_REV) && PUSH_BYTES(hinv->hw_revision, strlen(hinv->hw_revision)) )) return 0; END_LLDP_TLV; } // firmware revision if (strlen(hinv->fw_revision) > 0) { if (!( START_LLDP_TLV(LLDP_TYPE_PRIVATE) && PUSH_BYTES(OUI_TIA, OUI_LEN) && PUSH_UINT8(LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_FIRMWARE_REV) && PUSH_BYTES(hinv->fw_revision, strlen(hinv->fw_revision)) )) return 0; END_LLDP_TLV; } // software revision if (strlen(hinv->sw_revision) > 0) { if (!( START_LLDP_TLV(LLDP_TYPE_PRIVATE) && PUSH_BYTES(OUI_TIA, OUI_LEN) && PUSH_UINT8(LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_SOFTWARE_REV) && PUSH_BYTES(hinv->sw_revision, strlen(hinv->sw_revision)) )) return 0; END_LLDP_TLV; } // serial number if (strlen(hinv->serial_number) > 0) { if (!( START_LLDP_TLV(LLDP_TYPE_PRIVATE) && PUSH_BYTES(OUI_TIA, OUI_LEN) && PUSH_UINT8(LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_SERIAL_NUMBER) && PUSH_BYTES(hinv->serial_number, strlen(hinv->serial_number)) )) return 0; END_LLDP_TLV; } // manufacturer if (strlen(hinv->manufacturer) > 0) { if (!( START_LLDP_TLV(LLDP_TYPE_PRIVATE) && PUSH_BYTES(OUI_TIA, OUI_LEN) && PUSH_UINT8(LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_MANUFACTURER_NAME) && PUSH_BYTES(hinv->manufacturer, strlen(hinv->manufacturer)) )) return 0; END_LLDP_TLV; } // model name if (strlen(hinv->model_name) > 0) { if (!( START_LLDP_TLV(LLDP_TYPE_PRIVATE) && PUSH_BYTES(OUI_TIA, OUI_LEN) && PUSH_UINT8(LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_MODEL_NAME) && PUSH_BYTES(hinv->model_name, strlen(hinv->model_name)) )) return 0; END_LLDP_TLV; } // asset id if (strlen(hinv->asset_id) > 0) { if (!( START_LLDP_TLV(LLDP_TYPE_PRIVATE) && PUSH_BYTES(OUI_TIA, OUI_LEN) && PUSH_UINT8(LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_ASSET_ID) && PUSH_BYTES(hinv->asset_id, strlen(hinv->asset_id)) )) return 0; END_LLDP_TLV; } // the end if (!( START_LLDP_TLV(LLDP_TYPE_END) )) return 0; END_LLDP_TLV; // return the packet length return(VOIDP_DIFF(pos, packet)); }
int fr_packet_list_socket_add(fr_packet_list_t *pl, int sockfd) { int i, start; struct sockaddr_storage src; socklen_t sizeof_src = sizeof(src); fr_packet_socket_t *ps; if (!pl) return 0; ps = NULL; i = start = SOCK2OFFSET(sockfd); do { if (pl->sockets[i].sockfd == -1) { ps = &pl->sockets[i]; start = i; break; } i = (i + 1) & SOCKOFFSET_MASK; } while (i != start); if (!ps) { return 0; } memset(ps, 0, sizeof(*ps)); ps->sockfd = sockfd; ps->offset = start; /* * Get address family, etc. first, so we know if we * need to do udpfromto. * * FIXME: udpfromto also does this, but it's not * a critical problem. */ memset(&src, 0, sizeof_src); if (getsockname(sockfd, (struct sockaddr *) &src, &sizeof_src) < 0) { return 0; } if (!fr_sockaddr2ipaddr(&src, sizeof_src, &ps->ipaddr, &ps->port)) { return 0; } /* * Grab IP addresses & ports from the sockaddr. */ if (src.ss_family == AF_INET) { if (ps->ipaddr.ipaddr.ip4addr.s_addr == INADDR_ANY) { ps->inaddr_any = 1; } #ifdef HAVE_STRUCT_SOCKADDR_IN6 } else if (src.ss_family == AF_INET6) { if (IN6_IS_ADDR_UNSPECIFIED(&ps->ipaddr.ipaddr.ip6addr)) { ps->inaddr_any = 1; } #endif } else { return 0; } pl->mask |= (1 << ps->offset); return 1; }
/* * Input a Neighbor Solicitation Message. * * Based on RFC 2461 * Based on RFC 2462 (duplicate address detection) */ void nd6_ns_input(struct mbuf *m, int off, int icmp6len) { struct ifnet *ifp = m->m_pkthdr.rcvif; struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); struct nd_neighbor_solicit *nd_ns; struct in6_addr saddr6 = ip6->ip6_src; struct in6_addr daddr6 = ip6->ip6_dst; struct in6_addr taddr6; struct in6_addr myaddr6; char *lladdr = NULL; struct ifaddr *ifa = NULL; int lladdrlen = 0; int anycast = 0, proxy = 0, tentative = 0; int tlladdr; int rflag; union nd_opts ndopts; struct sockaddr_dl proxydl; char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; rflag = (V_ip6_forwarding) ? ND_NA_FLAG_ROUTER : 0; if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV && V_ip6_norbit_raif) rflag = 0; #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, icmp6len,); nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off); #else IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len); if (nd_ns == NULL) { ICMP6STAT_INC(icp6s_tooshort); return; } #endif ip6 = mtod(m, struct ip6_hdr *); /* adjust pointer for safety */ taddr6 = nd_ns->nd_ns_target; if (in6_setscope(&taddr6, ifp, NULL) != 0) goto bad; if (ip6->ip6_hlim != 255) { nd6log((LOG_ERR, "nd6_ns_input: invalid hlim (%d) from %s to %s on %s\n", ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src), ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp))); goto bad; } if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { /* dst has to be a solicited node multicast address. */ if (daddr6.s6_addr16[0] == IPV6_ADDR_INT16_MLL && /* don't check ifindex portion */ daddr6.s6_addr32[1] == 0 && daddr6.s6_addr32[2] == IPV6_ADDR_INT32_ONE && daddr6.s6_addr8[12] == 0xff) { ; /* good */ } else { nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet " "(wrong ip6 dst)\n")); goto bad; } } else if (!V_nd6_onlink_ns_rfc4861) { struct sockaddr_in6 src_sa6; /* * According to recent IETF discussions, it is not a good idea * to accept a NS from an address which would not be deemed * to be a neighbor otherwise. This point is expected to be * clarified in future revisions of the specification. */ bzero(&src_sa6, sizeof(src_sa6)); src_sa6.sin6_family = AF_INET6; src_sa6.sin6_len = sizeof(src_sa6); src_sa6.sin6_addr = saddr6; if (nd6_is_addr_neighbor(&src_sa6, ifp) == 0) { nd6log((LOG_INFO, "nd6_ns_input: " "NS packet from non-neighbor\n")); goto bad; } } if (IN6_IS_ADDR_MULTICAST(&taddr6)) { nd6log((LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n")); goto bad; } icmp6len -= sizeof(*nd_ns); nd6_option_init(nd_ns + 1, icmp6len, &ndopts); if (nd6_options(&ndopts) < 0) { nd6log((LOG_INFO, "nd6_ns_input: invalid ND option, ignored\n")); /* nd6_options have incremented stats */ goto freeit; } if (ndopts.nd_opts_src_lladdr) { lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; } if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) && lladdr) { nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet " "(link-layer address option)\n")); goto bad; } /* * Attaching target link-layer address to the NA? * (RFC 2461 7.2.4) * * NS IP dst is unicast/anycast MUST NOT add * NS IP dst is solicited-node multicast MUST add * * In implementation, we add target link-layer address by default. * We do not add one in MUST NOT cases. */ if (!IN6_IS_ADDR_MULTICAST(&daddr6)) tlladdr = 0; else tlladdr = 1; /* * Target address (taddr6) must be either: * (1) Valid unicast/anycast address for my receiving interface, * (2) Unicast address for which I'm offering proxy service, or * (3) "tentative" address on which DAD is being performed. */ /* (1) and (3) check. */ if (ifp->if_carp) ifa = (*carp_iamatch6_p)(ifp, &taddr6); if (ifa == NULL) ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6); /* (2) check. */ if (ifa == NULL) { struct route_in6 ro; int need_proxy; bzero(&ro, sizeof(ro)); ro.ro_dst.sin6_len = sizeof(struct sockaddr_in6); ro.ro_dst.sin6_family = AF_INET6; ro.ro_dst.sin6_addr = taddr6; /* Always use the default FIB. */ #ifdef RADIX_MPATH rtalloc_mpath_fib((struct route *)&ro, RTF_ANNOUNCE, RT_DEFAULT_FIB); #else in6_rtalloc(&ro, RT_DEFAULT_FIB); #endif need_proxy = (ro.ro_rt && (ro.ro_rt->rt_flags & RTF_ANNOUNCE) != 0 && ro.ro_rt->rt_gateway->sa_family == AF_LINK); if (ro.ro_rt != NULL) { if (need_proxy) proxydl = *SDL(ro.ro_rt->rt_gateway); RTFREE(ro.ro_rt); } if (need_proxy) { /* * proxy NDP for single entry */ ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, IN6_IFF_NOTREADY|IN6_IFF_ANYCAST); if (ifa) proxy = 1; } } if (ifa == NULL) { /* * We've got an NS packet, and we don't have that adddress * assigned for us. We MUST silently ignore it. * See RFC2461 7.2.3. */ goto freeit; } myaddr6 = *IFA_IN6(ifa); anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST; tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE; if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED) goto freeit; if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { nd6log((LOG_INFO, "nd6_ns_input: lladdrlen mismatch for %s " "(if %d, NS packet %d)\n", ip6_sprintf(ip6bufs, &taddr6), ifp->if_addrlen, lladdrlen - 2)); goto bad; } if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) { nd6log((LOG_INFO, "nd6_ns_input: duplicate IP6 address %s\n", ip6_sprintf(ip6bufs, &saddr6))); goto freeit; } /* * We have neighbor solicitation packet, with target address equals to * one of my tentative address. * * src addr how to process? * --- --- * multicast of course, invalid (rejected in ip6_input) * unicast somebody is doing address resolution -> ignore * unspec dup address detection * * The processing is defined in RFC 2462. */ if (tentative) { /* * If source address is unspecified address, it is for * duplicate address detection. * * If not, the packet is for addess resolution; * silently ignore it. */ if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) nd6_dad_ns_input(ifa); goto freeit; } /* * If the source address is unspecified address, entries must not * be created or updated. * It looks that sender is performing DAD. Output NA toward * all-node multicast address, to tell the sender that I'm using * the address. * S bit ("solicited") must be zero. */ if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { struct in6_addr in6_all; in6_all = in6addr_linklocal_allnodes; if (in6_setscope(&in6_all, ifp, NULL) != 0) goto bad; nd6_na_output_fib(ifp, &in6_all, &taddr6, ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) | rflag, tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m)); goto freeit; } nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_NEIGHBOR_SOLICIT, 0); nd6_na_output_fib(ifp, &saddr6, &taddr6, ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) | rflag | ND_NA_FLAG_SOLICITED, tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m)); freeit: if (ifa != NULL) ifa_free(ifa); m_freem(m); return; bad: nd6log((LOG_ERR, "nd6_ns_input: src=%s\n", ip6_sprintf(ip6bufs, &saddr6))); nd6log((LOG_ERR, "nd6_ns_input: dst=%s\n", ip6_sprintf(ip6bufs, &daddr6))); nd6log((LOG_ERR, "nd6_ns_input: tgt=%s\n", ip6_sprintf(ip6bufs, &taddr6))); ICMP6STAT_INC(icp6s_badns); if (ifa != NULL) ifa_free(ifa); m_freem(m); }
/* * Type0 routing header processing * * RFC2292 backward compatibility warning: no support for strict/loose bitmap, * as it was dropped between RFC1883 and RFC2460. */ static int ip6_rthdr0(struct mbuf *m, struct ip6_hdr *ip6, struct ip6_rthdr0 *rh0) { int addrs, index; struct in6_addr *nextaddr, tmpaddr; const struct ip6aux *ip6a; if (rh0->ip6r0_segleft == 0) return (0); if (rh0->ip6r0_len % 2 #ifdef COMPAT_RFC1883 || rh0->ip6r0_len > 46 #endif ) { /* * Type 0 routing header can't contain more than 23 addresses. * RFC 2462: this limitation was removed since strict/loose * bitmap field was deleted. */ IP6_STATINC(IP6_STAT_BADOPTIONS); icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, (char *)&rh0->ip6r0_len - (char *)ip6); return (-1); } if ((addrs = rh0->ip6r0_len / 2) < rh0->ip6r0_segleft) { IP6_STATINC(IP6_STAT_BADOPTIONS); icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, (char *)&rh0->ip6r0_segleft - (char *)ip6); return (-1); } index = addrs - rh0->ip6r0_segleft; rh0->ip6r0_segleft--; nextaddr = ((struct in6_addr *)(rh0 + 1)) + index; /* * reject invalid addresses. be proactive about malicious use of * IPv4 mapped/compat address. * XXX need more checks? */ if (IN6_IS_ADDR_MULTICAST(nextaddr) || IN6_IS_ADDR_UNSPECIFIED(nextaddr) || IN6_IS_ADDR_V4MAPPED(nextaddr) || IN6_IS_ADDR_V4COMPAT(nextaddr)) { p6stat[IP6_STAT_BADOPTIONS]++; goto bad; } if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst) || IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst) || IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) { IP6_STATINC(IP6_STAT_BADOPTIONS); goto bad; } /* * Determine the scope zone of the next hop, based on the interface * of the current hop. [RFC4007, Section 9] * Then disambiguate the scope zone for the next hop (if necessary). */ if ((ip6a = ip6_getdstifaddr(m)) == NULL) goto bad; if (in6_setzoneid(nextaddr, ip6a->ip6a_scope_id) != 0) { IP6_STATINC(IP6_STAT_BADSCOPE); goto bad; } /* * Swap the IPv6 destination address and nextaddr. Forward the packet. */ tmpaddr = *nextaddr; *nextaddr = ip6->ip6_dst; in6_clearscope(nextaddr); /* XXX */ ip6->ip6_dst = tmpaddr; #ifdef COMPAT_RFC1883 if (rh0->ip6r0_slmap[index / 8] & (1 << (7 - (index % 8)))) ip6_forward(m, IPV6_SRCRT_NEIGHBOR); else ip6_forward(m, IPV6_SRCRT_NOTNEIGHBOR); #else ip6_forward(m, 1); #endif return (-1); /* m would be freed in ip6_forward() */ bad: m_freem(m); return (-1); }
void ospf6_asbr_external_lsa_update (struct ospf6_route_req *request) { char buffer [MAXLSASIZE]; u_int16_t size; struct ospf6_lsa_as_external *external; char *p; struct ospf6_route_req route; char pbuf[BUFSIZ]; /* assert this is best path; if not, return */ ospf6_route_lookup (&route, &request->route.prefix, request->table); if (memcmp (&route.path, &request->path, sizeof (route.path))) return; if (IS_OSPF6_DUMP_LSA) zlog_info ("Update AS-External: ID: %lu", (u_long) ntohl (request->path.origin.id)); /* prepare buffer */ memset (buffer, 0, sizeof (buffer)); size = sizeof (struct ospf6_lsa_as_external); external = (struct ospf6_lsa_as_external *) buffer; p = (char *) (external + 1); if (route.path.metric_type == 2) SET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E); /* type2 */ else UNSET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E); /* type1 */ /* forwarding address */ if (! IN6_IS_ADDR_UNSPECIFIED (&route.nexthop.address)) SET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F); else UNSET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F); /* external route tag */ UNSET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T); /* set metric. note: related to E bit */ OSPF6_ASBR_METRIC_SET (external, route.path.cost); /* prefixlen */ external->prefix.prefix_length = route.route.prefix.prefixlen; /* PrefixOptions */ external->prefix.prefix_options = route.path.prefix_options; /* don't use refer LS-type */ external->prefix.prefix_refer_lstype = htons (0); if (IS_OSPF6_DUMP_LSA) { prefix2str (&route.route.prefix, pbuf, sizeof (pbuf)); zlog_info (" Prefix: %s", pbuf); } /* set Prefix */ memcpy (p, &route.route.prefix.u.prefix6, OSPF6_PREFIX_SPACE (route.route.prefix.prefixlen)); ospf6_prefix_apply_mask (&external->prefix); size += OSPF6_PREFIX_SPACE (route.route.prefix.prefixlen); p += OSPF6_PREFIX_SPACE (route.route.prefix.prefixlen); /* Forwarding address */ if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F)) { memcpy (p, &route.nexthop.address, sizeof (struct in6_addr)); size += sizeof (struct in6_addr); p += sizeof (struct in6_addr); } /* External Route Tag */ if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T)) { /* xxx */ } ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_AS_EXTERNAL), route.path.origin.id, ospf6->router_id, (char *) external, size, ospf6); return; }
static bool inetAddressToSockaddr(JNIEnv* env, jobject inetAddress, int port, sockaddr_storage* ss, bool map) { memset(ss, 0, sizeof(*ss)); if (inetAddress == NULL) { jniThrowNullPointerException(env, NULL); return false; } // Get the address family. static jfieldID familyFid = env->GetFieldID(JniConstants::inetAddressClass, "family", "I"); ss->ss_family = env->GetIntField(inetAddress, familyFid); if (ss->ss_family == AF_UNSPEC) { return true; // Job done! } // Check this is an address family we support. if (ss->ss_family != AF_INET && ss->ss_family != AF_INET6) { jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "inetAddressToSockaddr bad family: %i", ss->ss_family); return false; } // Get the byte array that stores the IP address bytes in the InetAddress. static jfieldID bytesFid = env->GetFieldID(JniConstants::inetAddressClass, "ipaddress", "[B"); ScopedLocalRef<jbyteArray> addressBytes(env, reinterpret_cast<jbyteArray>(env->GetObjectField(inetAddress, bytesFid))); if (addressBytes.get() == NULL) { jniThrowNullPointerException(env, NULL); return false; } // We use AF_INET6 sockets, so we want an IPv6 address (which may be a IPv4-mapped address). sockaddr_in6* sin6 = reinterpret_cast<sockaddr_in6*>(ss); sin6->sin6_port = htons(port); if (ss->ss_family == AF_INET6) { // IPv6 address. Copy the bytes... jbyte* dst = reinterpret_cast<jbyte*>(&sin6->sin6_addr.s6_addr); env->GetByteArrayRegion(addressBytes.get(), 0, 16, dst); // ...and set the scope id... static jfieldID scopeFid = env->GetFieldID(JniConstants::inet6AddressClass, "scope_id", "I"); sin6->sin6_scope_id = env->GetIntField(inetAddress, scopeFid); return true; } // Deal with Inet4Address instances. if (map) { // We should represent this Inet4Address as an IPv4-mapped IPv6 sockaddr_in6. // Change the family... sin6->sin6_family = AF_INET6; // Copy the bytes... jbyte* dst = reinterpret_cast<jbyte*>(&sin6->sin6_addr.s6_addr[12]); env->GetByteArrayRegion(addressBytes.get(), 0, 4, dst); // INADDR_ANY and in6addr_any are both all-zeros... if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { // ...but all other IPv4-mapped addresses are ::ffff:a.b.c.d, so insert the ffff... memset(&(sin6->sin6_addr.s6_addr[10]), 0xff, 2); } } else { // We should represent this Inet4Address as an IPv4 sockaddr_in. sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(ss); sin->sin_port = htons(port); jbyte* dst = reinterpret_cast<jbyte*>(&sin->sin_addr.s_addr); env->GetByteArrayRegion(addressBytes.get(), 0, 4, dst); } return true; }
static GPtrArray * read_ip6_addresses (GKeyFile *file, const char *setting_name, const char *key) { GPtrArray *addresses; struct in6_addr addr, gw; guint32 prefix; int i = 0; addresses = g_ptr_array_sized_new (3); /* Look for individual addresses */ while (i++ < 1000) { char *tmp, *key_name, *str_prefix, *str_gw; int ret; GValueArray *values; GByteArray *address; GByteArray *gateway; GValue value = { 0 }; key_name = g_strdup_printf ("%s%d", key, i); tmp = g_key_file_get_string (file, setting_name, key_name, NULL); g_free (key_name); if (!tmp) break; /* all done */ /* convert the string array into IPv6 addresses */ values = g_value_array_new (2); /* NMIP6Address has 2 items */ /* Split the address and prefix */ str_prefix = split_prefix (tmp); /* address */ ret = inet_pton (AF_INET6, tmp, &addr); if (ret <= 0) { g_warning ("%s: ignoring invalid IPv6 %s element '%s'", __func__, key_name, tmp); g_value_array_free (values); goto next; } address = g_byte_array_new (); g_byte_array_append (address, (guint8 *) addr.s6_addr, 16); g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY); g_value_take_boxed (&value, address); g_value_array_append (values, &value); g_value_unset (&value); /* prefix */ prefix = 0; if (str_prefix) { if (!get_one_int (str_prefix, 128, key_name, &prefix)) { g_value_array_free (values); goto next; } } else { /* Missing prefix defaults to /64 */ prefix = 64; } g_value_init (&value, G_TYPE_UINT); g_value_set_uint (&value, prefix); g_value_array_append (values, &value); g_value_unset (&value); /* Gateway (optional) */ str_gw = split_gw (str_prefix); if (str_gw) { ret = inet_pton (AF_INET6, str_gw, &gw); if (ret <= 0) { g_warning ("%s: ignoring invalid IPv6 %s gateway '%s'", __func__, key_name, tmp); g_value_array_free (values); goto next; } if (!IN6_IS_ADDR_UNSPECIFIED (&gw)) { gateway = g_byte_array_new (); g_byte_array_append (gateway, (guint8 *) gw.s6_addr, 16); g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY); g_value_take_boxed (&value, gateway); g_value_array_append (values, &value); g_value_unset (&value); } } g_ptr_array_add (addresses, values); next: g_free (tmp); } if (addresses->len < 1) { g_ptr_array_free (addresses, TRUE); addresses = NULL; } return addresses; }
int udp6_input(struct mbuf **mp, int *offp, int proto) { struct mbuf *m = *mp; struct ifnet *ifp; struct ip6_hdr *ip6; struct udphdr *uh; struct inpcb *inp; struct inpcbinfo *pcbinfo; struct udpcb *up; int off = *offp; int cscov_partial; int plen, ulen; struct sockaddr_in6 fromsa; struct m_tag *fwd_tag; uint16_t uh_sum; uint8_t nxt; ifp = m->m_pkthdr.rcvif; ip6 = mtod(m, struct ip6_hdr *); #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); ip6 = mtod(m, struct ip6_hdr *); uh = (struct udphdr *)((caddr_t)ip6 + off); #else IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(*uh)); if (!uh) return (IPPROTO_DONE); #endif UDPSTAT_INC(udps_ipackets); /* * Destination port of 0 is illegal, based on RFC768. */ if (uh->uh_dport == 0) goto badunlocked; plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6); ulen = ntohs((u_short)uh->uh_ulen); nxt = ip6->ip6_nxt; cscov_partial = (nxt == IPPROTO_UDPLITE) ? 1 : 0; if (nxt == IPPROTO_UDPLITE) { /* Zero means checksum over the complete packet. */ if (ulen == 0) ulen = plen; if (ulen == plen) cscov_partial = 0; if ((ulen < sizeof(struct udphdr)) || (ulen > plen)) { /* XXX: What is the right UDPLite MIB counter? */ goto badunlocked; } if (uh->uh_sum == 0) { /* XXX: What is the right UDPLite MIB counter? */ goto badunlocked; } } else { if ((ulen < sizeof(struct udphdr)) || (plen != ulen)) { UDPSTAT_INC(udps_badlen); goto badunlocked; } if (uh->uh_sum == 0) { UDPSTAT_INC(udps_nosum); goto badunlocked; } } if ((m->m_pkthdr.csum_flags & CSUM_DATA_VALID_IPV6) && !cscov_partial) { if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) uh_sum = m->m_pkthdr.csum_data; else uh_sum = in6_cksum_pseudo(ip6, ulen, nxt, m->m_pkthdr.csum_data); uh_sum ^= 0xffff; } else uh_sum = in6_cksum_partial(m, nxt, off, plen, ulen); if (uh_sum != 0) { UDPSTAT_INC(udps_badsum); goto badunlocked; } /* * Construct sockaddr format source address. */ init_sin6(&fromsa, m); fromsa.sin6_port = uh->uh_sport; pcbinfo = udp_get_inpcbinfo(nxt); if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { struct inpcb *last; struct inpcbhead *pcblist; struct ip6_moptions *imo; INP_INFO_RLOCK(pcbinfo); /* * In the event that laddr should be set to the link-local * address (this happens in RIPng), the multicast address * specified in the received packet will not match laddr. To * handle this situation, matching is relaxed if the * receiving interface is the same as one specified in the * socket and if the destination multicast address matches * one of the multicast groups specified in the socket. */ /* * KAME note: traditionally we dropped udpiphdr from mbuf * here. We need udphdr for IPsec processing so we do that * later. */ pcblist = udp_get_pcblist(nxt); last = NULL; LIST_FOREACH(inp, pcblist, inp_list) { if ((inp->inp_vflag & INP_IPV6) == 0) continue; if (inp->inp_lport != uh->uh_dport) continue; if (inp->inp_fport != 0 && inp->inp_fport != uh->uh_sport) continue; if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) { if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, &ip6->ip6_dst)) continue; } if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, &ip6->ip6_src) || inp->inp_fport != uh->uh_sport) continue; } /* * XXXRW: Because we weren't holding either the inpcb * or the hash lock when we checked for a match * before, we should probably recheck now that the * inpcb lock is (supposed to be) held. */ /* * Handle socket delivery policy for any-source * and source-specific multicast. [RFC3678] */ imo = inp->in6p_moptions; if (imo && IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { struct sockaddr_in6 mcaddr; int blocked; INP_RLOCK(inp); bzero(&mcaddr, sizeof(struct sockaddr_in6)); mcaddr.sin6_len = sizeof(struct sockaddr_in6); mcaddr.sin6_family = AF_INET6; mcaddr.sin6_addr = ip6->ip6_dst; blocked = im6o_mc_filter(imo, ifp, (struct sockaddr *)&mcaddr, (struct sockaddr *)&fromsa); if (blocked != MCAST_PASS) { if (blocked == MCAST_NOTGMEMBER) IP6STAT_INC(ip6s_notmember); if (blocked == MCAST_NOTSMEMBER || blocked == MCAST_MUTED) UDPSTAT_INC(udps_filtermcast); INP_RUNLOCK(inp); /* XXX */ continue; } INP_RUNLOCK(inp); } if (last != NULL) { struct mbuf *n; if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { INP_RLOCK(last); UDP_PROBE(receive, NULL, last, ip6, last, uh); if (udp6_append(last, n, off, &fromsa)) goto inp_lost; INP_RUNLOCK(last); } } last = inp; /* * Don't look for additional matches if this one does * not have either the SO_REUSEPORT or SO_REUSEADDR * socket options set. This heuristic avoids * searching through all pcbs in the common case of a * non-shared port. It assumes that an application * will never clear these options after setting them. */ if ((last->inp_socket->so_options & (SO_REUSEPORT|SO_REUSEADDR)) == 0) break; } if (last == NULL) { /* * No matching pcb found; discard datagram. (No need * to send an ICMP Port Unreachable for a broadcast * or multicast datgram.) */ UDPSTAT_INC(udps_noport); UDPSTAT_INC(udps_noportmcast); goto badheadlocked; } INP_RLOCK(last); INP_INFO_RUNLOCK(pcbinfo); UDP_PROBE(receive, NULL, last, ip6, last, uh); if (udp6_append(last, m, off, &fromsa) == 0) INP_RUNLOCK(last); inp_lost: return (IPPROTO_DONE); } /* * Locate pcb for datagram. */ /* * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. */ if ((m->m_flags & M_IP6_NEXTHOP) && (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) { struct sockaddr_in6 *next_hop6; next_hop6 = (struct sockaddr_in6 *)(fwd_tag + 1); /* * Transparently forwarded. Pretend to be the destination. * Already got one like this? */ inp = in6_pcblookup_mbuf(pcbinfo, &ip6->ip6_src, uh->uh_sport, &ip6->ip6_dst, uh->uh_dport, INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif, m); if (!inp) { /* * It's new. Try to find the ambushing socket. * Because we've rewritten the destination address, * any hardware-generated hash is ignored. */ inp = in6_pcblookup(pcbinfo, &ip6->ip6_src, uh->uh_sport, &next_hop6->sin6_addr, next_hop6->sin6_port ? htons(next_hop6->sin6_port) : uh->uh_dport, INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif); } /* Remove the tag from the packet. We don't need it anymore. */ m_tag_delete(m, fwd_tag); m->m_flags &= ~M_IP6_NEXTHOP; } else inp = in6_pcblookup_mbuf(pcbinfo, &ip6->ip6_src, uh->uh_sport, &ip6->ip6_dst, uh->uh_dport, INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif, m); if (inp == NULL) { if (udp_log_in_vain) { char ip6bufs[INET6_ADDRSTRLEN]; char ip6bufd[INET6_ADDRSTRLEN]; log(LOG_INFO, "Connection attempt to UDP [%s]:%d from [%s]:%d\n", ip6_sprintf(ip6bufd, &ip6->ip6_dst), ntohs(uh->uh_dport), ip6_sprintf(ip6bufs, &ip6->ip6_src), ntohs(uh->uh_sport)); } UDPSTAT_INC(udps_noport); if (m->m_flags & M_MCAST) { printf("UDP6: M_MCAST is set in a unicast packet.\n"); UDPSTAT_INC(udps_noportmcast); goto badunlocked; } if (V_udp_blackhole) goto badunlocked; if (badport_bandlim(BANDLIM_ICMP6_UNREACH) < 0) goto badunlocked; icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0); return (IPPROTO_DONE); } INP_RLOCK_ASSERT(inp); up = intoudpcb(inp); if (cscov_partial) { if (up->u_rxcslen == 0 || up->u_rxcslen > ulen) { INP_RUNLOCK(inp); m_freem(m); return (IPPROTO_DONE); } } UDP_PROBE(receive, NULL, inp, ip6, inp, uh); if (udp6_append(inp, m, off, &fromsa) == 0) INP_RUNLOCK(inp); return (IPPROTO_DONE); badheadlocked: INP_INFO_RUNLOCK(pcbinfo); badunlocked: if (m) m_freem(m); return (IPPROTO_DONE); }
static int udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6, struct mbuf *control, struct thread *td) { u_int32_t ulen = m->m_pkthdr.len; u_int32_t plen = sizeof(struct udphdr) + ulen; struct ip6_hdr *ip6; struct udphdr *udp6; struct in6_addr *laddr, *faddr, in6a; struct sockaddr_in6 *sin6 = NULL; struct ifnet *oifp = NULL; int cscov_partial = 0; int scope_ambiguous = 0; u_short fport; int error = 0; uint8_t nxt; uint16_t cscov = 0; struct ip6_pktopts *optp, opt; int af = AF_INET6, hlen = sizeof(struct ip6_hdr); int flags; struct sockaddr_in6 tmp; INP_WLOCK_ASSERT(inp); INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo); if (addr6) { /* addr6 has been validated in udp6_send(). */ sin6 = (struct sockaddr_in6 *)addr6; /* protect *sin6 from overwrites */ tmp = *sin6; sin6 = &tmp; /* * Application should provide a proper zone ID or the use of * default zone IDs should be enabled. Unfortunately, some * applications do not behave as it should, so we need a * workaround. Even if an appropriate ID is not determined, * we'll see if we can determine the outgoing interface. If we * can, determine the zone ID based on the interface below. */ if (sin6->sin6_scope_id == 0 && !V_ip6_use_defzone) scope_ambiguous = 1; if ((error = sa6_embedscope(sin6, V_ip6_use_defzone)) != 0) return (error); } if (control) { if ((error = ip6_setpktopts(control, &opt, inp->in6p_outputopts, td->td_ucred, IPPROTO_UDP)) != 0) goto release; optp = &opt; } else optp = inp->in6p_outputopts; if (sin6) { faddr = &sin6->sin6_addr; /* * Since we saw no essential reason for calling in_pcbconnect, * we get rid of such kind of logic, and call in6_selectsrc * and in6_pcbsetport in order to fill in the local address * and the local port. */ if (sin6->sin6_port == 0) { error = EADDRNOTAVAIL; goto release; } if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { /* how about ::ffff:0.0.0.0 case? */ error = EISCONN; goto release; } fport = sin6->sin6_port; /* allow 0 port */ if (IN6_IS_ADDR_V4MAPPED(faddr)) { if ((inp->inp_flags & IN6P_IPV6_V6ONLY)) { /* * I believe we should explicitly discard the * packet when mapped addresses are disabled, * rather than send the packet as an IPv6 one. * If we chose the latter approach, the packet * might be sent out on the wire based on the * default route, the situation which we'd * probably want to avoid. * (20010421 [email protected]) */ error = EINVAL; goto release; } if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) && !IN6_IS_ADDR_V4MAPPED(&inp->in6p_laddr)) { /* * when remote addr is an IPv4-mapped address, * local addr should not be an IPv6 address, * since you cannot determine how to map IPv6 * source address to IPv4. */ error = EINVAL; goto release; } af = AF_INET; } if (!IN6_IS_ADDR_V4MAPPED(faddr)) { error = in6_selectsrc(sin6, optp, inp, NULL, td->td_ucred, &oifp, &in6a); if (error) goto release; if (oifp && scope_ambiguous && (error = in6_setscope(&sin6->sin6_addr, oifp, NULL))) { goto release; } laddr = &in6a; } else laddr = &inp->in6p_laddr; /* XXX */ if (laddr == NULL) { if (error == 0) error = EADDRNOTAVAIL; goto release; } if (inp->inp_lport == 0 && (error = in6_pcbsetport(laddr, inp, td->td_ucred)) != 0) { /* Undo an address bind that may have occurred. */ inp->in6p_laddr = in6addr_any; goto release; } } else { if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { error = ENOTCONN; goto release; } if (IN6_IS_ADDR_V4MAPPED(&inp->in6p_faddr)) { if ((inp->inp_flags & IN6P_IPV6_V6ONLY)) { /* * XXX: this case would happen when the * application sets the V6ONLY flag after * connecting the foreign address. * Such applications should be fixed, * so we bark here. */ log(LOG_INFO, "udp6_output: IPV6_V6ONLY " "option was set for a connected socket\n"); error = EINVAL; goto release; } else af = AF_INET; } laddr = &inp->in6p_laddr; faddr = &inp->in6p_faddr; fport = inp->inp_fport; } if (af == AF_INET) hlen = sizeof(struct ip); /* * Calculate data length and get a mbuf * for UDP and IP6 headers. */ M_PREPEND(m, hlen + sizeof(struct udphdr), M_NOWAIT); if (m == 0) { error = ENOBUFS; goto release; } /* * Stuff checksum and output datagram. */ nxt = (inp->inp_socket->so_proto->pr_protocol == IPPROTO_UDP) ? IPPROTO_UDP : IPPROTO_UDPLITE; udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen); udp6->uh_sport = inp->inp_lport; /* lport is always set in the PCB */ udp6->uh_dport = fport; if (nxt == IPPROTO_UDPLITE) { struct udpcb *up; up = intoudpcb(inp); cscov = up->u_txcslen; if (cscov >= plen) cscov = 0; udp6->uh_ulen = htons(cscov); /* * For UDP-Lite, checksum coverage length of zero means * the entire UDPLite packet is covered by the checksum. */ cscov_partial = (cscov == 0) ? 0 : 1; } else if (plen <= 0xffff) udp6->uh_ulen = htons((u_short)plen); else udp6->uh_ulen = 0; udp6->uh_sum = 0; switch (af) { case AF_INET6: ip6 = mtod(m, struct ip6_hdr *); ip6->ip6_flow = inp->inp_flow & IPV6_FLOWINFO_MASK; ip6->ip6_vfc &= ~IPV6_VERSION_MASK; ip6->ip6_vfc |= IPV6_VERSION; ip6->ip6_plen = htons((u_short)plen); ip6->ip6_nxt = nxt; ip6->ip6_hlim = in6_selecthlim(inp, NULL); ip6->ip6_src = *laddr; ip6->ip6_dst = *faddr; if (cscov_partial) { if ((udp6->uh_sum = in6_cksum_partial(m, nxt, sizeof(struct ip6_hdr), plen, cscov)) == 0) udp6->uh_sum = 0xffff; } else { udp6->uh_sum = in6_cksum_pseudo(ip6, plen, nxt, 0); m->m_pkthdr.csum_flags = CSUM_UDP_IPV6; m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); } #ifdef RSS { uint32_t hash_val, hash_type; uint8_t pr; pr = inp->inp_socket->so_proto->pr_protocol; /* * Calculate an appropriate RSS hash for UDP and * UDP Lite. * * The called function will take care of figuring out * whether a 2-tuple or 4-tuple hash is required based * on the currently configured scheme. * * Later later on connected socket values should be * cached in the inpcb and reused, rather than constantly * re-calculating it. * * UDP Lite is a different protocol number and will * likely end up being hashed as a 2-tuple until * RSS / NICs grow UDP Lite protocol awareness. */ if (rss_proto_software_hash_v6(faddr, laddr, fport, inp->inp_lport, pr, &hash_val, &hash_type) == 0) { m->m_pkthdr.flowid = hash_val; M_HASHTYPE_SET(m, hash_type); } } #endif flags = 0; #ifdef RSS /* * Don't override with the inp cached flowid. * * Until the whole UDP path is vetted, it may actually * be incorrect. */ flags |= IP_NODEFAULTFLOWID; #endif UDP_PROBE(send, NULL, inp, ip6, inp, udp6); UDPSTAT_INC(udps_opackets); error = ip6_output(m, optp, NULL, flags, inp->in6p_moptions, NULL, inp); break; case AF_INET: error = EAFNOSUPPORT; goto release; } goto releaseopt; release: m_freem(m); releaseopt: if (control) { ip6_clearpktopts(&opt, -1); m_freem(control); } return (error); }
/* * rad_continue_send_request() has given us `got' (non-zero). Deal with it. */ static void radius_Process(struct radius *r, int got) { char *argv[MAXARGS], *nuke; struct bundle *bundle; int argc, addrs, res, width; size_t len; struct ncprange dest; struct ncpaddr gw; const void *data; const char *stype; u_int32_t ipaddr, vendor; struct in_addr ip; #ifndef NOINET6 uint8_t ipv6addr[INET6_ADDRSTRLEN]; struct in6_addr ip6; #endif r->cx.fd = -1; /* Stop select()ing */ stype = r->cx.auth ? "auth" : "acct"; switch (got) { case RAD_ACCESS_ACCEPT: log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, "Radius(%s): ACCEPT received\n", stype); if (!r->cx.auth) { rad_close(r->cx.rad); return; } break; case RAD_ACCESS_REJECT: log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, "Radius(%s): REJECT received\n", stype); if (!r->cx.auth) { rad_close(r->cx.rad); return; } break; case RAD_ACCESS_CHALLENGE: /* we can't deal with this (for now) ! */ log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, "Radius: CHALLENGE received (can't handle yet)\n"); if (r->cx.auth) auth_Failure(r->cx.auth); rad_close(r->cx.rad); return; case RAD_ACCOUNTING_RESPONSE: /* * It's probably not ideal to log this at PHASE level as we'll see * too much stuff going to the log when ``set rad_alive'' is used. * So we differ from older behaviour (ppp version 3.1 and before) * and just log accounting responses to LogRADIUS. */ log_Printf(LogRADIUS, "Radius(%s): Accounting response received\n", stype); if (r->cx.auth) auth_Failure(r->cx.auth); /* unexpected !!! */ /* No further processing for accounting requests, please */ rad_close(r->cx.rad); return; case -1: log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, "radius(%s): %s\n", stype, rad_strerror(r->cx.rad)); if (r->cx.auth) auth_Failure(r->cx.auth); rad_close(r->cx.rad); return; default: log_Printf(LogERROR, "rad_send_request(%s): Failed %d: %s\n", stype, got, rad_strerror(r->cx.rad)); if (r->cx.auth) auth_Failure(r->cx.auth); rad_close(r->cx.rad); return; } /* Let's see what we've got in our reply */ r->ip.s_addr = r->mask.s_addr = INADDR_NONE; r->mtu = 0; r->vj = 0; while ((res = rad_get_attr(r->cx.rad, &data, &len)) > 0) { switch (res) { case RAD_FRAMED_IP_ADDRESS: r->ip = rad_cvt_addr(data); log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, " IP %s\n", inet_ntoa(r->ip)); break; case RAD_FILTER_ID: free(r->filterid); if ((r->filterid = rad_cvt_string(data, len)) == NULL) { log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); auth_Failure(r->cx.auth); rad_close(r->cx.rad); return; } log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, " Filter \"%s\"\n", r->filterid); break; case RAD_SESSION_TIMEOUT: r->sessiontime = rad_cvt_int(data); log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, " Session-Timeout %lu\n", r->sessiontime); break; case RAD_FRAMED_IP_NETMASK: r->mask = rad_cvt_addr(data); log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, " Netmask %s\n", inet_ntoa(r->mask)); break; case RAD_FRAMED_MTU: r->mtu = rad_cvt_int(data); log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, " MTU %lu\n", r->mtu); break; case RAD_FRAMED_ROUTING: /* Disabled for now - should we automatically set up some filters ? */ /* rad_cvt_int(data); */ /* bit 1 = Send routing packets */ /* bit 2 = Receive routing packets */ break; case RAD_FRAMED_COMPRESSION: r->vj = rad_cvt_int(data) == 1 ? 1 : 0; log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, " VJ %sabled\n", r->vj ? "en" : "dis"); break; case RAD_FRAMED_ROUTE: /* * We expect a string of the format ``dest[/bits] gw [metrics]'' * Any specified metrics are ignored. MYADDR and HISADDR are * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same * as ``HISADDR''. */ if ((nuke = rad_cvt_string(data, len)) == NULL) { log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); auth_Failure(r->cx.auth); rad_close(r->cx.rad); return; } log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, " Route: %s\n", nuke); bundle = r->cx.auth->physical->dl->bundle; ip.s_addr = INADDR_ANY; ncpaddr_setip4(&gw, ip); ncprange_setip4host(&dest, ip); argc = command_Interpret(nuke, strlen(nuke), argv); if (argc < 0) log_Printf(LogWARN, "radius: %s: Syntax error\n", argc == 1 ? argv[0] : "\"\""); else if (argc < 2) log_Printf(LogWARN, "radius: %s: Invalid route\n", argc == 1 ? argv[0] : "\"\""); else if ((strcasecmp(argv[0], "default") != 0 && !ncprange_aton(&dest, &bundle->ncp, argv[0])) || !ncpaddr_aton(&gw, &bundle->ncp, argv[1])) log_Printf(LogWARN, "radius: %s %s: Invalid route\n", argv[0], argv[1]); else { ncprange_getwidth(&dest, &width); if (width == 32 && strchr(argv[0], '/') == NULL) { /* No mask specified - use the natural mask */ ncprange_getip4addr(&dest, &ip); ncprange_setip4mask(&dest, addr2mask(ip)); } addrs = 0; if (!strncasecmp(argv[0], "HISADDR", 7)) addrs = ROUTE_DSTHISADDR; else if (!strncasecmp(argv[0], "MYADDR", 6)) addrs = ROUTE_DSTMYADDR; if (ncpaddr_getip4addr(&gw, &ipaddr) && ipaddr == INADDR_ANY) { addrs |= ROUTE_GWHISADDR; ncpaddr_setip4(&gw, bundle->ncp.ipcp.peer_ip); } else if (strcasecmp(argv[1], "HISADDR") == 0) addrs |= ROUTE_GWHISADDR; route_Add(&r->routes, addrs, &dest, &gw); } free(nuke); break; case RAD_REPLY_MESSAGE: free(r->repstr); if ((r->repstr = rad_cvt_string(data, len)) == NULL) { log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); auth_Failure(r->cx.auth); rad_close(r->cx.rad); return; } log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, " Reply-Message \"%s\"\n", r->repstr); break; #ifndef NOINET6 case RAD_FRAMED_IPV6_PREFIX: free(r->ipv6prefix); if ((r->ipv6prefix = rad_cvt_ipv6prefix(data, len)) == NULL) { log_Printf(LogERROR, "rad_cvt_ipv6prefix: %s\n", "Malformed attribute in response"); auth_Failure(r->cx.auth); rad_close(r->cx.rad); return; } inet_ntop(AF_INET6, &r->ipv6prefix[2], ipv6addr, sizeof(ipv6addr)); log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, " IPv6 %s/%d\n", ipv6addr, r->ipv6prefix[1]); break; case RAD_FRAMED_IPV6_ROUTE: /* * We expect a string of the format ``dest[/bits] gw [metrics]'' * Any specified metrics are ignored. MYADDR6 and HISADDR6 are * understood for ``dest'' and ``gw'' and ``::'' is the same * as ``HISADDR6''. */ if ((nuke = rad_cvt_string(data, len)) == NULL) { log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); auth_Failure(r->cx.auth); rad_close(r->cx.rad); return; } log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, " IPv6 Route: %s\n", nuke); bundle = r->cx.auth->physical->dl->bundle; ncpaddr_setip6(&gw, &in6addr_any); ncprange_set(&dest, &gw, 0); argc = command_Interpret(nuke, strlen(nuke), argv); if (argc < 0) log_Printf(LogWARN, "radius: %s: Syntax error\n", argc == 1 ? argv[0] : "\"\""); else if (argc < 2) log_Printf(LogWARN, "radius: %s: Invalid route\n", argc == 1 ? argv[0] : "\"\""); else if ((strcasecmp(argv[0], "default") != 0 && !ncprange_aton(&dest, &bundle->ncp, argv[0])) || !ncpaddr_aton(&gw, &bundle->ncp, argv[1])) log_Printf(LogWARN, "radius: %s %s: Invalid route\n", argv[0], argv[1]); else { addrs = 0; if (!strncasecmp(argv[0], "HISADDR6", 8)) addrs = ROUTE_DSTHISADDR6; else if (!strncasecmp(argv[0], "MYADDR6", 7)) addrs = ROUTE_DSTMYADDR6; if (ncpaddr_getip6(&gw, &ip6) && IN6_IS_ADDR_UNSPECIFIED(&ip6)) { addrs |= ROUTE_GWHISADDR6; ncpaddr_copy(&gw, &bundle->ncp.ipv6cp.hisaddr); } else if (strcasecmp(argv[1], "HISADDR6") == 0) addrs |= ROUTE_GWHISADDR6; route_Add(&r->ipv6routes, addrs, &dest, &gw); } free(nuke); break; #endif case RAD_VENDOR_SPECIFIC: if ((res = rad_get_vendor_attr(&vendor, &data, &len)) <= 0) { log_Printf(LogERROR, "rad_get_vendor_attr: %s (failing!)\n", rad_strerror(r->cx.rad)); auth_Failure(r->cx.auth); rad_close(r->cx.rad); return; } switch (vendor) { case RAD_VENDOR_MICROSOFT: switch (res) { #ifndef NODES case RAD_MICROSOFT_MS_CHAP_ERROR: free(r->errstr); if (len == 0) r->errstr = NULL; else { if (len < 3 || ((const char *)data)[1] != '=') { /* * Only point at the String field if we don't think the * peer has misformatted the response. */ data = (const char *)data + 1; len--; } else log_Printf(LogWARN, "Warning: The MS-CHAP-Error " "attribute is mis-formatted. Compensating\n"); if ((r->errstr = rad_cvt_string((const char *)data, len)) == NULL) { log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); auth_Failure(r->cx.auth); rad_close(r->cx.rad); return; } log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, " MS-CHAP-Error \"%s\"\n", r->errstr); } break; case RAD_MICROSOFT_MS_CHAP2_SUCCESS: free(r->msrepstr); if (len == 0) r->msrepstr = NULL; else { if (len < 3 || ((const char *)data)[1] != '=') { /* * Only point at the String field if we don't think the * peer has misformatted the response. */ data = (const char *)data + 1; len--; } else log_Printf(LogWARN, "Warning: The MS-CHAP2-Success " "attribute is mis-formatted. Compensating\n"); if ((r->msrepstr = rad_cvt_string((const char *)data, len)) == NULL) { log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); auth_Failure(r->cx.auth); rad_close(r->cx.rad); return; } log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, " MS-CHAP2-Success \"%s\"\n", r->msrepstr); } break; case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY: r->mppe.policy = rad_cvt_int(data); log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, " MS-MPPE-Encryption-Policy %s\n", radius_policyname(r->mppe.policy)); break; case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES: r->mppe.types = rad_cvt_int(data); log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, " MS-MPPE-Encryption-Types %s\n", radius_typesname(r->mppe.types)); break; case RAD_MICROSOFT_MS_MPPE_RECV_KEY: free(r->mppe.recvkey); demangle(r, data, len, &r->mppe.recvkey, &r->mppe.recvkeylen); log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, " MS-MPPE-Recv-Key ********\n"); break; case RAD_MICROSOFT_MS_MPPE_SEND_KEY: demangle(r, data, len, &r->mppe.sendkey, &r->mppe.sendkeylen); log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE, " MS-MPPE-Send-Key ********\n"); break; #endif default: log_Printf(LogDEBUG, "Dropping MICROSOFT vendor specific " "RADIUS attribute %d\n", res); break; } break; default: log_Printf(LogDEBUG, "Dropping vendor %lu RADIUS attribute %d\n", (unsigned long)vendor, res); break; } break; default: log_Printf(LogDEBUG, "Dropping RADIUS attribute %d\n", res); break; } } if (res == -1) { log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n", rad_strerror(r->cx.rad)); auth_Failure(r->cx.auth); } else if (got == RAD_ACCESS_REJECT) auth_Failure(r->cx.auth); else { r->valid = 1; auth_Success(r->cx.auth); } rad_close(r->cx.rad); }
static int udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td) { struct inpcb *inp; struct inpcbinfo *pcbinfo; struct sockaddr_in6 *sin6; int error; pcbinfo = udp_get_inpcbinfo(so->so_proto->pr_protocol); inp = sotoinpcb(so); sin6 = (struct sockaddr_in6 *)nam; KASSERT(inp != NULL, ("udp6_connect: inp == NULL")); /* * XXXRW: Need to clarify locking of v4/v6 flags. */ INP_WLOCK(inp); #ifdef INET if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { struct sockaddr_in sin; if ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0) { error = EINVAL; goto out; } if (inp->inp_faddr.s_addr != INADDR_ANY) { error = EISCONN; goto out; } in6_sin6_2_sin(&sin, sin6); inp->inp_vflag |= INP_IPV4; inp->inp_vflag &= ~INP_IPV6; error = prison_remote_ip4(td->td_ucred, &sin.sin_addr); if (error != 0) goto out; INP_HASH_WLOCK(pcbinfo); error = in_pcbconnect(inp, (struct sockaddr *)&sin, td->td_ucred); INP_HASH_WUNLOCK(pcbinfo); if (error == 0) soisconnected(so); goto out; } #endif if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { error = EISCONN; goto out; } inp->inp_vflag &= ~INP_IPV4; inp->inp_vflag |= INP_IPV6; error = prison_remote_ip6(td->td_ucred, &sin6->sin6_addr); if (error != 0) goto out; INP_HASH_WLOCK(pcbinfo); error = in6_pcbconnect(inp, nam, td->td_ucred); INP_HASH_WUNLOCK(pcbinfo); if (error == 0) soisconnected(so); out: INP_WUNLOCK(inp); return (error); }
static void outputpcb(int proto, const char *name, struct inpcb *inp, struct xsocket *so, struct tcpcb *tp) { const char *vchar; static struct clockinfo clockinfo; if (clockinfo.hz == 0) { size_t size = sizeof(clockinfo); sysctlbyname("kern.clockrate", &clockinfo, &size, NULL, 0); if (clockinfo.hz == 0) clockinfo.hz = 100; } /* Ignore sockets for protocols other than the desired one. */ if (so->xso_protocol != (int)proto) return; if ((af == AF_INET && (inp->inp_vflag & INP_IPV4) == 0) #ifdef INET6 || (af == AF_INET6 && (inp->inp_vflag & INP_IPV6) == 0) #endif /* INET6 */ || (af == AF_UNSPEC && ((inp->inp_vflag & INP_IPV4) == 0 #ifdef INET6 && (inp->inp_vflag & INP_IPV6) == 0 #endif /* INET6 */ )) ) { return; } if (!aflag && ( (proto == IPPROTO_TCP && tp->t_state == TCPS_LISTEN) || (af == AF_INET && inet_lnaof(inp->inp_laddr) == INADDR_ANY) #ifdef INET6 || (af == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) #endif /* INET6 */ || (af == AF_UNSPEC && (((inp->inp_vflag & INP_IPV4) != 0 && inet_lnaof(inp->inp_laddr) == INADDR_ANY) #ifdef INET6 || ((inp->inp_vflag & INP_IPV6) != 0 && IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) #endif )) )) { return; } if (ppr_first) { if (!Lflag) { printf("Active Internet connections"); if (aflag) printf(" (including servers)"); } else { printf("Current listen queue sizes " "(qlen/incqlen/maxqlen)"); } putchar('\n'); if (Aflag) printf("%-8.8s ", "Socket"); if (Pflag) printf("%8.8s %8.8s %8.8s ", "TxWin", "Unacked", "RTT/ms"); if (Lflag) { printf("%-5.5s %-14.14s %-22.22s\n", "Proto", "Listen", "Local Address"); } else { printf((Aflag && !Wflag) ? "%-5.5s %-6.6s %-6.6s %-17.17s %-17.17s %s\n" : "%-5.5s %-6.6s %-6.6s %-21.21s %-21.21s %s\n", "Proto", "Recv-Q", "Send-Q", "Local Address", "Foreign Address", "(state)"); } ppr_first = 0; } if (Lflag && so->so_qlimit == 0) return; if (Aflag) { if (tp) printf("%8lx ", (u_long)inp->inp_ppcb); else printf("%8lx ", (u_long)so->so_pcb); } if (Pflag) { if (tp) { int window = MIN(tp->snd_cwnd, tp->snd_bwnd); if (window == 1073725440) printf("%8s ", "max"); else printf("%8d ", (int)MIN(tp->snd_cwnd, tp->snd_bwnd)); printf("%8d ", (int)(tp->snd_max - tp->snd_una)); if (tp->t_srtt == 0) printf("%8s ", "-"); else printf("%8.3f ", (double)tp->t_srtt * 1000.0 / TCP_RTT_SCALE / clockinfo.hz); } else { printf("%8s %8s %8s ", "-", "-", "-"); } } #ifdef INET6 if ((inp->inp_vflag & INP_IPV6) != 0) vchar = ((inp->inp_vflag & INP_IPV4) != 0) ? "46" : "6 "; else #endif vchar = ((inp->inp_vflag & INP_IPV4) != 0) ? "4 " : " "; printf("%-3.3s%-2.2s ", name, vchar); if (Lflag) { char buf[15]; snprintf(buf, sizeof(buf), "%d/%d/%d", so->so_qlen, so->so_incqlen, so->so_qlimit); printf("%-13.13s ", buf); } else if (Bflag) { printf("%6ld %6ld ", so->so_rcv.sb_hiwat, so->so_snd.sb_hiwat); } else { printf("%6ld %6ld ", so->so_rcv.sb_cc, so->so_snd.sb_cc); } if (numeric_port) { if (inp->inp_vflag & INP_IPV4) { inetprint(&inp->inp_laddr, (int)inp->inp_lport, name, 1); if (!Lflag) inetprint(&inp->inp_faddr, (int)inp->inp_fport, name, 1); } #ifdef INET6 else if (inp->inp_vflag & INP_IPV6) { inet6print(&inp->in6p_laddr, (int)inp->inp_lport, name, 1); if (!Lflag) inet6print(&inp->in6p_faddr, (int)inp->inp_fport, name, 1); } /* else nothing printed now */ #endif /* INET6 */ } else if (inp->inp_flags & INP_ANONPORT) { if (inp->inp_vflag & INP_IPV4) { inetprint(&inp->inp_laddr, (int)inp->inp_lport, name, 1); if (!Lflag) inetprint(&inp->inp_faddr, (int)inp->inp_fport, name, 0); } #ifdef INET6 else if (inp->inp_vflag & INP_IPV6) { inet6print(&inp->in6p_laddr, (int)inp->inp_lport, name, 1); if (!Lflag) inet6print(&inp->in6p_faddr, (int)inp->inp_fport, name, 0); } /* else nothing printed now */ #endif /* INET6 */ } else { if (inp->inp_vflag & INP_IPV4) { inetprint(&inp->inp_laddr, (int)inp->inp_lport, name, 0); if (!Lflag) inetprint(&inp->inp_faddr, (int)inp->inp_fport, name, inp->inp_lport != inp->inp_fport); } #ifdef INET6 else if (inp->inp_vflag & INP_IPV6) { inet6print(&inp->in6p_laddr, (int)inp->inp_lport, name, 0); if (!Lflag) inet6print(&inp->in6p_faddr, (int)inp->inp_fport, name, inp->inp_lport != inp->inp_fport); } /* else nothing printed now */ #endif /* INET6 */ } if (tp && !Lflag) { if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES) printf("%d", tp->t_state); else { printf("%s", tcpstates[tp->t_state]); #if defined(TF_NEEDSYN) && defined(TF_NEEDFIN) /* Show T/TCP `hidden state' */ if (tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN)) putchar('*'); #endif /* defined(TF_NEEDSYN) && defined(TF_NEEDFIN) */ } } putchar('\n'); }
int if_route6(const struct rt6 *rt, int action) { struct nlmr *nlm; char metricsbuf[32]; struct rtattr *metrics = (void *)metricsbuf; int retval = 0; nlm = calloc(1, sizeof(*nlm)); if (nlm == NULL) return -1; nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); nlm->hdr.nlmsg_type = RTM_NEWROUTE; nlm->hdr.nlmsg_flags = NLM_F_REQUEST; if (action == 0) nlm->hdr.nlmsg_flags |= NLM_F_REPLACE; else if (action == 1) nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; else nlm->hdr.nlmsg_type = RTM_DELROUTE; nlm->rt.rtm_family = AF_INET6; nlm->rt.rtm_table = RT_TABLE_MAIN; if (action == -1 || action == -2) nlm->rt.rtm_scope = RT_SCOPE_NOWHERE; else { nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; /* None interface subnet routes are static. */ if (IN6_IS_ADDR_UNSPECIFIED(&rt->gate)) { nlm->rt.rtm_protocol = RTPROT_KERNEL; nlm->rt.rtm_scope = RT_SCOPE_LINK; } else nlm->rt.rtm_protocol = RTPROT_BOOT; nlm->rt.rtm_type = RTN_UNICAST; } nlm->rt.rtm_dst_len = ipv6_prefixlen(&rt->net); add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_DST, &rt->dest.s6_addr, sizeof(rt->dest.s6_addr)); /* If destination == gateway then don't add the gateway */ if (!IN6_IS_ADDR_UNSPECIFIED(&rt->gate) && !IN6_ARE_ADDR_EQUAL(&rt->dest, &rt->gate)) add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_GATEWAY, &rt->gate.s6_addr, sizeof(rt->gate.s6_addr)); add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_OIF, rt->iface->index); add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_PRIORITY, rt->metric); if (rt->mtu) { metrics->rta_type = RTA_METRICS; metrics->rta_len = RTA_LENGTH(0); rta_add_attr_32(metrics, sizeof(metricsbuf), RTAX_MTU, rt->mtu); add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_METRICS, RTA_DATA(metrics), RTA_PAYLOAD(metrics)); } if (send_netlink(&nlm->hdr) == -1) retval = -1; free(nlm); return retval; errno = ENOTSUP; return -1; }
int sendfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t fromlen, struct sockaddr *to, socklen_t tolen) { struct msghdr msgh; struct cmsghdr *cmsg; struct iovec iov; char cbuf[256]; #ifdef __FreeBSD__ /* * FreeBSD is extra pedantic about the use of IP_SENDSRCADDR, * and sendmsg will fail with EINVAL if IP_SENDSRCADDR is used * with a socket which is bound to something other than * INADDR_ANY */ struct sockaddr bound; socklen_t bound_len = sizeof(bound); if (getsockname(s, &bound, &bound_len) < 0) { return -1; } switch (bound.sa_family) { case AF_INET: if (((struct sockaddr_in *) &bound)->sin_addr.s_addr != INADDR_ANY) { from = NULL; } break; case AF_INET6: if (!IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) &bound)->sin6_addr)) { from = NULL; } break; } #else # if !defined(IP_PKTINFO) && !defined(IP_SENDSRCADDR) && !defined(IPV6_PKTINFO) /* * If the sendmsg() flags aren't defined, fall back to * using sendto(). */ from = NULL; # endif #endif /* * Catch the case where the caller passes invalid arguments. */ if (!from || (fromlen == 0) || (from->sa_family == AF_UNSPEC)) { return sendto(s, buf, len, flags, to, tolen); } /* Set up control buffer iov and msgh structures. */ memset(&cbuf, 0, sizeof(cbuf)); memset(&msgh, 0, sizeof(msgh)); memset(&iov, 0, sizeof(iov)); iov.iov_base = buf; iov.iov_len = len; msgh.msg_iov = &iov; msgh.msg_iovlen = 1; msgh.msg_name = to; msgh.msg_namelen = tolen; if (from->sa_family == AF_INET) { #if !defined(IP_PKTINFO) && !defined(IP_SENDSRCADDR) return sendto(s, buf, len, flags, to, tolen); #else struct sockaddr_in *s4 = (struct sockaddr_in *) from; # ifdef IP_PKTINFO struct in_pktinfo *pkt; msgh.msg_control = cbuf; msgh.msg_controllen = CMSG_SPACE(sizeof(*pkt)); cmsg = CMSG_FIRSTHDR(&msgh); cmsg->cmsg_level = SOL_IP; cmsg->cmsg_type = IP_PKTINFO; cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt)); pkt = (struct in_pktinfo *) CMSG_DATA(cmsg); memset(pkt, 0, sizeof(*pkt)); pkt->ipi_spec_dst = s4->sin_addr; # endif # ifdef IP_SENDSRCADDR struct in_addr *in; msgh.msg_control = cbuf; msgh.msg_controllen = CMSG_SPACE(sizeof(*in)); cmsg = CMSG_FIRSTHDR(&msgh); cmsg->cmsg_level = IPPROTO_IP; cmsg->cmsg_type = IP_SENDSRCADDR; cmsg->cmsg_len = CMSG_LEN(sizeof(*in)); in = (struct in_addr *) CMSG_DATA(cmsg); *in = s4->sin_addr; # endif #endif /* IP_PKTINFO or IP_SENDSRCADDR */ } #ifdef AF_INET6 else if (from->sa_family == AF_INET6) { # if !defined(IPV6_PKTINFO) return sendto(s, buf, len, flags, to, tolen); # else struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) from; struct in6_pktinfo *pkt; msgh.msg_control = cbuf; msgh.msg_controllen = CMSG_SPACE(sizeof(*pkt)); cmsg = CMSG_FIRSTHDR(&msgh); cmsg->cmsg_level = IPPROTO_IPV6; cmsg->cmsg_type = IPV6_PKTINFO; cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt)); pkt = (struct in6_pktinfo *) CMSG_DATA(cmsg); memset(pkt, 0, sizeof(*pkt)); pkt->ipi6_addr = s6->sin6_addr; # endif /* IPV6_PKTINFO */ } #endif /* * Unknown address family. */ else { errno = EINVAL; return -1; } return sendmsg(s, &msgh, flags); }
static bool inetAddressToSockaddr(JNIEnv* env, jobject inetAddress, int port, sockaddr_storage& ss, socklen_t& sa_len, bool map) { memset(&ss, 0, sizeof(ss)); sa_len = 0; if (inetAddress == NULL) { jniThrowNullPointerException(env, NULL); return false; } // Get the address family. static jfieldID familyFid = env->GetFieldID(JniConstants::inetAddressClass, "family", "I"); ss.ss_family = env->GetIntField(inetAddress, familyFid); if (ss.ss_family == AF_UNSPEC) { sa_len = sizeof(ss.ss_family); return true; // Job done! } // Check this is an address family we support. if (ss.ss_family != AF_INET && ss.ss_family != AF_INET6 && ss.ss_family != AF_UNIX) { jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "inetAddressToSockaddr bad family: %i", ss.ss_family); return false; } // Get the byte array that stores the IP address bytes in the InetAddress. static jfieldID bytesFid = env->GetFieldID(JniConstants::inetAddressClass, "ipaddress", "[B"); ScopedLocalRef<jbyteArray> addressBytes(env, reinterpret_cast<jbyteArray>(env->GetObjectField(inetAddress, bytesFid))); if (addressBytes.get() == NULL) { jniThrowNullPointerException(env, NULL); return false; } // Handle the AF_UNIX special case. if (ss.ss_family == AF_UNIX) { sockaddr_un& sun = reinterpret_cast<sockaddr_un&>(ss); size_t path_length = env->GetArrayLength(addressBytes.get()); if (path_length >= sizeof(sun.sun_path)) { jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "inetAddressToSockaddr path too long for AF_UNIX: %i", path_length); return false; } // Copy the bytes... jbyte* dst = reinterpret_cast<jbyte*>(&sun.sun_path); memset(dst, 0, sizeof(sun.sun_path)); env->GetByteArrayRegion(addressBytes.get(), 0, path_length, dst); sa_len = sizeof(sun.sun_path); return true; } // TODO: bionic's getnameinfo(3) seems to want its length parameter to be exactly // sizeof(sockaddr_in) for an IPv4 address and sizeof (sockaddr_in6) for an // IPv6 address. Fix getnameinfo so it accepts sizeof(sockaddr_storage), and // then unconditionally set sa_len to sizeof(sockaddr_storage) instead of having // to deal with this case by case. // We use AF_INET6 sockets, so we want an IPv6 address (which may be a IPv4-mapped address). sockaddr_in6& sin6 = reinterpret_cast<sockaddr_in6&>(ss); sin6.sin6_port = htons(port); if (ss.ss_family == AF_INET6) { // IPv6 address. Copy the bytes... jbyte* dst = reinterpret_cast<jbyte*>(&sin6.sin6_addr.s6_addr); env->GetByteArrayRegion(addressBytes.get(), 0, 16, dst); // ...and set the scope id... static jfieldID scopeFid = env->GetFieldID(JniConstants::inet6AddressClass, "scope_id", "I"); sin6.sin6_scope_id = env->GetIntField(inetAddress, scopeFid); sa_len = sizeof(sockaddr_in6); return true; } // Deal with Inet4Address instances. if (map) { // We should represent this Inet4Address as an IPv4-mapped IPv6 sockaddr_in6. // Change the family... sin6.sin6_family = AF_INET6; // Copy the bytes... jbyte* dst = reinterpret_cast<jbyte*>(&sin6.sin6_addr.s6_addr[12]); env->GetByteArrayRegion(addressBytes.get(), 0, 4, dst); // INADDR_ANY and in6addr_any are both all-zeros... if (!IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)) { // ...but all other IPv4-mapped addresses are ::ffff:a.b.c.d, so insert the ffff... memset(&(sin6.sin6_addr.s6_addr[10]), 0xff, 2); } sa_len = sizeof(sockaddr_in6); } else { // We should represent this Inet4Address as an IPv4 sockaddr_in. sockaddr_in& sin = reinterpret_cast<sockaddr_in&>(ss); sin.sin_port = htons(port); jbyte* dst = reinterpret_cast<jbyte*>(&sin.sin_addr.s_addr); env->GetByteArrayRegion(addressBytes.get(), 0, 4, dst); sa_len = sizeof(sockaddr_in); } return true; }
void ip6_forward(struct mbuf *m, int srcrt) { struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); struct sockaddr_in6 *dst; struct rtentry *rt; int error = 0, type = 0, code = 0; struct mbuf *mcopy = NULL; struct ifnet *origifp; /* maybe unnecessary */ #ifdef IPSEC u_int8_t sproto = 0; struct m_tag *mtag; union sockaddr_union sdst; struct tdb_ident *tdbi; u_int32_t sspi; struct tdb *tdb; int s; #endif /* IPSEC */ u_int rtableid = 0; /* * Do not forward packets to multicast destination (should be handled * by ip6_mforward(). * Do not forward packets with unspecified source. It was discussed * in July 2000, on ipngwg mailing list. */ if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 || IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { ip6stat.ip6s_cantforward++; /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */ if (ip6_log_time + ip6_log_interval < time_second) { ip6_log_time = time_second; log(LOG_DEBUG, "cannot forward " "from %s to %s nxt %d received on %s\n", ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst), ip6->ip6_nxt, m->m_pkthdr.rcvif->if_xname); } m_freem(m); return; } if (ip6->ip6_hlim <= IPV6_HLIMDEC) { /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */ icmp6_error(m, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT, 0); return; } ip6->ip6_hlim -= IPV6_HLIMDEC; #if NPF > 0 reroute: #endif #ifdef IPSEC if (!ipsec_in_use) goto done_spd; s = splnet(); /* * Check if there was an outgoing SA bound to the flow * from a transport protocol. */ /* Do we have any pending SAs to apply ? */ mtag = m_tag_find(m, PACKET_TAG_IPSEC_PENDING_TDB, NULL); if (mtag != NULL) { #ifdef DIAGNOSTIC if (mtag->m_tag_len != sizeof (struct tdb_ident)) panic("ip6_forward: tag of length %d (should be %d", mtag->m_tag_len, sizeof (struct tdb_ident)); #endif tdbi = (struct tdb_ident *)(mtag + 1); tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto); if (tdb == NULL) error = -EINVAL; m_tag_delete(m, mtag); } else tdb = ipsp_spd_lookup(m, AF_INET6, sizeof(struct ip6_hdr), &error, IPSP_DIRECTION_OUT, NULL, NULL); if (tdb == NULL) { splx(s); if (error == 0) { /* * No IPsec processing required, we'll just send the * packet out. */ sproto = 0; /* Fall through to routing/multicast handling */ } else { /* * -EINVAL is used to indicate that the packet should * be silently dropped, typically because we've asked * key management for an SA. */ if (error == -EINVAL) /* Should silently drop packet */ error = 0; goto freecopy; } } else { /* Loop detection */ for (mtag = m_tag_first(m); mtag != NULL; mtag = m_tag_next(m, mtag)) { if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE && mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED) continue; tdbi = (struct tdb_ident *)(mtag + 1); if (tdbi->spi == tdb->tdb_spi && tdbi->proto == tdb->tdb_sproto && !bcmp(&tdbi->dst, &tdb->tdb_dst, sizeof(union sockaddr_union))) { splx(s); sproto = 0; /* mark as no-IPsec-needed */ goto done_spd; } } /* We need to do IPsec */ bcopy(&tdb->tdb_dst, &sdst, sizeof(sdst)); sspi = tdb->tdb_spi; sproto = tdb->tdb_sproto; splx(s); } /* Fall through to the routing/multicast handling code */ done_spd: #endif /* IPSEC */ #if NPF > 0 rtableid = m->m_pkthdr.rdomain; #endif /* * Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU - * size of IPv6 + ICMPv6 headers) bytes of the packet in case * we need to generate an ICMP6 message to the src. * Thanks to M_EXT, in most cases copy will not occur. * * It is important to save it before IPsec processing as IPsec * processing may modify the mbuf. */ mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN)); dst = &ip6_forward_rt.ro_dst; if (!srcrt) { /* * ip6_forward_rt.ro_dst.sin6_addr is equal to ip6->ip6_dst */ if (ip6_forward_rt.ro_rt == 0 || (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) == 0 || ip6_forward_rtableid != rtableid) { if (ip6_forward_rt.ro_rt) { RTFREE(ip6_forward_rt.ro_rt); ip6_forward_rt.ro_rt = 0; } /* this probably fails but give it a try again */ rtalloc_mpath((struct route *)&ip6_forward_rt, &ip6->ip6_src.s6_addr32[0], rtableid); ip6_forward_rtableid = rtableid; } if (ip6_forward_rt.ro_rt == 0) { ip6stat.ip6s_noroute++; /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */ if (mcopy) { icmp6_error(mcopy, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE, 0); } m_freem(m); return; } } else if (ip6_forward_rt.ro_rt == 0 || (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) == 0 || !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst->sin6_addr) || ip6_forward_rtableid != rtableid) { if (ip6_forward_rt.ro_rt) { RTFREE(ip6_forward_rt.ro_rt); ip6_forward_rt.ro_rt = 0; } bzero(dst, sizeof(*dst)); dst->sin6_len = sizeof(struct sockaddr_in6); dst->sin6_family = AF_INET6; dst->sin6_addr = ip6->ip6_dst; rtalloc_mpath((struct route *)&ip6_forward_rt, &ip6->ip6_src.s6_addr32[0], rtableid); ip6_forward_rtableid = rtableid; if (ip6_forward_rt.ro_rt == 0) { ip6stat.ip6s_noroute++; /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */ if (mcopy) { icmp6_error(mcopy, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE, 0); } m_freem(m); return; } } rt = ip6_forward_rt.ro_rt; /* * Scope check: if a packet can't be delivered to its destination * for the reason that the destination is beyond the scope of the * source address, discard the packet and return an icmp6 destination * unreachable error with Code 2 (beyond scope of source address). * [draft-ietf-ipngwg-icmp-v3-00.txt, Section 3.1] */ if (in6_addr2scopeid(m->m_pkthdr.rcvif, &ip6->ip6_src) != in6_addr2scopeid(rt->rt_ifp, &ip6->ip6_src)) { ip6stat.ip6s_cantforward++; ip6stat.ip6s_badscope++; in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard); if (ip6_log_time + ip6_log_interval < time_second) { ip6_log_time = time_second; log(LOG_DEBUG, "cannot forward " "src %s, dst %s, nxt %d, rcvif %s, outif %s\n", ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst), ip6->ip6_nxt, m->m_pkthdr.rcvif->if_xname, rt->rt_ifp->if_xname); } if (mcopy) icmp6_error(mcopy, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_BEYONDSCOPE, 0); m_freem(m); goto freert; } #ifdef IPSEC /* * Check if the packet needs encapsulation. * ipsp_process_packet will never come back to here. * XXX ipsp_process_packet() calls ip6_output(), and there'll be no * PMTU notification. is it okay? */ if (sproto != 0) { s = splnet(); #if NPF > 0 if (pf_test6(PF_OUT, &encif[0].sc_if, &m, NULL) != PF_PASS) { splx(s); error = EHOSTUNREACH; m_freem(m); goto senderr; } if (m == NULL) { splx(s); goto senderr; } ip6 = mtod(m, struct ip6_hdr *); /* * PF_TAG_REROUTE handling or not... * Packet is entering IPsec so the routing is * already overruled by the IPsec policy. * Until now the change was not reconsidered. * What's the behaviour? */ #endif tdb = gettdb(sspi, &sdst, sproto); if (tdb == NULL) { splx(s); error = EHOSTUNREACH; m_freem(m); goto senderr; /*XXX*/ } m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */ /* Callee frees mbuf */ error = ipsp_process_packet(m, tdb, AF_INET6, 0); splx(s); m_freem(mcopy); goto freert; }
void mcast_recv_mld(int sockfd, int version) { unsigned char buf[MAX_RECV_BUF_LEN] = {0}; int num = 0; pi_addr pig, pia; struct msghdr msg; struct sockaddr_in6 sa; struct iovec iov; struct cmsghdr *cmsg; char *ctrl = (char *) malloc(MAXCTRLSIZE); struct in6_pktinfo *info; unsigned int if_index = 0; struct mld_hdr *p_mldh; imp_interface *p_if = NULL; /*To get the unique index of the interfacethe packet was received on*/ bzero(&msg, sizeof(msg)); iov.iov_base = buf; iov.iov_len = 2048; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = ctrl; msg.msg_controllen = MAXCTRLSIZE; msg.msg_name = &sa; msg.msg_namelen = sizeof(struct sockaddr_in6); num = recvmsg(get_igmp_mld_socket(AF_INET6), &msg, MSG_WAITALL); if (num <= 20) { IMP_LOG_ERROR("BAD packet received n=%d \n", num); free(ctrl); return; } for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_type == IPV6_PKTINFO) { info = (struct in6_pktinfo *) CMSG_DATA(cmsg); if_index = info->ipi6_ifindex; imp_build_piaddr(AF_INET6, &info->ipi6_addr, &pig); imp_build_piaddr(AF_INET6, &sa.sin6_addr, &pia); IMP_LOG_DEBUG("from %s %s %d\n", imp_pi_ntoa(&pig), imp_pi_ntoa(&pia), if_index); } } free(ctrl); if (if_index == 0) { /* * Structure used to communicate from kernel to multicast router. * We'll overlay the structure onto an MLD header (not an IPv6 heder like igmpmsg{} * used for IPv4 implementation). This is because this structure will be passed via an * IPv6 raw socket, on wich an application will only receiver the payload i.e the data after * the IPv6 header and all the extension headers. (See section 3 of RFC 3542) */ struct mrt6msg *p_mrmsg; int mif = 0; p_mrmsg = msg.msg_iov->iov_base; IMP_LOG_DEBUG("DUMP mrmsg:\n\tmif %d\n\tmsgtype %d\n\tsrc %s\n\tgroup %s\n", p_mrmsg->im6_mif, p_mrmsg->im6_msgtype, imp_inet6_ntoa(p_mrmsg->im6_src.s6_addr), imp_inet6_ntoa(p_mrmsg->im6_dst.s6_addr)); imp_build_piaddr(AF_INET6, &p_mrmsg->im6_dst, &pig); imp_build_piaddr(AF_INET6, &p_mrmsg->im6_src, &pia); mif = k_get_vmif(get_up_if_index(), AF_INET6); IMP_LOG_DEBUG("k_get_vmif = %d im6_mif %d\n", mif, p_mrmsg->im6_mif); if (mif == p_mrmsg->im6_mif) { if_set ttls; bzero(&ttls, sizeof(ttls)); /*get ttls*/ if (imp_get_mfcc_ttls(&ttls, MAXVIFS, &pia, &pig) != 0) { IMP_LOG_DEBUG("add MFC:src -- %s group -- %s\n\n", imp_pi_ntoa(&pia), imp_pi_ntoa(&pig)); imp_membership_db_mfc_add(&pig, &pia, &ttls); } } return; } /* An MLDv2 Report MUST be sent with a valid IPv6 link-local source * address, or the unspecified address (::), if the sending interface * has not acquired a valid link-local address yet. * [rfc 3810 5.2.13] */ if (!(IN6_IS_ADDR_LINKLOCAL(&sa.sin6_addr) || IN6_IS_ADDR_UNSPECIFIED(&sa.sin6_addr))) { IMP_LOG_ERROR("MLDv2 Report MUST be sent with a valid IPv6 link-local " "source address, or the unspecified address (::).\n"); return; } /*return if the interface don't enable igmp*/ for(p_if = imp_interface_first();p_if;p_if = LIST_NEXT(p_if, link)) { if(p_if->if_index == if_index && p_if->if_addr.ss.ss_family == AF_INET6) break; } if (p_if == NULL) { IMP_LOG_WARNING("Don't exist this VIF\n"); return; } p_mldh = msg.msg_iov->iov_base; switch (p_mldh->mld_type) { case MLD_LISTENER_REPORT: case MLD_LISTENER_REDUCTION: imp_input_report_mld(p_if, p_mldh); break; case MLD_V2_LISTENER_REPORT: if (version < IM_IGMPv3_MLDv2) { IMP_LOG_WARNING("current version is mldv%d\n", version - 1); return; } imp_input_report_mldv2(p_if, p_mldh, num); break; default: IMP_LOG_WARNING("unknown type %d\n", p_mldh->mld_type); break; } }
/* * Loop over a tdb chain, taking into consideration protocol tunneling. The * fourth argument is set if the first encapsulation header is already in * place. */ int ipsp_process_packet(struct mbuf *m, struct tdb *tdb, int af, int tunalready) { struct timeval tv; int i, off, error; struct mbuf *mp; #ifdef INET6 struct ip6_ext ip6e; int nxt; int dstopt = 0; #endif #ifdef INET int setdf = 0; struct ip *ip; #endif /* INET */ #ifdef INET6 struct ip6_hdr *ip6; #endif /* INET6 */ /* Check that the transform is allowed by the administrator. */ if ((tdb->tdb_sproto == IPPROTO_ESP && !esp_enable) || (tdb->tdb_sproto == IPPROTO_AH && !ah_enable) || (tdb->tdb_sproto == IPPROTO_IPCOMP && !ipcomp_enable)) { DPRINTF(("ipsp_process_packet(): IPsec outbound packet " "dropped due to policy (check your sysctls)\n")); m_freem(m); return EHOSTUNREACH; } /* Sanity check. */ if (!tdb->tdb_xform) { DPRINTF(("ipsp_process_packet(): uninitialized TDB\n")); m_freem(m); return EHOSTUNREACH; } /* Check if the SPI is invalid. */ if (tdb->tdb_flags & TDBF_INVALID) { DPRINTF(("ipsp_process_packet(): attempt to use invalid " "SA %s/%08x/%u\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), tdb->tdb_sproto)); m_freem(m); return ENXIO; } /* Check that the network protocol is supported */ switch (tdb->tdb_dst.sa.sa_family) { #ifdef INET case AF_INET: break; #endif /* INET */ #ifdef INET6 case AF_INET6: break; #endif /* INET6 */ default: DPRINTF(("ipsp_process_packet(): attempt to use " "SA %s/%08x/%u for protocol family %d\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), tdb->tdb_sproto, tdb->tdb_dst.sa.sa_family)); m_freem(m); return ENXIO; } /* * Register first use if applicable, setup relevant expiration timer. */ if (tdb->tdb_first_use == 0) { tdb->tdb_first_use = time_second; tv.tv_usec = 0; tv.tv_sec = tdb->tdb_first_use + tdb->tdb_exp_first_use; if (tdb->tdb_flags & TDBF_FIRSTUSE) timeout_add(&tdb->tdb_first_tmo, hzto(&tv)); tv.tv_sec = tdb->tdb_first_use + tdb->tdb_soft_first_use; if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE) timeout_add(&tdb->tdb_sfirst_tmo, hzto(&tv)); } /* * Check for tunneling if we don't have the first header in place. * When doing Ethernet-over-IP, we are handed an already-encapsulated * frame, so we don't need to re-encapsulate. */ if (tunalready == 0) { /* * If the target protocol family is different, we know we'll be * doing tunneling. */ if (af == tdb->tdb_dst.sa.sa_family) { #ifdef INET if (af == AF_INET) i = sizeof(struct ip); #endif /* INET */ #ifdef INET6 if (af == AF_INET6) i = sizeof(struct ip6_hdr); #endif /* INET6 */ /* Bring the network header in the first mbuf. */ if (m->m_len < i) { if ((m = m_pullup(m, i)) == NULL) return ENOBUFS; } #ifdef INET if (af == AF_INET) { ip = mtod(m, struct ip *); /* * This is not a bridge packet, remember if we * had IP_DF. */ setdf = ip->ip_off & htons(IP_DF); } #endif /* INET */ #ifdef INET6 if (af == AF_INET6) ip6 = mtod(m, struct ip6_hdr *); #endif /* INET6 */ } /* Do the appropriate encapsulation, if necessary. */ if ((tdb->tdb_dst.sa.sa_family != af) || /* PF mismatch */ (tdb->tdb_flags & TDBF_TUNNELING) || /* Tunneling needed */ (tdb->tdb_xform->xf_type == XF_IP4) || /* ditto */ #ifdef INET ((tdb->tdb_dst.sa.sa_family == AF_INET) && (tdb->tdb_dst.sin.sin_addr.s_addr != INADDR_ANY) && (tdb->tdb_dst.sin.sin_addr.s_addr != ip->ip_dst.s_addr)) || #endif /* INET */ #ifdef INET6 ((tdb->tdb_dst.sa.sa_family == AF_INET6) && (!IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_dst.sin6.sin6_addr)) && (!IN6_ARE_ADDR_EQUAL(&tdb->tdb_dst.sin6.sin6_addr, &ip6->ip6_dst))) || #endif /* INET6 */ 0) { #ifdef INET /* Fix IPv4 header checksum and length. */ if (af == AF_INET) { if (m->m_len < sizeof(struct ip)) if ((m = m_pullup(m, sizeof(struct ip))) == NULL) return ENOBUFS; ip = mtod(m, struct ip *); ip->ip_len = htons(m->m_pkthdr.len); ip->ip_sum = 0; ip->ip_sum = in_cksum(m, ip->ip_hl << 2); } #endif /* INET */ #ifdef INET6 /* Fix IPv6 header payload length. */ if (af == AF_INET6) { if (m->m_len < sizeof(struct ip6_hdr)) if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) return ENOBUFS; if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) { /* No jumbogram support. */ m_freem(m); return ENXIO; /*?*/ } ip6 = mtod(m, struct ip6_hdr *); ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6)); } #endif /* INET6 */ /* Encapsulate -- the last two arguments are unused. */ error = ipip_output(m, tdb, &mp, 0, 0); if ((mp == NULL) && (!error)) error = EFAULT; if (error) { if (mp) { m_freem(mp); mp = NULL; } return error; } m = mp; mp = NULL; #ifdef INET if (tdb->tdb_dst.sa.sa_family == AF_INET && setdf) { if (m->m_len < sizeof(struct ip)) if ((m = m_pullup(m, sizeof(struct ip))) == NULL) return ENOBUFS; ip = mtod(m, struct ip *); ip->ip_off |= htons(IP_DF); } #endif /* Remember that we appended a tunnel header. */ tdb->tdb_flags |= TDBF_USEDTUNNEL; } /* We may be done with this TDB */ if (tdb->tdb_xform->xf_type == XF_IP4) return ipsp_process_done(m, tdb); } else {
/* * Reads a linux sockaddr and does any necessary translation. * Linux sockaddrs don't have a length field, only a family. * Copy the osockaddr structure pointed to by osa to kernel, adjust * family and convert to sockaddr. */ static int linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int salen) { struct sockaddr *sa; struct osockaddr *kosa; #ifdef INET6 struct sockaddr_in6 *sin6; int oldv6size; #endif char *name; int bdom, error, hdrlen, namelen; if (salen < 2 || salen > UCHAR_MAX || !osa) return (EINVAL); #ifdef INET6 oldv6size = 0; /* * Check for old (pre-RFC2553) sockaddr_in6. We may accept it * if it's a v4-mapped address, so reserve the proper space * for it. */ if (salen == sizeof(struct sockaddr_in6) - sizeof(uint32_t)) { salen += sizeof(uint32_t); oldv6size = 1; } #endif kosa = malloc(salen, M_SONAME, M_WAITOK); if ((error = copyin(osa, kosa, salen))) goto out; bdom = linux_to_bsd_domain(kosa->sa_family); if (bdom == -1) { error = EAFNOSUPPORT; goto out; } #ifdef INET6 /* * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6, * which lacks the scope id compared with RFC2553 one. If we detect * the situation, reject the address and write a message to system log. * * Still accept addresses for which the scope id is not used. */ if (oldv6size) { if (bdom == AF_INET6) { sin6 = (struct sockaddr_in6 *)kosa; if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) || (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) && !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) { sin6->sin6_scope_id = 0; } else { log(LOG_DEBUG, "obsolete pre-RFC2553 sockaddr_in6 rejected\n"); error = EINVAL; goto out; } } else salen -= sizeof(uint32_t); } #endif if (bdom == AF_INET) { if (salen < sizeof(struct sockaddr_in)) { error = EINVAL; goto out; } salen = sizeof(struct sockaddr_in); } if (bdom == AF_LOCAL && salen > sizeof(struct sockaddr_un)) { hdrlen = offsetof(struct sockaddr_un, sun_path); name = ((struct sockaddr_un *)kosa)->sun_path; if (*name == '\0') { /* * Linux abstract namespace starts with a NULL byte. * XXX We do not support abstract namespace yet. */ namelen = strnlen(name + 1, salen - hdrlen - 1) + 1; } else namelen = strnlen(name, salen - hdrlen); salen = hdrlen + namelen; if (salen > sizeof(struct sockaddr_un)) { error = ENAMETOOLONG; goto out; } }
int ncprange_aton(struct ncprange *range, struct ncp *ncp, const char *data) { int bits, len; char *wp; const char *cp; char *s; len = strcspn(data, "/"); if (ncp && strncasecmp(data, "HISADDR", len) == 0) { range->ncprange_family = AF_INET; range->ncprange_ip4addr = ncp->ipcp.peer_ip; range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; range->ncprange_ip4width = 32; return 1; #ifndef NOINET6 } else if (ncp && strncasecmp(data, "HISADDR6", len) == 0) { range->ncprange_family = AF_INET6; range->ncprange_ip6addr = ncp->ipv6cp.hisaddr.ncpaddr_ip6addr; range->ncprange_ip6width = 128; return 1; #endif } else if (ncp && strncasecmp(data, "MYADDR", len) == 0) { range->ncprange_family = AF_INET; range->ncprange_ip4addr = ncp->ipcp.my_ip; range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; range->ncprange_ip4width = 32; return 1; #ifndef NOINET6 } else if (ncp && strncasecmp(data, "MYADDR6", len) == 0) { range->ncprange_family = AF_INET6; range->ncprange_ip6addr = ncp->ipv6cp.myaddr.ncpaddr_ip6addr; range->ncprange_ip6width = 128; return 1; #endif } else if (ncp && strncasecmp(data, "DNS0", len) == 0) { range->ncprange_family = AF_INET; range->ncprange_ip4addr = ncp->ipcp.ns.dns[0]; range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; range->ncprange_ip4width = 32; return 1; } else if (ncp && strncasecmp(data, "DNS1", len) == 0) { range->ncprange_family = AF_INET; range->ncprange_ip4addr = ncp->ipcp.ns.dns[1]; range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; range->ncprange_ip4width = 32; return 1; } s = (char *)alloca(len + 1); strncpy(s, data, len); s[len] = '\0'; bits = -1; if (data[len] != '\0') { bits = strtol(data + len + 1, &wp, 0); if (*wp || wp == data + len + 1 || bits < 0 || bits > 128) { log_Printf(LogWARN, "ncprange_aton: bad mask width.\n"); return 0; } } if ((cp = strchr(data, ':')) == NULL) { range->ncprange_family = AF_INET; range->ncprange_ip4addr = GetIpAddr(s); if (range->ncprange_ip4addr.s_addr == INADDR_NONE) { log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s); return 0; } if (range->ncprange_ip4addr.s_addr == INADDR_ANY) { range->ncprange_ip4mask.s_addr = INADDR_ANY; range->ncprange_ip4width = 0; } else if (bits == -1) { range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; range->ncprange_ip4width = 32; } else if (bits > 32) { log_Printf(LogWARN, "ncprange_aton: bad mask width.\n"); return 0; } else { range->ncprange_ip4mask = bits2mask4(bits); range->ncprange_ip4width = bits; } return 1; #ifndef NOINET6 } else if (strchr(cp + 1, ':') != NULL) { range->ncprange_family = AF_INET6; if (inet_pton(AF_INET6, s, &range->ncprange_ip6addr) != 1) { log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s); return 0; } if (IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr)) range->ncprange_ip6width = 0; else range->ncprange_ip6width = (bits == -1) ? 128 : bits; return 1; #endif } return 0; }
static void process_rs(struct Interface *iface, unsigned char *msg, int len, struct sockaddr_in6 *addr) { double delay; double next; struct timeval tv; uint8_t *opt_str; /* validation */ len -= sizeof(struct nd_router_solicit); opt_str = (uint8_t *)(msg + sizeof(struct nd_router_solicit)); while (len > 0) { int optlen; if (len < 2) { flog(LOG_WARNING, "trailing garbage in RS"); return; } optlen = (opt_str[1] << 3); if (optlen == 0) { flog(LOG_WARNING, "zero length option in RS"); return; } else if (optlen > len) { flog(LOG_WARNING, "option length greater than total length in RS"); return; } if (*opt_str == ND_OPT_SOURCE_LINKADDR && IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr)) { flog(LOG_WARNING, "received icmpv6 RS packet with unspecified source address and there is a lladdr option"); return; } len -= optlen; opt_str += optlen; } gettimeofday(&tv, NULL); delay = MAX_RA_DELAY_TIME * rand() / (RAND_MAX +1.0); if (iface->UnicastOnly) { send_ra_forall(iface, &addr->sin6_addr); } else if ( timevaldiff(&tv, &iface->last_multicast) / 1000.0 < iface->MinDelayBetweenRAs ) { /* last RA was sent only a few moments ago, don't send another immediately. */ next = iface->MinDelayBetweenRAs - (tv.tv_sec + tv.tv_usec / 1000000.0) + (iface->last_multicast.tv_sec + iface->last_multicast.tv_usec / 1000000.0) + delay/1000.0; iface->next_multicast = next_timeval(next); } else { /* no RA sent in a while, send a multicast reply */ send_ra_forall(iface, NULL); next = rand_between(iface->MinRtrAdvInterval, iface->MaxRtrAdvInterval); iface->next_multicast = next_timeval(next); } }
int udp6_input(struct mbuf **mp, int *offp, int proto) { struct mbuf *m = *mp; struct ip6_hdr *ip6; struct udphdr *uh; struct inpcb *in6p; struct mbuf *opts = NULL; int off = *offp; int plen, ulen; struct sockaddr_in6 udp_in6; struct socket *so; struct inpcbinfo *pcbinfo = &udbinfo[0]; IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); ip6 = mtod(m, struct ip6_hdr *); udp_stat.udps_ipackets++; plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6); uh = (struct udphdr *)((caddr_t)ip6 + off); ulen = ntohs((u_short)uh->uh_ulen); if (plen != ulen) { udp_stat.udps_badlen++; goto bad; } /* * Checksum extended UDP header and data. */ if (uh->uh_sum == 0) udp_stat.udps_nosum++; else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) { udp_stat.udps_badsum++; goto bad; } if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { struct inpcb *last, *marker; /* * Deliver a multicast datagram to all sockets * for which the local and remote addresses and ports match * those of the incoming datagram. This allows more than * one process to receive multicasts on the same port. * (This really ought to be done for unicast datagrams as * well, but that would cause problems with existing * applications that open both address-specific sockets and * a wildcard socket listening to the same port -- they would * end up receiving duplicates of every unicast datagram. * Those applications open the multiple sockets to overcome an * inadequacy of the UDP socket interface, but for backwards * compatibility we avoid the problem here rather than * fixing the interface. Maybe 4.5BSD will remedy this?) */ /* * In a case that laddr should be set to the link-local * address (this happens in RIPng), the multicast address * specified in the received packet does not match with * laddr. To cure this situation, the matching is relaxed * if the receiving interface is the same as one specified * in the socket and if the destination multicast address * matches one of the multicast groups specified in the socket. */ /* * Construct sockaddr format source address. */ init_sin6(&udp_in6, m); /* general init */ udp_in6.sin6_port = uh->uh_sport; /* * KAME note: traditionally we dropped udpiphdr from mbuf here. */ /* * Locate pcb(s) for datagram. * (Algorithm copied from raw_intr().) */ last = NULL; marker = in_pcbmarker(); GET_PCBINFO_TOKEN(pcbinfo); LIST_INSERT_HEAD(&pcbinfo->pcblisthead, marker, inp_list); while ((in6p = LIST_NEXT(marker, inp_list)) != NULL) { LIST_REMOVE(marker, inp_list); LIST_INSERT_AFTER(in6p, marker, inp_list); if (in6p->inp_flags & INP_PLACEMARKER) continue; if (!INP_ISIPV6(in6p)) continue; if (in6p->in6p_lport != uh->uh_dport) continue; if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) { if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst) && !in6_mcmatch(in6p, &ip6->ip6_dst, m->m_pkthdr.rcvif)) continue; } if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src) || in6p->in6p_fport != uh->uh_sport) continue; } if (last != NULL) { struct mbuf *n; if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { /* * KAME NOTE: do not * m_copy(m, offset, ...) above. * ssb_appendaddr() expects M_PKTHDR, * and m_copy() will copy M_PKTHDR * only if offset is 0. */ so = last->in6p_socket; if ((last->in6p_flags & IN6P_CONTROLOPTS) || (so->so_options & SO_TIMESTAMP)) { ip6_savecontrol(last, &opts, ip6, n); } m_adj(n, off + sizeof(struct udphdr)); lwkt_gettoken(&so->so_rcv.ssb_token); if (ssb_appendaddr(&so->so_rcv, (struct sockaddr *)&udp_in6, n, opts) == 0) { m_freem(n); if (opts) m_freem(opts); udp_stat.udps_fullsock++; } else { sorwakeup(so); } lwkt_reltoken(&so->so_rcv.ssb_token); opts = NULL; } } last = in6p; /* * Don't look for additional matches if this one does * not have either the SO_REUSEPORT or SO_REUSEADDR * socket options set. This heuristic avoids searching * through all pcbs in the common case of a non-shared * port. It assumes that an application will never * clear these options after setting them. */ if ((last->in6p_socket->so_options & (SO_REUSEPORT | SO_REUSEADDR)) == 0) break; } LIST_REMOVE(marker, inp_list); REL_PCBINFO_TOKEN(pcbinfo); if (last == NULL) { /* * No matching pcb found; discard datagram. * (No need to send an ICMP Port Unreachable * for a broadcast or multicast datgram.) */ udp_stat.udps_noport++; udp_stat.udps_noportmcast++; goto bad; } if (last->in6p_flags & IN6P_CONTROLOPTS || last->in6p_socket->so_options & SO_TIMESTAMP) ip6_savecontrol(last, &opts, ip6, m); m_adj(m, off + sizeof(struct udphdr)); so = last->in6p_socket; lwkt_gettoken(&so->so_rcv.ssb_token); if (ssb_appendaddr(&so->so_rcv, (struct sockaddr *)&udp_in6, m, opts) == 0) { udp_stat.udps_fullsock++; lwkt_reltoken(&so->so_rcv.ssb_token); goto bad; } sorwakeup(so); lwkt_reltoken(&so->so_rcv.ssb_token); return IPPROTO_DONE; } /* * Locate pcb for datagram. */ in6p = in6_pcblookup_hash(pcbinfo, &ip6->ip6_src, uh->uh_sport, &ip6->ip6_dst, uh->uh_dport, 1, m->m_pkthdr.rcvif); if (in6p == NULL) { if (log_in_vain) { char buf[INET6_ADDRSTRLEN]; strcpy(buf, ip6_sprintf(&ip6->ip6_dst)); log(LOG_INFO, "Connection attempt to UDP [%s]:%d from [%s]:%d\n", buf, ntohs(uh->uh_dport), ip6_sprintf(&ip6->ip6_src), ntohs(uh->uh_sport)); } udp_stat.udps_noport++; if (m->m_flags & M_MCAST) { kprintf("UDP6: M_MCAST is set in a unicast packet.\n"); udp_stat.udps_noportmcast++; goto bad; } icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0); return IPPROTO_DONE; } /* * Construct sockaddr format source address. * Stuff source address and datagram in user buffer. */ init_sin6(&udp_in6, m); /* general init */ udp_in6.sin6_port = uh->uh_sport; if (in6p->in6p_flags & IN6P_CONTROLOPTS || in6p->in6p_socket->so_options & SO_TIMESTAMP) ip6_savecontrol(in6p, &opts, ip6, m); m_adj(m, off + sizeof(struct udphdr)); so = in6p->in6p_socket; lwkt_gettoken(&so->so_rcv.ssb_token); if (ssb_appendaddr(&so->so_rcv, (struct sockaddr *)&udp_in6, m, opts) == 0) { udp_stat.udps_fullsock++; lwkt_reltoken(&so->so_rcv.ssb_token); goto bad; } sorwakeup(so); lwkt_reltoken(&so->so_rcv.ssb_token); return IPPROTO_DONE; bad: if (m) m_freem(m); if (opts) m_freem(opts); return IPPROTO_DONE; }
static const char *udp_host_addr6(socket_udp *s) { #ifdef HAVE_IPv6 static char hname[MAXHOSTNAMELEN]; int gai_err, newsock; struct addrinfo hints, *ai; struct sockaddr_in6 local, addr6; int len = sizeof(local), result = 0; newsock=socket(AF_INET6, SOCK_DGRAM,0); memset ((char *)&addr6, 0, len); addr6.sin6_family = AF_INET6; #ifdef HAVE_SIN6_LEN addr6.sin6_len = len; #endif bind (newsock, (struct sockaddr *) &addr6, len); addr6.sin6_addr = s->addr6; addr6.sin6_port = htons (s->rx_port); connect (newsock, (struct sockaddr *) &addr6, len); memset ((char *)&local, 0, len); if ((result = getsockname(newsock,(struct sockaddr *)&local, &len)) < 0){ local.sin6_addr = in6addr_any; local.sin6_port = 0; debug_msg("getsockname failed\n"); } close (newsock); if (IN6_IS_ADDR_UNSPECIFIED(&local.sin6_addr) || IN6_IS_ADDR_MULTICAST(&local.sin6_addr)) { if (gethostname(hname, MAXHOSTNAMELEN) != 0) { debug_msg("gethostname failed\n"); abort(); } hints.ai_protocol = 0; hints.ai_flags = 0; hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_DGRAM; hints.ai_addrlen = 0; hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; if ((gai_err = getaddrinfo(hname, NULL, &hints, &ai))) { debug_msg("getaddrinfo: %s: %s\n", hname, gai_strerror(gai_err)); abort(); } if (inet_ntopxp(AF_INET6, &(((struct sockaddr_in6 *)(ai->ai_addr))->sin6_addr), hname, MAXHOSTNAMELEN) == NULL) { debug_msg("inet_ntop: %s: \n", hname); abort(); } freeaddrinfo(ai); return (const char*)hname; } if (inet_ntopxp(AF_INET6, &local.sin6_addr, hname, MAXHOSTNAMELEN) == NULL) { debug_msg("inet_ntop: %s: \n", hname); abort(); } return (const char*)hname; #else /* HAVE_IPv6 */ UNUSED(s); return "::"; /* The unspecified address... */ #endif /* HAVE_IPv6 */ }
void us_mfa::handle_ipv6(int dev, uint8_t *buf, uint16_t len) { ip6_hdr *hdr = (ip6_hdr *)buf; if (len < sizeof(ip6_hdr)) return; if (hdr->ip6_hlim <= 1) return; if (!IN6_IS_ADDR_MULTICAST(&hdr->ip6_dst)) return; if (IN6_IS_ADDR_MULTICAST(&hdr->ip6_src) || IN6_IS_ADDR_UNSPECIFIED(&hdr->ip6_src) || IN6_IS_ADDR_LINKLOCAL(&hdr->ip6_src)) return; /* * Silently drop packets with scope reserved, interface-local or link-local. * RFC 4291, Section 2.7. * Nodes must not originate a packet to a multicast address whose scope * field contains the reserved value 0; if such a packet is received, it * must be silently dropped. */ if ((hdr->ip6_dst.s6_addr[1] & 0xc) == 0) return; /* Do we have a Hop by Hop header? */ if (hdr->ip6_nxt == 0) { int spaceLeft = (((const ip6_ext *)(hdr + 1))->ip6e_len + 1) * 8; if (len < (sizeof(ip6_hdr) + spaceLeft)) return; const uint8_t *ptr = buf + sizeof(ip6_hdr) + 2; while (spaceLeft > 0) { if (ptr[0] == 0) { /* Pad1 */ spaceLeft--; } else { spaceLeft -= ptr[1] + 2; if (spaceLeft < 0) { /* Badly encoded HbH, discard packet */ return; } if (ptr[0] != 1) { /* not PadN, check top-order 2 bits */ switch (ptr[0] >> 6) { case 0: // skip option break; case 1: // discard packet return; case 2: case 3: // We handle 2 same as 3 as all of our destinations are // multicast // XXX send icmp parameter problem, code 2 to the source return; } } } } }
/* * Open a socket on the given IP and port. */ int fr_socket(fr_ipaddr_t *ipaddr, int port) { int sockfd; struct sockaddr_storage salocal; socklen_t salen; if ((port < 0) || (port > 65535)) { fr_strerror_printf("Port %d is out of allowed bounds", port); return -1; } sockfd = socket(ipaddr->af, SOCK_DGRAM, 0); if (sockfd < 0) { fr_strerror_printf("cannot open socket: %s", strerror(errno)); return sockfd; } #ifdef WITH_UDPFROMTO /* * Initialize udpfromto for all sockets. */ if (udpfromto_init(sockfd) != 0) { close(sockfd); fr_strerror_printf("cannot initialize udpfromto: %s", strerror(errno)); return -1; } #endif if (!fr_ipaddr2sockaddr(ipaddr, port, &salocal, &salen)) { return sockfd; } #ifdef HAVE_STRUCT_SOCKADDR_IN6 if (ipaddr->af == AF_INET6) { /* * Listening on '::' does NOT get you IPv4 to * IPv6 mapping. You've got to listen on an IPv4 * address, too. This makes the rest of the server * design a little simpler. */ #ifdef IPV6_V6ONLY if (IN6_IS_ADDR_UNSPECIFIED(&ipaddr->ipaddr.ip6addr)) { int on = 1; setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)); } #endif /* IPV6_V6ONLY */ } #endif /* HAVE_STRUCT_SOCKADDR_IN6 */ if (ipaddr->af == AF_INET) { UNUSED int flag; #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) /* * Disable PMTU discovery. On Linux, this * also makes sure that the "don't fragment" * flag is zero. */ flag = IP_PMTUDISC_DONT; setsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &flag, sizeof(flag)); #endif #if defined(IP_DONTFRAG) /* * Ensure that the "don't fragment" flag is zero. */ flag = 0; setsockopt(sockfd, IPPROTO_IP, IP_DONTFRAG, &flag, sizeof(flag)); #endif } if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) { close(sockfd); fr_strerror_printf("cannot bind socket: %s", strerror(errno)); return -1; } return sockfd; }
status_t ipv6_setsockopt(net_protocol* _protocol, int level, int option, const void* value, int length) { ipv6_protocol* protocol = (ipv6_protocol*)_protocol; if (level == IPPROTO_IPV6) { // TODO: support more of these options if (option == IPV6_MULTICAST_IF) { if (length != sizeof(struct in6_addr)) return B_BAD_VALUE; struct sockaddr_in6* address = new (std::nothrow) sockaddr_in6; if (address == NULL) return B_NO_MEMORY; if (user_memcpy(&address->sin6_addr, value, sizeof(in6_addr)) != B_OK) { delete address; return B_BAD_ADDRESS; } // Using the unspecifed address to remove the previous setting. if (IN6_IS_ADDR_UNSPECIFIED(&address->sin6_addr)) { delete address; delete protocol->multicast_address; protocol->multicast_address = NULL; return B_OK; } struct net_interface* interface = sDatalinkModule->get_interface_with_address( (sockaddr*)address); if (interface == NULL) { delete address; return EADDRNOTAVAIL; } delete protocol->multicast_address; protocol->multicast_address = (struct sockaddr*)address; return B_OK; } if (option == IPV6_MULTICAST_HOPS) { return set_int_option(protocol->multicast_time_to_live, value, length); } if (option == IPV6_MULTICAST_LOOP) return EOPNOTSUPP; if (option == IPV6_UNICAST_HOPS) return set_int_option(protocol->time_to_live, value, length); if (option == IPV6_V6ONLY) return EOPNOTSUPP; if (option == IPV6_RECVPKTINFO) return set_int_option(protocol->receive_pktinfo, value, length); if (option == IPV6_RECVHOPLIMIT) return set_int_option(protocol->receive_hoplimit, value, length); if (option == IPV6_JOIN_GROUP || option == IPV6_LEAVE_GROUP) { ipv6_mreq mreq; if (length != sizeof(ipv6_mreq)) return B_BAD_VALUE; if (user_memcpy(&mreq, value, sizeof(ipv6_mreq)) != B_OK) return B_BAD_ADDRESS; return ipv6_delta_membership(protocol, option, mreq.ipv6mr_interface, &mreq.ipv6mr_multiaddr, NULL); } dprintf("IPv6::setsockopt(): set unknown option: %d\n", option); return ENOPROTOOPT; } return sSocketModule->set_option(protocol->socket, level, option, value, length); }
/* * Input an Neighbor Solicitation Message. * * Based on RFC 2461 * Based on RFC 2462 (duplicated address detection) */ void nd6_ns_input(struct mbuf *m, int off, int icmp6len) { struct ifnet *ifp = m->m_pkthdr.rcvif; struct ifnet *cmpifp; struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); struct nd_neighbor_solicit *nd_ns; struct in6_addr saddr6 = ip6->ip6_src; struct in6_addr daddr6 = ip6->ip6_dst; struct in6_addr taddr6; struct in6_addr myaddr6; char *lladdr = NULL; struct ifaddr *ifa = NULL; int lladdrlen = 0; int anycast = 0, proxy = 0, tentative = 0; int tlladdr; union nd_opts ndopts; struct sockaddr_dl *proxydl = NULL; /* * Collapse interfaces to the bridge for comparison and * mac (llinfo) purposes. */ cmpifp = ifp; if (ifp->if_bridge) cmpifp = ifp->if_bridge; #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, icmp6len,); nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off); #else IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len); if (nd_ns == NULL) { icmp6stat.icp6s_tooshort++; return; } #endif ip6 = mtod(m, struct ip6_hdr *); /* adjust pointer for safety */ taddr6 = nd_ns->nd_ns_target; if (ip6->ip6_hlim != 255) { nd6log((LOG_ERR, "nd6_ns_input: invalid hlim (%d) from %s to %s on %s\n", ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst), if_name(ifp))); goto bad; } if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { /* dst has to be solicited node multicast address. */ if (daddr6.s6_addr16[0] == IPV6_ADDR_INT16_MLL && /* don't check ifindex portion */ daddr6.s6_addr32[1] == 0 && daddr6.s6_addr32[2] == IPV6_ADDR_INT32_ONE && daddr6.s6_addr8[12] == 0xff) { ; /* good */ } else { nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet " "(wrong ip6 dst)\n")); goto bad; } } else if (!nd6_onlink_ns_rfc4861) { /* * Make sure the source address is from a neighbor's address. * * XXX probably only need to check cmpifp. */ if (in6ifa_ifplocaladdr(cmpifp, &saddr6) == NULL && in6ifa_ifplocaladdr(ifp, &saddr6) == NULL) { nd6log((LOG_INFO, "nd6_ns_input: " "NS packet from non-neighbor\n")); goto bad; } } if (IN6_IS_ADDR_MULTICAST(&taddr6)) { nd6log((LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n")); goto bad; } if (IN6_IS_SCOPE_LINKLOCAL(&taddr6)) taddr6.s6_addr16[1] = htons(ifp->if_index); icmp6len -= sizeof(*nd_ns); nd6_option_init(nd_ns + 1, icmp6len, &ndopts); if (nd6_options(&ndopts) < 0) { nd6log((LOG_INFO, "nd6_ns_input: invalid ND option, ignored\n")); /* nd6_options have incremented stats */ goto freeit; } if (ndopts.nd_opts_src_lladdr) { lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; } if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) && lladdr) { nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet " "(link-layer address option)\n")); goto bad; } /* * Attaching target link-layer address to the NA? * (RFC 2461 7.2.4) * * NS IP dst is unicast/anycast MUST NOT add * NS IP dst is solicited-node multicast MUST add * * In implementation, we add target link-layer address by default. * We do not add one in MUST NOT cases. */ #if 0 /* too much! */ ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &daddr6); if (ifa && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)) tlladdr = 0; else #endif if (!IN6_IS_ADDR_MULTICAST(&daddr6)) tlladdr = 0; else tlladdr = 1; /* * Target address (taddr6) must be either: * (1) Valid unicast/anycast address for my receiving interface. * (2) Unicast or anycast address for which I'm offering proxy * service. * (3) "tentative" address on which DAD is being performed. */ /* (1) and (3) check. */ #ifdef CARP if (ifp->if_carp) ifa = carp_iamatch6(ifp->if_carp, &taddr6); if (!ifa) ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6); #else ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6); #endif /* * (2) Check proxying. Requires ip6_forwarding to be turned on. * * If the packet is anycast the target route must be on a * different interface because the anycast will get anything * on the current interface. * * If the packet is unicast the target route may be on the * same interface. If the gateway is a (typically manually * configured) link address we can directly offer it. * XXX for now we don't do this but instead offer ours and * presumably relay. * * WARNING! Since this is a subnet proxy the interface proxying * the ND6 must be in promiscuous mode or it will not see the * solicited multicast requests for various hosts being proxied. * * WARNING! Since this is a subnet proxy we have to treat bridge * interfaces as being the bridge itself so we do not proxy-nd6 * between bridge interfaces (which are effectively switched). * * (In the specific-host-proxy case via RTF_ANNOUNCE, which is * a bitch to configure, a specific multicast route is already * added for that host <-- NOT RECOMMENDED). */ if (!ifa && ip6_forwarding) { struct rtentry *rt; struct sockaddr_in6 tsin6; struct ifnet *rtifp; bzero(&tsin6, sizeof tsin6); tsin6.sin6_len = sizeof(struct sockaddr_in6); tsin6.sin6_family = AF_INET6; tsin6.sin6_addr = taddr6; rt = rtpurelookup((struct sockaddr *)&tsin6); rtifp = rt ? rt->rt_ifp : NULL; if (rtifp && rtifp->if_bridge) rtifp = rtifp->if_bridge; if (rt != NULL && (cmpifp != rtifp || (cmpifp == rtifp && (m->m_flags & M_MCAST) == 0)) ) { ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(cmpifp, IN6_IFF_NOTREADY|IN6_IFF_ANYCAST); nd6log((LOG_INFO, "nd6_ns_input: nd6 proxy %s(%s)<-%s ifa %p\n", if_name(cmpifp), if_name(ifp), if_name(rtifp), ifa)); if (ifa) { proxy = 1; /* * Manual link address on same interface * w/announce flag will proxy-arp using * target mac, else our mac is used. */ if (cmpifp == rtifp && (rt->rt_flags & RTF_ANNOUNCE) && rt->rt_gateway->sa_family == AF_LINK) { proxydl = SDL(rt->rt_gateway); } } } if (rt != NULL) --rt->rt_refcnt; } if (ifa == NULL) { /* * We've got an NS packet, and we don't have that adddress * assigned for us. We MUST silently ignore it. * See RFC2461 7.2.3. */ goto freeit; } myaddr6 = *IFA_IN6(ifa); anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST; tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE; if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED) goto freeit; if (lladdr && ((cmpifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { nd6log((LOG_INFO, "nd6_ns_input: lladdrlen mismatch for %s " "(if %d, NS packet %d)\n", ip6_sprintf(&taddr6), cmpifp->if_addrlen, lladdrlen - 2)); goto bad; } if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) { nd6log((LOG_INFO, "nd6_ns_input: duplicate IP6 address %s\n", ip6_sprintf(&saddr6))); goto freeit; } /* * We have neighbor solicitation packet, with target address equals to * one of my tentative address. * * src addr how to process? * --- --- * multicast of course, invalid (rejected in ip6_input) * unicast somebody is doing address resolution -> ignore * unspec dup address detection * * The processing is defined in RFC 2462. */ if (tentative) { /* * If source address is unspecified address, it is for * duplicated address detection. * * If not, the packet is for addess resolution; * silently ignore it. */ if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) nd6_dad_ns_input(ifa); goto freeit; } /* * If the source address is unspecified address, entries must not * be created or updated. * It looks that sender is performing DAD. Output NA toward * all-node multicast address, to tell the sender that I'm using * the address. * S bit ("solicited") must be zero. */ if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { saddr6 = kin6addr_linklocal_allnodes; saddr6.s6_addr16[1] = htons(cmpifp->if_index); nd6_na_output(cmpifp, &saddr6, &taddr6, ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) | (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0), tlladdr, (struct sockaddr *)proxydl); goto freeit; } nd6_cache_lladdr(cmpifp, &saddr6, lladdr, lladdrlen, ND_NEIGHBOR_SOLICIT, 0); nd6_na_output(ifp, &saddr6, &taddr6, ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) | (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED, tlladdr, (struct sockaddr *)proxydl); freeit: m_freem(m); return; bad: nd6log((LOG_ERR, "nd6_ns_input: src=%s\n", ip6_sprintf(&saddr6))); nd6log((LOG_ERR, "nd6_ns_input: dst=%s\n", ip6_sprintf(&daddr6))); nd6log((LOG_ERR, "nd6_ns_input: tgt=%s\n", ip6_sprintf(&taddr6))); icmp6stat.icp6s_badns++; m_freem(m); }
status_t ipv6_send_routed_data(net_protocol* _protocol, struct net_route* route, net_buffer* buffer) { if (route == NULL) return B_BAD_VALUE; ipv6_protocol* protocol = (ipv6_protocol*)_protocol; net_interface* interface = route->interface_address->interface; uint8 protocolNumber; if (protocol != NULL && protocol->socket != NULL) protocolNumber = protocol->socket->protocol; else protocolNumber = buffer->protocol; TRACE_SK(protocol, "SendRoutedData(%p, %p [%ld bytes])", route, buffer, buffer->size); sockaddr_in6& source = *(sockaddr_in6*)buffer->source; sockaddr_in6& destination = *(sockaddr_in6*)buffer->destination; buffer->flags &= ~(MSG_BCAST | MSG_MCAST); if (IN6_IS_ADDR_UNSPECIFIED(&destination.sin6_addr)) return EDESTADDRREQ; if (IN6_IS_ADDR_MULTICAST(&destination.sin6_addr)) buffer->flags |= MSG_MCAST; uint16 dataLength = buffer->size; // Add IPv6 header NetBufferPrepend<ip6_hdr> header(buffer); if (header.Status() != B_OK) return header.Status(); if (buffer->size > 0xffff) return EMSGSIZE; uint32 flowinfo = 0; // TODO: fill in the flow id from somewhere if (protocol) { // fill in traffic class flowinfo |= htonl(protocol->service_type << 20); } // set lower 28 bits header->ip6_flow = htonl(flowinfo) & IPV6_FLOWINFO_MASK; // set upper 4 bits header->ip6_vfc |= IPV6_VERSION; header->ip6_plen = htons(dataLength); header->ip6_nxt = protocolNumber; header->ip6_hlim = ip6_select_hoplimit(protocol, buffer); memcpy(&header->ip6_src, &source.sin6_addr, sizeof(in6_addr)); memcpy(&header->ip6_dst, &destination.sin6_addr, sizeof(in6_addr)); header.Sync(); // write the checksum for ICMPv6 sockets if (protocolNumber == IPPROTO_ICMPV6 && dataLength >= sizeof(struct icmp6_hdr)) { NetBufferField<uint16, sizeof(ip6_hdr) + offsetof(icmp6_hdr, icmp6_cksum)> icmpChecksum(buffer); // first make sure the existing checksum is zero *icmpChecksum = 0; icmpChecksum.Sync(); uint16 checksum = gBufferModule->checksum(buffer, sizeof(ip6_hdr), buffer->size - sizeof(ip6_hdr), false); checksum = ipv6_checksum(&header->ip6_src, &header->ip6_dst, dataLength, protocolNumber, checksum); *icmpChecksum = checksum; } char addrbuf[INET6_ADDRSTRLEN]; TRACE_SK(protocol, " SendRoutedData(): destination: %s", ip6_sprintf(&destination.sin6_addr, addrbuf)); uint32 mtu = route->mtu ? route->mtu : interface->mtu; if (buffer->size > mtu) { // we need to fragment the packet return send_fragments(protocol, route, buffer, mtu); } return sDatalinkModule->send_routed_data(route, buffer); }
os_result os_sockQueryIPv6Interfaces( os_ifAttributes *ifList, os_uint32 listSize, os_uint32 *validElements) { os_result result = os_resultSuccess; os_result addressInfoResult =0; unsigned long returnedBytes; unsigned int listIndex; os_socket ifcs; int retVal, done; char* errorMessage; os_sockErrno errNo; PIP_ADAPTER_ADDRESSES pAddresses = NULL; PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL; unsigned long outBufLen = 0; /* Set the flags to pass to GetAdaptersAddresses*/ unsigned long flags = GAA_FLAG_INCLUDE_PREFIX; int i = 0; /* IPv6 addition */ SOCKET_ADDRESS_LIST* ipv6InterfaceList; *validElements = 0; listIndex = 0; outBufLen = sizeof (IP_ADAPTER_ADDRESSES); pAddresses = (IP_ADAPTER_ADDRESSES *) os_malloc(outBufLen); if (GetAdaptersAddresses(AF_INET6, flags, NULL, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW) { os_free(pAddresses); pAddresses = (IP_ADAPTER_ADDRESSES *) os_malloc(outBufLen); } addressInfoResult = GetAdaptersAddresses(AF_INET6, flags, NULL, pAddresses, &outBufLen); /* Now do the IPv6 interfaces */ ifcs = os_sockNew (AF_INET6, SOCK_DGRAM); if (ifcs != INVALID_SOCKET) { /* List returned from this control code query will need to be sized as 1 * SOCKET_ADDRESS_LIST + n * SOCKET_ADDRESS */ ipv6InterfaceList = os_malloc(sizeof(SOCKET_ADDRESS_LIST) + ((MAX_INTERFACES - 1) * sizeof(SOCKET_ADDRESS))); memset(ipv6InterfaceList, 0, sizeof(SOCKET_ADDRESS_LIST) + ((MAX_INTERFACES - 1) * sizeof(SOCKET_ADDRESS))); retVal = WSAIoctl(ifcs, SIO_ADDRESS_LIST_QUERY, NULL, 0, ipv6InterfaceList, sizeof(SOCKET_ADDRESS_LIST) + ((MAX_INTERFACES - 1) * sizeof(SOCKET_ADDRESS)), &returnedBytes, 0, 0); if (retVal == SOCKET_ERROR && WSAGetLastError() == WSAEFAULT) { /* The buffer wasn't big enough. returnedBytes will now contain the required size so we can reallocate & try again */ os_free(ipv6InterfaceList); ipv6InterfaceList = os_malloc(returnedBytes); memset(ipv6InterfaceList, 0, returnedBytes); retVal = WSAIoctl(ifcs, SIO_ADDRESS_LIST_QUERY, NULL, 0, ipv6InterfaceList, returnedBytes, &returnedBytes, 0, 0); } if (retVal == SOCKET_ERROR) { errNo = os_sockError(); errorMessage = os_sockErrnoToString(errNo); os_report(OS_ERROR, "os_sockQueryInterfaces", __FILE__, __LINE__, 0, "Socket error calling WSAIoctl for IPv6 interfaces: %d %s", errNo, errorMessage); os_free(errorMessage); /* @todo Is it right to return a fail here ? Need to check on box w/ no IPv6 interfaces */ result = os_resultFail; } else { for (i = 0; i < ipv6InterfaceList->iAddressCount; ++i) { if (ipv6InterfaceList->Address[i].lpSockaddr->sa_family == AF_INET6 && ! (IN6_IS_ADDR_UNSPECIFIED(&((os_sockaddr_in6 *)&ipv6InterfaceList->Address[i].lpSockaddr)->sin6_addr))) { done = 0; if (addressInfoResult == NO_ERROR) { pCurrAddresses = pAddresses; while (pCurrAddresses && !done) { /* adapter needs to be enabled*/ if (pCurrAddresses->OperStatus == IfOperStatusUp) { pUnicast = pCurrAddresses->FirstUnicastAddress; while (pUnicast && !done) { /* check if interface ip matches adapter ip */ if (os_sockaddrIPAddressEqual((os_sockaddr*) ipv6InterfaceList->Address[i].lpSockaddr, (os_sockaddr*) pUnicast->Address.lpSockaddr)) { snprintf(ifList[listIndex].name, OS_IFNAMESIZE, "%wS", pCurrAddresses->FriendlyName); ifList[listIndex].interfaceIndexNo = (os_uint) pCurrAddresses->Ipv6IfIndex; done = 1; } pUnicast = pUnicast->Next; } } pCurrAddresses = pCurrAddresses->Next; } } /* if no name was found set this interface name to string representation of the IPv6 address */ if (!done) { os_sockaddrAddressToString((os_sockaddr*) ipv6InterfaceList->Address[i].lpSockaddr, ifList[listIndex].name, OS_IFNAMESIZE); os_report(OS_WARNING, "os_sockQueryInterfaces", __FILE__, __LINE__, 0, "Unable to determine IPv6 adapter name. Setting instead to adapter address %s", ifList[listIndex].name); } ifList[listIndex].flags = 0; ifList[listIndex].address = *((os_sockaddr_storage*) ipv6InterfaceList->Address[i].lpSockaddr); listIndex++; ++(*validElements); } } } os_sockFree (ifcs); } if (addressInfoResult == NO_ERROR) { os_free(pAddresses); } return result; }
void ripng_print(netdissect_options *ndo, const u_char *dat, unsigned int length) { register const struct rip6 *rp = (const struct rip6 *)dat; register const struct netinfo6 *ni; unsigned int length_left; u_int j; ND_TCHECK(rp->rip6_cmd); switch (rp->rip6_cmd) { case RIP6_REQUEST: length_left = length; if (length_left < (sizeof(struct rip6) - sizeof(struct netinfo6))) goto trunc; length_left -= (sizeof(struct rip6) - sizeof(struct netinfo6)); j = length_left / sizeof(*ni); if (j == 1) { ND_TCHECK(rp->rip6_nets); if (rp->rip6_nets->rip6_metric == HOPCNT_INFINITY6 && IN6_IS_ADDR_UNSPECIFIED(&rp->rip6_nets->rip6_dest)) { ND_PRINT((ndo, " ripng-req dump")); break; } } if (j * sizeof(*ni) != length_left) ND_PRINT((ndo, " ripng-req %u[%u]:", j, length)); else ND_PRINT((ndo, " ripng-req %u:", j)); for (ni = rp->rip6_nets; length_left >= sizeof(*ni); length_left -= sizeof(*ni), ++ni) { ND_TCHECK(*ni); if (ndo->ndo_vflag > 1) ND_PRINT((ndo, "\n\t")); else ND_PRINT((ndo, " ")); rip6_entry_print(ndo, ni, 0); } if (length_left != 0) goto trunc; break; case RIP6_RESPONSE: length_left = length; if (length_left < (sizeof(struct rip6) - sizeof(struct netinfo6))) goto trunc; length_left -= (sizeof(struct rip6) - sizeof(struct netinfo6)); j = length_left / sizeof(*ni); if (j * sizeof(*ni) != length_left) ND_PRINT((ndo, " ripng-resp %d[%u]:", j, length)); else ND_PRINT((ndo, " ripng-resp %d:", j)); for (ni = rp->rip6_nets; length_left >= sizeof(*ni); length_left -= sizeof(*ni), ++ni) { ND_TCHECK(*ni); if (ndo->ndo_vflag > 1) ND_PRINT((ndo, "\n\t")); else ND_PRINT((ndo, " ")); rip6_entry_print(ndo, ni, ni->rip6_metric); } if (length_left != 0) goto trunc; break; default: ND_PRINT((ndo, " ripng-%d ?? %u", rp->rip6_cmd, length)); break; } ND_TCHECK(rp->rip6_vers); if (rp->rip6_vers != RIP6_VERSION) ND_PRINT((ndo, " [vers %d]", rp->rip6_vers)); return; trunc: ND_PRINT((ndo, "[|ripng]")); return; }