const char * inet6_n2a(struct in6_addr *p) { static char buf[NI_MAXHOST]; struct sockaddr_in6 sin6; u_int32_t scopeid; #ifdef NI_WITHSCOPEID const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID; #else const int niflags = NI_NUMERICHOST; #endif memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_len = sizeof(struct sockaddr_in6); sin6.sin6_addr = *p; if (IN6_IS_ADDR_LINKLOCAL(p) || IN6_IS_ADDR_MC_LINKLOCAL(p)) { scopeid = ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); if (scopeid) { sin6.sin6_scope_id = scopeid; sin6.sin6_addr.s6_addr[2] = 0; sin6.sin6_addr.s6_addr[3] = 0; } } if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, buf, sizeof(buf), NULL, 0, niflags) == 0) return buf; else return "(invalid)"; }
/** Determines the IPv6 scope of a specified address. * * @param[in] v6Addr - The IPv6 address to be checked. * * @return The ipv6 scope of the address. * * @remarks The @p v6Addr parameter must be pointer to a 16-byte IPv6 * address in binary form. * * @internal */ static int setScopeFromAddress(const struct in6_addr * v6Addr) { if (IN6_IS_ADDR_MULTICAST(v6Addr)) { if (IN6_IS_ADDR_MC_GLOBAL(v6Addr)) return SLP_SCOPE_GLOBAL; if (IN6_IS_ADDR_MC_ORGLOCAL(v6Addr)) return SLP_SCOPE_ORG_LOCAL; if (IN6_IS_ADDR_MC_SITELOCAL(v6Addr)) return SLP_SCOPE_SITE_LOCAL; if (IN6_IS_ADDR_MC_NODELOCAL(v6Addr)) return SLP_SCOPE_NODE_LOCAL; if (IN6_IS_ADDR_MC_LINKLOCAL(v6Addr)) return SLP_SCOPE_LINK_LOCAL; } if (IN6_IS_ADDR_SITELOCAL(v6Addr)) return SLP_SCOPE_SITE_LOCAL; if (SLP_IN6_IS_ADDR_LOOPBACK(v6Addr)) return SLP_SCOPE_NODE_LOCAL; if (IN6_IS_ADDR_LINKLOCAL(v6Addr)) return SLP_SCOPE_LINK_LOCAL; return 0; }
static void ifa_make_sockaddr(sa_family_t family, struct sockaddr *sa, void *p, size_t len, uint32_t scope, uint32_t scopeid) { if (sa == NULL) return; switch(family){ case AF_INET: memcpy(&((struct sockaddr_in*)sa)->sin_addr, (char *)p, len); break; case AF_INET6: memcpy(&((struct sockaddr_in6*)sa)->sin6_addr, (char *)p, len); if (IN6_IS_ADDR_LINKLOCAL(p) || IN6_IS_ADDR_MC_LINKLOCAL(p)){ ((struct sockaddr_in6*)sa)->sin6_scope_id = scopeid; } break; case AF_PACKET: memcpy(((struct sockaddr_ll*)sa)->sll_addr, (char *)p, len); ((struct sockaddr_ll*)sa)->sll_halen = len; break; default: memcpy(sa->sa_data, p, len); /*XXX*/ break; } sa->sa_family = family; #ifdef HAVE_SOCKADDR_SA_LEN sa->sa_len = ifa_sa_len(family, len); #endif }
static void copy_addr(struct sockaddr** r, int af, union sockany* sa, void* addr, size_t addrlen, int ifindex) { uint8_t* dst; int len; switch (af) { case AF_INET: dst = (uint8_t*)&sa->v4.sin_addr; len = 4; break; case AF_INET6: dst = (uint8_t*)&sa->v6.sin6_addr; len = 16; if (IN6_IS_ADDR_LINKLOCAL(addr) || IN6_IS_ADDR_MC_LINKLOCAL(addr)) sa->v6.sin6_scope_id = ifindex; break; default: return; } if (addrlen < len) return; sa->sa.sa_family = af; memcpy(dst, addr, len); *r = &sa->sa; }
/* Parse SOURCE as a scope ID for ADDRESS. Return 0 on success and -1 on error. */ internal_function int __inet6_scopeid_pton (const struct in6_addr *address, const char *scope, uint32_t *result) { if (IN6_IS_ADDR_LINKLOCAL (address) || IN6_IS_ADDR_MC_LINKLOCAL (address)) { uint32_t number = __if_nametoindex (scope); if (number != 0) { *result = number; return 0; } } if (isdigit_l (scope[0], _nl_C_locobj_ptr)) { char *end; unsigned long long number = ____strtoull_l_internal (scope, &end, /*base */ 10, /* group */ 0, _nl_C_locobj_ptr); if (*end == '\0' && number <= UINT32_MAX) { *result = number; return 0; } } __set_errno (EINVAL); return -1; }
const char * ACE_INET_Addr::get_host_addr (char *dst, int size) const { #if defined (ACE_HAS_IPV6) if (this->get_type () == AF_INET6) { // [email protected] - Aug-26, 2005 // I don't think this should be done because it results in a decimal address // representation which is not distinguishable from the IPv4 form which makes // it impossible to resolve back to an IPv6 INET_Addr without prior knowledge // that this was such an address to begin with. //if (IN6_IS_ADDR_V4MAPPED (&this->inet_addr_.in6_.sin6_addr)) //{ // ACE_UINT32 addr; // addr = this->get_ip_address(); // addr = ACE_HTONL (addr); // return ACE_OS::inet_ntop (AF_INET, &addr, dst, size); //} # if defined (ACE_WIN32) if (0 == ::getnameinfo (reinterpret_cast<const sockaddr*> (&this->inet_addr_.in6_), this->get_size (), dst, size, 0, 0, // Don't want service name NI_NUMERICHOST)) return dst; ACE_OS::set_errno_to_wsa_last_error (); return 0; # else const char *ch = ACE_OS::inet_ntop (AF_INET6, &this->inet_addr_.in6_.sin6_addr, dst, size); #if defined (__linux__) if ((IN6_IS_ADDR_LINKLOCAL (&this->inet_addr_.in6_.sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL (&this->inet_addr_.in6_.sin6_addr)) && this->inet_addr_.in6_.sin6_scope_id != 0) { char scope_buf[32]; ACE_OS::sprintf (scope_buf, "%%%u", this->inet_addr_.in6_.sin6_scope_id); if ((ACE_OS::strlen (ch)+ACE_OS::strlen (scope_buf)) < (size_t)size) { ACE_OS::strcat (dst, scope_buf); } } #endif return ch; # endif /* ACE_WIN32 */ } #endif /* ACE_HAS_IPV6 */ return ACE_OS::inet_ntop (AF_INET, &this->inet_addr_.in4_.sin_addr, dst, size); }
struct sockaddr * _SC_string_to_sockaddr(const char *str, sa_family_t af, void *buf, size_t bufLen) { union { void *buf; struct sockaddr *sa; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; } addr; if (buf == NULL) { bufLen = sizeof(struct sockaddr_storage); addr.buf = CFAllocatorAllocate(NULL, bufLen, 0); } else { addr.buf = buf; } bzero(addr.buf, bufLen); if (((af == AF_UNSPEC) || (af == AF_INET)) && (bufLen >= sizeof(struct sockaddr_in)) && inet_aton(str, &addr.sin->sin_addr) == 1) { // if IPv4 address addr.sin->sin_len = sizeof(struct sockaddr_in); addr.sin->sin_family = AF_INET; } else if (((af == AF_UNSPEC) || (af == AF_INET6)) && (bufLen >= sizeof(struct sockaddr_in6)) && inet_pton(AF_INET6, str, &addr.sin6->sin6_addr) == 1) { // if IPv6 address char *p; addr.sin6->sin6_len = sizeof(struct sockaddr_in6); addr.sin6->sin6_family = AF_INET6; p = strchr(buf, '%'); if (p != NULL) { addr.sin6->sin6_scope_id = if_nametoindex(p + 1); } if (IN6_IS_ADDR_LINKLOCAL(&addr.sin6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&addr.sin6->sin6_addr)) { uint16_t if_index; if_index = ntohs(addr.sin6->sin6_addr.__u6_addr.__u6_addr16[1]); addr.sin6->sin6_addr.__u6_addr.__u6_addr16[1] = 0; if (addr.sin6->sin6_scope_id == 0) { // use the scope id that was embedded in the [link local] IPv6 address addr.sin6->sin6_scope_id = if_index; } } } else { if (addr.buf != buf) { CFAllocatorDeallocate(NULL, addr.buf); } addr.buf = NULL; } return addr.sa; }
static int parse_kernel_route(const struct rt_msghdr *rtm, struct kernel_route *route) { void *rta = (void*)rtm + sizeof(struct rt_msghdr); struct sockaddr_in6 *sin6; char addr[INET6_ADDRSTRLEN]; memset(route, 0, sizeof(*route)); route->metric = 0; route->ifindex = rtm->rtm_index; if(!(rtm->rtm_addrs & RTA_DST)) return -1; sin6 = (struct sockaddr_in6 *)rta; if(IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) return -1; if((rtm->rtm_flags & RTF_PROTO2) != 0) return -1; memcpy(&route->prefix, &sin6->sin6_addr, 16); rta += ROUNDUP(sizeof(struct sockaddr_in6)); if(!(rtm->rtm_addrs & RTA_GATEWAY)) return -1; sin6 = (struct sockaddr_in6 *)rta; if(IN6_IS_ADDR_LINKLOCAL (&sin6->sin6_addr)) { route->ifindex = IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr); SET_IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr, 0); } memcpy(&route->gw, &sin6->sin6_addr, 16); rta += ROUNDUP(sizeof(struct sockaddr_in6)); if(!(rtm->rtm_addrs & RTA_NETMASK)) { route->plen = 0; } else { sin6 = (struct sockaddr_in6 *)rta; route->plen = mask2len(&sin6->sin6_addr); inet_ntop(AF_INET6, &sin6->sin6_addr, addr, sizeof(addr)); rta += ROUNDUP(sizeof(struct sockaddr_in6)); } if (rtm->rtm_flags & RTF_HOST) route->plen = 128; if(ifindex_lo < 0) { ifindex_lo = if_nametoindex("lo0"); if(ifindex_lo <= 0) return -1; } if(route->ifindex == ifindex_lo) return -1; return 0; }
/* * check validity of a router renumbering command packet * return 0 on success, 1 on failure */ static int rr_command_check(int len, struct icmp6_router_renum *rr, struct in6_addr *from, struct in6_addr *dst) { char ntopbuf[INET6_ADDRSTRLEN]; /* omit rr minimal length check. hope kernel have done it. */ /* rr_command length check */ if (len < (sizeof(struct icmp6_router_renum) + sizeof(struct rr_pco_match))) { syslog(LOG_ERR, "<%s> rr_command len %d is too short", __func__, len); return 1; } /* destination check. only for multicast. omit unicast check. */ if (IN6_IS_ADDR_MULTICAST(dst) && !IN6_IS_ADDR_MC_LINKLOCAL(dst) && !IN6_IS_ADDR_MC_SITELOCAL(dst)) { syslog(LOG_ERR, "<%s> dst mcast addr %s is illegal", __func__, inet_ntop(AF_INET6, dst, ntopbuf, INET6_ADDRSTRLEN)); return 1; } /* seqnum and segnum check */ if (rro.rro_seqnum > rr->rr_seqnum) { syslog(LOG_WARNING, "<%s> rcvd old seqnum %d from %s", __func__, (u_int32_t)ntohl(rr->rr_seqnum), inet_ntop(AF_INET6, from, ntopbuf, INET6_ADDRSTRLEN)); return 1; } if (rro.rro_seqnum == rr->rr_seqnum && (rr->rr_flags & ICMP6_RR_FLAGS_TEST) == 0 && RR_ISSET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum)) { if ((rr->rr_flags & ICMP6_RR_FLAGS_REQRESULT) != 0) syslog(LOG_WARNING, "<%s> rcvd duped segnum %d from %s", __func__, rr->rr_segnum, inet_ntop(AF_INET6, from, ntopbuf, INET6_ADDRSTRLEN)); return 0; } /* update seqnum */ if (rro.rro_seqnum != rr->rr_seqnum) { /* then must be "<" */ /* init rro_segnum_bits */ memset(rro.rro_segnum_bits, 0, sizeof(rro.rro_segnum_bits)); } rro.rro_seqnum = rr->rr_seqnum; return 0; }
char * inet6name(struct in6_addr *in6p) { char *cp; static char line[NI_MAXHOST]; struct hostent *hp; static char domain[MAXHOSTNAMELEN]; static int first = 1; char hbuf[NI_MAXHOST]; struct sockaddr_in6 sin6; const int niflag = NI_NUMERICHOST; if (first && !nflag) { first = 0; if (gethostname(domain, sizeof(domain)) == 0 && (cp = strchr(domain, '.'))) (void) strlcpy(domain, cp + 1, sizeof domain); else domain[0] = '\0'; } cp = 0; if (!nflag && !IN6_IS_ADDR_UNSPECIFIED(in6p)) { hp = gethostbyaddr((char *)in6p, sizeof(*in6p), AF_INET6); if (hp) { if ((cp = strchr(hp->h_name, '.')) && !strcmp(cp + 1, domain)) *cp = 0; cp = hp->h_name; } } if (IN6_IS_ADDR_UNSPECIFIED(in6p)) strlcpy(line, "*", sizeof(line)); else if (cp) strlcpy(line, cp, sizeof(line)); else { memset(&sin6, 0, sizeof(sin6)); sin6.sin6_len = sizeof(sin6); sin6.sin6_family = AF_INET6; sin6.sin6_addr = *in6p; #ifdef __KAME__ if (IN6_IS_ADDR_LINKLOCAL(in6p) || IN6_IS_ADDR_MC_LINKLOCAL(in6p)) { sin6.sin6_scope_id = ntohs(*(u_int16_t *)&in6p->s6_addr[2]); sin6.sin6_addr.s6_addr[2] = 0; sin6.sin6_addr.s6_addr[3] = 0; } #endif if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, hbuf, sizeof(hbuf), NULL, 0, niflag) != 0) strlcpy(hbuf, "?", sizeof hbuf); strlcpy(line, hbuf, sizeof(line)); } return (line); }
bool BNetworkAddress::IsMulticastLinkLocal() const { switch (fAddress.ss_family) { case AF_INET6: return IN6_IS_ADDR_MC_LINKLOCAL( &((sockaddr_in6&)fAddress).sin6_addr); default: return false; } }
int svx_inetaddr_from_ipport(svx_inetaddr_t *self, const char *ip, uint16_t port) { int r = 0; char *ifname = NULL; char ipv6[INET6_ADDRSTRLEN + 1 + IF_NAMESIZE + 1]; if(NULL == self || NULL == ip) SVX_LOG_ERRNO_RETURN_ERR(SVX_ERRNO_INVAL, "self:%p, ip:%p\n", self, ip); memset(self, 0, sizeof(svx_inetaddr_t)); if(!strchr(ip, ':')) { /* IPv4 */ self->storage.addr4.sin_family = AF_INET; self->storage.addr4.sin_port = htons(port); if(1 != (r = inet_pton(AF_INET, ip, &(self->storage.addr4.sin_addr)))) SVX_LOG_ERRNO_RETURN_ERR((0 == r ? SVX_ERRNO_INVAL : errno), "ip:%s\n", ip); } else { /* IPv6 */ self->storage.addr6.sin6_family = AF_INET6; self->storage.addr6.sin6_port = htons(port); self->storage.addr6.sin6_flowinfo = 0; /* ignored, always 0 */ self->storage.addr6.sin6_scope_id = 0; /* only used for link-local IPv6 address */ strncpy(ipv6, ip, sizeof(ipv6)); if(NULL != (ifname = strchr(ipv6, '%'))) { *ifname = '\0'; ifname++; } if(1 != (r = inet_pton(AF_INET6, ipv6, &(self->storage.addr6.sin6_addr)))) SVX_LOG_ERRNO_RETURN_ERR((0 == r ? SVX_ERRNO_INVAL : errno), "ip:%s\n", ipv6); /* set scope id for link-local IPv6 address */ /* man ipv6(7): Linux supports it only for link-local addresses, in that case sin6_scope_id contains the interface index */ if(IN6_IS_ADDR_LINKLOCAL(&(self->storage.addr6.sin6_addr)) || IN6_IS_ADDR_MC_LINKLOCAL(&(self->storage.addr6.sin6_addr))) { if(NULL == ifname || '\0' == *ifname) SVX_LOG_ERRNO_RETURN_ERR(SVX_ERRNO_FORMAT, "IPv6 link-local address without interface: %s\n", ip); if(0 == (self->storage.addr6.sin6_scope_id = if_nametoindex(ifname))) SVX_LOG_ERRNO_RETURN_ERR(errno, "ifname:%s\n", ifname); } } return 0; }
int inet6_uvif2scopeid(struct sockaddr_in6 *sa, struct uvif *v) { if (IN6_IS_ADDR_MULTICAST(&sa->sin6_addr)) { if (IN6_IS_ADDR_MC_LINKLOCAL(&sa->sin6_addr)) return(v->uv_ifindex); } else { if (IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr)) return(v->uv_ifindex); } return(0); }
/* * Print the textual representation (as given by inet_ntop(3)) of the address * set in "sa". * * Return the total length of the string it tried to create or 0 if an error * occured, in which case errno is set. On success, the constructed string * is guaranteed to be NUL-terminated. Overflow must be detected by checking * the returned size against buflen. * */ static size_t asr_print_addr(const struct sockaddr *sa, char *buf, size_t buflen) { unsigned int ifidx; char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; char scope[IF_NAMESIZE + 1], *ifname; const void *addr; size_t s; switch(sa->sa_family) { case AF_INET: addr = &SA_IN(sa)->sin_addr; break; case AF_INET6: addr = &SA_IN6(sa)->sin6_addr; break; default: errno = EINVAL; return (0); } if (inet_ntop(sa->sa_family, addr, tmp, sizeof(tmp)) == NULL) return (0); /* errno set */ s = strlcpy(buf, tmp, buflen); if (sa->sa_family == AF_INET6 && SA_IN6(sa)->sin6_scope_id) { scope[0] = SCOPE_DELIMITER; scope[1] = '\0'; ifidx = SA_IN6(sa)->sin6_scope_id; ifname = NULL; if (IN6_IS_ADDR_LINKLOCAL(&(SA_IN6(sa)->sin6_addr)) || IN6_IS_ADDR_MC_LINKLOCAL(&(SA_IN6(sa)->sin6_addr)) || IN6_IS_ADDR_MC_INTFACELOCAL(&(SA_IN6(sa)->sin6_addr))) ifname = if_indextoname(ifidx, scope + 1); if (ifname == NULL) (void)snprintf(scope + 1, sizeof(scope) - 1, "%u", ifidx); if (s < buflen) (void)strlcat(buf, scope, buflen); s += strlen(scope); } return (s); }
static struct sockaddr * ifa_make_sockaddr_mask (sa_family_t family, struct sockaddr *sa, uint32_t prefixlen) { int i; char *p = NULL, c; uint32_t max_prefixlen = 0; if (sa == NULL) return NULL; switch (family) { case AF_INET: memset (&((struct sockaddr_in *) sa)->sin_addr, 0, sizeof (((struct sockaddr_in *) sa)->sin_addr)); p = (char *) &((struct sockaddr_in *) sa)->sin_addr; max_prefixlen = 32; break; case AF_INET6: memset (&((struct sockaddr_in6 *) sa)->sin6_addr, 0, sizeof (((struct sockaddr_in6 *) sa)->sin6_addr)); p = (char *) &((struct sockaddr_in6 *) sa)->sin6_addr; #if 0 /* XXX: fill scope-id? */ if (IN6_IS_ADDR_LINKLOCAL (p) || IN6_IS_ADDR_MC_LINKLOCAL (p)) { ((struct sockaddr_in6 *) sa)->sin6_scope_id = scopeid; } #endif max_prefixlen = 128; break; default: return NULL; } sa->sa_family = family; #ifdef HAVE_SOCKADDR_SA_LEN sa->sa_len = ifa_sa_len (family, len); #endif if (p) { if (prefixlen > max_prefixlen) prefixlen = max_prefixlen; for (i = 0; i < (prefixlen / 8); i++) *p++ = 0xff; c = 0xff; c <<= (8 - (prefixlen % 8)); *p = c; } return sa; }
static void add_scope(struct sockaddr *sa, int ifindex) { struct sockaddr_in6 *sa6; if (sa->sa_family != AF_INET6) return; sa6 = (struct sockaddr_in6 *)sa; if (!IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) && !IN6_IS_ADDR_MC_LINKLOCAL(&sa6->sin6_addr)) return; if (*(u_int16_t *)&sa6->sin6_addr.s6_addr[2] != 0) return; *(u_int16_t *)&sa6->sin6_addr.s6_addr[2] = htons(ifindex); }
sockaddr* CopyAddress(int family, const void* data, size_t byteCount, sockaddr_storage* ss) { // Netlink gives us the address family in the header, and the // sockaddr_in or sockaddr_in6 bytes as the payload. We need to // stitch the two bits together into the sockaddr that's part of // our portable interface. ss->ss_family = family; memcpy(SockaddrBytes(family, ss), data, byteCount); // For IPv6 we might also have to set the scope id. if (family == AF_INET6 && (IN6_IS_ADDR_LINKLOCAL(data) || IN6_IS_ADDR_MC_LINKLOCAL(data))) { reinterpret_cast<sockaddr_in6*>(ss)->sin6_scope_id = interface_index; } return reinterpret_cast<sockaddr*>(ss); }
int ncprange_scopeid(const struct ncprange *range) { const struct in6_addr *sin6; int scopeid = -1; if (range->ncprange_family == AF_INET6) { sin6 = &range->ncprange_ip6addr; if (IN6_IS_ADDR_LINKLOCAL(sin6) || IN6_IS_ADDR_MC_LINKLOCAL(sin6)) if ((scopeid = ntohs(*(const u_short *)&sin6->s6_addr[2])) == 0) scopeid = -1; } return scopeid; }
static void foreach_route_cb (struct nl_object *object, void *user_data) { ForeachRouteInfo *info = user_data; struct rtnl_route *route = (struct rtnl_route *) object; struct nl_addr *dst; if (info->out_route) return; if (nm_logging_level_enabled (LOGL_DEBUG)) dump_route (route); if ( info->ifindex > 0 && rtnl_route_get_oif (route) != info->ifindex) return; if ( info->scope != RT_SCOPE_UNIVERSE && rtnl_route_get_scope (route) != info->scope) return; if ( info->family != AF_UNSPEC && rtnl_route_get_family (route) != info->family) return; dst = rtnl_route_get_dst (route); /* Check for IPv6 LL and MC routes that might need to be ignored */ if ( (info->family == AF_INET6 || info->family == AF_UNSPEC) && (rtnl_route_get_family (route) == AF_INET6)) { struct in6_addr *addr = NULL; if (dst) addr = nl_addr_get_binary_addr (dst); if (addr) { if ( IN6_IS_ADDR_LINKLOCAL (addr) || IN6_IS_ADDR_MC_LINKLOCAL (addr) || (IN6_IS_ADDR_MULTICAST (addr) && (nl_addr_get_prefixlen (dst) == 8))) return; } } info->out_route = info->callback (route, dst, info->iface, info->user_data); if (info->out_route) { /* Ref the route so it sticks around after the cache is cleared */ rtnl_route_get (info->out_route); } }
static void adjust_linklocal(struct sockaddr_in6 *sin6) { /* XXX: ?????!?!?!!!!! This is horrible ! */ /* * The kernel does not understand sin6_scope_id for routing at this moment. * We should rather keep the embedded ID. * [email protected], 20011026 */ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) { sin6->sin6_scope_id = ntohs(*(u_short *)&sin6->sin6_addr.s6_addr[2]); *(u_short *)&sin6->sin6_addr.s6_addr[2] = 0; } }
bool icmp_base::send_icmp(const interface *intf, const in6_addr &dst, int rta, icmp6_hdr *hdr, uint16_t len) const { if (IN6_IS_ADDR_LINKLOCAL(&dst) || IN6_IS_ADDR_MC_LINKLOCAL(&dst)) return send_icmp(intf, *intf->linklocal(), dst, rta, hdr, len); else { if (intf->globals().empty()) { if (g_mrd->should_log(DEBUG)) { g_mrd->log().xprintf( "[ICMPv6] Failed to send message to " "%{addr}, no global address.\n", dst); } return false; } return send_icmp(intf, *intf->globals().begin(), dst, rta, hdr, len); } }
TEST(ifaddrs, inet6_scope_ids) { ifaddrs* addrs; ASSERT_EQ(0, getifaddrs(&addrs)); for (ifaddrs* ifa = addrs; ifa != nullptr; ifa = ifa->ifa_next) { if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) { sockaddr_in6* sa6 = reinterpret_cast<sockaddr_in6*>(ifa->ifa_addr); // Any link-local IPv6 address should have a scope id. (http://b/27219454.) // 0 isn't a valid interface index, so that would mean the scope id wasn't set. if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sa6->sin6_addr)) { ASSERT_NE(sa6->sin6_scope_id, 0U); } } } freeifaddrs(addrs); }
int really_send(struct in6_addr const *dest, unsigned int if_index, struct in6_addr if_addr, unsigned char *buff, size_t len) { char __attribute__ ((aligned(8))) chdr[CMSG_SPACE(sizeof(struct in6_pktinfo))]; struct in6_pktinfo *pkt_info; struct msghdr mhdr; struct cmsghdr *cmsg; struct iovec iov; int err; struct sockaddr_in6 addr; memset((void *)&addr, 0, sizeof(addr)); addr.sin6_family = AF_INET6; addr.sin6_port = htons(IPPROTO_ICMPV6); memcpy(&addr.sin6_addr, dest, sizeof(struct in6_addr)); iov.iov_len = len; iov.iov_base = (caddr_t) buff; memset(chdr, 0, sizeof(chdr)); cmsg = (struct cmsghdr *)chdr; cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); cmsg->cmsg_level = IPPROTO_IPV6; cmsg->cmsg_type = IPV6_PKTINFO; pkt_info = (struct in6_pktinfo *)CMSG_DATA(cmsg); pkt_info->ipi6_ifindex = if_index; memcpy(&pkt_info->ipi6_addr, &if_addr, sizeof(struct in6_addr)); #ifdef HAVE_SIN6_SCOPE_ID if (IN6_IS_ADDR_LINKLOCAL(&addr.sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&addr.sin6_addr)) addr.sin6_scope_id = if_index; #endif memset(&mhdr, 0, sizeof(mhdr)); mhdr.msg_name = (caddr_t) & addr; mhdr.msg_namelen = sizeof(struct sockaddr_in6); mhdr.msg_iov = &iov; mhdr.msg_iovlen = 1; mhdr.msg_control = (void *)cmsg; mhdr.msg_controllen = sizeof(chdr); err = sendmsg(sock, &mhdr, 0); return err; }
void mld_interface::handle_mldv1_membership_reduction(const in6_addr &src, mldv1 *mldhdr) { m_stats.counter(ReductionCount, RX)++; mld->stats().counter(ReductionCount, RX)++; if (!IN6_IS_ADDR_MULTICAST(&mldhdr->mcaddr)) { m_stats.counter(ReductionCount, Bad)++; mld->stats().counter(ReductionCount, Bad)++; return; } if (IN6_IS_ADDR_MC_NODELOCAL(&mldhdr->mcaddr) || IN6_IS_ADDR_MC_LINKLOCAL(&mldhdr->mcaddr)) return; handle_mode_change_for_group(1, src, mldhdr->mcaddr, MLD_SSM_CHANGE_TO_INCLUDE, address_set()); }
void ipv6ll_db_store(struct sockaddr_in6 *sin6, struct sockaddr_in6 *sin6mask, int dbflag, char *ifname) { /* * If linklocal, store a version that will match conf output * with no scope id, ifname in separate database field */ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr) || IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) { sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0; sin6->sin6_scope_id = 0; db_delete_flag_x_ctl_data("ipv6linklocal", ifname, netname6(sin6, sin6mask)); if (dbflag != DB_X_REMOVE) db_insert_flag_x("ipv6linklocal", ifname, 0, dbflag, netname6(sin6, sin6mask)); } }
int svx_inetaddr_get_ipport(svx_inetaddr_t *self, char *ip, size_t ip_len, uint16_t *port) { size_t len; if(NULL == self || ((NULL == ip || ip_len < SVX_INETADDR_STR_IP_LEN) && NULL == port)) SVX_LOG_ERRNO_RETURN_ERR(SVX_ERRNO_INVAL, "self:%p, ip:%p, ip_len:%zu, port:%p\n", self, ip, ip_len, port); switch(self->storage.addr.sa_family) { case AF_INET: if(NULL != ip && ip_len >= SVX_INETADDR_STR_IP_LEN) { memset(ip, 0, ip_len); if(NULL == inet_ntop(AF_INET, &(self->storage.addr4.sin_addr), ip, (socklen_t)ip_len)) SVX_LOG_ERRNO_RETURN_ERR(errno, NULL); } if(NULL != port) *port = ntohs(self->storage.addr4.sin_port); return 0; case AF_INET6: if(NULL != ip && ip_len >= SVX_INETADDR_STR_IP_LEN) { memset(ip, 0, ip_len); if(NULL == inet_ntop(AF_INET6, &(self->storage.addr6.sin6_addr), ip, (socklen_t)ip_len)) SVX_LOG_ERRNO_RETURN_ERR(errno, NULL); /* append IPv6 link-local address interface name */ if(IN6_IS_ADDR_LINKLOCAL(&(self->storage.addr6.sin6_addr)) || IN6_IS_ADDR_MC_LINKLOCAL(&(self->storage.addr6.sin6_addr))) { len = strlen(ip); ip[len++] = '%'; if(NULL == if_indextoname(self->storage.addr6.sin6_scope_id, ip + len)) SVX_LOG_ERRNO_RETURN_ERR(errno, NULL); } } if(NULL != port) *port = ntohs(self->storage.addr6.sin6_port); return 0; default: SVX_LOG_ERRNO_RETURN_ERR(SVX_ERRNO_NOTSPT, "family:%u\n", self->storage.addr.sa_family); } }
void mld_interface::handle_mldv2_membership_report(const in6_addr &src, mldv2_report *mldhdr, int len) { m_stats.counter(ReportV2Count, RX)++; mld->stats().counter(ReportV2Count, RX)++; mldv2_mrec *mrec = mldhdr->mrecs(); int clen = 0; int reccount = ntoh(mldhdr->nmrecs()); for (int i = 0; i < reccount && clen < len; i++, mrec = mrec->next()) { clen += sizeof(mldv2_mrec); if (clen <= len) clen += sizeof(in6_addr) * ntoh(mrec->nsrcs); } if (clen > len) { if (should_log(MESSAGE_ERR)) log().writeline("Dropped badly formed MLDv2 Membership"); m_stats.counter(ReportV2Count, Bad)++; mld->stats().counter(ReportV2Count, Bad)++; return; } mrec = mldhdr->mrecs(); for (int i = 0; i < reccount; i++, mrec = mrec->next()) { if (!IN6_IS_ADDR_MULTICAST(&mrec->mca) || IN6_IS_ADDR_MC_NODELOCAL(&mrec->mca) || IN6_IS_ADDR_MC_LINKLOCAL(&mrec->mca)) continue; address_set sources; in6_addr *srcs = mrec->sources(); for (uint16_t j = 0; j < ntoh(mrec->nsrcs); j++) sources += srcs[j]; handle_mode_change_for_group(2, src, mrec->mca, mrec->type, sources); } }
static int really_send(int sock, struct in6_addr const *dest, struct properties const *props, struct safe_buffer const *sb) { struct sockaddr_in6 addr; memset((void *)&addr, 0, sizeof(addr)); addr.sin6_family = AF_INET6; addr.sin6_port = htons(IPPROTO_ICMPV6); memcpy(&addr.sin6_addr, dest, sizeof(struct in6_addr)); struct iovec iov; iov.iov_len = sb->used; iov.iov_base = (caddr_t)sb->buffer; char __attribute__ ((aligned(8))) chdr[CMSG_SPACE(sizeof(struct in6_pktinfo))]; memset(chdr, 0, sizeof(chdr)); struct cmsghdr *cmsg = (struct cmsghdr *)chdr; cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); cmsg->cmsg_level = IPPROTO_IPV6; cmsg->cmsg_type = IPV6_PKTINFO; struct in6_pktinfo *pkt_info = (struct in6_pktinfo *)CMSG_DATA(cmsg); pkt_info->ipi6_ifindex = props->if_index; memcpy(&pkt_info->ipi6_addr, &props->if_addr, sizeof(struct in6_addr)); #ifdef HAVE_SIN6_SCOPE_ID if (IN6_IS_ADDR_LINKLOCAL(&addr.sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&addr.sin6_addr)) addr.sin6_scope_id = props->if_index; #endif struct msghdr mhdr; memset(&mhdr, 0, sizeof(mhdr)); mhdr.msg_name = (caddr_t) & addr; mhdr.msg_namelen = sizeof(struct sockaddr_in6); mhdr.msg_iov = &iov; mhdr.msg_iovlen = 1; mhdr.msg_control = (void *)cmsg; mhdr.msg_controllen = sizeof(chdr); return sendmsg(sock, &mhdr, 0); }
// Forwards a packet on a specific interface ssize_t relayd_forward_packet(int socket, struct sockaddr_in6 *dest, struct iovec *iov, size_t iov_len, const struct relayd_interface *iface) { // Construct headers uint8_t cmsg_buf[CMSG_SPACE(sizeof(struct in6_pktinfo))] = {0}; struct msghdr msg = {(void*)dest, sizeof(*dest), iov, iov_len, cmsg_buf, sizeof(cmsg_buf), 0}; // Set control data (define destination interface) struct cmsghdr *chdr = CMSG_FIRSTHDR(&msg); chdr->cmsg_level = IPPROTO_IPV6; chdr->cmsg_type = IPV6_PKTINFO; chdr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); struct in6_pktinfo *pktinfo = (struct in6_pktinfo*)CMSG_DATA(chdr); pktinfo->ipi6_ifindex = iface->ifindex; // Also set scope ID if link-local if (IN6_IS_ADDR_LINKLOCAL(&dest->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&dest->sin6_addr)) dest->sin6_scope_id = iface->ifindex; // IPV6_PKTINFO doesn't really work for IPv6-raw sockets (bug?) if (dest->sin6_port == 0) { msg.msg_control = NULL; msg.msg_controllen = 0; } char ipbuf[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &dest->sin6_addr, ipbuf, sizeof(ipbuf)); ssize_t sent = sendmsg(socket, &msg, MSG_DONTWAIT); if (sent < 0) syslog(LOG_WARNING, "Failed to relay to %s%%%s (%s)", ipbuf, iface->ifname, strerror(errno)); else syslog(LOG_NOTICE, "Relayed %li bytes to %s%%%s", (long)sent, ipbuf, iface->ifname); return sent; }
/* * Write the numeric address */ static int _numerichost(struct asr_query *as) { unsigned int ifidx; char scope[IF_NAMESIZE + 1], *ifname; void *addr; char *buf = as->as.ni.hostname; size_t buflen = as->as.ni.hostnamelen; if (as->as.ni.sa.sa.sa_family == AF_INET) addr = &as->as.ni.sa.sain.sin_addr; else addr = &as->as.ni.sa.sain6.sin6_addr; if (inet_ntop(as->as.ni.sa.sa.sa_family, addr, buf, buflen) == NULL) return (-1); /* errno set */ if (as->as.ni.sa.sa.sa_family == AF_INET6 && as->as.ni.sa.sain6.sin6_scope_id) { scope[0] = SCOPE_DELIMITER; scope[1] = '\0'; ifidx = as->as.ni.sa.sain6.sin6_scope_id; ifname = NULL; if (IN6_IS_ADDR_LINKLOCAL(&as->as.ni.sa.sain6.sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&as->as.ni.sa.sain6.sin6_addr) || IN6_IS_ADDR_MC_NODELOCAL(&as->as.ni.sa.sain6.sin6_addr)) ifname = if_indextoname(ifidx, scope + 1); if (ifname == NULL) snprintf(scope + 1, sizeof(scope) - 1, "%u", ifidx); strlcat(buf, scope, buflen); } return (0); }