17c478bd9Sstevel@tonic-gate /* 2ab25eeb5Syz * Copyright (C) 1993-2001, 2003 by Darren Reed. 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * See the IPFILTER.LICENCE file for details on licencing. 57c478bd9Sstevel@tonic-gate * 6*33f2fefdSDarren Reed * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 77c478bd9Sstevel@tonic-gate * Use is subject to license terms. 87c478bd9Sstevel@tonic-gate */ 97c478bd9Sstevel@tonic-gate 107c478bd9Sstevel@tonic-gate #if !defined(lint) 11c793af95Ssangeeta static const char sccsid[] = "@(#)ip_fil_solaris.c 1.7 07/22/06 (C) 1993-2000 Darren Reed"; 12ab25eeb5Syz static const char rcsid[] = "@(#)$Id: ip_fil_solaris.c,v 2.62.2.19 2005/07/13 21:40:46 darrenr Exp $"; 137c478bd9Sstevel@tonic-gate #endif 147c478bd9Sstevel@tonic-gate 157c478bd9Sstevel@tonic-gate #include <sys/types.h> 167c478bd9Sstevel@tonic-gate #include <sys/errno.h> 177c478bd9Sstevel@tonic-gate #include <sys/param.h> 187c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 197c478bd9Sstevel@tonic-gate #include <sys/open.h> 207c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 217c478bd9Sstevel@tonic-gate #include <sys/filio.h> 227c478bd9Sstevel@tonic-gate #include <sys/systm.h> 23ab25eeb5Syz #include <sys/strsubr.h> 247c478bd9Sstevel@tonic-gate #include <sys/cred.h> 25f4b3ec61Sdh #include <sys/cred_impl.h> 267c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 277c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 287c478bd9Sstevel@tonic-gate #include <sys/ksynch.h> 297c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 307c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 317c478bd9Sstevel@tonic-gate #include <sys/protosw.h> 327c478bd9Sstevel@tonic-gate #include <sys/socket.h> 337c478bd9Sstevel@tonic-gate #include <sys/dditypes.h> 347c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 35f4b3ec61Sdh #include <sys/zone.h> 367c478bd9Sstevel@tonic-gate #include <net/if.h> 377c478bd9Sstevel@tonic-gate #include <net/af.h> 387c478bd9Sstevel@tonic-gate #include <net/route.h> 397c478bd9Sstevel@tonic-gate #include <netinet/in.h> 407c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h> 417c478bd9Sstevel@tonic-gate #include <netinet/ip.h> 427c478bd9Sstevel@tonic-gate #include <netinet/ip_var.h> 437c478bd9Sstevel@tonic-gate #include <netinet/tcp.h> 447c478bd9Sstevel@tonic-gate #include <netinet/udp.h> 457c478bd9Sstevel@tonic-gate #include <netinet/tcpip.h> 467c478bd9Sstevel@tonic-gate #include <netinet/ip_icmp.h> 47ab25eeb5Syz #include "netinet/ip_compat.h" 487c478bd9Sstevel@tonic-gate #ifdef USE_INET6 497c478bd9Sstevel@tonic-gate # include <netinet/icmp6.h> 507c478bd9Sstevel@tonic-gate #endif 51ab25eeb5Syz #include "netinet/ip_fil.h" 52ab25eeb5Syz #include "netinet/ip_nat.h" 53ab25eeb5Syz #include "netinet/ip_frag.h" 54ab25eeb5Syz #include "netinet/ip_state.h" 55ab25eeb5Syz #include "netinet/ip_auth.h" 56ab25eeb5Syz #include "netinet/ip_proxy.h" 57f4b3ec61Sdh #include "netinet/ipf_stack.h" 587c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOOKUP 59ab25eeb5Syz # include "netinet/ip_lookup.h" 607c478bd9Sstevel@tonic-gate #endif 617c478bd9Sstevel@tonic-gate #include <inet/ip_ire.h> 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate #include <sys/md5.h> 64381a2a9aSdr #include <sys/neti.h> 657c478bd9Sstevel@tonic-gate 66f4b3ec61Sdh static int frzerostats __P((caddr_t, ipf_stack_t *)); 67f4b3ec61Sdh static int fr_setipfloopback __P((int, ipf_stack_t *)); 687ddc9b1aSDarren Reed static int fr_enableipf __P((ipf_stack_t *, int)); 69ab25eeb5Syz static int fr_send_ip __P((fr_info_t *fin, mblk_t *m, mblk_t **mp)); 707ddc9b1aSDarren Reed static int ipf_nic_event_v4 __P((hook_event_token_t, hook_data_t, void *)); 717ddc9b1aSDarren Reed static int ipf_nic_event_v6 __P((hook_event_token_t, hook_data_t, void *)); 727ddc9b1aSDarren Reed static int ipf_hook __P((hook_data_t, int, int, void *)); 737ddc9b1aSDarren Reed static int ipf_hook4_in __P((hook_event_token_t, hook_data_t, void *)); 747ddc9b1aSDarren Reed static int ipf_hook4_out __P((hook_event_token_t, hook_data_t, void *)); 75cbded9aeSdr static int ipf_hook4_loop_out __P((hook_event_token_t, hook_data_t, 767ddc9b1aSDarren Reed void *)); 777ddc9b1aSDarren Reed static int ipf_hook4_loop_in __P((hook_event_token_t, hook_data_t, void *)); 787ddc9b1aSDarren Reed static int ipf_hook4 __P((hook_data_t, int, int, void *)); 797ddc9b1aSDarren Reed static int ipf_hook6_out __P((hook_event_token_t, hook_data_t, void *)); 807ddc9b1aSDarren Reed static int ipf_hook6_in __P((hook_event_token_t, hook_data_t, void *)); 81cbded9aeSdr static int ipf_hook6_loop_out __P((hook_event_token_t, hook_data_t, 827ddc9b1aSDarren Reed void *)); 83cbded9aeSdr static int ipf_hook6_loop_in __P((hook_event_token_t, hook_data_t, 847ddc9b1aSDarren Reed void *)); 857ddc9b1aSDarren Reed static int ipf_hook6 __P((hook_data_t, int, int, void *)); 86f4b3ec61Sdh extern int ipf_geniter __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *)); 87f4b3ec61Sdh extern int ipf_frruleiter __P((void *, int, void *, ipf_stack_t *)); 88f4b3ec61Sdh 897c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 907c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 7 91ab25eeb5Syz u_int *ip_ttl_ptr = NULL; 92ab25eeb5Syz u_int *ip_mtudisc = NULL; 937c478bd9Sstevel@tonic-gate # if SOLARIS2 >= 8 94ab25eeb5Syz int *ip_forwarding = NULL; 95ab25eeb5Syz u_int *ip6_forwarding = NULL; 967c478bd9Sstevel@tonic-gate # else 97ab25eeb5Syz u_int *ip_forwarding = NULL; 987c478bd9Sstevel@tonic-gate # endif 997c478bd9Sstevel@tonic-gate #else 100ab25eeb5Syz u_long *ip_ttl_ptr = NULL; 101ab25eeb5Syz u_long *ip_mtudisc = NULL; 102ab25eeb5Syz u_long *ip_forwarding = NULL; 1037c478bd9Sstevel@tonic-gate #endif 1047c478bd9Sstevel@tonic-gate #endif 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 1087c478bd9Sstevel@tonic-gate /* Function: ipldetach */ 1097c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, else error. */ 1107c478bd9Sstevel@tonic-gate /* Parameters: Nil */ 1117c478bd9Sstevel@tonic-gate /* */ 1127c478bd9Sstevel@tonic-gate /* This function is responsible for undoing anything that might have been */ 1137c478bd9Sstevel@tonic-gate /* done in a call to iplattach(). It must be able to clean up from a call */ 1147c478bd9Sstevel@tonic-gate /* to iplattach() that did not succeed. Why might that happen? Someone */ 1157c478bd9Sstevel@tonic-gate /* configures a table to be so large that we cannot allocate enough memory */ 1167c478bd9Sstevel@tonic-gate /* for it. */ 1177c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 118f4b3ec61Sdh int ipldetach(ifs) 119f4b3ec61Sdh ipf_stack_t *ifs; 1207c478bd9Sstevel@tonic-gate { 1217c478bd9Sstevel@tonic-gate 122f4b3ec61Sdh ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0); 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 1257c478bd9Sstevel@tonic-gate 126f4b3ec61Sdh if (ifs->ifs_fr_control_forwarding & 2) { 127ab25eeb5Syz if (ip_forwarding != NULL) 128ab25eeb5Syz *ip_forwarding = 0; 1297c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 130ab25eeb5Syz if (ip6_forwarding != NULL) 131ab25eeb5Syz *ip6_forwarding = 0; 1327c478bd9Sstevel@tonic-gate #endif 1337c478bd9Sstevel@tonic-gate } 1347c478bd9Sstevel@tonic-gate #endif 1357c478bd9Sstevel@tonic-gate 136381a2a9aSdr /* 1377ddc9b1aSDarren Reed * This lock needs to be dropped around the net_hook_unregister calls 138381a2a9aSdr * because we can deadlock here with: 139381a2a9aSdr * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs 140381a2a9aSdr * R(hook_family)->R(hei_lock)->R(ipf_global) (active hook running) 141381a2a9aSdr */ 142f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 143381a2a9aSdr 1447ddc9b1aSDarren Reed #define UNDO_HOOK(_f, _b, _e, _h) \ 1457ddc9b1aSDarren Reed do { \ 1467ddc9b1aSDarren Reed if (ifs->_f != NULL) { \ 1477ddc9b1aSDarren Reed if (ifs->_b) { \ 1487ddc9b1aSDarren Reed ifs->_b = (net_hook_unregister(ifs->_f, \ 1497ddc9b1aSDarren Reed _e, ifs->_h) != 0); \ 1507ddc9b1aSDarren Reed if (!ifs->_b) { \ 1517ddc9b1aSDarren Reed hook_free(ifs->_h); \ 1527ddc9b1aSDarren Reed ifs->_h = NULL; \ 1537ddc9b1aSDarren Reed } \ 1547ddc9b1aSDarren Reed } else if (ifs->_h != NULL) { \ 1557ddc9b1aSDarren Reed hook_free(ifs->_h); \ 1567ddc9b1aSDarren Reed ifs->_h = NULL; \ 1577ddc9b1aSDarren Reed } \ 1587ddc9b1aSDarren Reed } \ 1597ddc9b1aSDarren Reed _NOTE(CONSTCOND) \ 1607ddc9b1aSDarren Reed } while (0) 1617ddc9b1aSDarren Reed 162381a2a9aSdr /* 163381a2a9aSdr * Remove IPv6 Hooks 164381a2a9aSdr */ 165f4b3ec61Sdh if (ifs->ifs_ipf_ipv6 != NULL) { 1667ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_in, 1677ddc9b1aSDarren Reed NH_PHYSICAL_IN, ifs_ipfhook6_in); 1687ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_out, 1697ddc9b1aSDarren Reed NH_PHYSICAL_OUT, ifs_ipfhook6_out); 1707ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_nic_events, 1717ddc9b1aSDarren Reed NH_NIC_EVENTS, ifs_ipfhook6_nicevents); 1727ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_in, 1737ddc9b1aSDarren Reed NH_LOOPBACK_IN, ifs_ipfhook6_loop_in); 1747ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_out, 1757ddc9b1aSDarren Reed NH_LOOPBACK_OUT, ifs_ipfhook6_loop_out); 1767ddc9b1aSDarren Reed 1777ddc9b1aSDarren Reed if (net_protocol_release(ifs->ifs_ipf_ipv6) != 0) 178381a2a9aSdr goto detach_failed; 179f4b3ec61Sdh ifs->ifs_ipf_ipv6 = NULL; 180381a2a9aSdr } 181381a2a9aSdr 182381a2a9aSdr /* 183381a2a9aSdr * Remove IPv4 Hooks 184381a2a9aSdr */ 185f4b3ec61Sdh if (ifs->ifs_ipf_ipv4 != NULL) { 1867ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_in, 1877ddc9b1aSDarren Reed NH_PHYSICAL_IN, ifs_ipfhook4_in); 1887ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_out, 1897ddc9b1aSDarren Reed NH_PHYSICAL_OUT, ifs_ipfhook4_out); 1907ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_nic_events, 1917ddc9b1aSDarren Reed NH_NIC_EVENTS, ifs_ipfhook4_nicevents); 1927ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_in, 1937ddc9b1aSDarren Reed NH_LOOPBACK_IN, ifs_ipfhook4_loop_in); 1947ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_out, 1957ddc9b1aSDarren Reed NH_LOOPBACK_OUT, ifs_ipfhook4_loop_out); 1967ddc9b1aSDarren Reed 1977ddc9b1aSDarren Reed if (net_protocol_release(ifs->ifs_ipf_ipv4) != 0) 198381a2a9aSdr goto detach_failed; 199f4b3ec61Sdh ifs->ifs_ipf_ipv4 = NULL; 200381a2a9aSdr } 201381a2a9aSdr 2027ddc9b1aSDarren Reed #undef UNDO_HOOK 2037ddc9b1aSDarren Reed 2047c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 2057c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "ipldetach()\n"); 2067c478bd9Sstevel@tonic-gate #endif 2077c478bd9Sstevel@tonic-gate 208f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 209f4b3ec61Sdh fr_deinitialise(ifs); 2107c478bd9Sstevel@tonic-gate 211f4b3ec61Sdh (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE, ifs); 212f4b3ec61Sdh (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE, ifs); 2137c478bd9Sstevel@tonic-gate 214f4b3ec61Sdh if (ifs->ifs_ipf_locks_done == 1) { 215f4b3ec61Sdh MUTEX_DESTROY(&ifs->ifs_ipf_timeoutlock); 216f4b3ec61Sdh MUTEX_DESTROY(&ifs->ifs_ipf_rw); 217f4b3ec61Sdh RW_DESTROY(&ifs->ifs_ipf_tokens); 218f4b3ec61Sdh RW_DESTROY(&ifs->ifs_ipf_ipidfrag); 219f4b3ec61Sdh ifs->ifs_ipf_locks_done = 0; 2207c478bd9Sstevel@tonic-gate } 221381a2a9aSdr 2227ddc9b1aSDarren Reed if (ifs->ifs_hook4_physical_in || ifs->ifs_hook4_physical_out || 2237ddc9b1aSDarren Reed ifs->ifs_hook4_nic_events || ifs->ifs_hook4_loopback_in || 2247ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_out || ifs->ifs_hook6_nic_events || 2257ddc9b1aSDarren Reed ifs->ifs_hook6_physical_in || ifs->ifs_hook6_physical_out || 2267ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_in || ifs->ifs_hook6_loopback_out) 227381a2a9aSdr return -1; 228381a2a9aSdr 2297c478bd9Sstevel@tonic-gate return 0; 230381a2a9aSdr 231381a2a9aSdr detach_failed: 232f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 233381a2a9aSdr return -1; 2347c478bd9Sstevel@tonic-gate } 2357c478bd9Sstevel@tonic-gate 2367ddc9b1aSDarren Reed int iplattach(ifs) 237f4b3ec61Sdh ipf_stack_t *ifs; 2387c478bd9Sstevel@tonic-gate { 2397c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 2407c478bd9Sstevel@tonic-gate int i; 2417c478bd9Sstevel@tonic-gate #endif 2427ddc9b1aSDarren Reed netid_t id = ifs->ifs_netid; 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 2457c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplattach()\n"); 2467c478bd9Sstevel@tonic-gate #endif 2477c478bd9Sstevel@tonic-gate 248f4b3ec61Sdh ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0); 249f4b3ec61Sdh ifs->ifs_fr_flags = IPF_LOGGING; 250f4b3ec61Sdh #ifdef _KERNEL 251f4b3ec61Sdh ifs->ifs_fr_update_ipid = 0; 252f4b3ec61Sdh #else 253f4b3ec61Sdh ifs->ifs_fr_update_ipid = 1; 254f4b3ec61Sdh #endif 255f4b3ec61Sdh ifs->ifs_fr_minttl = 4; 256f4b3ec61Sdh ifs->ifs_fr_icmpminfragmtu = 68; 257f4b3ec61Sdh #if defined(IPFILTER_DEFAULT_BLOCK) 258f4b3ec61Sdh ifs->ifs_fr_pass = FR_BLOCK|FR_NOMATCH; 259f4b3ec61Sdh #else 260f4b3ec61Sdh ifs->ifs_fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH; 261f4b3ec61Sdh #endif 2627c478bd9Sstevel@tonic-gate 263f4b3ec61Sdh MUTEX_INIT(&ifs->ifs_ipf_rw, "ipf rw mutex"); 264f4b3ec61Sdh MUTEX_INIT(&ifs->ifs_ipf_timeoutlock, "ipf timeout lock mutex"); 265f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); 266f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_tokens, "ipf token rwlock"); 267f4b3ec61Sdh ifs->ifs_ipf_locks_done = 1; 2687c478bd9Sstevel@tonic-gate 269f4b3ec61Sdh if (fr_initialise(ifs) < 0) 2707c478bd9Sstevel@tonic-gate return -1; 2717c478bd9Sstevel@tonic-gate 2727ddc9b1aSDarren Reed HOOK_INIT(ifs->ifs_ipfhook4_nicevents, ipf_nic_event_v4, 2737ddc9b1aSDarren Reed "ipfilter_hook4_nicevents", ifs); 2747ddc9b1aSDarren Reed HOOK_INIT(ifs->ifs_ipfhook4_in, ipf_hook4_in, 2757ddc9b1aSDarren Reed "ipfilter_hook4_in", ifs); 2767ddc9b1aSDarren Reed HOOK_INIT(ifs->ifs_ipfhook4_out, ipf_hook4_out, 2777ddc9b1aSDarren Reed "ipfilter_hook4_out", ifs); 27840cdc2e8SAlexandr Nedvedicky HOOK_INIT(ifs->ifs_ipfhook4_loop_in, ipf_hook4_loop_in, 2797ddc9b1aSDarren Reed "ipfilter_hook4_loop_in", ifs); 28040cdc2e8SAlexandr Nedvedicky HOOK_INIT(ifs->ifs_ipfhook4_loop_out, ipf_hook4_loop_out, 2817ddc9b1aSDarren Reed "ipfilter_hook4_loop_out", ifs); 282381a2a9aSdr 283381a2a9aSdr /* 2847ddc9b1aSDarren Reed * If we hold this lock over all of the net_hook_register calls, we 285381a2a9aSdr * can cause a deadlock to occur with the following lock ordering: 286381a2a9aSdr * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs 287381a2a9aSdr * R(hook_family)->R(hei_lock)->R(ipf_global) (packet path) 288381a2a9aSdr */ 289f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 290381a2a9aSdr 291381a2a9aSdr /* 292381a2a9aSdr * Add IPv4 hooks 293381a2a9aSdr */ 2947ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4 = net_protocol_lookup(id, NHF_INET); 295f4b3ec61Sdh if (ifs->ifs_ipf_ipv4 == NULL) 296381a2a9aSdr goto hookup_failed; 297381a2a9aSdr 2987ddc9b1aSDarren Reed ifs->ifs_hook4_nic_events = (net_hook_register(ifs->ifs_ipf_ipv4, 2997ddc9b1aSDarren Reed NH_NIC_EVENTS, ifs->ifs_ipfhook4_nicevents) == 0); 300f4b3ec61Sdh if (!ifs->ifs_hook4_nic_events) 301381a2a9aSdr goto hookup_failed; 302381a2a9aSdr 3037ddc9b1aSDarren Reed ifs->ifs_hook4_physical_in = (net_hook_register(ifs->ifs_ipf_ipv4, 3047ddc9b1aSDarren Reed NH_PHYSICAL_IN, ifs->ifs_ipfhook4_in) == 0); 305f4b3ec61Sdh if (!ifs->ifs_hook4_physical_in) 306381a2a9aSdr goto hookup_failed; 307381a2a9aSdr 3087ddc9b1aSDarren Reed ifs->ifs_hook4_physical_out = (net_hook_register(ifs->ifs_ipf_ipv4, 3097ddc9b1aSDarren Reed NH_PHYSICAL_OUT, ifs->ifs_ipfhook4_out) == 0); 310f4b3ec61Sdh if (!ifs->ifs_hook4_physical_out) 311381a2a9aSdr goto hookup_failed; 312381a2a9aSdr 313f4b3ec61Sdh if (ifs->ifs_ipf_loopback) { 3147ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_in = (net_hook_register( 3157ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN, 3167ddc9b1aSDarren Reed ifs->ifs_ipfhook4_loop_in) == 0); 317f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_in) 318381a2a9aSdr goto hookup_failed; 319381a2a9aSdr 3207ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_out = (net_hook_register( 3217ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT, 3227ddc9b1aSDarren Reed ifs->ifs_ipfhook4_loop_out) == 0); 323f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_out) 324381a2a9aSdr goto hookup_failed; 325381a2a9aSdr } 326381a2a9aSdr /* 327381a2a9aSdr * Add IPv6 hooks 328381a2a9aSdr */ 3297ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6 = net_protocol_lookup(id, NHF_INET6); 330f4b3ec61Sdh if (ifs->ifs_ipf_ipv6 == NULL) 331381a2a9aSdr goto hookup_failed; 332381a2a9aSdr 3337ddc9b1aSDarren Reed HOOK_INIT(ifs->ifs_ipfhook6_nicevents, ipf_nic_event_v6, 3347ddc9b1aSDarren Reed "ipfilter_hook6_nicevents", ifs); 3357ddc9b1aSDarren Reed HOOK_INIT(ifs->ifs_ipfhook6_in, ipf_hook6_in, 3367ddc9b1aSDarren Reed "ipfilter_hook6_in", ifs); 3377ddc9b1aSDarren Reed HOOK_INIT(ifs->ifs_ipfhook6_out, ipf_hook6_out, 3387ddc9b1aSDarren Reed "ipfilter_hook6_out", ifs); 33940cdc2e8SAlexandr Nedvedicky HOOK_INIT(ifs->ifs_ipfhook6_loop_in, ipf_hook6_loop_in, 3407ddc9b1aSDarren Reed "ipfilter_hook6_loop_in", ifs); 34140cdc2e8SAlexandr Nedvedicky HOOK_INIT(ifs->ifs_ipfhook6_loop_out, ipf_hook6_loop_out, 3427ddc9b1aSDarren Reed "ipfilter_hook6_loop_out", ifs); 3437ddc9b1aSDarren Reed 3447ddc9b1aSDarren Reed ifs->ifs_hook6_nic_events = (net_hook_register(ifs->ifs_ipf_ipv6, 3457ddc9b1aSDarren Reed NH_NIC_EVENTS, ifs->ifs_ipfhook6_nicevents) == 0); 346f4b3ec61Sdh if (!ifs->ifs_hook6_nic_events) 347381a2a9aSdr goto hookup_failed; 348381a2a9aSdr 3497ddc9b1aSDarren Reed ifs->ifs_hook6_physical_in = (net_hook_register(ifs->ifs_ipf_ipv6, 3507ddc9b1aSDarren Reed NH_PHYSICAL_IN, ifs->ifs_ipfhook6_in) == 0); 351f4b3ec61Sdh if (!ifs->ifs_hook6_physical_in) 352381a2a9aSdr goto hookup_failed; 353381a2a9aSdr 3547ddc9b1aSDarren Reed ifs->ifs_hook6_physical_out = (net_hook_register(ifs->ifs_ipf_ipv6, 3557ddc9b1aSDarren Reed NH_PHYSICAL_OUT, ifs->ifs_ipfhook6_out) == 0); 356f4b3ec61Sdh if (!ifs->ifs_hook6_physical_out) 357381a2a9aSdr goto hookup_failed; 358381a2a9aSdr 359f4b3ec61Sdh if (ifs->ifs_ipf_loopback) { 3607ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_in = (net_hook_register( 3617ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN, 3627ddc9b1aSDarren Reed ifs->ifs_ipfhook6_loop_in) == 0); 363f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_in) 364381a2a9aSdr goto hookup_failed; 365381a2a9aSdr 3667ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_out = (net_hook_register( 3677ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT, 3687ddc9b1aSDarren Reed ifs->ifs_ipfhook6_loop_out) == 0); 369f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_out) 370381a2a9aSdr goto hookup_failed; 371381a2a9aSdr } 372381a2a9aSdr 373381a2a9aSdr /* 374381a2a9aSdr * Reacquire ipf_global, now it is safe. 375381a2a9aSdr */ 376f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 377381a2a9aSdr 3787c478bd9Sstevel@tonic-gate /* Do not use private interface ip_params_arr[] in Solaris 10 */ 3797c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 3827c478bd9Sstevel@tonic-gate ip_forwarding = &ip_g_forward; 3837c478bd9Sstevel@tonic-gate #endif 3847c478bd9Sstevel@tonic-gate /* 3857c478bd9Sstevel@tonic-gate * XXX - There is no terminator for this array, so it is not possible 3867c478bd9Sstevel@tonic-gate * to tell if what we are looking for is missing and go off the end 3877c478bd9Sstevel@tonic-gate * of the array. 3887c478bd9Sstevel@tonic-gate */ 3897c478bd9Sstevel@tonic-gate 390ab25eeb5Syz #if SOLARIS2 <= 8 3917c478bd9Sstevel@tonic-gate for (i = 0; ; i++) { 3927c478bd9Sstevel@tonic-gate if (!strcmp(ip_param_arr[i].ip_param_name, "ip_def_ttl")) { 3937c478bd9Sstevel@tonic-gate ip_ttl_ptr = &ip_param_arr[i].ip_param_value; 3947c478bd9Sstevel@tonic-gate } else if (!strcmp(ip_param_arr[i].ip_param_name, 3957c478bd9Sstevel@tonic-gate "ip_path_mtu_discovery")) { 3967c478bd9Sstevel@tonic-gate ip_mtudisc = &ip_param_arr[i].ip_param_value; 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate #if SOLARIS2 < 8 3997c478bd9Sstevel@tonic-gate else if (!strcmp(ip_param_arr[i].ip_param_name, 4007c478bd9Sstevel@tonic-gate "ip_forwarding")) { 4017c478bd9Sstevel@tonic-gate ip_forwarding = &ip_param_arr[i].ip_param_value; 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate #else 4047c478bd9Sstevel@tonic-gate else if (!strcmp(ip_param_arr[i].ip_param_name, 4057c478bd9Sstevel@tonic-gate "ip6_forwarding")) { 4067c478bd9Sstevel@tonic-gate ip6_forwarding = &ip_param_arr[i].ip_param_value; 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate #endif 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate if (ip_mtudisc != NULL && ip_ttl_ptr != NULL && 4117c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 4127c478bd9Sstevel@tonic-gate ip6_forwarding != NULL && 4137c478bd9Sstevel@tonic-gate #endif 4147c478bd9Sstevel@tonic-gate ip_forwarding != NULL) 4157c478bd9Sstevel@tonic-gate break; 4167c478bd9Sstevel@tonic-gate } 417ab25eeb5Syz #endif 4187c478bd9Sstevel@tonic-gate 419f4b3ec61Sdh if (ifs->ifs_fr_control_forwarding & 1) { 420ab25eeb5Syz if (ip_forwarding != NULL) 421ab25eeb5Syz *ip_forwarding = 1; 4227c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 423ab25eeb5Syz if (ip6_forwarding != NULL) 424ab25eeb5Syz *ip6_forwarding = 1; 4257c478bd9Sstevel@tonic-gate #endif 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate #endif 4297c478bd9Sstevel@tonic-gate 430381a2a9aSdr return 0; 431381a2a9aSdr hookup_failed: 432f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 433381a2a9aSdr return -1; 434381a2a9aSdr } 435381a2a9aSdr 436f4b3ec61Sdh static int fr_setipfloopback(set, ifs) 437381a2a9aSdr int set; 438f4b3ec61Sdh ipf_stack_t *ifs; 439381a2a9aSdr { 440f4b3ec61Sdh if (ifs->ifs_ipf_ipv4 == NULL || ifs->ifs_ipf_ipv6 == NULL) 441381a2a9aSdr return EFAULT; 442381a2a9aSdr 443f4b3ec61Sdh if (set && !ifs->ifs_ipf_loopback) { 444f4b3ec61Sdh ifs->ifs_ipf_loopback = 1; 445381a2a9aSdr 4467ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_in = (net_hook_register( 4477ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN, 4487ddc9b1aSDarren Reed ifs->ifs_ipfhook4_loop_in) == 0); 449f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_in) 450381a2a9aSdr return EINVAL; 451381a2a9aSdr 4527ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_out = (net_hook_register( 4537ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT, 4547ddc9b1aSDarren Reed ifs->ifs_ipfhook4_loop_out) == 0); 455f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_out) 456381a2a9aSdr return EINVAL; 457381a2a9aSdr 4587ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_in = (net_hook_register( 4597ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN, 4607ddc9b1aSDarren Reed ifs->ifs_ipfhook6_loop_in) == 0); 461f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_in) 462381a2a9aSdr return EINVAL; 463381a2a9aSdr 4647ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_out = (net_hook_register( 4657ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT, 4667ddc9b1aSDarren Reed ifs->ifs_ipfhook6_loop_out) == 0); 467f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_out) 468381a2a9aSdr return EINVAL; 469381a2a9aSdr 470f4b3ec61Sdh } else if (!set && ifs->ifs_ipf_loopback) { 471f4b3ec61Sdh ifs->ifs_ipf_loopback = 0; 472381a2a9aSdr 473f4b3ec61Sdh ifs->ifs_hook4_loopback_in = 4747ddc9b1aSDarren Reed (net_hook_unregister(ifs->ifs_ipf_ipv4, 4757ddc9b1aSDarren Reed NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0); 476f4b3ec61Sdh if (ifs->ifs_hook4_loopback_in) 477381a2a9aSdr return EBUSY; 478381a2a9aSdr 479f4b3ec61Sdh ifs->ifs_hook4_loopback_out = 4807ddc9b1aSDarren Reed (net_hook_unregister(ifs->ifs_ipf_ipv4, 4817ddc9b1aSDarren Reed NH_LOOPBACK_OUT, ifs->ifs_ipfhook4_loop_out) != 0); 482f4b3ec61Sdh if (ifs->ifs_hook4_loopback_out) 483381a2a9aSdr return EBUSY; 484381a2a9aSdr 485f4b3ec61Sdh ifs->ifs_hook6_loopback_in = 4867ddc9b1aSDarren Reed (net_hook_unregister(ifs->ifs_ipf_ipv6, 4877ddc9b1aSDarren Reed NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0); 488f4b3ec61Sdh if (ifs->ifs_hook6_loopback_in) 489381a2a9aSdr return EBUSY; 490381a2a9aSdr 491f4b3ec61Sdh ifs->ifs_hook6_loopback_out = 4927ddc9b1aSDarren Reed (net_hook_unregister(ifs->ifs_ipf_ipv6, 4937ddc9b1aSDarren Reed NH_LOOPBACK_OUT, ifs->ifs_ipfhook6_loop_out) != 0); 494f4b3ec61Sdh if (ifs->ifs_hook6_loopback_out) 495381a2a9aSdr return EBUSY; 496381a2a9aSdr } 4977c478bd9Sstevel@tonic-gate return 0; 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate /* 5027c478bd9Sstevel@tonic-gate * Filter ioctl interface. 5037c478bd9Sstevel@tonic-gate */ 5047c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5057c478bd9Sstevel@tonic-gate int iplioctl(dev, cmd, data, mode, cp, rp) 5067c478bd9Sstevel@tonic-gate dev_t dev; 5077c478bd9Sstevel@tonic-gate int cmd; 5087c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 7 5097c478bd9Sstevel@tonic-gate intptr_t data; 5107c478bd9Sstevel@tonic-gate #else 5117c478bd9Sstevel@tonic-gate int *data; 5127c478bd9Sstevel@tonic-gate #endif 5137c478bd9Sstevel@tonic-gate int mode; 5147c478bd9Sstevel@tonic-gate cred_t *cp; 5157c478bd9Sstevel@tonic-gate int *rp; 5167c478bd9Sstevel@tonic-gate { 5177c478bd9Sstevel@tonic-gate int error = 0, tmp; 5187c478bd9Sstevel@tonic-gate friostat_t fio; 5197c478bd9Sstevel@tonic-gate minor_t unit; 5207c478bd9Sstevel@tonic-gate u_int enable; 521f4b3ec61Sdh ipf_stack_t *ifs; 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 5247c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplioctl(%x,%x,%x,%d,%x,%d)\n", 5257c478bd9Sstevel@tonic-gate dev, cmd, data, mode, cp, rp); 5267c478bd9Sstevel@tonic-gate #endif 5277c478bd9Sstevel@tonic-gate unit = getminor(dev); 5287c478bd9Sstevel@tonic-gate if (IPL_LOGMAX < unit) 5297c478bd9Sstevel@tonic-gate return ENXIO; 5307c478bd9Sstevel@tonic-gate 5317ddc9b1aSDarren Reed /* 5327ddc9b1aSDarren Reed * As we're calling ipf_find_stack in user space, from a given zone 5337ddc9b1aSDarren Reed * to find the stack pointer for this zone, there is no need to have 5347ddc9b1aSDarren Reed * a hold/refence count here. 5357ddc9b1aSDarren Reed */ 5367ddc9b1aSDarren Reed ifs = ipf_find_stack(crgetzoneid(cp)); 537f4b3ec61Sdh ASSERT(ifs != NULL); 538f4b3ec61Sdh 539f4b3ec61Sdh if (ifs->ifs_fr_running <= 0) { 540f4b3ec61Sdh if (unit != IPL_LOGIPF) { 5417c478bd9Sstevel@tonic-gate return EIO; 542f4b3ec61Sdh } 5437c478bd9Sstevel@tonic-gate if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 544ab25eeb5Syz cmd != SIOCIPFSET && cmd != SIOCFRENB && 545f4b3ec61Sdh cmd != SIOCGETFS && cmd != SIOCGETFF) { 5467c478bd9Sstevel@tonic-gate return EIO; 547f4b3ec61Sdh } 5487c478bd9Sstevel@tonic-gate } 5497c478bd9Sstevel@tonic-gate 550f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_global); 5517c478bd9Sstevel@tonic-gate 5527ddc9b1aSDarren Reed error = fr_ioctlswitch(unit, (caddr_t)data, cmd, mode, cp->cr_uid, 5537ddc9b1aSDarren Reed curproc, ifs); 5547c478bd9Sstevel@tonic-gate if (error != -1) { 555f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 5567c478bd9Sstevel@tonic-gate return error; 5577c478bd9Sstevel@tonic-gate } 5587c478bd9Sstevel@tonic-gate error = 0; 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate switch (cmd) 5617c478bd9Sstevel@tonic-gate { 5627c478bd9Sstevel@tonic-gate case SIOCFRENB : 5637c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 5647c478bd9Sstevel@tonic-gate error = EPERM; 5657c478bd9Sstevel@tonic-gate else { 5667c478bd9Sstevel@tonic-gate error = COPYIN((caddr_t)data, (caddr_t)&enable, 5677c478bd9Sstevel@tonic-gate sizeof(enable)); 5687c478bd9Sstevel@tonic-gate if (error != 0) { 5697c478bd9Sstevel@tonic-gate error = EFAULT; 5707c478bd9Sstevel@tonic-gate break; 5717c478bd9Sstevel@tonic-gate } 5727c478bd9Sstevel@tonic-gate 573f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 574f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 5757ddc9b1aSDarren Reed error = fr_enableipf(ifs, enable); 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate break; 5787c478bd9Sstevel@tonic-gate case SIOCIPFSET : 5797c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) { 5807c478bd9Sstevel@tonic-gate error = EPERM; 5817c478bd9Sstevel@tonic-gate break; 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate /* FALLTHRU */ 5847c478bd9Sstevel@tonic-gate case SIOCIPFGETNEXT : 5857c478bd9Sstevel@tonic-gate case SIOCIPFGET : 586f4b3ec61Sdh error = fr_ipftune(cmd, (void *)data, ifs); 5877c478bd9Sstevel@tonic-gate break; 5887c478bd9Sstevel@tonic-gate case SIOCSETFF : 5897c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 5907c478bd9Sstevel@tonic-gate error = EPERM; 5917c478bd9Sstevel@tonic-gate else { 5927ddc9b1aSDarren Reed error = COPYIN((caddr_t)data, 5937ddc9b1aSDarren Reed (caddr_t)&ifs->ifs_fr_flags, 5947ddc9b1aSDarren Reed sizeof(ifs->ifs_fr_flags)); 5957c478bd9Sstevel@tonic-gate if (error != 0) 5967c478bd9Sstevel@tonic-gate error = EFAULT; 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate break; 599381a2a9aSdr case SIOCIPFLP : 600381a2a9aSdr error = COPYIN((caddr_t)data, (caddr_t)&tmp, 601381a2a9aSdr sizeof(tmp)); 602381a2a9aSdr if (error != 0) 603381a2a9aSdr error = EFAULT; 604381a2a9aSdr else 605f4b3ec61Sdh error = fr_setipfloopback(tmp, ifs); 606381a2a9aSdr break; 6077c478bd9Sstevel@tonic-gate case SIOCGETFF : 608f4b3ec61Sdh error = COPYOUT((caddr_t)&ifs->ifs_fr_flags, (caddr_t)data, 6097ddc9b1aSDarren Reed sizeof(ifs->ifs_fr_flags)); 6107c478bd9Sstevel@tonic-gate if (error != 0) 6117c478bd9Sstevel@tonic-gate error = EFAULT; 6127c478bd9Sstevel@tonic-gate break; 6137c478bd9Sstevel@tonic-gate case SIOCFUNCL : 6147c478bd9Sstevel@tonic-gate error = fr_resolvefunc((void *)data); 6157c478bd9Sstevel@tonic-gate break; 6167c478bd9Sstevel@tonic-gate case SIOCINAFR : 6177c478bd9Sstevel@tonic-gate case SIOCRMAFR : 6187c478bd9Sstevel@tonic-gate case SIOCADAFR : 6197c478bd9Sstevel@tonic-gate case SIOCZRLST : 6207c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6217c478bd9Sstevel@tonic-gate error = EPERM; 6227c478bd9Sstevel@tonic-gate else 6237c478bd9Sstevel@tonic-gate error = frrequest(unit, cmd, (caddr_t)data, 624f4b3ec61Sdh ifs->ifs_fr_active, 1, ifs); 6257c478bd9Sstevel@tonic-gate break; 6267c478bd9Sstevel@tonic-gate case SIOCINIFR : 6277c478bd9Sstevel@tonic-gate case SIOCRMIFR : 6287c478bd9Sstevel@tonic-gate case SIOCADIFR : 6297c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6307c478bd9Sstevel@tonic-gate error = EPERM; 6317c478bd9Sstevel@tonic-gate else 6327c478bd9Sstevel@tonic-gate error = frrequest(unit, cmd, (caddr_t)data, 633f4b3ec61Sdh 1 - ifs->ifs_fr_active, 1, ifs); 6347c478bd9Sstevel@tonic-gate break; 6357c478bd9Sstevel@tonic-gate case SIOCSWAPA : 6367c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6377c478bd9Sstevel@tonic-gate error = EPERM; 6387c478bd9Sstevel@tonic-gate else { 639f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_mutex); 640f4b3ec61Sdh error = COPYOUT((caddr_t)&ifs->ifs_fr_active, 641f4b3ec61Sdh (caddr_t)data, 642f4b3ec61Sdh sizeof(ifs->ifs_fr_active)); 6437c478bd9Sstevel@tonic-gate if (error != 0) 6447c478bd9Sstevel@tonic-gate error = EFAULT; 6457c478bd9Sstevel@tonic-gate else 646f4b3ec61Sdh ifs->ifs_fr_active = 1 - ifs->ifs_fr_active; 647f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 6487c478bd9Sstevel@tonic-gate } 6497c478bd9Sstevel@tonic-gate break; 6507c478bd9Sstevel@tonic-gate case SIOCGETFS : 651f4b3ec61Sdh fr_getstat(&fio, ifs); 6527c478bd9Sstevel@tonic-gate error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT); 6537c478bd9Sstevel@tonic-gate break; 6547c478bd9Sstevel@tonic-gate case SIOCFRZST : 6557c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6567c478bd9Sstevel@tonic-gate error = EPERM; 6577c478bd9Sstevel@tonic-gate else 658f4b3ec61Sdh error = fr_zerostats((caddr_t)data, ifs); 6597c478bd9Sstevel@tonic-gate break; 6607c478bd9Sstevel@tonic-gate case SIOCIPFFL : 6617c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6627c478bd9Sstevel@tonic-gate error = EPERM; 6637c478bd9Sstevel@tonic-gate else { 6647c478bd9Sstevel@tonic-gate error = COPYIN((caddr_t)data, (caddr_t)&tmp, 6657c478bd9Sstevel@tonic-gate sizeof(tmp)); 6667c478bd9Sstevel@tonic-gate if (!error) { 667f4b3ec61Sdh tmp = frflush(unit, 4, tmp, ifs); 6687c478bd9Sstevel@tonic-gate error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 6697ddc9b1aSDarren Reed sizeof(tmp)); 6707c478bd9Sstevel@tonic-gate if (error != 0) 6717c478bd9Sstevel@tonic-gate error = EFAULT; 6727c478bd9Sstevel@tonic-gate } else 6737c478bd9Sstevel@tonic-gate error = EFAULT; 6747c478bd9Sstevel@tonic-gate } 6757c478bd9Sstevel@tonic-gate break; 6767663b816Sml #ifdef USE_INET6 6777663b816Sml case SIOCIPFL6 : 6787663b816Sml if (!(mode & FWRITE)) 6797663b816Sml error = EPERM; 6807663b816Sml else { 6817663b816Sml error = COPYIN((caddr_t)data, (caddr_t)&tmp, 6827663b816Sml sizeof(tmp)); 6837663b816Sml if (!error) { 684f4b3ec61Sdh tmp = frflush(unit, 6, tmp, ifs); 6857663b816Sml error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 6867ddc9b1aSDarren Reed sizeof(tmp)); 6877663b816Sml if (error != 0) 6887663b816Sml error = EFAULT; 6897663b816Sml } else 6907663b816Sml error = EFAULT; 6917663b816Sml } 6927663b816Sml break; 6937663b816Sml #endif 6947c478bd9Sstevel@tonic-gate case SIOCSTLCK : 6957c478bd9Sstevel@tonic-gate error = COPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 6967c478bd9Sstevel@tonic-gate if (error == 0) { 697f4b3ec61Sdh ifs->ifs_fr_state_lock = tmp; 698f4b3ec61Sdh ifs->ifs_fr_nat_lock = tmp; 699f4b3ec61Sdh ifs->ifs_fr_frag_lock = tmp; 700f4b3ec61Sdh ifs->ifs_fr_auth_lock = tmp; 7017c478bd9Sstevel@tonic-gate } else 7027c478bd9Sstevel@tonic-gate error = EFAULT; 7037c478bd9Sstevel@tonic-gate break; 7047c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 7057c478bd9Sstevel@tonic-gate case SIOCIPFFB : 7067c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 7077c478bd9Sstevel@tonic-gate error = EPERM; 7087c478bd9Sstevel@tonic-gate else { 709f4b3ec61Sdh tmp = ipflog_clear(unit, ifs); 7107c478bd9Sstevel@tonic-gate error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 7117c478bd9Sstevel@tonic-gate sizeof(tmp)); 7127c478bd9Sstevel@tonic-gate if (error) 7137c478bd9Sstevel@tonic-gate error = EFAULT; 7147c478bd9Sstevel@tonic-gate } 7157c478bd9Sstevel@tonic-gate break; 7167c478bd9Sstevel@tonic-gate #endif /* IPFILTER_LOG */ 7177c478bd9Sstevel@tonic-gate case SIOCFRSYN : 7187c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 7197c478bd9Sstevel@tonic-gate error = EPERM; 7207c478bd9Sstevel@tonic-gate else { 721f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 722f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 723381a2a9aSdr 724f4b3ec61Sdh frsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 725d6c23f6fSyx fr_natifpsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 726d6c23f6fSyx fr_nataddrsync(0, NULL, NULL, ifs); 727f4b3ec61Sdh fr_statesync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 728381a2a9aSdr error = 0; 7297c478bd9Sstevel@tonic-gate } 7307c478bd9Sstevel@tonic-gate break; 7317c478bd9Sstevel@tonic-gate case SIOCGFRST : 732f4b3ec61Sdh error = fr_outobj((void *)data, fr_fragstats(ifs), 7337c478bd9Sstevel@tonic-gate IPFOBJ_FRAGSTAT); 7347c478bd9Sstevel@tonic-gate break; 7357c478bd9Sstevel@tonic-gate case FIONREAD : 7367c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 737f4b3ec61Sdh tmp = (int)ifs->ifs_iplused[IPL_LOGIPF]; 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate error = COPYOUT((caddr_t)&tmp, (caddr_t)data, sizeof(tmp)); 7407c478bd9Sstevel@tonic-gate if (error != 0) 7417c478bd9Sstevel@tonic-gate error = EFAULT; 7427c478bd9Sstevel@tonic-gate #endif 7437c478bd9Sstevel@tonic-gate break; 744f4b3ec61Sdh case SIOCIPFITER : 7457ddc9b1aSDarren Reed error = ipf_frruleiter((caddr_t)data, cp->cr_uid, 7467ddc9b1aSDarren Reed curproc, ifs); 747f4b3ec61Sdh break; 748f4b3ec61Sdh 749f4b3ec61Sdh case SIOCGENITER : 7507ddc9b1aSDarren Reed error = ipf_genericiter((caddr_t)data, cp->cr_uid, 7517ddc9b1aSDarren Reed curproc, ifs); 752f4b3ec61Sdh break; 753f4b3ec61Sdh 754f4b3ec61Sdh case SIOCIPFDELTOK : 755bb1d9de5SJohn Ojemann error = BCOPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 756bb1d9de5SJohn Ojemann if (error != 0) { 757bb1d9de5SJohn Ojemann error = EFAULT; 758bb1d9de5SJohn Ojemann } else { 759bb1d9de5SJohn Ojemann error = ipf_deltoken(tmp, cp->cr_uid, curproc, ifs); 760bb1d9de5SJohn Ojemann } 761f4b3ec61Sdh break; 762f4b3ec61Sdh 7637c478bd9Sstevel@tonic-gate default : 764*33f2fefdSDarren Reed #ifdef IPFDEBUG 7657ddc9b1aSDarren Reed cmn_err(CE_NOTE, "Unknown: cmd 0x%x data %p", 7667ddc9b1aSDarren Reed cmd, (void *)data); 767*33f2fefdSDarren Reed #endif 7687c478bd9Sstevel@tonic-gate error = EINVAL; 7697c478bd9Sstevel@tonic-gate break; 7707c478bd9Sstevel@tonic-gate } 771f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 7727c478bd9Sstevel@tonic-gate return error; 7737c478bd9Sstevel@tonic-gate } 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate 7767ddc9b1aSDarren Reed static int fr_enableipf(ifs, enable) 777882bd30bSdr ipf_stack_t *ifs; 778882bd30bSdr int enable; 779882bd30bSdr { 780882bd30bSdr int error; 781882bd30bSdr 78244aaa2b6Sjojemann if (!enable) { 783882bd30bSdr error = ipldetach(ifs); 784882bd30bSdr if (error == 0) 785882bd30bSdr ifs->ifs_fr_running = -1; 7867ddc9b1aSDarren Reed return error; 787882bd30bSdr } 788882bd30bSdr 78944aaa2b6Sjojemann if (ifs->ifs_fr_running > 0) 7907ddc9b1aSDarren Reed return 0; 79144aaa2b6Sjojemann 7927ddc9b1aSDarren Reed error = iplattach(ifs); 79344aaa2b6Sjojemann if (error == 0) { 79444aaa2b6Sjojemann if (ifs->ifs_fr_timer_id == NULL) { 79544aaa2b6Sjojemann int hz = drv_usectohz(500000); 79644aaa2b6Sjojemann 79744aaa2b6Sjojemann ifs->ifs_fr_timer_id = timeout(fr_slowtimer, 7987ddc9b1aSDarren Reed (void *)ifs, 7997ddc9b1aSDarren Reed hz); 80044aaa2b6Sjojemann } 80144aaa2b6Sjojemann ifs->ifs_fr_running = 1; 80244aaa2b6Sjojemann } else { 80344aaa2b6Sjojemann (void) ipldetach(ifs); 80444aaa2b6Sjojemann } 8057ddc9b1aSDarren Reed return error; 806882bd30bSdr } 807882bd30bSdr 808882bd30bSdr 809f4b3ec61Sdh phy_if_t get_unit(name, v, ifs) 810f4b3ec61Sdh char *name; 811f4b3ec61Sdh int v; 812f4b3ec61Sdh ipf_stack_t *ifs; 8137c478bd9Sstevel@tonic-gate { 8147ddc9b1aSDarren Reed net_handle_t nif; 815381a2a9aSdr 816381a2a9aSdr if (v == 4) 817f4b3ec61Sdh nif = ifs->ifs_ipf_ipv4; 818381a2a9aSdr else if (v == 6) 819f4b3ec61Sdh nif = ifs->ifs_ipf_ipv6; 820381a2a9aSdr else 821381a2a9aSdr return 0; 822381a2a9aSdr 823f4b3ec61Sdh return (net_phylookup(nif, name)); 8247c478bd9Sstevel@tonic-gate } 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate /* 8277c478bd9Sstevel@tonic-gate * routines below for saving IP headers to buffer 8287c478bd9Sstevel@tonic-gate */ 8297c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8307c478bd9Sstevel@tonic-gate int iplopen(devp, flags, otype, cred) 8317c478bd9Sstevel@tonic-gate dev_t *devp; 8327c478bd9Sstevel@tonic-gate int flags, otype; 8337c478bd9Sstevel@tonic-gate cred_t *cred; 8347c478bd9Sstevel@tonic-gate { 8357c478bd9Sstevel@tonic-gate minor_t min = getminor(*devp); 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 8387c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplopen(%x,%x,%x,%x)\n", devp, flags, otype, cred); 8397c478bd9Sstevel@tonic-gate #endif 8407c478bd9Sstevel@tonic-gate if (!(otype & OTYP_CHR)) 8417c478bd9Sstevel@tonic-gate return ENXIO; 8427c478bd9Sstevel@tonic-gate 8437c478bd9Sstevel@tonic-gate min = (IPL_LOGMAX < min) ? ENXIO : 0; 8447c478bd9Sstevel@tonic-gate return min; 8457c478bd9Sstevel@tonic-gate } 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8497c478bd9Sstevel@tonic-gate int iplclose(dev, flags, otype, cred) 8507c478bd9Sstevel@tonic-gate dev_t dev; 8517c478bd9Sstevel@tonic-gate int flags, otype; 8527c478bd9Sstevel@tonic-gate cred_t *cred; 8537c478bd9Sstevel@tonic-gate { 8547c478bd9Sstevel@tonic-gate minor_t min = getminor(dev); 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 8577c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplclose(%x,%x,%x,%x)\n", dev, flags, otype, cred); 8587c478bd9Sstevel@tonic-gate #endif 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate min = (IPL_LOGMAX < min) ? ENXIO : 0; 8617c478bd9Sstevel@tonic-gate return min; 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 8657c478bd9Sstevel@tonic-gate /* 8667c478bd9Sstevel@tonic-gate * iplread/ipllog 8677c478bd9Sstevel@tonic-gate * both of these must operate with at least splnet() lest they be 8687c478bd9Sstevel@tonic-gate * called during packet processing and cause an inconsistancy to appear in 8697c478bd9Sstevel@tonic-gate * the filter lists. 8707c478bd9Sstevel@tonic-gate */ 8717c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8727c478bd9Sstevel@tonic-gate int iplread(dev, uio, cp) 8737c478bd9Sstevel@tonic-gate dev_t dev; 8747c478bd9Sstevel@tonic-gate register struct uio *uio; 8757c478bd9Sstevel@tonic-gate cred_t *cp; 8767c478bd9Sstevel@tonic-gate { 877f4b3ec61Sdh ipf_stack_t *ifs; 878f4b3ec61Sdh int ret; 879f4b3ec61Sdh 8807ddc9b1aSDarren Reed /* 8817ddc9b1aSDarren Reed * As we're calling ipf_find_stack in user space, from a given zone 8827ddc9b1aSDarren Reed * to find the stack pointer for this zone, there is no need to have 8837ddc9b1aSDarren Reed * a hold/refence count here. 8847ddc9b1aSDarren Reed */ 8857ddc9b1aSDarren Reed ifs = ipf_find_stack(crgetzoneid(cp)); 886f4b3ec61Sdh ASSERT(ifs != NULL); 887f4b3ec61Sdh 8887c478bd9Sstevel@tonic-gate # ifdef IPFDEBUG 8897c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplread(%x,%x,%x)\n", dev, uio, cp); 8907c478bd9Sstevel@tonic-gate # endif 89108ee25aeSdr 892f4b3ec61Sdh if (ifs->ifs_fr_running < 1) { 89308ee25aeSdr return EIO; 894f4b3ec61Sdh } 89508ee25aeSdr 8967c478bd9Sstevel@tonic-gate # ifdef IPFILTER_SYNC 897f4b3ec61Sdh if (getminor(dev) == IPL_LOGSYNC) { 8987c478bd9Sstevel@tonic-gate return ipfsync_read(uio); 899f4b3ec61Sdh } 9007c478bd9Sstevel@tonic-gate # endif 9017c478bd9Sstevel@tonic-gate 902f4b3ec61Sdh ret = ipflog_read(getminor(dev), uio, ifs); 903f4b3ec61Sdh return ret; 9047c478bd9Sstevel@tonic-gate } 9057c478bd9Sstevel@tonic-gate #endif /* IPFILTER_LOG */ 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate 9087c478bd9Sstevel@tonic-gate /* 9097c478bd9Sstevel@tonic-gate * iplread/ipllog 9107c478bd9Sstevel@tonic-gate * both of these must operate with at least splnet() lest they be 9117c478bd9Sstevel@tonic-gate * called during packet processing and cause an inconsistancy to appear in 9127c478bd9Sstevel@tonic-gate * the filter lists. 9137c478bd9Sstevel@tonic-gate */ 9147c478bd9Sstevel@tonic-gate int iplwrite(dev, uio, cp) 9157c478bd9Sstevel@tonic-gate dev_t dev; 9167c478bd9Sstevel@tonic-gate register struct uio *uio; 9177c478bd9Sstevel@tonic-gate cred_t *cp; 9187c478bd9Sstevel@tonic-gate { 919f4b3ec61Sdh ipf_stack_t *ifs; 920f4b3ec61Sdh 9217ddc9b1aSDarren Reed /* 9227ddc9b1aSDarren Reed * As we're calling ipf_find_stack in user space, from a given zone 9237ddc9b1aSDarren Reed * to find the stack pointer for this zone, there is no need to have 9247ddc9b1aSDarren Reed * a hold/refence count here. 9257ddc9b1aSDarren Reed */ 9267ddc9b1aSDarren Reed ifs = ipf_find_stack(crgetzoneid(cp)); 927f4b3ec61Sdh ASSERT(ifs != NULL); 928f4b3ec61Sdh 9297c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 9307c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplwrite(%x,%x,%x)\n", dev, uio, cp); 9317c478bd9Sstevel@tonic-gate #endif 93208ee25aeSdr 933f4b3ec61Sdh if (ifs->ifs_fr_running < 1) { 93408ee25aeSdr return EIO; 935f4b3ec61Sdh } 93608ee25aeSdr 937ab25eeb5Syz #ifdef IPFILTER_SYNC 938ab25eeb5Syz if (getminor(dev) == IPL_LOGSYNC) 939ab25eeb5Syz return ipfsync_write(uio); 9407c478bd9Sstevel@tonic-gate #endif /* IPFILTER_SYNC */ 941ab25eeb5Syz dev = dev; /* LINT */ 942ab25eeb5Syz uio = uio; /* LINT */ 943ab25eeb5Syz cp = cp; /* LINT */ 944ab25eeb5Syz return ENXIO; 945ab25eeb5Syz } 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate /* 9497c478bd9Sstevel@tonic-gate * fr_send_reset - this could conceivably be a call to tcp_respond(), but that 9507c478bd9Sstevel@tonic-gate * requires a large amount of setting up and isn't any more efficient. 9517c478bd9Sstevel@tonic-gate */ 9527c478bd9Sstevel@tonic-gate int fr_send_reset(fin) 9537c478bd9Sstevel@tonic-gate fr_info_t *fin; 9547c478bd9Sstevel@tonic-gate { 9557c478bd9Sstevel@tonic-gate tcphdr_t *tcp, *tcp2; 9567c478bd9Sstevel@tonic-gate int tlen, hlen; 9577c478bd9Sstevel@tonic-gate mblk_t *m; 9587c478bd9Sstevel@tonic-gate #ifdef USE_INET6 9597c478bd9Sstevel@tonic-gate ip6_t *ip6; 9607c478bd9Sstevel@tonic-gate #endif 9617c478bd9Sstevel@tonic-gate ip_t *ip; 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate tcp = fin->fin_dp; 9647c478bd9Sstevel@tonic-gate if (tcp->th_flags & TH_RST) 9657c478bd9Sstevel@tonic-gate return -1; 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate #ifndef IPFILTER_CKSUM 9687c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 9697c478bd9Sstevel@tonic-gate return -1; 9707c478bd9Sstevel@tonic-gate #endif 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate tlen = (tcp->th_flags & (TH_SYN|TH_FIN)) ? 1 : 0; 9737c478bd9Sstevel@tonic-gate #ifdef USE_INET6 9747c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) 9757c478bd9Sstevel@tonic-gate hlen = sizeof(ip6_t); 9767c478bd9Sstevel@tonic-gate else 9777c478bd9Sstevel@tonic-gate #endif 9787c478bd9Sstevel@tonic-gate hlen = sizeof(ip_t); 9797c478bd9Sstevel@tonic-gate hlen += sizeof(*tcp2); 9807c478bd9Sstevel@tonic-gate if ((m = (mblk_t *)allocb(hlen + 64, BPRI_HI)) == NULL) 9817c478bd9Sstevel@tonic-gate return -1; 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate m->b_rptr += 64; 9847c478bd9Sstevel@tonic-gate MTYPE(m) = M_DATA; 9857c478bd9Sstevel@tonic-gate m->b_wptr = m->b_rptr + hlen; 986ab25eeb5Syz ip = (ip_t *)m->b_rptr; 987ab25eeb5Syz bzero((char *)ip, hlen); 9887c478bd9Sstevel@tonic-gate tcp2 = (struct tcphdr *)(m->b_rptr + hlen - sizeof(*tcp2)); 9897c478bd9Sstevel@tonic-gate tcp2->th_dport = tcp->th_sport; 9907c478bd9Sstevel@tonic-gate tcp2->th_sport = tcp->th_dport; 9917c478bd9Sstevel@tonic-gate if (tcp->th_flags & TH_ACK) { 9927c478bd9Sstevel@tonic-gate tcp2->th_seq = tcp->th_ack; 9937c478bd9Sstevel@tonic-gate tcp2->th_flags = TH_RST; 9947c478bd9Sstevel@tonic-gate } else { 9957c478bd9Sstevel@tonic-gate tcp2->th_ack = ntohl(tcp->th_seq); 9967c478bd9Sstevel@tonic-gate tcp2->th_ack += tlen; 9977c478bd9Sstevel@tonic-gate tcp2->th_ack = htonl(tcp2->th_ack); 9987c478bd9Sstevel@tonic-gate tcp2->th_flags = TH_RST|TH_ACK; 9997c478bd9Sstevel@tonic-gate } 10007c478bd9Sstevel@tonic-gate tcp2->th_off = sizeof(struct tcphdr) >> 2; 10017c478bd9Sstevel@tonic-gate 1002ab25eeb5Syz ip->ip_v = fin->fin_v; 10037c478bd9Sstevel@tonic-gate #ifdef USE_INET6 10047c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 10057c478bd9Sstevel@tonic-gate ip6 = (ip6_t *)m->b_rptr; 10067663b816Sml ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 1007d6c23f6fSyx ip6->ip6_src = fin->fin_dst6.in6; 1008d6c23f6fSyx ip6->ip6_dst = fin->fin_src6.in6; 10097c478bd9Sstevel@tonic-gate ip6->ip6_plen = htons(sizeof(*tcp)); 10107c478bd9Sstevel@tonic-gate ip6->ip6_nxt = IPPROTO_TCP; 10117663b816Sml tcp2->th_sum = fr_cksum(m, (ip_t *)ip6, IPPROTO_TCP, tcp2); 10127c478bd9Sstevel@tonic-gate } else 10137c478bd9Sstevel@tonic-gate #endif 10147c478bd9Sstevel@tonic-gate { 10157c478bd9Sstevel@tonic-gate ip->ip_src.s_addr = fin->fin_daddr; 10167c478bd9Sstevel@tonic-gate ip->ip_dst.s_addr = fin->fin_saddr; 10177c478bd9Sstevel@tonic-gate ip->ip_id = fr_nextipid(fin); 10187c478bd9Sstevel@tonic-gate ip->ip_hl = sizeof(*ip) >> 2; 10197c478bd9Sstevel@tonic-gate ip->ip_p = IPPROTO_TCP; 102037b40788Sekozlow ip->ip_len = sizeof(*ip) + sizeof(*tcp); 10217c478bd9Sstevel@tonic-gate ip->ip_tos = fin->fin_ip->ip_tos; 10227c478bd9Sstevel@tonic-gate tcp2->th_sum = fr_cksum(m, ip, IPPROTO_TCP, tcp2); 10237c478bd9Sstevel@tonic-gate } 1024ab25eeb5Syz return fr_send_ip(fin, m, &m); 10257c478bd9Sstevel@tonic-gate } 10267c478bd9Sstevel@tonic-gate 102737b40788Sekozlow /* 102837b40788Sekozlow * Function: fr_send_ip 102937b40788Sekozlow * Returns: 0: success 103037b40788Sekozlow * -1: failed 103137b40788Sekozlow * Parameters: 103237b40788Sekozlow * fin: packet information 103337b40788Sekozlow * m: the message block where ip head starts 103437b40788Sekozlow * 103537b40788Sekozlow * Send a new packet through the IP stack. 103637b40788Sekozlow * 103737b40788Sekozlow * For IPv4 packets, ip_len must be in host byte order, and ip_v, 103837b40788Sekozlow * ip_ttl, ip_off, and ip_sum are ignored (filled in by this 103937b40788Sekozlow * function). 104037b40788Sekozlow * 104137b40788Sekozlow * For IPv6 packets, ip6_flow, ip6_vfc, and ip6_hlim are filled 104237b40788Sekozlow * in by this function. 104337b40788Sekozlow * 104437b40788Sekozlow * All other portions of the packet must be in on-the-wire format. 104537b40788Sekozlow */ 1046ab25eeb5Syz /*ARGSUSED*/ 1047ab25eeb5Syz static int fr_send_ip(fin, m, mpp) 10487c478bd9Sstevel@tonic-gate fr_info_t *fin; 1049ab25eeb5Syz mblk_t *m, **mpp; 10507c478bd9Sstevel@tonic-gate { 1051ab25eeb5Syz qpktinfo_t qpi, *qpip; 1052ab25eeb5Syz fr_info_t fnew; 1053ab25eeb5Syz ip_t *ip; 1054ab25eeb5Syz int i, hlen; 1055f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1056ab25eeb5Syz 1057ab25eeb5Syz ip = (ip_t *)m->b_rptr; 1058ab25eeb5Syz bzero((char *)&fnew, sizeof(fnew)); 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate #ifdef USE_INET6 10617c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 10627c478bd9Sstevel@tonic-gate ip6_t *ip6; 10637c478bd9Sstevel@tonic-gate 1064ab25eeb5Syz ip6 = (ip6_t *)ip; 10657c478bd9Sstevel@tonic-gate ip6->ip6_vfc = 0x60; 10667c478bd9Sstevel@tonic-gate ip6->ip6_hlim = 127; 1067ab25eeb5Syz fnew.fin_v = 6; 1068ab25eeb5Syz hlen = sizeof(*ip6); 1069923d6102Szf fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen; 10707c478bd9Sstevel@tonic-gate } else 10717c478bd9Sstevel@tonic-gate #endif 10727c478bd9Sstevel@tonic-gate { 1073ab25eeb5Syz fnew.fin_v = 4; 10747c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 10 10757c478bd9Sstevel@tonic-gate ip->ip_ttl = 255; 1076f4b3ec61Sdh if (net_getpmtuenabled(ifs->ifs_ipf_ipv4) == 1) 1077381a2a9aSdr ip->ip_off = htons(IP_DF); 10787c478bd9Sstevel@tonic-gate #else 1079ab25eeb5Syz if (ip_ttl_ptr != NULL) 1080ab25eeb5Syz ip->ip_ttl = (u_char)(*ip_ttl_ptr); 1081ab25eeb5Syz else 1082ab25eeb5Syz ip->ip_ttl = 63; 1083ab25eeb5Syz if (ip_mtudisc != NULL) 1084ab25eeb5Syz ip->ip_off = htons(*ip_mtudisc ? IP_DF : 0); 1085ab25eeb5Syz else 1086ab25eeb5Syz ip->ip_off = htons(IP_DF); 10877c478bd9Sstevel@tonic-gate #endif 1088ab25eeb5Syz /* 1089ab25eeb5Syz * The dance with byte order and ip_len/ip_off is because in 1090ab25eeb5Syz * fr_fastroute, it expects them to be in host byte order but 1091ab25eeb5Syz * ipf_cksum expects them to be in network byte order. 1092ab25eeb5Syz */ 1093ab25eeb5Syz ip->ip_len = htons(ip->ip_len); 10947c478bd9Sstevel@tonic-gate ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip)); 1095ab25eeb5Syz ip->ip_len = ntohs(ip->ip_len); 1096ab25eeb5Syz ip->ip_off = ntohs(ip->ip_off); 1097ab25eeb5Syz hlen = sizeof(*ip); 1098923d6102Szf fnew.fin_plen = ip->ip_len; 10997c478bd9Sstevel@tonic-gate } 1100ab25eeb5Syz 1101ab25eeb5Syz qpip = fin->fin_qpi; 1102ab25eeb5Syz qpi.qpi_off = 0; 1103381a2a9aSdr qpi.qpi_ill = qpip->qpi_ill; 1104ab25eeb5Syz qpi.qpi_m = m; 1105ab25eeb5Syz qpi.qpi_data = ip; 1106ab25eeb5Syz fnew.fin_qpi = &qpi; 1107ab25eeb5Syz fnew.fin_ifp = fin->fin_ifp; 1108ab25eeb5Syz fnew.fin_flx = FI_NOCKSUM; 1109ab25eeb5Syz fnew.fin_m = m; 111090907f62SJohn Ojemann fnew.fin_qfm = m; 1111ab25eeb5Syz fnew.fin_ip = ip; 1112ab25eeb5Syz fnew.fin_mp = mpp; 1113ab25eeb5Syz fnew.fin_hlen = hlen; 1114ab25eeb5Syz fnew.fin_dp = (char *)ip + hlen; 1115f4b3ec61Sdh fnew.fin_ifs = fin->fin_ifs; 1116ab25eeb5Syz (void) fr_makefrip(hlen, ip, &fnew); 1117ab25eeb5Syz 1118ab25eeb5Syz i = fr_fastroute(m, mpp, &fnew, NULL); 11197c478bd9Sstevel@tonic-gate return i; 11207c478bd9Sstevel@tonic-gate } 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate int fr_send_icmp_err(type, fin, dst) 11247c478bd9Sstevel@tonic-gate int type; 11257c478bd9Sstevel@tonic-gate fr_info_t *fin; 11267c478bd9Sstevel@tonic-gate int dst; 11277c478bd9Sstevel@tonic-gate { 11287c478bd9Sstevel@tonic-gate struct in_addr dst4; 11297c478bd9Sstevel@tonic-gate struct icmp *icmp; 1130ab25eeb5Syz qpktinfo_t *qpi; 11317c478bd9Sstevel@tonic-gate int hlen, code; 1132381a2a9aSdr phy_if_t phy; 11337c478bd9Sstevel@tonic-gate u_short sz; 11347c478bd9Sstevel@tonic-gate #ifdef USE_INET6 11357c478bd9Sstevel@tonic-gate mblk_t *mb; 11367c478bd9Sstevel@tonic-gate #endif 11377c478bd9Sstevel@tonic-gate mblk_t *m; 11387c478bd9Sstevel@tonic-gate #ifdef USE_INET6 11397c478bd9Sstevel@tonic-gate ip6_t *ip6; 11407c478bd9Sstevel@tonic-gate #endif 11417c478bd9Sstevel@tonic-gate ip_t *ip; 1142f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate if ((type < 0) || (type > ICMP_MAXTYPE)) 11457c478bd9Sstevel@tonic-gate return -1; 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate code = fin->fin_icode; 11487c478bd9Sstevel@tonic-gate #ifdef USE_INET6 1149*33f2fefdSDarren Reed if ((code < 0) || (code >= ICMP_MAX_UNREACH)) 11507c478bd9Sstevel@tonic-gate return -1; 11517c478bd9Sstevel@tonic-gate #endif 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate #ifndef IPFILTER_CKSUM 11547c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 11557c478bd9Sstevel@tonic-gate return -1; 11567c478bd9Sstevel@tonic-gate #endif 11577c478bd9Sstevel@tonic-gate 1158ab25eeb5Syz qpi = fin->fin_qpi; 11597c478bd9Sstevel@tonic-gate 11607c478bd9Sstevel@tonic-gate #ifdef USE_INET6 11617c478bd9Sstevel@tonic-gate mb = fin->fin_qfm; 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 11647c478bd9Sstevel@tonic-gate sz = sizeof(ip6_t); 11657c478bd9Sstevel@tonic-gate sz += MIN(mb->b_wptr - mb->b_rptr, 512); 11667c478bd9Sstevel@tonic-gate hlen = sizeof(ip6_t); 11677c478bd9Sstevel@tonic-gate type = icmptoicmp6types[type]; 11687c478bd9Sstevel@tonic-gate if (type == ICMP6_DST_UNREACH) 11697c478bd9Sstevel@tonic-gate code = icmptoicmp6unreach[code]; 11707c478bd9Sstevel@tonic-gate } else 11717c478bd9Sstevel@tonic-gate #endif 11727c478bd9Sstevel@tonic-gate { 11737c478bd9Sstevel@tonic-gate if ((fin->fin_p == IPPROTO_ICMP) && 11747c478bd9Sstevel@tonic-gate !(fin->fin_flx & FI_SHORT)) 11757c478bd9Sstevel@tonic-gate switch (ntohs(fin->fin_data[0]) >> 8) 11767c478bd9Sstevel@tonic-gate { 11777c478bd9Sstevel@tonic-gate case ICMP_ECHO : 11787c478bd9Sstevel@tonic-gate case ICMP_TSTAMP : 11797c478bd9Sstevel@tonic-gate case ICMP_IREQ : 11807c478bd9Sstevel@tonic-gate case ICMP_MASKREQ : 11817c478bd9Sstevel@tonic-gate break; 11827c478bd9Sstevel@tonic-gate default : 11837c478bd9Sstevel@tonic-gate return 0; 11847c478bd9Sstevel@tonic-gate } 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate sz = sizeof(ip_t) * 2; 11877c478bd9Sstevel@tonic-gate sz += 8; /* 64 bits of data */ 11887c478bd9Sstevel@tonic-gate hlen = sizeof(ip_t); 11897c478bd9Sstevel@tonic-gate } 11907c478bd9Sstevel@tonic-gate 11917c478bd9Sstevel@tonic-gate sz += offsetof(struct icmp, icmp_ip); 11927c478bd9Sstevel@tonic-gate if ((m = (mblk_t *)allocb((size_t)sz + 64, BPRI_HI)) == NULL) 11937c478bd9Sstevel@tonic-gate return -1; 11947c478bd9Sstevel@tonic-gate MTYPE(m) = M_DATA; 11957c478bd9Sstevel@tonic-gate m->b_rptr += 64; 11967c478bd9Sstevel@tonic-gate m->b_wptr = m->b_rptr + sz; 11977c478bd9Sstevel@tonic-gate bzero((char *)m->b_rptr, (size_t)sz); 1198ab25eeb5Syz ip = (ip_t *)m->b_rptr; 1199ab25eeb5Syz ip->ip_v = fin->fin_v; 12007c478bd9Sstevel@tonic-gate icmp = (struct icmp *)(m->b_rptr + hlen); 12017c478bd9Sstevel@tonic-gate icmp->icmp_type = type & 0xff; 12027c478bd9Sstevel@tonic-gate icmp->icmp_code = code & 0xff; 1203381a2a9aSdr phy = (phy_if_t)qpi->qpi_ill; 1204381a2a9aSdr if (type == ICMP_UNREACH && (phy != 0) && 12057c478bd9Sstevel@tonic-gate fin->fin_icode == ICMP_UNREACH_NEEDFRAG) 1206f4b3ec61Sdh icmp->icmp_nextmtu = net_getmtu(ifs->ifs_ipf_ipv4, phy,0 ); 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate #ifdef USE_INET6 12097c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 12107c478bd9Sstevel@tonic-gate struct in6_addr dst6; 12117c478bd9Sstevel@tonic-gate int csz; 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate if (dst == 0) { 1214f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1215f4b3ec61Sdh 1216381a2a9aSdr if (fr_ifpaddr(6, FRI_NORMAL, (void *)phy, 1217f4b3ec61Sdh (void *)&dst6, NULL, ifs) == -1) { 12187c478bd9Sstevel@tonic-gate FREE_MB_T(m); 12197c478bd9Sstevel@tonic-gate return -1; 12207c478bd9Sstevel@tonic-gate } 12217c478bd9Sstevel@tonic-gate } else 1222d6c23f6fSyx dst6 = fin->fin_dst6.in6; 12237c478bd9Sstevel@tonic-gate 12247c478bd9Sstevel@tonic-gate csz = sz; 12257c478bd9Sstevel@tonic-gate sz -= sizeof(ip6_t); 12267c478bd9Sstevel@tonic-gate ip6 = (ip6_t *)m->b_rptr; 12277663b816Sml ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 12287c478bd9Sstevel@tonic-gate ip6->ip6_plen = htons((u_short)sz); 12297c478bd9Sstevel@tonic-gate ip6->ip6_nxt = IPPROTO_ICMPV6; 12307c478bd9Sstevel@tonic-gate ip6->ip6_src = dst6; 1231d6c23f6fSyx ip6->ip6_dst = fin->fin_src6.in6; 12327c478bd9Sstevel@tonic-gate sz -= offsetof(struct icmp, icmp_ip); 12337c478bd9Sstevel@tonic-gate bcopy((char *)mb->b_rptr, (char *)&icmp->icmp_ip, sz); 12347c478bd9Sstevel@tonic-gate icmp->icmp_cksum = csz - sizeof(ip6_t); 12357c478bd9Sstevel@tonic-gate } else 12367c478bd9Sstevel@tonic-gate #endif 12377c478bd9Sstevel@tonic-gate { 12387c478bd9Sstevel@tonic-gate ip->ip_hl = sizeof(*ip) >> 2; 12397c478bd9Sstevel@tonic-gate ip->ip_p = IPPROTO_ICMP; 12407c478bd9Sstevel@tonic-gate ip->ip_id = fin->fin_ip->ip_id; 12417c478bd9Sstevel@tonic-gate ip->ip_tos = fin->fin_ip->ip_tos; 124237b40788Sekozlow ip->ip_len = (u_short)sz; 12437c478bd9Sstevel@tonic-gate if (dst == 0) { 1244f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1245f4b3ec61Sdh 1246381a2a9aSdr if (fr_ifpaddr(4, FRI_NORMAL, (void *)phy, 1247f4b3ec61Sdh (void *)&dst4, NULL, ifs) == -1) { 12487c478bd9Sstevel@tonic-gate FREE_MB_T(m); 12497c478bd9Sstevel@tonic-gate return -1; 12507c478bd9Sstevel@tonic-gate } 1251381a2a9aSdr } else { 12527c478bd9Sstevel@tonic-gate dst4 = fin->fin_dst; 1253381a2a9aSdr } 12547c478bd9Sstevel@tonic-gate ip->ip_src = dst4; 12557c478bd9Sstevel@tonic-gate ip->ip_dst = fin->fin_src; 12567c478bd9Sstevel@tonic-gate bcopy((char *)fin->fin_ip, (char *)&icmp->icmp_ip, 12577c478bd9Sstevel@tonic-gate sizeof(*fin->fin_ip)); 12587c478bd9Sstevel@tonic-gate bcopy((char *)fin->fin_ip + fin->fin_hlen, 12597c478bd9Sstevel@tonic-gate (char *)&icmp->icmp_ip + sizeof(*fin->fin_ip), 8); 12607663b816Sml icmp->icmp_ip.ip_len = htons(icmp->icmp_ip.ip_len); 1261ab25eeb5Syz icmp->icmp_ip.ip_off = htons(icmp->icmp_ip.ip_off); 12627c478bd9Sstevel@tonic-gate icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 12637c478bd9Sstevel@tonic-gate sz - sizeof(ip_t)); 12647c478bd9Sstevel@tonic-gate } 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate /* 12677c478bd9Sstevel@tonic-gate * Need to exit out of these so we don't recursively call rw_enter 12687c478bd9Sstevel@tonic-gate * from fr_qout. 12697c478bd9Sstevel@tonic-gate */ 1270ab25eeb5Syz return fr_send_ip(fin, m, &m); 12717c478bd9Sstevel@tonic-gate } 12727c478bd9Sstevel@tonic-gate 12737c478bd9Sstevel@tonic-gate #include <sys/time.h> 12747c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate #ifndef _KERNEL 12777c478bd9Sstevel@tonic-gate #include <stdio.h> 12787c478bd9Sstevel@tonic-gate #endif 12797c478bd9Sstevel@tonic-gate 12807c478bd9Sstevel@tonic-gate #define NULLADDR_RATE_LIMIT 10 /* 10 seconds */ 12817c478bd9Sstevel@tonic-gate 12827c478bd9Sstevel@tonic-gate 12837c478bd9Sstevel@tonic-gate /* 12847c478bd9Sstevel@tonic-gate * Print out warning message at rate-limited speed. 12857c478bd9Sstevel@tonic-gate */ 1286f4b3ec61Sdh static void rate_limit_message(ipf_stack_t *ifs, 1287f4b3ec61Sdh int rate, const char *message, ...) 12887c478bd9Sstevel@tonic-gate { 12897c478bd9Sstevel@tonic-gate static time_t last_time = 0; 12907c478bd9Sstevel@tonic-gate time_t now; 12917c478bd9Sstevel@tonic-gate va_list args; 12927c478bd9Sstevel@tonic-gate char msg_buf[256]; 12937c478bd9Sstevel@tonic-gate int need_printed = 0; 12947c478bd9Sstevel@tonic-gate 12957c478bd9Sstevel@tonic-gate now = ddi_get_time(); 12967c478bd9Sstevel@tonic-gate 12977c478bd9Sstevel@tonic-gate /* make sure, no multiple entries */ 1298f4b3ec61Sdh ASSERT(MUTEX_NOT_HELD(&(ifs->ifs_ipf_rw.ipf_lk))); 1299f4b3ec61Sdh MUTEX_ENTER(&ifs->ifs_ipf_rw); 13007c478bd9Sstevel@tonic-gate if (now - last_time >= rate) { 13017c478bd9Sstevel@tonic-gate need_printed = 1; 13027c478bd9Sstevel@tonic-gate last_time = now; 13037c478bd9Sstevel@tonic-gate } 1304f4b3ec61Sdh MUTEX_EXIT(&ifs->ifs_ipf_rw); 13057c478bd9Sstevel@tonic-gate 13067c478bd9Sstevel@tonic-gate if (need_printed) { 13077c478bd9Sstevel@tonic-gate va_start(args, message); 13087c478bd9Sstevel@tonic-gate (void)vsnprintf(msg_buf, 255, message, args); 13097c478bd9Sstevel@tonic-gate va_end(args); 13107c478bd9Sstevel@tonic-gate #ifdef _KERNEL 13117c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, msg_buf); 13127c478bd9Sstevel@tonic-gate #else 13137c478bd9Sstevel@tonic-gate fprintf(std_err, msg_buf); 13147c478bd9Sstevel@tonic-gate #endif 13157c478bd9Sstevel@tonic-gate } 13167c478bd9Sstevel@tonic-gate } 13177c478bd9Sstevel@tonic-gate 13187c478bd9Sstevel@tonic-gate /* 13197c478bd9Sstevel@tonic-gate * return the first IP Address associated with an interface 13207c478bd9Sstevel@tonic-gate */ 13217c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1322f4b3ec61Sdh int fr_ifpaddr(v, atype, ifptr, inp, inpmask, ifs) 13237c478bd9Sstevel@tonic-gate int v, atype; 1324381a2a9aSdr void *ifptr; 1325381a2a9aSdr struct in_addr *inp, *inpmask; 1326f4b3ec61Sdh ipf_stack_t *ifs; 13277c478bd9Sstevel@tonic-gate { 1328381a2a9aSdr struct sockaddr_in6 v6addr[2]; 1329381a2a9aSdr struct sockaddr_in v4addr[2]; 1330381a2a9aSdr net_ifaddr_t type[2]; 13317ddc9b1aSDarren Reed net_handle_t net_data; 1332381a2a9aSdr phy_if_t phyif; 1333381a2a9aSdr void *array; 1334381a2a9aSdr 1335381a2a9aSdr switch (v) 1336381a2a9aSdr { 1337381a2a9aSdr case 4: 1338f4b3ec61Sdh net_data = ifs->ifs_ipf_ipv4; 1339381a2a9aSdr array = v4addr; 1340381a2a9aSdr break; 1341381a2a9aSdr case 6: 1342f4b3ec61Sdh net_data = ifs->ifs_ipf_ipv6; 1343381a2a9aSdr array = v6addr; 1344381a2a9aSdr break; 1345381a2a9aSdr default: 1346381a2a9aSdr net_data = NULL; 1347381a2a9aSdr break; 1348381a2a9aSdr } 13497c478bd9Sstevel@tonic-gate 1350381a2a9aSdr if (net_data == NULL) 13517c478bd9Sstevel@tonic-gate return -1; 13527c478bd9Sstevel@tonic-gate 1353381a2a9aSdr phyif = (phy_if_t)ifptr; 1354ab25eeb5Syz 1355ab25eeb5Syz switch (atype) 1356ab25eeb5Syz { 1357ab25eeb5Syz case FRI_PEERADDR : 1358381a2a9aSdr type[0] = NA_PEER; 1359ab25eeb5Syz break; 1360381a2a9aSdr 1361381a2a9aSdr case FRI_BROADCAST : 1362381a2a9aSdr type[0] = NA_BROADCAST; 1363381a2a9aSdr break; 1364381a2a9aSdr 1365ab25eeb5Syz default : 1366381a2a9aSdr type[0] = NA_ADDRESS; 1367ab25eeb5Syz break; 1368ab25eeb5Syz } 13697c478bd9Sstevel@tonic-gate 1370381a2a9aSdr type[1] = NA_NETMASK; 1371381a2a9aSdr 1372381a2a9aSdr if (net_getlifaddr(net_data, phyif, 0, 2, type, array) < 0) 13737c478bd9Sstevel@tonic-gate return -1; 1374381a2a9aSdr 1375381a2a9aSdr if (v == 6) { 1376381a2a9aSdr return fr_ifpfillv6addr(atype, &v6addr[0], &v6addr[1], 1377381a2a9aSdr inp, inpmask); 13787c478bd9Sstevel@tonic-gate } 1379381a2a9aSdr return fr_ifpfillv4addr(atype, &v4addr[0], &v4addr[1], inp, inpmask); 13807c478bd9Sstevel@tonic-gate } 13817c478bd9Sstevel@tonic-gate 13827c478bd9Sstevel@tonic-gate 13837c478bd9Sstevel@tonic-gate u_32_t fr_newisn(fin) 13847c478bd9Sstevel@tonic-gate fr_info_t *fin; 13857c478bd9Sstevel@tonic-gate { 13867c478bd9Sstevel@tonic-gate static int iss_seq_off = 0; 13877c478bd9Sstevel@tonic-gate u_char hash[16]; 13887c478bd9Sstevel@tonic-gate u_32_t newiss; 13897c478bd9Sstevel@tonic-gate MD5_CTX ctx; 1390f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate /* 13937c478bd9Sstevel@tonic-gate * Compute the base value of the ISS. It is a hash 13947c478bd9Sstevel@tonic-gate * of (saddr, sport, daddr, dport, secret). 13957c478bd9Sstevel@tonic-gate */ 13967c478bd9Sstevel@tonic-gate MD5Init(&ctx); 13977c478bd9Sstevel@tonic-gate 13987c478bd9Sstevel@tonic-gate MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 13997c478bd9Sstevel@tonic-gate sizeof(fin->fin_fi.fi_src)); 14007c478bd9Sstevel@tonic-gate MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 14017c478bd9Sstevel@tonic-gate sizeof(fin->fin_fi.fi_dst)); 14027c478bd9Sstevel@tonic-gate MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 14037c478bd9Sstevel@tonic-gate 1404f4b3ec61Sdh MD5Update(&ctx, ifs->ifs_ipf_iss_secret, sizeof(ifs->ifs_ipf_iss_secret)); 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate MD5Final(hash, &ctx); 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate bcopy(hash, &newiss, sizeof(newiss)); 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate /* 14117c478bd9Sstevel@tonic-gate * Now increment our "timer", and add it in to 14127c478bd9Sstevel@tonic-gate * the computed value. 14137c478bd9Sstevel@tonic-gate * 14147c478bd9Sstevel@tonic-gate * XXX Use `addin'? 14157c478bd9Sstevel@tonic-gate * XXX TCP_ISSINCR too large to use? 14167c478bd9Sstevel@tonic-gate */ 14177c478bd9Sstevel@tonic-gate iss_seq_off += 0x00010000; 14187c478bd9Sstevel@tonic-gate newiss += iss_seq_off; 14197c478bd9Sstevel@tonic-gate return newiss; 14207c478bd9Sstevel@tonic-gate } 14217c478bd9Sstevel@tonic-gate 14227c478bd9Sstevel@tonic-gate 14237c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 14247c478bd9Sstevel@tonic-gate /* Function: fr_nextipid */ 14257c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 14267c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 14277c478bd9Sstevel@tonic-gate /* */ 14287c478bd9Sstevel@tonic-gate /* Returns the next IPv4 ID to use for this packet. */ 14297c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 1430ab25eeb5Syz u_short fr_nextipid(fin) 14317c478bd9Sstevel@tonic-gate fr_info_t *fin; 14327c478bd9Sstevel@tonic-gate { 14337c478bd9Sstevel@tonic-gate static u_short ipid = 0; 14347c478bd9Sstevel@tonic-gate u_short id; 1435f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 14367c478bd9Sstevel@tonic-gate 1437f4b3ec61Sdh MUTEX_ENTER(&ifs->ifs_ipf_rw); 1438*33f2fefdSDarren Reed if (fin->fin_pktnum != 0) { 1439*33f2fefdSDarren Reed id = fin->fin_pktnum & 0xffff; 1440*33f2fefdSDarren Reed } else { 14417c478bd9Sstevel@tonic-gate id = ipid++; 1442*33f2fefdSDarren Reed } 1443f4b3ec61Sdh MUTEX_EXIT(&ifs->ifs_ipf_rw); 14447c478bd9Sstevel@tonic-gate 14457c478bd9Sstevel@tonic-gate return id; 14467c478bd9Sstevel@tonic-gate } 14477c478bd9Sstevel@tonic-gate 14487c478bd9Sstevel@tonic-gate 14497c478bd9Sstevel@tonic-gate #ifndef IPFILTER_CKSUM 14507c478bd9Sstevel@tonic-gate /* ARGSUSED */ 14517c478bd9Sstevel@tonic-gate #endif 14527c478bd9Sstevel@tonic-gate INLINE void fr_checkv4sum(fin) 14537c478bd9Sstevel@tonic-gate fr_info_t *fin; 14547c478bd9Sstevel@tonic-gate { 14557c478bd9Sstevel@tonic-gate #ifdef IPFILTER_CKSUM 14567c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 14577c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_BAD; 14587c478bd9Sstevel@tonic-gate #endif 14597c478bd9Sstevel@tonic-gate } 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate #ifdef USE_INET6 1463ab25eeb5Syz # ifndef IPFILTER_CKSUM 14647663b816Sml /* ARGSUSED */ 1465ab25eeb5Syz # endif 14667c478bd9Sstevel@tonic-gate INLINE void fr_checkv6sum(fin) 14677c478bd9Sstevel@tonic-gate fr_info_t *fin; 14687c478bd9Sstevel@tonic-gate { 14697c478bd9Sstevel@tonic-gate # ifdef IPFILTER_CKSUM 14707c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 14717c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_BAD; 14727c478bd9Sstevel@tonic-gate # endif 14737c478bd9Sstevel@tonic-gate } 14747c478bd9Sstevel@tonic-gate #endif /* USE_INET6 */ 1475ab25eeb5Syz 1476ab25eeb5Syz 1477ab25eeb5Syz #if (SOLARIS2 < 7) 1478ab25eeb5Syz void fr_slowtimer() 1479ab25eeb5Syz #else 1480ab25eeb5Syz /*ARGSUSED*/ 1481f4b3ec61Sdh void fr_slowtimer __P((void *arg)) 1482ab25eeb5Syz #endif 1483ab25eeb5Syz { 1484f4b3ec61Sdh ipf_stack_t *ifs = arg; 1485ab25eeb5Syz 148644aaa2b6Sjojemann READ_ENTER(&ifs->ifs_ipf_global); 148744aaa2b6Sjojemann if (ifs->ifs_fr_running != 1) { 148844aaa2b6Sjojemann ifs->ifs_fr_timer_id = NULL; 1489f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 1490ab25eeb5Syz return; 1491ab25eeb5Syz } 1492fd636508Szf ipf_expiretokens(ifs); 1493f4b3ec61Sdh fr_fragexpire(ifs); 1494f4b3ec61Sdh fr_timeoutstate(ifs); 1495f4b3ec61Sdh fr_natexpire(ifs); 1496f4b3ec61Sdh fr_authexpire(ifs); 1497f4b3ec61Sdh ifs->ifs_fr_ticks++; 149844aaa2b6Sjojemann if (ifs->ifs_fr_running == 1) 1499f4b3ec61Sdh ifs->ifs_fr_timer_id = timeout(fr_slowtimer, arg, 1500f4b3ec61Sdh drv_usectohz(500000)); 1501ab25eeb5Syz else 1502f4b3ec61Sdh ifs->ifs_fr_timer_id = NULL; 1503f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 1504ab25eeb5Syz } 1505ab25eeb5Syz 1506ab25eeb5Syz 1507381a2a9aSdr /* ------------------------------------------------------------------------ */ 1508381a2a9aSdr /* Function: fr_pullup */ 1509381a2a9aSdr /* Returns: NULL == pullup failed, else pointer to protocol header */ 1510381a2a9aSdr /* Parameters: m(I) - pointer to buffer where data packet starts */ 1511381a2a9aSdr /* fin(I) - pointer to packet information */ 1512381a2a9aSdr /* len(I) - number of bytes to pullup */ 1513381a2a9aSdr /* */ 1514381a2a9aSdr /* Attempt to move at least len bytes (from the start of the buffer) into a */ 1515381a2a9aSdr /* single buffer for ease of access. Operating system native functions are */ 1516381a2a9aSdr /* used to manage buffers - if necessary. If the entire packet ends up in */ 1517381a2a9aSdr /* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */ 1518381a2a9aSdr /* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ 1519381a2a9aSdr /* and ONLY if the pullup succeeds. */ 1520381a2a9aSdr /* */ 1521381a2a9aSdr /* We assume that 'min' is a pointer to a buffer that is part of the chain */ 1522381a2a9aSdr /* of buffers that starts at *fin->fin_mp. */ 1523381a2a9aSdr /* ------------------------------------------------------------------------ */ 1524381a2a9aSdr void *fr_pullup(min, fin, len) 1525381a2a9aSdr mb_t *min; 1526381a2a9aSdr fr_info_t *fin; 1527381a2a9aSdr int len; 1528381a2a9aSdr { 1529381a2a9aSdr qpktinfo_t *qpi = fin->fin_qpi; 1530381a2a9aSdr int out = fin->fin_out, dpoff, ipoff; 1531381a2a9aSdr mb_t *m = min, *m1, *m2; 1532381a2a9aSdr char *ip; 153308ee25aeSdr uint32_t start, stuff, end, value, flags; 1534f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1535381a2a9aSdr 1536381a2a9aSdr if (m == NULL) 1537381a2a9aSdr return NULL; 1538381a2a9aSdr 1539381a2a9aSdr ip = (char *)fin->fin_ip; 1540381a2a9aSdr if ((fin->fin_flx & FI_COALESCE) != 0) 1541381a2a9aSdr return ip; 1542381a2a9aSdr 1543381a2a9aSdr ipoff = fin->fin_ipoff; 1544381a2a9aSdr if (fin->fin_dp != NULL) 1545381a2a9aSdr dpoff = (char *)fin->fin_dp - (char *)ip; 1546381a2a9aSdr else 1547381a2a9aSdr dpoff = 0; 1548381a2a9aSdr 154940cdc2e8SAlexandr Nedvedicky if (M_LEN(m) < len + ipoff) { 1550381a2a9aSdr 1551381a2a9aSdr /* 1552381a2a9aSdr * pfil_precheck ensures the IP header is on a 32bit 1553381a2a9aSdr * aligned address so simply fail if that isn't currently 1554381a2a9aSdr * the case (should never happen). 1555381a2a9aSdr */ 1556381a2a9aSdr int inc = 0; 1557381a2a9aSdr 1558381a2a9aSdr if (ipoff > 0) { 1559381a2a9aSdr if ((ipoff & 3) != 0) { 1560381a2a9aSdr inc = 4 - (ipoff & 3); 1561381a2a9aSdr if (m->b_rptr - inc >= m->b_datap->db_base) 1562381a2a9aSdr m->b_rptr -= inc; 1563381a2a9aSdr else 1564381a2a9aSdr inc = 0; 1565381a2a9aSdr } 1566381a2a9aSdr } 1567381a2a9aSdr 1568381a2a9aSdr /* 1569381a2a9aSdr * XXX This is here as a work around for a bug with DEBUG 1570381a2a9aSdr * XXX Solaris kernels. The problem is b_prev is used by IP 1571381a2a9aSdr * XXX code as a way to stash the phyint_index for a packet, 1572381a2a9aSdr * XXX this doesn't get reset by IP but freeb does an ASSERT() 1573381a2a9aSdr * XXX for both of these to be NULL. See 6442390. 1574381a2a9aSdr */ 1575381a2a9aSdr m1 = m; 1576381a2a9aSdr m2 = m->b_prev; 1577381a2a9aSdr 1578381a2a9aSdr do { 1579381a2a9aSdr m1->b_next = NULL; 1580381a2a9aSdr m1->b_prev = NULL; 1581381a2a9aSdr m1 = m1->b_cont; 1582381a2a9aSdr } while (m1); 158308ee25aeSdr 158408ee25aeSdr /* 158508ee25aeSdr * Need to preserve checksum information by copying them 158608ee25aeSdr * to newmp which heads the pulluped message. 158708ee25aeSdr */ 158808ee25aeSdr hcksum_retrieve(m, NULL, NULL, &start, &stuff, &end, 158908ee25aeSdr &value, &flags); 159008ee25aeSdr 1591381a2a9aSdr if (pullupmsg(m, len + ipoff + inc) == 0) { 1592f4b3ec61Sdh ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[1]); 1593381a2a9aSdr FREE_MB_T(*fin->fin_mp); 1594381a2a9aSdr *fin->fin_mp = NULL; 1595381a2a9aSdr fin->fin_m = NULL; 1596381a2a9aSdr fin->fin_ip = NULL; 1597381a2a9aSdr fin->fin_dp = NULL; 1598381a2a9aSdr qpi->qpi_data = NULL; 1599381a2a9aSdr return NULL; 1600381a2a9aSdr } 160108ee25aeSdr 160208ee25aeSdr (void) hcksum_assoc(m, NULL, NULL, start, stuff, end, 160308ee25aeSdr value, flags, 0); 160408ee25aeSdr 1605381a2a9aSdr m->b_prev = m2; 1606381a2a9aSdr m->b_rptr += inc; 1607381a2a9aSdr fin->fin_m = m; 1608381a2a9aSdr ip = MTOD(m, char *) + ipoff; 1609381a2a9aSdr qpi->qpi_data = ip; 1610381a2a9aSdr } 1611381a2a9aSdr 1612f4b3ec61Sdh ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[0]); 1613381a2a9aSdr fin->fin_ip = (ip_t *)ip; 1614381a2a9aSdr if (fin->fin_dp != NULL) 1615381a2a9aSdr fin->fin_dp = (char *)fin->fin_ip + dpoff; 1616381a2a9aSdr 1617381a2a9aSdr if (len == fin->fin_plen) 1618381a2a9aSdr fin->fin_flx |= FI_COALESCE; 1619381a2a9aSdr return ip; 1620381a2a9aSdr } 1621381a2a9aSdr 1622381a2a9aSdr 1623ab25eeb5Syz /* 1624381a2a9aSdr * Function: fr_verifysrc 1625381a2a9aSdr * Returns: int (really boolean) 1626381a2a9aSdr * Parameters: fin - packet information 1627381a2a9aSdr * 1628381a2a9aSdr * Check whether the packet has a valid source address for the interface on 1629381a2a9aSdr * which the packet arrived, implementing the "fr_chksrc" feature. 1630381a2a9aSdr * Returns true iff the packet's source address is valid. 1631381a2a9aSdr */ 1632381a2a9aSdr int fr_verifysrc(fin) 1633381a2a9aSdr fr_info_t *fin; 1634381a2a9aSdr { 16357ddc9b1aSDarren Reed net_handle_t net_data_p; 1636381a2a9aSdr phy_if_t phy_ifdata_routeto; 1637381a2a9aSdr struct sockaddr sin; 1638f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1639381a2a9aSdr 1640381a2a9aSdr if (fin->fin_v == 4) { 1641f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv4; 1642381a2a9aSdr } else if (fin->fin_v == 6) { 1643f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv6; 1644381a2a9aSdr } else { 1645381a2a9aSdr return (0); 1646381a2a9aSdr } 1647381a2a9aSdr 1648381a2a9aSdr /* Get the index corresponding to the if name */ 1649381a2a9aSdr sin.sa_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 1650381a2a9aSdr bcopy(&fin->fin_saddr, &sin.sa_data, sizeof (struct in_addr)); 16517ddc9b1aSDarren Reed phy_ifdata_routeto = net_routeto(net_data_p, &sin, NULL); 1652381a2a9aSdr 1653381a2a9aSdr return (((phy_if_t)fin->fin_ifp == phy_ifdata_routeto) ? 1 : 0); 1654381a2a9aSdr } 1655381a2a9aSdr 1656381a2a9aSdr 1657381a2a9aSdr /* 1658381a2a9aSdr * Function: fr_fastroute 1659381a2a9aSdr * Returns: 0: success; 1660381a2a9aSdr * -1: failed 1661ab25eeb5Syz * Parameters: 1662381a2a9aSdr * mb: the message block where ip head starts 1663381a2a9aSdr * mpp: the pointer to the pointer of the orignal 1664381a2a9aSdr * packet message 1665381a2a9aSdr * fin: packet information 1666381a2a9aSdr * fdp: destination interface information 1667381a2a9aSdr * if it is NULL, no interface information provided. 1668ab25eeb5Syz * 1669ab25eeb5Syz * This function is for fastroute/to/dup-to rules. It calls 1670ab25eeb5Syz * pfil_make_lay2_packet to search route, make lay-2 header 1671ab25eeb5Syz * ,and identify output queue for the IP packet. 1672ab25eeb5Syz * The destination address depends on the following conditions: 1673ab25eeb5Syz * 1: for fastroute rule, fdp is passed in as NULL, so the 1674381a2a9aSdr * destination address is the IP Packet's destination address 1675ab25eeb5Syz * 2: for to/dup-to rule, if an ip address is specified after 1676381a2a9aSdr * the interface name, this address is the as destination 1677381a2a9aSdr * address. Otherwise IP Packet's destination address is used 1678ab25eeb5Syz */ 1679ab25eeb5Syz int fr_fastroute(mb, mpp, fin, fdp) 1680ab25eeb5Syz mblk_t *mb, **mpp; 1681ab25eeb5Syz fr_info_t *fin; 1682ab25eeb5Syz frdest_t *fdp; 1683ab25eeb5Syz { 16847ddc9b1aSDarren Reed net_handle_t net_data_p; 16857ddc9b1aSDarren Reed net_inject_t *inj; 1686ab25eeb5Syz mblk_t *mp = NULL; 1687381a2a9aSdr frentry_t *fr = fin->fin_fr; 1688ab25eeb5Syz qpktinfo_t *qpi; 1689ab25eeb5Syz ip_t *ip; 1690381a2a9aSdr 1691381a2a9aSdr struct sockaddr_in *sin; 1692381a2a9aSdr struct sockaddr_in6 *sin6; 1693381a2a9aSdr struct sockaddr *sinp; 1694f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1695ab25eeb5Syz #ifndef sparc 1696ab25eeb5Syz u_short __iplen, __ipoff; 1697ab25eeb5Syz #endif 1698381a2a9aSdr 1699381a2a9aSdr if (fin->fin_v == 4) { 1700f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv4; 1701381a2a9aSdr } else if (fin->fin_v == 6) { 1702f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv6; 1703381a2a9aSdr } else { 1704381a2a9aSdr return (-1); 1705381a2a9aSdr } 1706381a2a9aSdr 17077ddc9b1aSDarren Reed inj = net_inject_alloc(NETINFO_VERSION); 17087ddc9b1aSDarren Reed if (inj == NULL) 17097ddc9b1aSDarren Reed return -1; 17107ddc9b1aSDarren Reed 1711ab25eeb5Syz ip = fin->fin_ip; 1712ab25eeb5Syz qpi = fin->fin_qpi; 1713ab25eeb5Syz 1714ab25eeb5Syz /* 1715ab25eeb5Syz * If this is a duplicate mblk then we want ip to point at that 1716ab25eeb5Syz * data, not the original, if and only if it is already pointing at 1717ab25eeb5Syz * the current mblk data. 1718381a2a9aSdr * 1719381a2a9aSdr * Otherwise, if it's not a duplicate, and we're not already pointing 1720e6c6c1faSyz * at the current mblk data, then we want to ensure that the data 1721e6c6c1faSyz * points at ip. 1722ab25eeb5Syz */ 1723381a2a9aSdr 1724381a2a9aSdr if ((ip == (ip_t *)qpi->qpi_m->b_rptr) && (qpi->qpi_m != mb)) { 1725ab25eeb5Syz ip = (ip_t *)mb->b_rptr; 1726381a2a9aSdr } else if ((qpi->qpi_m == mb) && (ip != (ip_t *)qpi->qpi_m->b_rptr)) { 1727381a2a9aSdr qpi->qpi_m->b_rptr = (uchar_t *)ip; 1728e6c6c1faSyz qpi->qpi_off = 0; 1729e6c6c1faSyz } 1730ab25eeb5Syz 1731ab25eeb5Syz /* 1732ab25eeb5Syz * If there is another M_PROTO, we don't want it 1733ab25eeb5Syz */ 1734ab25eeb5Syz if (*mpp != mb) { 1735ab25eeb5Syz mp = unlinkb(*mpp); 1736ab25eeb5Syz freeb(*mpp); 1737ab25eeb5Syz *mpp = mp; 1738ab25eeb5Syz } 1739ab25eeb5Syz 17407ddc9b1aSDarren Reed sinp = (struct sockaddr *)&inj->ni_addr; 1741381a2a9aSdr sin = (struct sockaddr_in *)sinp; 1742381a2a9aSdr sin6 = (struct sockaddr_in6 *)sinp; 17437ddc9b1aSDarren Reed bzero((char *)&inj->ni_addr, sizeof (inj->ni_addr)); 17447ddc9b1aSDarren Reed inj->ni_addr.ss_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 17457ddc9b1aSDarren Reed inj->ni_packet = mb; 1746ab25eeb5Syz 1747ab25eeb5Syz /* 1748ab25eeb5Syz * In case we're here due to "to <if>" being used with 1749ab25eeb5Syz * "keep state", check that we're going in the correct 1750ab25eeb5Syz * direction. 1751ab25eeb5Syz */ 1752381a2a9aSdr if (fdp != NULL) { 1753381a2a9aSdr if ((fr != NULL) && (fdp->fd_ifp != NULL) && 1754381a2a9aSdr (fin->fin_rev != 0) && (fdp == &fr->fr_tif)) 1755381a2a9aSdr goto bad_fastroute; 17567ddc9b1aSDarren Reed inj->ni_physical = (phy_if_t)fdp->fd_ifp; 1757ab25eeb5Syz if (fin->fin_v == 4) { 1758381a2a9aSdr sin->sin_addr = fdp->fd_ip; 1759381a2a9aSdr } else { 1760381a2a9aSdr sin6->sin6_addr = fdp->fd_ip6.in6; 1761ab25eeb5Syz } 1762381a2a9aSdr } else { 1763381a2a9aSdr if (fin->fin_v == 4) { 1764381a2a9aSdr sin->sin_addr = ip->ip_dst; 1765381a2a9aSdr } else { 1766381a2a9aSdr sin6->sin6_addr = ((ip6_t *)ip)->ip6_dst; 1767ab25eeb5Syz } 17687ddc9b1aSDarren Reed inj->ni_physical = net_routeto(net_data_p, sinp, NULL); 1769ab25eeb5Syz } 1770ab25eeb5Syz 1771edd26dc5Sdr /* 1772edd26dc5Sdr * Clear the hardware checksum flags from packets that we are doing 1773edd26dc5Sdr * input processing on as leaving them set will cause the outgoing 1774edd26dc5Sdr * NIC (if it supports hardware checksum) to calculate them anew, 1775edd26dc5Sdr * using the old (correct) checksums as the pseudo value to start 1776edd26dc5Sdr * from. 1777edd26dc5Sdr */ 1778edd26dc5Sdr if (fin->fin_out == 0) { 1779edd26dc5Sdr DB_CKSUMFLAGS(mb) = 0; 1780edd26dc5Sdr } 1781c793af95Ssangeeta 1782381a2a9aSdr *mpp = mb; 1783ab25eeb5Syz 1784381a2a9aSdr if (fin->fin_out == 0) { 1785381a2a9aSdr void *saveifp; 1786381a2a9aSdr u_32_t pass; 1787ab25eeb5Syz 1788381a2a9aSdr saveifp = fin->fin_ifp; 17897ddc9b1aSDarren Reed fin->fin_ifp = (void *)inj->ni_physical; 1790d3675867Sjojemann fin->fin_flx &= ~FI_STATE; 1791381a2a9aSdr fin->fin_out = 1; 1792381a2a9aSdr (void) fr_acctpkt(fin, &pass); 1793381a2a9aSdr fin->fin_fr = NULL; 1794381a2a9aSdr if (!fr || !(fr->fr_flags & FR_RETMASK)) 1795381a2a9aSdr (void) fr_checkstate(fin, &pass); 1796d3675867Sjojemann if (fr_checknatout(fin, NULL) == -1) 1797381a2a9aSdr goto bad_fastroute; 1798381a2a9aSdr fin->fin_out = 0; 1799381a2a9aSdr fin->fin_ifp = saveifp; 1800381a2a9aSdr } 1801381a2a9aSdr #ifndef sparc 1802381a2a9aSdr if (fin->fin_v == 4) { 1803381a2a9aSdr __iplen = (u_short)ip->ip_len, 1804381a2a9aSdr __ipoff = (u_short)ip->ip_off; 1805ab25eeb5Syz 1806381a2a9aSdr ip->ip_len = htons(__iplen); 1807381a2a9aSdr ip->ip_off = htons(__ipoff); 1808381a2a9aSdr } 1809ab25eeb5Syz #endif 1810381a2a9aSdr 1811381a2a9aSdr if (net_data_p) { 18127ddc9b1aSDarren Reed if (net_inject(net_data_p, NI_DIRECT_OUT, inj) < 0) { 18137ddc9b1aSDarren Reed net_inject_free(inj); 1814381a2a9aSdr return (-1); 1815ab25eeb5Syz } 1816ab25eeb5Syz } 1817381a2a9aSdr 1818f4b3ec61Sdh ifs->ifs_fr_frouteok[0]++; 18197ddc9b1aSDarren Reed net_inject_free(inj); 1820381a2a9aSdr return 0; 1821ab25eeb5Syz bad_fastroute: 18227ddc9b1aSDarren Reed net_inject_free(inj); 1823ab25eeb5Syz freemsg(mb); 1824f4b3ec61Sdh ifs->ifs_fr_frouteok[1]++; 1825ab25eeb5Syz return -1; 1826ab25eeb5Syz } 1827ab25eeb5Syz 1828ab25eeb5Syz 1829ab25eeb5Syz /* ------------------------------------------------------------------------ */ 18307ddc9b1aSDarren Reed /* Function: ipf_hook4_out */ 1831381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1832381a2a9aSdr /* Parameters: event(I) - pointer to event */ 1833381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 1834ab25eeb5Syz /* */ 1835381a2a9aSdr /* Calling ipf_hook. */ 1836381a2a9aSdr /* ------------------------------------------------------------------------ */ 1837381a2a9aSdr /*ARGSUSED*/ 18387ddc9b1aSDarren Reed int ipf_hook4_out(hook_event_token_t token, hook_data_t info, void *arg) 1839381a2a9aSdr { 18407ddc9b1aSDarren Reed return ipf_hook(info, 1, 0, arg); 1841cbded9aeSdr } 1842cbded9aeSdr /*ARGSUSED*/ 18437ddc9b1aSDarren Reed int ipf_hook6_out(hook_event_token_t token, hook_data_t info, void *arg) 1844cbded9aeSdr { 18457ddc9b1aSDarren Reed return ipf_hook6(info, 1, 0, arg); 1846381a2a9aSdr } 1847381a2a9aSdr 1848381a2a9aSdr /* ------------------------------------------------------------------------ */ 18497ddc9b1aSDarren Reed /* Function: ipf_hook4_in */ 1850381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1851381a2a9aSdr /* Parameters: event(I) - pointer to event */ 1852381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 1853ab25eeb5Syz /* */ 1854381a2a9aSdr /* Calling ipf_hook. */ 1855ab25eeb5Syz /* ------------------------------------------------------------------------ */ 1856381a2a9aSdr /*ARGSUSED*/ 18577ddc9b1aSDarren Reed int ipf_hook4_in(hook_event_token_t token, hook_data_t info, void *arg) 1858ab25eeb5Syz { 18597ddc9b1aSDarren Reed return ipf_hook(info, 0, 0, arg); 1860cbded9aeSdr } 1861cbded9aeSdr /*ARGSUSED*/ 18627ddc9b1aSDarren Reed int ipf_hook6_in(hook_event_token_t token, hook_data_t info, void *arg) 1863cbded9aeSdr { 18647ddc9b1aSDarren Reed return ipf_hook6(info, 0, 0, arg); 1865381a2a9aSdr } 1866ab25eeb5Syz 1867ab25eeb5Syz 1868381a2a9aSdr /* ------------------------------------------------------------------------ */ 18697ddc9b1aSDarren Reed /* Function: ipf_hook4_loop_out */ 1870381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1871381a2a9aSdr /* Parameters: event(I) - pointer to event */ 1872381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 1873381a2a9aSdr /* */ 1874381a2a9aSdr /* Calling ipf_hook. */ 1875381a2a9aSdr /* ------------------------------------------------------------------------ */ 1876381a2a9aSdr /*ARGSUSED*/ 18777ddc9b1aSDarren Reed int ipf_hook4_loop_out(hook_event_token_t token, hook_data_t info, void *arg) 1878cbded9aeSdr { 18797ddc9b1aSDarren Reed return ipf_hook(info, 1, FI_NOCKSUM, arg); 1880cbded9aeSdr } 1881cbded9aeSdr /*ARGSUSED*/ 18827ddc9b1aSDarren Reed int ipf_hook6_loop_out(hook_event_token_t token, hook_data_t info, void *arg) 1883381a2a9aSdr { 18847ddc9b1aSDarren Reed return ipf_hook6(info, 1, FI_NOCKSUM, arg); 1885381a2a9aSdr } 1886ab25eeb5Syz 1887381a2a9aSdr /* ------------------------------------------------------------------------ */ 188840cdc2e8SAlexandr Nedvedicky /* Function: ipf_hook4_loop_in */ 1889381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1890381a2a9aSdr /* Parameters: event(I) - pointer to event */ 1891381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 1892381a2a9aSdr /* */ 1893381a2a9aSdr /* Calling ipf_hook. */ 1894381a2a9aSdr /* ------------------------------------------------------------------------ */ 1895381a2a9aSdr /*ARGSUSED*/ 189640cdc2e8SAlexandr Nedvedicky int ipf_hook4_loop_in(hook_event_token_t token, hook_data_t info, void *arg) 1897cbded9aeSdr { 18987ddc9b1aSDarren Reed return ipf_hook(info, 0, FI_NOCKSUM, arg); 1899cbded9aeSdr } 1900cbded9aeSdr /*ARGSUSED*/ 19017ddc9b1aSDarren Reed int ipf_hook6_loop_in(hook_event_token_t token, hook_data_t info, void *arg) 1902381a2a9aSdr { 19037ddc9b1aSDarren Reed return ipf_hook6(info, 0, FI_NOCKSUM, arg); 1904381a2a9aSdr } 1905381a2a9aSdr 1906381a2a9aSdr /* ------------------------------------------------------------------------ */ 1907381a2a9aSdr /* Function: ipf_hook */ 1908381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1909381a2a9aSdr /* Parameters: info(I) - pointer to hook information for firewalling */ 1910381a2a9aSdr /* out(I) - whether packet is going in or out */ 1911381a2a9aSdr /* loopback(I) - whether packet is a loopback packet or not */ 1912381a2a9aSdr /* */ 1913381a2a9aSdr /* Stepping stone function between the IP mainline and IPFilter. Extracts */ 1914381a2a9aSdr /* parameters out of the info structure and forms them up to be useful for */ 1915381a2a9aSdr /* calling ipfilter. */ 1916381a2a9aSdr /* ------------------------------------------------------------------------ */ 19177ddc9b1aSDarren Reed int ipf_hook(hook_data_t info, int out, int loopback, void *arg) 1918381a2a9aSdr { 1919381a2a9aSdr hook_pkt_event_t *fw; 19207ddc9b1aSDarren Reed ipf_stack_t *ifs; 1921381a2a9aSdr qpktinfo_t qpi; 19227ddc9b1aSDarren Reed int rval, hlen; 1923381a2a9aSdr u_short swap; 1924381a2a9aSdr phy_if_t phy; 1925381a2a9aSdr ip_t *ip; 1926381a2a9aSdr 19277ddc9b1aSDarren Reed ifs = arg; 1928381a2a9aSdr fw = (hook_pkt_event_t *)info; 1929381a2a9aSdr 1930381a2a9aSdr ASSERT(fw != NULL); 1931381a2a9aSdr phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp; 1932381a2a9aSdr 1933381a2a9aSdr ip = fw->hpe_hdr; 1934cbded9aeSdr swap = ntohs(ip->ip_len); 1935cbded9aeSdr ip->ip_len = swap; 1936cbded9aeSdr swap = ntohs(ip->ip_off); 1937cbded9aeSdr ip->ip_off = swap; 1938cbded9aeSdr hlen = IPH_HDR_LENGTH(ip); 1939381a2a9aSdr 1940381a2a9aSdr qpi.qpi_m = fw->hpe_mb; 1941381a2a9aSdr qpi.qpi_data = fw->hpe_hdr; 1942381a2a9aSdr qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr; 1943381a2a9aSdr qpi.qpi_ill = (void *)phy; 1944cbded9aeSdr qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST); 1945cbded9aeSdr if (qpi.qpi_flags) 1946cbded9aeSdr qpi.qpi_flags |= FI_MBCAST; 1947cbded9aeSdr qpi.qpi_flags |= loopback; 1948381a2a9aSdr 1949f4b3ec61Sdh rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, 19507ddc9b1aSDarren Reed &qpi, fw->hpe_mp, ifs); 1951381a2a9aSdr 1952381a2a9aSdr /* For fastroute cases, fr_check returns 0 with mp set to NULL */ 1953381a2a9aSdr if (rval == 0 && *(fw->hpe_mp) == NULL) 1954381a2a9aSdr rval = 1; 1955381a2a9aSdr 1956cbded9aeSdr /* Notify IP the packet mblk_t and IP header pointers. */ 1957381a2a9aSdr fw->hpe_mb = qpi.qpi_m; 1958381a2a9aSdr fw->hpe_hdr = qpi.qpi_data; 1959cbded9aeSdr if (rval == 0) { 1960381a2a9aSdr ip = qpi.qpi_data; 1961381a2a9aSdr swap = ntohs(ip->ip_len); 1962381a2a9aSdr ip->ip_len = swap; 1963381a2a9aSdr swap = ntohs(ip->ip_off); 1964381a2a9aSdr ip->ip_off = swap; 1965381a2a9aSdr } 1966381a2a9aSdr return rval; 1967ab25eeb5Syz 1968381a2a9aSdr } 19697ddc9b1aSDarren Reed int ipf_hook6(hook_data_t info, int out, int loopback, void *arg) 1970cbded9aeSdr { 1971cbded9aeSdr hook_pkt_event_t *fw; 1972cbded9aeSdr int rval, hlen; 1973cbded9aeSdr qpktinfo_t qpi; 1974cbded9aeSdr phy_if_t phy; 1975cbded9aeSdr 1976cbded9aeSdr fw = (hook_pkt_event_t *)info; 1977cbded9aeSdr 1978cbded9aeSdr ASSERT(fw != NULL); 1979cbded9aeSdr phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp; 1980cbded9aeSdr 1981cbded9aeSdr hlen = sizeof (ip6_t); 1982cbded9aeSdr 1983cbded9aeSdr qpi.qpi_m = fw->hpe_mb; 1984cbded9aeSdr qpi.qpi_data = fw->hpe_hdr; 1985cbded9aeSdr qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr; 1986cbded9aeSdr qpi.qpi_ill = (void *)phy; 1987cbded9aeSdr qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST); 1988cbded9aeSdr if (qpi.qpi_flags) 1989cbded9aeSdr qpi.qpi_flags |= FI_MBCAST; 1990cbded9aeSdr qpi.qpi_flags |= loopback; 1991cbded9aeSdr 1992cbded9aeSdr rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, 19937ddc9b1aSDarren Reed &qpi, fw->hpe_mp, arg); 1994cbded9aeSdr 1995cbded9aeSdr /* For fastroute cases, fr_check returns 0 with mp set to NULL */ 1996cbded9aeSdr if (rval == 0 && *(fw->hpe_mp) == NULL) 1997cbded9aeSdr rval = 1; 1998cbded9aeSdr 1999cbded9aeSdr /* Notify IP the packet mblk_t and IP header pointers. */ 2000cbded9aeSdr fw->hpe_mb = qpi.qpi_m; 2001cbded9aeSdr fw->hpe_hdr = qpi.qpi_data; 2002cbded9aeSdr return rval; 2003cbded9aeSdr 2004cbded9aeSdr } 2005ab25eeb5Syz 2006ab25eeb5Syz 2007381a2a9aSdr /* ------------------------------------------------------------------------ */ 2008381a2a9aSdr /* Function: ipf_nic_event_v4 */ 2009381a2a9aSdr /* Returns: int - 0 == no problems encountered */ 2010381a2a9aSdr /* Parameters: event(I) - pointer to event */ 2011381a2a9aSdr /* info(I) - pointer to information about a NIC event */ 2012381a2a9aSdr /* */ 2013381a2a9aSdr /* Function to receive asynchronous NIC events from IP */ 2014381a2a9aSdr /* ------------------------------------------------------------------------ */ 2015381a2a9aSdr /*ARGSUSED*/ 20167ddc9b1aSDarren Reed int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info, void *arg) 2017381a2a9aSdr { 2018381a2a9aSdr struct sockaddr_in *sin; 2019381a2a9aSdr hook_nic_event_t *hn; 20207ddc9b1aSDarren Reed ipf_stack_t *ifs = arg; 2021381a2a9aSdr 2022381a2a9aSdr hn = (hook_nic_event_t *)info; 2023381a2a9aSdr 2024381a2a9aSdr switch (hn->hne_event) 2025381a2a9aSdr { 2026381a2a9aSdr case NE_PLUMB : 2027a4cf92b0Sdr frsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, hn->hne_data, 2028d6c23f6fSyx ifs); 2029d6c23f6fSyx fr_natifpsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, 2030f4b3ec61Sdh hn->hne_data, ifs); 2031381a2a9aSdr fr_statesync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, 2032f4b3ec61Sdh hn->hne_data, ifs); 2033381a2a9aSdr break; 2034381a2a9aSdr 2035381a2a9aSdr case NE_UNPLUMB : 2036f4b3ec61Sdh frsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 2037d6c23f6fSyx fr_natifpsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, 2038d6c23f6fSyx ifs); 2039f4b3ec61Sdh fr_statesync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 2040381a2a9aSdr break; 2041381a2a9aSdr 2042381a2a9aSdr case NE_ADDRESS_CHANGE : 2043a4cf92b0Sdr /* 2044a4cf92b0Sdr * We only respond to events for logical interface 0 because 2045a4cf92b0Sdr * IPFilter only uses the first address given to a network 2046a4cf92b0Sdr * interface. We check for hne_lif==1 because the netinfo 2047a4cf92b0Sdr * code maps adds 1 to the lif number so that it can return 2048a4cf92b0Sdr * 0 to indicate "no more lifs" when walking them. 2049a4cf92b0Sdr */ 2050a4cf92b0Sdr if (hn->hne_lif == 1) { 2051a4cf92b0Sdr frsync(IPFSYNC_RESYNC, 4, (void *)hn->hne_nic, NULL, 2052a4cf92b0Sdr ifs); 2053a4cf92b0Sdr sin = hn->hne_data; 2054d6c23f6fSyx fr_nataddrsync(4, (void *)hn->hne_nic, &sin->sin_addr, 2055a4cf92b0Sdr ifs); 2056a4cf92b0Sdr } 2057381a2a9aSdr break; 2058381a2a9aSdr 2059381a2a9aSdr default : 2060381a2a9aSdr break; 2061ab25eeb5Syz } 2062ab25eeb5Syz 2063381a2a9aSdr return 0; 2064381a2a9aSdr } 2065ab25eeb5Syz 2066381a2a9aSdr 2067381a2a9aSdr /* ------------------------------------------------------------------------ */ 2068381a2a9aSdr /* Function: ipf_nic_event_v6 */ 2069381a2a9aSdr /* Returns: int - 0 == no problems encountered */ 2070381a2a9aSdr /* Parameters: event(I) - pointer to event */ 2071381a2a9aSdr /* info(I) - pointer to information about a NIC event */ 2072381a2a9aSdr /* */ 2073381a2a9aSdr /* Function to receive asynchronous NIC events from IP */ 2074381a2a9aSdr /* ------------------------------------------------------------------------ */ 2075381a2a9aSdr /*ARGSUSED*/ 20767ddc9b1aSDarren Reed int ipf_nic_event_v6(hook_event_token_t event, hook_data_t info, void *arg) 2077381a2a9aSdr { 2078d6c23f6fSyx struct sockaddr_in6 *sin6; 2079381a2a9aSdr hook_nic_event_t *hn; 20807ddc9b1aSDarren Reed ipf_stack_t *ifs = arg; 2081381a2a9aSdr 2082381a2a9aSdr hn = (hook_nic_event_t *)info; 2083381a2a9aSdr 2084381a2a9aSdr switch (hn->hne_event) 2085381a2a9aSdr { 2086381a2a9aSdr case NE_PLUMB : 2087d6c23f6fSyx frsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2088d6c23f6fSyx hn->hne_data, ifs); 2089d6c23f6fSyx fr_natifpsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2090d6c23f6fSyx hn->hne_data, ifs); 2091381a2a9aSdr fr_statesync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2092f4b3ec61Sdh hn->hne_data, ifs); 2093381a2a9aSdr break; 2094381a2a9aSdr 2095381a2a9aSdr case NE_UNPLUMB : 2096f4b3ec61Sdh frsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2097d6c23f6fSyx fr_natifpsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, 2098d6c23f6fSyx ifs); 2099f4b3ec61Sdh fr_statesync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2100381a2a9aSdr break; 2101381a2a9aSdr 2102381a2a9aSdr case NE_ADDRESS_CHANGE : 2103d6c23f6fSyx if (hn->hne_lif == 1) { 2104d6c23f6fSyx sin6 = hn->hne_data; 2105d6c23f6fSyx fr_nataddrsync(6, (void *)hn->hne_nic, &sin6->sin6_addr, 2106d6c23f6fSyx ifs); 2107d6c23f6fSyx } 2108381a2a9aSdr break; 2109381a2a9aSdr default : 2110381a2a9aSdr break; 2111381a2a9aSdr } 2112381a2a9aSdr 2113381a2a9aSdr return 0; 2114ab25eeb5Syz } 2115