ip_icmp.c revision 1.38.2.2 1 1.38.2.2 bouyer /* $NetBSD: ip_icmp.c,v 1.38.2.2 2001/02/11 19:17:14 bouyer Exp $ */
2 1.37 itojun
3 1.37 itojun /*
4 1.37 itojun * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 1.37 itojun * All rights reserved.
6 1.37 itojun *
7 1.37 itojun * Redistribution and use in source and binary forms, with or without
8 1.37 itojun * modification, are permitted provided that the following conditions
9 1.37 itojun * are met:
10 1.37 itojun * 1. Redistributions of source code must retain the above copyright
11 1.37 itojun * notice, this list of conditions and the following disclaimer.
12 1.37 itojun * 2. Redistributions in binary form must reproduce the above copyright
13 1.37 itojun * notice, this list of conditions and the following disclaimer in the
14 1.37 itojun * documentation and/or other materials provided with the distribution.
15 1.37 itojun * 3. Neither the name of the project nor the names of its contributors
16 1.37 itojun * may be used to endorse or promote products derived from this software
17 1.37 itojun * without specific prior written permission.
18 1.37 itojun *
19 1.37 itojun * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 1.37 itojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 1.37 itojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 1.37 itojun * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 1.37 itojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 1.37 itojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 1.37 itojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 1.37 itojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 1.37 itojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 1.37 itojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 1.37 itojun * SUCH DAMAGE.
30 1.37 itojun */
31 1.10 cgd
32 1.31 thorpej /*-
33 1.38.2.1 bouyer * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
34 1.31 thorpej * All rights reserved.
35 1.31 thorpej *
36 1.31 thorpej * This code is derived from software contributed to The NetBSD Foundation
37 1.31 thorpej * by Public Access Networks Corporation ("Panix"). It was developed under
38 1.31 thorpej * contract to Panix by Eric Haszlakiewicz and Thor Lancelot Simon.
39 1.31 thorpej *
40 1.38.2.1 bouyer * This code is derived from software contributed to The NetBSD Foundation
41 1.38.2.1 bouyer * by Jason R. Thorpe of Zembu Labs, Inc.
42 1.38.2.1 bouyer *
43 1.31 thorpej * Redistribution and use in source and binary forms, with or without
44 1.31 thorpej * modification, are permitted provided that the following conditions
45 1.31 thorpej * are met:
46 1.31 thorpej * 1. Redistributions of source code must retain the above copyright
47 1.31 thorpej * notice, this list of conditions and the following disclaimer.
48 1.31 thorpej * 2. Redistributions in binary form must reproduce the above copyright
49 1.31 thorpej * notice, this list of conditions and the following disclaimer in the
50 1.31 thorpej * documentation and/or other materials provided with the distribution.
51 1.31 thorpej * 3. All advertising materials mentioning features or use of this software
52 1.31 thorpej * must display the following acknowledgement:
53 1.31 thorpej * This product includes software developed by the NetBSD
54 1.31 thorpej * Foundation, Inc. and its contributors.
55 1.31 thorpej * 4. Neither the name of The NetBSD Foundation nor the names of its
56 1.31 thorpej * contributors may be used to endorse or promote products derived
57 1.31 thorpej * from this software without specific prior written permission.
58 1.31 thorpej *
59 1.31 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
60 1.31 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
61 1.31 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
62 1.31 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
63 1.31 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
64 1.31 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
65 1.31 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
66 1.31 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
67 1.31 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
68 1.31 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
69 1.31 thorpej * POSSIBILITY OF SUCH DAMAGE.
70 1.31 thorpej */
71 1.31 thorpej
72 1.1 cgd /*
73 1.9 mycroft * Copyright (c) 1982, 1986, 1988, 1993
74 1.9 mycroft * The Regents of the University of California. All rights reserved.
75 1.1 cgd *
76 1.1 cgd * Redistribution and use in source and binary forms, with or without
77 1.1 cgd * modification, are permitted provided that the following conditions
78 1.1 cgd * are met:
79 1.1 cgd * 1. Redistributions of source code must retain the above copyright
80 1.1 cgd * notice, this list of conditions and the following disclaimer.
81 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
82 1.1 cgd * notice, this list of conditions and the following disclaimer in the
83 1.1 cgd * documentation and/or other materials provided with the distribution.
84 1.1 cgd * 3. All advertising materials mentioning features or use of this software
85 1.1 cgd * must display the following acknowledgement:
86 1.1 cgd * This product includes software developed by the University of
87 1.1 cgd * California, Berkeley and its contributors.
88 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
89 1.1 cgd * may be used to endorse or promote products derived from this software
90 1.1 cgd * without specific prior written permission.
91 1.1 cgd *
92 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
93 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
94 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
95 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
96 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
97 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
98 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
99 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
100 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
101 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
102 1.1 cgd * SUCH DAMAGE.
103 1.1 cgd *
104 1.10 cgd * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94
105 1.1 cgd */
106 1.38 thorpej
107 1.38 thorpej #include "opt_ipsec.h"
108 1.1 cgd
109 1.4 mycroft #include <sys/param.h>
110 1.4 mycroft #include <sys/systm.h>
111 1.4 mycroft #include <sys/malloc.h>
112 1.4 mycroft #include <sys/mbuf.h>
113 1.4 mycroft #include <sys/protosw.h>
114 1.4 mycroft #include <sys/socket.h>
115 1.4 mycroft #include <sys/time.h>
116 1.4 mycroft #include <sys/kernel.h>
117 1.19 christos #include <sys/proc.h>
118 1.19 christos
119 1.38.2.1 bouyer #include <uvm/uvm_extern.h>
120 1.38.2.1 bouyer
121 1.19 christos #include <sys/sysctl.h>
122 1.1 cgd
123 1.9 mycroft #include <net/if.h>
124 1.4 mycroft #include <net/route.h>
125 1.1 cgd
126 1.4 mycroft #include <netinet/in.h>
127 1.4 mycroft #include <netinet/in_systm.h>
128 1.4 mycroft #include <netinet/in_var.h>
129 1.4 mycroft #include <netinet/ip.h>
130 1.4 mycroft #include <netinet/ip_icmp.h>
131 1.19 christos #include <netinet/ip_var.h>
132 1.38.2.1 bouyer #include <netinet/in_pcb.h>
133 1.4 mycroft #include <netinet/icmp_var.h>
134 1.1 cgd
135 1.37 itojun #ifdef IPSEC
136 1.37 itojun #include <netinet6/ipsec.h>
137 1.37 itojun #include <netkey/key.h>
138 1.37 itojun #endif
139 1.37 itojun
140 1.19 christos #include <machine/stdarg.h>
141 1.19 christos
142 1.1 cgd /*
143 1.1 cgd * ICMP routines: error generation, receive packet processing, and
144 1.1 cgd * routines to turnaround packets back to the originator, and
145 1.1 cgd * host table maintenance routines.
146 1.1 cgd */
147 1.9 mycroft
148 1.9 mycroft int icmpmaskrepl = 0;
149 1.1 cgd #ifdef ICMPPRINTFS
150 1.1 cgd int icmpprintfs = 0;
151 1.1 cgd #endif
152 1.38.2.1 bouyer int icmpreturndatabytes = 8;
153 1.38.2.1 bouyer
154 1.38.2.1 bouyer /*
155 1.38.2.1 bouyer * List of callbacks to notify when Path MTU changes are made.
156 1.38.2.1 bouyer */
157 1.38.2.1 bouyer struct icmp_mtudisc_callback {
158 1.38.2.1 bouyer LIST_ENTRY(icmp_mtudisc_callback) mc_list;
159 1.38.2.1 bouyer void (*mc_func) __P((struct in_addr));
160 1.38.2.1 bouyer };
161 1.38.2.1 bouyer
162 1.38.2.1 bouyer LIST_HEAD(, icmp_mtudisc_callback) icmp_mtudisc_callbacks =
163 1.38.2.1 bouyer LIST_HEAD_INITIALIZER(&icmp_mtudisc_callbacks);
164 1.1 cgd
165 1.37 itojun #if 0
166 1.37 itojun static int ip_next_mtu __P((int, int));
167 1.37 itojun #else
168 1.37 itojun /*static*/ int ip_next_mtu __P((int, int));
169 1.37 itojun #endif
170 1.37 itojun
171 1.38.2.1 bouyer extern int icmperrppslim;
172 1.38.2.1 bouyer static int icmperrpps_count = 0;
173 1.38.2.1 bouyer static struct timeval icmperrppslim_last;
174 1.1 cgd
175 1.29 kml static void icmp_mtudisc_timeout __P((struct rtentry *, struct rttimer *));
176 1.24 kml
177 1.38.2.1 bouyer static int icmp_ratelimit __P((const struct in_addr *, const int, const int));
178 1.38.2.1 bouyer
179 1.38.2.1 bouyer /*
180 1.38.2.1 bouyer * Register a Path MTU Discovery callback.
181 1.38.2.1 bouyer */
182 1.38.2.1 bouyer void
183 1.38.2.1 bouyer icmp_mtudisc_callback_register(func)
184 1.38.2.1 bouyer void (*func) __P((struct in_addr));
185 1.38.2.1 bouyer {
186 1.38.2.1 bouyer struct icmp_mtudisc_callback *mc;
187 1.38.2.1 bouyer
188 1.38.2.1 bouyer for (mc = LIST_FIRST(&icmp_mtudisc_callbacks); mc != NULL;
189 1.38.2.1 bouyer mc = LIST_NEXT(mc, mc_list)) {
190 1.38.2.1 bouyer if (mc->mc_func == func)
191 1.38.2.1 bouyer return;
192 1.38.2.1 bouyer }
193 1.38.2.1 bouyer
194 1.38.2.1 bouyer mc = malloc(sizeof(*mc), M_PCB, M_NOWAIT);
195 1.38.2.1 bouyer if (mc == NULL)
196 1.38.2.1 bouyer panic("icmp_mtudisc_callback_register");
197 1.38.2.1 bouyer
198 1.38.2.1 bouyer mc->mc_func = func;
199 1.38.2.1 bouyer LIST_INSERT_HEAD(&icmp_mtudisc_callbacks, mc, mc_list);
200 1.38.2.1 bouyer }
201 1.38.2.1 bouyer
202 1.1 cgd /*
203 1.1 cgd * Generate an error packet of type error
204 1.1 cgd * in response to bad packet ip.
205 1.1 cgd */
206 1.6 mycroft void
207 1.9 mycroft icmp_error(n, type, code, dest, destifp)
208 1.1 cgd struct mbuf *n;
209 1.1 cgd int type, code;
210 1.9 mycroft n_long dest;
211 1.9 mycroft struct ifnet *destifp;
212 1.1 cgd {
213 1.38.2.1 bouyer struct ip *oip = mtod(n, struct ip *), *nip;
214 1.38.2.1 bouyer unsigned oiplen = oip->ip_hl << 2;
215 1.38.2.1 bouyer struct icmp *icp;
216 1.38.2.1 bouyer struct mbuf *m;
217 1.38.2.1 bouyer unsigned icmplen, mblen;
218 1.1 cgd
219 1.1 cgd #ifdef ICMPPRINTFS
220 1.1 cgd if (icmpprintfs)
221 1.22 christos printf("icmp_error(%x, %d, %d)\n", oip, type, code);
222 1.1 cgd #endif
223 1.1 cgd if (type != ICMP_REDIRECT)
224 1.1 cgd icmpstat.icps_error++;
225 1.1 cgd /*
226 1.38.2.1 bouyer * Don't send error if the original packet was encrypted.
227 1.1 cgd * Don't send error if not the first fragment of message.
228 1.1 cgd * Don't error if the old packet protocol was ICMP
229 1.1 cgd * error message, only known informational types.
230 1.1 cgd */
231 1.38.2.1 bouyer if (n->m_flags & M_DECRYPTED)
232 1.38.2.1 bouyer goto freeit;
233 1.1 cgd if (oip->ip_off &~ (IP_MF|IP_DF))
234 1.1 cgd goto freeit;
235 1.1 cgd if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
236 1.1 cgd n->m_len >= oiplen + ICMP_MINLEN &&
237 1.1 cgd !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) {
238 1.1 cgd icmpstat.icps_oldicmp++;
239 1.1 cgd goto freeit;
240 1.1 cgd }
241 1.3 hpeyerl /* Don't send error in response to a multicast or broadcast packet */
242 1.9 mycroft if (n->m_flags & (M_BCAST|M_MCAST))
243 1.3 hpeyerl goto freeit;
244 1.38.2.1 bouyer
245 1.38.2.1 bouyer /*
246 1.38.2.1 bouyer * First, do a rate limitation check.
247 1.38.2.1 bouyer */
248 1.38.2.1 bouyer if (icmp_ratelimit(&oip->ip_src, type, code)) {
249 1.38.2.1 bouyer /* XXX stat */
250 1.38.2.1 bouyer goto freeit;
251 1.38.2.1 bouyer }
252 1.38.2.1 bouyer
253 1.38.2.1 bouyer /*
254 1.38.2.1 bouyer * Now, formulate icmp message
255 1.38.2.1 bouyer */
256 1.38.2.1 bouyer icmplen = oiplen + min(icmpreturndatabytes, oip->ip_len - oiplen);
257 1.1 cgd /*
258 1.38.2.1 bouyer * Defend against mbuf chains shorter than oip->ip_len:
259 1.1 cgd */
260 1.38.2.1 bouyer mblen = 0;
261 1.38.2.1 bouyer for (m = n; m && (mblen < icmplen); m = m->m_next)
262 1.38.2.1 bouyer mblen += m->m_len;
263 1.38.2.1 bouyer icmplen = min(mblen, icmplen);
264 1.38.2.1 bouyer
265 1.38.2.1 bouyer /*
266 1.38.2.1 bouyer * As we are not required to return everything we have,
267 1.38.2.1 bouyer * we return whatever we can return at ease.
268 1.38.2.1 bouyer *
269 1.38.2.1 bouyer * Note that ICMP datagrams longer than 576 octets are out of spec
270 1.38.2.1 bouyer * according to RFC1812; the limit on icmpreturndatabytes below in
271 1.38.2.1 bouyer * icmp_sysctl will keep things below that limit.
272 1.38.2.1 bouyer */
273 1.38.2.1 bouyer
274 1.38.2.1 bouyer KASSERT(ICMP_MINLEN <= MCLBYTES);
275 1.38.2.1 bouyer
276 1.38.2.1 bouyer if (icmplen + ICMP_MINLEN > MCLBYTES)
277 1.38.2.1 bouyer icmplen = MCLBYTES - ICMP_MINLEN;
278 1.38.2.1 bouyer
279 1.1 cgd m = m_gethdr(M_DONTWAIT, MT_HEADER);
280 1.38.2.1 bouyer if (m && (icmplen + ICMP_MINLEN > MHLEN)) {
281 1.38.2.1 bouyer MCLGET(m, M_DONTWAIT);
282 1.38.2.1 bouyer if ((m->m_flags & M_EXT) == 0) {
283 1.38.2.1 bouyer m_freem(m);
284 1.38.2.1 bouyer m = NULL;
285 1.38.2.1 bouyer }
286 1.38.2.1 bouyer }
287 1.1 cgd if (m == NULL)
288 1.1 cgd goto freeit;
289 1.1 cgd m->m_len = icmplen + ICMP_MINLEN;
290 1.38.2.1 bouyer if ((m->m_flags & M_EXT) == 0)
291 1.38.2.1 bouyer MH_ALIGN(m, m->m_len);
292 1.1 cgd icp = mtod(m, struct icmp *);
293 1.1 cgd if ((u_int)type > ICMP_MAXTYPE)
294 1.1 cgd panic("icmp_error");
295 1.1 cgd icmpstat.icps_outhist[type]++;
296 1.1 cgd icp->icmp_type = type;
297 1.1 cgd if (type == ICMP_REDIRECT)
298 1.9 mycroft icp->icmp_gwaddr.s_addr = dest;
299 1.9 mycroft else {
300 1.1 cgd icp->icmp_void = 0;
301 1.9 mycroft /*
302 1.9 mycroft * The following assignments assume an overlay with the
303 1.9 mycroft * zeroed icmp_void field.
304 1.9 mycroft */
305 1.9 mycroft if (type == ICMP_PARAMPROB) {
306 1.9 mycroft icp->icmp_pptr = code;
307 1.9 mycroft code = 0;
308 1.9 mycroft } else if (type == ICMP_UNREACH &&
309 1.12 cgd code == ICMP_UNREACH_NEEDFRAG && destifp)
310 1.9 mycroft icp->icmp_nextmtu = htons(destifp->if_mtu);
311 1.1 cgd }
312 1.9 mycroft
313 1.32 thorpej HTONS(oip->ip_off);
314 1.32 thorpej HTONS(oip->ip_len);
315 1.1 cgd icp->icmp_code = code;
316 1.38.2.1 bouyer m_copydata(n, 0, icmplen, (caddr_t)&icp->icmp_ip);
317 1.1 cgd nip = &icp->icmp_ip;
318 1.1 cgd
319 1.1 cgd /*
320 1.1 cgd * Now, copy old ip header (without options)
321 1.1 cgd * in front of icmp message.
322 1.1 cgd */
323 1.1 cgd if (m->m_data - sizeof(struct ip) < m->m_pktdat)
324 1.1 cgd panic("icmp len");
325 1.1 cgd m->m_data -= sizeof(struct ip);
326 1.1 cgd m->m_len += sizeof(struct ip);
327 1.1 cgd m->m_pkthdr.len = m->m_len;
328 1.1 cgd m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
329 1.1 cgd nip = mtod(m, struct ip *);
330 1.38.2.1 bouyer /* ip_v set in ip_output */
331 1.1 cgd nip->ip_hl = sizeof(struct ip) >> 2;
332 1.9 mycroft nip->ip_tos = 0;
333 1.38.2.1 bouyer nip->ip_len = m->m_len;
334 1.38.2.1 bouyer /* ip_id set in ip_output */
335 1.38.2.1 bouyer nip->ip_off = 0;
336 1.38.2.1 bouyer /* ip_ttl set in icmp_reflect */
337 1.38.2.1 bouyer nip->ip_p = IPPROTO_ICMP;
338 1.38.2.1 bouyer nip->ip_src = oip->ip_src;
339 1.38.2.1 bouyer nip->ip_dst = oip->ip_dst;
340 1.1 cgd icmp_reflect(m);
341 1.1 cgd
342 1.1 cgd freeit:
343 1.1 cgd m_freem(n);
344 1.1 cgd }
345 1.1 cgd
346 1.1 cgd static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };
347 1.1 cgd static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET };
348 1.1 cgd static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET };
349 1.1 cgd struct sockaddr_in icmpmask = { 8, 0 };
350 1.1 cgd
351 1.1 cgd /*
352 1.1 cgd * Process a received ICMP message.
353 1.1 cgd */
354 1.6 mycroft void
355 1.19 christos #if __STDC__
356 1.19 christos icmp_input(struct mbuf *m, ...)
357 1.19 christos #else
358 1.19 christos icmp_input(m, va_alist)
359 1.19 christos struct mbuf *m;
360 1.19 christos va_dcl
361 1.19 christos #endif
362 1.1 cgd {
363 1.37 itojun int proto;
364 1.38.2.1 bouyer struct icmp *icp;
365 1.38.2.1 bouyer struct ip *ip = mtod(m, struct ip *);
366 1.34 mycroft int icmplen;
367 1.38.2.1 bouyer int i;
368 1.1 cgd struct in_ifaddr *ia;
369 1.19 christos void *(*ctlfunc) __P((int, struct sockaddr *, void *));
370 1.9 mycroft int code;
371 1.19 christos int hlen;
372 1.19 christos va_list ap;
373 1.19 christos
374 1.19 christos va_start(ap, m);
375 1.19 christos hlen = va_arg(ap, int);
376 1.37 itojun proto = va_arg(ap, int);
377 1.19 christos va_end(ap);
378 1.1 cgd
379 1.1 cgd /*
380 1.1 cgd * Locate icmp structure in mbuf, and check
381 1.1 cgd * that not corrupted and of at least minimum length.
382 1.1 cgd */
383 1.34 mycroft icmplen = ip->ip_len - hlen;
384 1.1 cgd #ifdef ICMPPRINTFS
385 1.1 cgd if (icmpprintfs)
386 1.22 christos printf("icmp_input from %x to %x, len %d\n",
387 1.20 mycroft ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr),
388 1.20 mycroft icmplen);
389 1.1 cgd #endif
390 1.1 cgd if (icmplen < ICMP_MINLEN) {
391 1.1 cgd icmpstat.icps_tooshort++;
392 1.1 cgd goto freeit;
393 1.1 cgd }
394 1.9 mycroft i = hlen + min(icmplen, ICMP_ADVLENMIN);
395 1.20 mycroft if (m->m_len < i && (m = m_pullup(m, i)) == 0) {
396 1.1 cgd icmpstat.icps_tooshort++;
397 1.1 cgd return;
398 1.1 cgd }
399 1.5 mycroft ip = mtod(m, struct ip *);
400 1.1 cgd m->m_len -= hlen;
401 1.1 cgd m->m_data += hlen;
402 1.1 cgd icp = mtod(m, struct icmp *);
403 1.1 cgd if (in_cksum(m, icmplen)) {
404 1.1 cgd icmpstat.icps_checksum++;
405 1.1 cgd goto freeit;
406 1.1 cgd }
407 1.1 cgd m->m_len += hlen;
408 1.1 cgd m->m_data -= hlen;
409 1.1 cgd
410 1.1 cgd #ifdef ICMPPRINTFS
411 1.1 cgd /*
412 1.1 cgd * Message type specific processing.
413 1.1 cgd */
414 1.1 cgd if (icmpprintfs)
415 1.22 christos printf("icmp_input, type %d code %d\n", icp->icmp_type,
416 1.1 cgd icp->icmp_code);
417 1.1 cgd #endif
418 1.37 itojun #ifdef IPSEC
419 1.37 itojun /* drop it if it does not match the policy */
420 1.37 itojun if (ipsec4_in_reject(m, NULL)) {
421 1.37 itojun ipsecstat.in_polvio++;
422 1.37 itojun goto freeit;
423 1.37 itojun }
424 1.37 itojun #endif
425 1.1 cgd if (icp->icmp_type > ICMP_MAXTYPE)
426 1.1 cgd goto raw;
427 1.1 cgd icmpstat.icps_inhist[icp->icmp_type]++;
428 1.1 cgd code = icp->icmp_code;
429 1.1 cgd switch (icp->icmp_type) {
430 1.1 cgd
431 1.1 cgd case ICMP_UNREACH:
432 1.9 mycroft switch (code) {
433 1.9 mycroft case ICMP_UNREACH_NET:
434 1.9 mycroft case ICMP_UNREACH_HOST:
435 1.9 mycroft case ICMP_UNREACH_PROTOCOL:
436 1.9 mycroft case ICMP_UNREACH_PORT:
437 1.9 mycroft case ICMP_UNREACH_SRCFAIL:
438 1.9 mycroft code += PRC_UNREACH_NET;
439 1.9 mycroft break;
440 1.9 mycroft
441 1.9 mycroft case ICMP_UNREACH_NEEDFRAG:
442 1.9 mycroft code = PRC_MSGSIZE;
443 1.9 mycroft break;
444 1.9 mycroft
445 1.9 mycroft case ICMP_UNREACH_NET_UNKNOWN:
446 1.9 mycroft case ICMP_UNREACH_NET_PROHIB:
447 1.9 mycroft case ICMP_UNREACH_TOSNET:
448 1.9 mycroft code = PRC_UNREACH_NET;
449 1.9 mycroft break;
450 1.9 mycroft
451 1.9 mycroft case ICMP_UNREACH_HOST_UNKNOWN:
452 1.9 mycroft case ICMP_UNREACH_ISOLATED:
453 1.9 mycroft case ICMP_UNREACH_HOST_PROHIB:
454 1.9 mycroft case ICMP_UNREACH_TOSHOST:
455 1.9 mycroft code = PRC_UNREACH_HOST;
456 1.9 mycroft break;
457 1.9 mycroft
458 1.9 mycroft default:
459 1.9 mycroft goto badcode;
460 1.9 mycroft }
461 1.1 cgd goto deliver;
462 1.1 cgd
463 1.1 cgd case ICMP_TIMXCEED:
464 1.1 cgd if (code > 1)
465 1.1 cgd goto badcode;
466 1.1 cgd code += PRC_TIMXCEED_INTRANS;
467 1.1 cgd goto deliver;
468 1.1 cgd
469 1.1 cgd case ICMP_PARAMPROB:
470 1.9 mycroft if (code > 1)
471 1.1 cgd goto badcode;
472 1.1 cgd code = PRC_PARAMPROB;
473 1.1 cgd goto deliver;
474 1.1 cgd
475 1.1 cgd case ICMP_SOURCEQUENCH:
476 1.1 cgd if (code)
477 1.1 cgd goto badcode;
478 1.1 cgd code = PRC_QUENCH;
479 1.20 mycroft goto deliver;
480 1.20 mycroft
481 1.1 cgd deliver:
482 1.1 cgd /*
483 1.1 cgd * Problem with datagram; advise higher level routines.
484 1.1 cgd */
485 1.1 cgd if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
486 1.1 cgd icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {
487 1.1 cgd icmpstat.icps_badlen++;
488 1.1 cgd goto freeit;
489 1.1 cgd }
490 1.14 mycroft if (IN_MULTICAST(icp->icmp_ip.ip_dst.s_addr))
491 1.13 mycroft goto badcode;
492 1.1 cgd NTOHS(icp->icmp_ip.ip_len);
493 1.1 cgd #ifdef ICMPPRINTFS
494 1.1 cgd if (icmpprintfs)
495 1.22 christos printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
496 1.1 cgd #endif
497 1.1 cgd icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
498 1.19 christos ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput;
499 1.19 christos if (ctlfunc)
500 1.38.2.1 bouyer (void) (*ctlfunc)(code, sintosa(&icmpsrc),
501 1.38.2.1 bouyer &icp->icmp_ip);
502 1.1 cgd break;
503 1.1 cgd
504 1.1 cgd badcode:
505 1.1 cgd icmpstat.icps_badcode++;
506 1.1 cgd break;
507 1.1 cgd
508 1.1 cgd case ICMP_ECHO:
509 1.1 cgd icp->icmp_type = ICMP_ECHOREPLY;
510 1.1 cgd goto reflect;
511 1.1 cgd
512 1.1 cgd case ICMP_TSTAMP:
513 1.1 cgd if (icmplen < ICMP_TSLEN) {
514 1.1 cgd icmpstat.icps_badlen++;
515 1.1 cgd break;
516 1.1 cgd }
517 1.1 cgd icp->icmp_type = ICMP_TSTAMPREPLY;
518 1.1 cgd icp->icmp_rtime = iptime();
519 1.1 cgd icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */
520 1.1 cgd goto reflect;
521 1.9 mycroft
522 1.9 mycroft case ICMP_MASKREQ:
523 1.9 mycroft if (icmpmaskrepl == 0)
524 1.9 mycroft break;
525 1.9 mycroft /*
526 1.9 mycroft * We are not able to respond with all ones broadcast
527 1.9 mycroft * unless we receive it over a point-to-point interface.
528 1.9 mycroft */
529 1.23 thorpej if (icmplen < ICMP_MASKLEN) {
530 1.23 thorpej icmpstat.icps_badlen++;
531 1.9 mycroft break;
532 1.23 thorpej }
533 1.15 mycroft if (ip->ip_dst.s_addr == INADDR_BROADCAST ||
534 1.20 mycroft in_nullhost(ip->ip_dst))
535 1.9 mycroft icmpdst.sin_addr = ip->ip_src;
536 1.15 mycroft else
537 1.9 mycroft icmpdst.sin_addr = ip->ip_dst;
538 1.16 mycroft ia = ifatoia(ifaof_ifpforaddr(sintosa(&icmpdst),
539 1.16 mycroft m->m_pkthdr.rcvif));
540 1.9 mycroft if (ia == 0)
541 1.1 cgd break;
542 1.1 cgd icp->icmp_type = ICMP_MASKREPLY;
543 1.1 cgd icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
544 1.20 mycroft if (in_nullhost(ip->ip_src)) {
545 1.1 cgd if (ia->ia_ifp->if_flags & IFF_BROADCAST)
546 1.17 mycroft ip->ip_src = ia->ia_broadaddr.sin_addr;
547 1.1 cgd else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
548 1.17 mycroft ip->ip_src = ia->ia_dstaddr.sin_addr;
549 1.1 cgd }
550 1.1 cgd reflect:
551 1.1 cgd icmpstat.icps_reflect++;
552 1.1 cgd icmpstat.icps_outhist[icp->icmp_type]++;
553 1.1 cgd icmp_reflect(m);
554 1.1 cgd return;
555 1.1 cgd
556 1.1 cgd case ICMP_REDIRECT:
557 1.9 mycroft if (code > 3)
558 1.9 mycroft goto badcode;
559 1.9 mycroft if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
560 1.9 mycroft icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {
561 1.1 cgd icmpstat.icps_badlen++;
562 1.1 cgd break;
563 1.1 cgd }
564 1.1 cgd /*
565 1.1 cgd * Short circuit routing redirects to force
566 1.1 cgd * immediate change in the kernel's routing
567 1.1 cgd * tables. The message is also handed to anyone
568 1.1 cgd * listening on a raw socket (e.g. the routing
569 1.1 cgd * daemon for use in updating its tables).
570 1.1 cgd */
571 1.1 cgd icmpgw.sin_addr = ip->ip_src;
572 1.1 cgd icmpdst.sin_addr = icp->icmp_gwaddr;
573 1.1 cgd #ifdef ICMPPRINTFS
574 1.1 cgd if (icmpprintfs)
575 1.22 christos printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst,
576 1.20 mycroft icp->icmp_gwaddr);
577 1.1 cgd #endif
578 1.9 mycroft icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
579 1.16 mycroft rtredirect(sintosa(&icmpsrc), sintosa(&icmpdst),
580 1.12 cgd (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,
581 1.16 mycroft sintosa(&icmpgw), (struct rtentry **)0);
582 1.16 mycroft pfctlinput(PRC_REDIRECT_HOST, sintosa(&icmpsrc));
583 1.37 itojun #ifdef IPSEC
584 1.37 itojun key_sa_routechange((struct sockaddr *)&icmpsrc);
585 1.37 itojun #endif
586 1.1 cgd break;
587 1.1 cgd
588 1.1 cgd /*
589 1.1 cgd * No kernel processing for the following;
590 1.1 cgd * just fall through to send to raw listener.
591 1.1 cgd */
592 1.1 cgd case ICMP_ECHOREPLY:
593 1.9 mycroft case ICMP_ROUTERADVERT:
594 1.9 mycroft case ICMP_ROUTERSOLICIT:
595 1.1 cgd case ICMP_TSTAMPREPLY:
596 1.1 cgd case ICMP_IREQREPLY:
597 1.1 cgd case ICMP_MASKREPLY:
598 1.1 cgd default:
599 1.1 cgd break;
600 1.1 cgd }
601 1.1 cgd
602 1.1 cgd raw:
603 1.37 itojun rip_input(m, hlen, proto);
604 1.1 cgd return;
605 1.1 cgd
606 1.1 cgd freeit:
607 1.1 cgd m_freem(m);
608 1.37 itojun return;
609 1.1 cgd }
610 1.1 cgd
611 1.1 cgd /*
612 1.1 cgd * Reflect the ip packet back to the source
613 1.1 cgd */
614 1.6 mycroft void
615 1.1 cgd icmp_reflect(m)
616 1.1 cgd struct mbuf *m;
617 1.1 cgd {
618 1.38.2.1 bouyer struct ip *ip = mtod(m, struct ip *);
619 1.38.2.1 bouyer struct in_ifaddr *ia;
620 1.38.2.1 bouyer struct ifaddr *ifa;
621 1.38.2.1 bouyer struct sockaddr_in *sin = 0;
622 1.1 cgd struct in_addr t;
623 1.19 christos struct mbuf *opts = 0;
624 1.1 cgd int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
625 1.1 cgd
626 1.9 mycroft if (!in_canforward(ip->ip_src) &&
627 1.14 mycroft ((ip->ip_src.s_addr & IN_CLASSA_NET) !=
628 1.14 mycroft htonl(IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) {
629 1.9 mycroft m_freem(m); /* Bad return address */
630 1.12 cgd goto done; /* ip_output() will check for broadcast */
631 1.9 mycroft }
632 1.1 cgd t = ip->ip_dst;
633 1.1 cgd ip->ip_dst = ip->ip_src;
634 1.1 cgd /*
635 1.38.2.1 bouyer * If the incoming packet was addressed directly to us, use
636 1.38.2.1 bouyer * dst as the src for the reply. Otherwise (broadcast or
637 1.38.2.1 bouyer * anonymous), use an address which corresponds to the
638 1.38.2.1 bouyer * incoming interface, with a preference for the address which
639 1.38.2.1 bouyer * corresponds to the route to the destination of the ICMP.
640 1.1 cgd */
641 1.38.2.1 bouyer
642 1.38.2.1 bouyer /* Look for packet addressed to us */
643 1.27 tls INADDR_TO_IA(t, ia);
644 1.38.2.1 bouyer
645 1.38.2.1 bouyer /* look for packet sent to broadcast address */
646 1.27 tls if (ia == NULL && (m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST)) {
647 1.27 tls for (ifa = m->m_pkthdr.rcvif->if_addrlist.tqh_first;
648 1.27 tls ifa != NULL; ifa = ifa->ifa_list.tqe_next) {
649 1.27 tls if (ifa->ifa_addr->sa_family != AF_INET)
650 1.27 tls continue;
651 1.38.2.1 bouyer if (in_hosteq(t,ifatoia(ifa)->ia_broadaddr.sin_addr)) {
652 1.38.2.1 bouyer ia = ifatoia(ifa);
653 1.27 tls break;
654 1.38.2.1 bouyer }
655 1.27 tls }
656 1.1 cgd }
657 1.27 tls
658 1.38.2.1 bouyer if (ia)
659 1.38.2.1 bouyer sin = &ia->ia_addr;
660 1.38.2.1 bouyer
661 1.9 mycroft icmpdst.sin_addr = t;
662 1.38.2.1 bouyer
663 1.38.2.1 bouyer /* if the packet is addressed somewhere else, compute the
664 1.38.2.1 bouyer source address for packets routed back to the source, and
665 1.38.2.1 bouyer use that, if it's an address on the interface which
666 1.38.2.1 bouyer received the packet */
667 1.38.2.1 bouyer if (sin == (struct sockaddr_in *)0) {
668 1.38.2.1 bouyer struct sockaddr_in sin_dst;
669 1.38.2.1 bouyer struct route icmproute;
670 1.38.2.1 bouyer int errornum;
671 1.38.2.1 bouyer
672 1.38.2.1 bouyer sin_dst.sin_family = AF_INET;
673 1.38.2.1 bouyer sin_dst.sin_len = sizeof(struct sockaddr_in);
674 1.38.2.1 bouyer sin_dst.sin_addr = ip->ip_dst;
675 1.38.2.1 bouyer bzero(&icmproute, sizeof(icmproute));
676 1.38.2.1 bouyer errornum = 0;
677 1.38.2.1 bouyer sin = in_selectsrc(&sin_dst, &icmproute, 0, NULL, &errornum);
678 1.38.2.1 bouyer /* errornum is never used */
679 1.38.2.1 bouyer if (icmproute.ro_rt)
680 1.38.2.1 bouyer RTFREE(icmproute.ro_rt);
681 1.38.2.1 bouyer /* check to make sure sin is a source address on rcvif */
682 1.38.2.1 bouyer if (sin) {
683 1.38.2.1 bouyer t = sin->sin_addr;
684 1.38.2.1 bouyer sin = (struct sockaddr_in *)0;
685 1.38.2.1 bouyer INADDR_TO_IA(t, ia);
686 1.38.2.1 bouyer while (ia) {
687 1.38.2.1 bouyer if (ia->ia_ifp == m->m_pkthdr.rcvif) {
688 1.38.2.1 bouyer sin = &ia->ia_addr;
689 1.38.2.1 bouyer break;
690 1.38.2.1 bouyer }
691 1.38.2.1 bouyer NEXT_IA_WITH_SAME_ADDR(ia);
692 1.38.2.1 bouyer }
693 1.38.2.1 bouyer }
694 1.38.2.1 bouyer }
695 1.38.2.1 bouyer
696 1.38.2.1 bouyer /* if it was not addressed to us, but the route doesn't go out
697 1.38.2.1 bouyer the source interface, pick an address on the source
698 1.38.2.1 bouyer interface. This can happen when routing is asymmetric, or
699 1.38.2.1 bouyer when the incoming packet was encapsulated */
700 1.38.2.1 bouyer if (sin == (struct sockaddr_in *)0) {
701 1.38.2.1 bouyer for (ifa = m->m_pkthdr.rcvif->if_addrlist.tqh_first;
702 1.38.2.1 bouyer ifa != NULL; ifa = ifa->ifa_list.tqe_next) {
703 1.38.2.1 bouyer if (ifa->ifa_addr->sa_family != AF_INET)
704 1.38.2.1 bouyer continue;
705 1.38.2.1 bouyer sin = &(ifatoia(ifa)->ia_addr);
706 1.38.2.1 bouyer break;
707 1.38.2.1 bouyer }
708 1.38.2.1 bouyer }
709 1.38.2.1 bouyer
710 1.9 mycroft /*
711 1.9 mycroft * The following happens if the packet was not addressed to us,
712 1.27 tls * and was received on an interface with no IP address:
713 1.27 tls * We find the first AF_INET address on the first non-loopback
714 1.27 tls * interface.
715 1.9 mycroft */
716 1.38.2.1 bouyer if (sin == (struct sockaddr_in *)0)
717 1.27 tls for (ia = in_ifaddr.tqh_first; ia != NULL;
718 1.27 tls ia = ia->ia_list.tqe_next) {
719 1.27 tls if (ia->ia_ifp->if_flags & IFF_LOOPBACK)
720 1.27 tls continue;
721 1.38.2.1 bouyer sin = &ia->ia_addr;
722 1.27 tls break;
723 1.27 tls }
724 1.38.2.1 bouyer
725 1.36 mycroft /*
726 1.36 mycroft * If we still didn't find an address, punt. We could have an
727 1.36 mycroft * interface up (and receiving packets) with no address.
728 1.36 mycroft */
729 1.38.2.1 bouyer if (sin == (struct sockaddr_in *)0) {
730 1.36 mycroft m_freem(m);
731 1.36 mycroft goto done;
732 1.36 mycroft }
733 1.36 mycroft
734 1.38.2.1 bouyer ip->ip_src = sin->sin_addr;
735 1.1 cgd ip->ip_ttl = MAXTTL;
736 1.1 cgd
737 1.1 cgd if (optlen > 0) {
738 1.38.2.1 bouyer u_char *cp;
739 1.1 cgd int opt, cnt;
740 1.1 cgd u_int len;
741 1.1 cgd
742 1.1 cgd /*
743 1.1 cgd * Retrieve any source routing from the incoming packet;
744 1.1 cgd * add on any record-route or timestamp options.
745 1.1 cgd */
746 1.1 cgd cp = (u_char *) (ip + 1);
747 1.1 cgd if ((opts = ip_srcroute()) == 0 &&
748 1.1 cgd (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) {
749 1.1 cgd opts->m_len = sizeof(struct in_addr);
750 1.20 mycroft *mtod(opts, struct in_addr *) = zeroin_addr;
751 1.1 cgd }
752 1.1 cgd if (opts) {
753 1.1 cgd #ifdef ICMPPRINTFS
754 1.1 cgd if (icmpprintfs)
755 1.22 christos printf("icmp_reflect optlen %d rt %d => ",
756 1.1 cgd optlen, opts->m_len);
757 1.1 cgd #endif
758 1.1 cgd for (cnt = optlen; cnt > 0; cnt -= len, cp += len) {
759 1.1 cgd opt = cp[IPOPT_OPTVAL];
760 1.1 cgd if (opt == IPOPT_EOL)
761 1.1 cgd break;
762 1.1 cgd if (opt == IPOPT_NOP)
763 1.1 cgd len = 1;
764 1.1 cgd else {
765 1.38.2.1 bouyer if (cnt < IPOPT_OLEN + sizeof(*cp))
766 1.38.2.1 bouyer break;
767 1.1 cgd len = cp[IPOPT_OLEN];
768 1.38.2.1 bouyer if (len < IPOPT_OLEN + sizeof(*cp) ||
769 1.38.2.1 bouyer len > cnt)
770 1.1 cgd break;
771 1.1 cgd }
772 1.1 cgd /*
773 1.9 mycroft * Should check for overflow, but it "can't happen"
774 1.1 cgd */
775 1.9 mycroft if (opt == IPOPT_RR || opt == IPOPT_TS ||
776 1.9 mycroft opt == IPOPT_SECURITY) {
777 1.1 cgd bcopy((caddr_t)cp,
778 1.1 cgd mtod(opts, caddr_t) + opts->m_len, len);
779 1.1 cgd opts->m_len += len;
780 1.1 cgd }
781 1.1 cgd }
782 1.9 mycroft /* Terminate & pad, if necessary */
783 1.19 christos if ((cnt = opts->m_len % 4) != 0) {
784 1.9 mycroft for (; cnt < 4; cnt++) {
785 1.9 mycroft *(mtod(opts, caddr_t) + opts->m_len) =
786 1.9 mycroft IPOPT_EOL;
787 1.9 mycroft opts->m_len++;
788 1.9 mycroft }
789 1.1 cgd }
790 1.1 cgd #ifdef ICMPPRINTFS
791 1.1 cgd if (icmpprintfs)
792 1.22 christos printf("%d\n", opts->m_len);
793 1.1 cgd #endif
794 1.1 cgd }
795 1.1 cgd /*
796 1.1 cgd * Now strip out original options by copying rest of first
797 1.1 cgd * mbuf's data back, and adjust the IP length.
798 1.1 cgd */
799 1.1 cgd ip->ip_len -= optlen;
800 1.1 cgd ip->ip_hl = sizeof(struct ip) >> 2;
801 1.1 cgd m->m_len -= optlen;
802 1.1 cgd if (m->m_flags & M_PKTHDR)
803 1.1 cgd m->m_pkthdr.len -= optlen;
804 1.1 cgd optlen += sizeof(struct ip);
805 1.1 cgd bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1),
806 1.1 cgd (unsigned)(m->m_len - sizeof(struct ip)));
807 1.1 cgd }
808 1.3 hpeyerl m->m_flags &= ~(M_BCAST|M_MCAST);
809 1.1 cgd icmp_send(m, opts);
810 1.9 mycroft done:
811 1.1 cgd if (opts)
812 1.1 cgd (void)m_free(opts);
813 1.1 cgd }
814 1.1 cgd
815 1.1 cgd /*
816 1.1 cgd * Send an icmp packet back to the ip level,
817 1.1 cgd * after supplying a checksum.
818 1.1 cgd */
819 1.6 mycroft void
820 1.1 cgd icmp_send(m, opts)
821 1.38.2.1 bouyer struct mbuf *m;
822 1.1 cgd struct mbuf *opts;
823 1.1 cgd {
824 1.38.2.1 bouyer struct ip *ip = mtod(m, struct ip *);
825 1.38.2.1 bouyer int hlen;
826 1.38.2.1 bouyer struct icmp *icp;
827 1.1 cgd
828 1.1 cgd hlen = ip->ip_hl << 2;
829 1.1 cgd m->m_data += hlen;
830 1.1 cgd m->m_len -= hlen;
831 1.1 cgd icp = mtod(m, struct icmp *);
832 1.1 cgd icp->icmp_cksum = 0;
833 1.1 cgd icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
834 1.1 cgd m->m_data -= hlen;
835 1.1 cgd m->m_len += hlen;
836 1.1 cgd #ifdef ICMPPRINTFS
837 1.1 cgd if (icmpprintfs)
838 1.22 christos printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src);
839 1.1 cgd #endif
840 1.37 itojun #ifdef IPSEC
841 1.38.2.1 bouyer /* Don't lookup socket */
842 1.38.2.2 bouyer (void)ipsec_setsocket(m, NULL);
843 1.38.2.1 bouyer #endif
844 1.7 mycroft (void) ip_output(m, opts, NULL, 0, NULL);
845 1.1 cgd }
846 1.1 cgd
847 1.1 cgd n_time
848 1.1 cgd iptime()
849 1.1 cgd {
850 1.1 cgd struct timeval atv;
851 1.1 cgd u_long t;
852 1.1 cgd
853 1.1 cgd microtime(&atv);
854 1.1 cgd t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
855 1.1 cgd return (htonl(t));
856 1.9 mycroft }
857 1.9 mycroft
858 1.9 mycroft int
859 1.9 mycroft icmp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
860 1.9 mycroft int *name;
861 1.9 mycroft u_int namelen;
862 1.9 mycroft void *oldp;
863 1.9 mycroft size_t *oldlenp;
864 1.9 mycroft void *newp;
865 1.9 mycroft size_t newlen;
866 1.9 mycroft {
867 1.38.2.1 bouyer int arg, error;
868 1.9 mycroft
869 1.9 mycroft /* All sysctl names at this level are terminal. */
870 1.9 mycroft if (namelen != 1)
871 1.9 mycroft return (ENOTDIR);
872 1.9 mycroft
873 1.38.2.1 bouyer switch (name[0])
874 1.38.2.1 bouyer {
875 1.9 mycroft case ICMPCTL_MASKREPL:
876 1.38.2.1 bouyer error = sysctl_int(oldp, oldlenp, newp, newlen, &icmpmaskrepl);
877 1.38.2.1 bouyer break;
878 1.38.2.1 bouyer case ICMPCTL_RETURNDATABYTES:
879 1.38.2.1 bouyer arg = icmpreturndatabytes;
880 1.38.2.1 bouyer error = sysctl_int(oldp, oldlenp, newp, newlen, &arg);
881 1.38.2.1 bouyer if (error)
882 1.38.2.1 bouyer break;
883 1.38.2.1 bouyer if ((arg >= 8) || (arg <= 512))
884 1.38.2.1 bouyer icmpreturndatabytes = arg;
885 1.38.2.1 bouyer else
886 1.38.2.1 bouyer error = EINVAL;
887 1.38.2.1 bouyer break;
888 1.38.2.1 bouyer case ICMPCTL_ERRPPSLIMIT:
889 1.38.2.1 bouyer error = sysctl_int(oldp, oldlenp, newp, newlen, &icmperrppslim);
890 1.38.2.1 bouyer break;
891 1.9 mycroft default:
892 1.38.2.1 bouyer error = ENOPROTOOPT;
893 1.38.2.1 bouyer break;
894 1.9 mycroft }
895 1.38.2.1 bouyer return error;
896 1.24 kml }
897 1.24 kml
898 1.38.2.1 bouyer void
899 1.38.2.1 bouyer icmp_mtudisc(icp, faddr)
900 1.24 kml struct icmp *icp;
901 1.38.2.1 bouyer struct in_addr faddr;
902 1.24 kml {
903 1.38.2.1 bouyer struct icmp_mtudisc_callback *mc;
904 1.24 kml struct sockaddr *dst = sintosa(&icmpsrc);
905 1.38.2.1 bouyer struct rtentry *rt;
906 1.26 kml u_long mtu = ntohs(icp->icmp_nextmtu); /* Why a long? IPv6 */
907 1.29 kml int error;
908 1.24 kml
909 1.24 kml /* Table of common MTUs: */
910 1.24 kml
911 1.24 kml static u_long mtu_table[] = {65535, 65280, 32000, 17914, 9180, 8166,
912 1.24 kml 4352, 2002, 1492, 1006, 508, 296, 68, 0};
913 1.24 kml
914 1.24 kml rt = rtalloc1(dst, 1);
915 1.24 kml if (rt == 0)
916 1.24 kml return;
917 1.24 kml
918 1.24 kml /* If we didn't get a host route, allocate one */
919 1.24 kml
920 1.24 kml if ((rt->rt_flags & RTF_HOST) == 0) {
921 1.24 kml struct rtentry *nrt;
922 1.24 kml
923 1.24 kml error = rtrequest((int) RTM_ADD, dst,
924 1.24 kml (struct sockaddr *) rt->rt_gateway,
925 1.24 kml (struct sockaddr *) 0,
926 1.24 kml RTF_GATEWAY | RTF_HOST | RTF_DYNAMIC, &nrt);
927 1.24 kml if (error) {
928 1.24 kml rtfree(rt);
929 1.24 kml rtfree(nrt);
930 1.24 kml return;
931 1.24 kml }
932 1.24 kml nrt->rt_rmx = rt->rt_rmx;
933 1.24 kml rtfree(rt);
934 1.24 kml rt = nrt;
935 1.24 kml }
936 1.29 kml error = rt_timer_add(rt, icmp_mtudisc_timeout, ip_mtudisc_timeout_q);
937 1.29 kml if (error) {
938 1.29 kml rtfree(rt);
939 1.29 kml return;
940 1.29 kml }
941 1.24 kml
942 1.24 kml if (mtu == 0) {
943 1.24 kml int i = 0;
944 1.24 kml
945 1.26 kml mtu = icp->icmp_ip.ip_len; /* NTOHS happened in deliver: */
946 1.24 kml /* Some 4.2BSD-based routers incorrectly adjust the ip_len */
947 1.24 kml if (mtu > rt->rt_rmx.rmx_mtu && rt->rt_rmx.rmx_mtu != 0)
948 1.24 kml mtu -= (icp->icmp_ip.ip_hl << 2);
949 1.24 kml
950 1.26 kml /* If we still can't guess a value, try the route */
951 1.26 kml
952 1.26 kml if (mtu == 0) {
953 1.24 kml mtu = rt->rt_rmx.rmx_mtu;
954 1.24 kml
955 1.26 kml /* If no route mtu, default to the interface mtu */
956 1.26 kml
957 1.26 kml if (mtu == 0)
958 1.26 kml mtu = rt->rt_ifp->if_mtu;
959 1.26 kml }
960 1.26 kml
961 1.24 kml for (i = 0; i < sizeof(mtu_table) / sizeof(mtu_table[0]); i++)
962 1.26 kml if (mtu > mtu_table[i]) {
963 1.26 kml mtu = mtu_table[i];
964 1.24 kml break;
965 1.26 kml }
966 1.24 kml }
967 1.24 kml
968 1.29 kml /*
969 1.29 kml * XXX: RTV_MTU is overloaded, since the admin can set it
970 1.29 kml * to turn off PMTU for a route, and the kernel can
971 1.29 kml * set it to indicate a serious problem with PMTU
972 1.29 kml * on a route. We should be using a separate flag
973 1.29 kml * for the kernel to indicate this.
974 1.29 kml */
975 1.29 kml
976 1.24 kml if ((rt->rt_rmx.rmx_locks & RTV_MTU) == 0) {
977 1.26 kml if (mtu < 296 || mtu > rt->rt_ifp->if_mtu)
978 1.24 kml rt->rt_rmx.rmx_locks |= RTV_MTU;
979 1.24 kml else if (rt->rt_rmx.rmx_mtu > mtu ||
980 1.38.2.1 bouyer rt->rt_rmx.rmx_mtu == 0) {
981 1.38.2.1 bouyer icmpstat.icps_pmtuchg++;
982 1.24 kml rt->rt_rmx.rmx_mtu = mtu;
983 1.38.2.1 bouyer }
984 1.24 kml }
985 1.26 kml
986 1.24 kml if (rt)
987 1.24 kml rtfree(rt);
988 1.38.2.1 bouyer
989 1.38.2.1 bouyer /*
990 1.38.2.1 bouyer * Notify protocols that the MTU for this destination
991 1.38.2.1 bouyer * has changed.
992 1.38.2.1 bouyer */
993 1.38.2.1 bouyer for (mc = LIST_FIRST(&icmp_mtudisc_callbacks); mc != NULL;
994 1.38.2.1 bouyer mc = LIST_NEXT(mc, mc_list))
995 1.38.2.1 bouyer (*mc->mc_func)(faddr);
996 1.37 itojun }
997 1.37 itojun
998 1.37 itojun /*
999 1.37 itojun * Return the next larger or smaller MTU plateau (table from RFC 1191)
1000 1.37 itojun * given current value MTU. If DIR is less than zero, a larger plateau
1001 1.37 itojun * is returned; otherwise, a smaller value is returned.
1002 1.37 itojun */
1003 1.37 itojun int
1004 1.37 itojun ip_next_mtu(mtu, dir) /* XXX */
1005 1.37 itojun int mtu;
1006 1.37 itojun int dir;
1007 1.37 itojun {
1008 1.37 itojun static int mtutab[] = {
1009 1.37 itojun 65535, 32000, 17914, 8166, 4352, 2002, 1492, 1006, 508, 296,
1010 1.37 itojun 68, 0
1011 1.37 itojun };
1012 1.37 itojun int i;
1013 1.37 itojun
1014 1.37 itojun for (i = 0; i < (sizeof mtutab) / (sizeof mtutab[0]); i++) {
1015 1.37 itojun if (mtu >= mtutab[i])
1016 1.37 itojun break;
1017 1.37 itojun }
1018 1.37 itojun
1019 1.37 itojun if (dir < 0) {
1020 1.37 itojun if (i == 0) {
1021 1.37 itojun return 0;
1022 1.37 itojun } else {
1023 1.37 itojun return mtutab[i - 1];
1024 1.37 itojun }
1025 1.37 itojun } else {
1026 1.37 itojun if (mtutab[i] == 0) {
1027 1.37 itojun return 0;
1028 1.37 itojun } else if(mtu > mtutab[i]) {
1029 1.37 itojun return mtutab[i];
1030 1.37 itojun } else {
1031 1.37 itojun return mtutab[i + 1];
1032 1.37 itojun }
1033 1.37 itojun }
1034 1.29 kml }
1035 1.29 kml
1036 1.29 kml static void
1037 1.29 kml icmp_mtudisc_timeout(rt, r)
1038 1.29 kml struct rtentry *rt;
1039 1.29 kml struct rttimer *r;
1040 1.29 kml {
1041 1.29 kml if (rt == NULL)
1042 1.29 kml panic("icmp_mtudisc_timeout: bad route to timeout");
1043 1.29 kml if ((rt->rt_flags & (RTF_DYNAMIC | RTF_HOST)) ==
1044 1.29 kml (RTF_DYNAMIC | RTF_HOST)) {
1045 1.29 kml rtrequest((int) RTM_DELETE, (struct sockaddr *)rt_key(rt),
1046 1.29 kml rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
1047 1.29 kml } else {
1048 1.29 kml if ((rt->rt_rmx.rmx_locks & RTV_MTU) == 0) {
1049 1.29 kml rt->rt_rmx.rmx_mtu = 0;
1050 1.29 kml }
1051 1.29 kml }
1052 1.38.2.1 bouyer }
1053 1.38.2.1 bouyer
1054 1.38.2.1 bouyer /*
1055 1.38.2.1 bouyer * Perform rate limit check.
1056 1.38.2.1 bouyer * Returns 0 if it is okay to send the icmp packet.
1057 1.38.2.1 bouyer * Returns 1 if the router SHOULD NOT send this icmp packet due to rate
1058 1.38.2.1 bouyer * limitation.
1059 1.38.2.1 bouyer *
1060 1.38.2.1 bouyer * XXX per-destination/type check necessary?
1061 1.38.2.1 bouyer */
1062 1.38.2.1 bouyer static int
1063 1.38.2.1 bouyer icmp_ratelimit(dst, type, code)
1064 1.38.2.1 bouyer const struct in_addr *dst;
1065 1.38.2.1 bouyer const int type; /* not used at this moment */
1066 1.38.2.1 bouyer const int code; /* not used at this moment */
1067 1.38.2.1 bouyer {
1068 1.38.2.1 bouyer
1069 1.38.2.1 bouyer /* PPS limit */
1070 1.38.2.1 bouyer if (!ppsratecheck(&icmperrppslim_last, &icmperrpps_count,
1071 1.38.2.1 bouyer icmperrppslim)) {
1072 1.38.2.1 bouyer /* The packet is subject to rate limit */
1073 1.38.2.1 bouyer return 1;
1074 1.38.2.1 bouyer }
1075 1.38.2.1 bouyer
1076 1.38.2.1 bouyer /*okay to send*/
1077 1.38.2.1 bouyer return 0;
1078 1.1 cgd }
1079