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 if (ifs->ifs_fr_running > 0) 776 error = 0; 777 else 778 error = iplattach(ifs, ns); 779 if (error == 0) { 780 if (ifs->ifs_fr_timer_id == NULL) { 781 int hz = drv_usectohz(500000); 782 783 ifs->ifs_fr_timer_id = timeout(fr_slowtimer, 784 (void *)ifs, 785 hz); 786 } 787 ifs->ifs_fr_running = 1; 788 } else { 789 (void) ipldetach(ifs); 790 } 791 } else { 792 error = ipldetach(ifs); 793 if (error == 0) 794 ifs->ifs_fr_running = -1; 795 } 796 797 return error; 798 } 799 800 801 phy_if_t get_unit(name, v, ifs) 802 char *name; 803 int v; 804 ipf_stack_t *ifs; 805 { 806 net_data_t nif; 807 808 if (v == 4) 809 nif = ifs->ifs_ipf_ipv4; 810 else if (v == 6) 811 nif = ifs->ifs_ipf_ipv6; 812 else 813 return 0; 814 815 nif->netd_netstack = ifs->ifs_netstack; 816 817 return (net_phylookup(nif, name)); 818 } 819 820 /* 821 * routines below for saving IP headers to buffer 822 */ 823 /*ARGSUSED*/ 824 int iplopen(devp, flags, otype, cred) 825 dev_t *devp; 826 int flags, otype; 827 cred_t *cred; 828 { 829 minor_t min = getminor(*devp); 830 831 #ifdef IPFDEBUG 832 cmn_err(CE_CONT, "iplopen(%x,%x,%x,%x)\n", devp, flags, otype, cred); 833 #endif 834 if (!(otype & OTYP_CHR)) 835 return ENXIO; 836 837 min = (IPL_LOGMAX < min) ? ENXIO : 0; 838 return min; 839 } 840 841 842 /*ARGSUSED*/ 843 int iplclose(dev, flags, otype, cred) 844 dev_t dev; 845 int flags, otype; 846 cred_t *cred; 847 { 848 minor_t min = getminor(dev); 849 850 #ifdef IPFDEBUG 851 cmn_err(CE_CONT, "iplclose(%x,%x,%x,%x)\n", dev, flags, otype, cred); 852 #endif 853 854 min = (IPL_LOGMAX < min) ? ENXIO : 0; 855 return min; 856 } 857 858 #ifdef IPFILTER_LOG 859 /* 860 * iplread/ipllog 861 * both of these must operate with at least splnet() lest they be 862 * called during packet processing and cause an inconsistancy to appear in 863 * the filter lists. 864 */ 865 /*ARGSUSED*/ 866 int iplread(dev, uio, cp) 867 dev_t dev; 868 register struct uio *uio; 869 cred_t *cp; 870 { 871 netstack_t *ns; 872 ipf_stack_t *ifs; 873 int ret; 874 875 ns = netstack_find_by_cred(cp); 876 ASSERT(ns != NULL); 877 ifs = ns->netstack_ipf; 878 ASSERT(ifs != NULL); 879 880 # ifdef IPFDEBUG 881 cmn_err(CE_CONT, "iplread(%x,%x,%x)\n", dev, uio, cp); 882 # endif 883 884 if (ifs->ifs_fr_running < 1) { 885 netstack_rele(ifs->ifs_netstack); 886 return EIO; 887 } 888 889 # ifdef IPFILTER_SYNC 890 if (getminor(dev) == IPL_LOGSYNC) { 891 netstack_rele(ifs->ifs_netstack); 892 return ipfsync_read(uio); 893 } 894 # endif 895 896 ret = ipflog_read(getminor(dev), uio, ifs); 897 netstack_rele(ifs->ifs_netstack); 898 return ret; 899 } 900 #endif /* IPFILTER_LOG */ 901 902 903 /* 904 * iplread/ipllog 905 * both of these must operate with at least splnet() lest they be 906 * called during packet processing and cause an inconsistancy to appear in 907 * the filter lists. 908 */ 909 int iplwrite(dev, uio, cp) 910 dev_t dev; 911 register struct uio *uio; 912 cred_t *cp; 913 { 914 netstack_t *ns; 915 ipf_stack_t *ifs; 916 917 ns = netstack_find_by_cred(cp); 918 ASSERT(ns != NULL); 919 ifs = ns->netstack_ipf; 920 ASSERT(ifs != NULL); 921 922 #ifdef IPFDEBUG 923 cmn_err(CE_CONT, "iplwrite(%x,%x,%x)\n", dev, uio, cp); 924 #endif 925 926 if (ifs->ifs_fr_running < 1) { 927 netstack_rele(ifs->ifs_netstack); 928 return EIO; 929 } 930 931 #ifdef IPFILTER_SYNC 932 if (getminor(dev) == IPL_LOGSYNC) 933 return ipfsync_write(uio); 934 #endif /* IPFILTER_SYNC */ 935 dev = dev; /* LINT */ 936 uio = uio; /* LINT */ 937 cp = cp; /* LINT */ 938 netstack_rele(ifs->ifs_netstack); 939 return ENXIO; 940 } 941 942 943 /* 944 * fr_send_reset - this could conceivably be a call to tcp_respond(), but that 945 * requires a large amount of setting up and isn't any more efficient. 946 */ 947 int fr_send_reset(fin) 948 fr_info_t *fin; 949 { 950 tcphdr_t *tcp, *tcp2; 951 int tlen, hlen; 952 mblk_t *m; 953 #ifdef USE_INET6 954 ip6_t *ip6; 955 #endif 956 ip_t *ip; 957 958 tcp = fin->fin_dp; 959 if (tcp->th_flags & TH_RST) 960 return -1; 961 962 #ifndef IPFILTER_CKSUM 963 if (fr_checkl4sum(fin) == -1) 964 return -1; 965 #endif 966 967 tlen = (tcp->th_flags & (TH_SYN|TH_FIN)) ? 1 : 0; 968 #ifdef USE_INET6 969 if (fin->fin_v == 6) 970 hlen = sizeof(ip6_t); 971 else 972 #endif 973 hlen = sizeof(ip_t); 974 hlen += sizeof(*tcp2); 975 if ((m = (mblk_t *)allocb(hlen + 64, BPRI_HI)) == NULL) 976 return -1; 977 978 m->b_rptr += 64; 979 MTYPE(m) = M_DATA; 980 m->b_wptr = m->b_rptr + hlen; 981 ip = (ip_t *)m->b_rptr; 982 bzero((char *)ip, hlen); 983 tcp2 = (struct tcphdr *)(m->b_rptr + hlen - sizeof(*tcp2)); 984 tcp2->th_dport = tcp->th_sport; 985 tcp2->th_sport = tcp->th_dport; 986 if (tcp->th_flags & TH_ACK) { 987 tcp2->th_seq = tcp->th_ack; 988 tcp2->th_flags = TH_RST; 989 } else { 990 tcp2->th_ack = ntohl(tcp->th_seq); 991 tcp2->th_ack += tlen; 992 tcp2->th_ack = htonl(tcp2->th_ack); 993 tcp2->th_flags = TH_RST|TH_ACK; 994 } 995 tcp2->th_off = sizeof(struct tcphdr) >> 2; 996 997 ip->ip_v = fin->fin_v; 998 #ifdef USE_INET6 999 if (fin->fin_v == 6) { 1000 ip6 = (ip6_t *)m->b_rptr; 1001 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 1002 ip6->ip6_src = fin->fin_dst6; 1003 ip6->ip6_dst = fin->fin_src6; 1004 ip6->ip6_plen = htons(sizeof(*tcp)); 1005 ip6->ip6_nxt = IPPROTO_TCP; 1006 tcp2->th_sum = fr_cksum(m, (ip_t *)ip6, IPPROTO_TCP, tcp2); 1007 } else 1008 #endif 1009 { 1010 ip->ip_src.s_addr = fin->fin_daddr; 1011 ip->ip_dst.s_addr = fin->fin_saddr; 1012 ip->ip_id = fr_nextipid(fin); 1013 ip->ip_hl = sizeof(*ip) >> 2; 1014 ip->ip_p = IPPROTO_TCP; 1015 ip->ip_len = sizeof(*ip) + sizeof(*tcp); 1016 ip->ip_tos = fin->fin_ip->ip_tos; 1017 tcp2->th_sum = fr_cksum(m, ip, IPPROTO_TCP, tcp2); 1018 } 1019 return fr_send_ip(fin, m, &m); 1020 } 1021 1022 /* 1023 * Function: fr_send_ip 1024 * Returns: 0: success 1025 * -1: failed 1026 * Parameters: 1027 * fin: packet information 1028 * m: the message block where ip head starts 1029 * 1030 * Send a new packet through the IP stack. 1031 * 1032 * For IPv4 packets, ip_len must be in host byte order, and ip_v, 1033 * ip_ttl, ip_off, and ip_sum are ignored (filled in by this 1034 * function). 1035 * 1036 * For IPv6 packets, ip6_flow, ip6_vfc, and ip6_hlim are filled 1037 * in by this function. 1038 * 1039 * All other portions of the packet must be in on-the-wire format. 1040 */ 1041 /*ARGSUSED*/ 1042 static int fr_send_ip(fin, m, mpp) 1043 fr_info_t *fin; 1044 mblk_t *m, **mpp; 1045 { 1046 qpktinfo_t qpi, *qpip; 1047 fr_info_t fnew; 1048 ip_t *ip; 1049 int i, hlen; 1050 ipf_stack_t *ifs = fin->fin_ifs; 1051 1052 ip = (ip_t *)m->b_rptr; 1053 bzero((char *)&fnew, sizeof(fnew)); 1054 1055 #ifdef USE_INET6 1056 if (fin->fin_v == 6) { 1057 ip6_t *ip6; 1058 1059 ip6 = (ip6_t *)ip; 1060 ip6->ip6_vfc = 0x60; 1061 ip6->ip6_hlim = 127; 1062 fnew.fin_v = 6; 1063 hlen = sizeof(*ip6); 1064 fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen; 1065 } else 1066 #endif 1067 { 1068 fnew.fin_v = 4; 1069 #if SOLARIS2 >= 10 1070 ip->ip_ttl = 255; 1071 if (net_getpmtuenabled(ifs->ifs_ipf_ipv4) == 1) 1072 ip->ip_off = htons(IP_DF); 1073 #else 1074 if (ip_ttl_ptr != NULL) 1075 ip->ip_ttl = (u_char)(*ip_ttl_ptr); 1076 else 1077 ip->ip_ttl = 63; 1078 if (ip_mtudisc != NULL) 1079 ip->ip_off = htons(*ip_mtudisc ? IP_DF : 0); 1080 else 1081 ip->ip_off = htons(IP_DF); 1082 #endif 1083 /* 1084 * The dance with byte order and ip_len/ip_off is because in 1085 * fr_fastroute, it expects them to be in host byte order but 1086 * ipf_cksum expects them to be in network byte order. 1087 */ 1088 ip->ip_len = htons(ip->ip_len); 1089 ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip)); 1090 ip->ip_len = ntohs(ip->ip_len); 1091 ip->ip_off = ntohs(ip->ip_off); 1092 hlen = sizeof(*ip); 1093 fnew.fin_plen = ip->ip_len; 1094 } 1095 1096 qpip = fin->fin_qpi; 1097 qpi.qpi_off = 0; 1098 qpi.qpi_ill = qpip->qpi_ill; 1099 qpi.qpi_m = m; 1100 qpi.qpi_data = ip; 1101 fnew.fin_qpi = &qpi; 1102 fnew.fin_ifp = fin->fin_ifp; 1103 fnew.fin_flx = FI_NOCKSUM; 1104 fnew.fin_m = m; 1105 fnew.fin_ip = ip; 1106 fnew.fin_mp = mpp; 1107 fnew.fin_hlen = hlen; 1108 fnew.fin_dp = (char *)ip + hlen; 1109 fnew.fin_ifs = fin->fin_ifs; 1110 (void) fr_makefrip(hlen, ip, &fnew); 1111 1112 i = fr_fastroute(m, mpp, &fnew, NULL); 1113 return i; 1114 } 1115 1116 1117 int fr_send_icmp_err(type, fin, dst) 1118 int type; 1119 fr_info_t *fin; 1120 int dst; 1121 { 1122 struct in_addr dst4; 1123 struct icmp *icmp; 1124 qpktinfo_t *qpi; 1125 int hlen, code; 1126 phy_if_t phy; 1127 u_short sz; 1128 #ifdef USE_INET6 1129 mblk_t *mb; 1130 #endif 1131 mblk_t *m; 1132 #ifdef USE_INET6 1133 ip6_t *ip6; 1134 #endif 1135 ip_t *ip; 1136 ipf_stack_t *ifs = fin->fin_ifs; 1137 1138 if ((type < 0) || (type > ICMP_MAXTYPE)) 1139 return -1; 1140 1141 code = fin->fin_icode; 1142 #ifdef USE_INET6 1143 if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) 1144 return -1; 1145 #endif 1146 1147 #ifndef IPFILTER_CKSUM 1148 if (fr_checkl4sum(fin) == -1) 1149 return -1; 1150 #endif 1151 1152 qpi = fin->fin_qpi; 1153 1154 #ifdef USE_INET6 1155 mb = fin->fin_qfm; 1156 1157 if (fin->fin_v == 6) { 1158 sz = sizeof(ip6_t); 1159 sz += MIN(mb->b_wptr - mb->b_rptr, 512); 1160 hlen = sizeof(ip6_t); 1161 type = icmptoicmp6types[type]; 1162 if (type == ICMP6_DST_UNREACH) 1163 code = icmptoicmp6unreach[code]; 1164 } else 1165 #endif 1166 { 1167 if ((fin->fin_p == IPPROTO_ICMP) && 1168 !(fin->fin_flx & FI_SHORT)) 1169 switch (ntohs(fin->fin_data[0]) >> 8) 1170 { 1171 case ICMP_ECHO : 1172 case ICMP_TSTAMP : 1173 case ICMP_IREQ : 1174 case ICMP_MASKREQ : 1175 break; 1176 default : 1177 return 0; 1178 } 1179 1180 sz = sizeof(ip_t) * 2; 1181 sz += 8; /* 64 bits of data */ 1182 hlen = sizeof(ip_t); 1183 } 1184 1185 sz += offsetof(struct icmp, icmp_ip); 1186 if ((m = (mblk_t *)allocb((size_t)sz + 64, BPRI_HI)) == NULL) 1187 return -1; 1188 MTYPE(m) = M_DATA; 1189 m->b_rptr += 64; 1190 m->b_wptr = m->b_rptr + sz; 1191 bzero((char *)m->b_rptr, (size_t)sz); 1192 ip = (ip_t *)m->b_rptr; 1193 ip->ip_v = fin->fin_v; 1194 icmp = (struct icmp *)(m->b_rptr + hlen); 1195 icmp->icmp_type = type & 0xff; 1196 icmp->icmp_code = code & 0xff; 1197 phy = (phy_if_t)qpi->qpi_ill; 1198 if (type == ICMP_UNREACH && (phy != 0) && 1199 fin->fin_icode == ICMP_UNREACH_NEEDFRAG) 1200 icmp->icmp_nextmtu = net_getmtu(ifs->ifs_ipf_ipv4, phy,0 ); 1201 1202 #ifdef USE_INET6 1203 if (fin->fin_v == 6) { 1204 struct in6_addr dst6; 1205 int csz; 1206 1207 if (dst == 0) { 1208 ipf_stack_t *ifs = fin->fin_ifs; 1209 1210 if (fr_ifpaddr(6, FRI_NORMAL, (void *)phy, 1211 (void *)&dst6, NULL, ifs) == -1) { 1212 FREE_MB_T(m); 1213 return -1; 1214 } 1215 } else 1216 dst6 = fin->fin_dst6; 1217 1218 csz = sz; 1219 sz -= sizeof(ip6_t); 1220 ip6 = (ip6_t *)m->b_rptr; 1221 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 1222 ip6->ip6_plen = htons((u_short)sz); 1223 ip6->ip6_nxt = IPPROTO_ICMPV6; 1224 ip6->ip6_src = dst6; 1225 ip6->ip6_dst = fin->fin_src6; 1226 sz -= offsetof(struct icmp, icmp_ip); 1227 bcopy((char *)mb->b_rptr, (char *)&icmp->icmp_ip, sz); 1228 icmp->icmp_cksum = csz - sizeof(ip6_t); 1229 } else 1230 #endif 1231 { 1232 ip->ip_hl = sizeof(*ip) >> 2; 1233 ip->ip_p = IPPROTO_ICMP; 1234 ip->ip_id = fin->fin_ip->ip_id; 1235 ip->ip_tos = fin->fin_ip->ip_tos; 1236 ip->ip_len = (u_short)sz; 1237 if (dst == 0) { 1238 ipf_stack_t *ifs = fin->fin_ifs; 1239 1240 if (fr_ifpaddr(4, FRI_NORMAL, (void *)phy, 1241 (void *)&dst4, NULL, ifs) == -1) { 1242 FREE_MB_T(m); 1243 return -1; 1244 } 1245 } else { 1246 dst4 = fin->fin_dst; 1247 } 1248 ip->ip_src = dst4; 1249 ip->ip_dst = fin->fin_src; 1250 bcopy((char *)fin->fin_ip, (char *)&icmp->icmp_ip, 1251 sizeof(*fin->fin_ip)); 1252 bcopy((char *)fin->fin_ip + fin->fin_hlen, 1253 (char *)&icmp->icmp_ip + sizeof(*fin->fin_ip), 8); 1254 icmp->icmp_ip.ip_len = htons(icmp->icmp_ip.ip_len); 1255 icmp->icmp_ip.ip_off = htons(icmp->icmp_ip.ip_off); 1256 icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 1257 sz - sizeof(ip_t)); 1258 } 1259 1260 /* 1261 * Need to exit out of these so we don't recursively call rw_enter 1262 * from fr_qout. 1263 */ 1264 return fr_send_ip(fin, m, &m); 1265 } 1266 1267 #include <sys/time.h> 1268 #include <sys/varargs.h> 1269 1270 #ifndef _KERNEL 1271 #include <stdio.h> 1272 #endif 1273 1274 #define NULLADDR_RATE_LIMIT 10 /* 10 seconds */ 1275 1276 1277 /* 1278 * Print out warning message at rate-limited speed. 1279 */ 1280 static void rate_limit_message(ipf_stack_t *ifs, 1281 int rate, const char *message, ...) 1282 { 1283 static time_t last_time = 0; 1284 time_t now; 1285 va_list args; 1286 char msg_buf[256]; 1287 int need_printed = 0; 1288 1289 now = ddi_get_time(); 1290 1291 /* make sure, no multiple entries */ 1292 ASSERT(MUTEX_NOT_HELD(&(ifs->ifs_ipf_rw.ipf_lk))); 1293 MUTEX_ENTER(&ifs->ifs_ipf_rw); 1294 if (now - last_time >= rate) { 1295 need_printed = 1; 1296 last_time = now; 1297 } 1298 MUTEX_EXIT(&ifs->ifs_ipf_rw); 1299 1300 if (need_printed) { 1301 va_start(args, message); 1302 (void)vsnprintf(msg_buf, 255, message, args); 1303 va_end(args); 1304 #ifdef _KERNEL 1305 cmn_err(CE_WARN, msg_buf); 1306 #else 1307 fprintf(std_err, msg_buf); 1308 #endif 1309 } 1310 } 1311 1312 /* 1313 * return the first IP Address associated with an interface 1314 */ 1315 /*ARGSUSED*/ 1316 int fr_ifpaddr(v, atype, ifptr, inp, inpmask, ifs) 1317 int v, atype; 1318 void *ifptr; 1319 struct in_addr *inp, *inpmask; 1320 ipf_stack_t *ifs; 1321 { 1322 struct sockaddr_in6 v6addr[2]; 1323 struct sockaddr_in v4addr[2]; 1324 net_ifaddr_t type[2]; 1325 net_data_t net_data; 1326 phy_if_t phyif; 1327 void *array; 1328 1329 switch (v) 1330 { 1331 case 4: 1332 net_data = ifs->ifs_ipf_ipv4; 1333 array = v4addr; 1334 break; 1335 case 6: 1336 net_data = ifs->ifs_ipf_ipv6; 1337 array = v6addr; 1338 break; 1339 default: 1340 net_data = NULL; 1341 break; 1342 } 1343 1344 if (net_data == NULL) 1345 return -1; 1346 1347 phyif = (phy_if_t)ifptr; 1348 1349 switch (atype) 1350 { 1351 case FRI_PEERADDR : 1352 type[0] = NA_PEER; 1353 break; 1354 1355 case FRI_BROADCAST : 1356 type[0] = NA_BROADCAST; 1357 break; 1358 1359 default : 1360 type[0] = NA_ADDRESS; 1361 break; 1362 } 1363 1364 type[1] = NA_NETMASK; 1365 1366 if (net_getlifaddr(net_data, phyif, 0, 2, type, array) < 0) 1367 return -1; 1368 1369 if (v == 6) { 1370 return fr_ifpfillv6addr(atype, &v6addr[0], &v6addr[1], 1371 inp, inpmask); 1372 } 1373 return fr_ifpfillv4addr(atype, &v4addr[0], &v4addr[1], inp, inpmask); 1374 } 1375 1376 1377 u_32_t fr_newisn(fin) 1378 fr_info_t *fin; 1379 { 1380 static int iss_seq_off = 0; 1381 u_char hash[16]; 1382 u_32_t newiss; 1383 MD5_CTX ctx; 1384 ipf_stack_t *ifs = fin->fin_ifs; 1385 1386 /* 1387 * Compute the base value of the ISS. It is a hash 1388 * of (saddr, sport, daddr, dport, secret). 1389 */ 1390 MD5Init(&ctx); 1391 1392 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 1393 sizeof(fin->fin_fi.fi_src)); 1394 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 1395 sizeof(fin->fin_fi.fi_dst)); 1396 MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 1397 1398 MD5Update(&ctx, ifs->ifs_ipf_iss_secret, sizeof(ifs->ifs_ipf_iss_secret)); 1399 1400 MD5Final(hash, &ctx); 1401 1402 bcopy(hash, &newiss, sizeof(newiss)); 1403 1404 /* 1405 * Now increment our "timer", and add it in to 1406 * the computed value. 1407 * 1408 * XXX Use `addin'? 1409 * XXX TCP_ISSINCR too large to use? 1410 */ 1411 iss_seq_off += 0x00010000; 1412 newiss += iss_seq_off; 1413 return newiss; 1414 } 1415 1416 1417 /* ------------------------------------------------------------------------ */ 1418 /* Function: fr_nextipid */ 1419 /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 1420 /* Parameters: fin(I) - pointer to packet information */ 1421 /* */ 1422 /* Returns the next IPv4 ID to use for this packet. */ 1423 /* ------------------------------------------------------------------------ */ 1424 u_short fr_nextipid(fin) 1425 fr_info_t *fin; 1426 { 1427 static u_short ipid = 0; 1428 ipstate_t *is; 1429 nat_t *nat; 1430 u_short id; 1431 ipf_stack_t *ifs = fin->fin_ifs; 1432 1433 MUTEX_ENTER(&ifs->ifs_ipf_rw); 1434 if (fin->fin_state != NULL) { 1435 is = fin->fin_state; 1436 id = (u_short)(is->is_pkts[(fin->fin_rev << 1) + 1] & 0xffff); 1437 } else if (fin->fin_nat != NULL) { 1438 nat = fin->fin_nat; 1439 id = (u_short)(nat->nat_pkts[fin->fin_out] & 0xffff); 1440 } else 1441 id = ipid++; 1442 MUTEX_EXIT(&ifs->ifs_ipf_rw); 1443 1444 return id; 1445 } 1446 1447 1448 #ifndef IPFILTER_CKSUM 1449 /* ARGSUSED */ 1450 #endif 1451 INLINE void fr_checkv4sum(fin) 1452 fr_info_t *fin; 1453 { 1454 #ifdef IPFILTER_CKSUM 1455 if (fr_checkl4sum(fin) == -1) 1456 fin->fin_flx |= FI_BAD; 1457 #endif 1458 } 1459 1460 1461 #ifdef USE_INET6 1462 # ifndef IPFILTER_CKSUM 1463 /* ARGSUSED */ 1464 # endif 1465 INLINE void fr_checkv6sum(fin) 1466 fr_info_t *fin; 1467 { 1468 # ifdef IPFILTER_CKSUM 1469 if (fr_checkl4sum(fin) == -1) 1470 fin->fin_flx |= FI_BAD; 1471 # endif 1472 } 1473 #endif /* USE_INET6 */ 1474 1475 1476 #if (SOLARIS2 < 7) 1477 void fr_slowtimer() 1478 #else 1479 /*ARGSUSED*/ 1480 void fr_slowtimer __P((void *arg)) 1481 #endif 1482 { 1483 ipf_stack_t *ifs = arg; 1484 1485 WRITE_ENTER(&ifs->ifs_ipf_global); 1486 if (ifs->ifs_fr_running == -1 || ifs->ifs_fr_running == 0) { 1487 ifs->ifs_fr_timer_id = timeout(fr_slowtimer, arg, drv_usectohz(500000)); 1488 RWLOCK_EXIT(&ifs->ifs_ipf_global); 1489 return; 1490 } 1491 MUTEX_DOWNGRADE(&ifs->ifs_ipf_global); 1492 1493 ipf_expiretokens(ifs); 1494 fr_fragexpire(ifs); 1495 fr_timeoutstate(ifs); 1496 fr_natexpire(ifs); 1497 fr_authexpire(ifs); 1498 ifs->ifs_fr_ticks++; 1499 if (ifs->ifs_fr_running == -1 || ifs->ifs_fr_running == 1) 1500 ifs->ifs_fr_timer_id = timeout(fr_slowtimer, arg, 1501 drv_usectohz(500000)); 1502 else 1503 ifs->ifs_fr_timer_id = NULL; 1504 RWLOCK_EXIT(&ifs->ifs_ipf_global); 1505 } 1506 1507 1508 /* ------------------------------------------------------------------------ */ 1509 /* Function: fr_pullup */ 1510 /* Returns: NULL == pullup failed, else pointer to protocol header */ 1511 /* Parameters: m(I) - pointer to buffer where data packet starts */ 1512 /* fin(I) - pointer to packet information */ 1513 /* len(I) - number of bytes to pullup */ 1514 /* */ 1515 /* Attempt to move at least len bytes (from the start of the buffer) into a */ 1516 /* single buffer for ease of access. Operating system native functions are */ 1517 /* used to manage buffers - if necessary. If the entire packet ends up in */ 1518 /* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */ 1519 /* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ 1520 /* and ONLY if the pullup succeeds. */ 1521 /* */ 1522 /* We assume that 'min' is a pointer to a buffer that is part of the chain */ 1523 /* of buffers that starts at *fin->fin_mp. */ 1524 /* ------------------------------------------------------------------------ */ 1525 void *fr_pullup(min, fin, len) 1526 mb_t *min; 1527 fr_info_t *fin; 1528 int len; 1529 { 1530 qpktinfo_t *qpi = fin->fin_qpi; 1531 int out = fin->fin_out, dpoff, ipoff; 1532 mb_t *m = min, *m1, *m2; 1533 char *ip; 1534 uint32_t start, stuff, end, value, flags; 1535 ipf_stack_t *ifs = fin->fin_ifs; 1536 1537 if (m == NULL) 1538 return NULL; 1539 1540 ip = (char *)fin->fin_ip; 1541 if ((fin->fin_flx & FI_COALESCE) != 0) 1542 return ip; 1543 1544 ipoff = fin->fin_ipoff; 1545 if (fin->fin_dp != NULL) 1546 dpoff = (char *)fin->fin_dp - (char *)ip; 1547 else 1548 dpoff = 0; 1549 1550 if (M_LEN(m) < len) { 1551 1552 /* 1553 * pfil_precheck ensures the IP header is on a 32bit 1554 * aligned address so simply fail if that isn't currently 1555 * the case (should never happen). 1556 */ 1557 int inc = 0; 1558 1559 if (ipoff > 0) { 1560 if ((ipoff & 3) != 0) { 1561 inc = 4 - (ipoff & 3); 1562 if (m->b_rptr - inc >= m->b_datap->db_base) 1563 m->b_rptr -= inc; 1564 else 1565 inc = 0; 1566 } 1567 } 1568 1569 /* 1570 * XXX This is here as a work around for a bug with DEBUG 1571 * XXX Solaris kernels. The problem is b_prev is used by IP 1572 * XXX code as a way to stash the phyint_index for a packet, 1573 * XXX this doesn't get reset by IP but freeb does an ASSERT() 1574 * XXX for both of these to be NULL. See 6442390. 1575 */ 1576 m1 = m; 1577 m2 = m->b_prev; 1578 1579 do { 1580 m1->b_next = NULL; 1581 m1->b_prev = NULL; 1582 m1 = m1->b_cont; 1583 } while (m1); 1584 1585 /* 1586 * Need to preserve checksum information by copying them 1587 * to newmp which heads the pulluped message. 1588 */ 1589 hcksum_retrieve(m, NULL, NULL, &start, &stuff, &end, 1590 &value, &flags); 1591 1592 if (pullupmsg(m, len + ipoff + inc) == 0) { 1593 ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[1]); 1594 FREE_MB_T(*fin->fin_mp); 1595 *fin->fin_mp = NULL; 1596 fin->fin_m = NULL; 1597 fin->fin_ip = NULL; 1598 fin->fin_dp = NULL; 1599 qpi->qpi_data = NULL; 1600 return NULL; 1601 } 1602 1603 (void) hcksum_assoc(m, NULL, NULL, start, stuff, end, 1604 value, flags, 0); 1605 1606 m->b_prev = m2; 1607 m->b_rptr += inc; 1608 fin->fin_m = m; 1609 ip = MTOD(m, char *) + ipoff; 1610 qpi->qpi_data = ip; 1611 } 1612 1613 ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[0]); 1614 fin->fin_ip = (ip_t *)ip; 1615 if (fin->fin_dp != NULL) 1616 fin->fin_dp = (char *)fin->fin_ip + dpoff; 1617 1618 if (len == fin->fin_plen) 1619 fin->fin_flx |= FI_COALESCE; 1620 return ip; 1621 } 1622 1623 1624 /* 1625 * Function: fr_verifysrc 1626 * Returns: int (really boolean) 1627 * Parameters: fin - packet information 1628 * 1629 * Check whether the packet has a valid source address for the interface on 1630 * which the packet arrived, implementing the "fr_chksrc" feature. 1631 * Returns true iff the packet's source address is valid. 1632 */ 1633 int fr_verifysrc(fin) 1634 fr_info_t *fin; 1635 { 1636 net_data_t net_data_p; 1637 phy_if_t phy_ifdata_routeto; 1638 struct sockaddr sin; 1639 ipf_stack_t *ifs = fin->fin_ifs; 1640 1641 if (fin->fin_v == 4) { 1642 net_data_p = ifs->ifs_ipf_ipv4; 1643 } else if (fin->fin_v == 6) { 1644 net_data_p = ifs->ifs_ipf_ipv6; 1645 } else { 1646 return (0); 1647 } 1648 1649 /* Get the index corresponding to the if name */ 1650 sin.sa_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 1651 bcopy(&fin->fin_saddr, &sin.sa_data, sizeof (struct in_addr)); 1652 phy_ifdata_routeto = net_routeto(net_data_p, &sin); 1653 1654 return (((phy_if_t)fin->fin_ifp == phy_ifdata_routeto) ? 1 : 0); 1655 } 1656 1657 1658 /* 1659 * Function: fr_fastroute 1660 * Returns: 0: success; 1661 * -1: failed 1662 * Parameters: 1663 * mb: the message block where ip head starts 1664 * mpp: the pointer to the pointer of the orignal 1665 * packet message 1666 * fin: packet information 1667 * fdp: destination interface information 1668 * if it is NULL, no interface information provided. 1669 * 1670 * This function is for fastroute/to/dup-to rules. It calls 1671 * pfil_make_lay2_packet to search route, make lay-2 header 1672 * ,and identify output queue for the IP packet. 1673 * The destination address depends on the following conditions: 1674 * 1: for fastroute rule, fdp is passed in as NULL, so the 1675 * destination address is the IP Packet's destination address 1676 * 2: for to/dup-to rule, if an ip address is specified after 1677 * the interface name, this address is the as destination 1678 * address. Otherwise IP Packet's destination address is used 1679 */ 1680 int fr_fastroute(mb, mpp, fin, fdp) 1681 mblk_t *mb, **mpp; 1682 fr_info_t *fin; 1683 frdest_t *fdp; 1684 { 1685 net_data_t net_data_p; 1686 net_inject_t inj_data; 1687 mblk_t *mp = NULL; 1688 frentry_t *fr = fin->fin_fr; 1689 qpktinfo_t *qpi; 1690 ip_t *ip; 1691 1692 struct sockaddr_in *sin; 1693 struct sockaddr_in6 *sin6; 1694 struct sockaddr *sinp; 1695 ipf_stack_t *ifs = fin->fin_ifs; 1696 #ifndef sparc 1697 u_short __iplen, __ipoff; 1698 #endif 1699 1700 if (fin->fin_v == 4) { 1701 net_data_p = ifs->ifs_ipf_ipv4; 1702 } else if (fin->fin_v == 6) { 1703 net_data_p = ifs->ifs_ipf_ipv6; 1704 } else { 1705 return (-1); 1706 } 1707 1708 ip = fin->fin_ip; 1709 qpi = fin->fin_qpi; 1710 1711 /* 1712 * If this is a duplicate mblk then we want ip to point at that 1713 * data, not the original, if and only if it is already pointing at 1714 * the current mblk data. 1715 * 1716 * Otherwise, if it's not a duplicate, and we're not already pointing 1717 * at the current mblk data, then we want to ensure that the data 1718 * points at ip. 1719 */ 1720 1721 if ((ip == (ip_t *)qpi->qpi_m->b_rptr) && (qpi->qpi_m != mb)) { 1722 ip = (ip_t *)mb->b_rptr; 1723 } else if ((qpi->qpi_m == mb) && (ip != (ip_t *)qpi->qpi_m->b_rptr)) { 1724 qpi->qpi_m->b_rptr = (uchar_t *)ip; 1725 qpi->qpi_off = 0; 1726 } 1727 1728 /* 1729 * If there is another M_PROTO, we don't want it 1730 */ 1731 if (*mpp != mb) { 1732 mp = unlinkb(*mpp); 1733 freeb(*mpp); 1734 *mpp = mp; 1735 } 1736 1737 sinp = (struct sockaddr *)&inj_data.ni_addr; 1738 sin = (struct sockaddr_in *)sinp; 1739 sin6 = (struct sockaddr_in6 *)sinp; 1740 bzero((char *)&inj_data.ni_addr, sizeof (inj_data.ni_addr)); 1741 inj_data.ni_addr.ss_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 1742 inj_data.ni_packet = mb; 1743 1744 /* 1745 * In case we're here due to "to <if>" being used with 1746 * "keep state", check that we're going in the correct 1747 * direction. 1748 */ 1749 if (fdp != NULL) { 1750 if ((fr != NULL) && (fdp->fd_ifp != NULL) && 1751 (fin->fin_rev != 0) && (fdp == &fr->fr_tif)) 1752 goto bad_fastroute; 1753 inj_data.ni_physical = (phy_if_t)fdp->fd_ifp; 1754 if (fin->fin_v == 4) { 1755 sin->sin_addr = fdp->fd_ip; 1756 } else { 1757 sin6->sin6_addr = fdp->fd_ip6.in6; 1758 } 1759 } else { 1760 if (fin->fin_v == 4) { 1761 sin->sin_addr = ip->ip_dst; 1762 } else { 1763 sin6->sin6_addr = ((ip6_t *)ip)->ip6_dst; 1764 } 1765 inj_data.ni_physical = net_routeto(net_data_p, sinp); 1766 } 1767 1768 /* 1769 * Clear the hardware checksum flags from packets that we are doing 1770 * input processing on as leaving them set will cause the outgoing 1771 * NIC (if it supports hardware checksum) to calculate them anew, 1772 * using the old (correct) checksums as the pseudo value to start 1773 * from. 1774 */ 1775 if (fin->fin_out == 0) { 1776 DB_CKSUMFLAGS(mb) = 0; 1777 } 1778 1779 *mpp = mb; 1780 1781 if (fin->fin_out == 0) { 1782 void *saveifp; 1783 u_32_t pass; 1784 1785 saveifp = fin->fin_ifp; 1786 fin->fin_ifp = (void *)inj_data.ni_physical; 1787 fin->fin_flx &= ~FI_STATE; 1788 fin->fin_out = 1; 1789 (void) fr_acctpkt(fin, &pass); 1790 fin->fin_fr = NULL; 1791 if (!fr || !(fr->fr_flags & FR_RETMASK)) 1792 (void) fr_checkstate(fin, &pass); 1793 if (fr_checknatout(fin, NULL) == -1) 1794 goto bad_fastroute; 1795 fin->fin_out = 0; 1796 fin->fin_ifp = saveifp; 1797 1798 if (fin->fin_nat != NULL) 1799 fr_natderef((nat_t **)&fin->fin_nat, ifs); 1800 } 1801 #ifndef sparc 1802 if (fin->fin_v == 4) { 1803 __iplen = (u_short)ip->ip_len, 1804 __ipoff = (u_short)ip->ip_off; 1805 1806 ip->ip_len = htons(__iplen); 1807 ip->ip_off = htons(__ipoff); 1808 } 1809 #endif 1810 1811 if (net_data_p) { 1812 if (net_inject(net_data_p, NI_DIRECT_OUT, &inj_data) < 0) { 1813 return (-1); 1814 } 1815 } 1816 1817 ifs->ifs_fr_frouteok[0]++; 1818 return 0; 1819 bad_fastroute: 1820 freemsg(mb); 1821 ifs->ifs_fr_frouteok[1]++; 1822 return -1; 1823 } 1824 1825 1826 /* ------------------------------------------------------------------------ */ 1827 /* Function: ipf_hook_out */ 1828 /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1829 /* Parameters: event(I) - pointer to event */ 1830 /* info(I) - pointer to hook information for firewalling */ 1831 /* */ 1832 /* Calling ipf_hook. */ 1833 /* ------------------------------------------------------------------------ */ 1834 /*ARGSUSED*/ 1835 int ipf_hook_out(hook_event_token_t token, hook_data_t info, netstack_t *ns) 1836 { 1837 return ipf_hook(info, 1, 0, ns); 1838 } 1839 1840 /* ------------------------------------------------------------------------ */ 1841 /* Function: ipf_hook_in */ 1842 /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1843 /* Parameters: event(I) - pointer to event */ 1844 /* info(I) - pointer to hook information for firewalling */ 1845 /* */ 1846 /* Calling ipf_hook. */ 1847 /* ------------------------------------------------------------------------ */ 1848 /*ARGSUSED*/ 1849 int ipf_hook_in(hook_event_token_t token, hook_data_t info, netstack_t *ns) 1850 { 1851 return ipf_hook(info, 0, 0, ns); 1852 } 1853 1854 1855 /* ------------------------------------------------------------------------ */ 1856 /* Function: ipf_hook_loop_out */ 1857 /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1858 /* Parameters: event(I) - pointer to event */ 1859 /* info(I) - pointer to hook information for firewalling */ 1860 /* */ 1861 /* Calling ipf_hook. */ 1862 /* ------------------------------------------------------------------------ */ 1863 /*ARGSUSED*/ 1864 int ipf_hook_loop_out(hook_event_token_t token, hook_data_t info, 1865 netstack_t *ns) 1866 { 1867 return ipf_hook(info, 1, 1, ns); 1868 } 1869 1870 /* ------------------------------------------------------------------------ */ 1871 /* Function: ipf_hook_loop_in */ 1872 /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1873 /* Parameters: event(I) - pointer to event */ 1874 /* info(I) - pointer to hook information for firewalling */ 1875 /* */ 1876 /* Calling ipf_hook. */ 1877 /* ------------------------------------------------------------------------ */ 1878 /*ARGSUSED*/ 1879 int ipf_hook_loop_in(hook_event_token_t token, hook_data_t info, 1880 netstack_t *ns) 1881 { 1882 return ipf_hook(info, 0, 1, ns); 1883 } 1884 1885 /* ------------------------------------------------------------------------ */ 1886 /* Function: ipf_hook */ 1887 /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1888 /* Parameters: info(I) - pointer to hook information for firewalling */ 1889 /* out(I) - whether packet is going in or out */ 1890 /* loopback(I) - whether packet is a loopback packet or not */ 1891 /* */ 1892 /* Stepping stone function between the IP mainline and IPFilter. Extracts */ 1893 /* parameters out of the info structure and forms them up to be useful for */ 1894 /* calling ipfilter. */ 1895 /* ------------------------------------------------------------------------ */ 1896 int ipf_hook(hook_data_t info, int out, int loopback, netstack_t *ns) 1897 { 1898 hook_pkt_event_t *fw; 1899 int rval, v, hlen; 1900 qpktinfo_t qpi; 1901 u_short swap; 1902 phy_if_t phy; 1903 ip_t *ip; 1904 1905 fw = (hook_pkt_event_t *)info; 1906 1907 ASSERT(fw != NULL); 1908 phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp; 1909 1910 ip = fw->hpe_hdr; 1911 v = ip->ip_v; 1912 if (v == IPV4_VERSION) { 1913 swap = ntohs(ip->ip_len); 1914 ip->ip_len = swap; 1915 swap = ntohs(ip->ip_off); 1916 ip->ip_off = swap; 1917 1918 hlen = IPH_HDR_LENGTH(ip); 1919 } else 1920 hlen = sizeof (ip6_t); 1921 1922 bzero(&qpi, sizeof (qpktinfo_t)); 1923 1924 qpi.qpi_m = fw->hpe_mb; 1925 qpi.qpi_data = fw->hpe_hdr; 1926 qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr; 1927 qpi.qpi_ill = (void *)phy; 1928 qpi.qpi_flags = 0; 1929 if (fw->hpe_flags & HPE_MULTICAST) 1930 qpi.qpi_flags |= FI_MBCAST|FI_MULTICAST; 1931 else if (fw->hpe_flags & HPE_BROADCAST) 1932 qpi.qpi_flags = FI_MBCAST|FI_BROADCAST; 1933 if (loopback) 1934 qpi.qpi_flags |= FI_NOCKSUM; 1935 1936 rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, 1937 &qpi, fw->hpe_mp, ns->netstack_ipf); 1938 1939 /* For fastroute cases, fr_check returns 0 with mp set to NULL */ 1940 if (rval == 0 && *(fw->hpe_mp) == NULL) 1941 rval = 1; 1942 1943 /* Notify IP the packet mblk_t and IP header pointers. */ 1944 fw->hpe_mb = qpi.qpi_m; 1945 fw->hpe_hdr = qpi.qpi_data; 1946 if ((rval == 0) && (v == IPV4_VERSION)) { 1947 ip = qpi.qpi_data; 1948 swap = ntohs(ip->ip_len); 1949 ip->ip_len = swap; 1950 swap = ntohs(ip->ip_off); 1951 ip->ip_off = swap; 1952 } 1953 return rval; 1954 1955 } 1956 1957 1958 /* ------------------------------------------------------------------------ */ 1959 /* Function: ipf_nic_event_v4 */ 1960 /* Returns: int - 0 == no problems encountered */ 1961 /* Parameters: event(I) - pointer to event */ 1962 /* info(I) - pointer to information about a NIC event */ 1963 /* */ 1964 /* Function to receive asynchronous NIC events from IP */ 1965 /* ------------------------------------------------------------------------ */ 1966 /*ARGSUSED*/ 1967 int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info, 1968 netstack_t *ns) 1969 { 1970 struct sockaddr_in *sin; 1971 hook_nic_event_t *hn; 1972 ipf_stack_t *ifs = ns->netstack_ipf; 1973 1974 hn = (hook_nic_event_t *)info; 1975 1976 switch (hn->hne_event) 1977 { 1978 case NE_PLUMB : 1979 frsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, hn->hne_data, 1980 ifs); 1981 fr_natifpsync(IPFSYNC_NEWIFP, (void *)hn->hne_nic, 1982 hn->hne_data, ifs); 1983 fr_statesync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, 1984 hn->hne_data, ifs); 1985 break; 1986 1987 case NE_UNPLUMB : 1988 frsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 1989 fr_natifpsync(IPFSYNC_OLDIFP, (void *)hn->hne_nic, NULL, ifs); 1990 fr_statesync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 1991 break; 1992 1993 case NE_ADDRESS_CHANGE : 1994 /* 1995 * We only respond to events for logical interface 0 because 1996 * IPFilter only uses the first address given to a network 1997 * interface. We check for hne_lif==1 because the netinfo 1998 * code maps adds 1 to the lif number so that it can return 1999 * 0 to indicate "no more lifs" when walking them. 2000 */ 2001 if (hn->hne_lif == 1) { 2002 frsync(IPFSYNC_RESYNC, 4, (void *)hn->hne_nic, NULL, 2003 ifs); 2004 sin = hn->hne_data; 2005 fr_nataddrsync((void *)hn->hne_nic, &sin->sin_addr, 2006 ifs); 2007 } 2008 break; 2009 2010 default : 2011 break; 2012 } 2013 2014 return 0; 2015 } 2016 2017 2018 /* ------------------------------------------------------------------------ */ 2019 /* Function: ipf_nic_event_v6 */ 2020 /* Returns: int - 0 == no problems encountered */ 2021 /* Parameters: event(I) - pointer to event */ 2022 /* info(I) - pointer to information about a NIC event */ 2023 /* */ 2024 /* Function to receive asynchronous NIC events from IP */ 2025 /* ------------------------------------------------------------------------ */ 2026 /*ARGSUSED*/ 2027 int ipf_nic_event_v6(hook_event_token_t event, hook_data_t info, 2028 netstack_t *ns) 2029 { 2030 hook_nic_event_t *hn; 2031 ipf_stack_t *ifs = ns->netstack_ipf; 2032 2033 hn = (hook_nic_event_t *)info; 2034 2035 switch (hn->hne_event) 2036 { 2037 case NE_PLUMB : 2038 frsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, hn->hne_data, ifs); 2039 fr_statesync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2040 hn->hne_data, ifs); 2041 break; 2042 2043 case NE_UNPLUMB : 2044 frsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2045 fr_statesync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2046 break; 2047 2048 case NE_ADDRESS_CHANGE : 2049 break; 2050 default : 2051 break; 2052 } 2053 2054 return 0; 2055 } 2056