/** * Set fwdsrc to the IP address of the peer. * * For port-forwarded connections originating from hosts loopback the * source address is set to the address of one of lwIP interfaces. * * Currently we only have one interface so there's not much logic * here. In the future we might need to additionally consult fwspec * and routing table to determine which netif is used for connections * to the specified guest. */ int fwany_ipX_addr_set_src(ipX_addr_t *fwdsrc, const struct sockaddr *peer) { int mapping; if (peer->sa_family == AF_INET) { const struct sockaddr_in *peer4 = (const struct sockaddr_in *)peer; ip_addr_t peerip4; peerip4.addr = peer4->sin_addr.s_addr; mapping = pxremap_inbound_ip4(&fwdsrc->ip4, &peerip4); } else if (peer->sa_family == AF_INET6) { const struct sockaddr_in6 *peer6 = (const struct sockaddr_in6 *)peer; ip6_addr_t peerip6; memcpy(&peerip6, &peer6->sin6_addr, sizeof(ip6_addr_t)); mapping = pxremap_inbound_ip6(&fwdsrc->ip6, &peerip6); } else { mapping = PXREMAP_FAILED; } return mapping; }
static void pxping_icmp4_callback(struct pong4 *pong) { ICMP_ECHO_REPLY *reply; DWORD nreplies; size_t icmplen; struct pbuf *p; struct icmp_echo_hdr *icmph; ip_addr_t src; int mapped; nreplies = IcmpParseReplies(pong->buf, (DWORD)pong->bufsize); if (nreplies == 0) { DWORD error = GetLastError(); if (error == IP_REQ_TIMED_OUT) { DPRINTF2(("pong4: %p timed out\n", (void *)pong)); } else { DPRINTF(("pong4: %p: IcmpParseReplies: error %d\n", (void *)pong, error)); } return; } reply = (ICMP_ECHO_REPLY *)pong->buf; if (reply->Options.OptionsSize != 0) { /* don't do options */ return; } mapped = pxremap_inbound_ip4(&src, (ip_addr_t *)&reply->Address); if (mapped == PXREMAP_FAILED) { return; } if (mapped == PXREMAP_ASIS) { if (reply->Options.Ttl == 1) { return; } --reply->Options.Ttl; } if (reply->Status == IP_SUCCESS) { icmplen = sizeof(struct icmp_echo_hdr) + reply->DataSize; if ((reply->Options.Flags & IP_FLAG_DF) != 0 && IP_HLEN + icmplen > pong->netif->mtu) { return; } p = pbuf_alloc(PBUF_IP, (u16_t)icmplen, PBUF_RAM); if (RT_UNLIKELY(p == NULL)) { return; } icmph = (struct icmp_echo_hdr *)p->payload; icmph->type = ICMP_ER; icmph->code = 0; icmph->chksum = 0; icmph->id = pong->reqicmph.id; icmph->seqno = pong->reqicmph.seqno; memcpy((u8_t *)p->payload + sizeof(*icmph), reply->Data, reply->DataSize); } else { u8_t type, code; switch (reply->Status) { case IP_DEST_NET_UNREACHABLE: type = ICMP_DUR; code = ICMP_DUR_NET; break; case IP_DEST_HOST_UNREACHABLE: type = ICMP_DUR; code = ICMP_DUR_HOST; break; case IP_DEST_PROT_UNREACHABLE: type = ICMP_DUR; code = ICMP_DUR_PROTO; break; case IP_PACKET_TOO_BIG: type = ICMP_DUR; code = ICMP_DUR_FRAG; break; case IP_SOURCE_QUENCH: type = ICMP_SQ; code = 0; break; case IP_TTL_EXPIRED_TRANSIT: type = ICMP_TE; code = ICMP_TE_TTL; break; case IP_TTL_EXPIRED_REASSEM: type = ICMP_TE; code = ICMP_TE_FRAG; break; default: DPRINTF(("pong4: reply status %d, dropped\n", reply->Status)); return; } DPRINTF(("pong4: reply status %d -> type %d/code %d\n", reply->Status, type, code)); icmplen = sizeof(*icmph) + sizeof(pong->reqiph) + sizeof(pong->reqicmph); p = pbuf_alloc(PBUF_IP, (u16_t)icmplen, PBUF_RAM); if (RT_UNLIKELY(p == NULL)) { return; } icmph = (struct icmp_echo_hdr *)p->payload; icmph->type = type; icmph->code = code; icmph->chksum = 0; icmph->id = 0; icmph->seqno = 0; /* * XXX: we don't know the TTL of the request at the time this * ICMP error was generated (we can guess it was 1 for ttl * exceeded, but don't bother faking it). */ memcpy((u8_t *)p->payload + sizeof(*icmph), &pong->reqiph, sizeof(pong->reqiph)); memcpy((u8_t *)p->payload + sizeof(*icmph) + sizeof(pong->reqiph), &pong->reqicmph, sizeof(pong->reqicmph)); } icmph->chksum = inet_chksum(p->payload, (u16_t)icmplen); ip_output_if(p, &src, (ip_addr_t *)&pong->reqiph.src, /* dst */ reply->Options.Ttl, reply->Options.Tos, IPPROTO_ICMP, pong->netif); pbuf_free(p); }