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