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