xref: /csrg-svn/sys/netinet/ip_icmp.c (revision 18373)
1*18373Skarels /*	ip_icmp.c	6.9	85/03/18	*/
24785Swnj 
317059Sbloom #include "param.h"
417059Sbloom #include "systm.h"
517059Sbloom #include "mbuf.h"
617059Sbloom #include "protosw.h"
717059Sbloom #include "socket.h"
817059Sbloom #include "time.h"
917059Sbloom #include "kernel.h"
108694Sroot 
118694Sroot #include "../net/route.h"
12*18373Skarels #include "../net/if.h"
1310891Ssam 
1417059Sbloom #include "in.h"
1517059Sbloom #include "in_systm.h"
16*18373Skarels #include "in_var.h"
1717059Sbloom #include "ip.h"
1817059Sbloom #include "ip_icmp.h"
1917059Sbloom #include "icmp_var.h"
204785Swnj 
2115027Smckusick #ifdef ICMPPRINTFS
224785Swnj /*
234785Swnj  * ICMP routines: error generation, receive packet processing, and
244785Swnj  * routines to turnaround packets back to the originator, and
254785Swnj  * host table maintenance routines.
264785Swnj  */
276608Ssam int	icmpprintfs = 0;
2815027Smckusick #endif
294785Swnj 
304785Swnj /*
316583Ssam  * Generate an error packet of type error
326583Ssam  * in response to bad packet ip.
334785Swnj  */
344785Swnj icmp_error(oip, type, code)
354785Swnj 	struct ip *oip;
3612764Ssam 	int type, code;
374785Swnj {
386583Ssam 	register unsigned oiplen = oip->ip_hl << 2;
396583Ssam 	register struct icmp *icp;
404785Swnj 	struct mbuf *m;
414785Swnj 	struct ip *nip;
424785Swnj 
4315027Smckusick #ifdef ICMPPRINTFS
446590Ssam 	if (icmpprintfs)
456590Ssam 		printf("icmp_error(%x, %d, %d)\n", oip, type, code);
4615027Smckusick #endif
4711532Ssam 	icmpstat.icps_error++;
484785Swnj 	/*
494785Swnj 	 * Make sure that the old IP packet had 8 bytes of data to return;
504785Swnj 	 * if not, don't bother.  Also don't EVER error if the old
514785Swnj 	 * packet protocol was ICMP.
524785Swnj 	 */
5311532Ssam 	if (oip->ip_len < 8) {
5411532Ssam 		icmpstat.icps_oldshort++;
554785Swnj 		goto free;
5611532Ssam 	}
5711532Ssam 	if (oip->ip_p == IPPROTO_ICMP) {
5811532Ssam 		icmpstat.icps_oldicmp++;
5911532Ssam 		goto free;
6011532Ssam 	}
614785Swnj 
624785Swnj 	/*
636583Ssam 	 * First, formulate icmp message
644785Swnj 	 */
659640Ssam 	m = m_get(M_DONTWAIT, MT_HEADER);
6611532Ssam 	if (m == NULL)
674785Swnj 		goto free;
686583Ssam 	m->m_len = oiplen + 8 + ICMP_MINLEN;
696583Ssam 	m->m_off = MMAXOFF - m->m_len;
706583Ssam 	icp = mtod(m, struct icmp *);
7112764Ssam 	if ((u_int)type > ICMP_IREQREPLY)
7211532Ssam 		panic("icmp_error");
7311532Ssam 	icmpstat.icps_outhist[type]++;
744785Swnj 	icp->icmp_type = type;
756583Ssam 	icp->icmp_void = 0;
764785Swnj 	if (type == ICMP_PARAMPROB) {
774785Swnj 		icp->icmp_pptr = code;
786583Ssam 		code = 0;
796583Ssam 	}
806583Ssam 	icp->icmp_code = code;
814801Swnj 	bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, oiplen + 8);
826590Ssam 	nip = &icp->icmp_ip;
836590Ssam 	nip->ip_len += oiplen;
846590Ssam 	nip->ip_len = htons((u_short)nip->ip_len);
854785Swnj 
864785Swnj 	/*
876583Ssam 	 * Now, copy old ip header in front of icmp
886583Ssam 	 * message.  This allows us to reuse any source
896583Ssam 	 * routing info present.
904785Swnj 	 */
916583Ssam 	m->m_off -= oiplen;
926583Ssam 	nip = mtod(m, struct ip *);
936583Ssam 	bcopy((caddr_t)oip, (caddr_t)nip, oiplen);
946583Ssam 	nip->ip_len = m->m_len + oiplen;
956583Ssam 	nip->ip_p = IPPROTO_ICMP;
966583Ssam 	/* icmp_send adds ip header to m_off and m_len, so we deduct here */
976583Ssam 	m->m_off += oiplen;
984801Swnj 	icmp_reflect(nip);
994785Swnj 
1006485Swnj free:
1014785Swnj 	m_freem(dtom(oip));
1024785Swnj }
1034785Swnj 
1046583Ssam static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP };
1056583Ssam static struct sockaddr_in icmpsrc = { AF_INET };
1066583Ssam static struct sockaddr_in icmpdst = { AF_INET };
1076583Ssam 
1084785Swnj /*
1094801Swnj  * Process a received ICMP message.
1104785Swnj  */
1114785Swnj icmp_input(m)
1124785Swnj 	struct mbuf *m;
1134785Swnj {
1144801Swnj 	register struct icmp *icp;
1154801Swnj 	register struct ip *ip = mtod(m, struct ip *);
1169185Ssam 	int icmplen = ip->ip_len, hlen = ip->ip_hl << 2;
11716171Skarels 	register int i;
11816171Skarels 	int (*ctlfunc)(), code;
1195172Swnj 	extern u_char ip_protox[];
120*18373Skarels 	extern struct in_addr in_makeaddr();
1214785Swnj 
1224785Swnj 	/*
1234785Swnj 	 * Locate icmp structure in mbuf, and check
1244785Swnj 	 * that not corrupted and of at least minimum length.
1254785Swnj 	 */
12615027Smckusick #ifdef ICMPPRINTFS
1276590Ssam 	if (icmpprintfs)
1286590Ssam 		printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen);
12915027Smckusick #endif
13015913Skarels 	if (icmplen < ICMP_MINLEN) {
13111532Ssam 		icmpstat.icps_tooshort++;
1326583Ssam 		goto free;
13311532Ssam 	}
13416171Skarels 	/* THIS LENGTH CHECK STILL MISSES ANY IP OPTIONS IN ICMP_IP */
13516171Skarels 	i = MIN(icmplen, ICMP_ADVLENMIN + hlen);
13616171Skarels  	if ((m->m_off > MMAXOFF || m->m_len < i) &&
13716171Skarels  		(m = m_pullup(m, i)) == 0)  {
13815831Skarels 		icmpstat.icps_tooshort++;
13915831Skarels 		return;
14015831Skarels 	}
14116171Skarels  	ip = mtod(m, struct ip *);
1424785Swnj 	m->m_len -= hlen;
1434785Swnj 	m->m_off += hlen;
1446583Ssam 	icp = mtod(m, struct icmp *);
14516171Skarels 	if (in_cksum(m, icmplen)) {
14611532Ssam 		icmpstat.icps_checksum++;
1474801Swnj 		goto free;
1486583Ssam 	}
1494785Swnj 
15015027Smckusick #ifdef ICMPPRINTFS
1514785Swnj 	/*
1524785Swnj 	 * Message type specific processing.
1534785Swnj 	 */
1546590Ssam 	if (icmpprintfs)
1556590Ssam 		printf("icmp_input, type %d code %d\n", icp->icmp_type,
15615027Smckusick 		    icp->icmp_code);
15715027Smckusick #endif
15811532Ssam 	if (icp->icmp_type > ICMP_IREQREPLY)
15911532Ssam 		goto free;
16011532Ssam 	icmpstat.icps_inhist[icp->icmp_type]++;
16115027Smckusick 	code = icp->icmp_code;
16211532Ssam 	switch (icp->icmp_type) {
1634785Swnj 
1644785Swnj 	case ICMP_UNREACH:
16515027Smckusick 		if (code > 5)
16615027Smckusick 			goto badcode;
16715027Smckusick 		code += PRC_UNREACH_NET;
16815027Smckusick 		goto deliver;
16915027Smckusick 
1704785Swnj 	case ICMP_TIMXCEED:
17115027Smckusick 		if (code > 1)
17215027Smckusick 			goto badcode;
17315027Smckusick 		code += PRC_TIMXCEED_INTRANS;
17415027Smckusick 		goto deliver;
17515027Smckusick 
1764785Swnj 	case ICMP_PARAMPROB:
17715027Smckusick 		if (code)
17815027Smckusick 			goto badcode;
17915027Smckusick 		code = PRC_PARAMPROB;
18015027Smckusick 		goto deliver;
18115027Smckusick 
1824785Swnj 	case ICMP_SOURCEQUENCH:
18315027Smckusick 		if (code)
18415027Smckusick 			goto badcode;
18515027Smckusick 		code = PRC_QUENCH;
18615027Smckusick 	deliver:
1874785Swnj 		/*
18815027Smckusick 		 * Problem with datagram; advise higher level routines.
1894785Swnj 		 */
1908637Sroot 		icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len);
19111532Ssam 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
19211532Ssam 			icmpstat.icps_badlen++;
1934801Swnj 			goto free;
19411532Ssam 		}
19515027Smckusick #ifdef ICMPPRINTFS
1966590Ssam 		if (icmpprintfs)
1976590Ssam 			printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
19815027Smckusick #endif
1999030Sroot 		if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
20015027Smckusick 			(*ctlfunc)(code, (caddr_t)icp);
2014785Swnj 		goto free;
2024785Swnj 
20315027Smckusick 	badcode:
20415027Smckusick 		icmpstat.icps_badcode++;
20515027Smckusick 		goto free;
20615027Smckusick 
2074785Swnj 	case ICMP_ECHO:
2084785Swnj 		icp->icmp_type = ICMP_ECHOREPLY;
2094785Swnj 		goto reflect;
2104785Swnj 
2114785Swnj 	case ICMP_TSTAMP:
21211532Ssam 		if (icmplen < ICMP_TSLEN) {
21311532Ssam 			icmpstat.icps_badlen++;
2144801Swnj 			goto free;
21511532Ssam 		}
2164785Swnj 		icp->icmp_type = ICMP_TSTAMPREPLY;
2174923Swnj 		icp->icmp_rtime = iptime();
2184785Swnj 		icp->icmp_ttime = icp->icmp_rtime;	/* bogus, do later! */
2194785Swnj 		goto reflect;
2204785Swnj 
2214785Swnj 	case ICMP_IREQ:
222*18373Skarels #define	satosin(sa)	((struct sockaddr_in *)(sa))
223*18373Skarels 		if (in_netof(ip->ip_src) == 0)
224*18373Skarels 			ip->ip_src = in_makeaddr(
225*18373Skarels 			    in_netof(satosin(&in_ifaddr->ia_addr)->sin_addr),
226*18373Skarels 			    in_lnaof(ip->ip_src));
227*18373Skarels 		icp->icmp_type = ICMP_IREQREPLY;
2284785Swnj 		goto reflect;
2294785Swnj 
23011549Ssam 	case ICMP_REDIRECT:
23111532Ssam 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
23211532Ssam 			icmpstat.icps_badlen++;
2334801Swnj 			goto free;
23411532Ssam 		}
23511549Ssam 		/*
23611549Ssam 		 * Short circuit routing redirects to force
23711549Ssam 		 * immediate change in the kernel's routing
23811549Ssam 		 * tables.  The message is also handed to anyone
23911549Ssam 		 * listening on a raw socket (e.g. the routing
24017046Skarels 		 * daemon for use in updating its tables).
24111549Ssam 		 */
24215831Skarels 		icmpdst.sin_addr = icp->icmp_gwaddr;
24317046Skarels 		if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) {
24417046Skarels 			icmpsrc.sin_addr =
245*18373Skarels 			 in_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY);
24617046Skarels 			rtredirect((struct sockaddr *)&icmpsrc,
24717046Skarels 			  (struct sockaddr *)&icmpdst, RTF_GATEWAY);
24817358Skarels 			ip_ctlinput(PRC_REDIRECT_NET, (caddr_t)icp);
24917046Skarels 		} else {
25017046Skarels 			icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
25117046Skarels 			rtredirect((struct sockaddr *)&icmpsrc,
25217046Skarels 			  (struct sockaddr *)&icmpdst, RTF_GATEWAY | RTF_HOST);
25317358Skarels 			ip_ctlinput(PRC_REDIRECT_HOST, (caddr_t)icp);
25417046Skarels 		}
25515831Skarels 		/* FALL THROUGH */
25615831Skarels 
25715831Skarels 	case ICMP_ECHOREPLY:
25815831Skarels 	case ICMP_TSTAMPREPLY:
25915831Skarels 	case ICMP_IREQREPLY:
2606583Ssam 		icmpsrc.sin_addr = ip->ip_src;
2616583Ssam 		icmpdst.sin_addr = ip->ip_dst;
2626583Ssam 		raw_input(dtom(icp), &icmproto, (struct sockaddr *)&icmpsrc,
2636583Ssam 		  (struct sockaddr *)&icmpdst);
26412165Ssam 		return;
2654785Swnj 
2664785Swnj 	default:
2674785Swnj 		goto free;
2684785Swnj 	}
2694785Swnj reflect:
27011228Ssam 	ip->ip_len += hlen;		/* since ip_input deducts this */
27111532Ssam 	icmpstat.icps_reflect++;
2724785Swnj 	icmp_reflect(ip);
2739185Ssam 	return;
2744785Swnj free:
2754785Swnj 	m_freem(dtom(ip));
2764785Swnj }
2774785Swnj 
2784785Swnj /*
2794785Swnj  * Reflect the ip packet back to the source
2806583Ssam  * TODO: rearrange ip source routing options.
2814785Swnj  */
2824785Swnj icmp_reflect(ip)
2834785Swnj 	struct ip *ip;
2844785Swnj {
285*18373Skarels 	register struct in_addr t;
286*18373Skarels 	register struct in_ifaddr *ia;
2874785Swnj 
2886583Ssam 	t = ip->ip_dst;
289*18373Skarels 	if (t.s_addr == INADDR_ANY)
290*18373Skarels 		t = IA_SIN(in_ifaddr)->sin_addr;
291*18373Skarels 	else for (ia = in_ifaddr; ia; ia = ia->ia_next)
292*18373Skarels 		if (t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr &&
293*18373Skarels 		    (ia->ia_ifp->if_flags & IFF_BROADCAST)) {
294*18373Skarels 			t = IA_SIN(ia)->sin_addr;
295*18373Skarels 			break;
296*18373Skarels 		}
2976583Ssam 	ip->ip_dst = ip->ip_src;
2986583Ssam 	ip->ip_src = t;
2994785Swnj 	icmp_send(ip);
3004785Swnj }
3014785Swnj 
3024785Swnj /*
3036583Ssam  * Send an icmp packet back to the ip level,
3046583Ssam  * after supplying a checksum.
3054785Swnj  */
3064907Swnj icmp_send(ip)
3074785Swnj 	struct ip *ip;
3084785Swnj {
3099185Ssam 	register int hlen;
3106583Ssam 	register struct icmp *icp;
3119185Ssam 	register struct mbuf *m;
3126583Ssam 
3139185Ssam 	m = dtom(ip);
3149185Ssam 	hlen = ip->ip_hl << 2;
3156583Ssam 	icp = mtod(m, struct icmp *);
3166583Ssam 	icp->icmp_cksum = 0;
3176583Ssam 	icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
3186583Ssam 	m->m_off -= hlen;
3196583Ssam 	m->m_len += hlen;
32015027Smckusick #ifdef ICMPPRINTFS
3216590Ssam 	if (icmpprintfs)
3226590Ssam 		printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src);
32315027Smckusick #endif
3248637Sroot 	(void) ip_output(m, (struct mbuf *)0, (struct route *)0, 0);
3254785Swnj }
3264785Swnj 
3274907Swnj n_time
3284923Swnj iptime()
3294801Swnj {
3304907Swnj 	int s = spl6();
3314967Swnj 	u_long t;
3324801Swnj 
3338171Sroot 	t = (time.tv_sec % (24*60*60)) * 1000 + time.tv_usec / 1000;
3344907Swnj 	splx(s);
3354907Swnj 	return (htonl(t));
3364801Swnj }
337