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