📄 ip_icmp.c
字号:
icmp_input(m, hlen) register struct mbuf *m; int hlen;{ register struct icmp *icp; register struct ip *ip = mtod(m, struct ip *); int icmplen = ip->ip_len; register int i; struct in_ifaddr *ia; int (*ctlfunc) (int, struct sockaddr *, struct ip *); int code;#ifndef VIRTUAL_STACK extern u_char ip_protox[];#endif /* VIRTUAL_STACK */#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_NOTICE event */ WV_NET_EVENT_0 (NET_CORE_EVENT, WV_NET_NOTICE, 7, 8, WV_NETEVENT_ICMPIN_START, WV_NET_RECV)#endif /* INCLUDE_WVNET */#endif /* * Locate icmp structure in mbuf, and check * that not corrupted and of at least minimum length. */#ifdef ICMPPRINTFS if (icmpprintfs) printf("icmp_input from %x to %x, len %d\n", ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr), icmplen);#endif if (icmplen < ICMP_MINLEN) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_CRITICAL event */ WV_NET_ADDRIN_EVENT_0 (NET_CORE_EVENT, WV_NET_CRITICAL, 9, 3, ip->ip_src.s_addr, ip->ip_dst.s_addr, WV_NETEVENT_ICMPIN_SHORTMSG, WV_NET_RECV)#endif /* INCLUDE_WVNET */#endif#ifdef VIRTUAL_STACK _icmpstat.icps_tooshort++;#else icmpstat.icps_tooshort++;#endif /* VIRTUAL_STACK */ goto freeit; } i = hlen + min(icmplen, ICMP_ADVLENMIN); if (m->m_len < i && (m = m_pullup(m, i)) == 0) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_CRITICAL event */ WV_NET_ADDRIN_EVENT_0 (NET_CORE_EVENT, WV_NET_CRITICAL, 9, 3, ip->ip_src.s_addr, ip->ip_dst.s_addr, WV_NETEVENT_ICMPIN_SHORTMSG, WV_NET_RECV)#endif /* INCLUDE_WVNET */#endif#ifdef VIRTUAL_STACK _icmpstat.icps_tooshort++;#else icmpstat.icps_tooshort++;#endif /* VIRTUAL_STACK */ return; } ip = mtod(m, struct ip *); m->m_len -= hlen; m->m_data += hlen; icp = mtod(m, struct icmp *); if (in_cksum(m, icmplen)) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_CRITICAL event */ WV_NET_ADDRIN_EVENT_0 (NET_CORE_EVENT, WV_NET_CRITICAL, 10, 4, ip->ip_src.s_addr, ip->ip_dst.s_addr, WV_NETEVENT_ICMPIN_BADSUM, WV_NET_RECV)#endif /* INCLUDE_WVNET */#endif#ifdef VIRTUAL_STACK _icmpstat.icps_checksum++;#else icmpstat.icps_checksum++;#endif /* VIRTUAL_STACK */ goto freeit; } m->m_len += hlen; m->m_data -= hlen;#ifdef ICMPPRINTFS /* * Message type specific processing. */ if (icmpprintfs) printf("icmp_input, type %d code %d\n", icp->icmp_type, icp->icmp_code);#endif if (icp->icmp_type > ICMP_MAXTYPE) goto raw;#ifdef VIRTUAL_STACK _icmpstat.icps_inhist[icp->icmp_type]++;#else icmpstat.icps_inhist[icp->icmp_type]++;#endif /* VIRTUAL_STACK */ code = icp->icmp_code; switch (icp->icmp_type) { case ICMP_UNREACH: switch (code) { case ICMP_UNREACH_NET: case ICMP_UNREACH_HOST: case ICMP_UNREACH_PROTOCOL: case ICMP_UNREACH_PORT: case ICMP_UNREACH_SRCFAIL: code += PRC_UNREACH_NET; break; case ICMP_UNREACH_NEEDFRAG: code = PRC_MSGSIZE; break; case ICMP_UNREACH_NET_UNKNOWN: case ICMP_UNREACH_NET_PROHIB: case ICMP_UNREACH_TOSNET: code = PRC_UNREACH_NET; break; case ICMP_UNREACH_HOST_UNKNOWN: case ICMP_UNREACH_ISOLATED: case ICMP_UNREACH_HOST_PROHIB: case ICMP_UNREACH_TOSHOST: code = PRC_UNREACH_HOST; break; default: goto badcode; } goto deliver; case ICMP_TIMXCEED: if (code > 1) goto badcode; code += PRC_TIMXCEED_INTRANS; goto deliver; case ICMP_PARAMPROB: if (code > 1) goto badcode; code = PRC_PARAMPROB; goto deliver; case ICMP_SOURCEQUENCH: if (code) goto badcode; code = PRC_QUENCH; deliver: /* * Problem with datagram; advise higher level routines. */ if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_CRITICAL event */ WV_NET_ADDRIN_EVENT_2 (NET_CORE_EVENT, WV_NET_CRITICAL, 11, 5, ip->ip_src.s_addr, ip->ip_dst.s_addr, WV_NETEVENT_ICMPIN_BADLEN, WV_NET_RECV, icmplen, 4 * icp->icmp_ip.ip_hl)#endif /* INCLUDE_WVNET */#endif#ifdef VIRTUAL_STACK _icmpstat.icps_badlen++;#else icmpstat.icps_badlen++;#endif /* VIRTUAL_STACK */ goto freeit; } NTOHS(icp->icmp_ip.ip_len);#ifdef ICMPPRINTFS if (icmpprintfs) printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);#endif icmpsrc.sin_addr = icp->icmp_ip.ip_dst; /* Path MTU discovery: get new MTU value. */ if (code == PRC_MSGSIZE) { i = ntohs (icp->icmp_nextmtu); ip_next_mtu ( (struct sockaddr *)&icmpsrc, i); } if ((ctlfunc = (FUNCPTR)(inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput))) (*ctlfunc)(code, (struct sockaddr *)&icmpsrc, &icp->icmp_ip); break; badcode:#ifdef VIRTUAL_STACK _icmpstat.icps_badcode++;#else icmpstat.icps_badcode++;#endif /* VIRTUAL_STACK */ break; case ICMP_ECHO: icp->icmp_type = ICMP_ECHOREPLY; goto reflect; case ICMP_TSTAMP: if (icmplen < ICMP_TSLEN) {#ifdef VIRTUAL_STACK _icmpstat.icps_badlen++;#else icmpstat.icps_badlen++;#endif /* VIRTUAL_STACK */ break; } icp->icmp_type = ICMP_TSTAMPREPLY; icp->icmp_rtime = iptime(); icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ goto reflect; case ICMP_MASKREQ:#define satosin(sa) ((struct sockaddr_in *)(sa)) if (icmpmaskrepl == 0) break; /* * We are not able to respond with all ones broadcast * unless we receive it over a point-to-point interface. */ if (icmplen < ICMP_MASKLEN) break; switch (ip->ip_dst.s_addr) { case INADDR_BROADCAST: case INADDR_ANY: icmpdst.sin_addr = ip->ip_src; break; default: icmpdst.sin_addr = ip->ip_dst; } ia = (struct in_ifaddr *)ifaof_ifpforaddr( (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif); if (ia == 0 || ia->ia_ifp == 0) break; icp->icmp_type = ICMP_MASKREPLY; icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr; if (ip->ip_src.s_addr == 0) { if (ia->ia_ifp->if_flags & IFF_BROADCAST) ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr; else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT) ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr; }reflect: ip->ip_len += hlen; /* since ip_input deducts this */#ifdef VIRTUAL_STACK _icmpstat.icps_reflect++; _icmpstat.icps_outhist[icp->icmp_type]++;#else icmpstat.icps_reflect++; icmpstat.icps_outhist[icp->icmp_type]++;#endif /* VIRTUAL_STACK */ icmp_reflect(m); return; case ICMP_REDIRECT: if (code > 3) goto badcode; if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {#ifdef VIRTUAL_STACK _icmpstat.icps_badlen++;#else icmpstat.icps_badlen++;#endif /* VIRTUAL_STACK */ break; } /* * Short circuit routing redirects to force * immediate change in the kernel's routing * tables. The message is also handed to anyone * listening on a raw socket (e.g. the routing * daemon for use in updating its tables). */ icmpgw.sin_addr = ip->ip_src; icmpdst.sin_addr = icp->icmp_gwaddr;#ifdef ICMPPRINTFS if (icmpprintfs) printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst, icp->icmp_gwaddr);#endif icmpsrc.sin_addr = icp->icmp_ip.ip_dst; rtredirect((struct sockaddr *)&icmpsrc, (struct sockaddr *)&icmpdst, (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST, (struct sockaddr *)&icmpgw, (struct rtentry **)0); pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc); break; /* * No kernel processing for the following; * just fall through to send to raw listener. */ case ICMP_ECHOREPLY: case ICMP_ROUTERADVERT: case ICMP_ROUTERSOLICIT: case ICMP_TSTAMPREPLY: case ICMP_IREQREPLY: case ICMP_MASKREPLY: default: break; }raw: rip_input(m); return;freeit: m_freem(m); return;}/* * Reflect the ip packet back to the source */static voidicmp_reflect(m) struct mbuf *m;{ register struct ip *ip = mtod(m, struct ip *); register struct in_ifaddr *ia; struct in_addr t; struct mbuf *opts = 0, *ip_srcroute(); int optlen = (ip->ip_hl << 2) - sizeof(struct ip);#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_NOTICE event */ WV_NET_EVENT_1 (NET_CORE_EVENT, WV_NET_NOTICE, 8, 9, WV_NETEVENT_ICMPREFLECT_START, WV_NET_SEND, ip->ip_src.s_addr)#endif /* INCLUDE_WVNET */#endif if (!in_canforward(ip->ip_src) && ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) != (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) { m_freem(m); /* Bad return address */ goto done; /* Ip_output() will check for broadcast */ } t = ip->ip_dst; ip->ip_dst = ip->ip_src; /* * If the incoming packet was addressed directly to us, * use dst as the src for the reply. Otherwise (broadcast * or anonymous), use the address which corresponds * to the incoming interface. */#ifdef VIRTUAL_STACK for (ia = _in_ifaddr; ia; ia = ia->ia_next) {#else for (ia = in_ifaddr; ia; ia = ia->ia_next) {#endif /* VIRTUAL_STACK */ if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr) break; if (ia->ia_ifp && (ia->ia_ifp->if_flags & IFF_BROADCAST) && t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr) break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -