Print this page
4787 ipf: remove rate_limit_message
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/inet/ipf/ip_fil_solaris.c
+++ new/usr/src/uts/common/inet/ipf/ip_fil_solaris.c
1 1 /*
2 2 * Copyright (C) 1993-2001, 2003 by Darren Reed.
3 3 *
4 4 * See the IPFILTER.LICENCE file for details on licencing.
5 5 *
6 6 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
7 7 */
8 8
9 9 #if !defined(lint)
10 10 static const char sccsid[] = "@(#)ip_fil_solaris.c 1.7 07/22/06 (C) 1993-2000 Darren Reed";
11 11 static const char rcsid[] = "@(#)$Id: ip_fil_solaris.c,v 2.62.2.19 2005/07/13 21:40:46 darrenr Exp $";
12 12 #endif
13 13
14 14 #include <sys/types.h>
15 15 #include <sys/errno.h>
16 16 #include <sys/param.h>
17 17 #include <sys/cpuvar.h>
18 18 #include <sys/open.h>
19 19 #include <sys/ioctl.h>
20 20 #include <sys/filio.h>
21 21 #include <sys/systm.h>
22 22 #include <sys/strsubr.h>
23 23 #include <sys/cred.h>
24 24 #include <sys/ddi.h>
25 25 #include <sys/sunddi.h>
26 26 #include <sys/ksynch.h>
27 27 #include <sys/kmem.h>
28 28 #include <sys/mkdev.h>
29 29 #include <sys/protosw.h>
30 30 #include <sys/socket.h>
31 31 #include <sys/dditypes.h>
32 32 #include <sys/cmn_err.h>
33 33 #include <sys/zone.h>
34 34 #include <net/if.h>
35 35 #include <net/af.h>
36 36 #include <net/route.h>
37 37 #include <netinet/in.h>
38 38 #include <netinet/in_systm.h>
39 39 #include <netinet/ip.h>
40 40 #include <netinet/ip_var.h>
41 41 #include <netinet/tcp.h>
42 42 #include <netinet/udp.h>
43 43 #include <netinet/tcpip.h>
44 44 #include <netinet/ip_icmp.h>
45 45 #include "netinet/ip_compat.h"
46 46 #ifdef USE_INET6
47 47 # include <netinet/icmp6.h>
48 48 #endif
49 49 #include "netinet/ip_fil.h"
50 50 #include "netinet/ip_nat.h"
51 51 #include "netinet/ip_frag.h"
52 52 #include "netinet/ip_state.h"
53 53 #include "netinet/ip_auth.h"
54 54 #include "netinet/ip_proxy.h"
55 55 #include "netinet/ipf_stack.h"
56 56 #ifdef IPFILTER_LOOKUP
57 57 # include "netinet/ip_lookup.h"
58 58 #endif
59 59 #include <inet/ip_ire.h>
60 60
61 61 #include <sys/md5.h>
62 62 #include <sys/neti.h>
63 63
64 64 static int frzerostats __P((caddr_t, ipf_stack_t *));
65 65 static int fr_setipfloopback __P((int, ipf_stack_t *));
66 66 static int fr_enableipf __P((ipf_stack_t *, int));
67 67 static int fr_send_ip __P((fr_info_t *fin, mblk_t *m, mblk_t **mp));
68 68 static int ipf_nic_event_v4 __P((hook_event_token_t, hook_data_t, void *));
69 69 static int ipf_nic_event_v6 __P((hook_event_token_t, hook_data_t, void *));
70 70 static int ipf_hook __P((hook_data_t, int, int, void *));
71 71 static int ipf_hook4_in __P((hook_event_token_t, hook_data_t, void *));
72 72 static int ipf_hook4_out __P((hook_event_token_t, hook_data_t, void *));
73 73 static int ipf_hook4_loop_out __P((hook_event_token_t, hook_data_t,
74 74 void *));
75 75 static int ipf_hook4_loop_in __P((hook_event_token_t, hook_data_t, void *));
76 76 static int ipf_hook4 __P((hook_data_t, int, int, void *));
77 77 static int ipf_hook6_out __P((hook_event_token_t, hook_data_t, void *));
78 78 static int ipf_hook6_in __P((hook_event_token_t, hook_data_t, void *));
79 79 static int ipf_hook6_loop_out __P((hook_event_token_t, hook_data_t,
80 80 void *));
81 81 static int ipf_hook6_loop_in __P((hook_event_token_t, hook_data_t,
82 82 void *));
83 83 static int ipf_hook6 __P((hook_data_t, int, int, void *));
84 84 extern int ipf_geniter __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *));
85 85 extern int ipf_frruleiter __P((void *, int, void *, ipf_stack_t *));
86 86
87 87 #if SOLARIS2 < 10
88 88 #if SOLARIS2 >= 7
89 89 u_int *ip_ttl_ptr = NULL;
90 90 u_int *ip_mtudisc = NULL;
91 91 # if SOLARIS2 >= 8
92 92 int *ip_forwarding = NULL;
93 93 u_int *ip6_forwarding = NULL;
94 94 # else
95 95 u_int *ip_forwarding = NULL;
96 96 # endif
97 97 #else
98 98 u_long *ip_ttl_ptr = NULL;
99 99 u_long *ip_mtudisc = NULL;
100 100 u_long *ip_forwarding = NULL;
101 101 #endif
102 102 #endif
103 103
104 104
105 105 /* ------------------------------------------------------------------------ */
106 106 /* Function: ipldetach */
107 107 /* Returns: int - 0 == success, else error. */
108 108 /* Parameters: Nil */
109 109 /* */
110 110 /* This function is responsible for undoing anything that might have been */
111 111 /* done in a call to iplattach(). It must be able to clean up from a call */
112 112 /* to iplattach() that did not succeed. Why might that happen? Someone */
113 113 /* configures a table to be so large that we cannot allocate enough memory */
114 114 /* for it. */
115 115 /* ------------------------------------------------------------------------ */
116 116 int ipldetach(ifs)
117 117 ipf_stack_t *ifs;
118 118 {
119 119
120 120 ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0);
121 121
122 122 #if SOLARIS2 < 10
123 123
124 124 if (ifs->ifs_fr_control_forwarding & 2) {
125 125 if (ip_forwarding != NULL)
126 126 *ip_forwarding = 0;
127 127 #if SOLARIS2 >= 8
128 128 if (ip6_forwarding != NULL)
129 129 *ip6_forwarding = 0;
130 130 #endif
131 131 }
132 132 #endif
133 133
134 134 /*
135 135 * This lock needs to be dropped around the net_hook_unregister calls
136 136 * because we can deadlock here with:
137 137 * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs
138 138 * R(hook_family)->R(hei_lock)->R(ipf_global) (active hook running)
139 139 */
140 140 RWLOCK_EXIT(&ifs->ifs_ipf_global);
141 141
142 142 #define UNDO_HOOK(_f, _b, _e, _h) \
143 143 do { \
144 144 if (ifs->_f != NULL) { \
145 145 if (ifs->_b) { \
146 146 ifs->_b = (net_hook_unregister(ifs->_f, \
147 147 _e, ifs->_h) != 0); \
148 148 if (!ifs->_b) { \
149 149 hook_free(ifs->_h); \
150 150 ifs->_h = NULL; \
151 151 } \
152 152 } else if (ifs->_h != NULL) { \
153 153 hook_free(ifs->_h); \
154 154 ifs->_h = NULL; \
155 155 } \
156 156 } \
157 157 _NOTE(CONSTCOND) \
158 158 } while (0)
159 159
160 160 /*
161 161 * Remove IPv6 Hooks
162 162 */
163 163 if (ifs->ifs_ipf_ipv6 != NULL) {
164 164 UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_in,
165 165 NH_PHYSICAL_IN, ifs_ipfhook6_in);
166 166 UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_out,
167 167 NH_PHYSICAL_OUT, ifs_ipfhook6_out);
168 168 UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_nic_events,
169 169 NH_NIC_EVENTS, ifs_ipfhook6_nicevents);
170 170 UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_in,
171 171 NH_LOOPBACK_IN, ifs_ipfhook6_loop_in);
172 172 UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_out,
173 173 NH_LOOPBACK_OUT, ifs_ipfhook6_loop_out);
174 174
175 175 if (net_protocol_release(ifs->ifs_ipf_ipv6) != 0)
176 176 goto detach_failed;
177 177 ifs->ifs_ipf_ipv6 = NULL;
178 178 }
179 179
180 180 /*
181 181 * Remove IPv4 Hooks
182 182 */
183 183 if (ifs->ifs_ipf_ipv4 != NULL) {
184 184 UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_in,
185 185 NH_PHYSICAL_IN, ifs_ipfhook4_in);
186 186 UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_out,
187 187 NH_PHYSICAL_OUT, ifs_ipfhook4_out);
188 188 UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_nic_events,
189 189 NH_NIC_EVENTS, ifs_ipfhook4_nicevents);
190 190 UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_in,
191 191 NH_LOOPBACK_IN, ifs_ipfhook4_loop_in);
192 192 UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_out,
193 193 NH_LOOPBACK_OUT, ifs_ipfhook4_loop_out);
194 194
195 195 if (net_protocol_release(ifs->ifs_ipf_ipv4) != 0)
196 196 goto detach_failed;
197 197 ifs->ifs_ipf_ipv4 = NULL;
198 198 }
199 199
200 200 #undef UNDO_HOOK
201 201
202 202 #ifdef IPFDEBUG
203 203 cmn_err(CE_CONT, "ipldetach()\n");
204 204 #endif
205 205
206 206 WRITE_ENTER(&ifs->ifs_ipf_global);
207 207 fr_deinitialise(ifs);
208 208
209 209 (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE, ifs);
210 210 (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE, ifs);
211 211
212 212 if (ifs->ifs_ipf_locks_done == 1) {
213 213 MUTEX_DESTROY(&ifs->ifs_ipf_timeoutlock);
214 214 MUTEX_DESTROY(&ifs->ifs_ipf_rw);
215 215 RW_DESTROY(&ifs->ifs_ipf_tokens);
216 216 RW_DESTROY(&ifs->ifs_ipf_ipidfrag);
217 217 ifs->ifs_ipf_locks_done = 0;
218 218 }
219 219
220 220 if (ifs->ifs_hook4_physical_in || ifs->ifs_hook4_physical_out ||
221 221 ifs->ifs_hook4_nic_events || ifs->ifs_hook4_loopback_in ||
222 222 ifs->ifs_hook4_loopback_out || ifs->ifs_hook6_nic_events ||
223 223 ifs->ifs_hook6_physical_in || ifs->ifs_hook6_physical_out ||
224 224 ifs->ifs_hook6_loopback_in || ifs->ifs_hook6_loopback_out)
225 225 return -1;
226 226
227 227 return 0;
228 228
229 229 detach_failed:
230 230 WRITE_ENTER(&ifs->ifs_ipf_global);
231 231 return -1;
232 232 }
233 233
234 234 int iplattach(ifs)
235 235 ipf_stack_t *ifs;
236 236 {
237 237 #if SOLARIS2 < 10
238 238 int i;
239 239 #endif
240 240 netid_t id = ifs->ifs_netid;
241 241
242 242 #ifdef IPFDEBUG
243 243 cmn_err(CE_CONT, "iplattach()\n");
244 244 #endif
245 245
246 246 ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0);
247 247 ifs->ifs_fr_flags = IPF_LOGGING;
248 248 #ifdef _KERNEL
249 249 ifs->ifs_fr_update_ipid = 0;
250 250 #else
251 251 ifs->ifs_fr_update_ipid = 1;
252 252 #endif
253 253 ifs->ifs_fr_minttl = 4;
254 254 ifs->ifs_fr_icmpminfragmtu = 68;
255 255 #if defined(IPFILTER_DEFAULT_BLOCK)
256 256 ifs->ifs_fr_pass = FR_BLOCK|FR_NOMATCH;
257 257 #else
258 258 ifs->ifs_fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH;
259 259 #endif
260 260
261 261 bzero((char *)ifs->ifs_frcache, sizeof(ifs->ifs_frcache));
262 262 MUTEX_INIT(&ifs->ifs_ipf_rw, "ipf rw mutex");
263 263 MUTEX_INIT(&ifs->ifs_ipf_timeoutlock, "ipf timeout lock mutex");
264 264 RWLOCK_INIT(&ifs->ifs_ipf_ipidfrag, "ipf IP NAT-Frag rwlock");
265 265 RWLOCK_INIT(&ifs->ifs_ipf_tokens, "ipf token rwlock");
266 266 ifs->ifs_ipf_locks_done = 1;
267 267
268 268 if (fr_initialise(ifs) < 0)
269 269 return -1;
270 270
271 271 HOOK_INIT(ifs->ifs_ipfhook4_nicevents, ipf_nic_event_v4,
272 272 "ipfilter_hook4_nicevents", ifs);
273 273 HOOK_INIT(ifs->ifs_ipfhook4_in, ipf_hook4_in,
274 274 "ipfilter_hook4_in", ifs);
275 275 HOOK_INIT(ifs->ifs_ipfhook4_out, ipf_hook4_out,
276 276 "ipfilter_hook4_out", ifs);
277 277 HOOK_INIT(ifs->ifs_ipfhook4_loop_in, ipf_hook4_loop_in,
278 278 "ipfilter_hook4_loop_in", ifs);
279 279 HOOK_INIT(ifs->ifs_ipfhook4_loop_out, ipf_hook4_loop_out,
280 280 "ipfilter_hook4_loop_out", ifs);
281 281
282 282 /*
283 283 * If we hold this lock over all of the net_hook_register calls, we
284 284 * can cause a deadlock to occur with the following lock ordering:
285 285 * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs
286 286 * R(hook_family)->R(hei_lock)->R(ipf_global) (packet path)
287 287 */
288 288 RWLOCK_EXIT(&ifs->ifs_ipf_global);
289 289
290 290 /*
291 291 * Add IPv4 hooks
292 292 */
293 293 ifs->ifs_ipf_ipv4 = net_protocol_lookup(id, NHF_INET);
294 294 if (ifs->ifs_ipf_ipv4 == NULL)
295 295 goto hookup_failed;
296 296
297 297 ifs->ifs_hook4_nic_events = (net_hook_register(ifs->ifs_ipf_ipv4,
298 298 NH_NIC_EVENTS, ifs->ifs_ipfhook4_nicevents) == 0);
299 299 if (!ifs->ifs_hook4_nic_events)
300 300 goto hookup_failed;
301 301
302 302 ifs->ifs_hook4_physical_in = (net_hook_register(ifs->ifs_ipf_ipv4,
303 303 NH_PHYSICAL_IN, ifs->ifs_ipfhook4_in) == 0);
304 304 if (!ifs->ifs_hook4_physical_in)
305 305 goto hookup_failed;
306 306
307 307 ifs->ifs_hook4_physical_out = (net_hook_register(ifs->ifs_ipf_ipv4,
308 308 NH_PHYSICAL_OUT, ifs->ifs_ipfhook4_out) == 0);
309 309 if (!ifs->ifs_hook4_physical_out)
310 310 goto hookup_failed;
311 311
312 312 if (ifs->ifs_ipf_loopback) {
313 313 ifs->ifs_hook4_loopback_in = (net_hook_register(
314 314 ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN,
315 315 ifs->ifs_ipfhook4_loop_in) == 0);
316 316 if (!ifs->ifs_hook4_loopback_in)
317 317 goto hookup_failed;
318 318
319 319 ifs->ifs_hook4_loopback_out = (net_hook_register(
320 320 ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT,
321 321 ifs->ifs_ipfhook4_loop_out) == 0);
322 322 if (!ifs->ifs_hook4_loopback_out)
323 323 goto hookup_failed;
324 324 }
325 325 /*
326 326 * Add IPv6 hooks
327 327 */
328 328 ifs->ifs_ipf_ipv6 = net_protocol_lookup(id, NHF_INET6);
329 329 if (ifs->ifs_ipf_ipv6 == NULL)
330 330 goto hookup_failed;
331 331
332 332 HOOK_INIT(ifs->ifs_ipfhook6_nicevents, ipf_nic_event_v6,
333 333 "ipfilter_hook6_nicevents", ifs);
334 334 HOOK_INIT(ifs->ifs_ipfhook6_in, ipf_hook6_in,
335 335 "ipfilter_hook6_in", ifs);
336 336 HOOK_INIT(ifs->ifs_ipfhook6_out, ipf_hook6_out,
337 337 "ipfilter_hook6_out", ifs);
338 338 HOOK_INIT(ifs->ifs_ipfhook6_loop_in, ipf_hook6_loop_in,
339 339 "ipfilter_hook6_loop_in", ifs);
340 340 HOOK_INIT(ifs->ifs_ipfhook6_loop_out, ipf_hook6_loop_out,
341 341 "ipfilter_hook6_loop_out", ifs);
342 342
343 343 ifs->ifs_hook6_nic_events = (net_hook_register(ifs->ifs_ipf_ipv6,
344 344 NH_NIC_EVENTS, ifs->ifs_ipfhook6_nicevents) == 0);
345 345 if (!ifs->ifs_hook6_nic_events)
346 346 goto hookup_failed;
347 347
348 348 ifs->ifs_hook6_physical_in = (net_hook_register(ifs->ifs_ipf_ipv6,
349 349 NH_PHYSICAL_IN, ifs->ifs_ipfhook6_in) == 0);
350 350 if (!ifs->ifs_hook6_physical_in)
351 351 goto hookup_failed;
352 352
353 353 ifs->ifs_hook6_physical_out = (net_hook_register(ifs->ifs_ipf_ipv6,
354 354 NH_PHYSICAL_OUT, ifs->ifs_ipfhook6_out) == 0);
355 355 if (!ifs->ifs_hook6_physical_out)
356 356 goto hookup_failed;
357 357
358 358 if (ifs->ifs_ipf_loopback) {
359 359 ifs->ifs_hook6_loopback_in = (net_hook_register(
360 360 ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN,
361 361 ifs->ifs_ipfhook6_loop_in) == 0);
362 362 if (!ifs->ifs_hook6_loopback_in)
363 363 goto hookup_failed;
364 364
365 365 ifs->ifs_hook6_loopback_out = (net_hook_register(
366 366 ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT,
367 367 ifs->ifs_ipfhook6_loop_out) == 0);
368 368 if (!ifs->ifs_hook6_loopback_out)
369 369 goto hookup_failed;
370 370 }
371 371
372 372 /*
373 373 * Reacquire ipf_global, now it is safe.
374 374 */
375 375 WRITE_ENTER(&ifs->ifs_ipf_global);
376 376
377 377 /* Do not use private interface ip_params_arr[] in Solaris 10 */
378 378 #if SOLARIS2 < 10
379 379
380 380 #if SOLARIS2 >= 8
381 381 ip_forwarding = &ip_g_forward;
382 382 #endif
383 383 /*
384 384 * XXX - There is no terminator for this array, so it is not possible
385 385 * to tell if what we are looking for is missing and go off the end
386 386 * of the array.
387 387 */
388 388
389 389 #if SOLARIS2 <= 8
390 390 for (i = 0; ; i++) {
391 391 if (!strcmp(ip_param_arr[i].ip_param_name, "ip_def_ttl")) {
392 392 ip_ttl_ptr = &ip_param_arr[i].ip_param_value;
393 393 } else if (!strcmp(ip_param_arr[i].ip_param_name,
394 394 "ip_path_mtu_discovery")) {
395 395 ip_mtudisc = &ip_param_arr[i].ip_param_value;
396 396 }
397 397 #if SOLARIS2 < 8
398 398 else if (!strcmp(ip_param_arr[i].ip_param_name,
399 399 "ip_forwarding")) {
400 400 ip_forwarding = &ip_param_arr[i].ip_param_value;
401 401 }
402 402 #else
403 403 else if (!strcmp(ip_param_arr[i].ip_param_name,
404 404 "ip6_forwarding")) {
405 405 ip6_forwarding = &ip_param_arr[i].ip_param_value;
406 406 }
407 407 #endif
408 408
409 409 if (ip_mtudisc != NULL && ip_ttl_ptr != NULL &&
410 410 #if SOLARIS2 >= 8
411 411 ip6_forwarding != NULL &&
412 412 #endif
413 413 ip_forwarding != NULL)
414 414 break;
415 415 }
416 416 #endif
417 417
418 418 if (ifs->ifs_fr_control_forwarding & 1) {
419 419 if (ip_forwarding != NULL)
420 420 *ip_forwarding = 1;
421 421 #if SOLARIS2 >= 8
422 422 if (ip6_forwarding != NULL)
423 423 *ip6_forwarding = 1;
424 424 #endif
425 425 }
426 426
427 427 #endif
428 428
429 429 return 0;
430 430 hookup_failed:
431 431 WRITE_ENTER(&ifs->ifs_ipf_global);
432 432 return -1;
433 433 }
434 434
435 435 static int fr_setipfloopback(set, ifs)
436 436 int set;
437 437 ipf_stack_t *ifs;
438 438 {
439 439 if (ifs->ifs_ipf_ipv4 == NULL || ifs->ifs_ipf_ipv6 == NULL)
440 440 return EFAULT;
441 441
442 442 if (set && !ifs->ifs_ipf_loopback) {
443 443 ifs->ifs_ipf_loopback = 1;
444 444
445 445 ifs->ifs_hook4_loopback_in = (net_hook_register(
446 446 ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN,
447 447 ifs->ifs_ipfhook4_loop_in) == 0);
448 448 if (!ifs->ifs_hook4_loopback_in)
449 449 return EINVAL;
450 450
451 451 ifs->ifs_hook4_loopback_out = (net_hook_register(
452 452 ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT,
453 453 ifs->ifs_ipfhook4_loop_out) == 0);
454 454 if (!ifs->ifs_hook4_loopback_out)
455 455 return EINVAL;
456 456
457 457 ifs->ifs_hook6_loopback_in = (net_hook_register(
458 458 ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN,
459 459 ifs->ifs_ipfhook6_loop_in) == 0);
460 460 if (!ifs->ifs_hook6_loopback_in)
461 461 return EINVAL;
462 462
463 463 ifs->ifs_hook6_loopback_out = (net_hook_register(
464 464 ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT,
465 465 ifs->ifs_ipfhook6_loop_out) == 0);
466 466 if (!ifs->ifs_hook6_loopback_out)
467 467 return EINVAL;
468 468
469 469 } else if (!set && ifs->ifs_ipf_loopback) {
470 470 ifs->ifs_ipf_loopback = 0;
471 471
472 472 ifs->ifs_hook4_loopback_in =
473 473 (net_hook_unregister(ifs->ifs_ipf_ipv4,
474 474 NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0);
475 475 if (ifs->ifs_hook4_loopback_in)
476 476 return EBUSY;
477 477
478 478 ifs->ifs_hook4_loopback_out =
479 479 (net_hook_unregister(ifs->ifs_ipf_ipv4,
480 480 NH_LOOPBACK_OUT, ifs->ifs_ipfhook4_loop_out) != 0);
481 481 if (ifs->ifs_hook4_loopback_out)
482 482 return EBUSY;
483 483
484 484 ifs->ifs_hook6_loopback_in =
485 485 (net_hook_unregister(ifs->ifs_ipf_ipv6,
486 486 NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0);
487 487 if (ifs->ifs_hook6_loopback_in)
488 488 return EBUSY;
489 489
490 490 ifs->ifs_hook6_loopback_out =
491 491 (net_hook_unregister(ifs->ifs_ipf_ipv6,
492 492 NH_LOOPBACK_OUT, ifs->ifs_ipfhook6_loop_out) != 0);
493 493 if (ifs->ifs_hook6_loopback_out)
494 494 return EBUSY;
495 495 }
496 496 return 0;
497 497 }
498 498
499 499
500 500 /*
501 501 * Filter ioctl interface.
502 502 */
503 503 /*ARGSUSED*/
504 504 int iplioctl(dev, cmd, data, mode, cp, rp)
505 505 dev_t dev;
506 506 int cmd;
507 507 #if SOLARIS2 >= 7
508 508 intptr_t data;
509 509 #else
510 510 int *data;
511 511 #endif
512 512 int mode;
513 513 cred_t *cp;
514 514 int *rp;
515 515 {
516 516 int error = 0, tmp;
517 517 friostat_t fio;
518 518 minor_t unit;
519 519 u_int enable;
520 520 ipf_stack_t *ifs;
521 521
522 522 #ifdef IPFDEBUG
523 523 cmn_err(CE_CONT, "iplioctl(%x,%x,%x,%d,%x,%d)\n",
524 524 dev, cmd, data, mode, cp, rp);
525 525 #endif
526 526 unit = getminor(dev);
527 527 if (IPL_LOGMAX < unit)
528 528 return ENXIO;
529 529
530 530 /*
531 531 * As we're calling ipf_find_stack in user space, from a given zone
532 532 * to find the stack pointer for this zone, there is no need to have
533 533 * a hold/refence count here.
534 534 */
535 535 ifs = ipf_find_stack(crgetzoneid(cp));
536 536 ASSERT(ifs != NULL);
537 537
538 538 if (ifs->ifs_fr_running <= 0) {
539 539 if (unit != IPL_LOGIPF) {
540 540 return EIO;
541 541 }
542 542 if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET &&
543 543 cmd != SIOCIPFSET && cmd != SIOCFRENB &&
544 544 cmd != SIOCGETFS && cmd != SIOCGETFF) {
545 545 return EIO;
546 546 }
547 547 }
548 548
549 549 READ_ENTER(&ifs->ifs_ipf_global);
550 550 if (ifs->ifs_fr_enable_active != 0) {
551 551 RWLOCK_EXIT(&ifs->ifs_ipf_global);
552 552 return EBUSY;
553 553 }
554 554
555 555 error = fr_ioctlswitch(unit, (caddr_t)data, cmd, mode, crgetuid(cp),
556 556 curproc, ifs);
557 557 if (error != -1) {
558 558 RWLOCK_EXIT(&ifs->ifs_ipf_global);
559 559 return error;
560 560 }
561 561 error = 0;
562 562
563 563 switch (cmd)
564 564 {
565 565 case SIOCFRENB :
566 566 if (!(mode & FWRITE))
567 567 error = EPERM;
568 568 else {
569 569 error = COPYIN((caddr_t)data, (caddr_t)&enable,
570 570 sizeof(enable));
571 571 if (error != 0) {
572 572 error = EFAULT;
573 573 break;
574 574 }
575 575
576 576 RWLOCK_EXIT(&ifs->ifs_ipf_global);
577 577 WRITE_ENTER(&ifs->ifs_ipf_global);
578 578
579 579 /*
580 580 * We must recheck fr_enable_active here, since we've
581 581 * dropped ifs_ipf_global from R in order to get it
582 582 * exclusively.
583 583 */
584 584 if (ifs->ifs_fr_enable_active == 0) {
585 585 ifs->ifs_fr_enable_active = 1;
586 586 error = fr_enableipf(ifs, enable);
587 587 ifs->ifs_fr_enable_active = 0;
588 588 }
589 589 }
590 590 break;
591 591 case SIOCIPFSET :
592 592 if (!(mode & FWRITE)) {
593 593 error = EPERM;
594 594 break;
595 595 }
596 596 /* FALLTHRU */
597 597 case SIOCIPFGETNEXT :
598 598 case SIOCIPFGET :
599 599 error = fr_ipftune(cmd, (void *)data, ifs);
600 600 break;
601 601 case SIOCSETFF :
602 602 if (!(mode & FWRITE))
603 603 error = EPERM;
604 604 else {
605 605 error = COPYIN((caddr_t)data,
606 606 (caddr_t)&ifs->ifs_fr_flags,
607 607 sizeof(ifs->ifs_fr_flags));
608 608 if (error != 0)
609 609 error = EFAULT;
610 610 }
611 611 break;
612 612 case SIOCIPFLP :
613 613 error = COPYIN((caddr_t)data, (caddr_t)&tmp,
614 614 sizeof(tmp));
615 615 if (error != 0)
616 616 error = EFAULT;
617 617 else
618 618 error = fr_setipfloopback(tmp, ifs);
619 619 break;
620 620 case SIOCGETFF :
621 621 error = COPYOUT((caddr_t)&ifs->ifs_fr_flags, (caddr_t)data,
622 622 sizeof(ifs->ifs_fr_flags));
623 623 if (error != 0)
624 624 error = EFAULT;
625 625 break;
626 626 case SIOCFUNCL :
627 627 error = fr_resolvefunc((void *)data);
628 628 break;
629 629 case SIOCINAFR :
630 630 case SIOCRMAFR :
631 631 case SIOCADAFR :
632 632 case SIOCZRLST :
633 633 if (!(mode & FWRITE))
634 634 error = EPERM;
635 635 else
636 636 error = frrequest(unit, cmd, (caddr_t)data,
637 637 ifs->ifs_fr_active, 1, ifs);
638 638 break;
639 639 case SIOCINIFR :
640 640 case SIOCRMIFR :
641 641 case SIOCADIFR :
642 642 if (!(mode & FWRITE))
643 643 error = EPERM;
644 644 else
645 645 error = frrequest(unit, cmd, (caddr_t)data,
646 646 1 - ifs->ifs_fr_active, 1, ifs);
647 647 break;
648 648 case SIOCSWAPA :
649 649 if (!(mode & FWRITE))
650 650 error = EPERM;
651 651 else {
652 652 WRITE_ENTER(&ifs->ifs_ipf_mutex);
653 653 bzero((char *)ifs->ifs_frcache,
654 654 sizeof (ifs->ifs_frcache));
655 655 error = COPYOUT((caddr_t)&ifs->ifs_fr_active,
656 656 (caddr_t)data,
657 657 sizeof(ifs->ifs_fr_active));
658 658 if (error != 0)
659 659 error = EFAULT;
660 660 else
661 661 ifs->ifs_fr_active = 1 - ifs->ifs_fr_active;
662 662 RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
663 663 }
664 664 break;
665 665 case SIOCGETFS :
666 666 fr_getstat(&fio, ifs);
667 667 error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT);
668 668 break;
669 669 case SIOCFRZST :
670 670 if (!(mode & FWRITE))
671 671 error = EPERM;
672 672 else
673 673 error = fr_zerostats((caddr_t)data, ifs);
674 674 break;
675 675 case SIOCIPFFL :
676 676 if (!(mode & FWRITE))
677 677 error = EPERM;
678 678 else {
679 679 error = COPYIN((caddr_t)data, (caddr_t)&tmp,
680 680 sizeof(tmp));
681 681 if (!error) {
682 682 tmp = frflush(unit, 4, tmp, ifs);
683 683 error = COPYOUT((caddr_t)&tmp, (caddr_t)data,
684 684 sizeof(tmp));
685 685 if (error != 0)
686 686 error = EFAULT;
687 687 } else
688 688 error = EFAULT;
689 689 }
690 690 break;
691 691 #ifdef USE_INET6
692 692 case SIOCIPFL6 :
693 693 if (!(mode & FWRITE))
694 694 error = EPERM;
695 695 else {
696 696 error = COPYIN((caddr_t)data, (caddr_t)&tmp,
697 697 sizeof(tmp));
698 698 if (!error) {
699 699 tmp = frflush(unit, 6, tmp, ifs);
700 700 error = COPYOUT((caddr_t)&tmp, (caddr_t)data,
701 701 sizeof(tmp));
702 702 if (error != 0)
703 703 error = EFAULT;
704 704 } else
705 705 error = EFAULT;
706 706 }
707 707 break;
708 708 #endif
709 709 case SIOCSTLCK :
710 710 error = COPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp));
711 711 if (error == 0) {
712 712 ifs->ifs_fr_state_lock = tmp;
713 713 ifs->ifs_fr_nat_lock = tmp;
714 714 ifs->ifs_fr_frag_lock = tmp;
715 715 ifs->ifs_fr_auth_lock = tmp;
716 716 } else
717 717 error = EFAULT;
718 718 break;
719 719 #ifdef IPFILTER_LOG
720 720 case SIOCIPFFB :
721 721 if (!(mode & FWRITE))
722 722 error = EPERM;
723 723 else {
724 724 tmp = ipflog_clear(unit, ifs);
725 725 error = COPYOUT((caddr_t)&tmp, (caddr_t)data,
726 726 sizeof(tmp));
727 727 if (error)
728 728 error = EFAULT;
729 729 }
730 730 break;
731 731 #endif /* IPFILTER_LOG */
732 732 case SIOCFRSYN :
733 733 if (!(mode & FWRITE))
734 734 error = EPERM;
735 735 else {
736 736 RWLOCK_EXIT(&ifs->ifs_ipf_global);
737 737 WRITE_ENTER(&ifs->ifs_ipf_global);
738 738
739 739 frsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs);
740 740 fr_natifpsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs);
741 741 fr_nataddrsync(0, NULL, NULL, ifs);
742 742 fr_statesync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs);
743 743 error = 0;
744 744 }
745 745 break;
746 746 case SIOCGFRST :
747 747 error = fr_outobj((void *)data, fr_fragstats(ifs),
748 748 IPFOBJ_FRAGSTAT);
749 749 break;
750 750 case FIONREAD :
751 751 #ifdef IPFILTER_LOG
752 752 tmp = (int)ifs->ifs_iplused[IPL_LOGIPF];
753 753
754 754 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, sizeof(tmp));
755 755 if (error != 0)
756 756 error = EFAULT;
757 757 #endif
758 758 break;
759 759 case SIOCIPFITER :
760 760 error = ipf_frruleiter((caddr_t)data, crgetuid(cp),
761 761 curproc, ifs);
762 762 break;
763 763
764 764 case SIOCGENITER :
765 765 error = ipf_genericiter((caddr_t)data, crgetuid(cp),
766 766 curproc, ifs);
767 767 break;
768 768
769 769 case SIOCIPFDELTOK :
770 770 error = BCOPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp));
771 771 if (error != 0) {
772 772 error = EFAULT;
773 773 } else {
774 774 error = ipf_deltoken(tmp, crgetuid(cp), curproc, ifs);
775 775 }
776 776 break;
777 777
778 778 default :
779 779 #ifdef IPFDEBUG
780 780 cmn_err(CE_NOTE, "Unknown: cmd 0x%x data %p",
781 781 cmd, (void *)data);
782 782 #endif
783 783 error = EINVAL;
784 784 break;
785 785 }
786 786 RWLOCK_EXIT(&ifs->ifs_ipf_global);
787 787 return error;
788 788 }
789 789
790 790
791 791 static int fr_enableipf(ifs, enable)
792 792 ipf_stack_t *ifs;
793 793 int enable;
794 794 {
795 795 int error;
796 796
797 797 if (!enable) {
798 798 error = ipldetach(ifs);
799 799 if (error == 0)
800 800 ifs->ifs_fr_running = -1;
801 801 return error;
802 802 }
803 803
804 804 if (ifs->ifs_fr_running > 0)
805 805 return 0;
806 806
807 807 error = iplattach(ifs);
808 808 if (error == 0) {
809 809 if (ifs->ifs_fr_timer_id == NULL) {
810 810 int hz = drv_usectohz(500000);
811 811
812 812 ifs->ifs_fr_timer_id = timeout(fr_slowtimer,
813 813 (void *)ifs,
814 814 hz);
815 815 }
816 816 ifs->ifs_fr_running = 1;
817 817 } else {
818 818 (void) ipldetach(ifs);
819 819 }
820 820 return error;
821 821 }
822 822
823 823
824 824 phy_if_t get_unit(name, v, ifs)
825 825 char *name;
826 826 int v;
827 827 ipf_stack_t *ifs;
828 828 {
829 829 net_handle_t nif;
830 830
831 831 if (v == 4)
832 832 nif = ifs->ifs_ipf_ipv4;
833 833 else if (v == 6)
834 834 nif = ifs->ifs_ipf_ipv6;
835 835 else
836 836 return 0;
837 837
838 838 return (net_phylookup(nif, name));
839 839 }
840 840
841 841 /*
842 842 * routines below for saving IP headers to buffer
843 843 */
844 844 /*ARGSUSED*/
845 845 int iplopen(devp, flags, otype, cred)
846 846 dev_t *devp;
847 847 int flags, otype;
848 848 cred_t *cred;
849 849 {
850 850 minor_t min = getminor(*devp);
851 851
852 852 #ifdef IPFDEBUG
853 853 cmn_err(CE_CONT, "iplopen(%x,%x,%x,%x)\n", devp, flags, otype, cred);
854 854 #endif
855 855 if (!(otype & OTYP_CHR))
856 856 return ENXIO;
857 857
858 858 min = (IPL_LOGMAX < min) ? ENXIO : 0;
859 859 return min;
860 860 }
861 861
862 862
863 863 /*ARGSUSED*/
864 864 int iplclose(dev, flags, otype, cred)
865 865 dev_t dev;
866 866 int flags, otype;
867 867 cred_t *cred;
868 868 {
869 869 minor_t min = getminor(dev);
870 870
871 871 #ifdef IPFDEBUG
872 872 cmn_err(CE_CONT, "iplclose(%x,%x,%x,%x)\n", dev, flags, otype, cred);
873 873 #endif
874 874
875 875 min = (IPL_LOGMAX < min) ? ENXIO : 0;
876 876 return min;
877 877 }
878 878
879 879 #ifdef IPFILTER_LOG
880 880 /*
881 881 * iplread/ipllog
882 882 * both of these must operate with at least splnet() lest they be
883 883 * called during packet processing and cause an inconsistancy to appear in
884 884 * the filter lists.
885 885 */
886 886 /*ARGSUSED*/
887 887 int iplread(dev, uio, cp)
888 888 dev_t dev;
889 889 register struct uio *uio;
890 890 cred_t *cp;
891 891 {
892 892 ipf_stack_t *ifs;
893 893 int ret;
894 894
895 895 /*
896 896 * As we're calling ipf_find_stack in user space, from a given zone
897 897 * to find the stack pointer for this zone, there is no need to have
898 898 * a hold/refence count here.
899 899 */
900 900 ifs = ipf_find_stack(crgetzoneid(cp));
901 901 ASSERT(ifs != NULL);
902 902
903 903 # ifdef IPFDEBUG
904 904 cmn_err(CE_CONT, "iplread(%x,%x,%x)\n", dev, uio, cp);
905 905 # endif
906 906
907 907 if (ifs->ifs_fr_running < 1) {
908 908 return EIO;
909 909 }
910 910
911 911 # ifdef IPFILTER_SYNC
912 912 if (getminor(dev) == IPL_LOGSYNC) {
913 913 return ipfsync_read(uio);
914 914 }
915 915 # endif
916 916
917 917 ret = ipflog_read(getminor(dev), uio, ifs);
918 918 return ret;
919 919 }
920 920 #endif /* IPFILTER_LOG */
921 921
922 922
923 923 /*
924 924 * iplread/ipllog
925 925 * both of these must operate with at least splnet() lest they be
926 926 * called during packet processing and cause an inconsistancy to appear in
927 927 * the filter lists.
928 928 */
929 929 int iplwrite(dev, uio, cp)
930 930 dev_t dev;
931 931 register struct uio *uio;
932 932 cred_t *cp;
933 933 {
934 934 ipf_stack_t *ifs;
935 935
936 936 /*
937 937 * As we're calling ipf_find_stack in user space, from a given zone
938 938 * to find the stack pointer for this zone, there is no need to have
939 939 * a hold/refence count here.
940 940 */
941 941 ifs = ipf_find_stack(crgetzoneid(cp));
942 942 ASSERT(ifs != NULL);
943 943
944 944 #ifdef IPFDEBUG
945 945 cmn_err(CE_CONT, "iplwrite(%x,%x,%x)\n", dev, uio, cp);
946 946 #endif
947 947
948 948 if (ifs->ifs_fr_running < 1) {
949 949 return EIO;
950 950 }
951 951
952 952 #ifdef IPFILTER_SYNC
953 953 if (getminor(dev) == IPL_LOGSYNC)
954 954 return ipfsync_write(uio);
955 955 #endif /* IPFILTER_SYNC */
956 956 dev = dev; /* LINT */
957 957 uio = uio; /* LINT */
958 958 cp = cp; /* LINT */
959 959 return ENXIO;
960 960 }
961 961
962 962
963 963 /*
964 964 * fr_send_reset - this could conceivably be a call to tcp_respond(), but that
965 965 * requires a large amount of setting up and isn't any more efficient.
966 966 */
967 967 int fr_send_reset(fin)
968 968 fr_info_t *fin;
969 969 {
970 970 tcphdr_t *tcp, *tcp2;
971 971 int tlen, hlen;
972 972 mblk_t *m;
973 973 #ifdef USE_INET6
974 974 ip6_t *ip6;
975 975 #endif
976 976 ip_t *ip;
977 977
978 978 tcp = fin->fin_dp;
979 979 if (tcp->th_flags & TH_RST)
980 980 return -1;
981 981
982 982 #ifndef IPFILTER_CKSUM
983 983 if (fr_checkl4sum(fin) == -1)
984 984 return -1;
985 985 #endif
986 986
987 987 tlen = (tcp->th_flags & (TH_SYN|TH_FIN)) ? 1 : 0;
988 988 #ifdef USE_INET6
989 989 if (fin->fin_v == 6)
990 990 hlen = sizeof(ip6_t);
991 991 else
992 992 #endif
993 993 hlen = sizeof(ip_t);
994 994 hlen += sizeof(*tcp2);
995 995 if ((m = (mblk_t *)allocb(hlen + 64, BPRI_HI)) == NULL)
996 996 return -1;
997 997
998 998 m->b_rptr += 64;
999 999 MTYPE(m) = M_DATA;
1000 1000 m->b_wptr = m->b_rptr + hlen;
1001 1001 ip = (ip_t *)m->b_rptr;
1002 1002 bzero((char *)ip, hlen);
1003 1003 tcp2 = (struct tcphdr *)(m->b_rptr + hlen - sizeof(*tcp2));
1004 1004 tcp2->th_dport = tcp->th_sport;
1005 1005 tcp2->th_sport = tcp->th_dport;
1006 1006 if (tcp->th_flags & TH_ACK) {
1007 1007 tcp2->th_seq = tcp->th_ack;
1008 1008 tcp2->th_flags = TH_RST;
1009 1009 } else {
1010 1010 tcp2->th_ack = ntohl(tcp->th_seq);
1011 1011 tcp2->th_ack += tlen;
1012 1012 tcp2->th_ack = htonl(tcp2->th_ack);
1013 1013 tcp2->th_flags = TH_RST|TH_ACK;
1014 1014 }
1015 1015 tcp2->th_off = sizeof(struct tcphdr) >> 2;
1016 1016
1017 1017 ip->ip_v = fin->fin_v;
1018 1018 #ifdef USE_INET6
1019 1019 if (fin->fin_v == 6) {
1020 1020 ip6 = (ip6_t *)m->b_rptr;
1021 1021 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
1022 1022 ip6->ip6_src = fin->fin_dst6.in6;
1023 1023 ip6->ip6_dst = fin->fin_src6.in6;
1024 1024 ip6->ip6_plen = htons(sizeof(*tcp));
1025 1025 ip6->ip6_nxt = IPPROTO_TCP;
1026 1026 tcp2->th_sum = fr_cksum(m, (ip_t *)ip6, IPPROTO_TCP, tcp2);
1027 1027 } else
1028 1028 #endif
1029 1029 {
1030 1030 ip->ip_src.s_addr = fin->fin_daddr;
1031 1031 ip->ip_dst.s_addr = fin->fin_saddr;
1032 1032 ip->ip_id = fr_nextipid(fin);
1033 1033 ip->ip_hl = sizeof(*ip) >> 2;
1034 1034 ip->ip_p = IPPROTO_TCP;
1035 1035 ip->ip_len = sizeof(*ip) + sizeof(*tcp);
1036 1036 ip->ip_tos = fin->fin_ip->ip_tos;
1037 1037 tcp2->th_sum = fr_cksum(m, ip, IPPROTO_TCP, tcp2);
1038 1038 }
1039 1039 return fr_send_ip(fin, m, &m);
1040 1040 }
1041 1041
1042 1042 /*
1043 1043 * Function: fr_send_ip
1044 1044 * Returns: 0: success
1045 1045 * -1: failed
1046 1046 * Parameters:
1047 1047 * fin: packet information
1048 1048 * m: the message block where ip head starts
1049 1049 *
1050 1050 * Send a new packet through the IP stack.
1051 1051 *
1052 1052 * For IPv4 packets, ip_len must be in host byte order, and ip_v,
1053 1053 * ip_ttl, ip_off, and ip_sum are ignored (filled in by this
1054 1054 * function).
1055 1055 *
1056 1056 * For IPv6 packets, ip6_flow, ip6_vfc, and ip6_hlim are filled
1057 1057 * in by this function.
1058 1058 *
1059 1059 * All other portions of the packet must be in on-the-wire format.
1060 1060 */
1061 1061 /*ARGSUSED*/
1062 1062 static int fr_send_ip(fin, m, mpp)
1063 1063 fr_info_t *fin;
1064 1064 mblk_t *m, **mpp;
1065 1065 {
1066 1066 qpktinfo_t qpi, *qpip;
1067 1067 fr_info_t fnew;
1068 1068 ip_t *ip;
1069 1069 int i, hlen;
1070 1070 ipf_stack_t *ifs = fin->fin_ifs;
1071 1071
1072 1072 ip = (ip_t *)m->b_rptr;
1073 1073 bzero((char *)&fnew, sizeof(fnew));
1074 1074
1075 1075 #ifdef USE_INET6
1076 1076 if (fin->fin_v == 6) {
1077 1077 ip6_t *ip6;
1078 1078
1079 1079 ip6 = (ip6_t *)ip;
1080 1080 ip6->ip6_vfc = 0x60;
1081 1081 ip6->ip6_hlim = 127;
1082 1082 fnew.fin_v = 6;
1083 1083 hlen = sizeof(*ip6);
1084 1084 fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen;
1085 1085 } else
1086 1086 #endif
1087 1087 {
1088 1088 fnew.fin_v = 4;
1089 1089 #if SOLARIS2 >= 10
1090 1090 ip->ip_ttl = 255;
1091 1091 if (net_getpmtuenabled(ifs->ifs_ipf_ipv4) == 1)
1092 1092 ip->ip_off = htons(IP_DF);
1093 1093 #else
1094 1094 if (ip_ttl_ptr != NULL)
1095 1095 ip->ip_ttl = (u_char)(*ip_ttl_ptr);
1096 1096 else
1097 1097 ip->ip_ttl = 63;
1098 1098 if (ip_mtudisc != NULL)
1099 1099 ip->ip_off = htons(*ip_mtudisc ? IP_DF : 0);
1100 1100 else
1101 1101 ip->ip_off = htons(IP_DF);
1102 1102 #endif
1103 1103 /*
1104 1104 * The dance with byte order and ip_len/ip_off is because in
1105 1105 * fr_fastroute, it expects them to be in host byte order but
1106 1106 * ipf_cksum expects them to be in network byte order.
1107 1107 */
1108 1108 ip->ip_len = htons(ip->ip_len);
1109 1109 ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip));
1110 1110 ip->ip_len = ntohs(ip->ip_len);
1111 1111 ip->ip_off = ntohs(ip->ip_off);
1112 1112 hlen = sizeof(*ip);
1113 1113 fnew.fin_plen = ip->ip_len;
1114 1114 }
1115 1115
1116 1116 qpip = fin->fin_qpi;
1117 1117 qpi.qpi_off = 0;
1118 1118 qpi.qpi_ill = qpip->qpi_ill;
1119 1119 qpi.qpi_m = m;
1120 1120 qpi.qpi_data = ip;
1121 1121 fnew.fin_qpi = &qpi;
1122 1122 fnew.fin_ifp = fin->fin_ifp;
1123 1123 fnew.fin_flx = FI_NOCKSUM;
1124 1124 fnew.fin_m = m;
1125 1125 fnew.fin_qfm = m;
1126 1126 fnew.fin_ip = ip;
1127 1127 fnew.fin_mp = mpp;
1128 1128 fnew.fin_hlen = hlen;
1129 1129 fnew.fin_dp = (char *)ip + hlen;
1130 1130 fnew.fin_ifs = fin->fin_ifs;
1131 1131 (void) fr_makefrip(hlen, ip, &fnew);
1132 1132
1133 1133 i = fr_fastroute(m, mpp, &fnew, NULL);
1134 1134 return i;
1135 1135 }
1136 1136
1137 1137
1138 1138 int fr_send_icmp_err(type, fin, dst)
1139 1139 int type;
1140 1140 fr_info_t *fin;
1141 1141 int dst;
1142 1142 {
1143 1143 struct in_addr dst4;
1144 1144 struct icmp *icmp;
1145 1145 qpktinfo_t *qpi;
1146 1146 int hlen, code;
1147 1147 phy_if_t phy;
1148 1148 u_short sz;
1149 1149 #ifdef USE_INET6
1150 1150 mblk_t *mb;
1151 1151 #endif
1152 1152 mblk_t *m;
1153 1153 #ifdef USE_INET6
1154 1154 ip6_t *ip6;
1155 1155 #endif
1156 1156 ip_t *ip;
1157 1157 ipf_stack_t *ifs = fin->fin_ifs;
1158 1158
1159 1159 if ((type < 0) || (type > ICMP_MAXTYPE))
1160 1160 return -1;
1161 1161
1162 1162 code = fin->fin_icode;
1163 1163 #ifdef USE_INET6
1164 1164 if ((code < 0) || (code >= ICMP_MAX_UNREACH))
1165 1165 return -1;
1166 1166 #endif
1167 1167
1168 1168 #ifndef IPFILTER_CKSUM
1169 1169 if (fr_checkl4sum(fin) == -1)
1170 1170 return -1;
1171 1171 #endif
1172 1172
1173 1173 qpi = fin->fin_qpi;
1174 1174
1175 1175 #ifdef USE_INET6
1176 1176 mb = fin->fin_qfm;
1177 1177
1178 1178 if (fin->fin_v == 6) {
1179 1179 sz = sizeof(ip6_t);
1180 1180 sz += MIN(mb->b_wptr - mb->b_rptr, 512);
1181 1181 hlen = sizeof(ip6_t);
1182 1182 type = icmptoicmp6types[type];
1183 1183 if (type == ICMP6_DST_UNREACH)
1184 1184 code = icmptoicmp6unreach[code];
1185 1185 } else
1186 1186 #endif
1187 1187 {
1188 1188 if ((fin->fin_p == IPPROTO_ICMP) &&
1189 1189 !(fin->fin_flx & FI_SHORT))
1190 1190 switch (ntohs(fin->fin_data[0]) >> 8)
1191 1191 {
1192 1192 case ICMP_ECHO :
1193 1193 case ICMP_TSTAMP :
1194 1194 case ICMP_IREQ :
1195 1195 case ICMP_MASKREQ :
1196 1196 break;
1197 1197 default :
1198 1198 return 0;
1199 1199 }
1200 1200
1201 1201 sz = sizeof(ip_t) * 2;
1202 1202 sz += 8; /* 64 bits of data */
1203 1203 hlen = sizeof(ip_t);
1204 1204 }
1205 1205
1206 1206 sz += offsetof(struct icmp, icmp_ip);
1207 1207 if ((m = (mblk_t *)allocb((size_t)sz + 64, BPRI_HI)) == NULL)
1208 1208 return -1;
1209 1209 MTYPE(m) = M_DATA;
1210 1210 m->b_rptr += 64;
1211 1211 m->b_wptr = m->b_rptr + sz;
1212 1212 bzero((char *)m->b_rptr, (size_t)sz);
1213 1213 ip = (ip_t *)m->b_rptr;
1214 1214 ip->ip_v = fin->fin_v;
1215 1215 icmp = (struct icmp *)(m->b_rptr + hlen);
1216 1216 icmp->icmp_type = type & 0xff;
1217 1217 icmp->icmp_code = code & 0xff;
1218 1218 phy = (phy_if_t)qpi->qpi_ill;
1219 1219 if (type == ICMP_UNREACH && (phy != 0) &&
1220 1220 fin->fin_icode == ICMP_UNREACH_NEEDFRAG)
1221 1221 icmp->icmp_nextmtu = net_getmtu(ifs->ifs_ipf_ipv4, phy,0 );
1222 1222
1223 1223 #ifdef USE_INET6
1224 1224 if (fin->fin_v == 6) {
1225 1225 struct in6_addr dst6;
1226 1226 int csz;
1227 1227
1228 1228 if (dst == 0) {
1229 1229 ipf_stack_t *ifs = fin->fin_ifs;
1230 1230
1231 1231 if (fr_ifpaddr(6, FRI_NORMAL, (void *)phy,
1232 1232 (void *)&dst6, NULL, ifs) == -1) {
1233 1233 FREE_MB_T(m);
1234 1234 return -1;
1235 1235 }
1236 1236 } else
1237 1237 dst6 = fin->fin_dst6.in6;
1238 1238
1239 1239 csz = sz;
1240 1240 sz -= sizeof(ip6_t);
1241 1241 ip6 = (ip6_t *)m->b_rptr;
1242 1242 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
1243 1243 ip6->ip6_plen = htons((u_short)sz);
1244 1244 ip6->ip6_nxt = IPPROTO_ICMPV6;
1245 1245 ip6->ip6_src = dst6;
1246 1246 ip6->ip6_dst = fin->fin_src6.in6;
1247 1247 sz -= offsetof(struct icmp, icmp_ip);
1248 1248 bcopy((char *)mb->b_rptr, (char *)&icmp->icmp_ip, sz);
1249 1249 icmp->icmp_cksum = csz - sizeof(ip6_t);
1250 1250 } else
1251 1251 #endif
1252 1252 {
1253 1253 ip->ip_hl = sizeof(*ip) >> 2;
1254 1254 ip->ip_p = IPPROTO_ICMP;
1255 1255 ip->ip_id = fin->fin_ip->ip_id;
1256 1256 ip->ip_tos = fin->fin_ip->ip_tos;
1257 1257 ip->ip_len = (u_short)sz;
1258 1258 if (dst == 0) {
1259 1259 ipf_stack_t *ifs = fin->fin_ifs;
1260 1260
1261 1261 if (fr_ifpaddr(4, FRI_NORMAL, (void *)phy,
1262 1262 (void *)&dst4, NULL, ifs) == -1) {
1263 1263 FREE_MB_T(m);
1264 1264 return -1;
1265 1265 }
1266 1266 } else {
1267 1267 dst4 = fin->fin_dst;
1268 1268 }
1269 1269 ip->ip_src = dst4;
1270 1270 ip->ip_dst = fin->fin_src;
1271 1271 bcopy((char *)fin->fin_ip, (char *)&icmp->icmp_ip,
1272 1272 sizeof(*fin->fin_ip));
1273 1273 bcopy((char *)fin->fin_ip + fin->fin_hlen,
1274 1274 (char *)&icmp->icmp_ip + sizeof(*fin->fin_ip), 8);
1275 1275 icmp->icmp_ip.ip_len = htons(icmp->icmp_ip.ip_len);
1276 1276 icmp->icmp_ip.ip_off = htons(icmp->icmp_ip.ip_off);
1277 1277 icmp->icmp_cksum = ipf_cksum((u_short *)icmp,
1278 1278 sz - sizeof(ip_t));
1279 1279 }
1280 1280
1281 1281 /*
1282 1282 * Need to exit out of these so we don't recursively call rw_enter
1283 1283 * from fr_qout.
1284 1284 */
↓ open down ↓ |
1284 lines elided |
↑ open up ↑ |
1285 1285 return fr_send_ip(fin, m, &m);
1286 1286 }
1287 1287
1288 1288 #include <sys/time.h>
1289 1289 #include <sys/varargs.h>
1290 1290
1291 1291 #ifndef _KERNEL
1292 1292 #include <stdio.h>
1293 1293 #endif
1294 1294
1295 -#define NULLADDR_RATE_LIMIT 10 /* 10 seconds */
1296 -
1297 -
1298 -/*
1299 - * Print out warning message at rate-limited speed.
1300 - */
1301 -static void rate_limit_message(ipf_stack_t *ifs,
1302 - int rate, const char *message, ...)
1303 -{
1304 - static time_t last_time = 0;
1305 - time_t now;
1306 - va_list args;
1307 - char msg_buf[256];
1308 - int need_printed = 0;
1309 -
1310 - now = ddi_get_time();
1311 -
1312 - /* make sure, no multiple entries */
1313 - ASSERT(MUTEX_NOT_HELD(&(ifs->ifs_ipf_rw.ipf_lk)));
1314 - MUTEX_ENTER(&ifs->ifs_ipf_rw);
1315 - if (now - last_time >= rate) {
1316 - need_printed = 1;
1317 - last_time = now;
1318 - }
1319 - MUTEX_EXIT(&ifs->ifs_ipf_rw);
1320 -
1321 - if (need_printed) {
1322 - va_start(args, message);
1323 - (void)vsnprintf(msg_buf, 255, message, args);
1324 - va_end(args);
1325 -#ifdef _KERNEL
1326 - cmn_err(CE_WARN, msg_buf);
1327 -#else
1328 - fprintf(std_err, msg_buf);
1329 -#endif
1330 - }
1331 -}
1332 -
1333 1295 /*
1334 1296 * Return the first IP Address associated with an interface
1335 1297 * For IPv6, we walk through the list of logical interfaces and return
1336 1298 * the address of the first one that isn't a link-local interface.
1337 1299 * We can't assume that it is :1 because another link-local address
1338 1300 * may have been assigned there.
1339 1301 */
1340 1302 /*ARGSUSED*/
1341 1303 int fr_ifpaddr(v, atype, ifptr, inp, inpmask, ifs)
1342 1304 int v, atype;
1343 1305 void *ifptr;
1344 1306 struct in_addr *inp, *inpmask;
1345 1307 ipf_stack_t *ifs;
1346 1308 {
1347 1309 struct sockaddr_in6 v6addr[2];
1348 1310 struct sockaddr_in v4addr[2];
1349 1311 net_ifaddr_t type[2];
1350 1312 net_handle_t net_data;
1351 1313 phy_if_t phyif;
1352 1314 void *array;
1353 1315
1354 1316 switch (v)
1355 1317 {
1356 1318 case 4:
1357 1319 net_data = ifs->ifs_ipf_ipv4;
1358 1320 array = v4addr;
1359 1321 break;
1360 1322 case 6:
1361 1323 net_data = ifs->ifs_ipf_ipv6;
1362 1324 array = v6addr;
1363 1325 break;
1364 1326 default:
1365 1327 net_data = NULL;
1366 1328 break;
1367 1329 }
1368 1330
1369 1331 if (net_data == NULL)
1370 1332 return -1;
1371 1333
1372 1334 phyif = (phy_if_t)ifptr;
1373 1335
1374 1336 switch (atype)
1375 1337 {
1376 1338 case FRI_PEERADDR :
1377 1339 type[0] = NA_PEER;
1378 1340 break;
1379 1341
1380 1342 case FRI_BROADCAST :
1381 1343 type[0] = NA_BROADCAST;
1382 1344 break;
1383 1345
1384 1346 default :
1385 1347 type[0] = NA_ADDRESS;
1386 1348 break;
1387 1349 }
1388 1350
1389 1351 type[1] = NA_NETMASK;
1390 1352
1391 1353 if (v == 6) {
1392 1354 lif_if_t idx = 0;
1393 1355
1394 1356 do {
1395 1357 idx = net_lifgetnext(net_data, phyif, idx);
1396 1358 if (net_getlifaddr(net_data, phyif, idx, 2, type,
1397 1359 array) < 0)
1398 1360 return -1;
1399 1361 if (!IN6_IS_ADDR_LINKLOCAL(&v6addr[0].sin6_addr) &&
1400 1362 !IN6_IS_ADDR_MULTICAST(&v6addr[0].sin6_addr))
1401 1363 break;
1402 1364 } while (idx != 0);
1403 1365
1404 1366 if (idx == 0)
1405 1367 return -1;
1406 1368
1407 1369 return fr_ifpfillv6addr(atype, &v6addr[0], &v6addr[1],
1408 1370 inp, inpmask);
1409 1371 }
1410 1372
1411 1373 if (net_getlifaddr(net_data, phyif, 0, 2, type, array) < 0)
1412 1374 return -1;
1413 1375
1414 1376 return fr_ifpfillv4addr(atype, &v4addr[0], &v4addr[1], inp, inpmask);
1415 1377 }
1416 1378
1417 1379
1418 1380 u_32_t fr_newisn(fin)
1419 1381 fr_info_t *fin;
1420 1382 {
1421 1383 static int iss_seq_off = 0;
1422 1384 u_char hash[16];
1423 1385 u_32_t newiss;
1424 1386 MD5_CTX ctx;
1425 1387 ipf_stack_t *ifs = fin->fin_ifs;
1426 1388
1427 1389 /*
1428 1390 * Compute the base value of the ISS. It is a hash
1429 1391 * of (saddr, sport, daddr, dport, secret).
1430 1392 */
1431 1393 MD5Init(&ctx);
1432 1394
1433 1395 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
1434 1396 sizeof(fin->fin_fi.fi_src));
1435 1397 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
1436 1398 sizeof(fin->fin_fi.fi_dst));
1437 1399 MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
1438 1400
1439 1401 MD5Update(&ctx, ifs->ifs_ipf_iss_secret, sizeof(ifs->ifs_ipf_iss_secret));
1440 1402
1441 1403 MD5Final(hash, &ctx);
1442 1404
1443 1405 bcopy(hash, &newiss, sizeof(newiss));
1444 1406
1445 1407 /*
1446 1408 * Now increment our "timer", and add it in to
1447 1409 * the computed value.
1448 1410 *
1449 1411 * XXX Use `addin'?
1450 1412 * XXX TCP_ISSINCR too large to use?
1451 1413 */
1452 1414 iss_seq_off += 0x00010000;
1453 1415 newiss += iss_seq_off;
1454 1416 return newiss;
1455 1417 }
1456 1418
1457 1419
1458 1420 /* ------------------------------------------------------------------------ */
1459 1421 /* Function: fr_nextipid */
1460 1422 /* Returns: int - 0 == success, -1 == error (packet should be droppped) */
1461 1423 /* Parameters: fin(I) - pointer to packet information */
1462 1424 /* */
1463 1425 /* Returns the next IPv4 ID to use for this packet. */
1464 1426 /* ------------------------------------------------------------------------ */
1465 1427 u_short fr_nextipid(fin)
1466 1428 fr_info_t *fin;
1467 1429 {
1468 1430 static u_short ipid = 0;
1469 1431 u_short id;
1470 1432 ipf_stack_t *ifs = fin->fin_ifs;
1471 1433
1472 1434 MUTEX_ENTER(&ifs->ifs_ipf_rw);
1473 1435 if (fin->fin_pktnum != 0) {
1474 1436 id = fin->fin_pktnum & 0xffff;
1475 1437 } else {
1476 1438 id = ipid++;
1477 1439 }
1478 1440 MUTEX_EXIT(&ifs->ifs_ipf_rw);
1479 1441
1480 1442 return id;
1481 1443 }
1482 1444
1483 1445
1484 1446 #ifndef IPFILTER_CKSUM
1485 1447 /* ARGSUSED */
1486 1448 #endif
1487 1449 INLINE void fr_checkv4sum(fin)
1488 1450 fr_info_t *fin;
1489 1451 {
1490 1452 #ifdef IPFILTER_CKSUM
1491 1453 if (fr_checkl4sum(fin) == -1)
1492 1454 fin->fin_flx |= FI_BAD;
1493 1455 #endif
1494 1456 }
1495 1457
1496 1458
1497 1459 #ifdef USE_INET6
1498 1460 # ifndef IPFILTER_CKSUM
1499 1461 /* ARGSUSED */
1500 1462 # endif
1501 1463 INLINE void fr_checkv6sum(fin)
1502 1464 fr_info_t *fin;
1503 1465 {
1504 1466 # ifdef IPFILTER_CKSUM
1505 1467 if (fr_checkl4sum(fin) == -1)
1506 1468 fin->fin_flx |= FI_BAD;
1507 1469 # endif
1508 1470 }
1509 1471 #endif /* USE_INET6 */
1510 1472
1511 1473
1512 1474 #if (SOLARIS2 < 7)
1513 1475 void fr_slowtimer()
1514 1476 #else
1515 1477 /*ARGSUSED*/
1516 1478 void fr_slowtimer __P((void *arg))
1517 1479 #endif
1518 1480 {
1519 1481 ipf_stack_t *ifs = arg;
1520 1482
1521 1483 READ_ENTER(&ifs->ifs_ipf_global);
1522 1484 if (ifs->ifs_fr_running != 1) {
1523 1485 ifs->ifs_fr_timer_id = NULL;
1524 1486 RWLOCK_EXIT(&ifs->ifs_ipf_global);
1525 1487 return;
1526 1488 }
1527 1489 ipf_expiretokens(ifs);
1528 1490 fr_fragexpire(ifs);
1529 1491 fr_timeoutstate(ifs);
1530 1492 fr_natexpire(ifs);
1531 1493 fr_authexpire(ifs);
1532 1494 ifs->ifs_fr_ticks++;
1533 1495 if (ifs->ifs_fr_running == 1)
1534 1496 ifs->ifs_fr_timer_id = timeout(fr_slowtimer, arg,
1535 1497 drv_usectohz(500000));
1536 1498 else
1537 1499 ifs->ifs_fr_timer_id = NULL;
1538 1500 RWLOCK_EXIT(&ifs->ifs_ipf_global);
1539 1501 }
1540 1502
1541 1503
1542 1504 /* ------------------------------------------------------------------------ */
1543 1505 /* Function: fr_pullup */
1544 1506 /* Returns: NULL == pullup failed, else pointer to protocol header */
1545 1507 /* Parameters: m(I) - pointer to buffer where data packet starts */
1546 1508 /* fin(I) - pointer to packet information */
1547 1509 /* len(I) - number of bytes to pullup */
1548 1510 /* */
1549 1511 /* Attempt to move at least len bytes (from the start of the buffer) into a */
1550 1512 /* single buffer for ease of access. Operating system native functions are */
1551 1513 /* used to manage buffers - if necessary. If the entire packet ends up in */
1552 1514 /* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */
1553 1515 /* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */
1554 1516 /* and ONLY if the pullup succeeds. */
1555 1517 /* */
1556 1518 /* We assume that 'min' is a pointer to a buffer that is part of the chain */
1557 1519 /* of buffers that starts at *fin->fin_mp. */
1558 1520 /* ------------------------------------------------------------------------ */
1559 1521 void *fr_pullup(min, fin, len)
1560 1522 mb_t *min;
1561 1523 fr_info_t *fin;
1562 1524 int len;
1563 1525 {
1564 1526 qpktinfo_t *qpi = fin->fin_qpi;
1565 1527 int out = fin->fin_out, dpoff, ipoff;
1566 1528 mb_t *m = min, *m1, *m2;
1567 1529 char *ip;
1568 1530 uint32_t start, stuff, end, value, flags;
1569 1531 ipf_stack_t *ifs = fin->fin_ifs;
1570 1532
1571 1533 if (m == NULL)
1572 1534 return NULL;
1573 1535
1574 1536 ip = (char *)fin->fin_ip;
1575 1537 if ((fin->fin_flx & FI_COALESCE) != 0)
1576 1538 return ip;
1577 1539
1578 1540 ipoff = fin->fin_ipoff;
1579 1541 if (fin->fin_dp != NULL)
1580 1542 dpoff = (char *)fin->fin_dp - (char *)ip;
1581 1543 else
1582 1544 dpoff = 0;
1583 1545
1584 1546 if (M_LEN(m) < len + ipoff) {
1585 1547
1586 1548 /*
1587 1549 * pfil_precheck ensures the IP header is on a 32bit
1588 1550 * aligned address so simply fail if that isn't currently
1589 1551 * the case (should never happen).
1590 1552 */
1591 1553 int inc = 0;
1592 1554
1593 1555 if (ipoff > 0) {
1594 1556 if ((ipoff & 3) != 0) {
1595 1557 inc = 4 - (ipoff & 3);
1596 1558 if (m->b_rptr - inc >= m->b_datap->db_base)
1597 1559 m->b_rptr -= inc;
1598 1560 else
1599 1561 inc = 0;
1600 1562 }
1601 1563 }
1602 1564
1603 1565 /*
1604 1566 * XXX This is here as a work around for a bug with DEBUG
1605 1567 * XXX Solaris kernels. The problem is b_prev is used by IP
1606 1568 * XXX code as a way to stash the phyint_index for a packet,
1607 1569 * XXX this doesn't get reset by IP but freeb does an ASSERT()
1608 1570 * XXX for both of these to be NULL. See 6442390.
1609 1571 */
1610 1572 m1 = m;
1611 1573 m2 = m->b_prev;
1612 1574
1613 1575 do {
1614 1576 m1->b_next = NULL;
1615 1577 m1->b_prev = NULL;
1616 1578 m1 = m1->b_cont;
1617 1579 } while (m1);
1618 1580
1619 1581 /*
1620 1582 * Need to preserve checksum information by copying them
1621 1583 * to newmp which heads the pulluped message.
1622 1584 */
1623 1585 hcksum_retrieve(m, NULL, NULL, &start, &stuff, &end,
1624 1586 &value, &flags);
1625 1587
1626 1588 if (pullupmsg(m, len + ipoff + inc) == 0) {
1627 1589 ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[1]);
1628 1590 FREE_MB_T(*fin->fin_mp);
1629 1591 *fin->fin_mp = NULL;
1630 1592 fin->fin_m = NULL;
1631 1593 fin->fin_ip = NULL;
1632 1594 fin->fin_dp = NULL;
1633 1595 qpi->qpi_data = NULL;
1634 1596 return NULL;
1635 1597 }
1636 1598
1637 1599 (void) hcksum_assoc(m, NULL, NULL, start, stuff, end,
1638 1600 value, flags, 0);
1639 1601
1640 1602 m->b_prev = m2;
1641 1603 m->b_rptr += inc;
1642 1604 fin->fin_m = m;
1643 1605 ip = MTOD(m, char *) + ipoff;
1644 1606 qpi->qpi_data = ip;
1645 1607 }
1646 1608
1647 1609 ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[0]);
1648 1610 fin->fin_ip = (ip_t *)ip;
1649 1611 if (fin->fin_dp != NULL)
1650 1612 fin->fin_dp = (char *)fin->fin_ip + dpoff;
1651 1613
1652 1614 if (len == fin->fin_plen)
1653 1615 fin->fin_flx |= FI_COALESCE;
1654 1616 return ip;
1655 1617 }
1656 1618
1657 1619
1658 1620 /*
1659 1621 * Function: fr_verifysrc
1660 1622 * Returns: int (really boolean)
1661 1623 * Parameters: fin - packet information
1662 1624 *
1663 1625 * Check whether the packet has a valid source address for the interface on
1664 1626 * which the packet arrived, implementing the "fr_chksrc" feature.
1665 1627 * Returns true iff the packet's source address is valid.
1666 1628 */
1667 1629 int fr_verifysrc(fin)
1668 1630 fr_info_t *fin;
1669 1631 {
1670 1632 net_handle_t net_data_p;
1671 1633 phy_if_t phy_ifdata_routeto;
1672 1634 struct sockaddr sin;
1673 1635 ipf_stack_t *ifs = fin->fin_ifs;
1674 1636
1675 1637 if (fin->fin_v == 4) {
1676 1638 net_data_p = ifs->ifs_ipf_ipv4;
1677 1639 } else if (fin->fin_v == 6) {
1678 1640 net_data_p = ifs->ifs_ipf_ipv6;
1679 1641 } else {
1680 1642 return (0);
1681 1643 }
1682 1644
1683 1645 /* Get the index corresponding to the if name */
1684 1646 sin.sa_family = (fin->fin_v == 4) ? AF_INET : AF_INET6;
1685 1647 bcopy(&fin->fin_saddr, &sin.sa_data, sizeof (struct in_addr));
1686 1648 phy_ifdata_routeto = net_routeto(net_data_p, &sin, NULL);
1687 1649
1688 1650 return (((phy_if_t)fin->fin_ifp == phy_ifdata_routeto) ? 1 : 0);
1689 1651 }
1690 1652
1691 1653
1692 1654 /*
1693 1655 * Function: fr_fastroute
1694 1656 * Returns: 0: success;
1695 1657 * -1: failed
1696 1658 * Parameters:
1697 1659 * mb: the message block where ip head starts
1698 1660 * mpp: the pointer to the pointer of the orignal
1699 1661 * packet message
1700 1662 * fin: packet information
1701 1663 * fdp: destination interface information
1702 1664 * if it is NULL, no interface information provided.
1703 1665 *
1704 1666 * This function is for fastroute/to/dup-to rules. It calls
1705 1667 * pfil_make_lay2_packet to search route, make lay-2 header
1706 1668 * ,and identify output queue for the IP packet.
1707 1669 * The destination address depends on the following conditions:
1708 1670 * 1: for fastroute rule, fdp is passed in as NULL, so the
1709 1671 * destination address is the IP Packet's destination address
1710 1672 * 2: for to/dup-to rule, if an ip address is specified after
1711 1673 * the interface name, this address is the as destination
1712 1674 * address. Otherwise IP Packet's destination address is used
1713 1675 */
1714 1676 int fr_fastroute(mb, mpp, fin, fdp)
1715 1677 mblk_t *mb, **mpp;
1716 1678 fr_info_t *fin;
1717 1679 frdest_t *fdp;
1718 1680 {
1719 1681 net_handle_t net_data_p;
1720 1682 net_inject_t *inj;
1721 1683 mblk_t *mp = NULL;
1722 1684 frentry_t *fr = fin->fin_fr;
1723 1685 qpktinfo_t *qpi;
1724 1686 ip_t *ip;
1725 1687
1726 1688 struct sockaddr_in *sin;
1727 1689 struct sockaddr_in6 *sin6;
1728 1690 struct sockaddr *sinp;
1729 1691 ipf_stack_t *ifs = fin->fin_ifs;
1730 1692 #ifndef sparc
1731 1693 u_short __iplen, __ipoff;
1732 1694 #endif
1733 1695
1734 1696 if (fin->fin_v == 4) {
1735 1697 net_data_p = ifs->ifs_ipf_ipv4;
1736 1698 } else if (fin->fin_v == 6) {
1737 1699 net_data_p = ifs->ifs_ipf_ipv6;
1738 1700 } else {
1739 1701 return (-1);
1740 1702 }
1741 1703
1742 1704 inj = net_inject_alloc(NETINFO_VERSION);
1743 1705 if (inj == NULL)
1744 1706 return -1;
1745 1707
1746 1708 ip = fin->fin_ip;
1747 1709 qpi = fin->fin_qpi;
1748 1710
1749 1711 /*
1750 1712 * If this is a duplicate mblk then we want ip to point at that
1751 1713 * data, not the original, if and only if it is already pointing at
1752 1714 * the current mblk data.
1753 1715 *
1754 1716 * Otherwise, if it's not a duplicate, and we're not already pointing
1755 1717 * at the current mblk data, then we want to ensure that the data
1756 1718 * points at ip.
1757 1719 */
1758 1720
1759 1721 if ((ip == (ip_t *)qpi->qpi_m->b_rptr) && (qpi->qpi_m != mb)) {
1760 1722 ip = (ip_t *)mb->b_rptr;
1761 1723 } else if ((qpi->qpi_m == mb) && (ip != (ip_t *)qpi->qpi_m->b_rptr)) {
1762 1724 qpi->qpi_m->b_rptr = (uchar_t *)ip;
1763 1725 qpi->qpi_off = 0;
1764 1726 }
1765 1727
1766 1728 /*
1767 1729 * If there is another M_PROTO, we don't want it
1768 1730 */
1769 1731 if (*mpp != mb) {
1770 1732 mp = unlinkb(*mpp);
1771 1733 freeb(*mpp);
1772 1734 *mpp = mp;
1773 1735 }
1774 1736
1775 1737 sinp = (struct sockaddr *)&inj->ni_addr;
1776 1738 sin = (struct sockaddr_in *)sinp;
1777 1739 sin6 = (struct sockaddr_in6 *)sinp;
1778 1740 bzero((char *)&inj->ni_addr, sizeof (inj->ni_addr));
1779 1741 inj->ni_addr.ss_family = (fin->fin_v == 4) ? AF_INET : AF_INET6;
1780 1742 inj->ni_packet = mb;
1781 1743
1782 1744 /*
1783 1745 * In case we're here due to "to <if>" being used with
1784 1746 * "keep state", check that we're going in the correct
1785 1747 * direction.
1786 1748 */
1787 1749 if (fdp != NULL) {
1788 1750 if ((fr != NULL) && (fdp->fd_ifp != NULL) &&
1789 1751 (fin->fin_rev != 0) && (fdp == &fr->fr_tif))
1790 1752 goto bad_fastroute;
1791 1753 inj->ni_physical = (phy_if_t)fdp->fd_ifp;
1792 1754 if (fin->fin_v == 4) {
1793 1755 sin->sin_addr = fdp->fd_ip;
1794 1756 } else {
1795 1757 sin6->sin6_addr = fdp->fd_ip6.in6;
1796 1758 }
1797 1759 } else {
1798 1760 if (fin->fin_v == 4) {
1799 1761 sin->sin_addr = ip->ip_dst;
1800 1762 } else {
1801 1763 sin6->sin6_addr = ((ip6_t *)ip)->ip6_dst;
1802 1764 }
1803 1765 inj->ni_physical = net_routeto(net_data_p, sinp, NULL);
1804 1766 }
1805 1767
1806 1768 /*
1807 1769 * Clear the hardware checksum flags from packets that we are doing
1808 1770 * input processing on as leaving them set will cause the outgoing
1809 1771 * NIC (if it supports hardware checksum) to calculate them anew,
1810 1772 * using the old (correct) checksums as the pseudo value to start
1811 1773 * from.
1812 1774 */
1813 1775 if (fin->fin_out == 0) {
1814 1776 DB_CKSUMFLAGS(mb) = 0;
1815 1777 }
1816 1778
1817 1779 *mpp = mb;
1818 1780
1819 1781 if (fin->fin_out == 0) {
1820 1782 void *saveifp;
1821 1783 u_32_t pass;
1822 1784
1823 1785 saveifp = fin->fin_ifp;
1824 1786 fin->fin_ifp = (void *)inj->ni_physical;
1825 1787 fin->fin_flx &= ~FI_STATE;
1826 1788 fin->fin_out = 1;
1827 1789 (void) fr_acctpkt(fin, &pass);
1828 1790 fin->fin_fr = NULL;
1829 1791 if (!fr || !(fr->fr_flags & FR_RETMASK))
1830 1792 (void) fr_checkstate(fin, &pass);
1831 1793 if (fr_checknatout(fin, NULL) == -1)
1832 1794 goto bad_fastroute;
1833 1795 fin->fin_out = 0;
1834 1796 fin->fin_ifp = saveifp;
1835 1797 }
1836 1798 #ifndef sparc
1837 1799 if (fin->fin_v == 4) {
1838 1800 __iplen = (u_short)ip->ip_len,
1839 1801 __ipoff = (u_short)ip->ip_off;
1840 1802
1841 1803 ip->ip_len = htons(__iplen);
1842 1804 ip->ip_off = htons(__ipoff);
1843 1805 }
1844 1806 #endif
1845 1807
1846 1808 if (net_data_p) {
1847 1809 if (net_inject(net_data_p, NI_DIRECT_OUT, inj) < 0) {
1848 1810 net_inject_free(inj);
1849 1811 return (-1);
1850 1812 }
1851 1813 }
1852 1814
1853 1815 ifs->ifs_fr_frouteok[0]++;
1854 1816 net_inject_free(inj);
1855 1817 return 0;
1856 1818 bad_fastroute:
1857 1819 net_inject_free(inj);
1858 1820 freemsg(mb);
1859 1821 ifs->ifs_fr_frouteok[1]++;
1860 1822 return -1;
1861 1823 }
1862 1824
1863 1825
1864 1826 /* ------------------------------------------------------------------------ */
1865 1827 /* Function: ipf_hook4_out */
1866 1828 /* Returns: int - 0 == packet ok, else problem, free packet if not done */
1867 1829 /* Parameters: event(I) - pointer to event */
1868 1830 /* info(I) - pointer to hook information for firewalling */
1869 1831 /* */
1870 1832 /* Calling ipf_hook. */
1871 1833 /* ------------------------------------------------------------------------ */
1872 1834 /*ARGSUSED*/
1873 1835 int ipf_hook4_out(hook_event_token_t token, hook_data_t info, void *arg)
1874 1836 {
1875 1837 return ipf_hook(info, 1, 0, arg);
1876 1838 }
1877 1839 /*ARGSUSED*/
1878 1840 int ipf_hook6_out(hook_event_token_t token, hook_data_t info, void *arg)
1879 1841 {
1880 1842 return ipf_hook6(info, 1, 0, arg);
1881 1843 }
1882 1844
1883 1845 /* ------------------------------------------------------------------------ */
1884 1846 /* Function: ipf_hook4_in */
1885 1847 /* Returns: int - 0 == packet ok, else problem, free packet if not done */
1886 1848 /* Parameters: event(I) - pointer to event */
1887 1849 /* info(I) - pointer to hook information for firewalling */
1888 1850 /* */
1889 1851 /* Calling ipf_hook. */
1890 1852 /* ------------------------------------------------------------------------ */
1891 1853 /*ARGSUSED*/
1892 1854 int ipf_hook4_in(hook_event_token_t token, hook_data_t info, void *arg)
1893 1855 {
1894 1856 return ipf_hook(info, 0, 0, arg);
1895 1857 }
1896 1858 /*ARGSUSED*/
1897 1859 int ipf_hook6_in(hook_event_token_t token, hook_data_t info, void *arg)
1898 1860 {
1899 1861 return ipf_hook6(info, 0, 0, arg);
1900 1862 }
1901 1863
1902 1864
1903 1865 /* ------------------------------------------------------------------------ */
1904 1866 /* Function: ipf_hook4_loop_out */
1905 1867 /* Returns: int - 0 == packet ok, else problem, free packet if not done */
1906 1868 /* Parameters: event(I) - pointer to event */
1907 1869 /* info(I) - pointer to hook information for firewalling */
1908 1870 /* */
1909 1871 /* Calling ipf_hook. */
1910 1872 /* ------------------------------------------------------------------------ */
1911 1873 /*ARGSUSED*/
1912 1874 int ipf_hook4_loop_out(hook_event_token_t token, hook_data_t info, void *arg)
1913 1875 {
1914 1876 return ipf_hook(info, 1, FI_NOCKSUM, arg);
1915 1877 }
1916 1878 /*ARGSUSED*/
1917 1879 int ipf_hook6_loop_out(hook_event_token_t token, hook_data_t info, void *arg)
1918 1880 {
1919 1881 return ipf_hook6(info, 1, FI_NOCKSUM, arg);
1920 1882 }
1921 1883
1922 1884 /* ------------------------------------------------------------------------ */
1923 1885 /* Function: ipf_hook4_loop_in */
1924 1886 /* Returns: int - 0 == packet ok, else problem, free packet if not done */
1925 1887 /* Parameters: event(I) - pointer to event */
1926 1888 /* info(I) - pointer to hook information for firewalling */
1927 1889 /* */
1928 1890 /* Calling ipf_hook. */
1929 1891 /* ------------------------------------------------------------------------ */
1930 1892 /*ARGSUSED*/
1931 1893 int ipf_hook4_loop_in(hook_event_token_t token, hook_data_t info, void *arg)
1932 1894 {
1933 1895 return ipf_hook(info, 0, FI_NOCKSUM, arg);
1934 1896 }
1935 1897 /*ARGSUSED*/
1936 1898 int ipf_hook6_loop_in(hook_event_token_t token, hook_data_t info, void *arg)
1937 1899 {
1938 1900 return ipf_hook6(info, 0, FI_NOCKSUM, arg);
1939 1901 }
1940 1902
1941 1903 /* ------------------------------------------------------------------------ */
1942 1904 /* Function: ipf_hook */
1943 1905 /* Returns: int - 0 == packet ok, else problem, free packet if not done */
1944 1906 /* Parameters: info(I) - pointer to hook information for firewalling */
1945 1907 /* out(I) - whether packet is going in or out */
1946 1908 /* loopback(I) - whether packet is a loopback packet or not */
1947 1909 /* */
1948 1910 /* Stepping stone function between the IP mainline and IPFilter. Extracts */
1949 1911 /* parameters out of the info structure and forms them up to be useful for */
1950 1912 /* calling ipfilter. */
1951 1913 /* ------------------------------------------------------------------------ */
1952 1914 int ipf_hook(hook_data_t info, int out, int loopback, void *arg)
1953 1915 {
1954 1916 hook_pkt_event_t *fw;
1955 1917 ipf_stack_t *ifs;
1956 1918 qpktinfo_t qpi;
1957 1919 int rval, hlen;
1958 1920 u_short swap;
1959 1921 phy_if_t phy;
1960 1922 ip_t *ip;
1961 1923
1962 1924 ifs = arg;
1963 1925 fw = (hook_pkt_event_t *)info;
1964 1926
1965 1927 ASSERT(fw != NULL);
1966 1928 phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp;
1967 1929
1968 1930 ip = fw->hpe_hdr;
1969 1931 swap = ntohs(ip->ip_len);
1970 1932 ip->ip_len = swap;
1971 1933 swap = ntohs(ip->ip_off);
1972 1934 ip->ip_off = swap;
1973 1935 hlen = IPH_HDR_LENGTH(ip);
1974 1936
1975 1937 qpi.qpi_m = fw->hpe_mb;
1976 1938 qpi.qpi_data = fw->hpe_hdr;
1977 1939 qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr;
1978 1940 qpi.qpi_ill = (void *)phy;
1979 1941 qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST);
1980 1942 if (qpi.qpi_flags)
1981 1943 qpi.qpi_flags |= FI_MBCAST;
1982 1944 qpi.qpi_flags |= loopback;
1983 1945
1984 1946 rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out,
1985 1947 &qpi, fw->hpe_mp, ifs);
1986 1948
1987 1949 /* For fastroute cases, fr_check returns 0 with mp set to NULL */
1988 1950 if (rval == 0 && *(fw->hpe_mp) == NULL)
1989 1951 rval = 1;
1990 1952
1991 1953 /* Notify IP the packet mblk_t and IP header pointers. */
1992 1954 fw->hpe_mb = qpi.qpi_m;
1993 1955 fw->hpe_hdr = qpi.qpi_data;
1994 1956 if (rval == 0) {
1995 1957 ip = qpi.qpi_data;
1996 1958 swap = ntohs(ip->ip_len);
1997 1959 ip->ip_len = swap;
1998 1960 swap = ntohs(ip->ip_off);
1999 1961 ip->ip_off = swap;
2000 1962 }
2001 1963 return rval;
2002 1964
2003 1965 }
2004 1966 int ipf_hook6(hook_data_t info, int out, int loopback, void *arg)
2005 1967 {
2006 1968 hook_pkt_event_t *fw;
2007 1969 int rval, hlen;
2008 1970 qpktinfo_t qpi;
2009 1971 phy_if_t phy;
2010 1972
2011 1973 fw = (hook_pkt_event_t *)info;
2012 1974
2013 1975 ASSERT(fw != NULL);
2014 1976 phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp;
2015 1977
2016 1978 hlen = sizeof (ip6_t);
2017 1979
2018 1980 qpi.qpi_m = fw->hpe_mb;
2019 1981 qpi.qpi_data = fw->hpe_hdr;
2020 1982 qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr;
2021 1983 qpi.qpi_ill = (void *)phy;
2022 1984 qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST);
2023 1985 if (qpi.qpi_flags)
2024 1986 qpi.qpi_flags |= FI_MBCAST;
2025 1987 qpi.qpi_flags |= loopback;
2026 1988
2027 1989 rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out,
2028 1990 &qpi, fw->hpe_mp, arg);
2029 1991
2030 1992 /* For fastroute cases, fr_check returns 0 with mp set to NULL */
2031 1993 if (rval == 0 && *(fw->hpe_mp) == NULL)
2032 1994 rval = 1;
2033 1995
2034 1996 /* Notify IP the packet mblk_t and IP header pointers. */
2035 1997 fw->hpe_mb = qpi.qpi_m;
2036 1998 fw->hpe_hdr = qpi.qpi_data;
2037 1999 return rval;
2038 2000
2039 2001 }
2040 2002
2041 2003
2042 2004 /* ------------------------------------------------------------------------ */
2043 2005 /* Function: ipf_nic_event_v4 */
2044 2006 /* Returns: int - 0 == no problems encountered */
2045 2007 /* Parameters: event(I) - pointer to event */
2046 2008 /* info(I) - pointer to information about a NIC event */
2047 2009 /* */
2048 2010 /* Function to receive asynchronous NIC events from IP */
2049 2011 /* ------------------------------------------------------------------------ */
2050 2012 /*ARGSUSED*/
2051 2013 int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info, void *arg)
2052 2014 {
2053 2015 struct sockaddr_in *sin;
2054 2016 hook_nic_event_t *hn;
2055 2017 ipf_stack_t *ifs = arg;
2056 2018 void *new_ifp = NULL;
2057 2019
2058 2020 if (ifs->ifs_fr_running <= 0)
2059 2021 return (0);
2060 2022
2061 2023 hn = (hook_nic_event_t *)info;
2062 2024
2063 2025 switch (hn->hne_event)
2064 2026 {
2065 2027 case NE_PLUMB :
2066 2028 frsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, hn->hne_data,
2067 2029 ifs);
2068 2030 fr_natifpsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic,
2069 2031 hn->hne_data, ifs);
2070 2032 fr_statesync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic,
2071 2033 hn->hne_data, ifs);
2072 2034 break;
2073 2035
2074 2036 case NE_UNPLUMB :
2075 2037 frsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs);
2076 2038 fr_natifpsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL,
2077 2039 ifs);
2078 2040 fr_statesync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs);
2079 2041 break;
2080 2042
2081 2043 case NE_ADDRESS_CHANGE :
2082 2044 /*
2083 2045 * We only respond to events for logical interface 0 because
2084 2046 * IPFilter only uses the first address given to a network
2085 2047 * interface. We check for hne_lif==1 because the netinfo
2086 2048 * code maps adds 1 to the lif number so that it can return
2087 2049 * 0 to indicate "no more lifs" when walking them.
2088 2050 */
2089 2051 if (hn->hne_lif == 1) {
2090 2052 frsync(IPFSYNC_RESYNC, 4, (void *)hn->hne_nic, NULL,
2091 2053 ifs);
2092 2054 sin = hn->hne_data;
2093 2055 fr_nataddrsync(4, (void *)hn->hne_nic, &sin->sin_addr,
2094 2056 ifs);
2095 2057 }
2096 2058 break;
2097 2059
2098 2060 #if SOLARIS2 >= 10
2099 2061 case NE_IFINDEX_CHANGE :
2100 2062 WRITE_ENTER(&ifs->ifs_ipf_mutex);
2101 2063
2102 2064 if (hn->hne_data != NULL) {
2103 2065 /*
2104 2066 * The netinfo passes interface index as int (hne_data should be
2105 2067 * handled as a pointer to int), which is always 32bit. We need to
2106 2068 * convert it to void pointer here, since interfaces are
2107 2069 * represented as pointers to void in IPF. The pointers are 64 bits
2108 2070 * long on 64bit platforms. Doing something like
2109 2071 * (void *)((int) x)
2110 2072 * will throw warning:
2111 2073 * "cast to pointer from integer of different size"
2112 2074 * during 64bit compilation.
2113 2075 *
2114 2076 * The line below uses (size_t) to typecast int to
2115 2077 * size_t, which might be 64bit/32bit (depending
2116 2078 * on architecture). Once we have proper 64bit/32bit
2117 2079 * type (size_t), we can safely convert it to void pointer.
2118 2080 */
2119 2081 new_ifp = (void *)(size_t)*((int *)hn->hne_data);
2120 2082 fr_ifindexsync((void *)hn->hne_nic, new_ifp, ifs);
2121 2083 fr_natifindexsync((void *)hn->hne_nic, new_ifp, ifs);
2122 2084 fr_stateifindexsync((void *)hn->hne_nic, new_ifp, ifs);
2123 2085 }
2124 2086 RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
2125 2087 break;
2126 2088 #endif
2127 2089
2128 2090 default :
2129 2091 break;
2130 2092 }
2131 2093
2132 2094 return 0;
2133 2095 }
2134 2096
2135 2097
2136 2098 /* ------------------------------------------------------------------------ */
2137 2099 /* Function: ipf_nic_event_v6 */
2138 2100 /* Returns: int - 0 == no problems encountered */
2139 2101 /* Parameters: event(I) - pointer to event */
2140 2102 /* info(I) - pointer to information about a NIC event */
2141 2103 /* */
2142 2104 /* Function to receive asynchronous NIC events from IP */
2143 2105 /* ------------------------------------------------------------------------ */
2144 2106 /*ARGSUSED*/
2145 2107 int ipf_nic_event_v6(hook_event_token_t event, hook_data_t info, void *arg)
2146 2108 {
2147 2109 struct sockaddr_in6 *sin6;
2148 2110 hook_nic_event_t *hn;
2149 2111 ipf_stack_t *ifs = arg;
2150 2112 void *new_ifp = NULL;
2151 2113
2152 2114 if (ifs->ifs_fr_running <= 0)
2153 2115 return (0);
2154 2116
2155 2117 hn = (hook_nic_event_t *)info;
2156 2118
2157 2119 switch (hn->hne_event)
2158 2120 {
2159 2121 case NE_PLUMB :
2160 2122 frsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic,
2161 2123 hn->hne_data, ifs);
2162 2124 fr_natifpsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic,
2163 2125 hn->hne_data, ifs);
2164 2126 fr_statesync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic,
2165 2127 hn->hne_data, ifs);
2166 2128 break;
2167 2129
2168 2130 case NE_UNPLUMB :
2169 2131 frsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs);
2170 2132 fr_natifpsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL,
2171 2133 ifs);
2172 2134 fr_statesync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs);
2173 2135 break;
2174 2136
2175 2137 case NE_ADDRESS_CHANGE :
2176 2138 if (hn->hne_lif == 1) {
2177 2139 sin6 = hn->hne_data;
2178 2140 fr_nataddrsync(6, (void *)hn->hne_nic, &sin6->sin6_addr,
2179 2141 ifs);
2180 2142 }
2181 2143 break;
2182 2144
2183 2145 #if SOLARIS2 >= 10
2184 2146 case NE_IFINDEX_CHANGE :
2185 2147 WRITE_ENTER(&ifs->ifs_ipf_mutex);
2186 2148 if (hn->hne_data != NULL) {
2187 2149 /*
2188 2150 * The netinfo passes interface index as int (hne_data should be
2189 2151 * handled as a pointer to int), which is always 32bit. We need to
2190 2152 * convert it to void pointer here, since interfaces are
2191 2153 * represented as pointers to void in IPF. The pointers are 64 bits
2192 2154 * long on 64bit platforms. Doing something like
2193 2155 * (void *)((int) x)
2194 2156 * will throw warning:
2195 2157 * "cast to pointer from integer of different size"
2196 2158 * during 64bit compilation.
2197 2159 *
2198 2160 * The line below uses (size_t) to typecast int to
2199 2161 * size_t, which might be 64bit/32bit (depending
2200 2162 * on architecture). Once we have proper 64bit/32bit
2201 2163 * type (size_t), we can safely convert it to void pointer.
2202 2164 */
2203 2165 new_ifp = (void *)(size_t)*((int *)hn->hne_data);
2204 2166 fr_ifindexsync((void *)hn->hne_nic, new_ifp, ifs);
2205 2167 fr_natifindexsync((void *)hn->hne_nic, new_ifp, ifs);
2206 2168 fr_stateifindexsync((void *)hn->hne_nic, new_ifp, ifs);
2207 2169 }
2208 2170 RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
2209 2171 break;
2210 2172 #endif
2211 2173
2212 2174 default :
2213 2175 break;
2214 2176 }
2215 2177
2216 2178 return 0;
2217 2179 }
2218 2180
2219 2181 /*
2220 2182 * Functions fr_make_rst(), fr_make_icmp_v4(), fr_make_icmp_v6()
2221 2183 * are needed in Solaris kernel only. We don't need them in
2222 2184 * ipftest to pretend the ICMP/RST packet was sent as a response.
2223 2185 */
2224 2186 #if defined(_KERNEL) && (SOLARIS2 >= 10)
2225 2187 /* ------------------------------------------------------------------------ */
2226 2188 /* Function: fr_make_rst */
2227 2189 /* Returns: int - 0 on success, -1 on failure */
2228 2190 /* Parameters: fin(I) - pointer to packet information */
2229 2191 /* */
2230 2192 /* We must alter the original mblks passed to IPF from IP stack via */
2231 2193 /* FW_HOOKS. FW_HOOKS interface is powerfull, but it has some limitations. */
2232 2194 /* IPF can basicaly do only these things with mblk representing the packet: */
2233 2195 /* leave it as it is (pass the packet) */
2234 2196 /* */
2235 2197 /* discard it (block the packet) */
2236 2198 /* */
2237 2199 /* alter it (i.e. NAT) */
2238 2200 /* */
2239 2201 /* As you can see IPF can not simply discard the mblk and supply a new one */
2240 2202 /* instead to IP stack via FW_HOOKS. */
2241 2203 /* */
2242 2204 /* The return-rst action for packets coming via NIC is handled as follows: */
2243 2205 /* mblk with packet is discarded */
2244 2206 /* */
2245 2207 /* new mblk with RST response is constructed and injected to network */
2246 2208 /* */
2247 2209 /* IPF can't inject packets to loopback interface, this is just another */
2248 2210 /* limitation we have to deal with here. The only option to send RST */
2249 2211 /* response to offending TCP packet coming via loopback is to alter it. */
2250 2212 /* */
2251 2213 /* The fr_make_rst() function alters TCP SYN/FIN packet intercepted on */
2252 2214 /* loopback interface into TCP RST packet. fin->fin_mp is pointer to */
2253 2215 /* mblk L3 (IP) and L4 (TCP/UDP) packet headers. */
2254 2216 /* ------------------------------------------------------------------------ */
2255 2217 int fr_make_rst(fin)
2256 2218 fr_info_t *fin;
2257 2219 {
2258 2220 uint16_t tmp_port;
2259 2221 int rv = -1;
2260 2222 uint32_t old_ack;
2261 2223 tcphdr_t *tcp = NULL;
2262 2224 struct in_addr tmp_src;
2263 2225 #ifdef USE_INET6
2264 2226 struct in6_addr tmp_src6;
2265 2227 #endif
2266 2228
2267 2229 ASSERT(fin->fin_p == IPPROTO_TCP);
2268 2230
2269 2231 /*
2270 2232 * We do not need to adjust chksum, since it is not being checked by
2271 2233 * Solaris IP stack for loopback clients.
2272 2234 */
2273 2235 if ((fin->fin_v == 4) && (fin->fin_p == IPPROTO_TCP) &&
2274 2236 ((tcp = (tcphdr_t *) fin->fin_dp) != NULL)) {
2275 2237
2276 2238 if (tcp->th_flags & (TH_SYN | TH_FIN)) {
2277 2239 /* Swap IPv4 addresses. */
2278 2240 tmp_src = fin->fin_ip->ip_src;
2279 2241 fin->fin_ip->ip_src = fin->fin_ip->ip_dst;
2280 2242 fin->fin_ip->ip_dst = tmp_src;
2281 2243
2282 2244 rv = 0;
2283 2245 }
2284 2246 else
2285 2247 tcp = NULL;
2286 2248 }
2287 2249 #ifdef USE_INET6
2288 2250 else if ((fin->fin_v == 6) && (fin->fin_p == IPPROTO_TCP) &&
2289 2251 ((tcp = (tcphdr_t *) fin->fin_dp) != NULL)) {
2290 2252 /*
2291 2253 * We are relying on fact the next header is TCP, which is true
2292 2254 * for regular TCP packets coming in over loopback.
2293 2255 */
2294 2256 if (tcp->th_flags & (TH_SYN | TH_FIN)) {
2295 2257 /* Swap IPv6 addresses. */
2296 2258 tmp_src6 = fin->fin_ip6->ip6_src;
2297 2259 fin->fin_ip6->ip6_src = fin->fin_ip6->ip6_dst;
2298 2260 fin->fin_ip6->ip6_dst = tmp_src6;
2299 2261
2300 2262 rv = 0;
2301 2263 }
2302 2264 else
2303 2265 tcp = NULL;
2304 2266 }
2305 2267 #endif
2306 2268
2307 2269 if (tcp != NULL) {
2308 2270 /*
2309 2271 * Adjust TCP header:
2310 2272 * swap ports,
2311 2273 * set flags,
2312 2274 * set correct ACK number
2313 2275 */
2314 2276 tmp_port = tcp->th_sport;
2315 2277 tcp->th_sport = tcp->th_dport;
2316 2278 tcp->th_dport = tmp_port;
2317 2279 old_ack = tcp->th_ack;
2318 2280 tcp->th_ack = htonl(ntohl(tcp->th_seq) + 1);
2319 2281 tcp->th_seq = old_ack;
2320 2282 tcp->th_flags = TH_RST | TH_ACK;
2321 2283 }
2322 2284
2323 2285 return (rv);
2324 2286 }
2325 2287
2326 2288 /* ------------------------------------------------------------------------ */
2327 2289 /* Function: fr_make_icmp_v4 */
2328 2290 /* Returns: int - 0 on success, -1 on failure */
2329 2291 /* Parameters: fin(I) - pointer to packet information */
2330 2292 /* */
2331 2293 /* Please read comment at fr_make_icmp() wrapper function to get an idea */
2332 2294 /* what is going to happen here and why. Once you read the comment there, */
2333 2295 /* continue here with next paragraph. */
2334 2296 /* */
2335 2297 /* To turn IPv4 packet into ICMPv4 response packet, these things must */
2336 2298 /* happen here: */
2337 2299 /* (1) Original mblk is copied (duplicated). */
2338 2300 /* */
2339 2301 /* (2) ICMP header is created. */
2340 2302 /* */
2341 2303 /* (3) Link ICMP header with copy of original mblk, we have ICMPv4 */
2342 2304 /* data ready then. */
2343 2305 /* */
2344 2306 /* (4) Swap IP addresses in original mblk and adjust IP header data. */
2345 2307 /* */
2346 2308 /* (5) The mblk containing original packet is trimmed to contain IP */
2347 2309 /* header only and ICMP chksum is computed. */
2348 2310 /* */
2349 2311 /* (6) The ICMP header we have from (3) is linked to original mblk, */
2350 2312 /* which now contains new IP header. If original packet was spread */
2351 2313 /* over several mblks, only the first mblk is kept. */
2352 2314 /* ------------------------------------------------------------------------ */
2353 2315 static int fr_make_icmp_v4(fin)
2354 2316 fr_info_t *fin;
2355 2317 {
2356 2318 struct in_addr tmp_src;
2357 2319 tcphdr_t *tcp;
2358 2320 struct icmp *icmp;
2359 2321 mblk_t *mblk_icmp;
2360 2322 mblk_t *mblk_ip;
2361 2323 size_t icmp_pld_len; /* octets to append to ICMP header */
2362 2324 size_t orig_iphdr_len; /* length of IP header only */
2363 2325 uint32_t sum;
2364 2326 uint16_t *buf;
2365 2327 int len;
2366 2328
2367 2329
2368 2330 if (fin->fin_v != 4)
2369 2331 return (-1);
2370 2332
2371 2333 /*
2372 2334 * If we are dealing with TCP, then packet must be SYN/FIN to be routed
2373 2335 * by IP stack. If it is not SYN/FIN, then we must drop it silently.
2374 2336 */
2375 2337 tcp = (tcphdr_t *) fin->fin_dp;
2376 2338
2377 2339 if ((fin->fin_p == IPPROTO_TCP) &&
2378 2340 ((tcp == NULL) || ((tcp->th_flags & (TH_SYN | TH_FIN)) == 0)))
2379 2341 return (-1);
2380 2342
2381 2343 /*
2382 2344 * Step (1)
2383 2345 *
2384 2346 * Make copy of original mblk.
2385 2347 *
2386 2348 * We want to copy as much data as necessary, not less, not more. The
2387 2349 * ICMPv4 payload length for unreachable messages is:
2388 2350 * original IP header + 8 bytes of L4 (if there are any).
2389 2351 *
2390 2352 * We determine if there are at least 8 bytes of L4 data following IP
2391 2353 * header first.
2392 2354 */
2393 2355 icmp_pld_len = (fin->fin_dlen > ICMPERR_ICMPHLEN) ?
2394 2356 ICMPERR_ICMPHLEN : fin->fin_dlen;
2395 2357 /*
2396 2358 * Since we don't want to copy more data than necessary, we must trim
2397 2359 * the original mblk here. The right way (STREAMish) would be to use
2398 2360 * adjmsg() to trim it. However we would have to calculate the length
2399 2361 * argument for adjmsg() from pointers we already have here.
2400 2362 *
2401 2363 * Since we have pointers and offsets, it's faster and easier for
2402 2364 * us to just adjust pointers by hand instead of using adjmsg().
2403 2365 */
2404 2366 fin->fin_m->b_wptr = (unsigned char *) fin->fin_dp;
2405 2367 fin->fin_m->b_wptr += icmp_pld_len;
2406 2368 icmp_pld_len = fin->fin_m->b_wptr - (unsigned char *) fin->fin_ip;
2407 2369
2408 2370 /*
2409 2371 * Also we don't want to copy any L2 stuff, which might precede IP
2410 2372 * header, so we have have to set b_rptr to point to the start of IP
2411 2373 * header.
2412 2374 */
2413 2375 fin->fin_m->b_rptr += fin->fin_ipoff;
2414 2376 if ((mblk_ip = copyb(fin->fin_m)) == NULL)
2415 2377 return (-1);
2416 2378 fin->fin_m->b_rptr -= fin->fin_ipoff;
2417 2379
2418 2380 /*
2419 2381 * Step (2)
2420 2382 *
2421 2383 * Create an ICMP header, which will be appened to original mblk later.
2422 2384 * ICMP header is just another mblk.
2423 2385 */
2424 2386 mblk_icmp = (mblk_t *) allocb(ICMPERR_ICMPHLEN, BPRI_HI);
2425 2387 if (mblk_icmp == NULL) {
2426 2388 FREE_MB_T(mblk_ip);
2427 2389 return (-1);
2428 2390 }
2429 2391
2430 2392 MTYPE(mblk_icmp) = M_DATA;
2431 2393 icmp = (struct icmp *) mblk_icmp->b_wptr;
2432 2394 icmp->icmp_type = ICMP_UNREACH;
2433 2395 icmp->icmp_code = fin->fin_icode & 0xFF;
2434 2396 icmp->icmp_void = 0;
2435 2397 icmp->icmp_cksum = 0;
2436 2398 mblk_icmp->b_wptr += ICMPERR_ICMPHLEN;
2437 2399
2438 2400 /*
2439 2401 * Step (3)
2440 2402 *
2441 2403 * Complete ICMP packet - link ICMP header with L4 data from original
2442 2404 * IP packet.
2443 2405 */
2444 2406 linkb(mblk_icmp, mblk_ip);
2445 2407
2446 2408 /*
2447 2409 * Step (4)
2448 2410 *
2449 2411 * Swap IP addresses and change IP header fields accordingly in
2450 2412 * original IP packet.
2451 2413 *
2452 2414 * There is a rule option return-icmp as a dest for physical
2453 2415 * interfaces. This option becomes useless for loopback, since IPF box
2454 2416 * uses same address as a loopback destination. We ignore the option
2455 2417 * here, the ICMP packet will always look like as it would have been
2456 2418 * sent from the original destination host.
2457 2419 */
2458 2420 tmp_src = fin->fin_ip->ip_src;
2459 2421 fin->fin_ip->ip_src = fin->fin_ip->ip_dst;
2460 2422 fin->fin_ip->ip_dst = tmp_src;
2461 2423 fin->fin_ip->ip_p = IPPROTO_ICMP;
2462 2424 fin->fin_ip->ip_sum = 0;
2463 2425
2464 2426 /*
2465 2427 * Step (5)
2466 2428 *
2467 2429 * We trim the orignal mblk to hold IP header only.
2468 2430 */
2469 2431 fin->fin_m->b_wptr = fin->fin_dp;
2470 2432 orig_iphdr_len = fin->fin_m->b_wptr -
2471 2433 (fin->fin_m->b_rptr + fin->fin_ipoff);
2472 2434 fin->fin_ip->ip_len = htons(icmp_pld_len + ICMPERR_ICMPHLEN +
2473 2435 orig_iphdr_len);
2474 2436
2475 2437 /*
2476 2438 * ICMP chksum calculation. The data we are calculating chksum for are
2477 2439 * spread over two mblks, therefore we have to use two for loops.
2478 2440 *
2479 2441 * First for loop computes chksum part for ICMP header.
2480 2442 */
2481 2443 buf = (uint16_t *) icmp;
2482 2444 len = ICMPERR_ICMPHLEN;
2483 2445 for (sum = 0; len > 1; len -= 2)
2484 2446 sum += *buf++;
2485 2447
2486 2448 /*
2487 2449 * Here we add chksum part for ICMP payload.
2488 2450 */
2489 2451 len = icmp_pld_len;
2490 2452 buf = (uint16_t *) mblk_ip->b_rptr;
2491 2453 for (; len > 1; len -= 2)
2492 2454 sum += *buf++;
2493 2455
2494 2456 /*
2495 2457 * Chksum is done.
2496 2458 */
2497 2459 sum = (sum >> 16) + (sum & 0xffff);
2498 2460 sum += (sum >> 16);
2499 2461 icmp->icmp_cksum = ~sum;
2500 2462
2501 2463 /*
2502 2464 * Step (6)
2503 2465 *
2504 2466 * Release all packet mblks, except the first one.
2505 2467 */
2506 2468 if (fin->fin_m->b_cont != NULL) {
2507 2469 FREE_MB_T(fin->fin_m->b_cont);
2508 2470 }
2509 2471
2510 2472 /*
2511 2473 * Append ICMP payload to first mblk, which already contains new IP
2512 2474 * header.
2513 2475 */
2514 2476 linkb(fin->fin_m, mblk_icmp);
2515 2477
2516 2478 return (0);
2517 2479 }
2518 2480
2519 2481 #ifdef USE_INET6
2520 2482 /* ------------------------------------------------------------------------ */
2521 2483 /* Function: fr_make_icmp_v6 */
2522 2484 /* Returns: int - 0 on success, -1 on failure */
2523 2485 /* Parameters: fin(I) - pointer to packet information */
2524 2486 /* */
2525 2487 /* Please read comment at fr_make_icmp() wrapper function to get an idea */
2526 2488 /* what and why is going to happen here. Once you read the comment there, */
2527 2489 /* continue here with next paragraph. */
2528 2490 /* */
2529 2491 /* This function turns IPv6 packet (UDP, TCP, ...) into ICMPv6 response. */
2530 2492 /* The algorithm is fairly simple: */
2531 2493 /* 1) We need to get copy of complete mblk. */
2532 2494 /* */
2533 2495 /* 2) New ICMPv6 header is created. */
2534 2496 /* */
2535 2497 /* 3) The copy of original mblk with packet is linked to ICMPv6 */
2536 2498 /* header. */
2537 2499 /* */
2538 2500 /* 4) The checksum must be adjusted. */
2539 2501 /* */
2540 2502 /* 5) IP addresses in original mblk are swapped and IP header data */
2541 2503 /* are adjusted (protocol number). */
2542 2504 /* */
2543 2505 /* 6) Original mblk is trimmed to hold IPv6 header only, then it is */
2544 2506 /* linked with the ICMPv6 data we got from (3). */
2545 2507 /* ------------------------------------------------------------------------ */
2546 2508 static int fr_make_icmp_v6(fin)
2547 2509 fr_info_t *fin;
2548 2510 {
2549 2511 struct icmp6_hdr *icmp6;
2550 2512 tcphdr_t *tcp;
2551 2513 struct in6_addr tmp_src6;
2552 2514 size_t icmp_pld_len;
2553 2515 mblk_t *mblk_ip, *mblk_icmp;
2554 2516
2555 2517 if (fin->fin_v != 6)
2556 2518 return (-1);
2557 2519
2558 2520 /*
2559 2521 * If we are dealing with TCP, then packet must SYN/FIN to be routed by
2560 2522 * IP stack. If it is not SYN/FIN, then we must drop it silently.
2561 2523 */
2562 2524 tcp = (tcphdr_t *) fin->fin_dp;
2563 2525
2564 2526 if ((fin->fin_p == IPPROTO_TCP) &&
2565 2527 ((tcp == NULL) || ((tcp->th_flags & (TH_SYN | TH_FIN)) == 0)))
2566 2528 return (-1);
2567 2529
2568 2530 /*
2569 2531 * Step (1)
2570 2532 *
2571 2533 * We need to copy complete packet in case of IPv6, no trimming is
2572 2534 * needed (except the L2 headers).
2573 2535 */
2574 2536 icmp_pld_len = M_LEN(fin->fin_m);
2575 2537 fin->fin_m->b_rptr += fin->fin_ipoff;
2576 2538 if ((mblk_ip = copyb(fin->fin_m)) == NULL)
2577 2539 return (-1);
2578 2540 fin->fin_m->b_rptr -= fin->fin_ipoff;
2579 2541
2580 2542 /*
2581 2543 * Step (2)
2582 2544 *
2583 2545 * Allocate and create ICMP header.
2584 2546 */
2585 2547 mblk_icmp = (mblk_t *) allocb(sizeof (struct icmp6_hdr),
2586 2548 BPRI_HI);
2587 2549
2588 2550 if (mblk_icmp == NULL)
2589 2551 return (-1);
2590 2552
2591 2553 MTYPE(mblk_icmp) = M_DATA;
2592 2554 icmp6 = (struct icmp6_hdr *) mblk_icmp->b_wptr;
2593 2555 icmp6->icmp6_type = ICMP6_DST_UNREACH;
2594 2556 icmp6->icmp6_code = fin->fin_icode & 0xFF;
2595 2557 icmp6->icmp6_data32[0] = 0;
2596 2558 mblk_icmp->b_wptr += sizeof (struct icmp6_hdr);
2597 2559
2598 2560 /*
2599 2561 * Step (3)
2600 2562 *
2601 2563 * Link the copy of IP packet to ICMP header.
2602 2564 */
2603 2565 linkb(mblk_icmp, mblk_ip);
2604 2566
2605 2567 /*
2606 2568 * Step (4)
2607 2569 *
2608 2570 * Calculate chksum - this is much more easier task than in case of
2609 2571 * IPv4 - ICMPv6 chksum only covers IP addresses, and payload length.
2610 2572 * We are making compensation just for change of packet length.
2611 2573 */
2612 2574 icmp6->icmp6_cksum = icmp_pld_len + sizeof (struct icmp6_hdr);
2613 2575
2614 2576 /*
2615 2577 * Step (5)
2616 2578 *
2617 2579 * Swap IP addresses.
2618 2580 */
2619 2581 tmp_src6 = fin->fin_ip6->ip6_src;
2620 2582 fin->fin_ip6->ip6_src = fin->fin_ip6->ip6_dst;
2621 2583 fin->fin_ip6->ip6_dst = tmp_src6;
2622 2584
2623 2585 /*
2624 2586 * and adjust IP header data.
2625 2587 */
2626 2588 fin->fin_ip6->ip6_nxt = IPPROTO_ICMPV6;
2627 2589 fin->fin_ip6->ip6_plen = htons(icmp_pld_len + sizeof (struct icmp6_hdr));
2628 2590
2629 2591 /*
2630 2592 * Step (6)
2631 2593 *
2632 2594 * We must release all linked mblks from original packet and keep only
2633 2595 * the first mblk with IP header to link ICMP data.
2634 2596 */
2635 2597 fin->fin_m->b_wptr = (unsigned char *) fin->fin_ip6 + sizeof (ip6_t);
2636 2598
2637 2599 if (fin->fin_m->b_cont != NULL) {
2638 2600 FREE_MB_T(fin->fin_m->b_cont);
2639 2601 }
2640 2602
2641 2603 /*
2642 2604 * Append ICMP payload to IP header.
2643 2605 */
2644 2606 linkb(fin->fin_m, mblk_icmp);
2645 2607
2646 2608 return (0);
2647 2609 }
2648 2610 #endif /* USE_INET6 */
2649 2611
2650 2612 /* ------------------------------------------------------------------------ */
2651 2613 /* Function: fr_make_icmp */
2652 2614 /* Returns: int - 0 on success, -1 on failure */
2653 2615 /* Parameters: fin(I) - pointer to packet information */
2654 2616 /* */
2655 2617 /* We must alter the original mblks passed to IPF from IP stack via */
2656 2618 /* FW_HOOKS. The reasons why we must alter packet are discussed within */
2657 2619 /* comment at fr_make_rst() function. */
2658 2620 /* */
2659 2621 /* The fr_make_icmp() function acts as a wrapper, which passes the code */
2660 2622 /* execution to fr_make_icmp_v4() or fr_make_icmp_v6() depending on */
2661 2623 /* protocol version. However there are some details, which are common to */
2662 2624 /* both IP versions. The details are going to be explained here. */
2663 2625 /* */
2664 2626 /* The packet looks as follows: */
2665 2627 /* xxx | IP hdr | IP payload ... | */
2666 2628 /* ^ ^ ^ ^ */
2667 2629 /* | | | | */
2668 2630 /* | | | fin_m->b_wptr = fin->fin_dp + fin->fin_dlen */
2669 2631 /* | | | */
2670 2632 /* | | `- fin_m->fin_dp (in case of IPv4 points to L4 header) */
2671 2633 /* | | */
2672 2634 /* | `- fin_m->b_rptr + fin_ipoff (fin_ipoff is most likely 0 in case */
2673 2635 /* | of loopback) */
2674 2636 /* | */
2675 2637 /* `- fin_m->b_rptr - points to L2 header in case of physical NIC */
2676 2638 /* */
2677 2639 /* All relevant IP headers are pulled up into the first mblk. It happened */
2678 2640 /* well in advance before the matching rule was found (the rule, which took */
2679 2641 /* us here, to fr_make_icmp() function). */
2680 2642 /* */
2681 2643 /* Both functions will turn packet passed in fin->fin_m mblk into a new */
2682 2644 /* packet. New packet will be represented as chain of mblks. */
2683 2645 /* orig mblk |- b_cont ---. */
2684 2646 /* ^ `-> ICMP hdr |- b_cont--. */
2685 2647 /* | ^ `-> duped orig mblk */
2686 2648 /* | | ^ */
2687 2649 /* `- The original mblk | | */
2688 2650 /* will be trimmed to | | */
2689 2651 /* to contain IP header | | */
2690 2652 /* only | | */
2691 2653 /* | | */
2692 2654 /* `- This is newly | */
2693 2655 /* allocated mblk to | */
2694 2656 /* hold ICMPv6 data. | */
2695 2657 /* | */
2696 2658 /* | */
2697 2659 /* | */
2698 2660 /* This is the copy of original mblk, it will contain -' */
2699 2661 /* orignal IP packet in case of ICMPv6. In case of */
2700 2662 /* ICMPv4 it will contain up to 8 bytes of IP payload */
2701 2663 /* (TCP/UDP/L4) data from original packet. */
2702 2664 /* ------------------------------------------------------------------------ */
2703 2665 int fr_make_icmp(fin)
2704 2666 fr_info_t *fin;
2705 2667 {
2706 2668 int rv;
2707 2669
2708 2670 if (fin->fin_v == 4)
2709 2671 rv = fr_make_icmp_v4(fin);
2710 2672 #ifdef USE_INET6
2711 2673 else if (fin->fin_v == 6)
2712 2674 rv = fr_make_icmp_v6(fin);
2713 2675 #endif
2714 2676 else
2715 2677 rv = -1;
2716 2678
2717 2679 return (rv);
2718 2680 }
2719 2681
2720 2682 /* ------------------------------------------------------------------------ */
2721 2683 /* Function: fr_buf_sum */
2722 2684 /* Returns: unsigned int - sum of buffer buf */
2723 2685 /* Parameters: buf - pointer to buf we want to sum up */
2724 2686 /* len - length of buffer buf */
2725 2687 /* */
2726 2688 /* Sums buffer buf. The result is used for chksum calculation. The buf */
2727 2689 /* argument must be aligned. */
2728 2690 /* ------------------------------------------------------------------------ */
2729 2691 static uint32_t fr_buf_sum(buf, len)
2730 2692 const void *buf;
2731 2693 unsigned int len;
2732 2694 {
2733 2695 uint32_t sum = 0;
2734 2696 uint16_t *b = (uint16_t *)buf;
2735 2697
2736 2698 while (len > 1) {
2737 2699 sum += *b++;
2738 2700 len -= 2;
2739 2701 }
2740 2702
2741 2703 if (len == 1)
2742 2704 sum += htons((*(unsigned char *)b) << 8);
2743 2705
2744 2706 return (sum);
2745 2707 }
2746 2708
2747 2709 /* ------------------------------------------------------------------------ */
2748 2710 /* Function: fr_calc_chksum */
2749 2711 /* Returns: void */
2750 2712 /* Parameters: fin - pointer to fr_info_t instance with packet data */
2751 2713 /* pkt - pointer to duplicated packet */
2752 2714 /* */
2753 2715 /* Calculates all chksums (L3, L4) for packet pkt. Works for both IP */
2754 2716 /* versions. */
2755 2717 /* ------------------------------------------------------------------------ */
2756 2718 void fr_calc_chksum(fin, pkt)
2757 2719 fr_info_t *fin;
2758 2720 mb_t *pkt;
2759 2721 {
2760 2722 struct pseudo_hdr {
2761 2723 union {
2762 2724 struct in_addr in4;
2763 2725 #ifdef USE_INET6
2764 2726 struct in6_addr in6;
2765 2727 #endif
2766 2728 } src_addr;
2767 2729 union {
2768 2730 struct in_addr in4;
2769 2731 #ifdef USE_INET6
2770 2732 struct in6_addr in6;
2771 2733 #endif
2772 2734 } dst_addr;
2773 2735 char zero;
2774 2736 char proto;
2775 2737 uint16_t len;
2776 2738 } phdr;
2777 2739 uint32_t sum, ip_sum;
2778 2740 void *buf;
2779 2741 uint16_t *l4_csum_p;
2780 2742 tcphdr_t *tcp;
2781 2743 udphdr_t *udp;
2782 2744 icmphdr_t *icmp;
2783 2745 #ifdef USE_INET6
2784 2746 struct icmp6_hdr *icmp6;
2785 2747 #endif
2786 2748 ip_t *ip;
2787 2749 unsigned int len;
2788 2750 int pld_len;
2789 2751
2790 2752 /*
2791 2753 * We need to pullup the packet to the single continuous buffer to avoid
2792 2754 * potential misaligment of b_rptr member in mblk chain.
2793 2755 */
2794 2756 if (pullupmsg(pkt, -1) == 0) {
2795 2757 cmn_err(CE_WARN, "Failed to pullup loopback pkt -> chksum"
2796 2758 " will not be computed by IPF");
2797 2759 return;
2798 2760 }
2799 2761
2800 2762 /*
2801 2763 * It is guaranteed IP header starts right at b_rptr, because we are
2802 2764 * working with a copy of the original packet.
2803 2765 *
2804 2766 * Compute pseudo header chksum for TCP and UDP.
2805 2767 */
2806 2768 if ((fin->fin_p == IPPROTO_UDP) ||
2807 2769 (fin->fin_p == IPPROTO_TCP)) {
2808 2770 bzero(&phdr, sizeof (phdr));
2809 2771 #ifdef USE_INET6
2810 2772 if (fin->fin_v == 6) {
2811 2773 phdr.src_addr.in6 = fin->fin_srcip6;
2812 2774 phdr.dst_addr.in6 = fin->fin_dstip6;
2813 2775 } else {
2814 2776 phdr.src_addr.in4 = fin->fin_src;
2815 2777 phdr.dst_addr.in4 = fin->fin_dst;
2816 2778 }
2817 2779 #else
2818 2780 phdr.src_addr.in4 = fin->fin_src;
2819 2781 phdr.dst_addr.in4 = fin->fin_dst;
2820 2782 #endif
2821 2783 phdr.zero = (char) 0;
2822 2784 phdr.proto = fin->fin_p;
2823 2785 phdr.len = htons((uint16_t)fin->fin_dlen);
2824 2786 sum = fr_buf_sum(&phdr, (unsigned int)sizeof (phdr));
2825 2787 } else {
2826 2788 sum = 0;
2827 2789 }
2828 2790
2829 2791 /*
2830 2792 * Set pointer to the L4 chksum field in the packet, set buf pointer to
2831 2793 * the L4 header start.
2832 2794 */
2833 2795 switch (fin->fin_p) {
2834 2796 case IPPROTO_UDP:
2835 2797 udp = (udphdr_t *)(pkt->b_rptr + fin->fin_hlen);
2836 2798 l4_csum_p = &udp->uh_sum;
2837 2799 buf = udp;
2838 2800 break;
2839 2801 case IPPROTO_TCP:
2840 2802 tcp = (tcphdr_t *)(pkt->b_rptr + fin->fin_hlen);
2841 2803 l4_csum_p = &tcp->th_sum;
2842 2804 buf = tcp;
2843 2805 break;
2844 2806 case IPPROTO_ICMP:
2845 2807 icmp = (icmphdr_t *)(pkt->b_rptr + fin->fin_hlen);
2846 2808 l4_csum_p = &icmp->icmp_cksum;
2847 2809 buf = icmp;
2848 2810 break;
2849 2811 #ifdef USE_INET6
2850 2812 case IPPROTO_ICMPV6:
2851 2813 icmp6 = (struct icmp6_hdr *)(pkt->b_rptr + fin->fin_hlen);
2852 2814 l4_csum_p = &icmp6->icmp6_cksum;
2853 2815 buf = icmp6;
2854 2816 break;
2855 2817 #endif
2856 2818 default:
2857 2819 l4_csum_p = NULL;
2858 2820 }
2859 2821
2860 2822 /*
2861 2823 * Compute L4 chksum if needed.
2862 2824 */
2863 2825 if (l4_csum_p != NULL) {
2864 2826 *l4_csum_p = (uint16_t)0;
2865 2827 pld_len = fin->fin_dlen;
2866 2828 len = pkt->b_wptr - (unsigned char *)buf;
2867 2829 ASSERT(len == pld_len);
2868 2830 /*
2869 2831 * Add payload sum to pseudoheader sum.
2870 2832 */
2871 2833 sum += fr_buf_sum(buf, len);
2872 2834 while (sum >> 16)
2873 2835 sum = (sum & 0xFFFF) + (sum >> 16);
2874 2836
2875 2837 *l4_csum_p = ~((uint16_t)sum);
2876 2838 DTRACE_PROBE1(l4_sum, uint16_t, *l4_csum_p);
2877 2839 }
2878 2840
2879 2841 /*
2880 2842 * The IP header chksum is needed just for IPv4.
2881 2843 */
2882 2844 if (fin->fin_v == 4) {
2883 2845 /*
2884 2846 * Compute IPv4 header chksum.
2885 2847 */
2886 2848 ip = (ip_t *)pkt->b_rptr;
2887 2849 ip->ip_sum = (uint16_t)0;
2888 2850 ip_sum = fr_buf_sum(ip, (unsigned int)fin->fin_hlen);
2889 2851 while (ip_sum >> 16)
2890 2852 ip_sum = (ip_sum & 0xFFFF) + (ip_sum >> 16);
2891 2853
2892 2854 ip->ip_sum = ~((uint16_t)ip_sum);
2893 2855 DTRACE_PROBE1(l3_sum, uint16_t, ip->ip_sum);
2894 2856 }
2895 2857
2896 2858 return;
2897 2859 }
2898 2860
2899 2861 #endif /* _KERNEL && SOLARIS2 >= 10 */
↓ open down ↓ |
1557 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX