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