|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by the University of
16: * California, Berkeley and its contributors.
17: * 4. Neither the name of the University nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: *
33: * @(#)ip_icmp.c 7.15 (Berkeley) 4/20/91
34: */
35:
36: #include "param.h"
37: #include "systm.h"
38: #include "malloc.h"
39: #include "mbuf.h"
40: #include "protosw.h"
41: #include "socket.h"
42: #include "time.h"
43: #include "kernel.h"
44:
45: #include "../net/route.h"
46: #include "../net/if.h"
47:
48: #include "in.h"
49: #include "in_systm.h"
50: #include "in_var.h"
51: #include "ip.h"
52: #include "ip_icmp.h"
53: #include "icmp_var.h"
54:
55: /*
56: * ICMP routines: error generation, receive packet processing, and
57: * routines to turnaround packets back to the originator, and
58: * host table maintenance routines.
59: */
60: #ifdef ICMPPRINTFS
61: int icmpprintfs = 0;
62: #endif
63:
64: extern struct protosw inetsw[];
65:
66: /*
67: * Generate an error packet of type error
68: * in response to bad packet ip.
69: */
70: /*VARARGS3*/
71: icmp_error(n, type, code, dest)
72: struct mbuf *n;
73: int type, code;
74: struct in_addr dest;
75: {
76: register struct ip *oip = mtod(n, struct ip *), *nip;
77: register unsigned oiplen = oip->ip_hl << 2;
78: register struct icmp *icp;
79: register struct mbuf *m;
80: unsigned icmplen;
81:
82: #ifdef ICMPPRINTFS
83: if (icmpprintfs)
84: printf("icmp_error(%x, %d, %d)\n", oip, type, code);
85: #endif
86: if (type != ICMP_REDIRECT)
87: icmpstat.icps_error++;
88: /*
89: * Don't send error if not the first fragment of message.
90: * Don't error if the old packet protocol was ICMP
91: * error message, only known informational types.
92: */
93: if (oip->ip_off &~ (IP_MF|IP_DF))
94: goto freeit;
95: if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
96: n->m_len >= oiplen + ICMP_MINLEN &&
97: !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) {
98: icmpstat.icps_oldicmp++;
99: goto freeit;
100: }
101:
102: /*
103: * First, formulate icmp message
104: */
105: m = m_gethdr(M_DONTWAIT, MT_HEADER);
106: if (m == NULL)
107: goto freeit;
108: icmplen = oiplen + min(8, oip->ip_len);
109: m->m_len = icmplen + ICMP_MINLEN;
110: MH_ALIGN(m, m->m_len);
111: icp = mtod(m, struct icmp *);
112: if ((u_int)type > ICMP_MAXTYPE)
113: panic("icmp_error");
114: icmpstat.icps_outhist[type]++;
115: icp->icmp_type = type;
116: if (type == ICMP_REDIRECT)
117: icp->icmp_gwaddr = dest;
118: else
119: icp->icmp_void = 0;
120: if (type == ICMP_PARAMPROB) {
121: icp->icmp_pptr = code;
122: code = 0;
123: }
124: icp->icmp_code = code;
125: bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen);
126: nip = &icp->icmp_ip;
127: nip->ip_len = htons((u_short)(nip->ip_len + oiplen));
128:
129: /*
130: * Now, copy old ip header (without options)
131: * in front of icmp message.
132: */
133: if (m->m_data - sizeof(struct ip) < m->m_pktdat)
134: panic("icmp len");
135: m->m_data -= sizeof(struct ip);
136: m->m_len += sizeof(struct ip);
137: m->m_pkthdr.len = m->m_len;
138: m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
139: nip = mtod(m, struct ip *);
140: bcopy((caddr_t)oip, (caddr_t)nip, oiplen);
141: nip->ip_len = m->m_len;
142: nip->ip_hl = sizeof(struct ip) >> 2;
143: nip->ip_p = IPPROTO_ICMP;
144: icmp_reflect(m);
145:
146: freeit:
147: m_freem(n);
148: }
149:
150: static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP };
151: static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };
152: static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET };
153: static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET };
154: struct sockaddr_in icmpmask = { 8, 0 };
155: struct in_ifaddr *ifptoia();
156:
157: /*
158: * Process a received ICMP message.
159: */
160: icmp_input(m, hlen)
161: register struct mbuf *m;
162: int hlen;
163: {
164: register struct icmp *icp;
165: register struct ip *ip = mtod(m, struct ip *);
166: int icmplen = ip->ip_len;
167: register int i;
168: struct in_ifaddr *ia;
169: int (*ctlfunc)(), code;
170: extern u_char ip_protox[];
171: extern struct in_addr in_makeaddr();
172:
173: /*
174: * Locate icmp structure in mbuf, and check
175: * that not corrupted and of at least minimum length.
176: */
177: #ifdef ICMPPRINTFS
178: if (icmpprintfs)
179: printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen);
180: #endif
181: if (icmplen < ICMP_MINLEN) {
182: icmpstat.icps_tooshort++;
183: goto freeit;
184: }
185: i = hlen + MIN(icmplen, ICMP_ADVLENMIN);
186: if (m->m_len < i && (m = m_pullup(m, i)) == 0) {
187: icmpstat.icps_tooshort++;
188: return;
189: }
190: ip = mtod(m, struct ip *);
191: m->m_len -= hlen;
192: m->m_data += hlen;
193: icp = mtod(m, struct icmp *);
194: if (in_cksum(m, icmplen)) {
195: icmpstat.icps_checksum++;
196: goto freeit;
197: }
198: m->m_len += hlen;
199: m->m_data -= hlen;
200:
201: #ifdef ICMPPRINTFS
202: /*
203: * Message type specific processing.
204: */
205: if (icmpprintfs)
206: printf("icmp_input, type %d code %d\n", icp->icmp_type,
207: icp->icmp_code);
208: #endif
209: if (icp->icmp_type > ICMP_MAXTYPE)
210: goto raw;
211: icmpstat.icps_inhist[icp->icmp_type]++;
212: code = icp->icmp_code;
213: switch (icp->icmp_type) {
214:
215: case ICMP_UNREACH:
216: if (code > 5)
217: goto badcode;
218: code += PRC_UNREACH_NET;
219: goto deliver;
220:
221: case ICMP_TIMXCEED:
222: if (code > 1)
223: goto badcode;
224: code += PRC_TIMXCEED_INTRANS;
225: goto deliver;
226:
227: case ICMP_PARAMPROB:
228: if (code)
229: goto badcode;
230: code = PRC_PARAMPROB;
231: goto deliver;
232:
233: case ICMP_SOURCEQUENCH:
234: if (code)
235: goto badcode;
236: code = PRC_QUENCH;
237: deliver:
238: /*
239: * Problem with datagram; advise higher level routines.
240: */
241: if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
242: icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {
243: icmpstat.icps_badlen++;
244: goto freeit;
245: }
246: NTOHS(icp->icmp_ip.ip_len);
247: #ifdef ICMPPRINTFS
248: if (icmpprintfs)
249: printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
250: #endif
251: icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
252: if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
253: (*ctlfunc)(code, (struct sockaddr *)&icmpsrc,
254: (caddr_t) &icp->icmp_ip);
255: break;
256:
257: badcode:
258: icmpstat.icps_badcode++;
259: break;
260:
261: case ICMP_ECHO:
262: icp->icmp_type = ICMP_ECHOREPLY;
263: goto reflect;
264:
265: case ICMP_TSTAMP:
266: if (icmplen < ICMP_TSLEN) {
267: icmpstat.icps_badlen++;
268: break;
269: }
270: icp->icmp_type = ICMP_TSTAMPREPLY;
271: icp->icmp_rtime = iptime();
272: icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */
273: goto reflect;
274:
275: case ICMP_IREQ:
276: #define satosin(sa) ((struct sockaddr_in *)(sa))
277: if (in_netof(ip->ip_src) == 0 &&
278: (ia = ifptoia(m->m_pkthdr.rcvif)))
279: ip->ip_src = in_makeaddr(in_netof(IA_SIN(ia)->sin_addr),
280: in_lnaof(ip->ip_src));
281: icp->icmp_type = ICMP_IREQREPLY;
282: goto reflect;
283:
284: case ICMP_MASKREQ:
285: if (icmplen < ICMP_MASKLEN ||
286: (ia = ifptoia(m->m_pkthdr.rcvif)) == 0)
287: break;
288: icp->icmp_type = ICMP_MASKREPLY;
289: icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
290: if (ip->ip_src.s_addr == 0) {
291: if (ia->ia_ifp->if_flags & IFF_BROADCAST)
292: ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr;
293: else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
294: ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
295: }
296: reflect:
297: ip->ip_len += hlen; /* since ip_input deducts this */
298: icmpstat.icps_reflect++;
299: icmpstat.icps_outhist[icp->icmp_type]++;
300: icmp_reflect(m);
301: return;
302:
303: case ICMP_REDIRECT:
304: if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
305: icmpstat.icps_badlen++;
306: break;
307: }
308: /*
309: * Short circuit routing redirects to force
310: * immediate change in the kernel's routing
311: * tables. The message is also handed to anyone
312: * listening on a raw socket (e.g. the routing
313: * daemon for use in updating its tables).
314: */
315: icmpgw.sin_addr = ip->ip_src;
316: icmpdst.sin_addr = icp->icmp_gwaddr;
317: #ifdef ICMPPRINTFS
318: if (icmpprintfs)
319: printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst,
320: icp->icmp_gwaddr);
321: #endif
322: if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) {
323: u_long in_netof();
324: icmpsrc.sin_addr =
325: in_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY);
326: in_sockmaskof(icp->icmp_ip.ip_dst, &icmpmask);
327: rtredirect((struct sockaddr *)&icmpsrc,
328: (struct sockaddr *)&icmpdst,
329: (struct sockaddr *)&icmpmask, RTF_GATEWAY,
330: (struct sockaddr *)&icmpgw, (struct rtentry **)0);
331: icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
332: pfctlinput(PRC_REDIRECT_NET,
333: (struct sockaddr *)&icmpsrc);
334: } else {
335: icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
336: rtredirect((struct sockaddr *)&icmpsrc,
337: (struct sockaddr *)&icmpdst,
338: (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,
339: (struct sockaddr *)&icmpgw, (struct rtentry **)0);
340: pfctlinput(PRC_REDIRECT_HOST,
341: (struct sockaddr *)&icmpsrc);
342: }
343: break;
344:
345: /*
346: * No kernel processing for the following;
347: * just fall through to send to raw listener.
348: */
349: case ICMP_ECHOREPLY:
350: case ICMP_TSTAMPREPLY:
351: case ICMP_IREQREPLY:
352: case ICMP_MASKREPLY:
353: default:
354: break;
355: }
356:
357: raw:
358: icmpsrc.sin_addr = ip->ip_src;
359: icmpdst.sin_addr = ip->ip_dst;
360: (void) raw_input(m, &icmproto, (struct sockaddr *)&icmpsrc,
361: (struct sockaddr *)&icmpdst);
362: return;
363:
364: freeit:
365: m_freem(m);
366: }
367:
368: /*
369: * Reflect the ip packet back to the source
370: */
371: icmp_reflect(m)
372: struct mbuf *m;
373: {
374: register struct ip *ip = mtod(m, struct ip *);
375: register struct in_ifaddr *ia;
376: struct in_addr t;
377: struct mbuf *opts = 0, *ip_srcroute();
378: int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
379:
380: t = ip->ip_dst;
381: ip->ip_dst = ip->ip_src;
382: /*
383: * If the incoming packet was addressed directly to us,
384: * use dst as the src for the reply. Otherwise (broadcast
385: * or anonymous), use the address which corresponds
386: * to the incoming interface.
387: */
388: for (ia = in_ifaddr; ia; ia = ia->ia_next) {
389: if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr)
390: break;
391: if ((ia->ia_ifp->if_flags & IFF_BROADCAST) &&
392: t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr)
393: break;
394: }
395: if (ia == (struct in_ifaddr *)0)
396: ia = ifptoia(m->m_pkthdr.rcvif);
397: if (ia == (struct in_ifaddr *)0)
398: ia = in_ifaddr;
399: t = IA_SIN(ia)->sin_addr;
400: ip->ip_src = t;
401: ip->ip_ttl = MAXTTL;
402:
403: if (optlen > 0) {
404: register u_char *cp;
405: int opt, cnt;
406: u_int len;
407:
408: /*
409: * Retrieve any source routing from the incoming packet;
410: * add on any record-route or timestamp options.
411: */
412: cp = (u_char *) (ip + 1);
413: if ((opts = ip_srcroute()) == 0 &&
414: (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) {
415: opts->m_len = sizeof(struct in_addr);
416: mtod(opts, struct in_addr *)->s_addr = 0;
417: }
418: if (opts) {
419: #ifdef ICMPPRINTFS
420: if (icmpprintfs)
421: printf("icmp_reflect optlen %d rt %d => ",
422: optlen, opts->m_len);
423: #endif
424: for (cnt = optlen; cnt > 0; cnt -= len, cp += len) {
425: opt = cp[IPOPT_OPTVAL];
426: if (opt == IPOPT_EOL)
427: break;
428: if (opt == IPOPT_NOP)
429: len = 1;
430: else {
431: len = cp[IPOPT_OLEN];
432: if (len <= 0 || len > cnt)
433: break;
434: }
435: /*
436: * should check for overflow, but it "can't happen"
437: */
438: if (opt == IPOPT_RR || opt == IPOPT_TS) {
439: bcopy((caddr_t)cp,
440: mtod(opts, caddr_t) + opts->m_len, len);
441: opts->m_len += len;
442: }
443: }
444: if (opts->m_len % 4 != 0) {
445: *(mtod(opts, caddr_t) + opts->m_len) = IPOPT_EOL;
446: opts->m_len++;
447: }
448: #ifdef ICMPPRINTFS
449: if (icmpprintfs)
450: printf("%d\n", opts->m_len);
451: #endif
452: }
453: /*
454: * Now strip out original options by copying rest of first
455: * mbuf's data back, and adjust the IP length.
456: */
457: ip->ip_len -= optlen;
458: ip->ip_hl = sizeof(struct ip) >> 2;
459: m->m_len -= optlen;
460: if (m->m_flags & M_PKTHDR)
461: m->m_pkthdr.len -= optlen;
462: optlen += sizeof(struct ip);
463: bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1),
464: (unsigned)(m->m_len - sizeof(struct ip)));
465: }
466: icmp_send(m, opts);
467: if (opts)
468: (void)m_free(opts);
469: }
470:
471: struct in_ifaddr *
472: ifptoia(ifp)
473: struct ifnet *ifp;
474: {
475: register struct in_ifaddr *ia;
476:
477: for (ia = in_ifaddr; ia; ia = ia->ia_next)
478: if (ia->ia_ifp == ifp)
479: return (ia);
480: return ((struct in_ifaddr *)0);
481: }
482:
483: /*
484: * Send an icmp packet back to the ip level,
485: * after supplying a checksum.
486: */
487: icmp_send(m, opts)
488: register struct mbuf *m;
489: struct mbuf *opts;
490: {
491: register struct ip *ip = mtod(m, struct ip *);
492: register int hlen;
493: register struct icmp *icp;
494:
495: hlen = ip->ip_hl << 2;
496: m->m_data += hlen;
497: m->m_len -= hlen;
498: icp = mtod(m, struct icmp *);
499: icp->icmp_cksum = 0;
500: icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
501: m->m_data -= hlen;
502: m->m_len += hlen;
503: #ifdef ICMPPRINTFS
504: if (icmpprintfs)
505: printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src);
506: #endif
507: (void) ip_output(m, opts, (struct route *)0, 0);
508: }
509:
510: n_time
511: iptime()
512: {
513: struct timeval atv;
514: u_long t;
515:
516: microtime(&atv);
517: t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
518: return (htonl(t));
519: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.