/** * Outbound TTL/HOPL check. */ static int pxudp_ttl_expired(struct pbuf *p) { int ttl; if (ip_current_is_v6()) { ttl = IP6H_HOPLIM(ip6_current_header()); } else { ttl = IPH_TTL(ip_current_header()); } if (RT_UNLIKELY(ttl <= 1)) { int status = pbuf_header(p, ip_current_header_tot_len() + UDP_HLEN); if (RT_LIKELY(status == 0)) { if (ip_current_is_v6()) { icmp6_time_exceeded(p, ICMP6_TE_HL); } else { icmp_time_exceeded(p, ICMP_TE_TTL); } } pbuf_free(p); return 1; } return 0; }
/* Print an IPv6 header by using LWIP_DEBUGF * @param p an IPv6 packet, p->payload pointing to the IPv6 header */ void ip6_debug_print(struct pbuf *p) { struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload; LWIP_UNUSED_ARG(ip6hdr); LWIP_DEBUGF(IP6_DEBUG, ("IPv6 header:\n")); LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP6_DEBUG, ("| %2"U16_F" | %3"U16_F" | %7"U32_F" | (ver, class, flow)\n", IP6H_V(ip6hdr), IP6H_TC(ip6hdr), IP6H_FL(ip6hdr))); LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP6_DEBUG, ("| %5"U16_F" | %3"U16_F" | %3"U16_F" | (plen, nexth, hopl)\n", IP6H_PLEN(ip6hdr), IP6H_NEXTH(ip6hdr), IP6H_HOPLIM(ip6hdr))); LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" | (src)\n", IP6_ADDR_BLOCK1(&(ip6hdr->src)), IP6_ADDR_BLOCK2(&(ip6hdr->src)), IP6_ADDR_BLOCK3(&(ip6hdr->src)), IP6_ADDR_BLOCK4(&(ip6hdr->src)))); LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" |\n", IP6_ADDR_BLOCK5(&(ip6hdr->src)), IP6_ADDR_BLOCK6(&(ip6hdr->src)), IP6_ADDR_BLOCK7(&(ip6hdr->src)), IP6_ADDR_BLOCK8(&(ip6hdr->src)))); LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" | (dest)\n", IP6_ADDR_BLOCK1(&(ip6hdr->dest)), IP6_ADDR_BLOCK2(&(ip6hdr->dest)), IP6_ADDR_BLOCK3(&(ip6hdr->dest)), IP6_ADDR_BLOCK4(&(ip6hdr->dest)))); LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" |\n", IP6_ADDR_BLOCK5(&(ip6hdr->dest)), IP6_ADDR_BLOCK6(&(ip6hdr->dest)), IP6_ADDR_BLOCK7(&(ip6hdr->dest)), IP6_ADDR_BLOCK8(&(ip6hdr->dest)))); LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); }
static void pxudp_pcb_forward_outbound(struct pxudp *pxudp, struct pbuf *p, ip_addr_t *addr, u16_t port) { int status; LWIP_UNUSED_ARG(addr); LWIP_UNUSED_ARG(port); if (!pxudp->is_mapped && pxudp_ttl_expired(p)) { return; } if (!ip_current_is_v6()) { /* IPv4 */ const struct ip_hdr *iph = ip_current_header(); int ttl, tos, df; /* * Different OSes have different socket options for DF. * Unlike pxping.c, we can't use IP_HDRINCL here as it's only * valid for SOCK_RAW. */ # define USE_DF_OPTION(_Optname) \ const int dfopt = _Optname; \ const char * const dfoptname = #_Optname; #if defined(IP_MTU_DISCOVER) /* Linux */ USE_DF_OPTION(IP_MTU_DISCOVER); #elif defined(IP_DONTFRAG) /* Solaris 11+, FreeBSD */ USE_DF_OPTION(IP_DONTFRAG); #elif defined(IP_DONTFRAGMENT) /* Windows */ USE_DF_OPTION(IP_DONTFRAGMENT); #else USE_DF_OPTION(0); #endif ttl = IPH_TTL(iph); if (!pxudp->is_mapped) { LWIP_ASSERT1(ttl > 1); --ttl; } if (ttl != pxudp->ttl) { status = setsockopt(pxudp->sock, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(ttl)); if (RT_LIKELY(status == 0)) { pxudp->ttl = ttl; } else { DPRINTF(("IP_TTL: %R[sockerr]\n", SOCKERRNO())); } } tos = IPH_TOS(iph); if (tos != pxudp->tos) { status = setsockopt(pxudp->sock, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(tos)); if (RT_LIKELY(status == 0)) { pxudp->tos = tos; } else { DPRINTF(("IP_TOS: %R[sockerr]\n", SOCKERRNO())); } } if (dfopt) { df = (IPH_OFFSET(iph) & PP_HTONS(IP_DF)) != 0; #if defined(IP_MTU_DISCOVER) df = df ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; #endif if (df != pxudp->df) { status = setsockopt(pxudp->sock, IPPROTO_IP, dfopt, (char *)&df, sizeof(df)); if (RT_LIKELY(status == 0)) { pxudp->df = df; } else { DPRINTF(("%s: %R[sockerr]\n", dfoptname, SOCKERRNO())); } } } } else { /* IPv6 */ const struct ip6_hdr *iph = ip6_current_header(); int ttl; ttl = IP6H_HOPLIM(iph); if (!pxudp->is_mapped) { LWIP_ASSERT1(ttl > 1); --ttl; } if (ttl != pxudp->ttl) { status = setsockopt(pxudp->sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *)&ttl, sizeof(ttl)); if (RT_LIKELY(status == 0)) { pxudp->ttl = ttl; } else { DPRINTF(("IPV6_UNICAST_HOPS: %R[sockerr]\n", SOCKERRNO())); } } } if (pxudp->pcb->local_port == 53) { ++pxudp->count; } proxy_sendto(pxudp->sock, p, NULL, 0); pbuf_free(p); }
/** * Forwards an IPv6 packet. It finds an appropriate route for the * packet, decrements the HL value of the packet, and outputs * the packet on the appropriate interface. * * @param p the packet to forward (p->payload points to IP header) * @param iphdr the IPv6 header of the input packet * @param inp the netif on which this packet was received */ static void ip6_forward(struct pbuf *p, struct ip6_hdr *iphdr, struct netif *inp) { struct netif *netif; /* do not forward link-local addresses */ if (ip6_addr_islinklocal(ip6_current_dest_addr())) { LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not forwarding link-local address.\n")); IP6_STATS_INC(ip6.rterr); IP6_STATS_INC(ip6.drop); return; } /* Find network interface where to forward this IP packet to. */ netif = ip6_route(IP6_ADDR_ANY6, ip6_current_dest_addr()); if (netif == NULL) { LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", IP6_ADDR_BLOCK1(ip6_current_dest_addr()), IP6_ADDR_BLOCK2(ip6_current_dest_addr()), IP6_ADDR_BLOCK3(ip6_current_dest_addr()), IP6_ADDR_BLOCK4(ip6_current_dest_addr()), IP6_ADDR_BLOCK5(ip6_current_dest_addr()), IP6_ADDR_BLOCK6(ip6_current_dest_addr()), IP6_ADDR_BLOCK7(ip6_current_dest_addr()), IP6_ADDR_BLOCK8(ip6_current_dest_addr()))); #if LWIP_ICMP6 /* Don't send ICMP messages in response to ICMP messages */ if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { icmp6_dest_unreach(p, ICMP6_DUR_NO_ROUTE); } #endif /* LWIP_ICMP6 */ IP6_STATS_INC(ip6.rterr); IP6_STATS_INC(ip6.drop); return; } /* Do not forward packets onto the same network interface on which * they arrived. */ if (netif == inp) { LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not bouncing packets back on incoming interface.\n")); IP6_STATS_INC(ip6.rterr); IP6_STATS_INC(ip6.drop); return; } /* decrement HL */ IP6H_HOPLIM_SET(iphdr, IP6H_HOPLIM(iphdr) - 1); /* send ICMP6 if HL == 0 */ if (IP6H_HOPLIM(iphdr) == 0) { #if LWIP_ICMP6 /* Don't send ICMP messages in response to ICMP messages */ if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { icmp6_time_exceeded(p, ICMP6_TE_HL); } #endif /* LWIP_ICMP6 */ IP6_STATS_INC(ip6.drop); return; } if (netif->mtu && (p->tot_len > netif->mtu)) { #if LWIP_ICMP6 /* Don't send ICMP messages in response to ICMP messages */ if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { icmp6_packet_too_big(p, netif->mtu); } #endif /* LWIP_ICMP6 */ IP6_STATS_INC(ip6.drop); return; } LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: forwarding packet to %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", IP6_ADDR_BLOCK1(ip6_current_dest_addr()), IP6_ADDR_BLOCK2(ip6_current_dest_addr()), IP6_ADDR_BLOCK3(ip6_current_dest_addr()), IP6_ADDR_BLOCK4(ip6_current_dest_addr()), IP6_ADDR_BLOCK5(ip6_current_dest_addr()), IP6_ADDR_BLOCK6(ip6_current_dest_addr()), IP6_ADDR_BLOCK7(ip6_current_dest_addr()), IP6_ADDR_BLOCK8(ip6_current_dest_addr()))); /* transmit pbuf on chosen interface */ netif->output_ip6(netif, p, ip6_current_dest_addr()); IP6_STATS_INC(ip6.fw); IP6_STATS_INC(ip6.xmit); return; }
static void pxping_recv6(void *arg, struct pbuf *p) { struct pxping *pxping = (struct pxping *)arg; struct icmp6_echo_hdr *icmph; size_t bufsize; struct pong6 *pong; int mapped; void *reqdata; size_t reqsize; struct sockaddr_in6 src, dst; int hopl; IP_OPTION_INFORMATION opts; int status; pong = NULL; icmph = (struct icmp6_echo_hdr *)p->payload; memset(&dst, 0, sizeof(dst)); dst.sin6_family = AF_INET6; mapped = pxremap_outbound_ip6((ip6_addr_t *)&dst.sin6_addr, ip6_current_dest_addr()); if (RT_UNLIKELY(mapped == PXREMAP_FAILED)) { goto out; } hopl = IP6H_HOPLIM(ip6_current_header()); if (mapped == PXREMAP_ASIS) { if (RT_UNLIKELY(hopl == 1)) { status = pbuf_header(p, ip_current_header_tot_len()); if (RT_LIKELY(status == 0)) { icmp6_time_exceeded(p, ICMP6_TE_HL); } goto out; } --hopl; } status = pbuf_header(p, -(u16_t)sizeof(*icmph)); /* to ping payload */ if (RT_UNLIKELY(status != 0)) { goto out; } bufsize = sizeof(ICMPV6_ECHO_REPLY) + p->tot_len; pong = (struct pong6 *)malloc(sizeof(*pong) - sizeof(pong->buf) + bufsize); if (RT_UNLIKELY(pong == NULL)) { goto out; } pong->bufsize = bufsize; pong->netif = pxping->netif; ip6_addr_copy(pong->reqsrc, *ip6_current_src_addr()); memcpy(&pong->reqicmph, icmph, sizeof(*icmph)); memset(pong->buf, 0xa5, pong->bufsize); pong->reqsize = 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; } memset(&src, 0, sizeof(src)); src.sin6_family = AF_INET6; src.sin6_addr = in6addr_any; /* let the OS select host source address */ memset(&opts, 0, sizeof(opts)); opts.Ttl = hopl; status = Icmp6SendEcho2(pxping->hdl6, NULL, pxping->callback6, pong, &src, &dst, reqdata, (WORD)reqsize, &opts, pong->buf, (DWORD)pong->bufsize, 5 * 1000 /* ms */); if (RT_UNLIKELY(status != 0)) { DPRINTF(("Icmp6SendEcho2: unexpected status %d\n", status)); goto out; } else if ((status = GetLastError()) != ERROR_IO_PENDING) { int code; DPRINTF(("Icmp6SendEcho2: error %d\n", status)); switch (status) { case ERROR_NETWORK_UNREACHABLE: case ERROR_HOST_UNREACHABLE: code = ICMP6_DUR_NO_ROUTE; break; default: code = -1; break; } if (code != -1) { /* move payload back to IP header */ status = pbuf_header(p, (u16_t)(sizeof(*icmph) + ip_current_header_tot_len())); if (RT_LIKELY(status == 0)) { icmp6_dest_unreach(p, code); } } goto out; } pong = NULL; /* callback owns it now */ out: if (pong != NULL) { free(pong); } pbuf_free(p); }
/********************************************************************************************************* ** 函数名称: __inetPingRecv ** 功能描述: 接收 ping 包 ** 输 入 : iSock socket ** usSeqRecv 需要判断的 seq ** piHL 接收的 hop limit ** 输 出 : ERROR ** 全局变量: ** 调用模块: *********************************************************************************************************/ static INT __inetPing6Recv (INT iSock, UINT16 usSeqRecv, INT *piHL) { CHAR cBuffer[512]; INT iCnt = 20; /* 默认最多接收的数据包数 */ REGISTER ssize_t sstLen; INT iAddLen = sizeof(struct sockaddr_in6); struct sockaddr_in6 sockaddrin6From; struct ip6_hdr *ip6hdrFrom; struct icmp6_echo_hdr *icmp6hdrFrom; u8_t nexth; INT hlen; INT totalhlen = 0; u8_t *pucData; *piHL = 0; while ((sstLen = recvfrom(iSock, cBuffer, sizeof(cBuffer), 0, (struct sockaddr *)&sockaddrin6From, (socklen_t *)&iAddLen)) > 0) { if (sstLen >= (sizeof(struct ip6_hdr) + sizeof(struct icmp6_echo_hdr))) { ip6hdrFrom = (struct ip6_hdr *)cBuffer; hlen = IP6_HLEN; totalhlen = IP6_HLEN; nexth = IP6H_NEXTH(ip6hdrFrom); *piHL = IP6H_HOPLIM(ip6hdrFrom); pucData = (u8_t *)cBuffer; pucData += IP6_HLEN; while (nexth != IP6_NEXTH_NONE) { switch (nexth) { case IP6_NEXTH_HOPBYHOP: case IP6_NEXTH_DESTOPTS: case IP6_NEXTH_ROUTING: nexth = *pucData; hlen = 8 * (1 + *(pucData + 1)); totalhlen += hlen; pucData += hlen; break; case IP6_NEXTH_FRAGMENT: nexth = *pucData; hlen = 8; totalhlen += hlen; pucData += hlen; break; default: goto __hdrlen_cal_ok; break; } } __hdrlen_cal_ok: icmp6hdrFrom = (struct icmp6_echo_hdr *)(cBuffer + totalhlen); if ((icmp6hdrFrom->id == 0xAFAF) && (icmp6hdrFrom->seqno == htons(usSeqRecv))) { return (ERROR_NONE); } } iCnt--; /* 接收到错误的数据包太多 */ if (iCnt < 0) { break; /* 退出 */ } } return (PX_ERROR); }
/** * Forwards an IPv6 packet. It finds an appropriate route for the * packet, decrements the HL value of the packet, and outputs * the packet on the appropriate interface. * * @param p the packet to forward (p->payload points to IP header) * @param iphdr the IPv6 header of the input packet * @param inp the netif on which this packet was received * @return -1 if packet is to be dropped, 0 if there's no route, 1 if forwarded */ static int ip6_forward(struct pbuf *p, struct ip6_hdr *iphdr, struct netif *inp) { enum { FWD_DROP = -1, FWD_PROXY = 0, FWD_FORWARDED = 1 }; struct netif *netif; /* do not forward link-local addresses */ if (ip6_addr_islinklocal(ip6_current_dest_addr())) { LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not forwarding link-local address.\n")); IP6_STATS_INC(ip6.rterr); IP6_STATS_INC(ip6.drop); return FWD_DROP; } /* Find network interface where to forward this IP packet to. */ netif = ip6_route_fwd(ip6_current_dest_addr()); if (netif == NULL) { LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", IP6_ADDR_BLOCK1(ip6_current_dest_addr()), IP6_ADDR_BLOCK2(ip6_current_dest_addr()), IP6_ADDR_BLOCK3(ip6_current_dest_addr()), IP6_ADDR_BLOCK4(ip6_current_dest_addr()), IP6_ADDR_BLOCK5(ip6_current_dest_addr()), IP6_ADDR_BLOCK6(ip6_current_dest_addr()), IP6_ADDR_BLOCK7(ip6_current_dest_addr()), IP6_ADDR_BLOCK8(ip6_current_dest_addr()))); #if LWIP_CONNECTION_PROXY return FWD_PROXY; #else /* !LWIP_CONNECTION_PROXY */ #if LWIP_ICMP6 /* Don't send ICMP messages in response to ICMP messages */ if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { icmp6_dest_unreach(p, ICMP6_DUR_NO_ROUTE); } #endif /* LWIP_ICMP6 */ IP6_STATS_INC(ip6.rterr); IP6_STATS_INC(ip6.drop); return FWD_DROP; #endif /* !LWIP_CONNECTION_PROXY */ } #if LWIP_CONNECTION_PROXY /* The packet is for a destination on a directly connected network. * Check for addresses in that address space that proxy wants to * remap (e.g. to host loopback address/es) and hand it off to * proxy */ if (netif != netif_default && proxy_ip6_divert_hook != NULL && (*proxy_ip6_divert_hook)(netif, ip6_current_dest_addr())) { return FWD_PROXY; } #endif /* LWIP_CONNECTION_PROXY */ /* Do not forward packets onto the same network interface on which * they arrived. */ if (netif == inp) { LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not bouncing packets back on incoming interface.\n")); IP6_STATS_INC(ip6.rterr); IP6_STATS_INC(ip6.drop); return FWD_DROP; } /* decrement HL */ IP6H_HOPLIM_SET(iphdr, IP6H_HOPLIM(iphdr) - 1); /* send ICMP6 if HL == 0 */ if (IP6H_HOPLIM(iphdr) == 0) { #if LWIP_ICMP6 /* Don't send ICMP messages in response to ICMP messages */ if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { icmp6_time_exceeded(p, ICMP6_TE_HL); } #endif /* LWIP_ICMP6 */ IP6_STATS_INC(ip6.drop); return FWD_DROP; } if (netif->mtu && (p->tot_len > netif->mtu)) { #if LWIP_ICMP6 /* Don't send ICMP messages in response to ICMP messages */ if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { icmp6_packet_too_big(p, netif->mtu); } #endif /* LWIP_ICMP6 */ IP6_STATS_INC(ip6.drop); return FWD_DROP; } LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: forwarding packet to %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", IP6_ADDR_BLOCK1(ip6_current_dest_addr()), IP6_ADDR_BLOCK2(ip6_current_dest_addr()), IP6_ADDR_BLOCK3(ip6_current_dest_addr()), IP6_ADDR_BLOCK4(ip6_current_dest_addr()), IP6_ADDR_BLOCK5(ip6_current_dest_addr()), IP6_ADDR_BLOCK6(ip6_current_dest_addr()), IP6_ADDR_BLOCK7(ip6_current_dest_addr()), IP6_ADDR_BLOCK8(ip6_current_dest_addr()))); /* transmit pbuf on chosen interface */ netif->output_ip6(netif, p, ip6_current_dest_addr()); IP6_STATS_INC(ip6.fw); IP6_STATS_INC(ip6.xmit); return FWD_FORWARDED; }