1 /* 2 * Copyright (C) 1993-2001, 2003 by Darren Reed. 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 * 6 * Copyright 2007 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 ifs->ifs_ipf_loopback = 0; 270 271 bzero((char *)ifs->ifs_frcache, sizeof(ifs->ifs_frcache)); 272 MUTEX_INIT(&ifs->ifs_ipf_rw, "ipf rw mutex"); 273 MUTEX_INIT(&ifs->ifs_ipf_timeoutlock, "ipf timeout lock mutex"); 274 RWLOCK_INIT(&ifs->ifs_ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); 275 RWLOCK_INIT(&ifs->ifs_ipf_tokens, "ipf token rwlock"); 276 ifs->ifs_ipf_locks_done = 1; 277 278 if (fr_initialise(ifs) < 0) 279 return -1; 280 281 HOOK_INIT(&ifs->ifs_ipfhook_nicevents, ipf_nic_event_v4, 282 "ipfilter_hook_nicevents"); 283 HOOK_INIT(&ifs->ifs_ipfhook_in, ipf_hook_in, "ipfilter_hook_in"); 284 HOOK_INIT(&ifs->ifs_ipfhook_out, ipf_hook_out, "ipfilter_hook_out"); 285 HOOK_INIT(&ifs->ifs_ipfhook_loop_in, ipf_hook_in, 286 "ipfilter_hook_loop_in"); 287 HOOK_INIT(&ifs->ifs_ipfhook_loop_out, ipf_hook_out, 288 "ipfilter_hook_loop_out"); 289 290 /* 291 * If we hold this lock over all of the net_register_hook calls, we 292 * can cause a deadlock to occur with the following lock ordering: 293 * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs 294 * R(hook_family)->R(hei_lock)->R(ipf_global) (packet path) 295 */ 296 RWLOCK_EXIT(&ifs->ifs_ipf_global); 297 298 /* 299 * Add IPv4 hooks 300 */ 301 ifs->ifs_ipf_ipv4 = net_lookup_impl(NHF_INET, ns); 302 if (ifs->ifs_ipf_ipv4 == NULL) 303 goto hookup_failed; 304 305 ifs->ifs_hook4_nic_events = (net_register_hook(ifs->ifs_ipf_ipv4, 306 NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) == 0); 307 if (!ifs->ifs_hook4_nic_events) 308 goto hookup_failed; 309 310 ifs->ifs_hook4_physical_in = (net_register_hook(ifs->ifs_ipf_ipv4, 311 NH_PHYSICAL_IN, &ifs->ifs_ipfhook_in) == 0); 312 if (!ifs->ifs_hook4_physical_in) 313 goto hookup_failed; 314 315 ifs->ifs_hook4_physical_out = (net_register_hook(ifs->ifs_ipf_ipv4, 316 NH_PHYSICAL_OUT, &ifs->ifs_ipfhook_out) == 0); 317 if (!ifs->ifs_hook4_physical_out) 318 goto hookup_failed; 319 320 if (ifs->ifs_ipf_loopback) { 321 ifs->ifs_hook4_loopback_in = 322 (net_register_hook(ifs->ifs_ipf_ipv4, 323 NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) == 0); 324 if (!ifs->ifs_hook4_loopback_in) 325 goto hookup_failed; 326 327 ifs->ifs_hook4_loopback_out = 328 (net_register_hook(ifs->ifs_ipf_ipv4, 329 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) == 0); 330 if (!ifs->ifs_hook4_loopback_out) 331 goto hookup_failed; 332 } 333 /* 334 * Add IPv6 hooks 335 */ 336 ifs->ifs_ipf_ipv6 = net_lookup_impl(NHF_INET6, ns); 337 if (ifs->ifs_ipf_ipv6 == NULL) 338 goto hookup_failed; 339 340 HOOK_INIT(&ifs->ifs_ipfhook_nicevents, ipf_nic_event_v6, 341 "ipfilter_hook_nicevents"); 342 ifs->ifs_hook6_nic_events = (net_register_hook(ifs->ifs_ipf_ipv6, 343 NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) == 0); 344 if (!ifs->ifs_hook6_nic_events) 345 goto hookup_failed; 346 347 ifs->ifs_hook6_physical_in = (net_register_hook(ifs->ifs_ipf_ipv6, 348 NH_PHYSICAL_IN, &ifs->ifs_ipfhook_in) == 0); 349 if (!ifs->ifs_hook6_physical_in) 350 goto hookup_failed; 351 352 ifs->ifs_hook6_physical_out = (net_register_hook(ifs->ifs_ipf_ipv6, 353 NH_PHYSICAL_OUT, &ifs->ifs_ipfhook_out) == 0); 354 if (!ifs->ifs_hook6_physical_out) 355 goto hookup_failed; 356 357 if (ifs->ifs_ipf_loopback) { 358 ifs->ifs_hook6_loopback_in = 359 (net_register_hook(ifs->ifs_ipf_ipv6, 360 NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) == 0); 361 if (!ifs->ifs_hook6_loopback_in) 362 goto hookup_failed; 363 364 ifs->ifs_hook6_loopback_out = 365 (net_register_hook(ifs->ifs_ipf_ipv6, 366 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) == 0); 367 if (!ifs->ifs_hook6_loopback_out) 368 goto hookup_failed; 369 } 370 371 /* 372 * Reacquire ipf_global, now it is safe. 373 */ 374 WRITE_ENTER(&ifs->ifs_ipf_global); 375 376 /* Do not use private interface ip_params_arr[] in Solaris 10 */ 377 #if SOLARIS2 < 10 378 379 #if SOLARIS2 >= 8 380 ip_forwarding = &ip_g_forward; 381 #endif 382 /* 383 * XXX - There is no terminator for this array, so it is not possible 384 * to tell if what we are looking for is missing and go off the end 385 * of the array. 386 */ 387 388 #if SOLARIS2 <= 8 389 for (i = 0; ; i++) { 390 if (!strcmp(ip_param_arr[i].ip_param_name, "ip_def_ttl")) { 391 ip_ttl_ptr = &ip_param_arr[i].ip_param_value; 392 } else if (!strcmp(ip_param_arr[i].ip_param_name, 393 "ip_path_mtu_discovery")) { 394 ip_mtudisc = &ip_param_arr[i].ip_param_value; 395 } 396 #if SOLARIS2 < 8 397 else if (!strcmp(ip_param_arr[i].ip_param_name, 398 "ip_forwarding")) { 399 ip_forwarding = &ip_param_arr[i].ip_param_value; 400 } 401 #else 402 else if (!strcmp(ip_param_arr[i].ip_param_name, 403 "ip6_forwarding")) { 404 ip6_forwarding = &ip_param_arr[i].ip_param_value; 405 } 406 #endif 407 408 if (ip_mtudisc != NULL && ip_ttl_ptr != NULL && 409 #if SOLARIS2 >= 8 410 ip6_forwarding != NULL && 411 #endif 412 ip_forwarding != NULL) 413 break; 414 } 415 #endif 416 417 if (ifs->ifs_fr_control_forwarding & 1) { 418 if (ip_forwarding != NULL) 419 *ip_forwarding = 1; 420 #if SOLARIS2 >= 8 421 if (ip6_forwarding != NULL) 422 *ip6_forwarding = 1; 423 #endif 424 } 425 426 #endif 427 428 return 0; 429 hookup_failed: 430 WRITE_ENTER(&ifs->ifs_ipf_global); 431 return -1; 432 } 433 434 static int fr_setipfloopback(set, ifs) 435 int set; 436 ipf_stack_t *ifs; 437 { 438 if (ifs->ifs_ipf_ipv4 == NULL || ifs->ifs_ipf_ipv6 == NULL) 439 return EFAULT; 440 441 if (set && !ifs->ifs_ipf_loopback) { 442 ifs->ifs_ipf_loopback = 1; 443 444 ifs->ifs_hook4_loopback_in = 445 (net_register_hook(ifs->ifs_ipf_ipv4, 446 NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) == 0); 447 if (!ifs->ifs_hook4_loopback_in) 448 return EINVAL; 449 450 ifs->ifs_hook4_loopback_out = 451 (net_register_hook(ifs->ifs_ipf_ipv4, 452 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) == 0); 453 if (!ifs->ifs_hook4_loopback_out) 454 return EINVAL; 455 456 ifs->ifs_hook6_loopback_in = 457 (net_register_hook(ifs->ifs_ipf_ipv6, 458 NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) == 0); 459 if (!ifs->ifs_hook6_loopback_in) 460 return EINVAL; 461 462 ifs->ifs_hook6_loopback_out = 463 (net_register_hook(ifs->ifs_ipf_ipv6, 464 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) == 0); 465 if (!ifs->ifs_hook6_loopback_out) 466 return EINVAL; 467 468 } else if (!set && ifs->ifs_ipf_loopback) { 469 ifs->ifs_ipf_loopback = 0; 470 471 ifs->ifs_hook4_loopback_in = 472 (net_unregister_hook(ifs->ifs_ipf_ipv4, 473 NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) != 0); 474 if (ifs->ifs_hook4_loopback_in) 475 return EBUSY; 476 477 ifs->ifs_hook4_loopback_out = 478 (net_unregister_hook(ifs->ifs_ipf_ipv4, 479 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) != 0); 480 if (ifs->ifs_hook4_loopback_out) 481 return EBUSY; 482 483 ifs->ifs_hook6_loopback_in = 484 (net_unregister_hook(ifs->ifs_ipf_ipv6, 485 NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) != 0); 486 if (ifs->ifs_hook6_loopback_in) 487 return EBUSY; 488 489 ifs->ifs_hook6_loopback_out = 490 (net_unregister_hook(ifs->ifs_ipf_ipv6, 491 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) != 0); 492 if (ifs->ifs_hook6_loopback_out) 493 return EBUSY; 494 } 495 return 0; 496 } 497 498 499 /* 500 * Filter ioctl interface. 501 */ 502 /*ARGSUSED*/ 503 int iplioctl(dev, cmd, data, mode, cp, rp) 504 dev_t dev; 505 int cmd; 506 #if SOLARIS2 >= 7 507 intptr_t data; 508 #else 509 int *data; 510 #endif 511 int mode; 512 cred_t *cp; 513 int *rp; 514 { 515 int error = 0, tmp; 516 friostat_t fio; 517 minor_t unit; 518 u_int enable; 519 netstack_t *ns; 520 ipf_stack_t *ifs; 521 522 #ifdef IPFDEBUG 523 cmn_err(CE_CONT, "iplioctl(%x,%x,%x,%d,%x,%d)\n", 524 dev, cmd, data, mode, cp, rp); 525 #endif 526 unit = getminor(dev); 527 if (IPL_LOGMAX < unit) 528 return ENXIO; 529 530 ns = netstack_find_by_cred(cp); 531 ASSERT(ns != NULL); 532 ifs = ns->netstack_ipf; 533 ASSERT(ifs != NULL); 534 535 if (ifs->ifs_fr_running <= 0) { 536 if (unit != IPL_LOGIPF) { 537 netstack_rele(ifs->ifs_netstack); 538 return EIO; 539 } 540 if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 541 cmd != SIOCIPFSET && cmd != SIOCFRENB && 542 cmd != SIOCGETFS && cmd != SIOCGETFF) { 543 netstack_rele(ifs->ifs_netstack); 544 return EIO; 545 } 546 } 547 548 READ_ENTER(&ifs->ifs_ipf_global); 549 550 error = fr_ioctlswitch(unit, (caddr_t)data, cmd, mode, cp->cr_uid, curproc, ifs); 551 if (error != -1) { 552 RWLOCK_EXIT(&ifs->ifs_ipf_global); 553 netstack_rele(ifs->ifs_netstack); 554 return error; 555 } 556 error = 0; 557 558 switch (cmd) 559 { 560 case SIOCFRENB : 561 if (!(mode & FWRITE)) 562 error = EPERM; 563 else { 564 error = COPYIN((caddr_t)data, (caddr_t)&enable, 565 sizeof(enable)); 566 if (error != 0) { 567 error = EFAULT; 568 break; 569 } 570 571 RWLOCK_EXIT(&ifs->ifs_ipf_global); 572 WRITE_ENTER(&ifs->ifs_ipf_global); 573 error = fr_enableipf(ifs, ns, enable); 574 } 575 break; 576 case SIOCIPFSET : 577 if (!(mode & FWRITE)) { 578 error = EPERM; 579 break; 580 } 581 /* FALLTHRU */ 582 case SIOCIPFGETNEXT : 583 case SIOCIPFGET : 584 error = fr_ipftune(cmd, (void *)data, ifs); 585 break; 586 case SIOCSETFF : 587 if (!(mode & FWRITE)) 588 error = EPERM; 589 else { 590 error = COPYIN((caddr_t)data, (caddr_t)&ifs->ifs_fr_flags, 591 sizeof(ifs->ifs_fr_flags)); 592 if (error != 0) 593 error = EFAULT; 594 } 595 break; 596 case SIOCIPFLP : 597 error = COPYIN((caddr_t)data, (caddr_t)&tmp, 598 sizeof(tmp)); 599 if (error != 0) 600 error = EFAULT; 601 else 602 error = fr_setipfloopback(tmp, ifs); 603 break; 604 case SIOCGETFF : 605 error = COPYOUT((caddr_t)&ifs->ifs_fr_flags, (caddr_t)data, 606 sizeof(ifs->ifs_fr_flags)); 607 if (error != 0) 608 error = EFAULT; 609 break; 610 case SIOCFUNCL : 611 error = fr_resolvefunc((void *)data); 612 break; 613 case SIOCINAFR : 614 case SIOCRMAFR : 615 case SIOCADAFR : 616 case SIOCZRLST : 617 if (!(mode & FWRITE)) 618 error = EPERM; 619 else 620 error = frrequest(unit, cmd, (caddr_t)data, 621 ifs->ifs_fr_active, 1, ifs); 622 break; 623 case SIOCINIFR : 624 case SIOCRMIFR : 625 case SIOCADIFR : 626 if (!(mode & FWRITE)) 627 error = EPERM; 628 else 629 error = frrequest(unit, cmd, (caddr_t)data, 630 1 - ifs->ifs_fr_active, 1, ifs); 631 break; 632 case SIOCSWAPA : 633 if (!(mode & FWRITE)) 634 error = EPERM; 635 else { 636 WRITE_ENTER(&ifs->ifs_ipf_mutex); 637 /* Clear one fourth of the table */ 638 bzero((char *)&ifs->ifs_frcache, 639 sizeof (ifs->ifs_frcache[0]) * 2); 640 error = COPYOUT((caddr_t)&ifs->ifs_fr_active, 641 (caddr_t)data, 642 sizeof(ifs->ifs_fr_active)); 643 if (error != 0) 644 error = EFAULT; 645 else 646 ifs->ifs_fr_active = 1 - ifs->ifs_fr_active; 647 RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 648 } 649 break; 650 case SIOCGETFS : 651 fr_getstat(&fio, ifs); 652 error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT); 653 break; 654 case SIOCFRZST : 655 if (!(mode & FWRITE)) 656 error = EPERM; 657 else 658 error = fr_zerostats((caddr_t)data, ifs); 659 break; 660 case SIOCIPFFL : 661 if (!(mode & FWRITE)) 662 error = EPERM; 663 else { 664 error = COPYIN((caddr_t)data, (caddr_t)&tmp, 665 sizeof(tmp)); 666 if (!error) { 667 tmp = frflush(unit, 4, tmp, ifs); 668 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 669 sizeof(tmp)); 670 if (error != 0) 671 error = EFAULT; 672 } else 673 error = EFAULT; 674 } 675 break; 676 #ifdef USE_INET6 677 case SIOCIPFL6 : 678 if (!(mode & FWRITE)) 679 error = EPERM; 680 else { 681 error = COPYIN((caddr_t)data, (caddr_t)&tmp, 682 sizeof(tmp)); 683 if (!error) { 684 tmp = frflush(unit, 6, tmp, ifs); 685 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 686 sizeof(tmp)); 687 if (error != 0) 688 error = EFAULT; 689 } else 690 error = EFAULT; 691 } 692 break; 693 #endif 694 case SIOCSTLCK : 695 error = COPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 696 if (error == 0) { 697 ifs->ifs_fr_state_lock = tmp; 698 ifs->ifs_fr_nat_lock = tmp; 699 ifs->ifs_fr_frag_lock = tmp; 700 ifs->ifs_fr_auth_lock = tmp; 701 } else 702 error = EFAULT; 703 break; 704 #ifdef IPFILTER_LOG 705 case SIOCIPFFB : 706 if (!(mode & FWRITE)) 707 error = EPERM; 708 else { 709 tmp = ipflog_clear(unit, ifs); 710 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 711 sizeof(tmp)); 712 if (error) 713 error = EFAULT; 714 } 715 break; 716 #endif /* IPFILTER_LOG */ 717 case SIOCFRSYN : 718 if (!(mode & FWRITE)) 719 error = EPERM; 720 else { 721 RWLOCK_EXIT(&ifs->ifs_ipf_global); 722 WRITE_ENTER(&ifs->ifs_ipf_global); 723 724 frsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 725 fr_natifpsync(IPFSYNC_RESYNC, NULL, NULL, ifs); 726 fr_nataddrsync(NULL, NULL, ifs); 727 fr_statesync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 728 error = 0; 729 } 730 break; 731 case SIOCGFRST : 732 error = fr_outobj((void *)data, fr_fragstats(ifs), 733 IPFOBJ_FRAGSTAT); 734 break; 735 case FIONREAD : 736 #ifdef IPFILTER_LOG 737 tmp = (int)ifs->ifs_iplused[IPL_LOGIPF]; 738 739 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, sizeof(tmp)); 740 if (error != 0) 741 error = EFAULT; 742 #endif 743 break; 744 case SIOCIPFITER : 745 error = ipf_frruleiter((caddr_t)data, cp->cr_uid, curproc, ifs); 746 break; 747 748 case SIOCGENITER : 749 error = ipf_genericiter((caddr_t)data, cp->cr_uid, curproc, ifs); 750 break; 751 752 case SIOCIPFDELTOK : 753 (void)BCOPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 754 error = ipf_deltoken(tmp, cp->cr_uid, curproc, ifs); 755 break; 756 757 default : 758 cmn_err(CE_NOTE, "Unknown: cmd 0x%x data %p", cmd, (void *)data); 759 error = EINVAL; 760 break; 761 } 762 RWLOCK_EXIT(&ifs->ifs_ipf_global); 763 netstack_rele(ifs->ifs_netstack); 764 return error; 765 } 766 767 768 static int fr_enableipf(ifs, ns, enable) 769 ipf_stack_t *ifs; 770 netstack_t *ns; 771 int enable; 772 { 773 int error; 774 775 if (enable) { 776 if (ifs->ifs_fr_running > 0) 777 error = 0; 778 else 779 error = iplattach(ifs, ns); 780 if (error == 0) { 781 if (ifs->ifs_fr_timer_id == NULL) { 782 int hz = drv_usectohz(500000); 783 784 ifs->ifs_fr_timer_id = timeout(fr_slowtimer, 785 (void *)ifs, 786 hz); 787 } 788 ifs->ifs_fr_running = 1; 789 } else { 790 (void) ipldetach(ifs); 791 } 792 } else { 793 error = ipldetach(ifs); 794 if (error == 0) 795 ifs->ifs_fr_running = -1; 796 } 797 798 return error; 799 } 800 801 802 phy_if_t get_unit(name, v, ifs) 803 char *name; 804 int v; 805 ipf_stack_t *ifs; 806 { 807 net_data_t nif; 808 809 if (v == 4) 810 nif = ifs->ifs_ipf_ipv4; 811 else if (v == 6) 812 nif = ifs->ifs_ipf_ipv6; 813 else 814 return 0; 815 816 nif->netd_netstack = ifs->ifs_netstack; 817 818 return (net_phylookup(nif, name)); 819 } 820 821 /* 822 * routines below for saving IP headers to buffer 823 */ 824 /*ARGSUSED*/ 825 int iplopen(devp, flags, otype, cred) 826 dev_t *devp; 827 int flags, otype; 828 cred_t *cred; 829 { 830 minor_t min = getminor(*devp); 831 832 #ifdef IPFDEBUG 833 cmn_err(CE_CONT, "iplopen(%x,%x,%x,%x)\n", devp, flags, otype, cred); 834 #endif 835 if (!(otype & OTYP_CHR)) 836 return ENXIO; 837 838 min = (IPL_LOGMAX < min) ? ENXIO : 0; 839 return min; 840 } 841 842 843 /*ARGSUSED*/ 844 int iplclose(dev, flags, otype, cred) 845 dev_t dev; 846 int flags, otype; 847 cred_t *cred; 848 { 849 minor_t min = getminor(dev); 850 851 #ifdef IPFDEBUG 852 cmn_err(CE_CONT, "iplclose(%x,%x,%x,%x)\n", dev, flags, otype, cred); 853 #endif 854 855 min = (IPL_LOGMAX < min) ? ENXIO : 0; 856 return min; 857 } 858 859 #ifdef IPFILTER_LOG 860 /* 861 * iplread/ipllog 862 * both of these must operate with at least splnet() lest they be 863 * called during packet processing and cause an inconsistancy to appear in 864 * the filter lists. 865 */ 866 /*ARGSUSED*/ 867 int iplread(dev, uio, cp) 868 dev_t dev; 869 register struct uio *uio; 870 cred_t *cp; 871 { 872 netstack_t *ns; 873 ipf_stack_t *ifs; 874 int ret; 875 876 ns = netstack_find_by_cred(cp); 877 ASSERT(ns != NULL); 878 ifs = ns->netstack_ipf; 879 ASSERT(ifs != NULL); 880 881 # ifdef IPFDEBUG 882 cmn_err(CE_CONT, "iplread(%x,%x,%x)\n", dev, uio, cp); 883 # endif 884 885 if (ifs->ifs_fr_running < 1) { 886 netstack_rele(ifs->ifs_netstack); 887 return EIO; 888 } 889 890 # ifdef IPFILTER_SYNC 891 if (getminor(dev) == IPL_LOGSYNC) { 892 netstack_rele(ifs->ifs_netstack); 893 return ipfsync_read(uio); 894 } 895 # endif 896 897 ret = ipflog_read(getminor(dev), uio, ifs); 898 netstack_rele(ifs->ifs_netstack); 899 return ret; 900 } 901 #endif /* IPFILTER_LOG */ 902 903 904 /* 905 * iplread/ipllog 906 * both of these must operate with at least splnet() lest they be 907 * called during packet processing and cause an inconsistancy to appear in 908 * the filter lists. 909 */ 910 int iplwrite(dev, uio, cp) 911 dev_t dev; 912 register struct uio *uio; 913 cred_t *cp; 914 { 915 netstack_t *ns; 916 ipf_stack_t *ifs; 917 918 ns = netstack_find_by_cred(cp); 919 ASSERT(ns != NULL); 920 ifs = ns->netstack_ipf; 921 ASSERT(ifs != NULL); 922 923 #ifdef IPFDEBUG 924 cmn_err(CE_CONT, "iplwrite(%x,%x,%x)\n", dev, uio, cp); 925 #endif 926 927 if (ifs->ifs_fr_running < 1) { 928 netstack_rele(ifs->ifs_netstack); 929 return EIO; 930 } 931 932 #ifdef IPFILTER_SYNC 933 if (getminor(dev) == IPL_LOGSYNC) 934 return ipfsync_write(uio); 935 #endif /* IPFILTER_SYNC */ 936 dev = dev; /* LINT */ 937 uio = uio; /* LINT */ 938 cp = cp; /* LINT */ 939 netstack_rele(ifs->ifs_netstack); 940 return ENXIO; 941 } 942 943 944 /* 945 * fr_send_reset - this could conceivably be a call to tcp_respond(), but that 946 * requires a large amount of setting up and isn't any more efficient. 947 */ 948 int fr_send_reset(fin) 949 fr_info_t *fin; 950 { 951 tcphdr_t *tcp, *tcp2; 952 int tlen, hlen; 953 mblk_t *m; 954 #ifdef USE_INET6 955 ip6_t *ip6; 956 #endif 957 ip_t *ip; 958 959 tcp = fin->fin_dp; 960 if (tcp->th_flags & TH_RST) 961 return -1; 962 963 #ifndef IPFILTER_CKSUM 964 if (fr_checkl4sum(fin) == -1) 965 return -1; 966 #endif 967 968 tlen = (tcp->th_flags & (TH_SYN|TH_FIN)) ? 1 : 0; 969 #ifdef USE_INET6 970 if (fin->fin_v == 6) 971 hlen = sizeof(ip6_t); 972 else 973 #endif 974 hlen = sizeof(ip_t); 975 hlen += sizeof(*tcp2); 976 if ((m = (mblk_t *)allocb(hlen + 64, BPRI_HI)) == NULL) 977 return -1; 978 979 m->b_rptr += 64; 980 MTYPE(m) = M_DATA; 981 m->b_wptr = m->b_rptr + hlen; 982 ip = (ip_t *)m->b_rptr; 983 bzero((char *)ip, hlen); 984 tcp2 = (struct tcphdr *)(m->b_rptr + hlen - sizeof(*tcp2)); 985 tcp2->th_dport = tcp->th_sport; 986 tcp2->th_sport = tcp->th_dport; 987 if (tcp->th_flags & TH_ACK) { 988 tcp2->th_seq = tcp->th_ack; 989 tcp2->th_flags = TH_RST; 990 } else { 991 tcp2->th_ack = ntohl(tcp->th_seq); 992 tcp2->th_ack += tlen; 993 tcp2->th_ack = htonl(tcp2->th_ack); 994 tcp2->th_flags = TH_RST|TH_ACK; 995 } 996 tcp2->th_off = sizeof(struct tcphdr) >> 2; 997 998 ip->ip_v = fin->fin_v; 999 #ifdef USE_INET6 1000 if (fin->fin_v == 6) { 1001 ip6 = (ip6_t *)m->b_rptr; 1002 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 1003 ip6->ip6_src = fin->fin_dst6; 1004 ip6->ip6_dst = fin->fin_src6; 1005 ip6->ip6_plen = htons(sizeof(*tcp)); 1006 ip6->ip6_nxt = IPPROTO_TCP; 1007 tcp2->th_sum = fr_cksum(m, (ip_t *)ip6, IPPROTO_TCP, tcp2); 1008 } else 1009 #endif 1010 { 1011 ip->ip_src.s_addr = fin->fin_daddr; 1012 ip->ip_dst.s_addr = fin->fin_saddr; 1013 ip->ip_id = fr_nextipid(fin); 1014 ip->ip_hl = sizeof(*ip) >> 2; 1015 ip->ip_p = IPPROTO_TCP; 1016 ip->ip_len = sizeof(*ip) + sizeof(*tcp); 1017 ip->ip_tos = fin->fin_ip->ip_tos; 1018 tcp2->th_sum = fr_cksum(m, ip, IPPROTO_TCP, tcp2); 1019 } 1020 return fr_send_ip(fin, m, &m); 1021 } 1022 1023 /* 1024 * Function: fr_send_ip 1025 * Returns: 0: success 1026 * -1: failed 1027 * Parameters: 1028 * fin: packet information 1029 * m: the message block where ip head starts 1030 * 1031 * Send a new packet through the IP stack. 1032 * 1033 * For IPv4 packets, ip_len must be in host byte order, and ip_v, 1034 * ip_ttl, ip_off, and ip_sum are ignored (filled in by this 1035 * function). 1036 * 1037 * For IPv6 packets, ip6_flow, ip6_vfc, and ip6_hlim are filled 1038 * in by this function. 1039 * 1040 * All other portions of the packet must be in on-the-wire format. 1041 */ 1042 /*ARGSUSED*/ 1043 static int fr_send_ip(fin, m, mpp) 1044 fr_info_t *fin; 1045 mblk_t *m, **mpp; 1046 { 1047 qpktinfo_t qpi, *qpip; 1048 fr_info_t fnew; 1049 ip_t *ip; 1050 int i, hlen; 1051 ipf_stack_t *ifs = fin->fin_ifs; 1052 1053 ip = (ip_t *)m->b_rptr; 1054 bzero((char *)&fnew, sizeof(fnew)); 1055 1056 #ifdef USE_INET6 1057 if (fin->fin_v == 6) { 1058 ip6_t *ip6; 1059 1060 ip6 = (ip6_t *)ip; 1061 ip6->ip6_vfc = 0x60; 1062 ip6->ip6_hlim = 127; 1063 fnew.fin_v = 6; 1064 hlen = sizeof(*ip6); 1065 fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen; 1066 } else 1067 #endif 1068 { 1069 fnew.fin_v = 4; 1070 #if SOLARIS2 >= 10 1071 ip->ip_ttl = 255; 1072 if (net_getpmtuenabled(ifs->ifs_ipf_ipv4) == 1) 1073 ip->ip_off = htons(IP_DF); 1074 #else 1075 if (ip_ttl_ptr != NULL) 1076 ip->ip_ttl = (u_char)(*ip_ttl_ptr); 1077 else 1078 ip->ip_ttl = 63; 1079 if (ip_mtudisc != NULL) 1080 ip->ip_off = htons(*ip_mtudisc ? IP_DF : 0); 1081 else 1082 ip->ip_off = htons(IP_DF); 1083 #endif 1084 /* 1085 * The dance with byte order and ip_len/ip_off is because in 1086 * fr_fastroute, it expects them to be in host byte order but 1087 * ipf_cksum expects them to be in network byte order. 1088 */ 1089 ip->ip_len = htons(ip->ip_len); 1090 ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip)); 1091 ip->ip_len = ntohs(ip->ip_len); 1092 ip->ip_off = ntohs(ip->ip_off); 1093 hlen = sizeof(*ip); 1094 fnew.fin_plen = ip->ip_len; 1095 } 1096 1097 qpip = fin->fin_qpi; 1098 qpi.qpi_off = 0; 1099 qpi.qpi_ill = qpip->qpi_ill; 1100 qpi.qpi_m = m; 1101 qpi.qpi_data = ip; 1102 fnew.fin_qpi = &qpi; 1103 fnew.fin_ifp = fin->fin_ifp; 1104 fnew.fin_flx = FI_NOCKSUM; 1105 fnew.fin_m = m; 1106 fnew.fin_ip = ip; 1107 fnew.fin_mp = mpp; 1108 fnew.fin_hlen = hlen; 1109 fnew.fin_dp = (char *)ip + hlen; 1110 fnew.fin_ifs = fin->fin_ifs; 1111 (void) fr_makefrip(hlen, ip, &fnew); 1112 1113 i = fr_fastroute(m, mpp, &fnew, NULL); 1114 return i; 1115 } 1116 1117 1118 int fr_send_icmp_err(type, fin, dst) 1119 int type; 1120 fr_info_t *fin; 1121 int dst; 1122 { 1123 struct in_addr dst4; 1124 struct icmp *icmp; 1125 qpktinfo_t *qpi; 1126 int hlen, code; 1127 phy_if_t phy; 1128 u_short sz; 1129 #ifdef USE_INET6 1130 mblk_t *mb; 1131 #endif 1132 mblk_t *m; 1133 #ifdef USE_INET6 1134 ip6_t *ip6; 1135 #endif 1136 ip_t *ip; 1137 ipf_stack_t *ifs = fin->fin_ifs; 1138 1139 if ((type < 0) || (type > ICMP_MAXTYPE)) 1140 return -1; 1141 1142 code = fin->fin_icode; 1143 #ifdef USE_INET6 1144 if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) 1145 return -1; 1146 #endif 1147 1148 #ifndef IPFILTER_CKSUM 1149 if (fr_checkl4sum(fin) == -1) 1150 return -1; 1151 #endif 1152 1153 qpi = fin->fin_qpi; 1154 1155 #ifdef USE_INET6 1156 mb = fin->fin_qfm; 1157 1158 if (fin->fin_v == 6) { 1159 sz = sizeof(ip6_t); 1160 sz += MIN(mb->b_wptr - mb->b_rptr, 512); 1161 hlen = sizeof(ip6_t); 1162 type = icmptoicmp6types[type]; 1163 if (type == ICMP6_DST_UNREACH) 1164 code = icmptoicmp6unreach[code]; 1165 } else 1166 #endif 1167 { 1168 if ((fin->fin_p == IPPROTO_ICMP) && 1169 !(fin->fin_flx & FI_SHORT)) 1170 switch (ntohs(fin->fin_data[0]) >> 8) 1171 { 1172 case ICMP_ECHO : 1173 case ICMP_TSTAMP : 1174 case ICMP_IREQ : 1175 case ICMP_MASKREQ : 1176 break; 1177 default : 1178 return 0; 1179 } 1180 1181 sz = sizeof(ip_t) * 2; 1182 sz += 8; /* 64 bits of data */ 1183 hlen = sizeof(ip_t); 1184 } 1185 1186 sz += offsetof(struct icmp, icmp_ip); 1187 if ((m = (mblk_t *)allocb((size_t)sz + 64, BPRI_HI)) == NULL) 1188 return -1; 1189 MTYPE(m) = M_DATA; 1190 m->b_rptr += 64; 1191 m->b_wptr = m->b_rptr + sz; 1192 bzero((char *)m->b_rptr, (size_t)sz); 1193 ip = (ip_t *)m->b_rptr; 1194 ip->ip_v = fin->fin_v; 1195 icmp = (struct icmp *)(m->b_rptr + hlen); 1196 icmp->icmp_type = type & 0xff; 1197 icmp->icmp_code = code & 0xff; 1198 phy = (phy_if_t)qpi->qpi_ill; 1199 if (type == ICMP_UNREACH && (phy != 0) && 1200 fin->fin_icode == ICMP_UNREACH_NEEDFRAG) 1201 icmp->icmp_nextmtu = net_getmtu(ifs->ifs_ipf_ipv4, phy,0 ); 1202 1203 #ifdef USE_INET6 1204 if (fin->fin_v == 6) { 1205 struct in6_addr dst6; 1206 int csz; 1207 1208 if (dst == 0) { 1209 ipf_stack_t *ifs = fin->fin_ifs; 1210 1211 if (fr_ifpaddr(6, FRI_NORMAL, (void *)phy, 1212 (void *)&dst6, NULL, ifs) == -1) { 1213 FREE_MB_T(m); 1214 return -1; 1215 } 1216 } else 1217 dst6 = fin->fin_dst6; 1218 1219 csz = sz; 1220 sz -= sizeof(ip6_t); 1221 ip6 = (ip6_t *)m->b_rptr; 1222 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 1223 ip6->ip6_plen = htons((u_short)sz); 1224 ip6->ip6_nxt = IPPROTO_ICMPV6; 1225 ip6->ip6_src = dst6; 1226 ip6->ip6_dst = fin->fin_src6; 1227 sz -= offsetof(struct icmp, icmp_ip); 1228 bcopy((char *)mb->b_rptr, (char *)&icmp->icmp_ip, sz); 1229 icmp->icmp_cksum = csz - sizeof(ip6_t); 1230 } else 1231 #endif 1232 { 1233 ip->ip_hl = sizeof(*ip) >> 2; 1234 ip->ip_p = IPPROTO_ICMP; 1235 ip->ip_id = fin->fin_ip->ip_id; 1236 ip->ip_tos = fin->fin_ip->ip_tos; 1237 ip->ip_len = (u_short)sz; 1238 if (dst == 0) { 1239 ipf_stack_t *ifs = fin->fin_ifs; 1240 1241 if (fr_ifpaddr(4, FRI_NORMAL, (void *)phy, 1242 (void *)&dst4, NULL, ifs) == -1) { 1243 FREE_MB_T(m); 1244 return -1; 1245 } 1246 } else { 1247 dst4 = fin->fin_dst; 1248 } 1249 ip->ip_src = dst4; 1250 ip->ip_dst = fin->fin_src; 1251 bcopy((char *)fin->fin_ip, (char *)&icmp->icmp_ip, 1252 sizeof(*fin->fin_ip)); 1253 bcopy((char *)fin->fin_ip + fin->fin_hlen, 1254 (char *)&icmp->icmp_ip + sizeof(*fin->fin_ip), 8); 1255 icmp->icmp_ip.ip_len = htons(icmp->icmp_ip.ip_len); 1256 icmp->icmp_ip.ip_off = htons(icmp->icmp_ip.ip_off); 1257 icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 1258 sz - sizeof(ip_t)); 1259 } 1260 1261 /* 1262 * Need to exit out of these so we don't recursively call rw_enter 1263 * from fr_qout. 1264 */ 1265 return fr_send_ip(fin, m, &m); 1266 } 1267 1268 #include <sys/time.h> 1269 #include <sys/varargs.h> 1270 1271 #ifndef _KERNEL 1272 #include <stdio.h> 1273 #endif 1274 1275 #define NULLADDR_RATE_LIMIT 10 /* 10 seconds */ 1276 1277 1278 /* 1279 * Print out warning message at rate-limited speed. 1280 */ 1281 static void rate_limit_message(ipf_stack_t *ifs, 1282 int rate, const char *message, ...) 1283 { 1284 static time_t last_time = 0; 1285 time_t now; 1286 va_list args; 1287 char msg_buf[256]; 1288 int need_printed = 0; 1289 1290 now = ddi_get_time(); 1291 1292 /* make sure, no multiple entries */ 1293 ASSERT(MUTEX_NOT_HELD(&(ifs->ifs_ipf_rw.ipf_lk))); 1294 MUTEX_ENTER(&ifs->ifs_ipf_rw); 1295 if (now - last_time >= rate) { 1296 need_printed = 1; 1297 last_time = now; 1298 } 1299 MUTEX_EXIT(&ifs->ifs_ipf_rw); 1300 1301 if (need_printed) { 1302 va_start(args, message); 1303 (void)vsnprintf(msg_buf, 255, message, args); 1304 va_end(args); 1305 #ifdef _KERNEL 1306 cmn_err(CE_WARN, msg_buf); 1307 #else 1308 fprintf(std_err, msg_buf); 1309 #endif 1310 } 1311 } 1312 1313 /* 1314 * return the first IP Address associated with an interface 1315 */ 1316 /*ARGSUSED*/ 1317 int fr_ifpaddr(v, atype, ifptr, inp, inpmask, ifs) 1318 int v, atype; 1319 void *ifptr; 1320 struct in_addr *inp, *inpmask; 1321 ipf_stack_t *ifs; 1322 { 1323 struct sockaddr_in6 v6addr[2]; 1324 struct sockaddr_in v4addr[2]; 1325 net_ifaddr_t type[2]; 1326 net_data_t net_data; 1327 phy_if_t phyif; 1328 void *array; 1329 1330 switch (v) 1331 { 1332 case 4: 1333 net_data = ifs->ifs_ipf_ipv4; 1334 array = v4addr; 1335 break; 1336 case 6: 1337 net_data = ifs->ifs_ipf_ipv6; 1338 array = v6addr; 1339 break; 1340 default: 1341 net_data = NULL; 1342 break; 1343 } 1344 1345 if (net_data == NULL) 1346 return -1; 1347 1348 phyif = (phy_if_t)ifptr; 1349 1350 switch (atype) 1351 { 1352 case FRI_PEERADDR : 1353 type[0] = NA_PEER; 1354 break; 1355 1356 case FRI_BROADCAST : 1357 type[0] = NA_BROADCAST; 1358 break; 1359 1360 default : 1361 type[0] = NA_ADDRESS; 1362 break; 1363 } 1364 1365 type[1] = NA_NETMASK; 1366 1367 if (net_getlifaddr(net_data, phyif, 0, 2, type, array) < 0) 1368 return -1; 1369 1370 if (v == 6) { 1371 return fr_ifpfillv6addr(atype, &v6addr[0], &v6addr[1], 1372 inp, inpmask); 1373 } 1374 return fr_ifpfillv4addr(atype, &v4addr[0], &v4addr[1], inp, inpmask); 1375 } 1376 1377 1378 u_32_t fr_newisn(fin) 1379 fr_info_t *fin; 1380 { 1381 static int iss_seq_off = 0; 1382 u_char hash[16]; 1383 u_32_t newiss; 1384 MD5_CTX ctx; 1385 ipf_stack_t *ifs = fin->fin_ifs; 1386 1387 /* 1388 * Compute the base value of the ISS. It is a hash 1389 * of (saddr, sport, daddr, dport, secret). 1390 */ 1391 MD5Init(&ctx); 1392 1393 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 1394 sizeof(fin->fin_fi.fi_src)); 1395 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 1396 sizeof(fin->fin_fi.fi_dst)); 1397 MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 1398 1399 MD5Update(&ctx, ifs->ifs_ipf_iss_secret, sizeof(ifs->ifs_ipf_iss_secret)); 1400 1401 MD5Final(hash, &ctx); 1402 1403 bcopy(hash, &newiss, sizeof(newiss)); 1404 1405 /* 1406 * Now increment our "timer", and add it in to 1407 * the computed value. 1408 * 1409 * XXX Use `addin'? 1410 * XXX TCP_ISSINCR too large to use? 1411 */ 1412 iss_seq_off += 0x00010000; 1413 newiss += iss_seq_off; 1414 return newiss; 1415 } 1416 1417 1418 /* ------------------------------------------------------------------------ */ 1419 /* Function: fr_nextipid */ 1420 /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 1421 /* Parameters: fin(I) - pointer to packet information */ 1422 /* */ 1423 /* Returns the next IPv4 ID to use for this packet. */ 1424 /* ------------------------------------------------------------------------ */ 1425 u_short fr_nextipid(fin) 1426 fr_info_t *fin; 1427 { 1428 static u_short ipid = 0; 1429 ipstate_t *is; 1430 nat_t *nat; 1431 u_short id; 1432 ipf_stack_t *ifs = fin->fin_ifs; 1433 1434 MUTEX_ENTER(&ifs->ifs_ipf_rw); 1435 if (fin->fin_state != NULL) { 1436 is = fin->fin_state; 1437 id = (u_short)(is->is_pkts[(fin->fin_rev << 1) + 1] & 0xffff); 1438 } else if (fin->fin_nat != NULL) { 1439 nat = fin->fin_nat; 1440 id = (u_short)(nat->nat_pkts[fin->fin_out] & 0xffff); 1441 } else 1442 id = ipid++; 1443 MUTEX_EXIT(&ifs->ifs_ipf_rw); 1444 1445 return id; 1446 } 1447 1448 1449 #ifndef IPFILTER_CKSUM 1450 /* ARGSUSED */ 1451 #endif 1452 INLINE void fr_checkv4sum(fin) 1453 fr_info_t *fin; 1454 { 1455 #ifdef IPFILTER_CKSUM 1456 if (fr_checkl4sum(fin) == -1) 1457 fin->fin_flx |= FI_BAD; 1458 #endif 1459 } 1460 1461 1462 #ifdef USE_INET6 1463 # ifndef IPFILTER_CKSUM 1464 /* ARGSUSED */ 1465 # endif 1466 INLINE void fr_checkv6sum(fin) 1467 fr_info_t *fin; 1468 { 1469 # ifdef IPFILTER_CKSUM 1470 if (fr_checkl4sum(fin) == -1) 1471 fin->fin_flx |= FI_BAD; 1472 # endif 1473 } 1474 #endif /* USE_INET6 */ 1475 1476 1477 #if (SOLARIS2 < 7) 1478 void fr_slowtimer() 1479 #else 1480 /*ARGSUSED*/ 1481 void fr_slowtimer __P((void *arg)) 1482 #endif 1483 { 1484 ipf_stack_t *ifs = arg; 1485 1486 WRITE_ENTER(&ifs->ifs_ipf_global); 1487 if (ifs->ifs_fr_running == -1 || ifs->ifs_fr_running == 0) { 1488 ifs->ifs_fr_timer_id = timeout(fr_slowtimer, arg, drv_usectohz(500000)); 1489 RWLOCK_EXIT(&ifs->ifs_ipf_global); 1490 return; 1491 } 1492 MUTEX_DOWNGRADE(&ifs->ifs_ipf_global); 1493 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 if (loopback) 1929 qpi.qpi_flags = QPI_NOCKSUM; 1930 else 1931 qpi.qpi_flags = 0; 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