xref: /original-bsd/sys/netinet/ip_icmp.c (revision 00986467)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)ip_icmp.c	7.8 (Berkeley) 06/29/88
18  */
19 
20 #include "param.h"
21 #include "systm.h"
22 #include "mbuf.h"
23 #include "protosw.h"
24 #include "socket.h"
25 #include "time.h"
26 #include "kernel.h"
27 
28 #include "../net/route.h"
29 #include "../net/if.h"
30 
31 #include "in.h"
32 #include "in_systm.h"
33 #include "in_var.h"
34 #include "ip.h"
35 #include "ip_icmp.h"
36 #include "icmp_var.h"
37 
38 #ifdef ICMPPRINTFS
39 /*
40  * ICMP routines: error generation, receive packet processing, and
41  * routines to turnaround packets back to the originator, and
42  * host table maintenance routines.
43  */
44 int	icmpprintfs = 0;
45 #endif
46 
47 /*
48  * Generate an error packet of type error
49  * in response to bad packet ip.
50  */
51 /*VARARGS4*/
52 icmp_error(oip, type, code, ifp, dest)
53 	struct ip *oip;
54 	int type, code;
55 	struct ifnet *ifp;
56 	struct in_addr dest;
57 {
58 	register unsigned oiplen = oip->ip_hl << 2;
59 	register struct icmp *icp;
60 	struct mbuf *m;
61 	struct ip *nip;
62 	unsigned icmplen;
63 
64 #ifdef ICMPPRINTFS
65 	if (icmpprintfs)
66 		printf("icmp_error(%x, %d, %d)\n", oip, type, code);
67 #endif
68 	if (type != ICMP_REDIRECT)
69 		icmpstat.icps_error++;
70 	/*
71 	 * Don't send error if not the first fragment of message.
72 	 * Don't error if the old packet protocol was ICMP
73 	 * error message, only known informational types.
74 	 */
75 	if (oip->ip_off &~ (IP_MF|IP_DF))
76 		goto free;
77 	if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
78 	  !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) {
79 		icmpstat.icps_oldicmp++;
80 		goto free;
81 	}
82 
83 	/*
84 	 * First, formulate icmp message
85 	 */
86 	m = m_get(M_DONTWAIT, MT_HEADER);
87 	if (m == NULL)
88 		goto free;
89 	icmplen = oiplen + MIN(8, oip->ip_len);
90 	m->m_len = icmplen + ICMP_MINLEN;
91 	m->m_off = MMAXOFF - m->m_len;
92 	icp = mtod(m, struct icmp *);
93 	if ((u_int)type > ICMP_MAXTYPE)
94 		panic("icmp_error");
95 	icmpstat.icps_outhist[type]++;
96 	icp->icmp_type = type;
97 	if (type == ICMP_REDIRECT)
98 		icp->icmp_gwaddr = dest;
99 	else
100 		icp->icmp_void = 0;
101 	if (type == ICMP_PARAMPROB) {
102 		icp->icmp_pptr = code;
103 		code = 0;
104 	}
105 	icp->icmp_code = code;
106 	bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen);
107 	nip = &icp->icmp_ip;
108 	nip->ip_len += oiplen;
109 	nip->ip_len = htons((u_short)nip->ip_len);
110 
111 	/*
112 	 * Now, copy old ip header in front of icmp message.
113 	 */
114 	if (m->m_len + oiplen > MLEN)
115 		oiplen = sizeof(struct ip);
116 	if (m->m_len + oiplen > MLEN)
117 		panic("icmp len");
118 	m->m_off -= oiplen;
119 	m->m_len += oiplen;
120 	nip = mtod(m, struct ip *);
121 	bcopy((caddr_t)oip, (caddr_t)nip, oiplen);
122 	nip->ip_len = m->m_len;
123 	nip->ip_p = IPPROTO_ICMP;
124 	icmp_reflect(nip, ifp);
125 
126 free:
127 	m_freem(dtom(oip));
128 }
129 
130 static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP };
131 static struct sockaddr_in icmpsrc = { AF_INET };
132 static struct sockaddr_in icmpdst = { AF_INET };
133 static struct sockaddr_in icmpgw = { AF_INET };
134 struct in_ifaddr *ifptoia();
135 
136 /*
137  * Process a received ICMP message.
138  */
139 icmp_input(m, ifp)
140 	register struct mbuf *m;
141 	struct ifnet *ifp;
142 {
143 	register struct icmp *icp;
144 	register struct ip *ip = mtod(m, struct ip *);
145 	int icmplen = ip->ip_len, hlen = ip->ip_hl << 2;
146 	register int i;
147 	struct in_ifaddr *ia;
148 	int (*ctlfunc)(), code;
149 	extern u_char ip_protox[];
150 	extern struct in_addr in_makeaddr();
151 
152 	/*
153 	 * Locate icmp structure in mbuf, and check
154 	 * that not corrupted and of at least minimum length.
155 	 */
156 #ifdef ICMPPRINTFS
157 	if (icmpprintfs)
158 		printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen);
159 #endif
160 	if (icmplen < ICMP_MINLEN) {
161 		icmpstat.icps_tooshort++;
162 		goto free;
163 	}
164 	i = hlen + MIN(icmplen, ICMP_ADVLENMIN);
165  	if ((m->m_off > MMAXOFF || m->m_len < i) &&
166  		(m = m_pullup(m, i)) == 0)  {
167 		icmpstat.icps_tooshort++;
168 		return;
169 	}
170  	ip = mtod(m, struct ip *);
171 	m->m_len -= hlen;
172 	m->m_off += hlen;
173 	icp = mtod(m, struct icmp *);
174 	if (in_cksum(m, icmplen)) {
175 		icmpstat.icps_checksum++;
176 		goto free;
177 	}
178 	m->m_len += hlen;
179 	m->m_off -= hlen;
180 
181 #ifdef ICMPPRINTFS
182 	/*
183 	 * Message type specific processing.
184 	 */
185 	if (icmpprintfs)
186 		printf("icmp_input, type %d code %d\n", icp->icmp_type,
187 		    icp->icmp_code);
188 #endif
189 	if (icp->icmp_type > ICMP_MAXTYPE)
190 		goto raw;
191 	icmpstat.icps_inhist[icp->icmp_type]++;
192 	code = icp->icmp_code;
193 	switch (icp->icmp_type) {
194 
195 	case ICMP_UNREACH:
196 		if (code > 5)
197 			goto badcode;
198 		code += PRC_UNREACH_NET;
199 		goto deliver;
200 
201 	case ICMP_TIMXCEED:
202 		if (code > 1)
203 			goto badcode;
204 		code += PRC_TIMXCEED_INTRANS;
205 		goto deliver;
206 
207 	case ICMP_PARAMPROB:
208 		if (code)
209 			goto badcode;
210 		code = PRC_PARAMPROB;
211 		goto deliver;
212 
213 	case ICMP_SOURCEQUENCH:
214 		if (code)
215 			goto badcode;
216 		code = PRC_QUENCH;
217 	deliver:
218 		/*
219 		 * Problem with datagram; advise higher level routines.
220 		 */
221 		icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len);
222 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
223 			icmpstat.icps_badlen++;
224 			goto free;
225 		}
226 #ifdef ICMPPRINTFS
227 		if (icmpprintfs)
228 			printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
229 #endif
230 		icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
231 		if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
232 			(*ctlfunc)(code, (struct sockaddr *)&icmpsrc);
233 		break;
234 
235 	badcode:
236 		icmpstat.icps_badcode++;
237 		break;
238 
239 	case ICMP_ECHO:
240 		icp->icmp_type = ICMP_ECHOREPLY;
241 		goto reflect;
242 
243 	case ICMP_TSTAMP:
244 		if (icmplen < ICMP_TSLEN) {
245 			icmpstat.icps_badlen++;
246 			break;
247 		}
248 		icp->icmp_type = ICMP_TSTAMPREPLY;
249 		icp->icmp_rtime = iptime();
250 		icp->icmp_ttime = icp->icmp_rtime;	/* bogus, do later! */
251 		goto reflect;
252 
253 	case ICMP_IREQ:
254 #define	satosin(sa)	((struct sockaddr_in *)(sa))
255 		if (in_netof(ip->ip_src) == 0 && (ia = ifptoia(ifp)))
256 			ip->ip_src = in_makeaddr(in_netof(IA_SIN(ia)->sin_addr),
257 			    in_lnaof(ip->ip_src));
258 		icp->icmp_type = ICMP_IREQREPLY;
259 		goto reflect;
260 
261 	case ICMP_MASKREQ:
262 		if (icmplen < ICMP_MASKLEN || (ia = ifptoia(ifp)) == 0)
263 			break;
264 		icp->icmp_type = ICMP_MASKREPLY;
265 		icp->icmp_mask = htonl(ia->ia_subnetmask);
266 		if (ip->ip_src.s_addr == 0) {
267 			if (ia->ia_ifp->if_flags & IFF_BROADCAST)
268 			    ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr;
269 			else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
270 			    ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
271 		}
272 reflect:
273 		ip->ip_len += hlen;	/* since ip_input deducts this */
274 		icmpstat.icps_reflect++;
275 		icmpstat.icps_outhist[icp->icmp_type]++;
276 		icmp_reflect(ip, ifp);
277 		return;
278 
279 	case ICMP_REDIRECT:
280 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
281 			icmpstat.icps_badlen++;
282 			break;
283 		}
284 		/*
285 		 * Short circuit routing redirects to force
286 		 * immediate change in the kernel's routing
287 		 * tables.  The message is also handed to anyone
288 		 * listening on a raw socket (e.g. the routing
289 		 * daemon for use in updating its tables).
290 		 */
291 		icmpgw.sin_addr = ip->ip_src;
292 		icmpdst.sin_addr = icp->icmp_gwaddr;
293 #ifdef	ICMPPRINTFS
294 		if (icmpprintfs)
295 			printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst,
296 				icp->icmp_gwaddr);
297 #endif
298 		if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) {
299 			icmpsrc.sin_addr =
300 			 in_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY);
301 			rtredirect((struct sockaddr *)&icmpsrc,
302 			  (struct sockaddr *)&icmpdst, RTF_GATEWAY,
303 			  (struct sockaddr *)&icmpgw);
304 			icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
305 			pfctlinput(PRC_REDIRECT_NET,
306 			  (struct sockaddr *)&icmpsrc);
307 		} else {
308 			icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
309 			rtredirect((struct sockaddr *)&icmpsrc,
310 			  (struct sockaddr *)&icmpdst, RTF_GATEWAY | RTF_HOST,
311 			  (struct sockaddr *)&icmpgw);
312 			pfctlinput(PRC_REDIRECT_HOST,
313 			  (struct sockaddr *)&icmpsrc);
314 		}
315 		break;
316 
317 	/*
318 	 * No kernel processing for the following;
319 	 * just fall through to send to raw listener.
320 	 */
321 	case ICMP_ECHOREPLY:
322 	case ICMP_TSTAMPREPLY:
323 	case ICMP_IREQREPLY:
324 	case ICMP_MASKREPLY:
325 	default:
326 		break;
327 	}
328 
329 raw:
330 	icmpsrc.sin_addr = ip->ip_src;
331 	icmpdst.sin_addr = ip->ip_dst;
332 	raw_input(m, &icmproto, (struct sockaddr *)&icmpsrc,
333 	    (struct sockaddr *)&icmpdst);
334 	return;
335 
336 free:
337 	m_freem(m);
338 }
339 
340 /*
341  * Reflect the ip packet back to the source
342  */
343 icmp_reflect(ip, ifp)
344 	register struct ip *ip;
345 	struct ifnet *ifp;
346 {
347 	register struct in_ifaddr *ia;
348 	struct in_addr t;
349 	struct mbuf *opts = 0, *ip_srcroute();
350 	int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
351 
352 	t = ip->ip_dst;
353 	ip->ip_dst = ip->ip_src;
354 	/*
355 	 * If the incoming packet was addressed directly to us,
356 	 * use dst as the src for the reply.  Otherwise (broadcast
357 	 * or anonymous), use the address which corresponds
358 	 * to the incoming interface.
359 	 */
360 	for (ia = in_ifaddr; ia; ia = ia->ia_next) {
361 		if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr)
362 			break;
363 		if ((ia->ia_ifp->if_flags & IFF_BROADCAST) &&
364 		    t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr)
365 			break;
366 	}
367 	if (ia == (struct in_ifaddr *)0)
368 		ia = ifptoia(ifp);
369 	if (ia == (struct in_ifaddr *)0)
370 		ia = in_ifaddr;
371 	t = IA_SIN(ia)->sin_addr;
372 	ip->ip_src = t;
373 	ip->ip_ttl = MAXTTL;
374 
375 	if (optlen > 0) {
376 		/*
377 		 * Retrieve any source routing from the incoming packet
378 		 * and strip out other options.  Adjust the IP length.
379 		 */
380 		opts = ip_srcroute();
381 		ip->ip_len -= optlen;
382 		ip_stripoptions(ip, (struct mbuf *)0);
383 	}
384 	icmp_send(ip, opts);
385 	if (opts)
386 		(void)m_free(opts);
387 }
388 
389 struct in_ifaddr *
390 ifptoia(ifp)
391 	struct ifnet *ifp;
392 {
393 	register struct in_ifaddr *ia;
394 
395 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
396 		if (ia->ia_ifp == ifp)
397 			return (ia);
398 	return ((struct in_ifaddr *)0);
399 }
400 
401 /*
402  * Send an icmp packet back to the ip level,
403  * after supplying a checksum.
404  */
405 icmp_send(ip, opts)
406 	register struct ip *ip;
407 	struct mbuf *opts;
408 {
409 	register int hlen;
410 	register struct icmp *icp;
411 	register struct mbuf *m;
412 
413 	m = dtom(ip);
414 	hlen = ip->ip_hl << 2;
415 	m->m_off += hlen;
416 	m->m_len -= hlen;
417 	icp = mtod(m, struct icmp *);
418 	icp->icmp_cksum = 0;
419 	icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
420 	m->m_off -= hlen;
421 	m->m_len += hlen;
422 #ifdef ICMPPRINTFS
423 	if (icmpprintfs)
424 		printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src);
425 #endif
426 	(void) ip_output(m, opts, (struct route *)0, 0);
427 }
428 
429 n_time
430 iptime()
431 {
432 	struct timeval atv;
433 	u_long t;
434 
435 	microtime(&atv);
436 	t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
437 	return (htonl(t));
438 }
439