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 * 61b47e080Sdr * Copyright 2008 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 *)); 68882bd30bSdr static int fr_enableipf __P((ipf_stack_t *, netstack_t *, int)); 69ab25eeb5Syz static int fr_send_ip __P((fr_info_t *fin, mblk_t *m, mblk_t **mp)); 70f4b3ec61Sdh static int ipf_nic_event_v4 __P((hook_event_token_t, hook_data_t, 71f4b3ec61Sdh netstack_t *)); 72f4b3ec61Sdh static int ipf_nic_event_v6 __P((hook_event_token_t, hook_data_t, 73f4b3ec61Sdh netstack_t *)); 74cbded9aeSdr static int ipf_hook4_out __P((hook_event_token_t, hook_data_t, 75f4b3ec61Sdh netstack_t *)); 76cbded9aeSdr static int ipf_hook4_in __P((hook_event_token_t, hook_data_t, 77f4b3ec61Sdh netstack_t *)); 78cbded9aeSdr static int ipf_hook4_loop_out __P((hook_event_token_t, hook_data_t, 79f4b3ec61Sdh netstack_t *)); 80cbded9aeSdr static int ipf_hook4_loop_in __P((hook_event_token_t, hook_data_t, 81f4b3ec61Sdh netstack_t *)); 82cbded9aeSdr static int ipf_hook4 __P((hook_data_t, int, int, netstack_t *)); 83cbded9aeSdr static int ipf_hook6_out __P((hook_event_token_t, hook_data_t, 84cbded9aeSdr netstack_t *)); 85cbded9aeSdr static int ipf_hook6_in __P((hook_event_token_t, hook_data_t, 86cbded9aeSdr netstack_t *)); 87cbded9aeSdr static int ipf_hook6_loop_out __P((hook_event_token_t, hook_data_t, 88cbded9aeSdr netstack_t *)); 89cbded9aeSdr static int ipf_hook6_loop_in __P((hook_event_token_t, hook_data_t, 90cbded9aeSdr netstack_t *)); 91cbded9aeSdr static int ipf_hook6 __P((hook_data_t, int, int, netstack_t *)); 92f4b3ec61Sdh extern int ipf_geniter __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *)); 93f4b3ec61Sdh extern int ipf_frruleiter __P((void *, int, void *, ipf_stack_t *)); 94f4b3ec61Sdh 957c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 967c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 7 97ab25eeb5Syz u_int *ip_ttl_ptr = NULL; 98ab25eeb5Syz u_int *ip_mtudisc = NULL; 997c478bd9Sstevel@tonic-gate # if SOLARIS2 >= 8 100ab25eeb5Syz int *ip_forwarding = NULL; 101ab25eeb5Syz u_int *ip6_forwarding = NULL; 1027c478bd9Sstevel@tonic-gate # else 103ab25eeb5Syz u_int *ip_forwarding = NULL; 1047c478bd9Sstevel@tonic-gate # endif 1057c478bd9Sstevel@tonic-gate #else 106ab25eeb5Syz u_long *ip_ttl_ptr = NULL; 107ab25eeb5Syz u_long *ip_mtudisc = NULL; 108ab25eeb5Syz u_long *ip_forwarding = NULL; 1097c478bd9Sstevel@tonic-gate #endif 1107c478bd9Sstevel@tonic-gate #endif 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 1147c478bd9Sstevel@tonic-gate /* Function: ipldetach */ 1157c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, else error. */ 1167c478bd9Sstevel@tonic-gate /* Parameters: Nil */ 1177c478bd9Sstevel@tonic-gate /* */ 1187c478bd9Sstevel@tonic-gate /* This function is responsible for undoing anything that might have been */ 1197c478bd9Sstevel@tonic-gate /* done in a call to iplattach(). It must be able to clean up from a call */ 1207c478bd9Sstevel@tonic-gate /* to iplattach() that did not succeed. Why might that happen? Someone */ 1217c478bd9Sstevel@tonic-gate /* configures a table to be so large that we cannot allocate enough memory */ 1227c478bd9Sstevel@tonic-gate /* for it. */ 1237c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 124f4b3ec61Sdh int ipldetach(ifs) 125f4b3ec61Sdh ipf_stack_t *ifs; 1267c478bd9Sstevel@tonic-gate { 1277c478bd9Sstevel@tonic-gate 128f4b3ec61Sdh ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0); 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 1317c478bd9Sstevel@tonic-gate 132f4b3ec61Sdh if (ifs->ifs_fr_control_forwarding & 2) { 133ab25eeb5Syz if (ip_forwarding != NULL) 134ab25eeb5Syz *ip_forwarding = 0; 1357c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 136ab25eeb5Syz if (ip6_forwarding != NULL) 137ab25eeb5Syz *ip6_forwarding = 0; 1387c478bd9Sstevel@tonic-gate #endif 1397c478bd9Sstevel@tonic-gate } 1407c478bd9Sstevel@tonic-gate #endif 1417c478bd9Sstevel@tonic-gate 142381a2a9aSdr /* 143381a2a9aSdr * This lock needs to be dropped around the net_unregister_hook calls 144381a2a9aSdr * because we can deadlock here with: 145381a2a9aSdr * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs 146381a2a9aSdr * R(hook_family)->R(hei_lock)->R(ipf_global) (active hook running) 147381a2a9aSdr */ 148f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 149381a2a9aSdr 150381a2a9aSdr /* 151381a2a9aSdr * Remove IPv6 Hooks 152381a2a9aSdr */ 153f4b3ec61Sdh if (ifs->ifs_ipf_ipv6 != NULL) { 154f4b3ec61Sdh if (ifs->ifs_hook6_physical_in) { 155f4b3ec61Sdh ifs->ifs_hook6_physical_in = (net_unregister_hook(ifs->ifs_ipf_ipv6, 156cbded9aeSdr NH_PHYSICAL_IN, &ifs->ifs_ipfhook6_in) != 0); 157381a2a9aSdr } 158f4b3ec61Sdh if (ifs->ifs_hook6_physical_out) { 159f4b3ec61Sdh ifs->ifs_hook6_physical_out = 160f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv6, 161cbded9aeSdr NH_PHYSICAL_OUT, &ifs->ifs_ipfhook6_out) != 0); 162381a2a9aSdr } 163f4b3ec61Sdh if (ifs->ifs_hook6_nic_events) { 164f4b3ec61Sdh ifs->ifs_hook6_nic_events = 165f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv6, 166f4b3ec61Sdh NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) != 0); 167381a2a9aSdr } 168f4b3ec61Sdh if (ifs->ifs_hook6_loopback_in) { 169f4b3ec61Sdh ifs->ifs_hook6_loopback_in = 170f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv6, 171cbded9aeSdr NH_LOOPBACK_IN, &ifs->ifs_ipfhook6_loop_in) != 0); 172381a2a9aSdr } 173f4b3ec61Sdh if (ifs->ifs_hook6_loopback_out) { 174f4b3ec61Sdh ifs->ifs_hook6_loopback_out = 175f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv6, 176cbded9aeSdr NH_LOOPBACK_OUT, &ifs->ifs_ipfhook6_loop_out) != 0); 177381a2a9aSdr } 178381a2a9aSdr 179f4b3ec61Sdh if (net_release(ifs->ifs_ipf_ipv6) != 0) 180381a2a9aSdr goto detach_failed; 181f4b3ec61Sdh ifs->ifs_ipf_ipv6 = NULL; 182381a2a9aSdr } 183381a2a9aSdr 184381a2a9aSdr /* 185381a2a9aSdr * Remove IPv4 Hooks 186381a2a9aSdr */ 187f4b3ec61Sdh if (ifs->ifs_ipf_ipv4 != NULL) { 188f4b3ec61Sdh if (ifs->ifs_hook4_physical_in) { 189f4b3ec61Sdh ifs->ifs_hook4_physical_in = 190f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv4, 191cbded9aeSdr NH_PHYSICAL_IN, &ifs->ifs_ipfhook4_in) != 0); 192381a2a9aSdr } 193f4b3ec61Sdh if (ifs->ifs_hook4_physical_out) { 194f4b3ec61Sdh ifs->ifs_hook4_physical_out = 195f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv4, 196cbded9aeSdr NH_PHYSICAL_OUT, &ifs->ifs_ipfhook4_out) != 0); 197381a2a9aSdr } 198f4b3ec61Sdh if (ifs->ifs_hook4_nic_events) { 199f4b3ec61Sdh ifs->ifs_hook4_nic_events = 200f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv4, 201f4b3ec61Sdh NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) != 0); 202381a2a9aSdr } 203f4b3ec61Sdh if (ifs->ifs_hook4_loopback_in) { 204f4b3ec61Sdh ifs->ifs_hook4_loopback_in = 205f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv4, 206cbded9aeSdr NH_LOOPBACK_IN, &ifs->ifs_ipfhook4_loop_in) != 0); 207381a2a9aSdr } 208f4b3ec61Sdh if (ifs->ifs_hook4_loopback_out) { 209f4b3ec61Sdh ifs->ifs_hook4_loopback_out = 210f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv4, 211cbded9aeSdr NH_LOOPBACK_OUT, &ifs->ifs_ipfhook4_loop_out) != 0); 212381a2a9aSdr } 213381a2a9aSdr 214f4b3ec61Sdh if (net_release(ifs->ifs_ipf_ipv4) != 0) 215381a2a9aSdr goto detach_failed; 216f4b3ec61Sdh ifs->ifs_ipf_ipv4 = NULL; 217381a2a9aSdr } 218381a2a9aSdr 2197c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 2207c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "ipldetach()\n"); 2217c478bd9Sstevel@tonic-gate #endif 2227c478bd9Sstevel@tonic-gate 223f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 224f4b3ec61Sdh fr_deinitialise(ifs); 2257c478bd9Sstevel@tonic-gate 226f4b3ec61Sdh (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE, ifs); 227f4b3ec61Sdh (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE, ifs); 2287c478bd9Sstevel@tonic-gate 229f4b3ec61Sdh if (ifs->ifs_ipf_locks_done == 1) { 230f4b3ec61Sdh MUTEX_DESTROY(&ifs->ifs_ipf_timeoutlock); 231f4b3ec61Sdh MUTEX_DESTROY(&ifs->ifs_ipf_rw); 232f4b3ec61Sdh RW_DESTROY(&ifs->ifs_ipf_tokens); 233f4b3ec61Sdh RW_DESTROY(&ifs->ifs_ipf_ipidfrag); 234f4b3ec61Sdh ifs->ifs_ipf_locks_done = 0; 2357c478bd9Sstevel@tonic-gate } 236381a2a9aSdr 237f4b3ec61Sdh if (ifs->ifs_hook4_physical_in || ifs->ifs_hook4_physical_out || ifs->ifs_hook4_nic_events || 238f4b3ec61Sdh ifs->ifs_hook4_loopback_in || ifs->ifs_hook4_loopback_out || ifs->ifs_hook6_nic_events || 239f4b3ec61Sdh ifs->ifs_hook6_physical_in || ifs->ifs_hook6_physical_out || ifs->ifs_hook6_loopback_in || 240f4b3ec61Sdh ifs->ifs_hook6_loopback_out) 241381a2a9aSdr return -1; 242381a2a9aSdr 2437c478bd9Sstevel@tonic-gate return 0; 244381a2a9aSdr 245381a2a9aSdr detach_failed: 246f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 247381a2a9aSdr return -1; 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate 250f4b3ec61Sdh int iplattach(ifs, ns) 251f4b3ec61Sdh ipf_stack_t *ifs; 252f4b3ec61Sdh netstack_t *ns; 2537c478bd9Sstevel@tonic-gate { 2547c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 2557c478bd9Sstevel@tonic-gate int i; 2567c478bd9Sstevel@tonic-gate #endif 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 2597c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplattach()\n"); 2607c478bd9Sstevel@tonic-gate #endif 2617c478bd9Sstevel@tonic-gate 262f4b3ec61Sdh ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0); 263f4b3ec61Sdh ifs->ifs_fr_flags = IPF_LOGGING; 264f4b3ec61Sdh #ifdef _KERNEL 265f4b3ec61Sdh ifs->ifs_fr_update_ipid = 0; 266f4b3ec61Sdh #else 267f4b3ec61Sdh ifs->ifs_fr_update_ipid = 1; 268f4b3ec61Sdh #endif 269f4b3ec61Sdh ifs->ifs_fr_minttl = 4; 270f4b3ec61Sdh ifs->ifs_fr_icmpminfragmtu = 68; 271f4b3ec61Sdh #if defined(IPFILTER_DEFAULT_BLOCK) 272f4b3ec61Sdh ifs->ifs_fr_pass = FR_BLOCK|FR_NOMATCH; 273f4b3ec61Sdh #else 274f4b3ec61Sdh ifs->ifs_fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH; 275f4b3ec61Sdh #endif 2767c478bd9Sstevel@tonic-gate 277f4b3ec61Sdh MUTEX_INIT(&ifs->ifs_ipf_rw, "ipf rw mutex"); 278f4b3ec61Sdh MUTEX_INIT(&ifs->ifs_ipf_timeoutlock, "ipf timeout lock mutex"); 279f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); 280f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_tokens, "ipf token rwlock"); 281f4b3ec61Sdh ifs->ifs_ipf_locks_done = 1; 2827c478bd9Sstevel@tonic-gate 283f4b3ec61Sdh if (fr_initialise(ifs) < 0) 2847c478bd9Sstevel@tonic-gate return -1; 2857c478bd9Sstevel@tonic-gate 286f4b3ec61Sdh HOOK_INIT(&ifs->ifs_ipfhook_nicevents, ipf_nic_event_v4, 287381a2a9aSdr "ipfilter_hook_nicevents"); 288cbded9aeSdr HOOK_INIT(&ifs->ifs_ipfhook4_in, ipf_hook4_in, "ipfilter_hook_in"); 289cbded9aeSdr HOOK_INIT(&ifs->ifs_ipfhook4_out, ipf_hook4_out, "ipfilter_hook_out"); 290cbded9aeSdr HOOK_INIT(&ifs->ifs_ipfhook4_loop_in, ipf_hook4_in, 291f4b3ec61Sdh "ipfilter_hook_loop_in"); 292cbded9aeSdr HOOK_INIT(&ifs->ifs_ipfhook4_loop_out, ipf_hook4_out, 293ca8c7054Syx "ipfilter_hook_loop_out"); 294381a2a9aSdr 295381a2a9aSdr /* 296381a2a9aSdr * If we hold this lock over all of the net_register_hook calls, we 297381a2a9aSdr * can cause a deadlock to occur with the following lock ordering: 298381a2a9aSdr * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs 299381a2a9aSdr * R(hook_family)->R(hei_lock)->R(ipf_global) (packet path) 300381a2a9aSdr */ 301f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 302381a2a9aSdr 303381a2a9aSdr /* 304381a2a9aSdr * Add IPv4 hooks 305381a2a9aSdr */ 306f4b3ec61Sdh ifs->ifs_ipf_ipv4 = net_lookup_impl(NHF_INET, ns); 307f4b3ec61Sdh if (ifs->ifs_ipf_ipv4 == NULL) 308381a2a9aSdr goto hookup_failed; 309381a2a9aSdr 310f4b3ec61Sdh ifs->ifs_hook4_nic_events = (net_register_hook(ifs->ifs_ipf_ipv4, 311f4b3ec61Sdh NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) == 0); 312f4b3ec61Sdh if (!ifs->ifs_hook4_nic_events) 313381a2a9aSdr goto hookup_failed; 314381a2a9aSdr 315f4b3ec61Sdh ifs->ifs_hook4_physical_in = (net_register_hook(ifs->ifs_ipf_ipv4, 316cbded9aeSdr NH_PHYSICAL_IN, &ifs->ifs_ipfhook4_in) == 0); 317f4b3ec61Sdh if (!ifs->ifs_hook4_physical_in) 318381a2a9aSdr goto hookup_failed; 319381a2a9aSdr 320f4b3ec61Sdh ifs->ifs_hook4_physical_out = (net_register_hook(ifs->ifs_ipf_ipv4, 321cbded9aeSdr NH_PHYSICAL_OUT, &ifs->ifs_ipfhook4_out) == 0); 322f4b3ec61Sdh if (!ifs->ifs_hook4_physical_out) 323381a2a9aSdr goto hookup_failed; 324381a2a9aSdr 325f4b3ec61Sdh if (ifs->ifs_ipf_loopback) { 326f4b3ec61Sdh ifs->ifs_hook4_loopback_in = 327f4b3ec61Sdh (net_register_hook(ifs->ifs_ipf_ipv4, 328cbded9aeSdr NH_LOOPBACK_IN, &ifs->ifs_ipfhook4_loop_in) == 0); 329f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_in) 330381a2a9aSdr goto hookup_failed; 331381a2a9aSdr 332f4b3ec61Sdh ifs->ifs_hook4_loopback_out = 333f4b3ec61Sdh (net_register_hook(ifs->ifs_ipf_ipv4, 334cbded9aeSdr NH_LOOPBACK_OUT, &ifs->ifs_ipfhook4_loop_out) == 0); 335f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_out) 336381a2a9aSdr goto hookup_failed; 337381a2a9aSdr } 338381a2a9aSdr /* 339381a2a9aSdr * Add IPv6 hooks 340381a2a9aSdr */ 341f4b3ec61Sdh ifs->ifs_ipf_ipv6 = net_lookup_impl(NHF_INET6, ns); 342f4b3ec61Sdh if (ifs->ifs_ipf_ipv6 == NULL) 343381a2a9aSdr goto hookup_failed; 344381a2a9aSdr 345cbded9aeSdr HOOK_INIT(&ifs->ifs_ipfhook6_in, ipf_hook6_in, "ipfilter_hook_in"); 346cbded9aeSdr HOOK_INIT(&ifs->ifs_ipfhook6_out, ipf_hook6_out, "ipfilter_hook_out"); 347cbded9aeSdr HOOK_INIT(&ifs->ifs_ipfhook6_loop_in, ipf_hook6_in, 348cbded9aeSdr "ipfilter_hook_loop_in"); 349cbded9aeSdr HOOK_INIT(&ifs->ifs_ipfhook6_loop_out, ipf_hook6_out, 350cbded9aeSdr "ipfilter_hook_loop_out"); 351cbded9aeSdr 352f4b3ec61Sdh HOOK_INIT(&ifs->ifs_ipfhook_nicevents, ipf_nic_event_v6, 353381a2a9aSdr "ipfilter_hook_nicevents"); 354f4b3ec61Sdh ifs->ifs_hook6_nic_events = (net_register_hook(ifs->ifs_ipf_ipv6, 355f4b3ec61Sdh NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) == 0); 356f4b3ec61Sdh if (!ifs->ifs_hook6_nic_events) 357381a2a9aSdr goto hookup_failed; 358381a2a9aSdr 359f4b3ec61Sdh ifs->ifs_hook6_physical_in = (net_register_hook(ifs->ifs_ipf_ipv6, 360cbded9aeSdr NH_PHYSICAL_IN, &ifs->ifs_ipfhook6_in) == 0); 361f4b3ec61Sdh if (!ifs->ifs_hook6_physical_in) 362381a2a9aSdr goto hookup_failed; 363381a2a9aSdr 364f4b3ec61Sdh ifs->ifs_hook6_physical_out = (net_register_hook(ifs->ifs_ipf_ipv6, 365cbded9aeSdr NH_PHYSICAL_OUT, &ifs->ifs_ipfhook6_out) == 0); 366f4b3ec61Sdh if (!ifs->ifs_hook6_physical_out) 367381a2a9aSdr goto hookup_failed; 368381a2a9aSdr 369f4b3ec61Sdh if (ifs->ifs_ipf_loopback) { 370f4b3ec61Sdh ifs->ifs_hook6_loopback_in = 371f4b3ec61Sdh (net_register_hook(ifs->ifs_ipf_ipv6, 372cbded9aeSdr NH_LOOPBACK_IN, &ifs->ifs_ipfhook6_loop_in) == 0); 373f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_in) 374381a2a9aSdr goto hookup_failed; 375381a2a9aSdr 376f4b3ec61Sdh ifs->ifs_hook6_loopback_out = 377f4b3ec61Sdh (net_register_hook(ifs->ifs_ipf_ipv6, 378cbded9aeSdr NH_LOOPBACK_OUT, &ifs->ifs_ipfhook6_loop_out) == 0); 379f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_out) 380381a2a9aSdr goto hookup_failed; 381381a2a9aSdr } 382381a2a9aSdr 383381a2a9aSdr /* 384381a2a9aSdr * Reacquire ipf_global, now it is safe. 385381a2a9aSdr */ 386f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 387381a2a9aSdr 3887c478bd9Sstevel@tonic-gate /* Do not use private interface ip_params_arr[] in Solaris 10 */ 3897c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 3927c478bd9Sstevel@tonic-gate ip_forwarding = &ip_g_forward; 3937c478bd9Sstevel@tonic-gate #endif 3947c478bd9Sstevel@tonic-gate /* 3957c478bd9Sstevel@tonic-gate * XXX - There is no terminator for this array, so it is not possible 3967c478bd9Sstevel@tonic-gate * to tell if what we are looking for is missing and go off the end 3977c478bd9Sstevel@tonic-gate * of the array. 3987c478bd9Sstevel@tonic-gate */ 3997c478bd9Sstevel@tonic-gate 400ab25eeb5Syz #if SOLARIS2 <= 8 4017c478bd9Sstevel@tonic-gate for (i = 0; ; i++) { 4027c478bd9Sstevel@tonic-gate if (!strcmp(ip_param_arr[i].ip_param_name, "ip_def_ttl")) { 4037c478bd9Sstevel@tonic-gate ip_ttl_ptr = &ip_param_arr[i].ip_param_value; 4047c478bd9Sstevel@tonic-gate } else if (!strcmp(ip_param_arr[i].ip_param_name, 4057c478bd9Sstevel@tonic-gate "ip_path_mtu_discovery")) { 4067c478bd9Sstevel@tonic-gate ip_mtudisc = &ip_param_arr[i].ip_param_value; 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate #if SOLARIS2 < 8 4097c478bd9Sstevel@tonic-gate else if (!strcmp(ip_param_arr[i].ip_param_name, 4107c478bd9Sstevel@tonic-gate "ip_forwarding")) { 4117c478bd9Sstevel@tonic-gate ip_forwarding = &ip_param_arr[i].ip_param_value; 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate #else 4147c478bd9Sstevel@tonic-gate else if (!strcmp(ip_param_arr[i].ip_param_name, 4157c478bd9Sstevel@tonic-gate "ip6_forwarding")) { 4167c478bd9Sstevel@tonic-gate ip6_forwarding = &ip_param_arr[i].ip_param_value; 4177c478bd9Sstevel@tonic-gate } 4187c478bd9Sstevel@tonic-gate #endif 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate if (ip_mtudisc != NULL && ip_ttl_ptr != NULL && 4217c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 4227c478bd9Sstevel@tonic-gate ip6_forwarding != NULL && 4237c478bd9Sstevel@tonic-gate #endif 4247c478bd9Sstevel@tonic-gate ip_forwarding != NULL) 4257c478bd9Sstevel@tonic-gate break; 4267c478bd9Sstevel@tonic-gate } 427ab25eeb5Syz #endif 4287c478bd9Sstevel@tonic-gate 429f4b3ec61Sdh if (ifs->ifs_fr_control_forwarding & 1) { 430ab25eeb5Syz if (ip_forwarding != NULL) 431ab25eeb5Syz *ip_forwarding = 1; 4327c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 433ab25eeb5Syz if (ip6_forwarding != NULL) 434ab25eeb5Syz *ip6_forwarding = 1; 4357c478bd9Sstevel@tonic-gate #endif 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate #endif 4397c478bd9Sstevel@tonic-gate 440381a2a9aSdr return 0; 441381a2a9aSdr hookup_failed: 442f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 443381a2a9aSdr return -1; 444381a2a9aSdr } 445381a2a9aSdr 446f4b3ec61Sdh static int fr_setipfloopback(set, ifs) 447381a2a9aSdr int set; 448f4b3ec61Sdh ipf_stack_t *ifs; 449381a2a9aSdr { 450f4b3ec61Sdh if (ifs->ifs_ipf_ipv4 == NULL || ifs->ifs_ipf_ipv6 == NULL) 451381a2a9aSdr return EFAULT; 452381a2a9aSdr 453f4b3ec61Sdh if (set && !ifs->ifs_ipf_loopback) { 454f4b3ec61Sdh ifs->ifs_ipf_loopback = 1; 455381a2a9aSdr 456f4b3ec61Sdh ifs->ifs_hook4_loopback_in = 457f4b3ec61Sdh (net_register_hook(ifs->ifs_ipf_ipv4, 458cbded9aeSdr NH_LOOPBACK_IN, &ifs->ifs_ipfhook4_loop_in) == 0); 459f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_in) 460381a2a9aSdr return EINVAL; 461381a2a9aSdr 462f4b3ec61Sdh ifs->ifs_hook4_loopback_out = 463f4b3ec61Sdh (net_register_hook(ifs->ifs_ipf_ipv4, 464cbded9aeSdr NH_LOOPBACK_OUT, &ifs->ifs_ipfhook4_loop_out) == 0); 465f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_out) 466381a2a9aSdr return EINVAL; 467381a2a9aSdr 468f4b3ec61Sdh ifs->ifs_hook6_loopback_in = 469f4b3ec61Sdh (net_register_hook(ifs->ifs_ipf_ipv6, 470cbded9aeSdr NH_LOOPBACK_IN, &ifs->ifs_ipfhook6_loop_in) == 0); 471f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_in) 472381a2a9aSdr return EINVAL; 473381a2a9aSdr 474f4b3ec61Sdh ifs->ifs_hook6_loopback_out = 475f4b3ec61Sdh (net_register_hook(ifs->ifs_ipf_ipv6, 476cbded9aeSdr NH_LOOPBACK_OUT, &ifs->ifs_ipfhook6_loop_out) == 0); 477f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_out) 478381a2a9aSdr return EINVAL; 479381a2a9aSdr 480f4b3ec61Sdh } else if (!set && ifs->ifs_ipf_loopback) { 481f4b3ec61Sdh ifs->ifs_ipf_loopback = 0; 482381a2a9aSdr 483f4b3ec61Sdh ifs->ifs_hook4_loopback_in = 484f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv4, 485cbded9aeSdr NH_LOOPBACK_IN, &ifs->ifs_ipfhook4_loop_in) != 0); 486f4b3ec61Sdh if (ifs->ifs_hook4_loopback_in) 487381a2a9aSdr return EBUSY; 488381a2a9aSdr 489f4b3ec61Sdh ifs->ifs_hook4_loopback_out = 490f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv4, 491cbded9aeSdr NH_LOOPBACK_OUT, &ifs->ifs_ipfhook4_loop_out) != 0); 492f4b3ec61Sdh if (ifs->ifs_hook4_loopback_out) 493381a2a9aSdr return EBUSY; 494381a2a9aSdr 495f4b3ec61Sdh ifs->ifs_hook6_loopback_in = 496f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv6, 497cbded9aeSdr NH_LOOPBACK_IN, &ifs->ifs_ipfhook6_loop_in) != 0); 498f4b3ec61Sdh if (ifs->ifs_hook6_loopback_in) 499381a2a9aSdr return EBUSY; 500381a2a9aSdr 501f4b3ec61Sdh ifs->ifs_hook6_loopback_out = 502f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv6, 503cbded9aeSdr NH_LOOPBACK_OUT, &ifs->ifs_ipfhook6_loop_out) != 0); 504f4b3ec61Sdh if (ifs->ifs_hook6_loopback_out) 505381a2a9aSdr return EBUSY; 506381a2a9aSdr } 5077c478bd9Sstevel@tonic-gate return 0; 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate /* 5127c478bd9Sstevel@tonic-gate * Filter ioctl interface. 5137c478bd9Sstevel@tonic-gate */ 5147c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5157c478bd9Sstevel@tonic-gate int iplioctl(dev, cmd, data, mode, cp, rp) 5167c478bd9Sstevel@tonic-gate dev_t dev; 5177c478bd9Sstevel@tonic-gate int cmd; 5187c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 7 5197c478bd9Sstevel@tonic-gate intptr_t data; 5207c478bd9Sstevel@tonic-gate #else 5217c478bd9Sstevel@tonic-gate int *data; 5227c478bd9Sstevel@tonic-gate #endif 5237c478bd9Sstevel@tonic-gate int mode; 5247c478bd9Sstevel@tonic-gate cred_t *cp; 5257c478bd9Sstevel@tonic-gate int *rp; 5267c478bd9Sstevel@tonic-gate { 5277c478bd9Sstevel@tonic-gate int error = 0, tmp; 5287c478bd9Sstevel@tonic-gate friostat_t fio; 5297c478bd9Sstevel@tonic-gate minor_t unit; 5307c478bd9Sstevel@tonic-gate u_int enable; 531f4b3ec61Sdh netstack_t *ns; 532f4b3ec61Sdh ipf_stack_t *ifs; 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 5357c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplioctl(%x,%x,%x,%d,%x,%d)\n", 5367c478bd9Sstevel@tonic-gate dev, cmd, data, mode, cp, rp); 5377c478bd9Sstevel@tonic-gate #endif 5387c478bd9Sstevel@tonic-gate unit = getminor(dev); 5397c478bd9Sstevel@tonic-gate if (IPL_LOGMAX < unit) 5407c478bd9Sstevel@tonic-gate return ENXIO; 5417c478bd9Sstevel@tonic-gate 542f4b3ec61Sdh ns = netstack_find_by_cred(cp); 543f4b3ec61Sdh ASSERT(ns != NULL); 544f4b3ec61Sdh ifs = ns->netstack_ipf; 545f4b3ec61Sdh ASSERT(ifs != NULL); 546f4b3ec61Sdh 547f4b3ec61Sdh if (ifs->ifs_fr_running <= 0) { 548f4b3ec61Sdh if (unit != IPL_LOGIPF) { 549f4b3ec61Sdh netstack_rele(ifs->ifs_netstack); 5507c478bd9Sstevel@tonic-gate return EIO; 551f4b3ec61Sdh } 5527c478bd9Sstevel@tonic-gate if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 553ab25eeb5Syz cmd != SIOCIPFSET && cmd != SIOCFRENB && 554f4b3ec61Sdh cmd != SIOCGETFS && cmd != SIOCGETFF) { 555f4b3ec61Sdh netstack_rele(ifs->ifs_netstack); 5567c478bd9Sstevel@tonic-gate return EIO; 557f4b3ec61Sdh } 5587c478bd9Sstevel@tonic-gate } 5597c478bd9Sstevel@tonic-gate 560f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_global); 5617c478bd9Sstevel@tonic-gate 562f4b3ec61Sdh error = fr_ioctlswitch(unit, (caddr_t)data, cmd, mode, cp->cr_uid, curproc, ifs); 5637c478bd9Sstevel@tonic-gate if (error != -1) { 564f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 565f4b3ec61Sdh netstack_rele(ifs->ifs_netstack); 5667c478bd9Sstevel@tonic-gate return error; 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate error = 0; 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate switch (cmd) 5717c478bd9Sstevel@tonic-gate { 5727c478bd9Sstevel@tonic-gate case SIOCFRENB : 5737c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 5747c478bd9Sstevel@tonic-gate error = EPERM; 5757c478bd9Sstevel@tonic-gate else { 5767c478bd9Sstevel@tonic-gate error = COPYIN((caddr_t)data, (caddr_t)&enable, 5777c478bd9Sstevel@tonic-gate sizeof(enable)); 5787c478bd9Sstevel@tonic-gate if (error != 0) { 5797c478bd9Sstevel@tonic-gate error = EFAULT; 5807c478bd9Sstevel@tonic-gate break; 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate 583f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 584f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 585882bd30bSdr error = fr_enableipf(ifs, ns, enable); 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate break; 5887c478bd9Sstevel@tonic-gate case SIOCIPFSET : 5897c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) { 5907c478bd9Sstevel@tonic-gate error = EPERM; 5917c478bd9Sstevel@tonic-gate break; 5927c478bd9Sstevel@tonic-gate } 5937c478bd9Sstevel@tonic-gate /* FALLTHRU */ 5947c478bd9Sstevel@tonic-gate case SIOCIPFGETNEXT : 5957c478bd9Sstevel@tonic-gate case SIOCIPFGET : 596f4b3ec61Sdh error = fr_ipftune(cmd, (void *)data, ifs); 5977c478bd9Sstevel@tonic-gate break; 5987c478bd9Sstevel@tonic-gate case SIOCSETFF : 5997c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6007c478bd9Sstevel@tonic-gate error = EPERM; 6017c478bd9Sstevel@tonic-gate else { 602f4b3ec61Sdh error = COPYIN((caddr_t)data, (caddr_t)&ifs->ifs_fr_flags, 603f4b3ec61Sdh sizeof(ifs->ifs_fr_flags)); 6047c478bd9Sstevel@tonic-gate if (error != 0) 6057c478bd9Sstevel@tonic-gate error = EFAULT; 6067c478bd9Sstevel@tonic-gate } 6077c478bd9Sstevel@tonic-gate break; 608381a2a9aSdr case SIOCIPFLP : 609381a2a9aSdr error = COPYIN((caddr_t)data, (caddr_t)&tmp, 610381a2a9aSdr sizeof(tmp)); 611381a2a9aSdr if (error != 0) 612381a2a9aSdr error = EFAULT; 613381a2a9aSdr else 614f4b3ec61Sdh error = fr_setipfloopback(tmp, ifs); 615381a2a9aSdr break; 6167c478bd9Sstevel@tonic-gate case SIOCGETFF : 617f4b3ec61Sdh error = COPYOUT((caddr_t)&ifs->ifs_fr_flags, (caddr_t)data, 618f4b3ec61Sdh sizeof(ifs->ifs_fr_flags)); 6197c478bd9Sstevel@tonic-gate if (error != 0) 6207c478bd9Sstevel@tonic-gate error = EFAULT; 6217c478bd9Sstevel@tonic-gate break; 6227c478bd9Sstevel@tonic-gate case SIOCFUNCL : 6237c478bd9Sstevel@tonic-gate error = fr_resolvefunc((void *)data); 6247c478bd9Sstevel@tonic-gate break; 6257c478bd9Sstevel@tonic-gate case SIOCINAFR : 6267c478bd9Sstevel@tonic-gate case SIOCRMAFR : 6277c478bd9Sstevel@tonic-gate case SIOCADAFR : 6287c478bd9Sstevel@tonic-gate case SIOCZRLST : 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 ifs->ifs_fr_active, 1, ifs); 6347c478bd9Sstevel@tonic-gate break; 6357c478bd9Sstevel@tonic-gate case SIOCINIFR : 6367c478bd9Sstevel@tonic-gate case SIOCRMIFR : 6377c478bd9Sstevel@tonic-gate case SIOCADIFR : 6387c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6397c478bd9Sstevel@tonic-gate error = EPERM; 6407c478bd9Sstevel@tonic-gate else 6417c478bd9Sstevel@tonic-gate error = frrequest(unit, cmd, (caddr_t)data, 642f4b3ec61Sdh 1 - ifs->ifs_fr_active, 1, ifs); 6437c478bd9Sstevel@tonic-gate break; 6447c478bd9Sstevel@tonic-gate case SIOCSWAPA : 6457c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6467c478bd9Sstevel@tonic-gate error = EPERM; 6477c478bd9Sstevel@tonic-gate else { 648f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_mutex); 649f4b3ec61Sdh error = COPYOUT((caddr_t)&ifs->ifs_fr_active, 650f4b3ec61Sdh (caddr_t)data, 651f4b3ec61Sdh sizeof(ifs->ifs_fr_active)); 6527c478bd9Sstevel@tonic-gate if (error != 0) 6537c478bd9Sstevel@tonic-gate error = EFAULT; 6547c478bd9Sstevel@tonic-gate else 655f4b3ec61Sdh ifs->ifs_fr_active = 1 - ifs->ifs_fr_active; 656f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 6577c478bd9Sstevel@tonic-gate } 6587c478bd9Sstevel@tonic-gate break; 6597c478bd9Sstevel@tonic-gate case SIOCGETFS : 660f4b3ec61Sdh fr_getstat(&fio, ifs); 6617c478bd9Sstevel@tonic-gate error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT); 6627c478bd9Sstevel@tonic-gate break; 6637c478bd9Sstevel@tonic-gate case SIOCFRZST : 6647c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6657c478bd9Sstevel@tonic-gate error = EPERM; 6667c478bd9Sstevel@tonic-gate else 667f4b3ec61Sdh error = fr_zerostats((caddr_t)data, ifs); 6687c478bd9Sstevel@tonic-gate break; 6697c478bd9Sstevel@tonic-gate case SIOCIPFFL : 6707c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6717c478bd9Sstevel@tonic-gate error = EPERM; 6727c478bd9Sstevel@tonic-gate else { 6737c478bd9Sstevel@tonic-gate error = COPYIN((caddr_t)data, (caddr_t)&tmp, 6747c478bd9Sstevel@tonic-gate sizeof(tmp)); 6757c478bd9Sstevel@tonic-gate if (!error) { 676f4b3ec61Sdh tmp = frflush(unit, 4, tmp, ifs); 6777c478bd9Sstevel@tonic-gate error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 6787c478bd9Sstevel@tonic-gate sizeof(tmp)); 6797c478bd9Sstevel@tonic-gate if (error != 0) 6807c478bd9Sstevel@tonic-gate error = EFAULT; 6817c478bd9Sstevel@tonic-gate } else 6827c478bd9Sstevel@tonic-gate error = EFAULT; 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate break; 6857663b816Sml #ifdef USE_INET6 6867663b816Sml case SIOCIPFL6 : 6877663b816Sml if (!(mode & FWRITE)) 6887663b816Sml error = EPERM; 6897663b816Sml else { 6907663b816Sml error = COPYIN((caddr_t)data, (caddr_t)&tmp, 6917663b816Sml sizeof(tmp)); 6927663b816Sml if (!error) { 693f4b3ec61Sdh tmp = frflush(unit, 6, tmp, ifs); 6947663b816Sml error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 6957663b816Sml sizeof(tmp)); 6967663b816Sml if (error != 0) 6977663b816Sml error = EFAULT; 6987663b816Sml } else 6997663b816Sml error = EFAULT; 7007663b816Sml } 7017663b816Sml break; 7027663b816Sml #endif 7037c478bd9Sstevel@tonic-gate case SIOCSTLCK : 7047c478bd9Sstevel@tonic-gate error = COPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 7057c478bd9Sstevel@tonic-gate if (error == 0) { 706f4b3ec61Sdh ifs->ifs_fr_state_lock = tmp; 707f4b3ec61Sdh ifs->ifs_fr_nat_lock = tmp; 708f4b3ec61Sdh ifs->ifs_fr_frag_lock = tmp; 709f4b3ec61Sdh ifs->ifs_fr_auth_lock = tmp; 7107c478bd9Sstevel@tonic-gate } else 7117c478bd9Sstevel@tonic-gate error = EFAULT; 7127c478bd9Sstevel@tonic-gate break; 7137c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 7147c478bd9Sstevel@tonic-gate case SIOCIPFFB : 7157c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 7167c478bd9Sstevel@tonic-gate error = EPERM; 7177c478bd9Sstevel@tonic-gate else { 718f4b3ec61Sdh tmp = ipflog_clear(unit, ifs); 7197c478bd9Sstevel@tonic-gate error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 7207c478bd9Sstevel@tonic-gate sizeof(tmp)); 7217c478bd9Sstevel@tonic-gate if (error) 7227c478bd9Sstevel@tonic-gate error = EFAULT; 7237c478bd9Sstevel@tonic-gate } 7247c478bd9Sstevel@tonic-gate break; 7257c478bd9Sstevel@tonic-gate #endif /* IPFILTER_LOG */ 7267c478bd9Sstevel@tonic-gate case SIOCFRSYN : 7277c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 7287c478bd9Sstevel@tonic-gate error = EPERM; 7297c478bd9Sstevel@tonic-gate else { 730f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 731f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 732381a2a9aSdr 733f4b3ec61Sdh frsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 734d6c23f6fSyx fr_natifpsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 735d6c23f6fSyx fr_nataddrsync(0, NULL, NULL, ifs); 736f4b3ec61Sdh fr_statesync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 737381a2a9aSdr error = 0; 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate break; 7407c478bd9Sstevel@tonic-gate case SIOCGFRST : 741f4b3ec61Sdh error = fr_outobj((void *)data, fr_fragstats(ifs), 7427c478bd9Sstevel@tonic-gate IPFOBJ_FRAGSTAT); 7437c478bd9Sstevel@tonic-gate break; 7447c478bd9Sstevel@tonic-gate case FIONREAD : 7457c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 746f4b3ec61Sdh tmp = (int)ifs->ifs_iplused[IPL_LOGIPF]; 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate error = COPYOUT((caddr_t)&tmp, (caddr_t)data, sizeof(tmp)); 7497c478bd9Sstevel@tonic-gate if (error != 0) 7507c478bd9Sstevel@tonic-gate error = EFAULT; 7517c478bd9Sstevel@tonic-gate #endif 7527c478bd9Sstevel@tonic-gate break; 753f4b3ec61Sdh case SIOCIPFITER : 754f4b3ec61Sdh error = ipf_frruleiter((caddr_t)data, cp->cr_uid, curproc, ifs); 755f4b3ec61Sdh break; 756f4b3ec61Sdh 757f4b3ec61Sdh case SIOCGENITER : 758f4b3ec61Sdh error = ipf_genericiter((caddr_t)data, cp->cr_uid, curproc, ifs); 759f4b3ec61Sdh break; 760f4b3ec61Sdh 761f4b3ec61Sdh case SIOCIPFDELTOK : 762*bb1d9de5SJohn Ojemann error = BCOPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 763*bb1d9de5SJohn Ojemann if (error != 0) { 764*bb1d9de5SJohn Ojemann error = EFAULT; 765*bb1d9de5SJohn Ojemann } else { 766*bb1d9de5SJohn Ojemann error = ipf_deltoken(tmp, cp->cr_uid, curproc, ifs); 767*bb1d9de5SJohn Ojemann } 768f4b3ec61Sdh break; 769f4b3ec61Sdh 7707c478bd9Sstevel@tonic-gate default : 771ab25eeb5Syz cmn_err(CE_NOTE, "Unknown: cmd 0x%x data %p", cmd, (void *)data); 7727c478bd9Sstevel@tonic-gate error = EINVAL; 7737c478bd9Sstevel@tonic-gate break; 7747c478bd9Sstevel@tonic-gate } 775f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 776f4b3ec61Sdh netstack_rele(ifs->ifs_netstack); 7777c478bd9Sstevel@tonic-gate return error; 7787c478bd9Sstevel@tonic-gate } 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate 781882bd30bSdr static int fr_enableipf(ifs, ns, enable) 782882bd30bSdr ipf_stack_t *ifs; 783882bd30bSdr netstack_t *ns; 784882bd30bSdr int enable; 785882bd30bSdr { 786882bd30bSdr int error; 787882bd30bSdr 78844aaa2b6Sjojemann if (!enable) { 789882bd30bSdr error = ipldetach(ifs); 790882bd30bSdr if (error == 0) 791882bd30bSdr ifs->ifs_fr_running = -1; 79244aaa2b6Sjojemann return (error); 793882bd30bSdr } 794882bd30bSdr 79544aaa2b6Sjojemann if (ifs->ifs_fr_running > 0) 79695c191c0Sjojemann return (0); 79744aaa2b6Sjojemann 79844aaa2b6Sjojemann error = iplattach(ifs, ns); 79944aaa2b6Sjojemann if (error == 0) { 80044aaa2b6Sjojemann if (ifs->ifs_fr_timer_id == NULL) { 80144aaa2b6Sjojemann int hz = drv_usectohz(500000); 80244aaa2b6Sjojemann 80344aaa2b6Sjojemann ifs->ifs_fr_timer_id = timeout(fr_slowtimer, 80444aaa2b6Sjojemann (void *)ifs, hz); 80544aaa2b6Sjojemann } 80644aaa2b6Sjojemann ifs->ifs_fr_running = 1; 80744aaa2b6Sjojemann } else { 80844aaa2b6Sjojemann (void) ipldetach(ifs); 80944aaa2b6Sjojemann } 81044aaa2b6Sjojemann return (error); 811882bd30bSdr } 812882bd30bSdr 813882bd30bSdr 814f4b3ec61Sdh phy_if_t get_unit(name, v, ifs) 815f4b3ec61Sdh char *name; 816f4b3ec61Sdh int v; 817f4b3ec61Sdh ipf_stack_t *ifs; 8187c478bd9Sstevel@tonic-gate { 819381a2a9aSdr net_data_t nif; 820381a2a9aSdr 821381a2a9aSdr if (v == 4) 822f4b3ec61Sdh nif = ifs->ifs_ipf_ipv4; 823381a2a9aSdr else if (v == 6) 824f4b3ec61Sdh nif = ifs->ifs_ipf_ipv6; 825381a2a9aSdr else 826381a2a9aSdr return 0; 827381a2a9aSdr 828f4b3ec61Sdh nif->netd_netstack = ifs->ifs_netstack; 829f4b3ec61Sdh 830f4b3ec61Sdh return (net_phylookup(nif, name)); 8317c478bd9Sstevel@tonic-gate } 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate /* 8347c478bd9Sstevel@tonic-gate * routines below for saving IP headers to buffer 8357c478bd9Sstevel@tonic-gate */ 8367c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8377c478bd9Sstevel@tonic-gate int iplopen(devp, flags, otype, cred) 8387c478bd9Sstevel@tonic-gate dev_t *devp; 8397c478bd9Sstevel@tonic-gate int flags, otype; 8407c478bd9Sstevel@tonic-gate cred_t *cred; 8417c478bd9Sstevel@tonic-gate { 8427c478bd9Sstevel@tonic-gate minor_t min = getminor(*devp); 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 8457c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplopen(%x,%x,%x,%x)\n", devp, flags, otype, cred); 8467c478bd9Sstevel@tonic-gate #endif 8477c478bd9Sstevel@tonic-gate if (!(otype & OTYP_CHR)) 8487c478bd9Sstevel@tonic-gate return ENXIO; 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate min = (IPL_LOGMAX < min) ? ENXIO : 0; 8517c478bd9Sstevel@tonic-gate return min; 8527c478bd9Sstevel@tonic-gate } 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8567c478bd9Sstevel@tonic-gate int iplclose(dev, flags, otype, cred) 8577c478bd9Sstevel@tonic-gate dev_t dev; 8587c478bd9Sstevel@tonic-gate int flags, otype; 8597c478bd9Sstevel@tonic-gate cred_t *cred; 8607c478bd9Sstevel@tonic-gate { 8617c478bd9Sstevel@tonic-gate minor_t min = getminor(dev); 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 8647c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplclose(%x,%x,%x,%x)\n", dev, flags, otype, cred); 8657c478bd9Sstevel@tonic-gate #endif 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate min = (IPL_LOGMAX < min) ? ENXIO : 0; 8687c478bd9Sstevel@tonic-gate return min; 8697c478bd9Sstevel@tonic-gate } 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 8727c478bd9Sstevel@tonic-gate /* 8737c478bd9Sstevel@tonic-gate * iplread/ipllog 8747c478bd9Sstevel@tonic-gate * both of these must operate with at least splnet() lest they be 8757c478bd9Sstevel@tonic-gate * called during packet processing and cause an inconsistancy to appear in 8767c478bd9Sstevel@tonic-gate * the filter lists. 8777c478bd9Sstevel@tonic-gate */ 8787c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8797c478bd9Sstevel@tonic-gate int iplread(dev, uio, cp) 8807c478bd9Sstevel@tonic-gate dev_t dev; 8817c478bd9Sstevel@tonic-gate register struct uio *uio; 8827c478bd9Sstevel@tonic-gate cred_t *cp; 8837c478bd9Sstevel@tonic-gate { 884f4b3ec61Sdh netstack_t *ns; 885f4b3ec61Sdh ipf_stack_t *ifs; 886f4b3ec61Sdh int ret; 887f4b3ec61Sdh 888f4b3ec61Sdh ns = netstack_find_by_cred(cp); 889f4b3ec61Sdh ASSERT(ns != NULL); 890f4b3ec61Sdh ifs = ns->netstack_ipf; 891f4b3ec61Sdh ASSERT(ifs != NULL); 892f4b3ec61Sdh 8937c478bd9Sstevel@tonic-gate # ifdef IPFDEBUG 8947c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplread(%x,%x,%x)\n", dev, uio, cp); 8957c478bd9Sstevel@tonic-gate # endif 89608ee25aeSdr 897f4b3ec61Sdh if (ifs->ifs_fr_running < 1) { 898f4b3ec61Sdh netstack_rele(ifs->ifs_netstack); 89908ee25aeSdr return EIO; 900f4b3ec61Sdh } 90108ee25aeSdr 9027c478bd9Sstevel@tonic-gate # ifdef IPFILTER_SYNC 903f4b3ec61Sdh if (getminor(dev) == IPL_LOGSYNC) { 904f4b3ec61Sdh netstack_rele(ifs->ifs_netstack); 9057c478bd9Sstevel@tonic-gate return ipfsync_read(uio); 906f4b3ec61Sdh } 9077c478bd9Sstevel@tonic-gate # endif 9087c478bd9Sstevel@tonic-gate 909f4b3ec61Sdh ret = ipflog_read(getminor(dev), uio, ifs); 910f4b3ec61Sdh netstack_rele(ifs->ifs_netstack); 911f4b3ec61Sdh return ret; 9127c478bd9Sstevel@tonic-gate } 9137c478bd9Sstevel@tonic-gate #endif /* IPFILTER_LOG */ 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate /* 9177c478bd9Sstevel@tonic-gate * iplread/ipllog 9187c478bd9Sstevel@tonic-gate * both of these must operate with at least splnet() lest they be 9197c478bd9Sstevel@tonic-gate * called during packet processing and cause an inconsistancy to appear in 9207c478bd9Sstevel@tonic-gate * the filter lists. 9217c478bd9Sstevel@tonic-gate */ 9227c478bd9Sstevel@tonic-gate int iplwrite(dev, uio, cp) 9237c478bd9Sstevel@tonic-gate dev_t dev; 9247c478bd9Sstevel@tonic-gate register struct uio *uio; 9257c478bd9Sstevel@tonic-gate cred_t *cp; 9267c478bd9Sstevel@tonic-gate { 927f4b3ec61Sdh netstack_t *ns; 928f4b3ec61Sdh ipf_stack_t *ifs; 929f4b3ec61Sdh 930f4b3ec61Sdh ns = netstack_find_by_cred(cp); 931f4b3ec61Sdh ASSERT(ns != NULL); 932f4b3ec61Sdh ifs = ns->netstack_ipf; 933f4b3ec61Sdh ASSERT(ifs != NULL); 934f4b3ec61Sdh 9357c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 9367c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplwrite(%x,%x,%x)\n", dev, uio, cp); 9377c478bd9Sstevel@tonic-gate #endif 93808ee25aeSdr 939f4b3ec61Sdh if (ifs->ifs_fr_running < 1) { 940f4b3ec61Sdh netstack_rele(ifs->ifs_netstack); 94108ee25aeSdr return EIO; 942f4b3ec61Sdh } 94308ee25aeSdr 944ab25eeb5Syz #ifdef IPFILTER_SYNC 945ab25eeb5Syz if (getminor(dev) == IPL_LOGSYNC) 946ab25eeb5Syz return ipfsync_write(uio); 9477c478bd9Sstevel@tonic-gate #endif /* IPFILTER_SYNC */ 948ab25eeb5Syz dev = dev; /* LINT */ 949ab25eeb5Syz uio = uio; /* LINT */ 950ab25eeb5Syz cp = cp; /* LINT */ 951f4b3ec61Sdh netstack_rele(ifs->ifs_netstack); 952ab25eeb5Syz return ENXIO; 953ab25eeb5Syz } 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate /* 9577c478bd9Sstevel@tonic-gate * fr_send_reset - this could conceivably be a call to tcp_respond(), but that 9587c478bd9Sstevel@tonic-gate * requires a large amount of setting up and isn't any more efficient. 9597c478bd9Sstevel@tonic-gate */ 9607c478bd9Sstevel@tonic-gate int fr_send_reset(fin) 9617c478bd9Sstevel@tonic-gate fr_info_t *fin; 9627c478bd9Sstevel@tonic-gate { 9637c478bd9Sstevel@tonic-gate tcphdr_t *tcp, *tcp2; 9647c478bd9Sstevel@tonic-gate int tlen, hlen; 9657c478bd9Sstevel@tonic-gate mblk_t *m; 9667c478bd9Sstevel@tonic-gate #ifdef USE_INET6 9677c478bd9Sstevel@tonic-gate ip6_t *ip6; 9687c478bd9Sstevel@tonic-gate #endif 9697c478bd9Sstevel@tonic-gate ip_t *ip; 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate tcp = fin->fin_dp; 9727c478bd9Sstevel@tonic-gate if (tcp->th_flags & TH_RST) 9737c478bd9Sstevel@tonic-gate return -1; 9747c478bd9Sstevel@tonic-gate 9757c478bd9Sstevel@tonic-gate #ifndef IPFILTER_CKSUM 9767c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 9777c478bd9Sstevel@tonic-gate return -1; 9787c478bd9Sstevel@tonic-gate #endif 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate tlen = (tcp->th_flags & (TH_SYN|TH_FIN)) ? 1 : 0; 9817c478bd9Sstevel@tonic-gate #ifdef USE_INET6 9827c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) 9837c478bd9Sstevel@tonic-gate hlen = sizeof(ip6_t); 9847c478bd9Sstevel@tonic-gate else 9857c478bd9Sstevel@tonic-gate #endif 9867c478bd9Sstevel@tonic-gate hlen = sizeof(ip_t); 9877c478bd9Sstevel@tonic-gate hlen += sizeof(*tcp2); 9887c478bd9Sstevel@tonic-gate if ((m = (mblk_t *)allocb(hlen + 64, BPRI_HI)) == NULL) 9897c478bd9Sstevel@tonic-gate return -1; 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate m->b_rptr += 64; 9927c478bd9Sstevel@tonic-gate MTYPE(m) = M_DATA; 9937c478bd9Sstevel@tonic-gate m->b_wptr = m->b_rptr + hlen; 994ab25eeb5Syz ip = (ip_t *)m->b_rptr; 995ab25eeb5Syz bzero((char *)ip, hlen); 9967c478bd9Sstevel@tonic-gate tcp2 = (struct tcphdr *)(m->b_rptr + hlen - sizeof(*tcp2)); 9977c478bd9Sstevel@tonic-gate tcp2->th_dport = tcp->th_sport; 9987c478bd9Sstevel@tonic-gate tcp2->th_sport = tcp->th_dport; 9997c478bd9Sstevel@tonic-gate if (tcp->th_flags & TH_ACK) { 10007c478bd9Sstevel@tonic-gate tcp2->th_seq = tcp->th_ack; 10017c478bd9Sstevel@tonic-gate tcp2->th_flags = TH_RST; 10027c478bd9Sstevel@tonic-gate } else { 10037c478bd9Sstevel@tonic-gate tcp2->th_ack = ntohl(tcp->th_seq); 10047c478bd9Sstevel@tonic-gate tcp2->th_ack += tlen; 10057c478bd9Sstevel@tonic-gate tcp2->th_ack = htonl(tcp2->th_ack); 10067c478bd9Sstevel@tonic-gate tcp2->th_flags = TH_RST|TH_ACK; 10077c478bd9Sstevel@tonic-gate } 10087c478bd9Sstevel@tonic-gate tcp2->th_off = sizeof(struct tcphdr) >> 2; 10097c478bd9Sstevel@tonic-gate 1010ab25eeb5Syz ip->ip_v = fin->fin_v; 10117c478bd9Sstevel@tonic-gate #ifdef USE_INET6 10127c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 10137c478bd9Sstevel@tonic-gate ip6 = (ip6_t *)m->b_rptr; 10147663b816Sml ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 1015d6c23f6fSyx ip6->ip6_src = fin->fin_dst6.in6; 1016d6c23f6fSyx ip6->ip6_dst = fin->fin_src6.in6; 10177c478bd9Sstevel@tonic-gate ip6->ip6_plen = htons(sizeof(*tcp)); 10187c478bd9Sstevel@tonic-gate ip6->ip6_nxt = IPPROTO_TCP; 10197663b816Sml tcp2->th_sum = fr_cksum(m, (ip_t *)ip6, IPPROTO_TCP, tcp2); 10207c478bd9Sstevel@tonic-gate } else 10217c478bd9Sstevel@tonic-gate #endif 10227c478bd9Sstevel@tonic-gate { 10237c478bd9Sstevel@tonic-gate ip->ip_src.s_addr = fin->fin_daddr; 10247c478bd9Sstevel@tonic-gate ip->ip_dst.s_addr = fin->fin_saddr; 10257c478bd9Sstevel@tonic-gate ip->ip_id = fr_nextipid(fin); 10267c478bd9Sstevel@tonic-gate ip->ip_hl = sizeof(*ip) >> 2; 10277c478bd9Sstevel@tonic-gate ip->ip_p = IPPROTO_TCP; 102837b40788Sekozlow ip->ip_len = sizeof(*ip) + sizeof(*tcp); 10297c478bd9Sstevel@tonic-gate ip->ip_tos = fin->fin_ip->ip_tos; 10307c478bd9Sstevel@tonic-gate tcp2->th_sum = fr_cksum(m, ip, IPPROTO_TCP, tcp2); 10317c478bd9Sstevel@tonic-gate } 1032ab25eeb5Syz return fr_send_ip(fin, m, &m); 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate 103537b40788Sekozlow /* 103637b40788Sekozlow * Function: fr_send_ip 103737b40788Sekozlow * Returns: 0: success 103837b40788Sekozlow * -1: failed 103937b40788Sekozlow * Parameters: 104037b40788Sekozlow * fin: packet information 104137b40788Sekozlow * m: the message block where ip head starts 104237b40788Sekozlow * 104337b40788Sekozlow * Send a new packet through the IP stack. 104437b40788Sekozlow * 104537b40788Sekozlow * For IPv4 packets, ip_len must be in host byte order, and ip_v, 104637b40788Sekozlow * ip_ttl, ip_off, and ip_sum are ignored (filled in by this 104737b40788Sekozlow * function). 104837b40788Sekozlow * 104937b40788Sekozlow * For IPv6 packets, ip6_flow, ip6_vfc, and ip6_hlim are filled 105037b40788Sekozlow * in by this function. 105137b40788Sekozlow * 105237b40788Sekozlow * All other portions of the packet must be in on-the-wire format. 105337b40788Sekozlow */ 1054ab25eeb5Syz /*ARGSUSED*/ 1055ab25eeb5Syz static int fr_send_ip(fin, m, mpp) 10567c478bd9Sstevel@tonic-gate fr_info_t *fin; 1057ab25eeb5Syz mblk_t *m, **mpp; 10587c478bd9Sstevel@tonic-gate { 1059ab25eeb5Syz qpktinfo_t qpi, *qpip; 1060ab25eeb5Syz fr_info_t fnew; 1061ab25eeb5Syz ip_t *ip; 1062ab25eeb5Syz int i, hlen; 1063f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1064ab25eeb5Syz 1065ab25eeb5Syz ip = (ip_t *)m->b_rptr; 1066ab25eeb5Syz bzero((char *)&fnew, sizeof(fnew)); 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate #ifdef USE_INET6 10697c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 10707c478bd9Sstevel@tonic-gate ip6_t *ip6; 10717c478bd9Sstevel@tonic-gate 1072ab25eeb5Syz ip6 = (ip6_t *)ip; 10737c478bd9Sstevel@tonic-gate ip6->ip6_vfc = 0x60; 10747c478bd9Sstevel@tonic-gate ip6->ip6_hlim = 127; 1075ab25eeb5Syz fnew.fin_v = 6; 1076ab25eeb5Syz hlen = sizeof(*ip6); 1077923d6102Szf fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen; 10787c478bd9Sstevel@tonic-gate } else 10797c478bd9Sstevel@tonic-gate #endif 10807c478bd9Sstevel@tonic-gate { 1081ab25eeb5Syz fnew.fin_v = 4; 10827c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 10 10837c478bd9Sstevel@tonic-gate ip->ip_ttl = 255; 1084f4b3ec61Sdh if (net_getpmtuenabled(ifs->ifs_ipf_ipv4) == 1) 1085381a2a9aSdr ip->ip_off = htons(IP_DF); 10867c478bd9Sstevel@tonic-gate #else 1087ab25eeb5Syz if (ip_ttl_ptr != NULL) 1088ab25eeb5Syz ip->ip_ttl = (u_char)(*ip_ttl_ptr); 1089ab25eeb5Syz else 1090ab25eeb5Syz ip->ip_ttl = 63; 1091ab25eeb5Syz if (ip_mtudisc != NULL) 1092ab25eeb5Syz ip->ip_off = htons(*ip_mtudisc ? IP_DF : 0); 1093ab25eeb5Syz else 1094ab25eeb5Syz ip->ip_off = htons(IP_DF); 10957c478bd9Sstevel@tonic-gate #endif 1096ab25eeb5Syz /* 1097ab25eeb5Syz * The dance with byte order and ip_len/ip_off is because in 1098ab25eeb5Syz * fr_fastroute, it expects them to be in host byte order but 1099ab25eeb5Syz * ipf_cksum expects them to be in network byte order. 1100ab25eeb5Syz */ 1101ab25eeb5Syz ip->ip_len = htons(ip->ip_len); 11027c478bd9Sstevel@tonic-gate ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip)); 1103ab25eeb5Syz ip->ip_len = ntohs(ip->ip_len); 1104ab25eeb5Syz ip->ip_off = ntohs(ip->ip_off); 1105ab25eeb5Syz hlen = sizeof(*ip); 1106923d6102Szf fnew.fin_plen = ip->ip_len; 11077c478bd9Sstevel@tonic-gate } 1108ab25eeb5Syz 1109ab25eeb5Syz qpip = fin->fin_qpi; 1110ab25eeb5Syz qpi.qpi_off = 0; 1111381a2a9aSdr qpi.qpi_ill = qpip->qpi_ill; 1112ab25eeb5Syz qpi.qpi_m = m; 1113ab25eeb5Syz qpi.qpi_data = ip; 1114ab25eeb5Syz fnew.fin_qpi = &qpi; 1115ab25eeb5Syz fnew.fin_ifp = fin->fin_ifp; 1116ab25eeb5Syz fnew.fin_flx = FI_NOCKSUM; 1117ab25eeb5Syz fnew.fin_m = m; 111890907f62SJohn Ojemann fnew.fin_qfm = m; 1119ab25eeb5Syz fnew.fin_ip = ip; 1120ab25eeb5Syz fnew.fin_mp = mpp; 1121ab25eeb5Syz fnew.fin_hlen = hlen; 1122ab25eeb5Syz fnew.fin_dp = (char *)ip + hlen; 1123f4b3ec61Sdh fnew.fin_ifs = fin->fin_ifs; 1124ab25eeb5Syz (void) fr_makefrip(hlen, ip, &fnew); 1125ab25eeb5Syz 1126ab25eeb5Syz i = fr_fastroute(m, mpp, &fnew, NULL); 11277c478bd9Sstevel@tonic-gate return i; 11287c478bd9Sstevel@tonic-gate } 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate int fr_send_icmp_err(type, fin, dst) 11327c478bd9Sstevel@tonic-gate int type; 11337c478bd9Sstevel@tonic-gate fr_info_t *fin; 11347c478bd9Sstevel@tonic-gate int dst; 11357c478bd9Sstevel@tonic-gate { 11367c478bd9Sstevel@tonic-gate struct in_addr dst4; 11377c478bd9Sstevel@tonic-gate struct icmp *icmp; 1138ab25eeb5Syz qpktinfo_t *qpi; 11397c478bd9Sstevel@tonic-gate int hlen, code; 1140381a2a9aSdr phy_if_t phy; 11417c478bd9Sstevel@tonic-gate u_short sz; 11427c478bd9Sstevel@tonic-gate #ifdef USE_INET6 11437c478bd9Sstevel@tonic-gate mblk_t *mb; 11447c478bd9Sstevel@tonic-gate #endif 11457c478bd9Sstevel@tonic-gate mblk_t *m; 11467c478bd9Sstevel@tonic-gate #ifdef USE_INET6 11477c478bd9Sstevel@tonic-gate ip6_t *ip6; 11487c478bd9Sstevel@tonic-gate #endif 11497c478bd9Sstevel@tonic-gate ip_t *ip; 1150f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 11517c478bd9Sstevel@tonic-gate 11527c478bd9Sstevel@tonic-gate if ((type < 0) || (type > ICMP_MAXTYPE)) 11537c478bd9Sstevel@tonic-gate return -1; 11547c478bd9Sstevel@tonic-gate 11557c478bd9Sstevel@tonic-gate code = fin->fin_icode; 11567c478bd9Sstevel@tonic-gate #ifdef USE_INET6 11577c478bd9Sstevel@tonic-gate if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) 11587c478bd9Sstevel@tonic-gate return -1; 11597c478bd9Sstevel@tonic-gate #endif 11607c478bd9Sstevel@tonic-gate 11617c478bd9Sstevel@tonic-gate #ifndef IPFILTER_CKSUM 11627c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 11637c478bd9Sstevel@tonic-gate return -1; 11647c478bd9Sstevel@tonic-gate #endif 11657c478bd9Sstevel@tonic-gate 1166ab25eeb5Syz qpi = fin->fin_qpi; 11677c478bd9Sstevel@tonic-gate 11687c478bd9Sstevel@tonic-gate #ifdef USE_INET6 11697c478bd9Sstevel@tonic-gate mb = fin->fin_qfm; 11707c478bd9Sstevel@tonic-gate 11717c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 11727c478bd9Sstevel@tonic-gate sz = sizeof(ip6_t); 11737c478bd9Sstevel@tonic-gate sz += MIN(mb->b_wptr - mb->b_rptr, 512); 11747c478bd9Sstevel@tonic-gate hlen = sizeof(ip6_t); 11757c478bd9Sstevel@tonic-gate type = icmptoicmp6types[type]; 11767c478bd9Sstevel@tonic-gate if (type == ICMP6_DST_UNREACH) 11777c478bd9Sstevel@tonic-gate code = icmptoicmp6unreach[code]; 11787c478bd9Sstevel@tonic-gate } else 11797c478bd9Sstevel@tonic-gate #endif 11807c478bd9Sstevel@tonic-gate { 11817c478bd9Sstevel@tonic-gate if ((fin->fin_p == IPPROTO_ICMP) && 11827c478bd9Sstevel@tonic-gate !(fin->fin_flx & FI_SHORT)) 11837c478bd9Sstevel@tonic-gate switch (ntohs(fin->fin_data[0]) >> 8) 11847c478bd9Sstevel@tonic-gate { 11857c478bd9Sstevel@tonic-gate case ICMP_ECHO : 11867c478bd9Sstevel@tonic-gate case ICMP_TSTAMP : 11877c478bd9Sstevel@tonic-gate case ICMP_IREQ : 11887c478bd9Sstevel@tonic-gate case ICMP_MASKREQ : 11897c478bd9Sstevel@tonic-gate break; 11907c478bd9Sstevel@tonic-gate default : 11917c478bd9Sstevel@tonic-gate return 0; 11927c478bd9Sstevel@tonic-gate } 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate sz = sizeof(ip_t) * 2; 11957c478bd9Sstevel@tonic-gate sz += 8; /* 64 bits of data */ 11967c478bd9Sstevel@tonic-gate hlen = sizeof(ip_t); 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate sz += offsetof(struct icmp, icmp_ip); 12007c478bd9Sstevel@tonic-gate if ((m = (mblk_t *)allocb((size_t)sz + 64, BPRI_HI)) == NULL) 12017c478bd9Sstevel@tonic-gate return -1; 12027c478bd9Sstevel@tonic-gate MTYPE(m) = M_DATA; 12037c478bd9Sstevel@tonic-gate m->b_rptr += 64; 12047c478bd9Sstevel@tonic-gate m->b_wptr = m->b_rptr + sz; 12057c478bd9Sstevel@tonic-gate bzero((char *)m->b_rptr, (size_t)sz); 1206ab25eeb5Syz ip = (ip_t *)m->b_rptr; 1207ab25eeb5Syz ip->ip_v = fin->fin_v; 12087c478bd9Sstevel@tonic-gate icmp = (struct icmp *)(m->b_rptr + hlen); 12097c478bd9Sstevel@tonic-gate icmp->icmp_type = type & 0xff; 12107c478bd9Sstevel@tonic-gate icmp->icmp_code = code & 0xff; 1211381a2a9aSdr phy = (phy_if_t)qpi->qpi_ill; 1212381a2a9aSdr if (type == ICMP_UNREACH && (phy != 0) && 12137c478bd9Sstevel@tonic-gate fin->fin_icode == ICMP_UNREACH_NEEDFRAG) 1214f4b3ec61Sdh icmp->icmp_nextmtu = net_getmtu(ifs->ifs_ipf_ipv4, phy,0 ); 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate #ifdef USE_INET6 12177c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 12187c478bd9Sstevel@tonic-gate struct in6_addr dst6; 12197c478bd9Sstevel@tonic-gate int csz; 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate if (dst == 0) { 1222f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1223f4b3ec61Sdh 1224381a2a9aSdr if (fr_ifpaddr(6, FRI_NORMAL, (void *)phy, 1225f4b3ec61Sdh (void *)&dst6, NULL, ifs) == -1) { 12267c478bd9Sstevel@tonic-gate FREE_MB_T(m); 12277c478bd9Sstevel@tonic-gate return -1; 12287c478bd9Sstevel@tonic-gate } 12297c478bd9Sstevel@tonic-gate } else 1230d6c23f6fSyx dst6 = fin->fin_dst6.in6; 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate csz = sz; 12337c478bd9Sstevel@tonic-gate sz -= sizeof(ip6_t); 12347c478bd9Sstevel@tonic-gate ip6 = (ip6_t *)m->b_rptr; 12357663b816Sml ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 12367c478bd9Sstevel@tonic-gate ip6->ip6_plen = htons((u_short)sz); 12377c478bd9Sstevel@tonic-gate ip6->ip6_nxt = IPPROTO_ICMPV6; 12387c478bd9Sstevel@tonic-gate ip6->ip6_src = dst6; 1239d6c23f6fSyx ip6->ip6_dst = fin->fin_src6.in6; 12407c478bd9Sstevel@tonic-gate sz -= offsetof(struct icmp, icmp_ip); 12417c478bd9Sstevel@tonic-gate bcopy((char *)mb->b_rptr, (char *)&icmp->icmp_ip, sz); 12427c478bd9Sstevel@tonic-gate icmp->icmp_cksum = csz - sizeof(ip6_t); 12437c478bd9Sstevel@tonic-gate } else 12447c478bd9Sstevel@tonic-gate #endif 12457c478bd9Sstevel@tonic-gate { 12467c478bd9Sstevel@tonic-gate ip->ip_hl = sizeof(*ip) >> 2; 12477c478bd9Sstevel@tonic-gate ip->ip_p = IPPROTO_ICMP; 12487c478bd9Sstevel@tonic-gate ip->ip_id = fin->fin_ip->ip_id; 12497c478bd9Sstevel@tonic-gate ip->ip_tos = fin->fin_ip->ip_tos; 125037b40788Sekozlow ip->ip_len = (u_short)sz; 12517c478bd9Sstevel@tonic-gate if (dst == 0) { 1252f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1253f4b3ec61Sdh 1254381a2a9aSdr if (fr_ifpaddr(4, FRI_NORMAL, (void *)phy, 1255f4b3ec61Sdh (void *)&dst4, NULL, ifs) == -1) { 12567c478bd9Sstevel@tonic-gate FREE_MB_T(m); 12577c478bd9Sstevel@tonic-gate return -1; 12587c478bd9Sstevel@tonic-gate } 1259381a2a9aSdr } else { 12607c478bd9Sstevel@tonic-gate dst4 = fin->fin_dst; 1261381a2a9aSdr } 12627c478bd9Sstevel@tonic-gate ip->ip_src = dst4; 12637c478bd9Sstevel@tonic-gate ip->ip_dst = fin->fin_src; 12647c478bd9Sstevel@tonic-gate bcopy((char *)fin->fin_ip, (char *)&icmp->icmp_ip, 12657c478bd9Sstevel@tonic-gate sizeof(*fin->fin_ip)); 12667c478bd9Sstevel@tonic-gate bcopy((char *)fin->fin_ip + fin->fin_hlen, 12677c478bd9Sstevel@tonic-gate (char *)&icmp->icmp_ip + sizeof(*fin->fin_ip), 8); 12687663b816Sml icmp->icmp_ip.ip_len = htons(icmp->icmp_ip.ip_len); 1269ab25eeb5Syz icmp->icmp_ip.ip_off = htons(icmp->icmp_ip.ip_off); 12707c478bd9Sstevel@tonic-gate icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 12717c478bd9Sstevel@tonic-gate sz - sizeof(ip_t)); 12727c478bd9Sstevel@tonic-gate } 12737c478bd9Sstevel@tonic-gate 12747c478bd9Sstevel@tonic-gate /* 12757c478bd9Sstevel@tonic-gate * Need to exit out of these so we don't recursively call rw_enter 12767c478bd9Sstevel@tonic-gate * from fr_qout. 12777c478bd9Sstevel@tonic-gate */ 1278ab25eeb5Syz return fr_send_ip(fin, m, &m); 12797c478bd9Sstevel@tonic-gate } 12807c478bd9Sstevel@tonic-gate 12817c478bd9Sstevel@tonic-gate #include <sys/time.h> 12827c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 12837c478bd9Sstevel@tonic-gate 12847c478bd9Sstevel@tonic-gate #ifndef _KERNEL 12857c478bd9Sstevel@tonic-gate #include <stdio.h> 12867c478bd9Sstevel@tonic-gate #endif 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate #define NULLADDR_RATE_LIMIT 10 /* 10 seconds */ 12897c478bd9Sstevel@tonic-gate 12907c478bd9Sstevel@tonic-gate 12917c478bd9Sstevel@tonic-gate /* 12927c478bd9Sstevel@tonic-gate * Print out warning message at rate-limited speed. 12937c478bd9Sstevel@tonic-gate */ 1294f4b3ec61Sdh static void rate_limit_message(ipf_stack_t *ifs, 1295f4b3ec61Sdh int rate, const char *message, ...) 12967c478bd9Sstevel@tonic-gate { 12977c478bd9Sstevel@tonic-gate static time_t last_time = 0; 12987c478bd9Sstevel@tonic-gate time_t now; 12997c478bd9Sstevel@tonic-gate va_list args; 13007c478bd9Sstevel@tonic-gate char msg_buf[256]; 13017c478bd9Sstevel@tonic-gate int need_printed = 0; 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate now = ddi_get_time(); 13047c478bd9Sstevel@tonic-gate 13057c478bd9Sstevel@tonic-gate /* make sure, no multiple entries */ 1306f4b3ec61Sdh ASSERT(MUTEX_NOT_HELD(&(ifs->ifs_ipf_rw.ipf_lk))); 1307f4b3ec61Sdh MUTEX_ENTER(&ifs->ifs_ipf_rw); 13087c478bd9Sstevel@tonic-gate if (now - last_time >= rate) { 13097c478bd9Sstevel@tonic-gate need_printed = 1; 13107c478bd9Sstevel@tonic-gate last_time = now; 13117c478bd9Sstevel@tonic-gate } 1312f4b3ec61Sdh MUTEX_EXIT(&ifs->ifs_ipf_rw); 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate if (need_printed) { 13157c478bd9Sstevel@tonic-gate va_start(args, message); 13167c478bd9Sstevel@tonic-gate (void)vsnprintf(msg_buf, 255, message, args); 13177c478bd9Sstevel@tonic-gate va_end(args); 13187c478bd9Sstevel@tonic-gate #ifdef _KERNEL 13197c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, msg_buf); 13207c478bd9Sstevel@tonic-gate #else 13217c478bd9Sstevel@tonic-gate fprintf(std_err, msg_buf); 13227c478bd9Sstevel@tonic-gate #endif 13237c478bd9Sstevel@tonic-gate } 13247c478bd9Sstevel@tonic-gate } 13257c478bd9Sstevel@tonic-gate 13267c478bd9Sstevel@tonic-gate /* 13277c478bd9Sstevel@tonic-gate * return the first IP Address associated with an interface 13287c478bd9Sstevel@tonic-gate */ 13297c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1330f4b3ec61Sdh int fr_ifpaddr(v, atype, ifptr, inp, inpmask, ifs) 13317c478bd9Sstevel@tonic-gate int v, atype; 1332381a2a9aSdr void *ifptr; 1333381a2a9aSdr struct in_addr *inp, *inpmask; 1334f4b3ec61Sdh ipf_stack_t *ifs; 13357c478bd9Sstevel@tonic-gate { 1336381a2a9aSdr struct sockaddr_in6 v6addr[2]; 1337381a2a9aSdr struct sockaddr_in v4addr[2]; 1338381a2a9aSdr net_ifaddr_t type[2]; 1339381a2a9aSdr net_data_t net_data; 1340381a2a9aSdr phy_if_t phyif; 1341381a2a9aSdr void *array; 1342381a2a9aSdr 1343381a2a9aSdr switch (v) 1344381a2a9aSdr { 1345381a2a9aSdr case 4: 1346f4b3ec61Sdh net_data = ifs->ifs_ipf_ipv4; 1347381a2a9aSdr array = v4addr; 1348381a2a9aSdr break; 1349381a2a9aSdr case 6: 1350f4b3ec61Sdh net_data = ifs->ifs_ipf_ipv6; 1351381a2a9aSdr array = v6addr; 1352381a2a9aSdr break; 1353381a2a9aSdr default: 1354381a2a9aSdr net_data = NULL; 1355381a2a9aSdr break; 1356381a2a9aSdr } 13577c478bd9Sstevel@tonic-gate 1358381a2a9aSdr if (net_data == NULL) 13597c478bd9Sstevel@tonic-gate return -1; 13607c478bd9Sstevel@tonic-gate 1361381a2a9aSdr phyif = (phy_if_t)ifptr; 1362ab25eeb5Syz 1363ab25eeb5Syz switch (atype) 1364ab25eeb5Syz { 1365ab25eeb5Syz case FRI_PEERADDR : 1366381a2a9aSdr type[0] = NA_PEER; 1367ab25eeb5Syz break; 1368381a2a9aSdr 1369381a2a9aSdr case FRI_BROADCAST : 1370381a2a9aSdr type[0] = NA_BROADCAST; 1371381a2a9aSdr break; 1372381a2a9aSdr 1373ab25eeb5Syz default : 1374381a2a9aSdr type[0] = NA_ADDRESS; 1375ab25eeb5Syz break; 1376ab25eeb5Syz } 13777c478bd9Sstevel@tonic-gate 1378381a2a9aSdr type[1] = NA_NETMASK; 1379381a2a9aSdr 1380381a2a9aSdr if (net_getlifaddr(net_data, phyif, 0, 2, type, array) < 0) 13817c478bd9Sstevel@tonic-gate return -1; 1382381a2a9aSdr 1383381a2a9aSdr if (v == 6) { 1384381a2a9aSdr return fr_ifpfillv6addr(atype, &v6addr[0], &v6addr[1], 1385381a2a9aSdr inp, inpmask); 13867c478bd9Sstevel@tonic-gate } 1387381a2a9aSdr return fr_ifpfillv4addr(atype, &v4addr[0], &v4addr[1], inp, inpmask); 13887c478bd9Sstevel@tonic-gate } 13897c478bd9Sstevel@tonic-gate 13907c478bd9Sstevel@tonic-gate 13917c478bd9Sstevel@tonic-gate u_32_t fr_newisn(fin) 13927c478bd9Sstevel@tonic-gate fr_info_t *fin; 13937c478bd9Sstevel@tonic-gate { 13947c478bd9Sstevel@tonic-gate static int iss_seq_off = 0; 13957c478bd9Sstevel@tonic-gate u_char hash[16]; 13967c478bd9Sstevel@tonic-gate u_32_t newiss; 13977c478bd9Sstevel@tonic-gate MD5_CTX ctx; 1398f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 13997c478bd9Sstevel@tonic-gate 14007c478bd9Sstevel@tonic-gate /* 14017c478bd9Sstevel@tonic-gate * Compute the base value of the ISS. It is a hash 14027c478bd9Sstevel@tonic-gate * of (saddr, sport, daddr, dport, secret). 14037c478bd9Sstevel@tonic-gate */ 14047c478bd9Sstevel@tonic-gate MD5Init(&ctx); 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 14077c478bd9Sstevel@tonic-gate sizeof(fin->fin_fi.fi_src)); 14087c478bd9Sstevel@tonic-gate MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 14097c478bd9Sstevel@tonic-gate sizeof(fin->fin_fi.fi_dst)); 14107c478bd9Sstevel@tonic-gate MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 14117c478bd9Sstevel@tonic-gate 1412f4b3ec61Sdh MD5Update(&ctx, ifs->ifs_ipf_iss_secret, sizeof(ifs->ifs_ipf_iss_secret)); 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate MD5Final(hash, &ctx); 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate bcopy(hash, &newiss, sizeof(newiss)); 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate /* 14197c478bd9Sstevel@tonic-gate * Now increment our "timer", and add it in to 14207c478bd9Sstevel@tonic-gate * the computed value. 14217c478bd9Sstevel@tonic-gate * 14227c478bd9Sstevel@tonic-gate * XXX Use `addin'? 14237c478bd9Sstevel@tonic-gate * XXX TCP_ISSINCR too large to use? 14247c478bd9Sstevel@tonic-gate */ 14257c478bd9Sstevel@tonic-gate iss_seq_off += 0x00010000; 14267c478bd9Sstevel@tonic-gate newiss += iss_seq_off; 14277c478bd9Sstevel@tonic-gate return newiss; 14287c478bd9Sstevel@tonic-gate } 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 14327c478bd9Sstevel@tonic-gate /* Function: fr_nextipid */ 14337c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 14347c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 14357c478bd9Sstevel@tonic-gate /* */ 14367c478bd9Sstevel@tonic-gate /* Returns the next IPv4 ID to use for this packet. */ 14377c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 1438ab25eeb5Syz u_short fr_nextipid(fin) 14397c478bd9Sstevel@tonic-gate fr_info_t *fin; 14407c478bd9Sstevel@tonic-gate { 14417c478bd9Sstevel@tonic-gate static u_short ipid = 0; 14427c478bd9Sstevel@tonic-gate ipstate_t *is; 14437c478bd9Sstevel@tonic-gate nat_t *nat; 14447c478bd9Sstevel@tonic-gate u_short id; 1445f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 14467c478bd9Sstevel@tonic-gate 1447f4b3ec61Sdh MUTEX_ENTER(&ifs->ifs_ipf_rw); 14487c478bd9Sstevel@tonic-gate if (fin->fin_state != NULL) { 14497c478bd9Sstevel@tonic-gate is = fin->fin_state; 14507c478bd9Sstevel@tonic-gate id = (u_short)(is->is_pkts[(fin->fin_rev << 1) + 1] & 0xffff); 14517c478bd9Sstevel@tonic-gate } else if (fin->fin_nat != NULL) { 14527c478bd9Sstevel@tonic-gate nat = fin->fin_nat; 14537c478bd9Sstevel@tonic-gate id = (u_short)(nat->nat_pkts[fin->fin_out] & 0xffff); 14547c478bd9Sstevel@tonic-gate } else 14557c478bd9Sstevel@tonic-gate id = ipid++; 1456f4b3ec61Sdh MUTEX_EXIT(&ifs->ifs_ipf_rw); 14577c478bd9Sstevel@tonic-gate 14587c478bd9Sstevel@tonic-gate return id; 14597c478bd9Sstevel@tonic-gate } 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate #ifndef IPFILTER_CKSUM 14637c478bd9Sstevel@tonic-gate /* ARGSUSED */ 14647c478bd9Sstevel@tonic-gate #endif 14657c478bd9Sstevel@tonic-gate INLINE void fr_checkv4sum(fin) 14667c478bd9Sstevel@tonic-gate fr_info_t *fin; 14677c478bd9Sstevel@tonic-gate { 14687c478bd9Sstevel@tonic-gate #ifdef IPFILTER_CKSUM 14697c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 14707c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_BAD; 14717c478bd9Sstevel@tonic-gate #endif 14727c478bd9Sstevel@tonic-gate } 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate 14757c478bd9Sstevel@tonic-gate #ifdef USE_INET6 1476ab25eeb5Syz # ifndef IPFILTER_CKSUM 14777663b816Sml /* ARGSUSED */ 1478ab25eeb5Syz # endif 14797c478bd9Sstevel@tonic-gate INLINE void fr_checkv6sum(fin) 14807c478bd9Sstevel@tonic-gate fr_info_t *fin; 14817c478bd9Sstevel@tonic-gate { 14827c478bd9Sstevel@tonic-gate # ifdef IPFILTER_CKSUM 14837c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 14847c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_BAD; 14857c478bd9Sstevel@tonic-gate # endif 14867c478bd9Sstevel@tonic-gate } 14877c478bd9Sstevel@tonic-gate #endif /* USE_INET6 */ 1488ab25eeb5Syz 1489ab25eeb5Syz 1490ab25eeb5Syz #if (SOLARIS2 < 7) 1491ab25eeb5Syz void fr_slowtimer() 1492ab25eeb5Syz #else 1493ab25eeb5Syz /*ARGSUSED*/ 1494f4b3ec61Sdh void fr_slowtimer __P((void *arg)) 1495ab25eeb5Syz #endif 1496ab25eeb5Syz { 1497f4b3ec61Sdh ipf_stack_t *ifs = arg; 1498ab25eeb5Syz 149944aaa2b6Sjojemann READ_ENTER(&ifs->ifs_ipf_global); 150044aaa2b6Sjojemann if (ifs->ifs_fr_running != 1) { 150144aaa2b6Sjojemann ifs->ifs_fr_timer_id = NULL; 1502f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 1503ab25eeb5Syz return; 1504ab25eeb5Syz } 1505fd636508Szf ipf_expiretokens(ifs); 1506f4b3ec61Sdh fr_fragexpire(ifs); 1507f4b3ec61Sdh fr_timeoutstate(ifs); 1508f4b3ec61Sdh fr_natexpire(ifs); 1509f4b3ec61Sdh fr_authexpire(ifs); 1510f4b3ec61Sdh ifs->ifs_fr_ticks++; 151144aaa2b6Sjojemann if (ifs->ifs_fr_running == 1) 1512f4b3ec61Sdh ifs->ifs_fr_timer_id = timeout(fr_slowtimer, arg, 1513f4b3ec61Sdh drv_usectohz(500000)); 1514ab25eeb5Syz else 1515f4b3ec61Sdh ifs->ifs_fr_timer_id = NULL; 1516f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 1517ab25eeb5Syz } 1518ab25eeb5Syz 1519ab25eeb5Syz 1520381a2a9aSdr /* ------------------------------------------------------------------------ */ 1521381a2a9aSdr /* Function: fr_pullup */ 1522381a2a9aSdr /* Returns: NULL == pullup failed, else pointer to protocol header */ 1523381a2a9aSdr /* Parameters: m(I) - pointer to buffer where data packet starts */ 1524381a2a9aSdr /* fin(I) - pointer to packet information */ 1525381a2a9aSdr /* len(I) - number of bytes to pullup */ 1526381a2a9aSdr /* */ 1527381a2a9aSdr /* Attempt to move at least len bytes (from the start of the buffer) into a */ 1528381a2a9aSdr /* single buffer for ease of access. Operating system native functions are */ 1529381a2a9aSdr /* used to manage buffers - if necessary. If the entire packet ends up in */ 1530381a2a9aSdr /* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */ 1531381a2a9aSdr /* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ 1532381a2a9aSdr /* and ONLY if the pullup succeeds. */ 1533381a2a9aSdr /* */ 1534381a2a9aSdr /* We assume that 'min' is a pointer to a buffer that is part of the chain */ 1535381a2a9aSdr /* of buffers that starts at *fin->fin_mp. */ 1536381a2a9aSdr /* ------------------------------------------------------------------------ */ 1537381a2a9aSdr void *fr_pullup(min, fin, len) 1538381a2a9aSdr mb_t *min; 1539381a2a9aSdr fr_info_t *fin; 1540381a2a9aSdr int len; 1541381a2a9aSdr { 1542381a2a9aSdr qpktinfo_t *qpi = fin->fin_qpi; 1543381a2a9aSdr int out = fin->fin_out, dpoff, ipoff; 1544381a2a9aSdr mb_t *m = min, *m1, *m2; 1545381a2a9aSdr char *ip; 154608ee25aeSdr uint32_t start, stuff, end, value, flags; 1547f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1548381a2a9aSdr 1549381a2a9aSdr if (m == NULL) 1550381a2a9aSdr return NULL; 1551381a2a9aSdr 1552381a2a9aSdr ip = (char *)fin->fin_ip; 1553381a2a9aSdr if ((fin->fin_flx & FI_COALESCE) != 0) 1554381a2a9aSdr return ip; 1555381a2a9aSdr 1556381a2a9aSdr ipoff = fin->fin_ipoff; 1557381a2a9aSdr if (fin->fin_dp != NULL) 1558381a2a9aSdr dpoff = (char *)fin->fin_dp - (char *)ip; 1559381a2a9aSdr else 1560381a2a9aSdr dpoff = 0; 1561381a2a9aSdr 1562381a2a9aSdr if (M_LEN(m) < len) { 1563381a2a9aSdr 1564381a2a9aSdr /* 1565381a2a9aSdr * pfil_precheck ensures the IP header is on a 32bit 1566381a2a9aSdr * aligned address so simply fail if that isn't currently 1567381a2a9aSdr * the case (should never happen). 1568381a2a9aSdr */ 1569381a2a9aSdr int inc = 0; 1570381a2a9aSdr 1571381a2a9aSdr if (ipoff > 0) { 1572381a2a9aSdr if ((ipoff & 3) != 0) { 1573381a2a9aSdr inc = 4 - (ipoff & 3); 1574381a2a9aSdr if (m->b_rptr - inc >= m->b_datap->db_base) 1575381a2a9aSdr m->b_rptr -= inc; 1576381a2a9aSdr else 1577381a2a9aSdr inc = 0; 1578381a2a9aSdr } 1579381a2a9aSdr } 1580381a2a9aSdr 1581381a2a9aSdr /* 1582381a2a9aSdr * XXX This is here as a work around for a bug with DEBUG 1583381a2a9aSdr * XXX Solaris kernels. The problem is b_prev is used by IP 1584381a2a9aSdr * XXX code as a way to stash the phyint_index for a packet, 1585381a2a9aSdr * XXX this doesn't get reset by IP but freeb does an ASSERT() 1586381a2a9aSdr * XXX for both of these to be NULL. See 6442390. 1587381a2a9aSdr */ 1588381a2a9aSdr m1 = m; 1589381a2a9aSdr m2 = m->b_prev; 1590381a2a9aSdr 1591381a2a9aSdr do { 1592381a2a9aSdr m1->b_next = NULL; 1593381a2a9aSdr m1->b_prev = NULL; 1594381a2a9aSdr m1 = m1->b_cont; 1595381a2a9aSdr } while (m1); 159608ee25aeSdr 159708ee25aeSdr /* 159808ee25aeSdr * Need to preserve checksum information by copying them 159908ee25aeSdr * to newmp which heads the pulluped message. 160008ee25aeSdr */ 160108ee25aeSdr hcksum_retrieve(m, NULL, NULL, &start, &stuff, &end, 160208ee25aeSdr &value, &flags); 160308ee25aeSdr 1604381a2a9aSdr if (pullupmsg(m, len + ipoff + inc) == 0) { 1605f4b3ec61Sdh ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[1]); 1606381a2a9aSdr FREE_MB_T(*fin->fin_mp); 1607381a2a9aSdr *fin->fin_mp = NULL; 1608381a2a9aSdr fin->fin_m = NULL; 1609381a2a9aSdr fin->fin_ip = NULL; 1610381a2a9aSdr fin->fin_dp = NULL; 1611381a2a9aSdr qpi->qpi_data = NULL; 1612381a2a9aSdr return NULL; 1613381a2a9aSdr } 161408ee25aeSdr 161508ee25aeSdr (void) hcksum_assoc(m, NULL, NULL, start, stuff, end, 161608ee25aeSdr value, flags, 0); 161708ee25aeSdr 1618381a2a9aSdr m->b_prev = m2; 1619381a2a9aSdr m->b_rptr += inc; 1620381a2a9aSdr fin->fin_m = m; 1621381a2a9aSdr ip = MTOD(m, char *) + ipoff; 1622381a2a9aSdr qpi->qpi_data = ip; 1623381a2a9aSdr } 1624381a2a9aSdr 1625f4b3ec61Sdh ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[0]); 1626381a2a9aSdr fin->fin_ip = (ip_t *)ip; 1627381a2a9aSdr if (fin->fin_dp != NULL) 1628381a2a9aSdr fin->fin_dp = (char *)fin->fin_ip + dpoff; 1629381a2a9aSdr 1630381a2a9aSdr if (len == fin->fin_plen) 1631381a2a9aSdr fin->fin_flx |= FI_COALESCE; 1632381a2a9aSdr return ip; 1633381a2a9aSdr } 1634381a2a9aSdr 1635381a2a9aSdr 1636ab25eeb5Syz /* 1637381a2a9aSdr * Function: fr_verifysrc 1638381a2a9aSdr * Returns: int (really boolean) 1639381a2a9aSdr * Parameters: fin - packet information 1640381a2a9aSdr * 1641381a2a9aSdr * Check whether the packet has a valid source address for the interface on 1642381a2a9aSdr * which the packet arrived, implementing the "fr_chksrc" feature. 1643381a2a9aSdr * Returns true iff the packet's source address is valid. 1644381a2a9aSdr */ 1645381a2a9aSdr int fr_verifysrc(fin) 1646381a2a9aSdr fr_info_t *fin; 1647381a2a9aSdr { 1648381a2a9aSdr net_data_t net_data_p; 1649381a2a9aSdr phy_if_t phy_ifdata_routeto; 1650381a2a9aSdr struct sockaddr sin; 1651f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1652381a2a9aSdr 1653381a2a9aSdr if (fin->fin_v == 4) { 1654f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv4; 1655381a2a9aSdr } else if (fin->fin_v == 6) { 1656f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv6; 1657381a2a9aSdr } else { 1658381a2a9aSdr return (0); 1659381a2a9aSdr } 1660381a2a9aSdr 1661381a2a9aSdr /* Get the index corresponding to the if name */ 1662381a2a9aSdr sin.sa_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 1663381a2a9aSdr bcopy(&fin->fin_saddr, &sin.sa_data, sizeof (struct in_addr)); 1664381a2a9aSdr phy_ifdata_routeto = net_routeto(net_data_p, &sin); 1665381a2a9aSdr 1666381a2a9aSdr return (((phy_if_t)fin->fin_ifp == phy_ifdata_routeto) ? 1 : 0); 1667381a2a9aSdr } 1668381a2a9aSdr 1669381a2a9aSdr 1670381a2a9aSdr /* 1671381a2a9aSdr * Function: fr_fastroute 1672381a2a9aSdr * Returns: 0: success; 1673381a2a9aSdr * -1: failed 1674ab25eeb5Syz * Parameters: 1675381a2a9aSdr * mb: the message block where ip head starts 1676381a2a9aSdr * mpp: the pointer to the pointer of the orignal 1677381a2a9aSdr * packet message 1678381a2a9aSdr * fin: packet information 1679381a2a9aSdr * fdp: destination interface information 1680381a2a9aSdr * if it is NULL, no interface information provided. 1681ab25eeb5Syz * 1682ab25eeb5Syz * This function is for fastroute/to/dup-to rules. It calls 1683ab25eeb5Syz * pfil_make_lay2_packet to search route, make lay-2 header 1684ab25eeb5Syz * ,and identify output queue for the IP packet. 1685ab25eeb5Syz * The destination address depends on the following conditions: 1686ab25eeb5Syz * 1: for fastroute rule, fdp is passed in as NULL, so the 1687381a2a9aSdr * destination address is the IP Packet's destination address 1688ab25eeb5Syz * 2: for to/dup-to rule, if an ip address is specified after 1689381a2a9aSdr * the interface name, this address is the as destination 1690381a2a9aSdr * address. Otherwise IP Packet's destination address is used 1691ab25eeb5Syz */ 1692ab25eeb5Syz int fr_fastroute(mb, mpp, fin, fdp) 1693ab25eeb5Syz mblk_t *mb, **mpp; 1694ab25eeb5Syz fr_info_t *fin; 1695ab25eeb5Syz frdest_t *fdp; 1696ab25eeb5Syz { 1697381a2a9aSdr net_data_t net_data_p; 1698381a2a9aSdr net_inject_t inj_data; 1699ab25eeb5Syz mblk_t *mp = NULL; 1700381a2a9aSdr frentry_t *fr = fin->fin_fr; 1701ab25eeb5Syz qpktinfo_t *qpi; 1702ab25eeb5Syz ip_t *ip; 1703381a2a9aSdr 1704381a2a9aSdr struct sockaddr_in *sin; 1705381a2a9aSdr struct sockaddr_in6 *sin6; 1706381a2a9aSdr struct sockaddr *sinp; 1707f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1708ab25eeb5Syz #ifndef sparc 1709ab25eeb5Syz u_short __iplen, __ipoff; 1710ab25eeb5Syz #endif 1711381a2a9aSdr 1712381a2a9aSdr if (fin->fin_v == 4) { 1713f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv4; 1714381a2a9aSdr } else if (fin->fin_v == 6) { 1715f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv6; 1716381a2a9aSdr } else { 1717381a2a9aSdr return (-1); 1718381a2a9aSdr } 1719381a2a9aSdr 1720ab25eeb5Syz ip = fin->fin_ip; 1721ab25eeb5Syz qpi = fin->fin_qpi; 1722ab25eeb5Syz 1723ab25eeb5Syz /* 1724ab25eeb5Syz * If this is a duplicate mblk then we want ip to point at that 1725ab25eeb5Syz * data, not the original, if and only if it is already pointing at 1726ab25eeb5Syz * the current mblk data. 1727381a2a9aSdr * 1728381a2a9aSdr * Otherwise, if it's not a duplicate, and we're not already pointing 1729e6c6c1faSyz * at the current mblk data, then we want to ensure that the data 1730e6c6c1faSyz * points at ip. 1731ab25eeb5Syz */ 1732381a2a9aSdr 1733381a2a9aSdr if ((ip == (ip_t *)qpi->qpi_m->b_rptr) && (qpi->qpi_m != mb)) { 1734ab25eeb5Syz ip = (ip_t *)mb->b_rptr; 1735381a2a9aSdr } else if ((qpi->qpi_m == mb) && (ip != (ip_t *)qpi->qpi_m->b_rptr)) { 1736381a2a9aSdr qpi->qpi_m->b_rptr = (uchar_t *)ip; 1737e6c6c1faSyz qpi->qpi_off = 0; 1738e6c6c1faSyz } 1739ab25eeb5Syz 1740ab25eeb5Syz /* 1741ab25eeb5Syz * If there is another M_PROTO, we don't want it 1742ab25eeb5Syz */ 1743ab25eeb5Syz if (*mpp != mb) { 1744ab25eeb5Syz mp = unlinkb(*mpp); 1745ab25eeb5Syz freeb(*mpp); 1746ab25eeb5Syz *mpp = mp; 1747ab25eeb5Syz } 1748ab25eeb5Syz 1749381a2a9aSdr sinp = (struct sockaddr *)&inj_data.ni_addr; 1750381a2a9aSdr sin = (struct sockaddr_in *)sinp; 1751381a2a9aSdr sin6 = (struct sockaddr_in6 *)sinp; 1752381a2a9aSdr bzero((char *)&inj_data.ni_addr, sizeof (inj_data.ni_addr)); 1753381a2a9aSdr inj_data.ni_addr.ss_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 1754381a2a9aSdr inj_data.ni_packet = mb; 1755ab25eeb5Syz 1756ab25eeb5Syz /* 1757ab25eeb5Syz * In case we're here due to "to <if>" being used with 1758ab25eeb5Syz * "keep state", check that we're going in the correct 1759ab25eeb5Syz * direction. 1760ab25eeb5Syz */ 1761381a2a9aSdr if (fdp != NULL) { 1762381a2a9aSdr if ((fr != NULL) && (fdp->fd_ifp != NULL) && 1763381a2a9aSdr (fin->fin_rev != 0) && (fdp == &fr->fr_tif)) 1764381a2a9aSdr goto bad_fastroute; 1765381a2a9aSdr inj_data.ni_physical = (phy_if_t)fdp->fd_ifp; 1766ab25eeb5Syz if (fin->fin_v == 4) { 1767381a2a9aSdr sin->sin_addr = fdp->fd_ip; 1768381a2a9aSdr } else { 1769381a2a9aSdr sin6->sin6_addr = fdp->fd_ip6.in6; 1770ab25eeb5Syz } 1771381a2a9aSdr } else { 1772381a2a9aSdr if (fin->fin_v == 4) { 1773381a2a9aSdr sin->sin_addr = ip->ip_dst; 1774381a2a9aSdr } else { 1775381a2a9aSdr sin6->sin6_addr = ((ip6_t *)ip)->ip6_dst; 1776ab25eeb5Syz } 1777381a2a9aSdr inj_data.ni_physical = net_routeto(net_data_p, sinp); 1778ab25eeb5Syz } 1779ab25eeb5Syz 1780edd26dc5Sdr /* 1781edd26dc5Sdr * Clear the hardware checksum flags from packets that we are doing 1782edd26dc5Sdr * input processing on as leaving them set will cause the outgoing 1783edd26dc5Sdr * NIC (if it supports hardware checksum) to calculate them anew, 1784edd26dc5Sdr * using the old (correct) checksums as the pseudo value to start 1785edd26dc5Sdr * from. 1786edd26dc5Sdr */ 1787edd26dc5Sdr if (fin->fin_out == 0) { 1788edd26dc5Sdr DB_CKSUMFLAGS(mb) = 0; 1789edd26dc5Sdr } 1790c793af95Ssangeeta 1791381a2a9aSdr *mpp = mb; 1792ab25eeb5Syz 1793381a2a9aSdr if (fin->fin_out == 0) { 1794381a2a9aSdr void *saveifp; 1795381a2a9aSdr u_32_t pass; 1796ab25eeb5Syz 1797381a2a9aSdr saveifp = fin->fin_ifp; 1798381a2a9aSdr fin->fin_ifp = (void *)inj_data.ni_physical; 1799d3675867Sjojemann fin->fin_flx &= ~FI_STATE; 1800381a2a9aSdr fin->fin_out = 1; 1801381a2a9aSdr (void) fr_acctpkt(fin, &pass); 1802381a2a9aSdr fin->fin_fr = NULL; 1803381a2a9aSdr if (!fr || !(fr->fr_flags & FR_RETMASK)) 1804381a2a9aSdr (void) fr_checkstate(fin, &pass); 1805d3675867Sjojemann if (fr_checknatout(fin, NULL) == -1) 1806381a2a9aSdr goto bad_fastroute; 1807381a2a9aSdr fin->fin_out = 0; 1808381a2a9aSdr fin->fin_ifp = saveifp; 1809ab25eeb5Syz 1810381a2a9aSdr if (fin->fin_nat != NULL) 1811f4b3ec61Sdh fr_natderef((nat_t **)&fin->fin_nat, ifs); 1812381a2a9aSdr } 1813381a2a9aSdr #ifndef sparc 1814381a2a9aSdr if (fin->fin_v == 4) { 1815381a2a9aSdr __iplen = (u_short)ip->ip_len, 1816381a2a9aSdr __ipoff = (u_short)ip->ip_off; 1817ab25eeb5Syz 1818381a2a9aSdr ip->ip_len = htons(__iplen); 1819381a2a9aSdr ip->ip_off = htons(__ipoff); 1820381a2a9aSdr } 1821ab25eeb5Syz #endif 1822381a2a9aSdr 1823381a2a9aSdr if (net_data_p) { 1824381a2a9aSdr if (net_inject(net_data_p, NI_DIRECT_OUT, &inj_data) < 0) { 1825381a2a9aSdr return (-1); 1826ab25eeb5Syz } 1827ab25eeb5Syz } 1828381a2a9aSdr 1829f4b3ec61Sdh ifs->ifs_fr_frouteok[0]++; 1830381a2a9aSdr return 0; 1831ab25eeb5Syz bad_fastroute: 1832ab25eeb5Syz freemsg(mb); 1833f4b3ec61Sdh ifs->ifs_fr_frouteok[1]++; 1834ab25eeb5Syz return -1; 1835ab25eeb5Syz } 1836ab25eeb5Syz 1837ab25eeb5Syz 1838ab25eeb5Syz /* ------------------------------------------------------------------------ */ 1839381a2a9aSdr /* Function: ipf_hook_out */ 1840381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1841381a2a9aSdr /* Parameters: event(I) - pointer to event */ 1842381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 1843ab25eeb5Syz /* */ 1844381a2a9aSdr /* Calling ipf_hook. */ 1845381a2a9aSdr /* ------------------------------------------------------------------------ */ 1846381a2a9aSdr /*ARGSUSED*/ 1847cbded9aeSdr int ipf_hook4_out(hook_event_token_t token, hook_data_t info, netstack_t *ns) 1848381a2a9aSdr { 1849cbded9aeSdr return ipf_hook4(info, 1, 0, ns); 1850cbded9aeSdr } 1851cbded9aeSdr /*ARGSUSED*/ 1852cbded9aeSdr int ipf_hook6_out(hook_event_token_t token, hook_data_t info, netstack_t *ns) 1853cbded9aeSdr { 1854cbded9aeSdr return ipf_hook6(info, 1, 0, ns); 1855381a2a9aSdr } 1856381a2a9aSdr 1857381a2a9aSdr /* ------------------------------------------------------------------------ */ 1858381a2a9aSdr /* Function: ipf_hook_in */ 1859381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1860381a2a9aSdr /* Parameters: event(I) - pointer to event */ 1861381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 1862ab25eeb5Syz /* */ 1863381a2a9aSdr /* Calling ipf_hook. */ 1864ab25eeb5Syz /* ------------------------------------------------------------------------ */ 1865381a2a9aSdr /*ARGSUSED*/ 1866cbded9aeSdr int ipf_hook4_in(hook_event_token_t token, hook_data_t info, netstack_t *ns) 1867ab25eeb5Syz { 1868cbded9aeSdr return ipf_hook4(info, 0, 0, ns); 1869cbded9aeSdr } 1870cbded9aeSdr /*ARGSUSED*/ 1871cbded9aeSdr int ipf_hook6_in(hook_event_token_t token, hook_data_t info, netstack_t *ns) 1872cbded9aeSdr { 1873cbded9aeSdr return ipf_hook6(info, 0, 0, ns); 1874381a2a9aSdr } 1875ab25eeb5Syz 1876ab25eeb5Syz 1877381a2a9aSdr /* ------------------------------------------------------------------------ */ 1878381a2a9aSdr /* Function: ipf_hook_loop_out */ 1879381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1880381a2a9aSdr /* Parameters: event(I) - pointer to event */ 1881381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 1882381a2a9aSdr /* */ 1883381a2a9aSdr /* Calling ipf_hook. */ 1884381a2a9aSdr /* ------------------------------------------------------------------------ */ 1885381a2a9aSdr /*ARGSUSED*/ 1886cbded9aeSdr int ipf_hook4_loop_out(hook_event_token_t token, hook_data_t info, 1887cbded9aeSdr netstack_t *ns) 1888cbded9aeSdr { 1889cbded9aeSdr return ipf_hook4(info, 1, FI_NOCKSUM, ns); 1890cbded9aeSdr } 1891cbded9aeSdr /*ARGSUSED*/ 1892cbded9aeSdr int ipf_hook6_loop_out(hook_event_token_t token, hook_data_t info, 1893f4b3ec61Sdh netstack_t *ns) 1894381a2a9aSdr { 1895cbded9aeSdr return ipf_hook6(info, 1, FI_NOCKSUM, ns); 1896381a2a9aSdr } 1897ab25eeb5Syz 1898381a2a9aSdr /* ------------------------------------------------------------------------ */ 1899381a2a9aSdr /* Function: ipf_hook_loop_in */ 1900381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1901381a2a9aSdr /* Parameters: event(I) - pointer to event */ 1902381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 1903381a2a9aSdr /* */ 1904381a2a9aSdr /* Calling ipf_hook. */ 1905381a2a9aSdr /* ------------------------------------------------------------------------ */ 1906381a2a9aSdr /*ARGSUSED*/ 1907cbded9aeSdr int ipf_hook4_loop_in(hook_event_token_t token, hook_data_t info, 1908cbded9aeSdr netstack_t *ns) 1909cbded9aeSdr { 1910cbded9aeSdr return ipf_hook4(info, 0, FI_NOCKSUM, ns); 1911cbded9aeSdr } 1912cbded9aeSdr /*ARGSUSED*/ 1913cbded9aeSdr int ipf_hook6_loop_in(hook_event_token_t token, hook_data_t info, 1914f4b3ec61Sdh netstack_t *ns) 1915381a2a9aSdr { 1916cbded9aeSdr return ipf_hook6(info, 0, FI_NOCKSUM, ns); 1917381a2a9aSdr } 1918381a2a9aSdr 1919381a2a9aSdr /* ------------------------------------------------------------------------ */ 1920381a2a9aSdr /* Function: ipf_hook */ 1921381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1922381a2a9aSdr /* Parameters: info(I) - pointer to hook information for firewalling */ 1923381a2a9aSdr /* out(I) - whether packet is going in or out */ 1924381a2a9aSdr /* loopback(I) - whether packet is a loopback packet or not */ 1925381a2a9aSdr /* */ 1926381a2a9aSdr /* Stepping stone function between the IP mainline and IPFilter. Extracts */ 1927381a2a9aSdr /* parameters out of the info structure and forms them up to be useful for */ 1928381a2a9aSdr /* calling ipfilter. */ 1929381a2a9aSdr /* ------------------------------------------------------------------------ */ 1930cbded9aeSdr int ipf_hook4(hook_data_t info, int out, int loopback, netstack_t *ns) 1931381a2a9aSdr { 1932381a2a9aSdr hook_pkt_event_t *fw; 1933cbded9aeSdr int rval, hlen; 1934381a2a9aSdr qpktinfo_t qpi; 1935381a2a9aSdr u_short swap; 1936381a2a9aSdr phy_if_t phy; 1937381a2a9aSdr ip_t *ip; 1938381a2a9aSdr 1939381a2a9aSdr fw = (hook_pkt_event_t *)info; 1940381a2a9aSdr 1941381a2a9aSdr ASSERT(fw != NULL); 1942381a2a9aSdr phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp; 1943381a2a9aSdr 1944381a2a9aSdr ip = fw->hpe_hdr; 1945cbded9aeSdr swap = ntohs(ip->ip_len); 1946cbded9aeSdr ip->ip_len = swap; 1947cbded9aeSdr swap = ntohs(ip->ip_off); 1948cbded9aeSdr ip->ip_off = swap; 1949cbded9aeSdr hlen = IPH_HDR_LENGTH(ip); 1950381a2a9aSdr 1951381a2a9aSdr qpi.qpi_m = fw->hpe_mb; 1952381a2a9aSdr qpi.qpi_data = fw->hpe_hdr; 1953381a2a9aSdr qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr; 1954381a2a9aSdr qpi.qpi_ill = (void *)phy; 1955cbded9aeSdr qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST); 1956cbded9aeSdr if (qpi.qpi_flags) 1957cbded9aeSdr qpi.qpi_flags |= FI_MBCAST; 1958cbded9aeSdr qpi.qpi_flags |= loopback; 1959381a2a9aSdr 1960f4b3ec61Sdh rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, 1961f4b3ec61Sdh &qpi, fw->hpe_mp, ns->netstack_ipf); 1962381a2a9aSdr 1963381a2a9aSdr /* For fastroute cases, fr_check returns 0 with mp set to NULL */ 1964381a2a9aSdr if (rval == 0 && *(fw->hpe_mp) == NULL) 1965381a2a9aSdr rval = 1; 1966381a2a9aSdr 1967cbded9aeSdr /* Notify IP the packet mblk_t and IP header pointers. */ 1968381a2a9aSdr fw->hpe_mb = qpi.qpi_m; 1969381a2a9aSdr fw->hpe_hdr = qpi.qpi_data; 1970cbded9aeSdr if (rval == 0) { 1971381a2a9aSdr ip = qpi.qpi_data; 1972381a2a9aSdr swap = ntohs(ip->ip_len); 1973381a2a9aSdr ip->ip_len = swap; 1974381a2a9aSdr swap = ntohs(ip->ip_off); 1975381a2a9aSdr ip->ip_off = swap; 1976381a2a9aSdr } 1977381a2a9aSdr return rval; 1978ab25eeb5Syz 1979381a2a9aSdr } 1980cbded9aeSdr int ipf_hook6(hook_data_t info, int out, int loopback, netstack_t *ns) 1981cbded9aeSdr { 1982cbded9aeSdr hook_pkt_event_t *fw; 1983cbded9aeSdr int rval, hlen; 1984cbded9aeSdr qpktinfo_t qpi; 1985cbded9aeSdr phy_if_t phy; 1986cbded9aeSdr 1987cbded9aeSdr fw = (hook_pkt_event_t *)info; 1988cbded9aeSdr 1989cbded9aeSdr ASSERT(fw != NULL); 1990cbded9aeSdr phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp; 1991cbded9aeSdr 1992cbded9aeSdr hlen = sizeof (ip6_t); 1993cbded9aeSdr 1994cbded9aeSdr qpi.qpi_m = fw->hpe_mb; 1995cbded9aeSdr qpi.qpi_data = fw->hpe_hdr; 1996cbded9aeSdr qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr; 1997cbded9aeSdr qpi.qpi_ill = (void *)phy; 1998cbded9aeSdr qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST); 1999cbded9aeSdr if (qpi.qpi_flags) 2000cbded9aeSdr qpi.qpi_flags |= FI_MBCAST; 2001cbded9aeSdr qpi.qpi_flags |= loopback; 2002cbded9aeSdr 2003cbded9aeSdr rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, 2004cbded9aeSdr &qpi, fw->hpe_mp, ns->netstack_ipf); 2005cbded9aeSdr 2006cbded9aeSdr /* For fastroute cases, fr_check returns 0 with mp set to NULL */ 2007cbded9aeSdr if (rval == 0 && *(fw->hpe_mp) == NULL) 2008cbded9aeSdr rval = 1; 2009cbded9aeSdr 2010cbded9aeSdr /* Notify IP the packet mblk_t and IP header pointers. */ 2011cbded9aeSdr fw->hpe_mb = qpi.qpi_m; 2012cbded9aeSdr fw->hpe_hdr = qpi.qpi_data; 2013cbded9aeSdr return rval; 2014cbded9aeSdr 2015cbded9aeSdr } 2016ab25eeb5Syz 2017ab25eeb5Syz 2018381a2a9aSdr /* ------------------------------------------------------------------------ */ 2019381a2a9aSdr /* Function: ipf_nic_event_v4 */ 2020381a2a9aSdr /* Returns: int - 0 == no problems encountered */ 2021381a2a9aSdr /* Parameters: event(I) - pointer to event */ 2022381a2a9aSdr /* info(I) - pointer to information about a NIC event */ 2023381a2a9aSdr /* */ 2024381a2a9aSdr /* Function to receive asynchronous NIC events from IP */ 2025381a2a9aSdr /* ------------------------------------------------------------------------ */ 2026381a2a9aSdr /*ARGSUSED*/ 2027f4b3ec61Sdh int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info, 2028f4b3ec61Sdh netstack_t *ns) 2029381a2a9aSdr { 2030381a2a9aSdr struct sockaddr_in *sin; 2031381a2a9aSdr hook_nic_event_t *hn; 2032f4b3ec61Sdh ipf_stack_t *ifs = ns->netstack_ipf; 2033381a2a9aSdr 2034381a2a9aSdr hn = (hook_nic_event_t *)info; 2035381a2a9aSdr 2036381a2a9aSdr switch (hn->hne_event) 2037381a2a9aSdr { 2038381a2a9aSdr case NE_PLUMB : 2039a4cf92b0Sdr frsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, hn->hne_data, 2040d6c23f6fSyx ifs); 2041d6c23f6fSyx fr_natifpsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, 2042f4b3ec61Sdh hn->hne_data, ifs); 2043381a2a9aSdr fr_statesync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, 2044f4b3ec61Sdh hn->hne_data, ifs); 2045381a2a9aSdr break; 2046381a2a9aSdr 2047381a2a9aSdr case NE_UNPLUMB : 2048f4b3ec61Sdh frsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 2049d6c23f6fSyx fr_natifpsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, 2050d6c23f6fSyx ifs); 2051f4b3ec61Sdh fr_statesync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 2052381a2a9aSdr break; 2053381a2a9aSdr 2054381a2a9aSdr case NE_ADDRESS_CHANGE : 2055a4cf92b0Sdr /* 2056a4cf92b0Sdr * We only respond to events for logical interface 0 because 2057a4cf92b0Sdr * IPFilter only uses the first address given to a network 2058a4cf92b0Sdr * interface. We check for hne_lif==1 because the netinfo 2059a4cf92b0Sdr * code maps adds 1 to the lif number so that it can return 2060a4cf92b0Sdr * 0 to indicate "no more lifs" when walking them. 2061a4cf92b0Sdr */ 2062a4cf92b0Sdr if (hn->hne_lif == 1) { 2063a4cf92b0Sdr frsync(IPFSYNC_RESYNC, 4, (void *)hn->hne_nic, NULL, 2064a4cf92b0Sdr ifs); 2065a4cf92b0Sdr sin = hn->hne_data; 2066d6c23f6fSyx fr_nataddrsync(4, (void *)hn->hne_nic, &sin->sin_addr, 2067a4cf92b0Sdr ifs); 2068a4cf92b0Sdr } 2069381a2a9aSdr break; 2070381a2a9aSdr 2071381a2a9aSdr default : 2072381a2a9aSdr break; 2073ab25eeb5Syz } 2074ab25eeb5Syz 2075381a2a9aSdr return 0; 2076381a2a9aSdr } 2077ab25eeb5Syz 2078381a2a9aSdr 2079381a2a9aSdr /* ------------------------------------------------------------------------ */ 2080381a2a9aSdr /* Function: ipf_nic_event_v6 */ 2081381a2a9aSdr /* Returns: int - 0 == no problems encountered */ 2082381a2a9aSdr /* Parameters: event(I) - pointer to event */ 2083381a2a9aSdr /* info(I) - pointer to information about a NIC event */ 2084381a2a9aSdr /* */ 2085381a2a9aSdr /* Function to receive asynchronous NIC events from IP */ 2086381a2a9aSdr /* ------------------------------------------------------------------------ */ 2087381a2a9aSdr /*ARGSUSED*/ 2088f4b3ec61Sdh int ipf_nic_event_v6(hook_event_token_t event, hook_data_t info, 2089f4b3ec61Sdh netstack_t *ns) 2090381a2a9aSdr { 2091d6c23f6fSyx struct sockaddr_in6 *sin6; 2092381a2a9aSdr hook_nic_event_t *hn; 2093f4b3ec61Sdh ipf_stack_t *ifs = ns->netstack_ipf; 2094381a2a9aSdr 2095381a2a9aSdr hn = (hook_nic_event_t *)info; 2096381a2a9aSdr 2097381a2a9aSdr switch (hn->hne_event) 2098381a2a9aSdr { 2099381a2a9aSdr case NE_PLUMB : 2100d6c23f6fSyx frsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2101d6c23f6fSyx hn->hne_data, ifs); 2102d6c23f6fSyx fr_natifpsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2103d6c23f6fSyx hn->hne_data, ifs); 2104381a2a9aSdr fr_statesync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2105f4b3ec61Sdh hn->hne_data, ifs); 2106381a2a9aSdr break; 2107381a2a9aSdr 2108381a2a9aSdr case NE_UNPLUMB : 2109f4b3ec61Sdh frsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2110d6c23f6fSyx fr_natifpsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, 2111d6c23f6fSyx ifs); 2112f4b3ec61Sdh fr_statesync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2113381a2a9aSdr break; 2114381a2a9aSdr 2115381a2a9aSdr case NE_ADDRESS_CHANGE : 2116d6c23f6fSyx if (hn->hne_lif == 1) { 2117d6c23f6fSyx sin6 = hn->hne_data; 2118d6c23f6fSyx fr_nataddrsync(6, (void *)hn->hne_nic, &sin6->sin6_addr, 2119d6c23f6fSyx ifs); 2120d6c23f6fSyx } 2121381a2a9aSdr break; 2122381a2a9aSdr default : 2123381a2a9aSdr break; 2124381a2a9aSdr } 2125381a2a9aSdr 2126381a2a9aSdr return 0; 2127ab25eeb5Syz } 2128