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