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