Beispiel #1
0
/*
 * XXX: This is pxudp_pcb_forward_outbound modulo:
 * - s/pxudp/fwudp/g
 * - addr/port (unused in either) dropped
 * - destination is specified since host socket is not connected
 */
static void
fwudp_pcb_forward_outbound(struct fwudp *fwudp, struct udp_pcb *pcb,
                           struct pbuf *p)
{
    union {
        struct sockaddr_in sin;
        struct sockaddr_in6 sin6;
    } peer;
    socklen_t namelen;

    memset(&peer, 0, sizeof(peer)); /* XXX: shut up valgrind */

    if (fwudp->fwspec.sdom == PF_INET) {
        peer.sin.sin_family = AF_INET;
#if HAVE_SA_LEN
        peer.sin.sin_len =
#endif
        namelen = sizeof(peer.sin);
        pxremap_outbound_ip4((ip_addr_t *)&peer.sin.sin_addr, &pcb->local_ip.ip4);
        peer.sin.sin_port = htons(pcb->local_port);
    }
    else {
        peer.sin6.sin6_family = AF_INET6;
#if HAVE_SA_LEN
        peer.sin6.sin6_len =
#endif
        namelen = sizeof(peer.sin6);

        pxremap_outbound_ip6((ip6_addr_t *)&peer.sin6.sin6_addr, &pcb->local_ip.ip6);
        peer.sin6.sin6_port = htons(pcb->local_port);
    }

    proxy_sendto(fwudp->sock, p, &peer, namelen);
    pbuf_free(p);
}
Beispiel #2
0
/**
 * ICMP Echo Request in pbuf "p" is to be proxied.
 */
static void
pxping_recv4(void *arg, struct pbuf *p)
{
    struct pxping *pxping = (struct pxping *)arg;
    const struct ip_hdr *iph;
    const struct icmp_echo_hdr *icmph;
    u16_t iphlen;
    size_t bufsize;
    struct pong4 *pong;
    IPAddr dst;
    int mapped;
    int ttl;
    IP_OPTION_INFORMATION opts;
    void *reqdata;
    size_t reqsize;
    int status;

    pong = NULL;

    iphlen = ip_current_header_tot_len();
    if (RT_UNLIKELY(iphlen != IP_HLEN)) { /* we don't do options */
        goto out;
    }

    iph = (const struct ip_hdr *)ip_current_header();
    icmph = (const struct icmp_echo_hdr *)p->payload;

    mapped = pxremap_outbound_ip4((ip_addr_t *)&dst, (ip_addr_t *)&iph->dest);
    if (RT_UNLIKELY(mapped == PXREMAP_FAILED)) {
        goto out;
    }

    ttl = IPH_TTL(iph);
    if (mapped == PXREMAP_ASIS) {
        if (RT_UNLIKELY(ttl == 1)) {
            status = pbuf_header(p, iphlen); /* back to IP header */
            if (RT_LIKELY(status == 0)) {
                icmp_time_exceeded(p, ICMP_TE_TTL);
            }
            goto out;
        }
        --ttl;
    }

    status = pbuf_header(p, -(u16_t)sizeof(*icmph)); /* to ping payload */
    if (RT_UNLIKELY(status != 0)) {
        goto out;
    }

    bufsize = sizeof(ICMP_ECHO_REPLY) + p->tot_len;
    pong = (struct pong4 *)malloc(sizeof(*pong) - sizeof(pong->buf) + bufsize);
    if (RT_UNLIKELY(pong == NULL)) {
        goto out;
    }
    pong->bufsize = bufsize;
    pong->netif = pxping->netif;

    memcpy(&pong->reqiph, iph, sizeof(*iph));
    memcpy(&pong->reqicmph, icmph, sizeof(*icmph));

    reqsize = p->tot_len;
    if (p->next == NULL) {
        /* single pbuf can be directly used as request data source */
        reqdata = p->payload;
    }
    else {
        /* data from pbuf chain must be concatenated */
        pbuf_copy_partial(p, pong->buf, p->tot_len, 0);
        reqdata = pong->buf;
    }

    opts.Ttl = ttl;
    opts.Tos = IPH_TOS(iph); /* affected by DisableUserTOSSetting key */
    opts.Flags = (IPH_OFFSET(iph) & PP_HTONS(IP_DF)) != 0 ? IP_FLAG_DF : 0;
    opts.OptionsSize = 0;
    opts.OptionsData = 0;

    status = IcmpSendEcho2(pxping->hdl4, NULL,
                           pxping->callback4, pong,
                           dst, reqdata, (WORD)reqsize, &opts,
                           pong->buf, (DWORD)pong->bufsize,
                           5 * 1000 /* ms */);

    if (RT_UNLIKELY(status != 0)) {
        DPRINTF(("IcmpSendEcho2: unexpected status %d\n", status));
        goto out;
    }
    else if ((status = GetLastError()) != ERROR_IO_PENDING) {
        int code;

        DPRINTF(("IcmpSendEcho2: error %d\n", status));
        switch (status) {
        case ERROR_NETWORK_UNREACHABLE:
            code = ICMP_DUR_NET;
            break;
        case ERROR_HOST_UNREACHABLE:
            code = ICMP_DUR_HOST;
            break;
        default:
            code = -1;
            break;
        }

        if (code != -1) {
            /* move payload back to IP header */
            status = pbuf_header(p, (u16_t)(sizeof(*icmph) + iphlen));
            if (RT_LIKELY(status == 0)) {
                icmp_dest_unreach(p, code);
            }
        }
        goto out;
    }

    pong = NULL;                /* callback owns it now */
  out:
    if (pong != NULL) {
        free(pong);
    }
    pbuf_free(p);
}