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