1 /* 2 * Copyright (C) 1993-2001, 2003 by Darren Reed. 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 * 6 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 7 * Use is subject to license terms. 8 */ 9 10 #pragma ident "%Z%%M% %I% %E% SMI" 11 12 #if !defined(lint) 13 static const char sccsid[] = "@(#)ip_fil_solaris.c 1.7 07/22/06 (C) 1993-2000 Darren Reed"; 14 static const char rcsid[] = "@(#)$Id: ip_fil_solaris.c,v 2.62.2.19 2005/07/13 21:40:46 darrenr Exp $"; 15 #endif 16 17 #include <sys/types.h> 18 #include <sys/errno.h> 19 #include <sys/param.h> 20 #include <sys/cpuvar.h> 21 #include <sys/open.h> 22 #include <sys/ioctl.h> 23 #include <sys/filio.h> 24 #include <sys/systm.h> 25 #include <sys/strsubr.h> 26 #include <sys/cred.h> 27 #include <sys/cred_impl.h> 28 #include <sys/ddi.h> 29 #include <sys/sunddi.h> 30 #include <sys/ksynch.h> 31 #include <sys/kmem.h> 32 #include <sys/mkdev.h> 33 #include <sys/protosw.h> 34 #include <sys/socket.h> 35 #include <sys/dditypes.h> 36 #include <sys/cmn_err.h> 37 #include <sys/zone.h> 38 #include <net/if.h> 39 #include <net/af.h> 40 #include <net/route.h> 41 #include <netinet/in.h> 42 #include <netinet/in_systm.h> 43 #include <netinet/ip.h> 44 #include <netinet/ip_var.h> 45 #include <netinet/tcp.h> 46 #include <netinet/udp.h> 47 #include <netinet/tcpip.h> 48 #include <netinet/ip_icmp.h> 49 #include "netinet/ip_compat.h" 50 #ifdef USE_INET6 51 # include <netinet/icmp6.h> 52 #endif 53 #include "netinet/ip_fil.h" 54 #include "netinet/ip_nat.h" 55 #include "netinet/ip_frag.h" 56 #include "netinet/ip_state.h" 57 #include "netinet/ip_auth.h" 58 #include "netinet/ip_proxy.h" 59 #include "netinet/ipf_stack.h" 60 #ifdef IPFILTER_LOOKUP 61 # include "netinet/ip_lookup.h" 62 #endif 63 #include <inet/ip_ire.h> 64 65 #include <sys/md5.h> 66 #include <sys/neti.h> 67 68 static int frzerostats __P((caddr_t, ipf_stack_t *)); 69 static int fr_setipfloopback __P((int, ipf_stack_t *)); 70 static int fr_enableipf __P((ipf_stack_t *, netstack_t *, int)); 71 static int fr_send_ip __P((fr_info_t *fin, mblk_t *m, mblk_t **mp)); 72 static int ipf_nic_event_v4 __P((hook_event_token_t, hook_data_t, 73 netstack_t *)); 74 static int ipf_nic_event_v6 __P((hook_event_token_t, hook_data_t, 75 netstack_t *)); 76 static int ipf_hook4_out __P((hook_event_token_t, hook_data_t, 77 netstack_t *)); 78 static int ipf_hook4_in __P((hook_event_token_t, hook_data_t, 79 netstack_t *)); 80 static int ipf_hook4_loop_out __P((hook_event_token_t, hook_data_t, 81 netstack_t *)); 82 static int ipf_hook4_loop_in __P((hook_event_token_t, hook_data_t, 83 netstack_t *)); 84 static int ipf_hook4 __P((hook_data_t, int, int, netstack_t *)); 85 static int ipf_hook6_out __P((hook_event_token_t, hook_data_t, 86 netstack_t *)); 87 static int ipf_hook6_in __P((hook_event_token_t, hook_data_t, 88 netstack_t *)); 89 static int ipf_hook6_loop_out __P((hook_event_token_t, hook_data_t, 90 netstack_t *)); 91 static int ipf_hook6_loop_in __P((hook_event_token_t, hook_data_t, 92 netstack_t *)); 93 static int ipf_hook6 __P((hook_data_t, int, int, netstack_t *)); 94 extern int ipf_geniter __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *)); 95 extern int ipf_frruleiter __P((void *, int, void *, ipf_stack_t *)); 96 97 #if SOLARIS2 < 10 98 #if SOLARIS2 >= 7 99 u_int *ip_ttl_ptr = NULL; 100 u_int *ip_mtudisc = NULL; 101 # if SOLARIS2 >= 8 102 int *ip_forwarding = NULL; 103 u_int *ip6_forwarding = NULL; 104 # else 105 u_int *ip_forwarding = NULL; 106 # endif 107 #else 108 u_long *ip_ttl_ptr = NULL; 109 u_long *ip_mtudisc = NULL; 110 u_long *ip_forwarding = NULL; 111 #endif 112 #endif 113 114 115 /* ------------------------------------------------------------------------ */ 116 /* Function: ipldetach */ 117 /* Returns: int - 0 == success, else error. */ 118 /* Parameters: Nil */ 119 /* */ 120 /* This function is responsible for undoing anything that might have been */ 121 /* done in a call to iplattach(). It must be able to clean up from a call */ 122 /* to iplattach() that did not succeed. Why might that happen? Someone */ 123 /* configures a table to be so large that we cannot allocate enough memory */ 124 /* for it. */ 125 /* ------------------------------------------------------------------------ */ 126 int ipldetach(ifs) 127 ipf_stack_t *ifs; 128 { 129 130 ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0); 131 132 #if SOLARIS2 < 10 133 134 if (ifs->ifs_fr_control_forwarding & 2) { 135 if (ip_forwarding != NULL) 136 *ip_forwarding = 0; 137 #if SOLARIS2 >= 8 138 if (ip6_forwarding != NULL) 139 *ip6_forwarding = 0; 140 #endif 141 } 142 #endif 143 144 /* 145 * This lock needs to be dropped around the net_unregister_hook calls 146 * because we can deadlock here with: 147 * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs 148 * R(hook_family)->R(hei_lock)->R(ipf_global) (active hook running) 149 */ 150 RWLOCK_EXIT(&ifs->ifs_ipf_global); 151 152 /* 153 * Remove IPv6 Hooks 154 */ 155 if (ifs->ifs_ipf_ipv6 != NULL) { 156 if (ifs->ifs_hook6_physical_in) { 157 ifs->ifs_hook6_physical_in = (net_unregister_hook(ifs->ifs_ipf_ipv6, 158 NH_PHYSICAL_IN, &ifs->ifs_ipfhook6_in) != 0); 159 } 160 if (ifs->ifs_hook6_physical_out) { 161 ifs->ifs_hook6_physical_out = 162 (net_unregister_hook(ifs->ifs_ipf_ipv6, 163 NH_PHYSICAL_OUT, &ifs->ifs_ipfhook6_out) != 0); 164 } 165 if (ifs->ifs_hook6_nic_events) { 166 ifs->ifs_hook6_nic_events = 167 (net_unregister_hook(ifs->ifs_ipf_ipv6, 168 NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) != 0); 169 } 170 if (ifs->ifs_hook6_loopback_in) { 171 ifs->ifs_hook6_loopback_in = 172 (net_unregister_hook(ifs->ifs_ipf_ipv6, 173 NH_LOOPBACK_IN, &ifs->ifs_ipfhook6_loop_in) != 0); 174 } 175 if (ifs->ifs_hook6_loopback_out) { 176 ifs->ifs_hook6_loopback_out = 177 (net_unregister_hook(ifs->ifs_ipf_ipv6, 178 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook6_loop_out) != 0); 179 } 180 181 if (net_release(ifs->ifs_ipf_ipv6) != 0) 182 goto detach_failed; 183 ifs->ifs_ipf_ipv6 = NULL; 184 } 185 186 /* 187 * Remove IPv4 Hooks 188 */ 189 if (ifs->ifs_ipf_ipv4 != NULL) { 190 if (ifs->ifs_hook4_physical_in) { 191 ifs->ifs_hook4_physical_in = 192 (net_unregister_hook(ifs->ifs_ipf_ipv4, 193 NH_PHYSICAL_IN, &ifs->ifs_ipfhook4_in) != 0); 194 } 195 if (ifs->ifs_hook4_physical_out) { 196 ifs->ifs_hook4_physical_out = 197 (net_unregister_hook(ifs->ifs_ipf_ipv4, 198 NH_PHYSICAL_OUT, &ifs->ifs_ipfhook4_out) != 0); 199 } 200 if (ifs->ifs_hook4_nic_events) { 201 ifs->ifs_hook4_nic_events = 202 (net_unregister_hook(ifs->ifs_ipf_ipv4, 203 NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) != 0); 204 } 205 if (ifs->ifs_hook4_loopback_in) { 206 ifs->ifs_hook4_loopback_in = 207 (net_unregister_hook(ifs->ifs_ipf_ipv4, 208 NH_LOOPBACK_IN, &ifs->ifs_ipfhook4_loop_in) != 0); 209 } 210 if (ifs->ifs_hook4_loopback_out) { 211 ifs->ifs_hook4_loopback_out = 212 (net_unregister_hook(ifs->ifs_ipf_ipv4, 213 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook4_loop_out) != 0); 214 } 215 216 if (net_release(ifs->ifs_ipf_ipv4) != 0) 217 goto detach_failed; 218 ifs->ifs_ipf_ipv4 = NULL; 219 } 220 221 #ifdef IPFDEBUG 222 cmn_err(CE_CONT, "ipldetach()\n"); 223 #endif 224 225 WRITE_ENTER(&ifs->ifs_ipf_global); 226 fr_deinitialise(ifs); 227 228 (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE, ifs); 229 (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE, ifs); 230 231 if (ifs->ifs_ipf_locks_done == 1) { 232 MUTEX_DESTROY(&ifs->ifs_ipf_timeoutlock); 233 MUTEX_DESTROY(&ifs->ifs_ipf_rw); 234 RW_DESTROY(&ifs->ifs_ipf_tokens); 235 RW_DESTROY(&ifs->ifs_ipf_ipidfrag); 236 ifs->ifs_ipf_locks_done = 0; 237 } 238 239 if (ifs->ifs_hook4_physical_in || ifs->ifs_hook4_physical_out || ifs->ifs_hook4_nic_events || 240 ifs->ifs_hook4_loopback_in || ifs->ifs_hook4_loopback_out || ifs->ifs_hook6_nic_events || 241 ifs->ifs_hook6_physical_in || ifs->ifs_hook6_physical_out || ifs->ifs_hook6_loopback_in || 242 ifs->ifs_hook6_loopback_out) 243 return -1; 244 245 return 0; 246 247 detach_failed: 248 WRITE_ENTER(&ifs->ifs_ipf_global); 249 return -1; 250 } 251 252 int iplattach(ifs, ns) 253 ipf_stack_t *ifs; 254 netstack_t *ns; 255 { 256 #if SOLARIS2 < 10 257 int i; 258 #endif 259 260 #ifdef IPFDEBUG 261 cmn_err(CE_CONT, "iplattach()\n"); 262 #endif 263 264 ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0); 265 ifs->ifs_fr_flags = IPF_LOGGING; 266 #ifdef _KERNEL 267 ifs->ifs_fr_update_ipid = 0; 268 #else 269 ifs->ifs_fr_update_ipid = 1; 270 #endif 271 ifs->ifs_fr_minttl = 4; 272 ifs->ifs_fr_icmpminfragmtu = 68; 273 #if defined(IPFILTER_DEFAULT_BLOCK) 274 ifs->ifs_fr_pass = FR_BLOCK|FR_NOMATCH; 275 #else 276 ifs->ifs_fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH; 277 #endif 278 279 MUTEX_INIT(&ifs->ifs_ipf_rw, "ipf rw mutex"); 280 MUTEX_INIT(&ifs->ifs_ipf_timeoutlock, "ipf timeout lock mutex"); 281 RWLOCK_INIT(&ifs->ifs_ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); 282 RWLOCK_INIT(&ifs->ifs_ipf_tokens, "ipf token rwlock"); 283 ifs->ifs_ipf_locks_done = 1; 284 285 if (fr_initialise(ifs) < 0) 286 return -1; 287 288 HOOK_INIT(&ifs->ifs_ipfhook_nicevents, ipf_nic_event_v4, 289 "ipfilter_hook_nicevents"); 290 HOOK_INIT(&ifs->ifs_ipfhook4_in, ipf_hook4_in, "ipfilter_hook_in"); 291 HOOK_INIT(&ifs->ifs_ipfhook4_out, ipf_hook4_out, "ipfilter_hook_out"); 292 HOOK_INIT(&ifs->ifs_ipfhook4_loop_in, ipf_hook4_in, 293 "ipfilter_hook_loop_in"); 294 HOOK_INIT(&ifs->ifs_ipfhook4_loop_out, ipf_hook4_out, 295 "ipfilter_hook_loop_out"); 296 297 /* 298 * If we hold this lock over all of the net_register_hook calls, we 299 * can cause a deadlock to occur with the following lock ordering: 300 * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs 301 * R(hook_family)->R(hei_lock)->R(ipf_global) (packet path) 302 */ 303 RWLOCK_EXIT(&ifs->ifs_ipf_global); 304 305 /* 306 * Add IPv4 hooks 307 */ 308 ifs->ifs_ipf_ipv4 = net_lookup_impl(NHF_INET, ns); 309 if (ifs->ifs_ipf_ipv4 == NULL) 310 goto hookup_failed; 311 312 ifs->ifs_hook4_nic_events = (net_register_hook(ifs->ifs_ipf_ipv4, 313 NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) == 0); 314 if (!ifs->ifs_hook4_nic_events) 315 goto hookup_failed; 316 317 ifs->ifs_hook4_physical_in = (net_register_hook(ifs->ifs_ipf_ipv4, 318 NH_PHYSICAL_IN, &ifs->ifs_ipfhook4_in) == 0); 319 if (!ifs->ifs_hook4_physical_in) 320 goto hookup_failed; 321 322 ifs->ifs_hook4_physical_out = (net_register_hook(ifs->ifs_ipf_ipv4, 323 NH_PHYSICAL_OUT, &ifs->ifs_ipfhook4_out) == 0); 324 if (!ifs->ifs_hook4_physical_out) 325 goto hookup_failed; 326 327 if (ifs->ifs_ipf_loopback) { 328 ifs->ifs_hook4_loopback_in = 329 (net_register_hook(ifs->ifs_ipf_ipv4, 330 NH_LOOPBACK_IN, &ifs->ifs_ipfhook4_loop_in) == 0); 331 if (!ifs->ifs_hook4_loopback_in) 332 goto hookup_failed; 333 334 ifs->ifs_hook4_loopback_out = 335 (net_register_hook(ifs->ifs_ipf_ipv4, 336 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook4_loop_out) == 0); 337 if (!ifs->ifs_hook4_loopback_out) 338 goto hookup_failed; 339 } 340 /* 341 * Add IPv6 hooks 342 */ 343 ifs->ifs_ipf_ipv6 = net_lookup_impl(NHF_INET6, ns); 344 if (ifs->ifs_ipf_ipv6 == NULL) 345 goto hookup_failed; 346 347 HOOK_INIT(&ifs->ifs_ipfhook6_in, ipf_hook6_in, "ipfilter_hook_in"); 348 HOOK_INIT(&ifs->ifs_ipfhook6_out, ipf_hook6_out, "ipfilter_hook_out"); 349 HOOK_INIT(&ifs->ifs_ipfhook6_loop_in, ipf_hook6_in, 350 "ipfilter_hook_loop_in"); 351 HOOK_INIT(&ifs->ifs_ipfhook6_loop_out, ipf_hook6_out, 352 "ipfilter_hook_loop_out"); 353 354 HOOK_INIT(&ifs->ifs_ipfhook_nicevents, ipf_nic_event_v6, 355 "ipfilter_hook_nicevents"); 356 ifs->ifs_hook6_nic_events = (net_register_hook(ifs->ifs_ipf_ipv6, 357 NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) == 0); 358 if (!ifs->ifs_hook6_nic_events) 359 goto hookup_failed; 360 361 ifs->ifs_hook6_physical_in = (net_register_hook(ifs->ifs_ipf_ipv6, 362 NH_PHYSICAL_IN, &ifs->ifs_ipfhook6_in) == 0); 363 if (!ifs->ifs_hook6_physical_in) 364 goto hookup_failed; 365 366 ifs->ifs_hook6_physical_out = (net_register_hook(ifs->ifs_ipf_ipv6, 367 NH_PHYSICAL_OUT, &ifs->ifs_ipfhook6_out) == 0); 368 if (!ifs->ifs_hook6_physical_out) 369 goto hookup_failed; 370 371 if (ifs->ifs_ipf_loopback) { 372 ifs->ifs_hook6_loopback_in = 373 (net_register_hook(ifs->ifs_ipf_ipv6, 374 NH_LOOPBACK_IN, &ifs->ifs_ipfhook6_loop_in) == 0); 375 if (!ifs->ifs_hook6_loopback_in) 376 goto hookup_failed; 377 378 ifs->ifs_hook6_loopback_out = 379 (net_register_hook(ifs->ifs_ipf_ipv6, 380 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook6_loop_out) == 0); 381 if (!ifs->ifs_hook6_loopback_out) 382 goto hookup_failed; 383 } 384 385 /* 386 * Reacquire ipf_global, now it is safe. 387 */ 388 WRITE_ENTER(&ifs->ifs_ipf_global); 389 390 /* Do not use private interface ip_params_arr[] in Solaris 10 */ 391 #if SOLARIS2 < 10 392 393 #if SOLARIS2 >= 8 394 ip_forwarding = &ip_g_forward; 395 #endif 396 /* 397 * XXX - There is no terminator for this array, so it is not possible 398 * to tell if what we are looking for is missing and go off the end 399 * of the array. 400 */ 401 402 #if SOLARIS2 <= 8 403 for (i = 0; ; i++) { 404 if (!strcmp(ip_param_arr[i].ip_param_name, "ip_def_ttl")) { 405 ip_ttl_ptr = &ip_param_arr[i].ip_param_value; 406 } else if (!strcmp(ip_param_arr[i].ip_param_name, 407 "ip_path_mtu_discovery")) { 408 ip_mtudisc = &ip_param_arr[i].ip_param_value; 409 } 410 #if SOLARIS2 < 8 411 else if (!strcmp(ip_param_arr[i].ip_param_name, 412 "ip_forwarding")) { 413 ip_forwarding = &ip_param_arr[i].ip_param_value; 414 } 415 #else 416 else if (!strcmp(ip_param_arr[i].ip_param_name, 417 "ip6_forwarding")) { 418 ip6_forwarding = &ip_param_arr[i].ip_param_value; 419 } 420 #endif 421 422 if (ip_mtudisc != NULL && ip_ttl_ptr != NULL && 423 #if SOLARIS2 >= 8 424 ip6_forwarding != NULL && 425 #endif 426 ip_forwarding != NULL) 427 break; 428 } 429 #endif 430 431 if (ifs->ifs_fr_control_forwarding & 1) { 432 if (ip_forwarding != NULL) 433 *ip_forwarding = 1; 434 #if SOLARIS2 >= 8 435 if (ip6_forwarding != NULL) 436 *ip6_forwarding = 1; 437 #endif 438 } 439 440 #endif 441 442 return 0; 443 hookup_failed: 444 WRITE_ENTER(&ifs->ifs_ipf_global); 445 return -1; 446 } 447 448 static int fr_setipfloopback(set, ifs) 449 int set; 450 ipf_stack_t *ifs; 451 { 452 if (ifs->ifs_ipf_ipv4 == NULL || ifs->ifs_ipf_ipv6 == NULL) 453 return EFAULT; 454 455 if (set && !ifs->ifs_ipf_loopback) { 456 ifs->ifs_ipf_loopback = 1; 457 458 ifs->ifs_hook4_loopback_in = 459 (net_register_hook(ifs->ifs_ipf_ipv4, 460 NH_LOOPBACK_IN, &ifs->ifs_ipfhook4_loop_in) == 0); 461 if (!ifs->ifs_hook4_loopback_in) 462 return EINVAL; 463 464 ifs->ifs_hook4_loopback_out = 465 (net_register_hook(ifs->ifs_ipf_ipv4, 466 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook4_loop_out) == 0); 467 if (!ifs->ifs_hook4_loopback_out) 468 return EINVAL; 469 470 ifs->ifs_hook6_loopback_in = 471 (net_register_hook(ifs->ifs_ipf_ipv6, 472 NH_LOOPBACK_IN, &ifs->ifs_ipfhook6_loop_in) == 0); 473 if (!ifs->ifs_hook6_loopback_in) 474 return EINVAL; 475 476 ifs->ifs_hook6_loopback_out = 477 (net_register_hook(ifs->ifs_ipf_ipv6, 478 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook6_loop_out) == 0); 479 if (!ifs->ifs_hook6_loopback_out) 480 return EINVAL; 481 482 } else if (!set && ifs->ifs_ipf_loopback) { 483 ifs->ifs_ipf_loopback = 0; 484 485 ifs->ifs_hook4_loopback_in = 486 (net_unregister_hook(ifs->ifs_ipf_ipv4, 487 NH_LOOPBACK_IN, &ifs->ifs_ipfhook4_loop_in) != 0); 488 if (ifs->ifs_hook4_loopback_in) 489 return EBUSY; 490 491 ifs->ifs_hook4_loopback_out = 492 (net_unregister_hook(ifs->ifs_ipf_ipv4, 493 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook4_loop_out) != 0); 494 if (ifs->ifs_hook4_loopback_out) 495 return EBUSY; 496 497 ifs->ifs_hook6_loopback_in = 498 (net_unregister_hook(ifs->ifs_ipf_ipv6, 499 NH_LOOPBACK_IN, &ifs->ifs_ipfhook6_loop_in) != 0); 500 if (ifs->ifs_hook6_loopback_in) 501 return EBUSY; 502 503 ifs->ifs_hook6_loopback_out = 504 (net_unregister_hook(ifs->ifs_ipf_ipv6, 505 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook6_loop_out) != 0); 506 if (ifs->ifs_hook6_loopback_out) 507 return EBUSY; 508 } 509 return 0; 510 } 511 512 513 /* 514 * Filter ioctl interface. 515 */ 516 /*ARGSUSED*/ 517 int iplioctl(dev, cmd, data, mode, cp, rp) 518 dev_t dev; 519 int cmd; 520 #if SOLARIS2 >= 7 521 intptr_t data; 522 #else 523 int *data; 524 #endif 525 int mode; 526 cred_t *cp; 527 int *rp; 528 { 529 int error = 0, tmp; 530 friostat_t fio; 531 minor_t unit; 532 u_int enable; 533 netstack_t *ns; 534 ipf_stack_t *ifs; 535 536 #ifdef IPFDEBUG 537 cmn_err(CE_CONT, "iplioctl(%x,%x,%x,%d,%x,%d)\n", 538 dev, cmd, data, mode, cp, rp); 539 #endif 540 unit = getminor(dev); 541 if (IPL_LOGMAX < unit) 542 return ENXIO; 543 544 ns = netstack_find_by_cred(cp); 545 ASSERT(ns != NULL); 546 ifs = ns->netstack_ipf; 547 ASSERT(ifs != NULL); 548 549 if (ifs->ifs_fr_running <= 0) { 550 if (unit != IPL_LOGIPF) { 551 netstack_rele(ifs->ifs_netstack); 552 return EIO; 553 } 554 if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 555 cmd != SIOCIPFSET && cmd != SIOCFRENB && 556 cmd != SIOCGETFS && cmd != SIOCGETFF) { 557 netstack_rele(ifs->ifs_netstack); 558 return EIO; 559 } 560 } 561 562 READ_ENTER(&ifs->ifs_ipf_global); 563 564 error = fr_ioctlswitch(unit, (caddr_t)data, cmd, mode, cp->cr_uid, curproc, ifs); 565 if (error != -1) { 566 RWLOCK_EXIT(&ifs->ifs_ipf_global); 567 netstack_rele(ifs->ifs_netstack); 568 return error; 569 } 570 error = 0; 571 572 switch (cmd) 573 { 574 case SIOCFRENB : 575 if (!(mode & FWRITE)) 576 error = EPERM; 577 else { 578 error = COPYIN((caddr_t)data, (caddr_t)&enable, 579 sizeof(enable)); 580 if (error != 0) { 581 error = EFAULT; 582 break; 583 } 584 585 RWLOCK_EXIT(&ifs->ifs_ipf_global); 586 WRITE_ENTER(&ifs->ifs_ipf_global); 587 error = fr_enableipf(ifs, ns, enable); 588 } 589 break; 590 case SIOCIPFSET : 591 if (!(mode & FWRITE)) { 592 error = EPERM; 593 break; 594 } 595 /* FALLTHRU */ 596 case SIOCIPFGETNEXT : 597 case SIOCIPFGET : 598 error = fr_ipftune(cmd, (void *)data, ifs); 599 break; 600 case SIOCSETFF : 601 if (!(mode & FWRITE)) 602 error = EPERM; 603 else { 604 error = COPYIN((caddr_t)data, (caddr_t)&ifs->ifs_fr_flags, 605 sizeof(ifs->ifs_fr_flags)); 606 if (error != 0) 607 error = EFAULT; 608 } 609 break; 610 case SIOCIPFLP : 611 error = COPYIN((caddr_t)data, (caddr_t)&tmp, 612 sizeof(tmp)); 613 if (error != 0) 614 error = EFAULT; 615 else 616 error = fr_setipfloopback(tmp, ifs); 617 break; 618 case SIOCGETFF : 619 error = COPYOUT((caddr_t)&ifs->ifs_fr_flags, (caddr_t)data, 620 sizeof(ifs->ifs_fr_flags)); 621 if (error != 0) 622 error = EFAULT; 623 break; 624 case SIOCFUNCL : 625 error = fr_resolvefunc((void *)data); 626 break; 627 case SIOCINAFR : 628 case SIOCRMAFR : 629 case SIOCADAFR : 630 case SIOCZRLST : 631 if (!(mode & FWRITE)) 632 error = EPERM; 633 else 634 error = frrequest(unit, cmd, (caddr_t)data, 635 ifs->ifs_fr_active, 1, ifs); 636 break; 637 case SIOCINIFR : 638 case SIOCRMIFR : 639 case SIOCADIFR : 640 if (!(mode & FWRITE)) 641 error = EPERM; 642 else 643 error = frrequest(unit, cmd, (caddr_t)data, 644 1 - ifs->ifs_fr_active, 1, ifs); 645 break; 646 case SIOCSWAPA : 647 if (!(mode & FWRITE)) 648 error = EPERM; 649 else { 650 WRITE_ENTER(&ifs->ifs_ipf_mutex); 651 error = COPYOUT((caddr_t)&ifs->ifs_fr_active, 652 (caddr_t)data, 653 sizeof(ifs->ifs_fr_active)); 654 if (error != 0) 655 error = EFAULT; 656 else 657 ifs->ifs_fr_active = 1 - ifs->ifs_fr_active; 658 RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 659 } 660 break; 661 case SIOCGETFS : 662 fr_getstat(&fio, ifs); 663 error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT); 664 break; 665 case SIOCFRZST : 666 if (!(mode & FWRITE)) 667 error = EPERM; 668 else 669 error = fr_zerostats((caddr_t)data, ifs); 670 break; 671 case SIOCIPFFL : 672 if (!(mode & FWRITE)) 673 error = EPERM; 674 else { 675 error = COPYIN((caddr_t)data, (caddr_t)&tmp, 676 sizeof(tmp)); 677 if (!error) { 678 tmp = frflush(unit, 4, tmp, ifs); 679 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 680 sizeof(tmp)); 681 if (error != 0) 682 error = EFAULT; 683 } else 684 error = EFAULT; 685 } 686 break; 687 #ifdef USE_INET6 688 case SIOCIPFL6 : 689 if (!(mode & FWRITE)) 690 error = EPERM; 691 else { 692 error = COPYIN((caddr_t)data, (caddr_t)&tmp, 693 sizeof(tmp)); 694 if (!error) { 695 tmp = frflush(unit, 6, tmp, ifs); 696 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 697 sizeof(tmp)); 698 if (error != 0) 699 error = EFAULT; 700 } else 701 error = EFAULT; 702 } 703 break; 704 #endif 705 case SIOCSTLCK : 706 error = COPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 707 if (error == 0) { 708 ifs->ifs_fr_state_lock = tmp; 709 ifs->ifs_fr_nat_lock = tmp; 710 ifs->ifs_fr_frag_lock = tmp; 711 ifs->ifs_fr_auth_lock = tmp; 712 } else 713 error = EFAULT; 714 break; 715 #ifdef IPFILTER_LOG 716 case SIOCIPFFB : 717 if (!(mode & FWRITE)) 718 error = EPERM; 719 else { 720 tmp = ipflog_clear(unit, ifs); 721 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 722 sizeof(tmp)); 723 if (error) 724 error = EFAULT; 725 } 726 break; 727 #endif /* IPFILTER_LOG */ 728 case SIOCFRSYN : 729 if (!(mode & FWRITE)) 730 error = EPERM; 731 else { 732 RWLOCK_EXIT(&ifs->ifs_ipf_global); 733 WRITE_ENTER(&ifs->ifs_ipf_global); 734 735 frsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 736 fr_natifpsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 737 fr_nataddrsync(0, NULL, NULL, ifs); 738 fr_statesync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 739 error = 0; 740 } 741 break; 742 case SIOCGFRST : 743 error = fr_outobj((void *)data, fr_fragstats(ifs), 744 IPFOBJ_FRAGSTAT); 745 break; 746 case FIONREAD : 747 #ifdef IPFILTER_LOG 748 tmp = (int)ifs->ifs_iplused[IPL_LOGIPF]; 749 750 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, sizeof(tmp)); 751 if (error != 0) 752 error = EFAULT; 753 #endif 754 break; 755 case SIOCIPFITER : 756 error = ipf_frruleiter((caddr_t)data, cp->cr_uid, curproc, ifs); 757 break; 758 759 case SIOCGENITER : 760 error = ipf_genericiter((caddr_t)data, cp->cr_uid, curproc, ifs); 761 break; 762 763 case SIOCIPFDELTOK : 764 (void)BCOPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 765 error = ipf_deltoken(tmp, cp->cr_uid, curproc, ifs); 766 break; 767 768 default : 769 cmn_err(CE_NOTE, "Unknown: cmd 0x%x data %p", cmd, (void *)data); 770 error = EINVAL; 771 break; 772 } 773 RWLOCK_EXIT(&ifs->ifs_ipf_global); 774 netstack_rele(ifs->ifs_netstack); 775 return error; 776 } 777 778 779 static int fr_enableipf(ifs, ns, enable) 780 ipf_stack_t *ifs; 781 netstack_t *ns; 782 int enable; 783 { 784 int error; 785 786 if (!enable) { 787 error = ipldetach(ifs); 788 if (error == 0) 789 ifs->ifs_fr_running = -1; 790 return (error); 791 } 792 793 if (ifs->ifs_fr_running > 0) 794 return (0); 795 796 error = iplattach(ifs, ns); 797 if (error == 0) { 798 if (ifs->ifs_fr_timer_id == NULL) { 799 int hz = drv_usectohz(500000); 800 801 ifs->ifs_fr_timer_id = timeout(fr_slowtimer, 802 (void *)ifs, hz); 803 } 804 ifs->ifs_fr_running = 1; 805 } else { 806 (void) ipldetach(ifs); 807 } 808 return (error); 809 } 810 811 812 phy_if_t get_unit(name, v, ifs) 813 char *name; 814 int v; 815 ipf_stack_t *ifs; 816 { 817 net_data_t nif; 818 819 if (v == 4) 820 nif = ifs->ifs_ipf_ipv4; 821 else if (v == 6) 822 nif = ifs->ifs_ipf_ipv6; 823 else 824 return 0; 825 826 nif->netd_netstack = ifs->ifs_netstack; 827 828 return (net_phylookup(nif, name)); 829 } 830 831 /* 832 * routines below for saving IP headers to buffer 833 */ 834 /*ARGSUSED*/ 835 int iplopen(devp, flags, otype, cred) 836 dev_t *devp; 837 int flags, otype; 838 cred_t *cred; 839 { 840 minor_t min = getminor(*devp); 841 842 #ifdef IPFDEBUG 843 cmn_err(CE_CONT, "iplopen(%x,%x,%x,%x)\n", devp, flags, otype, cred); 844 #endif 845 if (!(otype & OTYP_CHR)) 846 return ENXIO; 847 848 min = (IPL_LOGMAX < min) ? ENXIO : 0; 849 return min; 850 } 851 852 853 /*ARGSUSED*/ 854 int iplclose(dev, flags, otype, cred) 855 dev_t dev; 856 int flags, otype; 857 cred_t *cred; 858 { 859 minor_t min = getminor(dev); 860 861 #ifdef IPFDEBUG 862 cmn_err(CE_CONT, "iplclose(%x,%x,%x,%x)\n", dev, flags, otype, cred); 863 #endif 864 865 min = (IPL_LOGMAX < min) ? ENXIO : 0; 866 return min; 867 } 868 869 #ifdef IPFILTER_LOG 870 /* 871 * iplread/ipllog 872 * both of these must operate with at least splnet() lest they be 873 * called during packet processing and cause an inconsistancy to appear in 874 * the filter lists. 875 */ 876 /*ARGSUSED*/ 877 int iplread(dev, uio, cp) 878 dev_t dev; 879 register struct uio *uio; 880 cred_t *cp; 881 { 882 netstack_t *ns; 883 ipf_stack_t *ifs; 884 int ret; 885 886 ns = netstack_find_by_cred(cp); 887 ASSERT(ns != NULL); 888 ifs = ns->netstack_ipf; 889 ASSERT(ifs != NULL); 890 891 # ifdef IPFDEBUG 892 cmn_err(CE_CONT, "iplread(%x,%x,%x)\n", dev, uio, cp); 893 # endif 894 895 if (ifs->ifs_fr_running < 1) { 896 netstack_rele(ifs->ifs_netstack); 897 return EIO; 898 } 899 900 # ifdef IPFILTER_SYNC 901 if (getminor(dev) == IPL_LOGSYNC) { 902 netstack_rele(ifs->ifs_netstack); 903 return ipfsync_read(uio); 904 } 905 # endif 906 907 ret = ipflog_read(getminor(dev), uio, ifs); 908 netstack_rele(ifs->ifs_netstack); 909 return ret; 910 } 911 #endif /* IPFILTER_LOG */ 912 913 914 /* 915 * iplread/ipllog 916 * both of these must operate with at least splnet() lest they be 917 * called during packet processing and cause an inconsistancy to appear in 918 * the filter lists. 919 */ 920 int iplwrite(dev, uio, cp) 921 dev_t dev; 922 register struct uio *uio; 923 cred_t *cp; 924 { 925 netstack_t *ns; 926 ipf_stack_t *ifs; 927 928 ns = netstack_find_by_cred(cp); 929 ASSERT(ns != NULL); 930 ifs = ns->netstack_ipf; 931 ASSERT(ifs != NULL); 932 933 #ifdef IPFDEBUG 934 cmn_err(CE_CONT, "iplwrite(%x,%x,%x)\n", dev, uio, cp); 935 #endif 936 937 if (ifs->ifs_fr_running < 1) { 938 netstack_rele(ifs->ifs_netstack); 939 return EIO; 940 } 941 942 #ifdef IPFILTER_SYNC 943 if (getminor(dev) == IPL_LOGSYNC) 944 return ipfsync_write(uio); 945 #endif /* IPFILTER_SYNC */ 946 dev = dev; /* LINT */ 947 uio = uio; /* LINT */ 948 cp = cp; /* LINT */ 949 netstack_rele(ifs->ifs_netstack); 950 return ENXIO; 951 } 952 953 954 /* 955 * fr_send_reset - this could conceivably be a call to tcp_respond(), but that 956 * requires a large amount of setting up and isn't any more efficient. 957 */ 958 int fr_send_reset(fin) 959 fr_info_t *fin; 960 { 961 tcphdr_t *tcp, *tcp2; 962 int tlen, hlen; 963 mblk_t *m; 964 #ifdef USE_INET6 965 ip6_t *ip6; 966 #endif 967 ip_t *ip; 968 969 tcp = fin->fin_dp; 970 if (tcp->th_flags & TH_RST) 971 return -1; 972 973 #ifndef IPFILTER_CKSUM 974 if (fr_checkl4sum(fin) == -1) 975 return -1; 976 #endif 977 978 tlen = (tcp->th_flags & (TH_SYN|TH_FIN)) ? 1 : 0; 979 #ifdef USE_INET6 980 if (fin->fin_v == 6) 981 hlen = sizeof(ip6_t); 982 else 983 #endif 984 hlen = sizeof(ip_t); 985 hlen += sizeof(*tcp2); 986 if ((m = (mblk_t *)allocb(hlen + 64, BPRI_HI)) == NULL) 987 return -1; 988 989 m->b_rptr += 64; 990 MTYPE(m) = M_DATA; 991 m->b_wptr = m->b_rptr + hlen; 992 ip = (ip_t *)m->b_rptr; 993 bzero((char *)ip, hlen); 994 tcp2 = (struct tcphdr *)(m->b_rptr + hlen - sizeof(*tcp2)); 995 tcp2->th_dport = tcp->th_sport; 996 tcp2->th_sport = tcp->th_dport; 997 if (tcp->th_flags & TH_ACK) { 998 tcp2->th_seq = tcp->th_ack; 999 tcp2->th_flags = TH_RST; 1000 } else { 1001 tcp2->th_ack = ntohl(tcp->th_seq); 1002 tcp2->th_ack += tlen; 1003 tcp2->th_ack = htonl(tcp2->th_ack); 1004 tcp2->th_flags = TH_RST|TH_ACK; 1005 } 1006 tcp2->th_off = sizeof(struct tcphdr) >> 2; 1007 1008 ip->ip_v = fin->fin_v; 1009 #ifdef USE_INET6 1010 if (fin->fin_v == 6) { 1011 ip6 = (ip6_t *)m->b_rptr; 1012 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 1013 ip6->ip6_src = fin->fin_dst6.in6; 1014 ip6->ip6_dst = fin->fin_src6.in6; 1015 ip6->ip6_plen = htons(sizeof(*tcp)); 1016 ip6->ip6_nxt = IPPROTO_TCP; 1017 tcp2->th_sum = fr_cksum(m, (ip_t *)ip6, IPPROTO_TCP, tcp2); 1018 } else 1019 #endif 1020 { 1021 ip->ip_src.s_addr = fin->fin_daddr; 1022 ip->ip_dst.s_addr = fin->fin_saddr; 1023 ip->ip_id = fr_nextipid(fin); 1024 ip->ip_hl = sizeof(*ip) >> 2; 1025 ip->ip_p = IPPROTO_TCP; 1026 ip->ip_len = sizeof(*ip) + sizeof(*tcp); 1027 ip->ip_tos = fin->fin_ip->ip_tos; 1028 tcp2->th_sum = fr_cksum(m, ip, IPPROTO_TCP, tcp2); 1029 } 1030 return fr_send_ip(fin, m, &m); 1031 } 1032 1033 /* 1034 * Function: fr_send_ip 1035 * Returns: 0: success 1036 * -1: failed 1037 * Parameters: 1038 * fin: packet information 1039 * m: the message block where ip head starts 1040 * 1041 * Send a new packet through the IP stack. 1042 * 1043 * For IPv4 packets, ip_len must be in host byte order, and ip_v, 1044 * ip_ttl, ip_off, and ip_sum are ignored (filled in by this 1045 * function). 1046 * 1047 * For IPv6 packets, ip6_flow, ip6_vfc, and ip6_hlim are filled 1048 * in by this function. 1049 * 1050 * All other portions of the packet must be in on-the-wire format. 1051 */ 1052 /*ARGSUSED*/ 1053 static int fr_send_ip(fin, m, mpp) 1054 fr_info_t *fin; 1055 mblk_t *m, **mpp; 1056 { 1057 qpktinfo_t qpi, *qpip; 1058 fr_info_t fnew; 1059 ip_t *ip; 1060 int i, hlen; 1061 ipf_stack_t *ifs = fin->fin_ifs; 1062 1063 ip = (ip_t *)m->b_rptr; 1064 bzero((char *)&fnew, sizeof(fnew)); 1065 1066 #ifdef USE_INET6 1067 if (fin->fin_v == 6) { 1068 ip6_t *ip6; 1069 1070 ip6 = (ip6_t *)ip; 1071 ip6->ip6_vfc = 0x60; 1072 ip6->ip6_hlim = 127; 1073 fnew.fin_v = 6; 1074 hlen = sizeof(*ip6); 1075 fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen; 1076 } else 1077 #endif 1078 { 1079 fnew.fin_v = 4; 1080 #if SOLARIS2 >= 10 1081 ip->ip_ttl = 255; 1082 if (net_getpmtuenabled(ifs->ifs_ipf_ipv4) == 1) 1083 ip->ip_off = htons(IP_DF); 1084 #else 1085 if (ip_ttl_ptr != NULL) 1086 ip->ip_ttl = (u_char)(*ip_ttl_ptr); 1087 else 1088 ip->ip_ttl = 63; 1089 if (ip_mtudisc != NULL) 1090 ip->ip_off = htons(*ip_mtudisc ? IP_DF : 0); 1091 else 1092 ip->ip_off = htons(IP_DF); 1093 #endif 1094 /* 1095 * The dance with byte order and ip_len/ip_off is because in 1096 * fr_fastroute, it expects them to be in host byte order but 1097 * ipf_cksum expects them to be in network byte order. 1098 */ 1099 ip->ip_len = htons(ip->ip_len); 1100 ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip)); 1101 ip->ip_len = ntohs(ip->ip_len); 1102 ip->ip_off = ntohs(ip->ip_off); 1103 hlen = sizeof(*ip); 1104 fnew.fin_plen = ip->ip_len; 1105 } 1106 1107 qpip = fin->fin_qpi; 1108 qpi.qpi_off = 0; 1109 qpi.qpi_ill = qpip->qpi_ill; 1110 qpi.qpi_m = m; 1111 qpi.qpi_data = ip; 1112 fnew.fin_qpi = &qpi; 1113 fnew.fin_ifp = fin->fin_ifp; 1114 fnew.fin_flx = FI_NOCKSUM; 1115 fnew.fin_m = m; 1116 fnew.fin_ip = ip; 1117 fnew.fin_mp = mpp; 1118 fnew.fin_hlen = hlen; 1119 fnew.fin_dp = (char *)ip + hlen; 1120 fnew.fin_ifs = fin->fin_ifs; 1121 (void) fr_makefrip(hlen, ip, &fnew); 1122 1123 i = fr_fastroute(m, mpp, &fnew, NULL); 1124 return i; 1125 } 1126 1127 1128 int fr_send_icmp_err(type, fin, dst) 1129 int type; 1130 fr_info_t *fin; 1131 int dst; 1132 { 1133 struct in_addr dst4; 1134 struct icmp *icmp; 1135 qpktinfo_t *qpi; 1136 int hlen, code; 1137 phy_if_t phy; 1138 u_short sz; 1139 #ifdef USE_INET6 1140 mblk_t *mb; 1141 #endif 1142 mblk_t *m; 1143 #ifdef USE_INET6 1144 ip6_t *ip6; 1145 #endif 1146 ip_t *ip; 1147 ipf_stack_t *ifs = fin->fin_ifs; 1148 1149 if ((type < 0) || (type > ICMP_MAXTYPE)) 1150 return -1; 1151 1152 code = fin->fin_icode; 1153 #ifdef USE_INET6 1154 if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) 1155 return -1; 1156 #endif 1157 1158 #ifndef IPFILTER_CKSUM 1159 if (fr_checkl4sum(fin) == -1) 1160 return -1; 1161 #endif 1162 1163 qpi = fin->fin_qpi; 1164 1165 #ifdef USE_INET6 1166 mb = fin->fin_qfm; 1167 1168 if (fin->fin_v == 6) { 1169 sz = sizeof(ip6_t); 1170 sz += MIN(mb->b_wptr - mb->b_rptr, 512); 1171 hlen = sizeof(ip6_t); 1172 type = icmptoicmp6types[type]; 1173 if (type == ICMP6_DST_UNREACH) 1174 code = icmptoicmp6unreach[code]; 1175 } else 1176 #endif 1177 { 1178 if ((fin->fin_p == IPPROTO_ICMP) && 1179 !(fin->fin_flx & FI_SHORT)) 1180 switch (ntohs(fin->fin_data[0]) >> 8) 1181 { 1182 case ICMP_ECHO : 1183 case ICMP_TSTAMP : 1184 case ICMP_IREQ : 1185 case ICMP_MASKREQ : 1186 break; 1187 default : 1188 return 0; 1189 } 1190 1191 sz = sizeof(ip_t) * 2; 1192 sz += 8; /* 64 bits of data */ 1193 hlen = sizeof(ip_t); 1194 } 1195 1196 sz += offsetof(struct icmp, icmp_ip); 1197 if ((m = (mblk_t *)allocb((size_t)sz + 64, BPRI_HI)) == NULL) 1198 return -1; 1199 MTYPE(m) = M_DATA; 1200 m->b_rptr += 64; 1201 m->b_wptr = m->b_rptr + sz; 1202 bzero((char *)m->b_rptr, (size_t)sz); 1203 ip = (ip_t *)m->b_rptr; 1204 ip->ip_v = fin->fin_v; 1205 icmp = (struct icmp *)(m->b_rptr + hlen); 1206 icmp->icmp_type = type & 0xff; 1207 icmp->icmp_code = code & 0xff; 1208 phy = (phy_if_t)qpi->qpi_ill; 1209 if (type == ICMP_UNREACH && (phy != 0) && 1210 fin->fin_icode == ICMP_UNREACH_NEEDFRAG) 1211 icmp->icmp_nextmtu = net_getmtu(ifs->ifs_ipf_ipv4, phy,0 ); 1212 1213 #ifdef USE_INET6 1214 if (fin->fin_v == 6) { 1215 struct in6_addr dst6; 1216 int csz; 1217 1218 if (dst == 0) { 1219 ipf_stack_t *ifs = fin->fin_ifs; 1220 1221 if (fr_ifpaddr(6, FRI_NORMAL, (void *)phy, 1222 (void *)&dst6, NULL, ifs) == -1) { 1223 FREE_MB_T(m); 1224 return -1; 1225 } 1226 } else 1227 dst6 = fin->fin_dst6.in6; 1228 1229 csz = sz; 1230 sz -= sizeof(ip6_t); 1231 ip6 = (ip6_t *)m->b_rptr; 1232 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 1233 ip6->ip6_plen = htons((u_short)sz); 1234 ip6->ip6_nxt = IPPROTO_ICMPV6; 1235 ip6->ip6_src = dst6; 1236 ip6->ip6_dst = fin->fin_src6.in6; 1237 sz -= offsetof(struct icmp, icmp_ip); 1238 bcopy((char *)mb->b_rptr, (char *)&icmp->icmp_ip, sz); 1239 icmp->icmp_cksum = csz - sizeof(ip6_t); 1240 } else 1241 #endif 1242 { 1243 ip->ip_hl = sizeof(*ip) >> 2; 1244 ip->ip_p = IPPROTO_ICMP; 1245 ip->ip_id = fin->fin_ip->ip_id; 1246 ip->ip_tos = fin->fin_ip->ip_tos; 1247 ip->ip_len = (u_short)sz; 1248 if (dst == 0) { 1249 ipf_stack_t *ifs = fin->fin_ifs; 1250 1251 if (fr_ifpaddr(4, FRI_NORMAL, (void *)phy, 1252 (void *)&dst4, NULL, ifs) == -1) { 1253 FREE_MB_T(m); 1254 return -1; 1255 } 1256 } else { 1257 dst4 = fin->fin_dst; 1258 } 1259 ip->ip_src = dst4; 1260 ip->ip_dst = fin->fin_src; 1261 bcopy((char *)fin->fin_ip, (char *)&icmp->icmp_ip, 1262 sizeof(*fin->fin_ip)); 1263 bcopy((char *)fin->fin_ip + fin->fin_hlen, 1264 (char *)&icmp->icmp_ip + sizeof(*fin->fin_ip), 8); 1265 icmp->icmp_ip.ip_len = htons(icmp->icmp_ip.ip_len); 1266 icmp->icmp_ip.ip_off = htons(icmp->icmp_ip.ip_off); 1267 icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 1268 sz - sizeof(ip_t)); 1269 } 1270 1271 /* 1272 * Need to exit out of these so we don't recursively call rw_enter 1273 * from fr_qout. 1274 */ 1275 return fr_send_ip(fin, m, &m); 1276 } 1277 1278 #include <sys/time.h> 1279 #include <sys/varargs.h> 1280 1281 #ifndef _KERNEL 1282 #include <stdio.h> 1283 #endif 1284 1285 #define NULLADDR_RATE_LIMIT 10 /* 10 seconds */ 1286 1287 1288 /* 1289 * Print out warning message at rate-limited speed. 1290 */ 1291 static void rate_limit_message(ipf_stack_t *ifs, 1292 int rate, const char *message, ...) 1293 { 1294 static time_t last_time = 0; 1295 time_t now; 1296 va_list args; 1297 char msg_buf[256]; 1298 int need_printed = 0; 1299 1300 now = ddi_get_time(); 1301 1302 /* make sure, no multiple entries */ 1303 ASSERT(MUTEX_NOT_HELD(&(ifs->ifs_ipf_rw.ipf_lk))); 1304 MUTEX_ENTER(&ifs->ifs_ipf_rw); 1305 if (now - last_time >= rate) { 1306 need_printed = 1; 1307 last_time = now; 1308 } 1309 MUTEX_EXIT(&ifs->ifs_ipf_rw); 1310 1311 if (need_printed) { 1312 va_start(args, message); 1313 (void)vsnprintf(msg_buf, 255, message, args); 1314 va_end(args); 1315 #ifdef _KERNEL 1316 cmn_err(CE_WARN, msg_buf); 1317 #else 1318 fprintf(std_err, msg_buf); 1319 #endif 1320 } 1321 } 1322 1323 /* 1324 * return the first IP Address associated with an interface 1325 */ 1326 /*ARGSUSED*/ 1327 int fr_ifpaddr(v, atype, ifptr, inp, inpmask, ifs) 1328 int v, atype; 1329 void *ifptr; 1330 struct in_addr *inp, *inpmask; 1331 ipf_stack_t *ifs; 1332 { 1333 struct sockaddr_in6 v6addr[2]; 1334 struct sockaddr_in v4addr[2]; 1335 net_ifaddr_t type[2]; 1336 net_data_t net_data; 1337 phy_if_t phyif; 1338 void *array; 1339 1340 switch (v) 1341 { 1342 case 4: 1343 net_data = ifs->ifs_ipf_ipv4; 1344 array = v4addr; 1345 break; 1346 case 6: 1347 net_data = ifs->ifs_ipf_ipv6; 1348 array = v6addr; 1349 break; 1350 default: 1351 net_data = NULL; 1352 break; 1353 } 1354 1355 if (net_data == NULL) 1356 return -1; 1357 1358 phyif = (phy_if_t)ifptr; 1359 1360 switch (atype) 1361 { 1362 case FRI_PEERADDR : 1363 type[0] = NA_PEER; 1364 break; 1365 1366 case FRI_BROADCAST : 1367 type[0] = NA_BROADCAST; 1368 break; 1369 1370 default : 1371 type[0] = NA_ADDRESS; 1372 break; 1373 } 1374 1375 type[1] = NA_NETMASK; 1376 1377 if (net_getlifaddr(net_data, phyif, 0, 2, type, array) < 0) 1378 return -1; 1379 1380 if (v == 6) { 1381 return fr_ifpfillv6addr(atype, &v6addr[0], &v6addr[1], 1382 inp, inpmask); 1383 } 1384 return fr_ifpfillv4addr(atype, &v4addr[0], &v4addr[1], inp, inpmask); 1385 } 1386 1387 1388 u_32_t fr_newisn(fin) 1389 fr_info_t *fin; 1390 { 1391 static int iss_seq_off = 0; 1392 u_char hash[16]; 1393 u_32_t newiss; 1394 MD5_CTX ctx; 1395 ipf_stack_t *ifs = fin->fin_ifs; 1396 1397 /* 1398 * Compute the base value of the ISS. It is a hash 1399 * of (saddr, sport, daddr, dport, secret). 1400 */ 1401 MD5Init(&ctx); 1402 1403 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 1404 sizeof(fin->fin_fi.fi_src)); 1405 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 1406 sizeof(fin->fin_fi.fi_dst)); 1407 MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 1408 1409 MD5Update(&ctx, ifs->ifs_ipf_iss_secret, sizeof(ifs->ifs_ipf_iss_secret)); 1410 1411 MD5Final(hash, &ctx); 1412 1413 bcopy(hash, &newiss, sizeof(newiss)); 1414 1415 /* 1416 * Now increment our "timer", and add it in to 1417 * the computed value. 1418 * 1419 * XXX Use `addin'? 1420 * XXX TCP_ISSINCR too large to use? 1421 */ 1422 iss_seq_off += 0x00010000; 1423 newiss += iss_seq_off; 1424 return newiss; 1425 } 1426 1427 1428 /* ------------------------------------------------------------------------ */ 1429 /* Function: fr_nextipid */ 1430 /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 1431 /* Parameters: fin(I) - pointer to packet information */ 1432 /* */ 1433 /* Returns the next IPv4 ID to use for this packet. */ 1434 /* ------------------------------------------------------------------------ */ 1435 u_short fr_nextipid(fin) 1436 fr_info_t *fin; 1437 { 1438 static u_short ipid = 0; 1439 ipstate_t *is; 1440 nat_t *nat; 1441 u_short id; 1442 ipf_stack_t *ifs = fin->fin_ifs; 1443 1444 MUTEX_ENTER(&ifs->ifs_ipf_rw); 1445 if (fin->fin_state != NULL) { 1446 is = fin->fin_state; 1447 id = (u_short)(is->is_pkts[(fin->fin_rev << 1) + 1] & 0xffff); 1448 } else if (fin->fin_nat != NULL) { 1449 nat = fin->fin_nat; 1450 id = (u_short)(nat->nat_pkts[fin->fin_out] & 0xffff); 1451 } else 1452 id = ipid++; 1453 MUTEX_EXIT(&ifs->ifs_ipf_rw); 1454 1455 return id; 1456 } 1457 1458 1459 #ifndef IPFILTER_CKSUM 1460 /* ARGSUSED */ 1461 #endif 1462 INLINE void fr_checkv4sum(fin) 1463 fr_info_t *fin; 1464 { 1465 #ifdef IPFILTER_CKSUM 1466 if (fr_checkl4sum(fin) == -1) 1467 fin->fin_flx |= FI_BAD; 1468 #endif 1469 } 1470 1471 1472 #ifdef USE_INET6 1473 # ifndef IPFILTER_CKSUM 1474 /* ARGSUSED */ 1475 # endif 1476 INLINE void fr_checkv6sum(fin) 1477 fr_info_t *fin; 1478 { 1479 # ifdef IPFILTER_CKSUM 1480 if (fr_checkl4sum(fin) == -1) 1481 fin->fin_flx |= FI_BAD; 1482 # endif 1483 } 1484 #endif /* USE_INET6 */ 1485 1486 1487 #if (SOLARIS2 < 7) 1488 void fr_slowtimer() 1489 #else 1490 /*ARGSUSED*/ 1491 void fr_slowtimer __P((void *arg)) 1492 #endif 1493 { 1494 ipf_stack_t *ifs = arg; 1495 1496 READ_ENTER(&ifs->ifs_ipf_global); 1497 if (ifs->ifs_fr_running != 1) { 1498 ifs->ifs_fr_timer_id = NULL; 1499 RWLOCK_EXIT(&ifs->ifs_ipf_global); 1500 return; 1501 } 1502 ipf_expiretokens(ifs); 1503 fr_fragexpire(ifs); 1504 fr_timeoutstate(ifs); 1505 fr_natexpire(ifs); 1506 fr_authexpire(ifs); 1507 ifs->ifs_fr_ticks++; 1508 if (ifs->ifs_fr_running == 1) 1509 ifs->ifs_fr_timer_id = timeout(fr_slowtimer, arg, 1510 drv_usectohz(500000)); 1511 else 1512 ifs->ifs_fr_timer_id = NULL; 1513 RWLOCK_EXIT(&ifs->ifs_ipf_global); 1514 } 1515 1516 1517 /* ------------------------------------------------------------------------ */ 1518 /* Function: fr_pullup */ 1519 /* Returns: NULL == pullup failed, else pointer to protocol header */ 1520 /* Parameters: m(I) - pointer to buffer where data packet starts */ 1521 /* fin(I) - pointer to packet information */ 1522 /* len(I) - number of bytes to pullup */ 1523 /* */ 1524 /* Attempt to move at least len bytes (from the start of the buffer) into a */ 1525 /* single buffer for ease of access. Operating system native functions are */ 1526 /* used to manage buffers - if necessary. If the entire packet ends up in */ 1527 /* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */ 1528 /* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ 1529 /* and ONLY if the pullup succeeds. */ 1530 /* */ 1531 /* We assume that 'min' is a pointer to a buffer that is part of the chain */ 1532 /* of buffers that starts at *fin->fin_mp. */ 1533 /* ------------------------------------------------------------------------ */ 1534 void *fr_pullup(min, fin, len) 1535 mb_t *min; 1536 fr_info_t *fin; 1537 int len; 1538 { 1539 qpktinfo_t *qpi = fin->fin_qpi; 1540 int out = fin->fin_out, dpoff, ipoff; 1541 mb_t *m = min, *m1, *m2; 1542 char *ip; 1543 uint32_t start, stuff, end, value, flags; 1544 ipf_stack_t *ifs = fin->fin_ifs; 1545 1546 if (m == NULL) 1547 return NULL; 1548 1549 ip = (char *)fin->fin_ip; 1550 if ((fin->fin_flx & FI_COALESCE) != 0) 1551 return ip; 1552 1553 ipoff = fin->fin_ipoff; 1554 if (fin->fin_dp != NULL) 1555 dpoff = (char *)fin->fin_dp - (char *)ip; 1556 else 1557 dpoff = 0; 1558 1559 if (M_LEN(m) < len) { 1560 1561 /* 1562 * pfil_precheck ensures the IP header is on a 32bit 1563 * aligned address so simply fail if that isn't currently 1564 * the case (should never happen). 1565 */ 1566 int inc = 0; 1567 1568 if (ipoff > 0) { 1569 if ((ipoff & 3) != 0) { 1570 inc = 4 - (ipoff & 3); 1571 if (m->b_rptr - inc >= m->b_datap->db_base) 1572 m->b_rptr -= inc; 1573 else 1574 inc = 0; 1575 } 1576 } 1577 1578 /* 1579 * XXX This is here as a work around for a bug with DEBUG 1580 * XXX Solaris kernels. The problem is b_prev is used by IP 1581 * XXX code as a way to stash the phyint_index for a packet, 1582 * XXX this doesn't get reset by IP but freeb does an ASSERT() 1583 * XXX for both of these to be NULL. See 6442390. 1584 */ 1585 m1 = m; 1586 m2 = m->b_prev; 1587 1588 do { 1589 m1->b_next = NULL; 1590 m1->b_prev = NULL; 1591 m1 = m1->b_cont; 1592 } while (m1); 1593 1594 /* 1595 * Need to preserve checksum information by copying them 1596 * to newmp which heads the pulluped message. 1597 */ 1598 hcksum_retrieve(m, NULL, NULL, &start, &stuff, &end, 1599 &value, &flags); 1600 1601 if (pullupmsg(m, len + ipoff + inc) == 0) { 1602 ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[1]); 1603 FREE_MB_T(*fin->fin_mp); 1604 *fin->fin_mp = NULL; 1605 fin->fin_m = NULL; 1606 fin->fin_ip = NULL; 1607 fin->fin_dp = NULL; 1608 qpi->qpi_data = NULL; 1609 return NULL; 1610 } 1611 1612 (void) hcksum_assoc(m, NULL, NULL, start, stuff, end, 1613 value, flags, 0); 1614 1615 m->b_prev = m2; 1616 m->b_rptr += inc; 1617 fin->fin_m = m; 1618 ip = MTOD(m, char *) + ipoff; 1619 qpi->qpi_data = ip; 1620 } 1621 1622 ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[0]); 1623 fin->fin_ip = (ip_t *)ip; 1624 if (fin->fin_dp != NULL) 1625 fin->fin_dp = (char *)fin->fin_ip + dpoff; 1626 1627 if (len == fin->fin_plen) 1628 fin->fin_flx |= FI_COALESCE; 1629 return ip; 1630 } 1631 1632 1633 /* 1634 * Function: fr_verifysrc 1635 * Returns: int (really boolean) 1636 * Parameters: fin - packet information 1637 * 1638 * Check whether the packet has a valid source address for the interface on 1639 * which the packet arrived, implementing the "fr_chksrc" feature. 1640 * Returns true iff the packet's source address is valid. 1641 */ 1642 int fr_verifysrc(fin) 1643 fr_info_t *fin; 1644 { 1645 net_data_t net_data_p; 1646 phy_if_t phy_ifdata_routeto; 1647 struct sockaddr sin; 1648 ipf_stack_t *ifs = fin->fin_ifs; 1649 1650 if (fin->fin_v == 4) { 1651 net_data_p = ifs->ifs_ipf_ipv4; 1652 } else if (fin->fin_v == 6) { 1653 net_data_p = ifs->ifs_ipf_ipv6; 1654 } else { 1655 return (0); 1656 } 1657 1658 /* Get the index corresponding to the if name */ 1659 sin.sa_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 1660 bcopy(&fin->fin_saddr, &sin.sa_data, sizeof (struct in_addr)); 1661 phy_ifdata_routeto = net_routeto(net_data_p, &sin); 1662 1663 return (((phy_if_t)fin->fin_ifp == phy_ifdata_routeto) ? 1 : 0); 1664 } 1665 1666 1667 /* 1668 * Function: fr_fastroute 1669 * Returns: 0: success; 1670 * -1: failed 1671 * Parameters: 1672 * mb: the message block where ip head starts 1673 * mpp: the pointer to the pointer of the orignal 1674 * packet message 1675 * fin: packet information 1676 * fdp: destination interface information 1677 * if it is NULL, no interface information provided. 1678 * 1679 * This function is for fastroute/to/dup-to rules. It calls 1680 * pfil_make_lay2_packet to search route, make lay-2 header 1681 * ,and identify output queue for the IP packet. 1682 * The destination address depends on the following conditions: 1683 * 1: for fastroute rule, fdp is passed in as NULL, so the 1684 * destination address is the IP Packet's destination address 1685 * 2: for to/dup-to rule, if an ip address is specified after 1686 * the interface name, this address is the as destination 1687 * address. Otherwise IP Packet's destination address is used 1688 */ 1689 int fr_fastroute(mb, mpp, fin, fdp) 1690 mblk_t *mb, **mpp; 1691 fr_info_t *fin; 1692 frdest_t *fdp; 1693 { 1694 net_data_t net_data_p; 1695 net_inject_t inj_data; 1696 mblk_t *mp = NULL; 1697 frentry_t *fr = fin->fin_fr; 1698 qpktinfo_t *qpi; 1699 ip_t *ip; 1700 1701 struct sockaddr_in *sin; 1702 struct sockaddr_in6 *sin6; 1703 struct sockaddr *sinp; 1704 ipf_stack_t *ifs = fin->fin_ifs; 1705 #ifndef sparc 1706 u_short __iplen, __ipoff; 1707 #endif 1708 1709 if (fin->fin_v == 4) { 1710 net_data_p = ifs->ifs_ipf_ipv4; 1711 } else if (fin->fin_v == 6) { 1712 net_data_p = ifs->ifs_ipf_ipv6; 1713 } else { 1714 return (-1); 1715 } 1716 1717 ip = fin->fin_ip; 1718 qpi = fin->fin_qpi; 1719 1720 /* 1721 * If this is a duplicate mblk then we want ip to point at that 1722 * data, not the original, if and only if it is already pointing at 1723 * the current mblk data. 1724 * 1725 * Otherwise, if it's not a duplicate, and we're not already pointing 1726 * at the current mblk data, then we want to ensure that the data 1727 * points at ip. 1728 */ 1729 1730 if ((ip == (ip_t *)qpi->qpi_m->b_rptr) && (qpi->qpi_m != mb)) { 1731 ip = (ip_t *)mb->b_rptr; 1732 } else if ((qpi->qpi_m == mb) && (ip != (ip_t *)qpi->qpi_m->b_rptr)) { 1733 qpi->qpi_m->b_rptr = (uchar_t *)ip; 1734 qpi->qpi_off = 0; 1735 } 1736 1737 /* 1738 * If there is another M_PROTO, we don't want it 1739 */ 1740 if (*mpp != mb) { 1741 mp = unlinkb(*mpp); 1742 freeb(*mpp); 1743 *mpp = mp; 1744 } 1745 1746 sinp = (struct sockaddr *)&inj_data.ni_addr; 1747 sin = (struct sockaddr_in *)sinp; 1748 sin6 = (struct sockaddr_in6 *)sinp; 1749 bzero((char *)&inj_data.ni_addr, sizeof (inj_data.ni_addr)); 1750 inj_data.ni_addr.ss_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 1751 inj_data.ni_packet = mb; 1752 1753 /* 1754 * In case we're here due to "to <if>" being used with 1755 * "keep state", check that we're going in the correct 1756 * direction. 1757 */ 1758 if (fdp != NULL) { 1759 if ((fr != NULL) && (fdp->fd_ifp != NULL) && 1760 (fin->fin_rev != 0) && (fdp == &fr->fr_tif)) 1761 goto bad_fastroute; 1762 inj_data.ni_physical = (phy_if_t)fdp->fd_ifp; 1763 if (fin->fin_v == 4) { 1764 sin->sin_addr = fdp->fd_ip; 1765 } else { 1766 sin6->sin6_addr = fdp->fd_ip6.in6; 1767 } 1768 } else { 1769 if (fin->fin_v == 4) { 1770 sin->sin_addr = ip->ip_dst; 1771 } else { 1772 sin6->sin6_addr = ((ip6_t *)ip)->ip6_dst; 1773 } 1774 inj_data.ni_physical = net_routeto(net_data_p, sinp); 1775 } 1776 1777 /* 1778 * Clear the hardware checksum flags from packets that we are doing 1779 * input processing on as leaving them set will cause the outgoing 1780 * NIC (if it supports hardware checksum) to calculate them anew, 1781 * using the old (correct) checksums as the pseudo value to start 1782 * from. 1783 */ 1784 if (fin->fin_out == 0) { 1785 DB_CKSUMFLAGS(mb) = 0; 1786 } 1787 1788 *mpp = mb; 1789 1790 if (fin->fin_out == 0) { 1791 void *saveifp; 1792 u_32_t pass; 1793 1794 saveifp = fin->fin_ifp; 1795 fin->fin_ifp = (void *)inj_data.ni_physical; 1796 fin->fin_flx &= ~FI_STATE; 1797 fin->fin_out = 1; 1798 (void) fr_acctpkt(fin, &pass); 1799 fin->fin_fr = NULL; 1800 if (!fr || !(fr->fr_flags & FR_RETMASK)) 1801 (void) fr_checkstate(fin, &pass); 1802 if (fr_checknatout(fin, NULL) == -1) 1803 goto bad_fastroute; 1804 fin->fin_out = 0; 1805 fin->fin_ifp = saveifp; 1806 1807 if (fin->fin_nat != NULL) 1808 fr_natderef((nat_t **)&fin->fin_nat, ifs); 1809 } 1810 #ifndef sparc 1811 if (fin->fin_v == 4) { 1812 __iplen = (u_short)ip->ip_len, 1813 __ipoff = (u_short)ip->ip_off; 1814 1815 ip->ip_len = htons(__iplen); 1816 ip->ip_off = htons(__ipoff); 1817 } 1818 #endif 1819 1820 if (net_data_p) { 1821 if (net_inject(net_data_p, NI_DIRECT_OUT, &inj_data) < 0) { 1822 return (-1); 1823 } 1824 } 1825 1826 ifs->ifs_fr_frouteok[0]++; 1827 return 0; 1828 bad_fastroute: 1829 freemsg(mb); 1830 ifs->ifs_fr_frouteok[1]++; 1831 return -1; 1832 } 1833 1834 1835 /* ------------------------------------------------------------------------ */ 1836 /* Function: ipf_hook_out */ 1837 /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1838 /* Parameters: event(I) - pointer to event */ 1839 /* info(I) - pointer to hook information for firewalling */ 1840 /* */ 1841 /* Calling ipf_hook. */ 1842 /* ------------------------------------------------------------------------ */ 1843 /*ARGSUSED*/ 1844 int ipf_hook4_out(hook_event_token_t token, hook_data_t info, netstack_t *ns) 1845 { 1846 return ipf_hook4(info, 1, 0, ns); 1847 } 1848 /*ARGSUSED*/ 1849 int ipf_hook6_out(hook_event_token_t token, hook_data_t info, netstack_t *ns) 1850 { 1851 return ipf_hook6(info, 1, 0, ns); 1852 } 1853 1854 /* ------------------------------------------------------------------------ */ 1855 /* Function: ipf_hook_in */ 1856 /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1857 /* Parameters: event(I) - pointer to event */ 1858 /* info(I) - pointer to hook information for firewalling */ 1859 /* */ 1860 /* Calling ipf_hook. */ 1861 /* ------------------------------------------------------------------------ */ 1862 /*ARGSUSED*/ 1863 int ipf_hook4_in(hook_event_token_t token, hook_data_t info, netstack_t *ns) 1864 { 1865 return ipf_hook4(info, 0, 0, ns); 1866 } 1867 /*ARGSUSED*/ 1868 int ipf_hook6_in(hook_event_token_t token, hook_data_t info, netstack_t *ns) 1869 { 1870 return ipf_hook6(info, 0, 0, ns); 1871 } 1872 1873 1874 /* ------------------------------------------------------------------------ */ 1875 /* Function: ipf_hook_loop_out */ 1876 /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1877 /* Parameters: event(I) - pointer to event */ 1878 /* info(I) - pointer to hook information for firewalling */ 1879 /* */ 1880 /* Calling ipf_hook. */ 1881 /* ------------------------------------------------------------------------ */ 1882 /*ARGSUSED*/ 1883 int ipf_hook4_loop_out(hook_event_token_t token, hook_data_t info, 1884 netstack_t *ns) 1885 { 1886 return ipf_hook4(info, 1, FI_NOCKSUM, ns); 1887 } 1888 /*ARGSUSED*/ 1889 int ipf_hook6_loop_out(hook_event_token_t token, hook_data_t info, 1890 netstack_t *ns) 1891 { 1892 return ipf_hook6(info, 1, FI_NOCKSUM, ns); 1893 } 1894 1895 /* ------------------------------------------------------------------------ */ 1896 /* Function: ipf_hook_loop_in */ 1897 /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1898 /* Parameters: event(I) - pointer to event */ 1899 /* info(I) - pointer to hook information for firewalling */ 1900 /* */ 1901 /* Calling ipf_hook. */ 1902 /* ------------------------------------------------------------------------ */ 1903 /*ARGSUSED*/ 1904 int ipf_hook4_loop_in(hook_event_token_t token, hook_data_t info, 1905 netstack_t *ns) 1906 { 1907 return ipf_hook4(info, 0, FI_NOCKSUM, ns); 1908 } 1909 /*ARGSUSED*/ 1910 int ipf_hook6_loop_in(hook_event_token_t token, hook_data_t info, 1911 netstack_t *ns) 1912 { 1913 return ipf_hook6(info, 0, FI_NOCKSUM, ns); 1914 } 1915 1916 /* ------------------------------------------------------------------------ */ 1917 /* Function: ipf_hook */ 1918 /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1919 /* Parameters: info(I) - pointer to hook information for firewalling */ 1920 /* out(I) - whether packet is going in or out */ 1921 /* loopback(I) - whether packet is a loopback packet or not */ 1922 /* */ 1923 /* Stepping stone function between the IP mainline and IPFilter. Extracts */ 1924 /* parameters out of the info structure and forms them up to be useful for */ 1925 /* calling ipfilter. */ 1926 /* ------------------------------------------------------------------------ */ 1927 int ipf_hook4(hook_data_t info, int out, int loopback, netstack_t *ns) 1928 { 1929 hook_pkt_event_t *fw; 1930 int rval, hlen; 1931 qpktinfo_t qpi; 1932 u_short swap; 1933 phy_if_t phy; 1934 ip_t *ip; 1935 1936 fw = (hook_pkt_event_t *)info; 1937 1938 ASSERT(fw != NULL); 1939 phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp; 1940 1941 ip = fw->hpe_hdr; 1942 swap = ntohs(ip->ip_len); 1943 ip->ip_len = swap; 1944 swap = ntohs(ip->ip_off); 1945 ip->ip_off = swap; 1946 hlen = IPH_HDR_LENGTH(ip); 1947 1948 qpi.qpi_m = fw->hpe_mb; 1949 qpi.qpi_data = fw->hpe_hdr; 1950 qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr; 1951 qpi.qpi_ill = (void *)phy; 1952 qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST); 1953 if (qpi.qpi_flags) 1954 qpi.qpi_flags |= FI_MBCAST; 1955 qpi.qpi_flags |= loopback; 1956 1957 rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, 1958 &qpi, fw->hpe_mp, ns->netstack_ipf); 1959 1960 /* For fastroute cases, fr_check returns 0 with mp set to NULL */ 1961 if (rval == 0 && *(fw->hpe_mp) == NULL) 1962 rval = 1; 1963 1964 /* Notify IP the packet mblk_t and IP header pointers. */ 1965 fw->hpe_mb = qpi.qpi_m; 1966 fw->hpe_hdr = qpi.qpi_data; 1967 if (rval == 0) { 1968 ip = qpi.qpi_data; 1969 swap = ntohs(ip->ip_len); 1970 ip->ip_len = swap; 1971 swap = ntohs(ip->ip_off); 1972 ip->ip_off = swap; 1973 } 1974 return rval; 1975 1976 } 1977 int ipf_hook6(hook_data_t info, int out, int loopback, netstack_t *ns) 1978 { 1979 hook_pkt_event_t *fw; 1980 int rval, hlen; 1981 qpktinfo_t qpi; 1982 phy_if_t phy; 1983 1984 fw = (hook_pkt_event_t *)info; 1985 1986 ASSERT(fw != NULL); 1987 phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp; 1988 1989 hlen = sizeof (ip6_t); 1990 1991 qpi.qpi_m = fw->hpe_mb; 1992 qpi.qpi_data = fw->hpe_hdr; 1993 qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr; 1994 qpi.qpi_ill = (void *)phy; 1995 qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST); 1996 if (qpi.qpi_flags) 1997 qpi.qpi_flags |= FI_MBCAST; 1998 qpi.qpi_flags |= loopback; 1999 2000 rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, 2001 &qpi, fw->hpe_mp, ns->netstack_ipf); 2002 2003 /* For fastroute cases, fr_check returns 0 with mp set to NULL */ 2004 if (rval == 0 && *(fw->hpe_mp) == NULL) 2005 rval = 1; 2006 2007 /* Notify IP the packet mblk_t and IP header pointers. */ 2008 fw->hpe_mb = qpi.qpi_m; 2009 fw->hpe_hdr = qpi.qpi_data; 2010 return rval; 2011 2012 } 2013 2014 2015 /* ------------------------------------------------------------------------ */ 2016 /* Function: ipf_nic_event_v4 */ 2017 /* Returns: int - 0 == no problems encountered */ 2018 /* Parameters: event(I) - pointer to event */ 2019 /* info(I) - pointer to information about a NIC event */ 2020 /* */ 2021 /* Function to receive asynchronous NIC events from IP */ 2022 /* ------------------------------------------------------------------------ */ 2023 /*ARGSUSED*/ 2024 int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info, 2025 netstack_t *ns) 2026 { 2027 struct sockaddr_in *sin; 2028 hook_nic_event_t *hn; 2029 ipf_stack_t *ifs = ns->netstack_ipf; 2030 2031 hn = (hook_nic_event_t *)info; 2032 2033 switch (hn->hne_event) 2034 { 2035 case NE_PLUMB : 2036 frsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, hn->hne_data, 2037 ifs); 2038 fr_natifpsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, 2039 hn->hne_data, ifs); 2040 fr_statesync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, 2041 hn->hne_data, ifs); 2042 break; 2043 2044 case NE_UNPLUMB : 2045 frsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 2046 fr_natifpsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, 2047 ifs); 2048 fr_statesync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 2049 break; 2050 2051 case NE_ADDRESS_CHANGE : 2052 /* 2053 * We only respond to events for logical interface 0 because 2054 * IPFilter only uses the first address given to a network 2055 * interface. We check for hne_lif==1 because the netinfo 2056 * code maps adds 1 to the lif number so that it can return 2057 * 0 to indicate "no more lifs" when walking them. 2058 */ 2059 if (hn->hne_lif == 1) { 2060 frsync(IPFSYNC_RESYNC, 4, (void *)hn->hne_nic, NULL, 2061 ifs); 2062 sin = hn->hne_data; 2063 fr_nataddrsync(4, (void *)hn->hne_nic, &sin->sin_addr, 2064 ifs); 2065 } 2066 break; 2067 2068 default : 2069 break; 2070 } 2071 2072 return 0; 2073 } 2074 2075 2076 /* ------------------------------------------------------------------------ */ 2077 /* Function: ipf_nic_event_v6 */ 2078 /* Returns: int - 0 == no problems encountered */ 2079 /* Parameters: event(I) - pointer to event */ 2080 /* info(I) - pointer to information about a NIC event */ 2081 /* */ 2082 /* Function to receive asynchronous NIC events from IP */ 2083 /* ------------------------------------------------------------------------ */ 2084 /*ARGSUSED*/ 2085 int ipf_nic_event_v6(hook_event_token_t event, hook_data_t info, 2086 netstack_t *ns) 2087 { 2088 struct sockaddr_in6 *sin6; 2089 hook_nic_event_t *hn; 2090 ipf_stack_t *ifs = ns->netstack_ipf; 2091 2092 hn = (hook_nic_event_t *)info; 2093 2094 switch (hn->hne_event) 2095 { 2096 case NE_PLUMB : 2097 frsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2098 hn->hne_data, ifs); 2099 fr_natifpsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2100 hn->hne_data, ifs); 2101 fr_statesync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2102 hn->hne_data, ifs); 2103 break; 2104 2105 case NE_UNPLUMB : 2106 frsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2107 fr_natifpsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, 2108 ifs); 2109 fr_statesync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2110 break; 2111 2112 case NE_ADDRESS_CHANGE : 2113 if (hn->hne_lif == 1) { 2114 sin6 = hn->hne_data; 2115 fr_nataddrsync(6, (void *)hn->hne_nic, &sin6->sin6_addr, 2116 ifs); 2117 } 2118 break; 2119 default : 2120 break; 2121 } 2122 2123 return 0; 2124 } 2125