📄 ip_icmp.c
字号:
#ifndef lintstatic char *sccsid = "@(#)ip_icmp.c 4.2 (ULTRIX) 7/17/90";#endif lint/************************************************************************ * * * Copyright (c) 1985 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//************************************************************************ * Modification History * * 14-11-89 Ursula Sinkewicz * Removed lk_in_ifaddr and lk_ifnet to coincide with * slip changes. * * 10-17-89 Uttam Shikarpur * * Made MAXTTL a writeable entity, by introducing maxttl * * * * 28-May-89 Matt Thomas * * Fix panic on ICMP_INFOTYPE messages. Also fix option * * probnlems in icmp_reflect() * * * * 27-Mar-89 U. Sinkewicz * Lowered ipl of lk_rtentry, lk_ifnet, lk_in_ifaddr, as per * lp changes made 3/16/89. * * 3-Mar-89 U. Sinkewicz * Put new directory layout into smp file. * * 15-Jan-88 lp * Merge of final 43BSD changes. * * Larry Cohen - 09/16/85 * * Add 43bsd alpha tape changes for subnet routing * * * ************************************************************************//* * Copyright (c) 1982, 1986 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. * * ip_icmp.c 7.6 (Berkeley) 8/31/87 */#include "../h/param.h"#include "../h/systm.h"#include "../h/mbuf.h"#include "../h/protosw.h"#include "../h/socket.h"#include "../h/time.h"#include "../h/kernel.h"#include "../h/smp_lock.h"#include "../net/net/route.h"#include "../net/net/if.h"#include "../net/netinet/in.h"#include "../net/netinet/in_systm.h"#include "../net/netinet/in_var.h"#include "../net/netinet/ip.h"#include "../net/netinet/ip_icmp.h"#include "../net/netinet/icmp_var.h"#ifdef ICMPPRINTFS/* * ICMP routines: error generation, receive packet processing, and * routines to turnaround packets back to the originator, and * host table maintenance routines. */int icmpprintfs = 0;#endif/* initialize maxttl to MAXTTL, defined in ip.h */int maxttl = MAXTTL;/* * Generate an error packet of type error * in response to bad packet ip. *//*VARARGS4*/icmp_error(oip, type, code, ifp, dest) struct ip *oip; int type, code; struct ifnet *ifp; struct in_addr dest;{ register unsigned oiplen = oip->ip_hl << 2; register struct icmp *icp; struct mbuf *m; struct ip *nip; unsigned icmplen;#ifdef ICMPPRINTFS if (icmpprintfs) printf("icmp_error(%x, %d, %d)\n", oip, type, code);#endif if (type != ICMP_REDIRECT) icmpstat.icps_error++; /* * Don't send error if not the first fragment of message. * Don't error if the old packet protocol was ICMP * error message, only known informational types. */ if (oip->ip_off &~ (IP_MF|IP_DF)) goto free; /* * Pullup what we need into a single mbuf since the first * mbuf could contain only the IP header, which results * in a panic when attempting to point beyond end of data * when we execute the ICMP_INFOTYPE macro or copy the old * header. */ m = dtom(oip); /* Always need to see the stuff we're sending back */ icmplen = oiplen + MIN(8, oip->ip_len); if (oip->ip_p == IPPROTO_ICMP) /* need to see first word (or less) of orginal ICMP */ icmplen = MAX(icmplen, (oiplen + sizeof(long))); if (m->m_len < icmplen) { m = m_pullup(m, icmplen); if (m == 0) { return; } oip = mtod(m, struct ip *); } if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT && !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) { icmpstat.icps_oldicmp++; goto free; } /* * First, formulate icmp message */ m = m_get(M_DONTWAIT, MT_DATA); if (m == NULL) goto free; icmplen = oiplen + MIN(8, oip->ip_len); m->m_len = icmplen + ICMP_MINLEN; m->m_off = MMAXOFF - m->m_len; icp = mtod(m, struct icmp *); if ((u_int)type > ICMP_MAXTYPE) panic("icmp_error"); icmpstat.icps_outhist[type]++; icp->icmp_type = type; if (type == ICMP_REDIRECT) icp->icmp_gwaddr = dest; else icp->icmp_void = 0; if (type == ICMP_PARAMPROB) { icp->icmp_pptr = code; code = 0; } icp->icmp_code = code; bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen); nip = &icp->icmp_ip; nip->ip_len += oiplen; nip->ip_len = htons((u_short)nip->ip_len); /* * Now, copy old ip header in front of icmp message. */ if (m->m_len + oiplen > MLEN) oiplen = sizeof(struct ip); if (m->m_len + oiplen > MLEN) panic("icmp len"); m->m_off -= oiplen; m->m_len += oiplen; nip = mtod(m, struct ip *); bcopy((caddr_t)oip, (caddr_t)nip, oiplen); nip->ip_len = m->m_len; nip->ip_p = IPPROTO_ICMP; nip->ip_off = 0; /* keep DF flag for return packet */ icmp_reflect(nip, ifp);free: m_freem(dtom(oip));}static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP };static struct sockaddr_in icmpsrc = { AF_INET };static struct sockaddr_in icmpdst = { AF_INET };static struct sockaddr_in icmpgw = { AF_INET };struct in_ifaddr *ifptoia();/* * Process a received ICMP message. */icmp_input(m, ifp) register struct mbuf *m; struct ifnet *ifp;{ register struct icmp *icp; register struct ip *ip = mtod(m, struct ip *); int icmplen = ip->ip_len, hlen = ip->ip_hl << 2; register int i; struct in_ifaddr *ia; int (*ctlfunc)(), code; extern u_char ip_protox[]; extern struct in_addr in_makeaddr(); /* * 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, len %d\n", ip->ip_src, icmplen);#endif if (icmplen < ICMP_MINLEN) { icmpstat.icps_tooshort++; goto free; } i = hlen + MIN(icmplen, ICMP_ADVLENMIN); if ((m->m_off > MMAXOFF || m->m_len < i) && (m = m_pullup(m, i)) == 0) { icmpstat.icps_tooshort++; return; } ip = mtod(m, struct ip *); m->m_len -= hlen; m->m_off += hlen; icp = mtod(m, struct icmp *); if (in_cksum(m, icmplen)) { icmpstat.icps_checksum++; goto free; } m->m_len += hlen; m->m_off -= 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; icmpstat.icps_inhist[icp->icmp_type]++; code = icp->icmp_code; switch (icp->icmp_type) { case ICMP_UNREACH: if (code > 5) goto badcode; code += PRC_UNREACH_NET; goto deliver; case ICMP_TIMXCEED: if (code > 1) goto badcode; code += PRC_TIMXCEED_INTRANS; goto deliver; case ICMP_PARAMPROB: if (code) 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. */ icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len); if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) { icmpstat.icps_badlen++; goto free; }#ifdef ICMPPRINTFS if (icmpprintfs) printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);#endif icmpsrc.sin_addr = icp->icmp_ip.ip_dst; if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput) (*ctlfunc)(code, (struct sockaddr *)&icmpsrc); break; badcode: icmpstat.icps_badcode++; break; case ICMP_ECHO: icp->icmp_type = ICMP_ECHOREPLY; goto reflect; case ICMP_TSTAMP: if (icmplen < ICMP_TSLEN) { icmpstat.icps_badlen++; break; } icp->icmp_type = ICMP_TSTAMPREPLY; icp->icmp_rtime = iptime(); icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ goto reflect; case ICMP_IREQ:#define satosin(sa) ((struct sockaddr_in *)(sa)) if (in_netof(ip->ip_src) == 0 && (ia = ifptoia(ifp))){ ip->ip_src = in_makeaddr(in_netof(IA_SIN(ia)->sin_addr), in_lnaof(ip->ip_src)); } icp->icmp_type = ICMP_IREQREPLY; goto reflect; case ICMP_MASKREQ: if (icmplen < ICMP_MASKLEN || (ia = ifptoia(ifp)) == 0){ break; } icp->icmp_type = ICMP_MASKREPLY; icp->icmp_mask = htonl(ia->ia_subnetmask); 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 */ icmpstat.icps_reflect++; icmpstat.icps_outhist[icp->icmp_type]++; icmp_reflect(ip, ifp); return; case ICMP_REDIRECT: if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) { icmpstat.icps_badlen++; 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 if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) { icmpsrc.sin_addr = in_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY); rtredirect((struct sockaddr *)&icmpsrc, (struct sockaddr *)&icmpdst, RTF_GATEWAY, (struct sockaddr *)&icmpgw); icmpsrc.sin_addr = icp->icmp_ip.ip_dst; pfctlinput(PRC_REDIRECT_NET, (struct sockaddr *)&icmpsrc); } else { icmpsrc.sin_addr = icp->icmp_ip.ip_dst; rtredirect((struct sockaddr *)&icmpsrc, (struct sockaddr *)&icmpdst, RTF_GATEWAY | RTF_HOST, (struct sockaddr *)&icmpgw); 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_TSTAMPREPLY: case ICMP_IREQREPLY: case ICMP_MASKREPLY: default: break; }raw: icmpsrc.sin_addr = ip->ip_src; icmpdst.sin_addr = ip->ip_dst; raw_input(m, &icmproto, (struct sockaddr *)&icmpsrc, (struct sockaddr *)&icmpdst); return;free: m_freem(m);}/* * Reflect the ip packet back to the source */icmp_reflect(ip, ifp) register struct ip *ip; struct ifnet *ifp;{ register struct in_ifaddr *ia; struct in_addr t; struct mbuf *opts = 0, *ip_srcroute(); int optlen = (ip->ip_hl << 2) - sizeof(struct ip); 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. */ for (ia = in_ifaddr; ia; ia = ia->ia_next) { if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr) break; if ((ia->ia_ifp->if_flags & IFF_BROADCAST) && t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr) break; } if (ia == (struct in_ifaddr *)0) ia = ifptoia(ifp); if (ia == (struct in_ifaddr *)0){ ia = in_ifaddr; } t = IA_SIN(ia)->sin_addr; ip->ip_src = t; ip->ip_ttl = maxttl; ip->ip_off = 0; /* clear DF flag */ if (optlen > 0) { /* * Retrieve any source routing from the incoming packet * and imerge in the other non-routing options. Adjust * the IP length. */ opts = ip_srcroute(); if (!opts && (opts = m_get(M_DONTWAIT, MT_SOOPTS))) opts->m_len = 0; ip_stripoptions(ip, opts); ip->ip_len -= optlen; } icmp_send(ip, opts); if (opts) (void)m_free(opts);}struct in_ifaddr *ifptoia(ifp) struct ifnet *ifp;{ register struct in_ifaddr *ia; for (ia = in_ifaddr; ia; ia = ia->ia_next) if (ia->ia_ifp == ifp){ return (ia); } return ((struct in_ifaddr *)0);}/* * Send an icmp packet back to the ip level, * after supplying a checksum. */icmp_send(ip, opts) register struct ip *ip; struct mbuf *opts;{ register int hlen; register struct icmp *icp; register struct mbuf *m; m = dtom(ip); hlen = ip->ip_hl << 2; m->m_off += hlen; m->m_len -= hlen; icp = mtod(m, struct icmp *); icp->icmp_cksum = 0; icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); m->m_off -= hlen; m->m_len += hlen;#ifdef ICMPPRINTFS if (icmpprintfs) printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src);#endif (void) ip_output(m, opts, (struct route *)0, 0, 0);}n_timeiptime(){ struct timeval atv; u_long t; microtime(&atv); t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000; return (htonl(t));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -