|
|
1.1 root 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) 6/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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.