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