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