/* * Translate addr in host addr when it is a virtual address */ void sotranslate_out(struct socket *so, struct sockaddr_storage *addr) { Slirp *slirp = so->slirp; struct sockaddr_in *sin = (struct sockaddr_in *)addr; struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; switch (addr->ss_family) { case AF_INET: if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == slirp->vnetwork_addr.s_addr) { /* It's an alias */ if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) { if (get_dns_addr(&sin->sin_addr) < 0) { sin->sin_addr = loopback_addr; } } else { sin->sin_addr = loopback_addr; } } DEBUG_MISC((dfd, " addr.sin_port=%d, " "addr.sin_addr.s_addr=%.16s\n", ntohs(sin->sin_port), inet_ntoa(sin->sin_addr))); break; case AF_INET6: if (in6_equal_net(&so->so_faddr6, &slirp->vprefix_addr6, slirp->vprefix_len)) { if (in6_equal(&so->so_faddr6, &slirp->vnameserver_addr6)) { uint32_t scope_id; if (get_dns6_addr(&sin6->sin6_addr, &scope_id) >= 0) { sin6->sin6_scope_id = scope_id; } else { sin6->sin6_addr = in6addr_loopback; } } else { sin6->sin6_addr = in6addr_loopback; } } break; default: break; } }
/* * Send NDP Router Advertisement */ void ndp_send_ra(Slirp *slirp) { DEBUG_CALL("ndp_send_ra"); /* Build IPv6 packet */ struct mbuf *t = m_get(slirp); struct ip6 *rip = mtod(t, struct ip6 *); size_t pl_size = 0; struct in6_addr addr; uint32_t scope_id; rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR; rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST; rip->ip_nh = IPPROTO_ICMPV6; /* Build ICMPv6 packet */ t->m_data += sizeof(struct ip6); struct icmp6 *ricmp = mtod(t, struct icmp6 *); ricmp->icmp6_type = ICMP6_NDP_RA; ricmp->icmp6_code = 0; ricmp->icmp6_cksum = 0; /* NDP */ ricmp->icmp6_nra.chl = NDP_AdvCurHopLimit; ricmp->icmp6_nra.M = NDP_AdvManagedFlag; ricmp->icmp6_nra.O = NDP_AdvOtherConfigFlag; ricmp->icmp6_nra.reserved = 0; ricmp->icmp6_nra.lifetime = htons(NDP_AdvDefaultLifetime); ricmp->icmp6_nra.reach_time = htonl(NDP_AdvReachableTime); ricmp->icmp6_nra.retrans_time = htonl(NDP_AdvRetransTime); t->m_data += ICMP6_NDP_RA_MINLEN; pl_size += ICMP6_NDP_RA_MINLEN; /* Source link-layer address (NDP option) */ struct ndpopt *opt = mtod(t, struct ndpopt *); opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE; opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8; in6_compute_ethaddr(rip->ip_src, opt->ndpopt_linklayer); t->m_data += NDPOPT_LINKLAYER_LEN; pl_size += NDPOPT_LINKLAYER_LEN; /* Prefix information (NDP option) */ struct ndpopt *opt2 = mtod(t, struct ndpopt *); opt2->ndpopt_type = NDPOPT_PREFIX_INFO; opt2->ndpopt_len = NDPOPT_PREFIXINFO_LEN / 8; opt2->ndpopt_prefixinfo.prefix_length = slirp->vprefix_len; opt2->ndpopt_prefixinfo.L = 1; opt2->ndpopt_prefixinfo.A = 1; opt2->ndpopt_prefixinfo.reserved1 = 0; opt2->ndpopt_prefixinfo.valid_lt = htonl(NDP_AdvValidLifetime); opt2->ndpopt_prefixinfo.pref_lt = htonl(NDP_AdvPrefLifetime); opt2->ndpopt_prefixinfo.reserved2 = 0; opt2->ndpopt_prefixinfo.prefix = slirp->vprefix_addr6; t->m_data += NDPOPT_PREFIXINFO_LEN; pl_size += NDPOPT_PREFIXINFO_LEN; /* Prefix information (NDP option) */ if (get_dns6_addr(&addr, &scope_id) >= 0) { /* Host system does have an IPv6 DNS server, announce our proxy. */ struct ndpopt *opt3 = mtod(t, struct ndpopt *); opt3->ndpopt_type = NDPOPT_RDNSS; opt3->ndpopt_len = NDPOPT_RDNSS_LEN / 8; opt3->ndpopt_rdnss.reserved = 0; opt3->ndpopt_rdnss.lifetime = htonl(2 * NDP_MaxRtrAdvInterval); opt3->ndpopt_rdnss.addr = slirp->vnameserver_addr6; t->m_data += NDPOPT_RDNSS_LEN; pl_size += NDPOPT_RDNSS_LEN; } rip->ip_pl = htons(pl_size); t->m_data -= sizeof(struct ip6) + pl_size; t->m_len = sizeof(struct ip6) + pl_size; /* ICMPv6 Checksum */ ricmp->icmp6_cksum = ip6_cksum(t); ip6_output(NULL, t, 0); }