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