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 #pragma ident "%Z%%M% %I% %E% SMI" 117c478bd9Sstevel@tonic-gate 127c478bd9Sstevel@tonic-gate #if !defined(lint) 13c793af95Ssangeeta static const char sccsid[] = "@(#)ip_fil_solaris.c 1.7 07/22/06 (C) 1993-2000 Darren Reed"; 14ab25eeb5Syz static const char rcsid[] = "@(#)$Id: ip_fil_solaris.c,v 2.62.2.19 2005/07/13 21:40:46 darrenr Exp $"; 157c478bd9Sstevel@tonic-gate #endif 167c478bd9Sstevel@tonic-gate 177c478bd9Sstevel@tonic-gate #include <sys/types.h> 187c478bd9Sstevel@tonic-gate #include <sys/errno.h> 197c478bd9Sstevel@tonic-gate #include <sys/param.h> 207c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 217c478bd9Sstevel@tonic-gate #include <sys/open.h> 227c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 237c478bd9Sstevel@tonic-gate #include <sys/filio.h> 247c478bd9Sstevel@tonic-gate #include <sys/systm.h> 25ab25eeb5Syz #include <sys/strsubr.h> 267c478bd9Sstevel@tonic-gate #include <sys/cred.h> 27f4b3ec61Sdh #include <sys/cred_impl.h> 287c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 297c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 307c478bd9Sstevel@tonic-gate #include <sys/ksynch.h> 317c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 327c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 337c478bd9Sstevel@tonic-gate #include <sys/protosw.h> 347c478bd9Sstevel@tonic-gate #include <sys/socket.h> 357c478bd9Sstevel@tonic-gate #include <sys/dditypes.h> 367c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 37f4b3ec61Sdh #include <sys/zone.h> 387c478bd9Sstevel@tonic-gate #include <net/if.h> 397c478bd9Sstevel@tonic-gate #include <net/af.h> 407c478bd9Sstevel@tonic-gate #include <net/route.h> 417c478bd9Sstevel@tonic-gate #include <netinet/in.h> 427c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h> 437c478bd9Sstevel@tonic-gate #include <netinet/ip.h> 447c478bd9Sstevel@tonic-gate #include <netinet/ip_var.h> 457c478bd9Sstevel@tonic-gate #include <netinet/tcp.h> 467c478bd9Sstevel@tonic-gate #include <netinet/udp.h> 477c478bd9Sstevel@tonic-gate #include <netinet/tcpip.h> 487c478bd9Sstevel@tonic-gate #include <netinet/ip_icmp.h> 49ab25eeb5Syz #include "netinet/ip_compat.h" 507c478bd9Sstevel@tonic-gate #ifdef USE_INET6 517c478bd9Sstevel@tonic-gate # include <netinet/icmp6.h> 527c478bd9Sstevel@tonic-gate #endif 53ab25eeb5Syz #include "netinet/ip_fil.h" 54ab25eeb5Syz #include "netinet/ip_nat.h" 55ab25eeb5Syz #include "netinet/ip_frag.h" 56ab25eeb5Syz #include "netinet/ip_state.h" 57ab25eeb5Syz #include "netinet/ip_auth.h" 58ab25eeb5Syz #include "netinet/ip_proxy.h" 59f4b3ec61Sdh #include "netinet/ipf_stack.h" 607c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOOKUP 61ab25eeb5Syz # include "netinet/ip_lookup.h" 627c478bd9Sstevel@tonic-gate #endif 637c478bd9Sstevel@tonic-gate #include <inet/ip_ire.h> 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate #include <sys/md5.h> 66381a2a9aSdr #include <sys/neti.h> 677c478bd9Sstevel@tonic-gate 68f4b3ec61Sdh static int frzerostats __P((caddr_t, ipf_stack_t *)); 69f4b3ec61Sdh static int fr_setipfloopback __P((int, ipf_stack_t *)); 70882bd30bSdr static int fr_enableipf __P((ipf_stack_t *, netstack_t *, int)); 71ab25eeb5Syz static int fr_send_ip __P((fr_info_t *fin, mblk_t *m, mblk_t **mp)); 72f4b3ec61Sdh static int ipf_nic_event_v4 __P((hook_event_token_t, hook_data_t, 73f4b3ec61Sdh netstack_t *)); 74f4b3ec61Sdh static int ipf_nic_event_v6 __P((hook_event_token_t, hook_data_t, 75f4b3ec61Sdh netstack_t *)); 76f4b3ec61Sdh static int ipf_hook_out __P((hook_event_token_t, hook_data_t, 77f4b3ec61Sdh netstack_t *)); 78f4b3ec61Sdh static int ipf_hook_in __P((hook_event_token_t, hook_data_t, 79f4b3ec61Sdh netstack_t *)); 80f4b3ec61Sdh static int ipf_hook_loop_out __P((hook_event_token_t, hook_data_t, 81f4b3ec61Sdh netstack_t *)); 82f4b3ec61Sdh static int ipf_hook_loop_in __P((hook_event_token_t, hook_data_t, 83f4b3ec61Sdh netstack_t *)); 84f4b3ec61Sdh static int ipf_hook __P((hook_data_t, int, int, netstack_t *)); 85f4b3ec61Sdh extern int ipf_geniter __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *)); 86f4b3ec61Sdh extern int ipf_frruleiter __P((void *, int, void *, ipf_stack_t *)); 87f4b3ec61Sdh 887c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 897c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 7 90ab25eeb5Syz u_int *ip_ttl_ptr = NULL; 91ab25eeb5Syz u_int *ip_mtudisc = NULL; 927c478bd9Sstevel@tonic-gate # if SOLARIS2 >= 8 93ab25eeb5Syz int *ip_forwarding = NULL; 94ab25eeb5Syz u_int *ip6_forwarding = NULL; 957c478bd9Sstevel@tonic-gate # else 96ab25eeb5Syz u_int *ip_forwarding = NULL; 977c478bd9Sstevel@tonic-gate # endif 987c478bd9Sstevel@tonic-gate #else 99ab25eeb5Syz u_long *ip_ttl_ptr = NULL; 100ab25eeb5Syz u_long *ip_mtudisc = NULL; 101ab25eeb5Syz u_long *ip_forwarding = NULL; 1027c478bd9Sstevel@tonic-gate #endif 1037c478bd9Sstevel@tonic-gate #endif 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 1077c478bd9Sstevel@tonic-gate /* Function: ipldetach */ 1087c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, else error. */ 1097c478bd9Sstevel@tonic-gate /* Parameters: Nil */ 1107c478bd9Sstevel@tonic-gate /* */ 1117c478bd9Sstevel@tonic-gate /* This function is responsible for undoing anything that might have been */ 1127c478bd9Sstevel@tonic-gate /* done in a call to iplattach(). It must be able to clean up from a call */ 1137c478bd9Sstevel@tonic-gate /* to iplattach() that did not succeed. Why might that happen? Someone */ 1147c478bd9Sstevel@tonic-gate /* configures a table to be so large that we cannot allocate enough memory */ 1157c478bd9Sstevel@tonic-gate /* for it. */ 1167c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 117f4b3ec61Sdh int ipldetach(ifs) 118f4b3ec61Sdh ipf_stack_t *ifs; 1197c478bd9Sstevel@tonic-gate { 1207c478bd9Sstevel@tonic-gate 121f4b3ec61Sdh ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0); 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 1247c478bd9Sstevel@tonic-gate 125f4b3ec61Sdh if (ifs->ifs_fr_control_forwarding & 2) { 126ab25eeb5Syz if (ip_forwarding != NULL) 127ab25eeb5Syz *ip_forwarding = 0; 1287c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 129ab25eeb5Syz if (ip6_forwarding != NULL) 130ab25eeb5Syz *ip6_forwarding = 0; 1317c478bd9Sstevel@tonic-gate #endif 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate #endif 1347c478bd9Sstevel@tonic-gate 135381a2a9aSdr /* 136381a2a9aSdr * This lock needs to be dropped around the net_unregister_hook calls 137381a2a9aSdr * because we can deadlock here with: 138381a2a9aSdr * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs 139381a2a9aSdr * R(hook_family)->R(hei_lock)->R(ipf_global) (active hook running) 140381a2a9aSdr */ 141f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 142381a2a9aSdr 143381a2a9aSdr /* 144381a2a9aSdr * Remove IPv6 Hooks 145381a2a9aSdr */ 146f4b3ec61Sdh if (ifs->ifs_ipf_ipv6 != NULL) { 147f4b3ec61Sdh if (ifs->ifs_hook6_physical_in) { 148f4b3ec61Sdh ifs->ifs_hook6_physical_in = (net_unregister_hook(ifs->ifs_ipf_ipv6, 149f4b3ec61Sdh NH_PHYSICAL_IN, &ifs->ifs_ipfhook_in) != 0); 150381a2a9aSdr } 151f4b3ec61Sdh if (ifs->ifs_hook6_physical_out) { 152f4b3ec61Sdh ifs->ifs_hook6_physical_out = 153f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv6, 154f4b3ec61Sdh NH_PHYSICAL_OUT, &ifs->ifs_ipfhook_out) != 0); 155381a2a9aSdr } 156f4b3ec61Sdh if (ifs->ifs_hook6_nic_events) { 157f4b3ec61Sdh ifs->ifs_hook6_nic_events = 158f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv6, 159f4b3ec61Sdh NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) != 0); 160381a2a9aSdr } 161f4b3ec61Sdh if (ifs->ifs_hook6_loopback_in) { 162f4b3ec61Sdh ifs->ifs_hook6_loopback_in = 163f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv6, 164f4b3ec61Sdh NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) != 0); 165381a2a9aSdr } 166f4b3ec61Sdh if (ifs->ifs_hook6_loopback_out) { 167f4b3ec61Sdh ifs->ifs_hook6_loopback_out = 168f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv6, 169f4b3ec61Sdh NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) != 0); 170381a2a9aSdr } 171381a2a9aSdr 172f4b3ec61Sdh if (net_release(ifs->ifs_ipf_ipv6) != 0) 173381a2a9aSdr goto detach_failed; 174f4b3ec61Sdh ifs->ifs_ipf_ipv6 = NULL; 175381a2a9aSdr } 176381a2a9aSdr 177381a2a9aSdr /* 178381a2a9aSdr * Remove IPv4 Hooks 179381a2a9aSdr */ 180f4b3ec61Sdh if (ifs->ifs_ipf_ipv4 != NULL) { 181f4b3ec61Sdh if (ifs->ifs_hook4_physical_in) { 182f4b3ec61Sdh ifs->ifs_hook4_physical_in = 183f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv4, 184f4b3ec61Sdh NH_PHYSICAL_IN, &ifs->ifs_ipfhook_in) != 0); 185381a2a9aSdr } 186f4b3ec61Sdh if (ifs->ifs_hook4_physical_out) { 187f4b3ec61Sdh ifs->ifs_hook4_physical_out = 188f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv4, 189f4b3ec61Sdh NH_PHYSICAL_OUT, &ifs->ifs_ipfhook_out) != 0); 190381a2a9aSdr } 191f4b3ec61Sdh if (ifs->ifs_hook4_nic_events) { 192f4b3ec61Sdh ifs->ifs_hook4_nic_events = 193f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv4, 194f4b3ec61Sdh NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) != 0); 195381a2a9aSdr } 196f4b3ec61Sdh if (ifs->ifs_hook4_loopback_in) { 197f4b3ec61Sdh ifs->ifs_hook4_loopback_in = 198f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv4, 199f4b3ec61Sdh NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) != 0); 200381a2a9aSdr } 201f4b3ec61Sdh if (ifs->ifs_hook4_loopback_out) { 202f4b3ec61Sdh ifs->ifs_hook4_loopback_out = 203f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv4, 204f4b3ec61Sdh NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) != 0); 205381a2a9aSdr } 206381a2a9aSdr 207f4b3ec61Sdh if (net_release(ifs->ifs_ipf_ipv4) != 0) 208381a2a9aSdr goto detach_failed; 209f4b3ec61Sdh ifs->ifs_ipf_ipv4 = NULL; 210381a2a9aSdr } 211381a2a9aSdr 2127c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 2137c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "ipldetach()\n"); 2147c478bd9Sstevel@tonic-gate #endif 2157c478bd9Sstevel@tonic-gate 216f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 217f4b3ec61Sdh fr_deinitialise(ifs); 2187c478bd9Sstevel@tonic-gate 219f4b3ec61Sdh (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE, ifs); 220f4b3ec61Sdh (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE, ifs); 2217c478bd9Sstevel@tonic-gate 222f4b3ec61Sdh if (ifs->ifs_ipf_locks_done == 1) { 223f4b3ec61Sdh MUTEX_DESTROY(&ifs->ifs_ipf_timeoutlock); 224f4b3ec61Sdh MUTEX_DESTROY(&ifs->ifs_ipf_rw); 225f4b3ec61Sdh RW_DESTROY(&ifs->ifs_ipf_tokens); 226f4b3ec61Sdh RW_DESTROY(&ifs->ifs_ipf_ipidfrag); 227f4b3ec61Sdh ifs->ifs_ipf_locks_done = 0; 2287c478bd9Sstevel@tonic-gate } 229381a2a9aSdr 230f4b3ec61Sdh if (ifs->ifs_hook4_physical_in || ifs->ifs_hook4_physical_out || ifs->ifs_hook4_nic_events || 231f4b3ec61Sdh ifs->ifs_hook4_loopback_in || ifs->ifs_hook4_loopback_out || ifs->ifs_hook6_nic_events || 232f4b3ec61Sdh ifs->ifs_hook6_physical_in || ifs->ifs_hook6_physical_out || ifs->ifs_hook6_loopback_in || 233f4b3ec61Sdh ifs->ifs_hook6_loopback_out) 234381a2a9aSdr return -1; 235381a2a9aSdr 2367c478bd9Sstevel@tonic-gate return 0; 237381a2a9aSdr 238381a2a9aSdr detach_failed: 239f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 240381a2a9aSdr return -1; 2417c478bd9Sstevel@tonic-gate } 2427c478bd9Sstevel@tonic-gate 243f4b3ec61Sdh int iplattach(ifs, ns) 244f4b3ec61Sdh ipf_stack_t *ifs; 245f4b3ec61Sdh netstack_t *ns; 2467c478bd9Sstevel@tonic-gate { 2477c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 2487c478bd9Sstevel@tonic-gate int i; 2497c478bd9Sstevel@tonic-gate #endif 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 2527c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplattach()\n"); 2537c478bd9Sstevel@tonic-gate #endif 2547c478bd9Sstevel@tonic-gate 255f4b3ec61Sdh ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0); 256f4b3ec61Sdh ifs->ifs_fr_flags = IPF_LOGGING; 257f4b3ec61Sdh #ifdef _KERNEL 258f4b3ec61Sdh ifs->ifs_fr_update_ipid = 0; 259f4b3ec61Sdh #else 260f4b3ec61Sdh ifs->ifs_fr_update_ipid = 1; 261f4b3ec61Sdh #endif 262f4b3ec61Sdh ifs->ifs_fr_minttl = 4; 263f4b3ec61Sdh ifs->ifs_fr_icmpminfragmtu = 68; 264f4b3ec61Sdh #if defined(IPFILTER_DEFAULT_BLOCK) 265f4b3ec61Sdh ifs->ifs_fr_pass = FR_BLOCK|FR_NOMATCH; 266f4b3ec61Sdh #else 267f4b3ec61Sdh ifs->ifs_fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH; 268f4b3ec61Sdh #endif 2697c478bd9Sstevel@tonic-gate 270f4b3ec61Sdh bzero((char *)ifs->ifs_frcache, sizeof(ifs->ifs_frcache)); 271f4b3ec61Sdh MUTEX_INIT(&ifs->ifs_ipf_rw, "ipf rw mutex"); 272f4b3ec61Sdh MUTEX_INIT(&ifs->ifs_ipf_timeoutlock, "ipf timeout lock mutex"); 273f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); 274f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_tokens, "ipf token rwlock"); 275f4b3ec61Sdh ifs->ifs_ipf_locks_done = 1; 2767c478bd9Sstevel@tonic-gate 277f4b3ec61Sdh if (fr_initialise(ifs) < 0) 2787c478bd9Sstevel@tonic-gate return -1; 2797c478bd9Sstevel@tonic-gate 280f4b3ec61Sdh HOOK_INIT(&ifs->ifs_ipfhook_nicevents, ipf_nic_event_v4, 281381a2a9aSdr "ipfilter_hook_nicevents"); 282f4b3ec61Sdh HOOK_INIT(&ifs->ifs_ipfhook_in, ipf_hook_in, "ipfilter_hook_in"); 283f4b3ec61Sdh HOOK_INIT(&ifs->ifs_ipfhook_out, ipf_hook_out, "ipfilter_hook_out"); 284f4b3ec61Sdh HOOK_INIT(&ifs->ifs_ipfhook_loop_in, ipf_hook_in, 285f4b3ec61Sdh "ipfilter_hook_loop_in"); 286f4b3ec61Sdh HOOK_INIT(&ifs->ifs_ipfhook_loop_out, ipf_hook_out, 287ca8c7054Syx "ipfilter_hook_loop_out"); 288381a2a9aSdr 289381a2a9aSdr /* 290381a2a9aSdr * If we hold this lock over all of the net_register_hook calls, we 291381a2a9aSdr * can cause a deadlock to occur with the following lock ordering: 292381a2a9aSdr * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs 293381a2a9aSdr * R(hook_family)->R(hei_lock)->R(ipf_global) (packet path) 294381a2a9aSdr */ 295f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 296381a2a9aSdr 297381a2a9aSdr /* 298381a2a9aSdr * Add IPv4 hooks 299381a2a9aSdr */ 300f4b3ec61Sdh ifs->ifs_ipf_ipv4 = net_lookup_impl(NHF_INET, ns); 301f4b3ec61Sdh if (ifs->ifs_ipf_ipv4 == NULL) 302381a2a9aSdr goto hookup_failed; 303381a2a9aSdr 304f4b3ec61Sdh ifs->ifs_hook4_nic_events = (net_register_hook(ifs->ifs_ipf_ipv4, 305f4b3ec61Sdh NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) == 0); 306f4b3ec61Sdh if (!ifs->ifs_hook4_nic_events) 307381a2a9aSdr goto hookup_failed; 308381a2a9aSdr 309f4b3ec61Sdh ifs->ifs_hook4_physical_in = (net_register_hook(ifs->ifs_ipf_ipv4, 310f4b3ec61Sdh NH_PHYSICAL_IN, &ifs->ifs_ipfhook_in) == 0); 311f4b3ec61Sdh if (!ifs->ifs_hook4_physical_in) 312381a2a9aSdr goto hookup_failed; 313381a2a9aSdr 314f4b3ec61Sdh ifs->ifs_hook4_physical_out = (net_register_hook(ifs->ifs_ipf_ipv4, 315f4b3ec61Sdh NH_PHYSICAL_OUT, &ifs->ifs_ipfhook_out) == 0); 316f4b3ec61Sdh if (!ifs->ifs_hook4_physical_out) 317381a2a9aSdr goto hookup_failed; 318381a2a9aSdr 319f4b3ec61Sdh if (ifs->ifs_ipf_loopback) { 320f4b3ec61Sdh ifs->ifs_hook4_loopback_in = 321f4b3ec61Sdh (net_register_hook(ifs->ifs_ipf_ipv4, 322f4b3ec61Sdh NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) == 0); 323f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_in) 324381a2a9aSdr goto hookup_failed; 325381a2a9aSdr 326f4b3ec61Sdh ifs->ifs_hook4_loopback_out = 327f4b3ec61Sdh (net_register_hook(ifs->ifs_ipf_ipv4, 328f4b3ec61Sdh NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) == 0); 329f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_out) 330381a2a9aSdr goto hookup_failed; 331381a2a9aSdr } 332381a2a9aSdr /* 333381a2a9aSdr * Add IPv6 hooks 334381a2a9aSdr */ 335f4b3ec61Sdh ifs->ifs_ipf_ipv6 = net_lookup_impl(NHF_INET6, ns); 336f4b3ec61Sdh if (ifs->ifs_ipf_ipv6 == NULL) 337381a2a9aSdr goto hookup_failed; 338381a2a9aSdr 339f4b3ec61Sdh HOOK_INIT(&ifs->ifs_ipfhook_nicevents, ipf_nic_event_v6, 340381a2a9aSdr "ipfilter_hook_nicevents"); 341f4b3ec61Sdh ifs->ifs_hook6_nic_events = (net_register_hook(ifs->ifs_ipf_ipv6, 342f4b3ec61Sdh NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) == 0); 343f4b3ec61Sdh if (!ifs->ifs_hook6_nic_events) 344381a2a9aSdr goto hookup_failed; 345381a2a9aSdr 346f4b3ec61Sdh ifs->ifs_hook6_physical_in = (net_register_hook(ifs->ifs_ipf_ipv6, 347f4b3ec61Sdh NH_PHYSICAL_IN, &ifs->ifs_ipfhook_in) == 0); 348f4b3ec61Sdh if (!ifs->ifs_hook6_physical_in) 349381a2a9aSdr goto hookup_failed; 350381a2a9aSdr 351f4b3ec61Sdh ifs->ifs_hook6_physical_out = (net_register_hook(ifs->ifs_ipf_ipv6, 352f4b3ec61Sdh NH_PHYSICAL_OUT, &ifs->ifs_ipfhook_out) == 0); 353f4b3ec61Sdh if (!ifs->ifs_hook6_physical_out) 354381a2a9aSdr goto hookup_failed; 355381a2a9aSdr 356f4b3ec61Sdh if (ifs->ifs_ipf_loopback) { 357f4b3ec61Sdh ifs->ifs_hook6_loopback_in = 358f4b3ec61Sdh (net_register_hook(ifs->ifs_ipf_ipv6, 359f4b3ec61Sdh NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) == 0); 360f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_in) 361381a2a9aSdr goto hookup_failed; 362381a2a9aSdr 363f4b3ec61Sdh ifs->ifs_hook6_loopback_out = 364f4b3ec61Sdh (net_register_hook(ifs->ifs_ipf_ipv6, 365f4b3ec61Sdh NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) == 0); 366f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_out) 367381a2a9aSdr goto hookup_failed; 368381a2a9aSdr } 369381a2a9aSdr 370381a2a9aSdr /* 371381a2a9aSdr * Reacquire ipf_global, now it is safe. 372381a2a9aSdr */ 373f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 374381a2a9aSdr 3757c478bd9Sstevel@tonic-gate /* Do not use private interface ip_params_arr[] in Solaris 10 */ 3767c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 3797c478bd9Sstevel@tonic-gate ip_forwarding = &ip_g_forward; 3807c478bd9Sstevel@tonic-gate #endif 3817c478bd9Sstevel@tonic-gate /* 3827c478bd9Sstevel@tonic-gate * XXX - There is no terminator for this array, so it is not possible 3837c478bd9Sstevel@tonic-gate * to tell if what we are looking for is missing and go off the end 3847c478bd9Sstevel@tonic-gate * of the array. 3857c478bd9Sstevel@tonic-gate */ 3867c478bd9Sstevel@tonic-gate 387ab25eeb5Syz #if SOLARIS2 <= 8 3887c478bd9Sstevel@tonic-gate for (i = 0; ; i++) { 3897c478bd9Sstevel@tonic-gate if (!strcmp(ip_param_arr[i].ip_param_name, "ip_def_ttl")) { 3907c478bd9Sstevel@tonic-gate ip_ttl_ptr = &ip_param_arr[i].ip_param_value; 3917c478bd9Sstevel@tonic-gate } else if (!strcmp(ip_param_arr[i].ip_param_name, 3927c478bd9Sstevel@tonic-gate "ip_path_mtu_discovery")) { 3937c478bd9Sstevel@tonic-gate ip_mtudisc = &ip_param_arr[i].ip_param_value; 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate #if SOLARIS2 < 8 3967c478bd9Sstevel@tonic-gate else if (!strcmp(ip_param_arr[i].ip_param_name, 3977c478bd9Sstevel@tonic-gate "ip_forwarding")) { 3987c478bd9Sstevel@tonic-gate ip_forwarding = &ip_param_arr[i].ip_param_value; 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate #else 4017c478bd9Sstevel@tonic-gate else if (!strcmp(ip_param_arr[i].ip_param_name, 4027c478bd9Sstevel@tonic-gate "ip6_forwarding")) { 4037c478bd9Sstevel@tonic-gate ip6_forwarding = &ip_param_arr[i].ip_param_value; 4047c478bd9Sstevel@tonic-gate } 4057c478bd9Sstevel@tonic-gate #endif 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate if (ip_mtudisc != NULL && ip_ttl_ptr != NULL && 4087c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 4097c478bd9Sstevel@tonic-gate ip6_forwarding != NULL && 4107c478bd9Sstevel@tonic-gate #endif 4117c478bd9Sstevel@tonic-gate ip_forwarding != NULL) 4127c478bd9Sstevel@tonic-gate break; 4137c478bd9Sstevel@tonic-gate } 414ab25eeb5Syz #endif 4157c478bd9Sstevel@tonic-gate 416f4b3ec61Sdh if (ifs->ifs_fr_control_forwarding & 1) { 417ab25eeb5Syz if (ip_forwarding != NULL) 418ab25eeb5Syz *ip_forwarding = 1; 4197c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 420ab25eeb5Syz if (ip6_forwarding != NULL) 421ab25eeb5Syz *ip6_forwarding = 1; 4227c478bd9Sstevel@tonic-gate #endif 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate #endif 4267c478bd9Sstevel@tonic-gate 427381a2a9aSdr return 0; 428381a2a9aSdr hookup_failed: 429f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 430381a2a9aSdr return -1; 431381a2a9aSdr } 432381a2a9aSdr 433f4b3ec61Sdh static int fr_setipfloopback(set, ifs) 434381a2a9aSdr int set; 435f4b3ec61Sdh ipf_stack_t *ifs; 436381a2a9aSdr { 437f4b3ec61Sdh if (ifs->ifs_ipf_ipv4 == NULL || ifs->ifs_ipf_ipv6 == NULL) 438381a2a9aSdr return EFAULT; 439381a2a9aSdr 440f4b3ec61Sdh if (set && !ifs->ifs_ipf_loopback) { 441f4b3ec61Sdh ifs->ifs_ipf_loopback = 1; 442381a2a9aSdr 443f4b3ec61Sdh ifs->ifs_hook4_loopback_in = 444f4b3ec61Sdh (net_register_hook(ifs->ifs_ipf_ipv4, 445f4b3ec61Sdh NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) == 0); 446f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_in) 447381a2a9aSdr return EINVAL; 448381a2a9aSdr 449f4b3ec61Sdh ifs->ifs_hook4_loopback_out = 450f4b3ec61Sdh (net_register_hook(ifs->ifs_ipf_ipv4, 451f4b3ec61Sdh NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) == 0); 452f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_out) 453381a2a9aSdr return EINVAL; 454381a2a9aSdr 455f4b3ec61Sdh ifs->ifs_hook6_loopback_in = 456f4b3ec61Sdh (net_register_hook(ifs->ifs_ipf_ipv6, 457f4b3ec61Sdh NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) == 0); 458f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_in) 459381a2a9aSdr return EINVAL; 460381a2a9aSdr 461f4b3ec61Sdh ifs->ifs_hook6_loopback_out = 462f4b3ec61Sdh (net_register_hook(ifs->ifs_ipf_ipv6, 463f4b3ec61Sdh NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) == 0); 464f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_out) 465381a2a9aSdr return EINVAL; 466381a2a9aSdr 467f4b3ec61Sdh } else if (!set && ifs->ifs_ipf_loopback) { 468f4b3ec61Sdh ifs->ifs_ipf_loopback = 0; 469381a2a9aSdr 470f4b3ec61Sdh ifs->ifs_hook4_loopback_in = 471f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv4, 472f4b3ec61Sdh NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) != 0); 473f4b3ec61Sdh if (ifs->ifs_hook4_loopback_in) 474381a2a9aSdr return EBUSY; 475381a2a9aSdr 476f4b3ec61Sdh ifs->ifs_hook4_loopback_out = 477f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv4, 478f4b3ec61Sdh NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) != 0); 479f4b3ec61Sdh if (ifs->ifs_hook4_loopback_out) 480381a2a9aSdr return EBUSY; 481381a2a9aSdr 482f4b3ec61Sdh ifs->ifs_hook6_loopback_in = 483f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv6, 484f4b3ec61Sdh NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) != 0); 485f4b3ec61Sdh if (ifs->ifs_hook6_loopback_in) 486381a2a9aSdr return EBUSY; 487381a2a9aSdr 488f4b3ec61Sdh ifs->ifs_hook6_loopback_out = 489f4b3ec61Sdh (net_unregister_hook(ifs->ifs_ipf_ipv6, 490f4b3ec61Sdh NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) != 0); 491f4b3ec61Sdh if (ifs->ifs_hook6_loopback_out) 492381a2a9aSdr return EBUSY; 493381a2a9aSdr } 4947c478bd9Sstevel@tonic-gate return 0; 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate /* 4997c478bd9Sstevel@tonic-gate * Filter ioctl interface. 5007c478bd9Sstevel@tonic-gate */ 5017c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5027c478bd9Sstevel@tonic-gate int iplioctl(dev, cmd, data, mode, cp, rp) 5037c478bd9Sstevel@tonic-gate dev_t dev; 5047c478bd9Sstevel@tonic-gate int cmd; 5057c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 7 5067c478bd9Sstevel@tonic-gate intptr_t data; 5077c478bd9Sstevel@tonic-gate #else 5087c478bd9Sstevel@tonic-gate int *data; 5097c478bd9Sstevel@tonic-gate #endif 5107c478bd9Sstevel@tonic-gate int mode; 5117c478bd9Sstevel@tonic-gate cred_t *cp; 5127c478bd9Sstevel@tonic-gate int *rp; 5137c478bd9Sstevel@tonic-gate { 5147c478bd9Sstevel@tonic-gate int error = 0, tmp; 5157c478bd9Sstevel@tonic-gate friostat_t fio; 5167c478bd9Sstevel@tonic-gate minor_t unit; 5177c478bd9Sstevel@tonic-gate u_int enable; 518f4b3ec61Sdh netstack_t *ns; 519f4b3ec61Sdh ipf_stack_t *ifs; 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 5227c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplioctl(%x,%x,%x,%d,%x,%d)\n", 5237c478bd9Sstevel@tonic-gate dev, cmd, data, mode, cp, rp); 5247c478bd9Sstevel@tonic-gate #endif 5257c478bd9Sstevel@tonic-gate unit = getminor(dev); 5267c478bd9Sstevel@tonic-gate if (IPL_LOGMAX < unit) 5277c478bd9Sstevel@tonic-gate return ENXIO; 5287c478bd9Sstevel@tonic-gate 529f4b3ec61Sdh ns = netstack_find_by_cred(cp); 530f4b3ec61Sdh ASSERT(ns != NULL); 531f4b3ec61Sdh ifs = ns->netstack_ipf; 532f4b3ec61Sdh ASSERT(ifs != NULL); 533f4b3ec61Sdh 534f4b3ec61Sdh if (ifs->ifs_fr_running <= 0) { 535f4b3ec61Sdh if (unit != IPL_LOGIPF) { 536f4b3ec61Sdh netstack_rele(ifs->ifs_netstack); 5377c478bd9Sstevel@tonic-gate return EIO; 538f4b3ec61Sdh } 5397c478bd9Sstevel@tonic-gate if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 540ab25eeb5Syz cmd != SIOCIPFSET && cmd != SIOCFRENB && 541f4b3ec61Sdh cmd != SIOCGETFS && cmd != SIOCGETFF) { 542f4b3ec61Sdh netstack_rele(ifs->ifs_netstack); 5437c478bd9Sstevel@tonic-gate return EIO; 544f4b3ec61Sdh } 5457c478bd9Sstevel@tonic-gate } 5467c478bd9Sstevel@tonic-gate 547f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_global); 5487c478bd9Sstevel@tonic-gate 549f4b3ec61Sdh error = fr_ioctlswitch(unit, (caddr_t)data, cmd, mode, cp->cr_uid, curproc, ifs); 5507c478bd9Sstevel@tonic-gate if (error != -1) { 551f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 552f4b3ec61Sdh netstack_rele(ifs->ifs_netstack); 5537c478bd9Sstevel@tonic-gate return error; 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate error = 0; 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate switch (cmd) 5587c478bd9Sstevel@tonic-gate { 5597c478bd9Sstevel@tonic-gate case SIOCFRENB : 5607c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 5617c478bd9Sstevel@tonic-gate error = EPERM; 5627c478bd9Sstevel@tonic-gate else { 5637c478bd9Sstevel@tonic-gate error = COPYIN((caddr_t)data, (caddr_t)&enable, 5647c478bd9Sstevel@tonic-gate sizeof(enable)); 5657c478bd9Sstevel@tonic-gate if (error != 0) { 5667c478bd9Sstevel@tonic-gate error = EFAULT; 5677c478bd9Sstevel@tonic-gate break; 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate 570f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 571f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 572882bd30bSdr error = fr_enableipf(ifs, ns, enable); 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate break; 5757c478bd9Sstevel@tonic-gate case SIOCIPFSET : 5767c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) { 5777c478bd9Sstevel@tonic-gate error = EPERM; 5787c478bd9Sstevel@tonic-gate break; 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate /* FALLTHRU */ 5817c478bd9Sstevel@tonic-gate case SIOCIPFGETNEXT : 5827c478bd9Sstevel@tonic-gate case SIOCIPFGET : 583f4b3ec61Sdh error = fr_ipftune(cmd, (void *)data, ifs); 5847c478bd9Sstevel@tonic-gate break; 5857c478bd9Sstevel@tonic-gate case SIOCSETFF : 5867c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 5877c478bd9Sstevel@tonic-gate error = EPERM; 5887c478bd9Sstevel@tonic-gate else { 589f4b3ec61Sdh error = COPYIN((caddr_t)data, (caddr_t)&ifs->ifs_fr_flags, 590f4b3ec61Sdh sizeof(ifs->ifs_fr_flags)); 5917c478bd9Sstevel@tonic-gate if (error != 0) 5927c478bd9Sstevel@tonic-gate error = EFAULT; 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate break; 595381a2a9aSdr case SIOCIPFLP : 596381a2a9aSdr error = COPYIN((caddr_t)data, (caddr_t)&tmp, 597381a2a9aSdr sizeof(tmp)); 598381a2a9aSdr if (error != 0) 599381a2a9aSdr error = EFAULT; 600381a2a9aSdr else 601f4b3ec61Sdh error = fr_setipfloopback(tmp, ifs); 602381a2a9aSdr break; 6037c478bd9Sstevel@tonic-gate case SIOCGETFF : 604f4b3ec61Sdh error = COPYOUT((caddr_t)&ifs->ifs_fr_flags, (caddr_t)data, 605f4b3ec61Sdh sizeof(ifs->ifs_fr_flags)); 6067c478bd9Sstevel@tonic-gate if (error != 0) 6077c478bd9Sstevel@tonic-gate error = EFAULT; 6087c478bd9Sstevel@tonic-gate break; 6097c478bd9Sstevel@tonic-gate case SIOCFUNCL : 6107c478bd9Sstevel@tonic-gate error = fr_resolvefunc((void *)data); 6117c478bd9Sstevel@tonic-gate break; 6127c478bd9Sstevel@tonic-gate case SIOCINAFR : 6137c478bd9Sstevel@tonic-gate case SIOCRMAFR : 6147c478bd9Sstevel@tonic-gate case SIOCADAFR : 6157c478bd9Sstevel@tonic-gate case SIOCZRLST : 6167c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6177c478bd9Sstevel@tonic-gate error = EPERM; 6187c478bd9Sstevel@tonic-gate else 6197c478bd9Sstevel@tonic-gate error = frrequest(unit, cmd, (caddr_t)data, 620f4b3ec61Sdh ifs->ifs_fr_active, 1, ifs); 6217c478bd9Sstevel@tonic-gate break; 6227c478bd9Sstevel@tonic-gate case SIOCINIFR : 6237c478bd9Sstevel@tonic-gate case SIOCRMIFR : 6247c478bd9Sstevel@tonic-gate case SIOCADIFR : 6257c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6267c478bd9Sstevel@tonic-gate error = EPERM; 6277c478bd9Sstevel@tonic-gate else 6287c478bd9Sstevel@tonic-gate error = frrequest(unit, cmd, (caddr_t)data, 629f4b3ec61Sdh 1 - ifs->ifs_fr_active, 1, ifs); 6307c478bd9Sstevel@tonic-gate break; 6317c478bd9Sstevel@tonic-gate case SIOCSWAPA : 6327c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6337c478bd9Sstevel@tonic-gate error = EPERM; 6347c478bd9Sstevel@tonic-gate else { 635f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_mutex); 636f4b3ec61Sdh /* Clear one fourth of the table */ 637f4b3ec61Sdh bzero((char *)&ifs->ifs_frcache, 638f4b3ec61Sdh sizeof (ifs->ifs_frcache[0]) * 2); 639f4b3ec61Sdh error = COPYOUT((caddr_t)&ifs->ifs_fr_active, 640f4b3ec61Sdh (caddr_t)data, 641f4b3ec61Sdh sizeof(ifs->ifs_fr_active)); 6427c478bd9Sstevel@tonic-gate if (error != 0) 6437c478bd9Sstevel@tonic-gate error = EFAULT; 6447c478bd9Sstevel@tonic-gate else 645f4b3ec61Sdh ifs->ifs_fr_active = 1 - ifs->ifs_fr_active; 646f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 6477c478bd9Sstevel@tonic-gate } 6487c478bd9Sstevel@tonic-gate break; 6497c478bd9Sstevel@tonic-gate case SIOCGETFS : 650f4b3ec61Sdh fr_getstat(&fio, ifs); 6517c478bd9Sstevel@tonic-gate error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT); 6527c478bd9Sstevel@tonic-gate break; 6537c478bd9Sstevel@tonic-gate case SIOCFRZST : 6547c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6557c478bd9Sstevel@tonic-gate error = EPERM; 6567c478bd9Sstevel@tonic-gate else 657f4b3ec61Sdh error = fr_zerostats((caddr_t)data, ifs); 6587c478bd9Sstevel@tonic-gate break; 6597c478bd9Sstevel@tonic-gate case SIOCIPFFL : 6607c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6617c478bd9Sstevel@tonic-gate error = EPERM; 6627c478bd9Sstevel@tonic-gate else { 6637c478bd9Sstevel@tonic-gate error = COPYIN((caddr_t)data, (caddr_t)&tmp, 6647c478bd9Sstevel@tonic-gate sizeof(tmp)); 6657c478bd9Sstevel@tonic-gate if (!error) { 666f4b3ec61Sdh tmp = frflush(unit, 4, tmp, ifs); 6677c478bd9Sstevel@tonic-gate error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 6687c478bd9Sstevel@tonic-gate sizeof(tmp)); 6697c478bd9Sstevel@tonic-gate if (error != 0) 6707c478bd9Sstevel@tonic-gate error = EFAULT; 6717c478bd9Sstevel@tonic-gate } else 6727c478bd9Sstevel@tonic-gate error = EFAULT; 6737c478bd9Sstevel@tonic-gate } 6747c478bd9Sstevel@tonic-gate break; 6757663b816Sml #ifdef USE_INET6 6767663b816Sml case SIOCIPFL6 : 6777663b816Sml if (!(mode & FWRITE)) 6787663b816Sml error = EPERM; 6797663b816Sml else { 6807663b816Sml error = COPYIN((caddr_t)data, (caddr_t)&tmp, 6817663b816Sml sizeof(tmp)); 6827663b816Sml if (!error) { 683f4b3ec61Sdh tmp = frflush(unit, 6, tmp, ifs); 6847663b816Sml error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 6857663b816Sml sizeof(tmp)); 6867663b816Sml if (error != 0) 6877663b816Sml error = EFAULT; 6887663b816Sml } else 6897663b816Sml error = EFAULT; 6907663b816Sml } 6917663b816Sml break; 6927663b816Sml #endif 6937c478bd9Sstevel@tonic-gate case SIOCSTLCK : 6947c478bd9Sstevel@tonic-gate error = COPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 6957c478bd9Sstevel@tonic-gate if (error == 0) { 696f4b3ec61Sdh ifs->ifs_fr_state_lock = tmp; 697f4b3ec61Sdh ifs->ifs_fr_nat_lock = tmp; 698f4b3ec61Sdh ifs->ifs_fr_frag_lock = tmp; 699f4b3ec61Sdh ifs->ifs_fr_auth_lock = tmp; 7007c478bd9Sstevel@tonic-gate } else 7017c478bd9Sstevel@tonic-gate error = EFAULT; 7027c478bd9Sstevel@tonic-gate break; 7037c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 7047c478bd9Sstevel@tonic-gate case SIOCIPFFB : 7057c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 7067c478bd9Sstevel@tonic-gate error = EPERM; 7077c478bd9Sstevel@tonic-gate else { 708f4b3ec61Sdh tmp = ipflog_clear(unit, ifs); 7097c478bd9Sstevel@tonic-gate error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 7107c478bd9Sstevel@tonic-gate sizeof(tmp)); 7117c478bd9Sstevel@tonic-gate if (error) 7127c478bd9Sstevel@tonic-gate error = EFAULT; 7137c478bd9Sstevel@tonic-gate } 7147c478bd9Sstevel@tonic-gate break; 7157c478bd9Sstevel@tonic-gate #endif /* IPFILTER_LOG */ 7167c478bd9Sstevel@tonic-gate case SIOCFRSYN : 7177c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 7187c478bd9Sstevel@tonic-gate error = EPERM; 7197c478bd9Sstevel@tonic-gate else { 720f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 721f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 722381a2a9aSdr 723f4b3ec61Sdh frsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 724f4b3ec61Sdh fr_natifpsync(IPFSYNC_RESYNC, NULL, NULL, ifs); 725f4b3ec61Sdh fr_nataddrsync(NULL, NULL, ifs); 726f4b3ec61Sdh fr_statesync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 727381a2a9aSdr error = 0; 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate break; 7307c478bd9Sstevel@tonic-gate case SIOCGFRST : 731f4b3ec61Sdh error = fr_outobj((void *)data, fr_fragstats(ifs), 7327c478bd9Sstevel@tonic-gate IPFOBJ_FRAGSTAT); 7337c478bd9Sstevel@tonic-gate break; 7347c478bd9Sstevel@tonic-gate case FIONREAD : 7357c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 736f4b3ec61Sdh tmp = (int)ifs->ifs_iplused[IPL_LOGIPF]; 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate error = COPYOUT((caddr_t)&tmp, (caddr_t)data, sizeof(tmp)); 7397c478bd9Sstevel@tonic-gate if (error != 0) 7407c478bd9Sstevel@tonic-gate error = EFAULT; 7417c478bd9Sstevel@tonic-gate #endif 7427c478bd9Sstevel@tonic-gate break; 743f4b3ec61Sdh case SIOCIPFITER : 744f4b3ec61Sdh error = ipf_frruleiter((caddr_t)data, cp->cr_uid, curproc, ifs); 745f4b3ec61Sdh break; 746f4b3ec61Sdh 747f4b3ec61Sdh case SIOCGENITER : 748f4b3ec61Sdh error = ipf_genericiter((caddr_t)data, cp->cr_uid, curproc, ifs); 749f4b3ec61Sdh break; 750f4b3ec61Sdh 751f4b3ec61Sdh case SIOCIPFDELTOK : 752f4b3ec61Sdh (void)BCOPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 753f4b3ec61Sdh error = ipf_deltoken(tmp, cp->cr_uid, curproc, ifs); 754f4b3ec61Sdh break; 755f4b3ec61Sdh 7567c478bd9Sstevel@tonic-gate default : 757ab25eeb5Syz cmn_err(CE_NOTE, "Unknown: cmd 0x%x data %p", cmd, (void *)data); 7587c478bd9Sstevel@tonic-gate error = EINVAL; 7597c478bd9Sstevel@tonic-gate break; 7607c478bd9Sstevel@tonic-gate } 761f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 762f4b3ec61Sdh netstack_rele(ifs->ifs_netstack); 7637c478bd9Sstevel@tonic-gate return error; 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate 767882bd30bSdr static int fr_enableipf(ifs, ns, enable) 768882bd30bSdr ipf_stack_t *ifs; 769882bd30bSdr netstack_t *ns; 770882bd30bSdr int enable; 771882bd30bSdr { 772882bd30bSdr int error; 773882bd30bSdr 774882bd30bSdr if (enable) { 775882bd30bSdr if (ifs->ifs_fr_running > 0) 776882bd30bSdr error = 0; 777882bd30bSdr else 778882bd30bSdr error = iplattach(ifs, ns); 779882bd30bSdr if (error == 0) { 780882bd30bSdr if (ifs->ifs_fr_timer_id == NULL) { 781882bd30bSdr int hz = drv_usectohz(500000); 782882bd30bSdr 783882bd30bSdr ifs->ifs_fr_timer_id = timeout(fr_slowtimer, 784882bd30bSdr (void *)ifs, 785882bd30bSdr hz); 786882bd30bSdr } 787882bd30bSdr ifs->ifs_fr_running = 1; 788882bd30bSdr } else { 789882bd30bSdr (void) ipldetach(ifs); 790882bd30bSdr } 791882bd30bSdr } else { 792882bd30bSdr error = ipldetach(ifs); 793882bd30bSdr if (error == 0) 794882bd30bSdr ifs->ifs_fr_running = -1; 795882bd30bSdr } 796882bd30bSdr 797882bd30bSdr return error; 798882bd30bSdr } 799882bd30bSdr 800882bd30bSdr 801f4b3ec61Sdh phy_if_t get_unit(name, v, ifs) 802f4b3ec61Sdh char *name; 803f4b3ec61Sdh int v; 804f4b3ec61Sdh ipf_stack_t *ifs; 8057c478bd9Sstevel@tonic-gate { 806381a2a9aSdr net_data_t nif; 807381a2a9aSdr 808381a2a9aSdr if (v == 4) 809f4b3ec61Sdh nif = ifs->ifs_ipf_ipv4; 810381a2a9aSdr else if (v == 6) 811f4b3ec61Sdh nif = ifs->ifs_ipf_ipv6; 812381a2a9aSdr else 813381a2a9aSdr return 0; 814381a2a9aSdr 815f4b3ec61Sdh nif->netd_netstack = ifs->ifs_netstack; 816f4b3ec61Sdh 817f4b3ec61Sdh return (net_phylookup(nif, name)); 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate /* 8217c478bd9Sstevel@tonic-gate * routines below for saving IP headers to buffer 8227c478bd9Sstevel@tonic-gate */ 8237c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8247c478bd9Sstevel@tonic-gate int iplopen(devp, flags, otype, cred) 8257c478bd9Sstevel@tonic-gate dev_t *devp; 8267c478bd9Sstevel@tonic-gate int flags, otype; 8277c478bd9Sstevel@tonic-gate cred_t *cred; 8287c478bd9Sstevel@tonic-gate { 8297c478bd9Sstevel@tonic-gate minor_t min = getminor(*devp); 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 8327c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplopen(%x,%x,%x,%x)\n", devp, flags, otype, cred); 8337c478bd9Sstevel@tonic-gate #endif 8347c478bd9Sstevel@tonic-gate if (!(otype & OTYP_CHR)) 8357c478bd9Sstevel@tonic-gate return ENXIO; 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate min = (IPL_LOGMAX < min) ? ENXIO : 0; 8387c478bd9Sstevel@tonic-gate return min; 8397c478bd9Sstevel@tonic-gate } 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8437c478bd9Sstevel@tonic-gate int iplclose(dev, flags, otype, cred) 8447c478bd9Sstevel@tonic-gate dev_t dev; 8457c478bd9Sstevel@tonic-gate int flags, otype; 8467c478bd9Sstevel@tonic-gate cred_t *cred; 8477c478bd9Sstevel@tonic-gate { 8487c478bd9Sstevel@tonic-gate minor_t min = getminor(dev); 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 8517c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplclose(%x,%x,%x,%x)\n", dev, flags, otype, cred); 8527c478bd9Sstevel@tonic-gate #endif 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate min = (IPL_LOGMAX < min) ? ENXIO : 0; 8557c478bd9Sstevel@tonic-gate return min; 8567c478bd9Sstevel@tonic-gate } 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 8597c478bd9Sstevel@tonic-gate /* 8607c478bd9Sstevel@tonic-gate * iplread/ipllog 8617c478bd9Sstevel@tonic-gate * both of these must operate with at least splnet() lest they be 8627c478bd9Sstevel@tonic-gate * called during packet processing and cause an inconsistancy to appear in 8637c478bd9Sstevel@tonic-gate * the filter lists. 8647c478bd9Sstevel@tonic-gate */ 8657c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8667c478bd9Sstevel@tonic-gate int iplread(dev, uio, cp) 8677c478bd9Sstevel@tonic-gate dev_t dev; 8687c478bd9Sstevel@tonic-gate register struct uio *uio; 8697c478bd9Sstevel@tonic-gate cred_t *cp; 8707c478bd9Sstevel@tonic-gate { 871f4b3ec61Sdh netstack_t *ns; 872f4b3ec61Sdh ipf_stack_t *ifs; 873f4b3ec61Sdh int ret; 874f4b3ec61Sdh 875f4b3ec61Sdh ns = netstack_find_by_cred(cp); 876f4b3ec61Sdh ASSERT(ns != NULL); 877f4b3ec61Sdh ifs = ns->netstack_ipf; 878f4b3ec61Sdh ASSERT(ifs != NULL); 879f4b3ec61Sdh 8807c478bd9Sstevel@tonic-gate # ifdef IPFDEBUG 8817c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplread(%x,%x,%x)\n", dev, uio, cp); 8827c478bd9Sstevel@tonic-gate # endif 88308ee25aeSdr 884f4b3ec61Sdh if (ifs->ifs_fr_running < 1) { 885f4b3ec61Sdh netstack_rele(ifs->ifs_netstack); 88608ee25aeSdr return EIO; 887f4b3ec61Sdh } 88808ee25aeSdr 8897c478bd9Sstevel@tonic-gate # ifdef IPFILTER_SYNC 890f4b3ec61Sdh if (getminor(dev) == IPL_LOGSYNC) { 891f4b3ec61Sdh netstack_rele(ifs->ifs_netstack); 8927c478bd9Sstevel@tonic-gate return ipfsync_read(uio); 893f4b3ec61Sdh } 8947c478bd9Sstevel@tonic-gate # endif 8957c478bd9Sstevel@tonic-gate 896f4b3ec61Sdh ret = ipflog_read(getminor(dev), uio, ifs); 897f4b3ec61Sdh netstack_rele(ifs->ifs_netstack); 898f4b3ec61Sdh return ret; 8997c478bd9Sstevel@tonic-gate } 9007c478bd9Sstevel@tonic-gate #endif /* IPFILTER_LOG */ 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate /* 9047c478bd9Sstevel@tonic-gate * iplread/ipllog 9057c478bd9Sstevel@tonic-gate * both of these must operate with at least splnet() lest they be 9067c478bd9Sstevel@tonic-gate * called during packet processing and cause an inconsistancy to appear in 9077c478bd9Sstevel@tonic-gate * the filter lists. 9087c478bd9Sstevel@tonic-gate */ 9097c478bd9Sstevel@tonic-gate int iplwrite(dev, uio, cp) 9107c478bd9Sstevel@tonic-gate dev_t dev; 9117c478bd9Sstevel@tonic-gate register struct uio *uio; 9127c478bd9Sstevel@tonic-gate cred_t *cp; 9137c478bd9Sstevel@tonic-gate { 914f4b3ec61Sdh netstack_t *ns; 915f4b3ec61Sdh ipf_stack_t *ifs; 916f4b3ec61Sdh 917f4b3ec61Sdh ns = netstack_find_by_cred(cp); 918f4b3ec61Sdh ASSERT(ns != NULL); 919f4b3ec61Sdh ifs = ns->netstack_ipf; 920f4b3ec61Sdh ASSERT(ifs != NULL); 921f4b3ec61Sdh 9227c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 9237c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplwrite(%x,%x,%x)\n", dev, uio, cp); 9247c478bd9Sstevel@tonic-gate #endif 92508ee25aeSdr 926f4b3ec61Sdh if (ifs->ifs_fr_running < 1) { 927f4b3ec61Sdh netstack_rele(ifs->ifs_netstack); 92808ee25aeSdr return EIO; 929f4b3ec61Sdh } 93008ee25aeSdr 931ab25eeb5Syz #ifdef IPFILTER_SYNC 932ab25eeb5Syz if (getminor(dev) == IPL_LOGSYNC) 933ab25eeb5Syz return ipfsync_write(uio); 9347c478bd9Sstevel@tonic-gate #endif /* IPFILTER_SYNC */ 935ab25eeb5Syz dev = dev; /* LINT */ 936ab25eeb5Syz uio = uio; /* LINT */ 937ab25eeb5Syz cp = cp; /* LINT */ 938f4b3ec61Sdh netstack_rele(ifs->ifs_netstack); 939ab25eeb5Syz return ENXIO; 940ab25eeb5Syz } 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate 9437c478bd9Sstevel@tonic-gate /* 9447c478bd9Sstevel@tonic-gate * fr_send_reset - this could conceivably be a call to tcp_respond(), but that 9457c478bd9Sstevel@tonic-gate * requires a large amount of setting up and isn't any more efficient. 9467c478bd9Sstevel@tonic-gate */ 9477c478bd9Sstevel@tonic-gate int fr_send_reset(fin) 9487c478bd9Sstevel@tonic-gate fr_info_t *fin; 9497c478bd9Sstevel@tonic-gate { 9507c478bd9Sstevel@tonic-gate tcphdr_t *tcp, *tcp2; 9517c478bd9Sstevel@tonic-gate int tlen, hlen; 9527c478bd9Sstevel@tonic-gate mblk_t *m; 9537c478bd9Sstevel@tonic-gate #ifdef USE_INET6 9547c478bd9Sstevel@tonic-gate ip6_t *ip6; 9557c478bd9Sstevel@tonic-gate #endif 9567c478bd9Sstevel@tonic-gate ip_t *ip; 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate tcp = fin->fin_dp; 9597c478bd9Sstevel@tonic-gate if (tcp->th_flags & TH_RST) 9607c478bd9Sstevel@tonic-gate return -1; 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate #ifndef IPFILTER_CKSUM 9637c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 9647c478bd9Sstevel@tonic-gate return -1; 9657c478bd9Sstevel@tonic-gate #endif 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate tlen = (tcp->th_flags & (TH_SYN|TH_FIN)) ? 1 : 0; 9687c478bd9Sstevel@tonic-gate #ifdef USE_INET6 9697c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) 9707c478bd9Sstevel@tonic-gate hlen = sizeof(ip6_t); 9717c478bd9Sstevel@tonic-gate else 9727c478bd9Sstevel@tonic-gate #endif 9737c478bd9Sstevel@tonic-gate hlen = sizeof(ip_t); 9747c478bd9Sstevel@tonic-gate hlen += sizeof(*tcp2); 9757c478bd9Sstevel@tonic-gate if ((m = (mblk_t *)allocb(hlen + 64, BPRI_HI)) == NULL) 9767c478bd9Sstevel@tonic-gate return -1; 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate m->b_rptr += 64; 9797c478bd9Sstevel@tonic-gate MTYPE(m) = M_DATA; 9807c478bd9Sstevel@tonic-gate m->b_wptr = m->b_rptr + hlen; 981ab25eeb5Syz ip = (ip_t *)m->b_rptr; 982ab25eeb5Syz bzero((char *)ip, hlen); 9837c478bd9Sstevel@tonic-gate tcp2 = (struct tcphdr *)(m->b_rptr + hlen - sizeof(*tcp2)); 9847c478bd9Sstevel@tonic-gate tcp2->th_dport = tcp->th_sport; 9857c478bd9Sstevel@tonic-gate tcp2->th_sport = tcp->th_dport; 9867c478bd9Sstevel@tonic-gate if (tcp->th_flags & TH_ACK) { 9877c478bd9Sstevel@tonic-gate tcp2->th_seq = tcp->th_ack; 9887c478bd9Sstevel@tonic-gate tcp2->th_flags = TH_RST; 9897c478bd9Sstevel@tonic-gate } else { 9907c478bd9Sstevel@tonic-gate tcp2->th_ack = ntohl(tcp->th_seq); 9917c478bd9Sstevel@tonic-gate tcp2->th_ack += tlen; 9927c478bd9Sstevel@tonic-gate tcp2->th_ack = htonl(tcp2->th_ack); 9937c478bd9Sstevel@tonic-gate tcp2->th_flags = TH_RST|TH_ACK; 9947c478bd9Sstevel@tonic-gate } 9957c478bd9Sstevel@tonic-gate tcp2->th_off = sizeof(struct tcphdr) >> 2; 9967c478bd9Sstevel@tonic-gate 997ab25eeb5Syz ip->ip_v = fin->fin_v; 9987c478bd9Sstevel@tonic-gate #ifdef USE_INET6 9997c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 10007c478bd9Sstevel@tonic-gate ip6 = (ip6_t *)m->b_rptr; 10017663b816Sml ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 10027c478bd9Sstevel@tonic-gate ip6->ip6_src = fin->fin_dst6; 10037c478bd9Sstevel@tonic-gate ip6->ip6_dst = fin->fin_src6; 10047c478bd9Sstevel@tonic-gate ip6->ip6_plen = htons(sizeof(*tcp)); 10057c478bd9Sstevel@tonic-gate ip6->ip6_nxt = IPPROTO_TCP; 10067663b816Sml tcp2->th_sum = fr_cksum(m, (ip_t *)ip6, IPPROTO_TCP, tcp2); 10077c478bd9Sstevel@tonic-gate } else 10087c478bd9Sstevel@tonic-gate #endif 10097c478bd9Sstevel@tonic-gate { 10107c478bd9Sstevel@tonic-gate ip->ip_src.s_addr = fin->fin_daddr; 10117c478bd9Sstevel@tonic-gate ip->ip_dst.s_addr = fin->fin_saddr; 10127c478bd9Sstevel@tonic-gate ip->ip_id = fr_nextipid(fin); 10137c478bd9Sstevel@tonic-gate ip->ip_hl = sizeof(*ip) >> 2; 10147c478bd9Sstevel@tonic-gate ip->ip_p = IPPROTO_TCP; 101537b40788Sekozlow ip->ip_len = sizeof(*ip) + sizeof(*tcp); 10167c478bd9Sstevel@tonic-gate ip->ip_tos = fin->fin_ip->ip_tos; 10177c478bd9Sstevel@tonic-gate tcp2->th_sum = fr_cksum(m, ip, IPPROTO_TCP, tcp2); 10187c478bd9Sstevel@tonic-gate } 1019ab25eeb5Syz return fr_send_ip(fin, m, &m); 10207c478bd9Sstevel@tonic-gate } 10217c478bd9Sstevel@tonic-gate 102237b40788Sekozlow /* 102337b40788Sekozlow * Function: fr_send_ip 102437b40788Sekozlow * Returns: 0: success 102537b40788Sekozlow * -1: failed 102637b40788Sekozlow * Parameters: 102737b40788Sekozlow * fin: packet information 102837b40788Sekozlow * m: the message block where ip head starts 102937b40788Sekozlow * 103037b40788Sekozlow * Send a new packet through the IP stack. 103137b40788Sekozlow * 103237b40788Sekozlow * For IPv4 packets, ip_len must be in host byte order, and ip_v, 103337b40788Sekozlow * ip_ttl, ip_off, and ip_sum are ignored (filled in by this 103437b40788Sekozlow * function). 103537b40788Sekozlow * 103637b40788Sekozlow * For IPv6 packets, ip6_flow, ip6_vfc, and ip6_hlim are filled 103737b40788Sekozlow * in by this function. 103837b40788Sekozlow * 103937b40788Sekozlow * All other portions of the packet must be in on-the-wire format. 104037b40788Sekozlow */ 1041ab25eeb5Syz /*ARGSUSED*/ 1042ab25eeb5Syz static int fr_send_ip(fin, m, mpp) 10437c478bd9Sstevel@tonic-gate fr_info_t *fin; 1044ab25eeb5Syz mblk_t *m, **mpp; 10457c478bd9Sstevel@tonic-gate { 1046ab25eeb5Syz qpktinfo_t qpi, *qpip; 1047ab25eeb5Syz fr_info_t fnew; 1048ab25eeb5Syz ip_t *ip; 1049ab25eeb5Syz int i, hlen; 1050f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1051ab25eeb5Syz 1052ab25eeb5Syz ip = (ip_t *)m->b_rptr; 1053ab25eeb5Syz bzero((char *)&fnew, sizeof(fnew)); 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate #ifdef USE_INET6 10567c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 10577c478bd9Sstevel@tonic-gate ip6_t *ip6; 10587c478bd9Sstevel@tonic-gate 1059ab25eeb5Syz ip6 = (ip6_t *)ip; 10607c478bd9Sstevel@tonic-gate ip6->ip6_vfc = 0x60; 10617c478bd9Sstevel@tonic-gate ip6->ip6_hlim = 127; 1062ab25eeb5Syz fnew.fin_v = 6; 1063ab25eeb5Syz hlen = sizeof(*ip6); 1064923d6102Szf fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen; 10657c478bd9Sstevel@tonic-gate } else 10667c478bd9Sstevel@tonic-gate #endif 10677c478bd9Sstevel@tonic-gate { 1068ab25eeb5Syz fnew.fin_v = 4; 10697c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 10 10707c478bd9Sstevel@tonic-gate ip->ip_ttl = 255; 1071f4b3ec61Sdh if (net_getpmtuenabled(ifs->ifs_ipf_ipv4) == 1) 1072381a2a9aSdr ip->ip_off = htons(IP_DF); 10737c478bd9Sstevel@tonic-gate #else 1074ab25eeb5Syz if (ip_ttl_ptr != NULL) 1075ab25eeb5Syz ip->ip_ttl = (u_char)(*ip_ttl_ptr); 1076ab25eeb5Syz else 1077ab25eeb5Syz ip->ip_ttl = 63; 1078ab25eeb5Syz if (ip_mtudisc != NULL) 1079ab25eeb5Syz ip->ip_off = htons(*ip_mtudisc ? IP_DF : 0); 1080ab25eeb5Syz else 1081ab25eeb5Syz ip->ip_off = htons(IP_DF); 10827c478bd9Sstevel@tonic-gate #endif 1083ab25eeb5Syz /* 1084ab25eeb5Syz * The dance with byte order and ip_len/ip_off is because in 1085ab25eeb5Syz * fr_fastroute, it expects them to be in host byte order but 1086ab25eeb5Syz * ipf_cksum expects them to be in network byte order. 1087ab25eeb5Syz */ 1088ab25eeb5Syz ip->ip_len = htons(ip->ip_len); 10897c478bd9Sstevel@tonic-gate ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip)); 1090ab25eeb5Syz ip->ip_len = ntohs(ip->ip_len); 1091ab25eeb5Syz ip->ip_off = ntohs(ip->ip_off); 1092ab25eeb5Syz hlen = sizeof(*ip); 1093923d6102Szf fnew.fin_plen = ip->ip_len; 10947c478bd9Sstevel@tonic-gate } 1095ab25eeb5Syz 1096ab25eeb5Syz qpip = fin->fin_qpi; 1097ab25eeb5Syz qpi.qpi_off = 0; 1098381a2a9aSdr qpi.qpi_ill = qpip->qpi_ill; 1099ab25eeb5Syz qpi.qpi_m = m; 1100ab25eeb5Syz qpi.qpi_data = ip; 1101ab25eeb5Syz fnew.fin_qpi = &qpi; 1102ab25eeb5Syz fnew.fin_ifp = fin->fin_ifp; 1103ab25eeb5Syz fnew.fin_flx = FI_NOCKSUM; 1104ab25eeb5Syz fnew.fin_m = m; 1105ab25eeb5Syz fnew.fin_ip = ip; 1106ab25eeb5Syz fnew.fin_mp = mpp; 1107ab25eeb5Syz fnew.fin_hlen = hlen; 1108ab25eeb5Syz fnew.fin_dp = (char *)ip + hlen; 1109f4b3ec61Sdh fnew.fin_ifs = fin->fin_ifs; 1110ab25eeb5Syz (void) fr_makefrip(hlen, ip, &fnew); 1111ab25eeb5Syz 1112ab25eeb5Syz i = fr_fastroute(m, mpp, &fnew, NULL); 11137c478bd9Sstevel@tonic-gate return i; 11147c478bd9Sstevel@tonic-gate } 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate int fr_send_icmp_err(type, fin, dst) 11187c478bd9Sstevel@tonic-gate int type; 11197c478bd9Sstevel@tonic-gate fr_info_t *fin; 11207c478bd9Sstevel@tonic-gate int dst; 11217c478bd9Sstevel@tonic-gate { 11227c478bd9Sstevel@tonic-gate struct in_addr dst4; 11237c478bd9Sstevel@tonic-gate struct icmp *icmp; 1124ab25eeb5Syz qpktinfo_t *qpi; 11257c478bd9Sstevel@tonic-gate int hlen, code; 1126381a2a9aSdr phy_if_t phy; 11277c478bd9Sstevel@tonic-gate u_short sz; 11287c478bd9Sstevel@tonic-gate #ifdef USE_INET6 11297c478bd9Sstevel@tonic-gate mblk_t *mb; 11307c478bd9Sstevel@tonic-gate #endif 11317c478bd9Sstevel@tonic-gate mblk_t *m; 11327c478bd9Sstevel@tonic-gate #ifdef USE_INET6 11337c478bd9Sstevel@tonic-gate ip6_t *ip6; 11347c478bd9Sstevel@tonic-gate #endif 11357c478bd9Sstevel@tonic-gate ip_t *ip; 1136f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate if ((type < 0) || (type > ICMP_MAXTYPE)) 11397c478bd9Sstevel@tonic-gate return -1; 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate code = fin->fin_icode; 11427c478bd9Sstevel@tonic-gate #ifdef USE_INET6 11437c478bd9Sstevel@tonic-gate if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) 11447c478bd9Sstevel@tonic-gate return -1; 11457c478bd9Sstevel@tonic-gate #endif 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate #ifndef IPFILTER_CKSUM 11487c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 11497c478bd9Sstevel@tonic-gate return -1; 11507c478bd9Sstevel@tonic-gate #endif 11517c478bd9Sstevel@tonic-gate 1152ab25eeb5Syz qpi = fin->fin_qpi; 11537c478bd9Sstevel@tonic-gate 11547c478bd9Sstevel@tonic-gate #ifdef USE_INET6 11557c478bd9Sstevel@tonic-gate mb = fin->fin_qfm; 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 11587c478bd9Sstevel@tonic-gate sz = sizeof(ip6_t); 11597c478bd9Sstevel@tonic-gate sz += MIN(mb->b_wptr - mb->b_rptr, 512); 11607c478bd9Sstevel@tonic-gate hlen = sizeof(ip6_t); 11617c478bd9Sstevel@tonic-gate type = icmptoicmp6types[type]; 11627c478bd9Sstevel@tonic-gate if (type == ICMP6_DST_UNREACH) 11637c478bd9Sstevel@tonic-gate code = icmptoicmp6unreach[code]; 11647c478bd9Sstevel@tonic-gate } else 11657c478bd9Sstevel@tonic-gate #endif 11667c478bd9Sstevel@tonic-gate { 11677c478bd9Sstevel@tonic-gate if ((fin->fin_p == IPPROTO_ICMP) && 11687c478bd9Sstevel@tonic-gate !(fin->fin_flx & FI_SHORT)) 11697c478bd9Sstevel@tonic-gate switch (ntohs(fin->fin_data[0]) >> 8) 11707c478bd9Sstevel@tonic-gate { 11717c478bd9Sstevel@tonic-gate case ICMP_ECHO : 11727c478bd9Sstevel@tonic-gate case ICMP_TSTAMP : 11737c478bd9Sstevel@tonic-gate case ICMP_IREQ : 11747c478bd9Sstevel@tonic-gate case ICMP_MASKREQ : 11757c478bd9Sstevel@tonic-gate break; 11767c478bd9Sstevel@tonic-gate default : 11777c478bd9Sstevel@tonic-gate return 0; 11787c478bd9Sstevel@tonic-gate } 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate sz = sizeof(ip_t) * 2; 11817c478bd9Sstevel@tonic-gate sz += 8; /* 64 bits of data */ 11827c478bd9Sstevel@tonic-gate hlen = sizeof(ip_t); 11837c478bd9Sstevel@tonic-gate } 11847c478bd9Sstevel@tonic-gate 11857c478bd9Sstevel@tonic-gate sz += offsetof(struct icmp, icmp_ip); 11867c478bd9Sstevel@tonic-gate if ((m = (mblk_t *)allocb((size_t)sz + 64, BPRI_HI)) == NULL) 11877c478bd9Sstevel@tonic-gate return -1; 11887c478bd9Sstevel@tonic-gate MTYPE(m) = M_DATA; 11897c478bd9Sstevel@tonic-gate m->b_rptr += 64; 11907c478bd9Sstevel@tonic-gate m->b_wptr = m->b_rptr + sz; 11917c478bd9Sstevel@tonic-gate bzero((char *)m->b_rptr, (size_t)sz); 1192ab25eeb5Syz ip = (ip_t *)m->b_rptr; 1193ab25eeb5Syz ip->ip_v = fin->fin_v; 11947c478bd9Sstevel@tonic-gate icmp = (struct icmp *)(m->b_rptr + hlen); 11957c478bd9Sstevel@tonic-gate icmp->icmp_type = type & 0xff; 11967c478bd9Sstevel@tonic-gate icmp->icmp_code = code & 0xff; 1197381a2a9aSdr phy = (phy_if_t)qpi->qpi_ill; 1198381a2a9aSdr if (type == ICMP_UNREACH && (phy != 0) && 11997c478bd9Sstevel@tonic-gate fin->fin_icode == ICMP_UNREACH_NEEDFRAG) 1200f4b3ec61Sdh icmp->icmp_nextmtu = net_getmtu(ifs->ifs_ipf_ipv4, phy,0 ); 12017c478bd9Sstevel@tonic-gate 12027c478bd9Sstevel@tonic-gate #ifdef USE_INET6 12037c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 12047c478bd9Sstevel@tonic-gate struct in6_addr dst6; 12057c478bd9Sstevel@tonic-gate int csz; 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate if (dst == 0) { 1208f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1209f4b3ec61Sdh 1210381a2a9aSdr if (fr_ifpaddr(6, FRI_NORMAL, (void *)phy, 1211f4b3ec61Sdh (void *)&dst6, NULL, ifs) == -1) { 12127c478bd9Sstevel@tonic-gate FREE_MB_T(m); 12137c478bd9Sstevel@tonic-gate return -1; 12147c478bd9Sstevel@tonic-gate } 12157c478bd9Sstevel@tonic-gate } else 12167c478bd9Sstevel@tonic-gate dst6 = fin->fin_dst6; 12177c478bd9Sstevel@tonic-gate 12187c478bd9Sstevel@tonic-gate csz = sz; 12197c478bd9Sstevel@tonic-gate sz -= sizeof(ip6_t); 12207c478bd9Sstevel@tonic-gate ip6 = (ip6_t *)m->b_rptr; 12217663b816Sml ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 12227c478bd9Sstevel@tonic-gate ip6->ip6_plen = htons((u_short)sz); 12237c478bd9Sstevel@tonic-gate ip6->ip6_nxt = IPPROTO_ICMPV6; 12247c478bd9Sstevel@tonic-gate ip6->ip6_src = dst6; 12257c478bd9Sstevel@tonic-gate ip6->ip6_dst = fin->fin_src6; 12267c478bd9Sstevel@tonic-gate sz -= offsetof(struct icmp, icmp_ip); 12277c478bd9Sstevel@tonic-gate bcopy((char *)mb->b_rptr, (char *)&icmp->icmp_ip, sz); 12287c478bd9Sstevel@tonic-gate icmp->icmp_cksum = csz - sizeof(ip6_t); 12297c478bd9Sstevel@tonic-gate } else 12307c478bd9Sstevel@tonic-gate #endif 12317c478bd9Sstevel@tonic-gate { 12327c478bd9Sstevel@tonic-gate ip->ip_hl = sizeof(*ip) >> 2; 12337c478bd9Sstevel@tonic-gate ip->ip_p = IPPROTO_ICMP; 12347c478bd9Sstevel@tonic-gate ip->ip_id = fin->fin_ip->ip_id; 12357c478bd9Sstevel@tonic-gate ip->ip_tos = fin->fin_ip->ip_tos; 123637b40788Sekozlow ip->ip_len = (u_short)sz; 12377c478bd9Sstevel@tonic-gate if (dst == 0) { 1238f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1239f4b3ec61Sdh 1240381a2a9aSdr if (fr_ifpaddr(4, FRI_NORMAL, (void *)phy, 1241f4b3ec61Sdh (void *)&dst4, NULL, ifs) == -1) { 12427c478bd9Sstevel@tonic-gate FREE_MB_T(m); 12437c478bd9Sstevel@tonic-gate return -1; 12447c478bd9Sstevel@tonic-gate } 1245381a2a9aSdr } else { 12467c478bd9Sstevel@tonic-gate dst4 = fin->fin_dst; 1247381a2a9aSdr } 12487c478bd9Sstevel@tonic-gate ip->ip_src = dst4; 12497c478bd9Sstevel@tonic-gate ip->ip_dst = fin->fin_src; 12507c478bd9Sstevel@tonic-gate bcopy((char *)fin->fin_ip, (char *)&icmp->icmp_ip, 12517c478bd9Sstevel@tonic-gate sizeof(*fin->fin_ip)); 12527c478bd9Sstevel@tonic-gate bcopy((char *)fin->fin_ip + fin->fin_hlen, 12537c478bd9Sstevel@tonic-gate (char *)&icmp->icmp_ip + sizeof(*fin->fin_ip), 8); 12547663b816Sml icmp->icmp_ip.ip_len = htons(icmp->icmp_ip.ip_len); 1255ab25eeb5Syz icmp->icmp_ip.ip_off = htons(icmp->icmp_ip.ip_off); 12567c478bd9Sstevel@tonic-gate icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 12577c478bd9Sstevel@tonic-gate sz - sizeof(ip_t)); 12587c478bd9Sstevel@tonic-gate } 12597c478bd9Sstevel@tonic-gate 12607c478bd9Sstevel@tonic-gate /* 12617c478bd9Sstevel@tonic-gate * Need to exit out of these so we don't recursively call rw_enter 12627c478bd9Sstevel@tonic-gate * from fr_qout. 12637c478bd9Sstevel@tonic-gate */ 1264ab25eeb5Syz return fr_send_ip(fin, m, &m); 12657c478bd9Sstevel@tonic-gate } 12667c478bd9Sstevel@tonic-gate 12677c478bd9Sstevel@tonic-gate #include <sys/time.h> 12687c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate #ifndef _KERNEL 12717c478bd9Sstevel@tonic-gate #include <stdio.h> 12727c478bd9Sstevel@tonic-gate #endif 12737c478bd9Sstevel@tonic-gate 12747c478bd9Sstevel@tonic-gate #define NULLADDR_RATE_LIMIT 10 /* 10 seconds */ 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate 12777c478bd9Sstevel@tonic-gate /* 12787c478bd9Sstevel@tonic-gate * Print out warning message at rate-limited speed. 12797c478bd9Sstevel@tonic-gate */ 1280f4b3ec61Sdh static void rate_limit_message(ipf_stack_t *ifs, 1281f4b3ec61Sdh int rate, const char *message, ...) 12827c478bd9Sstevel@tonic-gate { 12837c478bd9Sstevel@tonic-gate static time_t last_time = 0; 12847c478bd9Sstevel@tonic-gate time_t now; 12857c478bd9Sstevel@tonic-gate va_list args; 12867c478bd9Sstevel@tonic-gate char msg_buf[256]; 12877c478bd9Sstevel@tonic-gate int need_printed = 0; 12887c478bd9Sstevel@tonic-gate 12897c478bd9Sstevel@tonic-gate now = ddi_get_time(); 12907c478bd9Sstevel@tonic-gate 12917c478bd9Sstevel@tonic-gate /* make sure, no multiple entries */ 1292f4b3ec61Sdh ASSERT(MUTEX_NOT_HELD(&(ifs->ifs_ipf_rw.ipf_lk))); 1293f4b3ec61Sdh MUTEX_ENTER(&ifs->ifs_ipf_rw); 12947c478bd9Sstevel@tonic-gate if (now - last_time >= rate) { 12957c478bd9Sstevel@tonic-gate need_printed = 1; 12967c478bd9Sstevel@tonic-gate last_time = now; 12977c478bd9Sstevel@tonic-gate } 1298f4b3ec61Sdh MUTEX_EXIT(&ifs->ifs_ipf_rw); 12997c478bd9Sstevel@tonic-gate 13007c478bd9Sstevel@tonic-gate if (need_printed) { 13017c478bd9Sstevel@tonic-gate va_start(args, message); 13027c478bd9Sstevel@tonic-gate (void)vsnprintf(msg_buf, 255, message, args); 13037c478bd9Sstevel@tonic-gate va_end(args); 13047c478bd9Sstevel@tonic-gate #ifdef _KERNEL 13057c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, msg_buf); 13067c478bd9Sstevel@tonic-gate #else 13077c478bd9Sstevel@tonic-gate fprintf(std_err, msg_buf); 13087c478bd9Sstevel@tonic-gate #endif 13097c478bd9Sstevel@tonic-gate } 13107c478bd9Sstevel@tonic-gate } 13117c478bd9Sstevel@tonic-gate 13127c478bd9Sstevel@tonic-gate /* 13137c478bd9Sstevel@tonic-gate * return the first IP Address associated with an interface 13147c478bd9Sstevel@tonic-gate */ 13157c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1316f4b3ec61Sdh int fr_ifpaddr(v, atype, ifptr, inp, inpmask, ifs) 13177c478bd9Sstevel@tonic-gate int v, atype; 1318381a2a9aSdr void *ifptr; 1319381a2a9aSdr struct in_addr *inp, *inpmask; 1320f4b3ec61Sdh ipf_stack_t *ifs; 13217c478bd9Sstevel@tonic-gate { 1322381a2a9aSdr struct sockaddr_in6 v6addr[2]; 1323381a2a9aSdr struct sockaddr_in v4addr[2]; 1324381a2a9aSdr net_ifaddr_t type[2]; 1325381a2a9aSdr net_data_t net_data; 1326381a2a9aSdr phy_if_t phyif; 1327381a2a9aSdr void *array; 1328381a2a9aSdr 1329381a2a9aSdr switch (v) 1330381a2a9aSdr { 1331381a2a9aSdr case 4: 1332f4b3ec61Sdh net_data = ifs->ifs_ipf_ipv4; 1333381a2a9aSdr array = v4addr; 1334381a2a9aSdr break; 1335381a2a9aSdr case 6: 1336f4b3ec61Sdh net_data = ifs->ifs_ipf_ipv6; 1337381a2a9aSdr array = v6addr; 1338381a2a9aSdr break; 1339381a2a9aSdr default: 1340381a2a9aSdr net_data = NULL; 1341381a2a9aSdr break; 1342381a2a9aSdr } 13437c478bd9Sstevel@tonic-gate 1344381a2a9aSdr if (net_data == NULL) 13457c478bd9Sstevel@tonic-gate return -1; 13467c478bd9Sstevel@tonic-gate 1347381a2a9aSdr phyif = (phy_if_t)ifptr; 1348ab25eeb5Syz 1349ab25eeb5Syz switch (atype) 1350ab25eeb5Syz { 1351ab25eeb5Syz case FRI_PEERADDR : 1352381a2a9aSdr type[0] = NA_PEER; 1353ab25eeb5Syz break; 1354381a2a9aSdr 1355381a2a9aSdr case FRI_BROADCAST : 1356381a2a9aSdr type[0] = NA_BROADCAST; 1357381a2a9aSdr break; 1358381a2a9aSdr 1359ab25eeb5Syz default : 1360381a2a9aSdr type[0] = NA_ADDRESS; 1361ab25eeb5Syz break; 1362ab25eeb5Syz } 13637c478bd9Sstevel@tonic-gate 1364381a2a9aSdr type[1] = NA_NETMASK; 1365381a2a9aSdr 1366381a2a9aSdr if (net_getlifaddr(net_data, phyif, 0, 2, type, array) < 0) 13677c478bd9Sstevel@tonic-gate return -1; 1368381a2a9aSdr 1369381a2a9aSdr if (v == 6) { 1370381a2a9aSdr return fr_ifpfillv6addr(atype, &v6addr[0], &v6addr[1], 1371381a2a9aSdr inp, inpmask); 13727c478bd9Sstevel@tonic-gate } 1373381a2a9aSdr return fr_ifpfillv4addr(atype, &v4addr[0], &v4addr[1], inp, inpmask); 13747c478bd9Sstevel@tonic-gate } 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate 13777c478bd9Sstevel@tonic-gate u_32_t fr_newisn(fin) 13787c478bd9Sstevel@tonic-gate fr_info_t *fin; 13797c478bd9Sstevel@tonic-gate { 13807c478bd9Sstevel@tonic-gate static int iss_seq_off = 0; 13817c478bd9Sstevel@tonic-gate u_char hash[16]; 13827c478bd9Sstevel@tonic-gate u_32_t newiss; 13837c478bd9Sstevel@tonic-gate MD5_CTX ctx; 1384f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 13857c478bd9Sstevel@tonic-gate 13867c478bd9Sstevel@tonic-gate /* 13877c478bd9Sstevel@tonic-gate * Compute the base value of the ISS. It is a hash 13887c478bd9Sstevel@tonic-gate * of (saddr, sport, daddr, dport, secret). 13897c478bd9Sstevel@tonic-gate */ 13907c478bd9Sstevel@tonic-gate MD5Init(&ctx); 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 13937c478bd9Sstevel@tonic-gate sizeof(fin->fin_fi.fi_src)); 13947c478bd9Sstevel@tonic-gate MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 13957c478bd9Sstevel@tonic-gate sizeof(fin->fin_fi.fi_dst)); 13967c478bd9Sstevel@tonic-gate MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 13977c478bd9Sstevel@tonic-gate 1398f4b3ec61Sdh MD5Update(&ctx, ifs->ifs_ipf_iss_secret, sizeof(ifs->ifs_ipf_iss_secret)); 13997c478bd9Sstevel@tonic-gate 14007c478bd9Sstevel@tonic-gate MD5Final(hash, &ctx); 14017c478bd9Sstevel@tonic-gate 14027c478bd9Sstevel@tonic-gate bcopy(hash, &newiss, sizeof(newiss)); 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate /* 14057c478bd9Sstevel@tonic-gate * Now increment our "timer", and add it in to 14067c478bd9Sstevel@tonic-gate * the computed value. 14077c478bd9Sstevel@tonic-gate * 14087c478bd9Sstevel@tonic-gate * XXX Use `addin'? 14097c478bd9Sstevel@tonic-gate * XXX TCP_ISSINCR too large to use? 14107c478bd9Sstevel@tonic-gate */ 14117c478bd9Sstevel@tonic-gate iss_seq_off += 0x00010000; 14127c478bd9Sstevel@tonic-gate newiss += iss_seq_off; 14137c478bd9Sstevel@tonic-gate return newiss; 14147c478bd9Sstevel@tonic-gate } 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 14187c478bd9Sstevel@tonic-gate /* Function: fr_nextipid */ 14197c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 14207c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 14217c478bd9Sstevel@tonic-gate /* */ 14227c478bd9Sstevel@tonic-gate /* Returns the next IPv4 ID to use for this packet. */ 14237c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 1424ab25eeb5Syz u_short fr_nextipid(fin) 14257c478bd9Sstevel@tonic-gate fr_info_t *fin; 14267c478bd9Sstevel@tonic-gate { 14277c478bd9Sstevel@tonic-gate static u_short ipid = 0; 14287c478bd9Sstevel@tonic-gate ipstate_t *is; 14297c478bd9Sstevel@tonic-gate nat_t *nat; 14307c478bd9Sstevel@tonic-gate u_short id; 1431f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 14327c478bd9Sstevel@tonic-gate 1433f4b3ec61Sdh MUTEX_ENTER(&ifs->ifs_ipf_rw); 14347c478bd9Sstevel@tonic-gate if (fin->fin_state != NULL) { 14357c478bd9Sstevel@tonic-gate is = fin->fin_state; 14367c478bd9Sstevel@tonic-gate id = (u_short)(is->is_pkts[(fin->fin_rev << 1) + 1] & 0xffff); 14377c478bd9Sstevel@tonic-gate } else if (fin->fin_nat != NULL) { 14387c478bd9Sstevel@tonic-gate nat = fin->fin_nat; 14397c478bd9Sstevel@tonic-gate id = (u_short)(nat->nat_pkts[fin->fin_out] & 0xffff); 14407c478bd9Sstevel@tonic-gate } else 14417c478bd9Sstevel@tonic-gate id = ipid++; 1442f4b3ec61Sdh MUTEX_EXIT(&ifs->ifs_ipf_rw); 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate return id; 14457c478bd9Sstevel@tonic-gate } 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate 14487c478bd9Sstevel@tonic-gate #ifndef IPFILTER_CKSUM 14497c478bd9Sstevel@tonic-gate /* ARGSUSED */ 14507c478bd9Sstevel@tonic-gate #endif 14517c478bd9Sstevel@tonic-gate INLINE void fr_checkv4sum(fin) 14527c478bd9Sstevel@tonic-gate fr_info_t *fin; 14537c478bd9Sstevel@tonic-gate { 14547c478bd9Sstevel@tonic-gate #ifdef IPFILTER_CKSUM 14557c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 14567c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_BAD; 14577c478bd9Sstevel@tonic-gate #endif 14587c478bd9Sstevel@tonic-gate } 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate #ifdef USE_INET6 1462ab25eeb5Syz # ifndef IPFILTER_CKSUM 14637663b816Sml /* ARGSUSED */ 1464ab25eeb5Syz # endif 14657c478bd9Sstevel@tonic-gate INLINE void fr_checkv6sum(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 #endif /* USE_INET6 */ 1474ab25eeb5Syz 1475ab25eeb5Syz 1476ab25eeb5Syz #if (SOLARIS2 < 7) 1477ab25eeb5Syz void fr_slowtimer() 1478ab25eeb5Syz #else 1479ab25eeb5Syz /*ARGSUSED*/ 1480f4b3ec61Sdh void fr_slowtimer __P((void *arg)) 1481ab25eeb5Syz #endif 1482ab25eeb5Syz { 1483f4b3ec61Sdh ipf_stack_t *ifs = arg; 1484ab25eeb5Syz 1485f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 1486f4b3ec61Sdh if (ifs->ifs_fr_running == -1 || ifs->ifs_fr_running == 0) { 1487f4b3ec61Sdh ifs->ifs_fr_timer_id = timeout(fr_slowtimer, arg, drv_usectohz(500000)); 1488f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 1489ab25eeb5Syz return; 1490ab25eeb5Syz } 1491f4b3ec61Sdh MUTEX_DOWNGRADE(&ifs->ifs_ipf_global); 1492f4b3ec61Sdh 1493*fd636508Szf ipf_expiretokens(ifs); 1494f4b3ec61Sdh fr_fragexpire(ifs); 1495f4b3ec61Sdh fr_timeoutstate(ifs); 1496f4b3ec61Sdh fr_natexpire(ifs); 1497f4b3ec61Sdh fr_authexpire(ifs); 1498f4b3ec61Sdh ifs->ifs_fr_ticks++; 1499f4b3ec61Sdh if (ifs->ifs_fr_running == -1 || ifs->ifs_fr_running == 1) 1500f4b3ec61Sdh ifs->ifs_fr_timer_id = timeout(fr_slowtimer, arg, 1501f4b3ec61Sdh drv_usectohz(500000)); 1502ab25eeb5Syz else 1503f4b3ec61Sdh ifs->ifs_fr_timer_id = NULL; 1504f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 1505ab25eeb5Syz } 1506ab25eeb5Syz 1507ab25eeb5Syz 1508381a2a9aSdr /* ------------------------------------------------------------------------ */ 1509381a2a9aSdr /* Function: fr_pullup */ 1510381a2a9aSdr /* Returns: NULL == pullup failed, else pointer to protocol header */ 1511381a2a9aSdr /* Parameters: m(I) - pointer to buffer where data packet starts */ 1512381a2a9aSdr /* fin(I) - pointer to packet information */ 1513381a2a9aSdr /* len(I) - number of bytes to pullup */ 1514381a2a9aSdr /* */ 1515381a2a9aSdr /* Attempt to move at least len bytes (from the start of the buffer) into a */ 1516381a2a9aSdr /* single buffer for ease of access. Operating system native functions are */ 1517381a2a9aSdr /* used to manage buffers - if necessary. If the entire packet ends up in */ 1518381a2a9aSdr /* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */ 1519381a2a9aSdr /* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ 1520381a2a9aSdr /* and ONLY if the pullup succeeds. */ 1521381a2a9aSdr /* */ 1522381a2a9aSdr /* We assume that 'min' is a pointer to a buffer that is part of the chain */ 1523381a2a9aSdr /* of buffers that starts at *fin->fin_mp. */ 1524381a2a9aSdr /* ------------------------------------------------------------------------ */ 1525381a2a9aSdr void *fr_pullup(min, fin, len) 1526381a2a9aSdr mb_t *min; 1527381a2a9aSdr fr_info_t *fin; 1528381a2a9aSdr int len; 1529381a2a9aSdr { 1530381a2a9aSdr qpktinfo_t *qpi = fin->fin_qpi; 1531381a2a9aSdr int out = fin->fin_out, dpoff, ipoff; 1532381a2a9aSdr mb_t *m = min, *m1, *m2; 1533381a2a9aSdr char *ip; 153408ee25aeSdr uint32_t start, stuff, end, value, flags; 1535f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1536381a2a9aSdr 1537381a2a9aSdr if (m == NULL) 1538381a2a9aSdr return NULL; 1539381a2a9aSdr 1540381a2a9aSdr ip = (char *)fin->fin_ip; 1541381a2a9aSdr if ((fin->fin_flx & FI_COALESCE) != 0) 1542381a2a9aSdr return ip; 1543381a2a9aSdr 1544381a2a9aSdr ipoff = fin->fin_ipoff; 1545381a2a9aSdr if (fin->fin_dp != NULL) 1546381a2a9aSdr dpoff = (char *)fin->fin_dp - (char *)ip; 1547381a2a9aSdr else 1548381a2a9aSdr dpoff = 0; 1549381a2a9aSdr 1550381a2a9aSdr if (M_LEN(m) < len) { 1551381a2a9aSdr 1552381a2a9aSdr /* 1553381a2a9aSdr * pfil_precheck ensures the IP header is on a 32bit 1554381a2a9aSdr * aligned address so simply fail if that isn't currently 1555381a2a9aSdr * the case (should never happen). 1556381a2a9aSdr */ 1557381a2a9aSdr int inc = 0; 1558381a2a9aSdr 1559381a2a9aSdr if (ipoff > 0) { 1560381a2a9aSdr if ((ipoff & 3) != 0) { 1561381a2a9aSdr inc = 4 - (ipoff & 3); 1562381a2a9aSdr if (m->b_rptr - inc >= m->b_datap->db_base) 1563381a2a9aSdr m->b_rptr -= inc; 1564381a2a9aSdr else 1565381a2a9aSdr inc = 0; 1566381a2a9aSdr } 1567381a2a9aSdr } 1568381a2a9aSdr 1569381a2a9aSdr /* 1570381a2a9aSdr * XXX This is here as a work around for a bug with DEBUG 1571381a2a9aSdr * XXX Solaris kernels. The problem is b_prev is used by IP 1572381a2a9aSdr * XXX code as a way to stash the phyint_index for a packet, 1573381a2a9aSdr * XXX this doesn't get reset by IP but freeb does an ASSERT() 1574381a2a9aSdr * XXX for both of these to be NULL. See 6442390. 1575381a2a9aSdr */ 1576381a2a9aSdr m1 = m; 1577381a2a9aSdr m2 = m->b_prev; 1578381a2a9aSdr 1579381a2a9aSdr do { 1580381a2a9aSdr m1->b_next = NULL; 1581381a2a9aSdr m1->b_prev = NULL; 1582381a2a9aSdr m1 = m1->b_cont; 1583381a2a9aSdr } while (m1); 158408ee25aeSdr 158508ee25aeSdr /* 158608ee25aeSdr * Need to preserve checksum information by copying them 158708ee25aeSdr * to newmp which heads the pulluped message. 158808ee25aeSdr */ 158908ee25aeSdr hcksum_retrieve(m, NULL, NULL, &start, &stuff, &end, 159008ee25aeSdr &value, &flags); 159108ee25aeSdr 1592381a2a9aSdr if (pullupmsg(m, len + ipoff + inc) == 0) { 1593f4b3ec61Sdh ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[1]); 1594381a2a9aSdr FREE_MB_T(*fin->fin_mp); 1595381a2a9aSdr *fin->fin_mp = NULL; 1596381a2a9aSdr fin->fin_m = NULL; 1597381a2a9aSdr fin->fin_ip = NULL; 1598381a2a9aSdr fin->fin_dp = NULL; 1599381a2a9aSdr qpi->qpi_data = NULL; 1600381a2a9aSdr return NULL; 1601381a2a9aSdr } 160208ee25aeSdr 160308ee25aeSdr (void) hcksum_assoc(m, NULL, NULL, start, stuff, end, 160408ee25aeSdr value, flags, 0); 160508ee25aeSdr 1606381a2a9aSdr m->b_prev = m2; 1607381a2a9aSdr m->b_rptr += inc; 1608381a2a9aSdr fin->fin_m = m; 1609381a2a9aSdr ip = MTOD(m, char *) + ipoff; 1610381a2a9aSdr qpi->qpi_data = ip; 1611381a2a9aSdr } 1612381a2a9aSdr 1613f4b3ec61Sdh ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[0]); 1614381a2a9aSdr fin->fin_ip = (ip_t *)ip; 1615381a2a9aSdr if (fin->fin_dp != NULL) 1616381a2a9aSdr fin->fin_dp = (char *)fin->fin_ip + dpoff; 1617381a2a9aSdr 1618381a2a9aSdr if (len == fin->fin_plen) 1619381a2a9aSdr fin->fin_flx |= FI_COALESCE; 1620381a2a9aSdr return ip; 1621381a2a9aSdr } 1622381a2a9aSdr 1623381a2a9aSdr 1624ab25eeb5Syz /* 1625381a2a9aSdr * Function: fr_verifysrc 1626381a2a9aSdr * Returns: int (really boolean) 1627381a2a9aSdr * Parameters: fin - packet information 1628381a2a9aSdr * 1629381a2a9aSdr * Check whether the packet has a valid source address for the interface on 1630381a2a9aSdr * which the packet arrived, implementing the "fr_chksrc" feature. 1631381a2a9aSdr * Returns true iff the packet's source address is valid. 1632381a2a9aSdr */ 1633381a2a9aSdr int fr_verifysrc(fin) 1634381a2a9aSdr fr_info_t *fin; 1635381a2a9aSdr { 1636381a2a9aSdr net_data_t net_data_p; 1637381a2a9aSdr phy_if_t phy_ifdata_routeto; 1638381a2a9aSdr struct sockaddr sin; 1639f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1640381a2a9aSdr 1641381a2a9aSdr if (fin->fin_v == 4) { 1642f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv4; 1643381a2a9aSdr } else if (fin->fin_v == 6) { 1644f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv6; 1645381a2a9aSdr } else { 1646381a2a9aSdr return (0); 1647381a2a9aSdr } 1648381a2a9aSdr 1649381a2a9aSdr /* Get the index corresponding to the if name */ 1650381a2a9aSdr sin.sa_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 1651381a2a9aSdr bcopy(&fin->fin_saddr, &sin.sa_data, sizeof (struct in_addr)); 1652381a2a9aSdr phy_ifdata_routeto = net_routeto(net_data_p, &sin); 1653381a2a9aSdr 1654381a2a9aSdr return (((phy_if_t)fin->fin_ifp == phy_ifdata_routeto) ? 1 : 0); 1655381a2a9aSdr } 1656381a2a9aSdr 1657381a2a9aSdr 1658381a2a9aSdr /* 1659381a2a9aSdr * Function: fr_fastroute 1660381a2a9aSdr * Returns: 0: success; 1661381a2a9aSdr * -1: failed 1662ab25eeb5Syz * Parameters: 1663381a2a9aSdr * mb: the message block where ip head starts 1664381a2a9aSdr * mpp: the pointer to the pointer of the orignal 1665381a2a9aSdr * packet message 1666381a2a9aSdr * fin: packet information 1667381a2a9aSdr * fdp: destination interface information 1668381a2a9aSdr * if it is NULL, no interface information provided. 1669ab25eeb5Syz * 1670ab25eeb5Syz * This function is for fastroute/to/dup-to rules. It calls 1671ab25eeb5Syz * pfil_make_lay2_packet to search route, make lay-2 header 1672ab25eeb5Syz * ,and identify output queue for the IP packet. 1673ab25eeb5Syz * The destination address depends on the following conditions: 1674ab25eeb5Syz * 1: for fastroute rule, fdp is passed in as NULL, so the 1675381a2a9aSdr * destination address is the IP Packet's destination address 1676ab25eeb5Syz * 2: for to/dup-to rule, if an ip address is specified after 1677381a2a9aSdr * the interface name, this address is the as destination 1678381a2a9aSdr * address. Otherwise IP Packet's destination address is used 1679ab25eeb5Syz */ 1680ab25eeb5Syz int fr_fastroute(mb, mpp, fin, fdp) 1681ab25eeb5Syz mblk_t *mb, **mpp; 1682ab25eeb5Syz fr_info_t *fin; 1683ab25eeb5Syz frdest_t *fdp; 1684ab25eeb5Syz { 1685381a2a9aSdr net_data_t net_data_p; 1686381a2a9aSdr net_inject_t inj_data; 1687ab25eeb5Syz mblk_t *mp = NULL; 1688381a2a9aSdr frentry_t *fr = fin->fin_fr; 1689ab25eeb5Syz qpktinfo_t *qpi; 1690ab25eeb5Syz ip_t *ip; 1691381a2a9aSdr 1692381a2a9aSdr struct sockaddr_in *sin; 1693381a2a9aSdr struct sockaddr_in6 *sin6; 1694381a2a9aSdr struct sockaddr *sinp; 1695f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1696ab25eeb5Syz #ifndef sparc 1697ab25eeb5Syz u_short __iplen, __ipoff; 1698ab25eeb5Syz #endif 1699381a2a9aSdr 1700381a2a9aSdr if (fin->fin_v == 4) { 1701f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv4; 1702381a2a9aSdr } else if (fin->fin_v == 6) { 1703f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv6; 1704381a2a9aSdr } else { 1705381a2a9aSdr return (-1); 1706381a2a9aSdr } 1707381a2a9aSdr 1708ab25eeb5Syz ip = fin->fin_ip; 1709ab25eeb5Syz qpi = fin->fin_qpi; 1710ab25eeb5Syz 1711ab25eeb5Syz /* 1712ab25eeb5Syz * If this is a duplicate mblk then we want ip to point at that 1713ab25eeb5Syz * data, not the original, if and only if it is already pointing at 1714ab25eeb5Syz * the current mblk data. 1715381a2a9aSdr * 1716381a2a9aSdr * Otherwise, if it's not a duplicate, and we're not already pointing 1717e6c6c1faSyz * at the current mblk data, then we want to ensure that the data 1718e6c6c1faSyz * points at ip. 1719ab25eeb5Syz */ 1720381a2a9aSdr 1721381a2a9aSdr if ((ip == (ip_t *)qpi->qpi_m->b_rptr) && (qpi->qpi_m != mb)) { 1722ab25eeb5Syz ip = (ip_t *)mb->b_rptr; 1723381a2a9aSdr } else if ((qpi->qpi_m == mb) && (ip != (ip_t *)qpi->qpi_m->b_rptr)) { 1724381a2a9aSdr qpi->qpi_m->b_rptr = (uchar_t *)ip; 1725e6c6c1faSyz qpi->qpi_off = 0; 1726e6c6c1faSyz } 1727ab25eeb5Syz 1728ab25eeb5Syz /* 1729ab25eeb5Syz * If there is another M_PROTO, we don't want it 1730ab25eeb5Syz */ 1731ab25eeb5Syz if (*mpp != mb) { 1732ab25eeb5Syz mp = unlinkb(*mpp); 1733ab25eeb5Syz freeb(*mpp); 1734ab25eeb5Syz *mpp = mp; 1735ab25eeb5Syz } 1736ab25eeb5Syz 1737381a2a9aSdr sinp = (struct sockaddr *)&inj_data.ni_addr; 1738381a2a9aSdr sin = (struct sockaddr_in *)sinp; 1739381a2a9aSdr sin6 = (struct sockaddr_in6 *)sinp; 1740381a2a9aSdr bzero((char *)&inj_data.ni_addr, sizeof (inj_data.ni_addr)); 1741381a2a9aSdr inj_data.ni_addr.ss_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 1742381a2a9aSdr inj_data.ni_packet = mb; 1743ab25eeb5Syz 1744ab25eeb5Syz /* 1745ab25eeb5Syz * In case we're here due to "to <if>" being used with 1746ab25eeb5Syz * "keep state", check that we're going in the correct 1747ab25eeb5Syz * direction. 1748ab25eeb5Syz */ 1749381a2a9aSdr if (fdp != NULL) { 1750381a2a9aSdr if ((fr != NULL) && (fdp->fd_ifp != NULL) && 1751381a2a9aSdr (fin->fin_rev != 0) && (fdp == &fr->fr_tif)) 1752381a2a9aSdr goto bad_fastroute; 1753381a2a9aSdr inj_data.ni_physical = (phy_if_t)fdp->fd_ifp; 1754ab25eeb5Syz if (fin->fin_v == 4) { 1755381a2a9aSdr sin->sin_addr = fdp->fd_ip; 1756381a2a9aSdr } else { 1757381a2a9aSdr sin6->sin6_addr = fdp->fd_ip6.in6; 1758ab25eeb5Syz } 1759381a2a9aSdr } else { 1760381a2a9aSdr if (fin->fin_v == 4) { 1761381a2a9aSdr sin->sin_addr = ip->ip_dst; 1762381a2a9aSdr } else { 1763381a2a9aSdr sin6->sin6_addr = ((ip6_t *)ip)->ip6_dst; 1764ab25eeb5Syz } 1765381a2a9aSdr inj_data.ni_physical = net_routeto(net_data_p, sinp); 1766ab25eeb5Syz } 1767ab25eeb5Syz 1768edd26dc5Sdr /* 1769edd26dc5Sdr * Clear the hardware checksum flags from packets that we are doing 1770edd26dc5Sdr * input processing on as leaving them set will cause the outgoing 1771edd26dc5Sdr * NIC (if it supports hardware checksum) to calculate them anew, 1772edd26dc5Sdr * using the old (correct) checksums as the pseudo value to start 1773edd26dc5Sdr * from. 1774edd26dc5Sdr */ 1775edd26dc5Sdr if (fin->fin_out == 0) { 1776edd26dc5Sdr DB_CKSUMFLAGS(mb) = 0; 1777edd26dc5Sdr } 1778c793af95Ssangeeta 1779381a2a9aSdr *mpp = mb; 1780ab25eeb5Syz 1781381a2a9aSdr if (fin->fin_out == 0) { 1782381a2a9aSdr void *saveifp; 1783381a2a9aSdr u_32_t pass; 1784ab25eeb5Syz 1785381a2a9aSdr saveifp = fin->fin_ifp; 1786381a2a9aSdr fin->fin_ifp = (void *)inj_data.ni_physical; 1787d3675867Sjojemann fin->fin_flx &= ~FI_STATE; 1788381a2a9aSdr fin->fin_out = 1; 1789381a2a9aSdr (void) fr_acctpkt(fin, &pass); 1790381a2a9aSdr fin->fin_fr = NULL; 1791381a2a9aSdr if (!fr || !(fr->fr_flags & FR_RETMASK)) 1792381a2a9aSdr (void) fr_checkstate(fin, &pass); 1793d3675867Sjojemann if (fr_checknatout(fin, NULL) == -1) 1794381a2a9aSdr goto bad_fastroute; 1795381a2a9aSdr fin->fin_out = 0; 1796381a2a9aSdr fin->fin_ifp = saveifp; 1797ab25eeb5Syz 1798381a2a9aSdr if (fin->fin_nat != NULL) 1799f4b3ec61Sdh fr_natderef((nat_t **)&fin->fin_nat, ifs); 1800381a2a9aSdr } 1801381a2a9aSdr #ifndef sparc 1802381a2a9aSdr if (fin->fin_v == 4) { 1803381a2a9aSdr __iplen = (u_short)ip->ip_len, 1804381a2a9aSdr __ipoff = (u_short)ip->ip_off; 1805ab25eeb5Syz 1806381a2a9aSdr ip->ip_len = htons(__iplen); 1807381a2a9aSdr ip->ip_off = htons(__ipoff); 1808381a2a9aSdr } 1809ab25eeb5Syz #endif 1810381a2a9aSdr 1811381a2a9aSdr if (net_data_p) { 1812381a2a9aSdr if (net_inject(net_data_p, NI_DIRECT_OUT, &inj_data) < 0) { 1813381a2a9aSdr return (-1); 1814ab25eeb5Syz } 1815ab25eeb5Syz } 1816381a2a9aSdr 1817f4b3ec61Sdh ifs->ifs_fr_frouteok[0]++; 1818381a2a9aSdr return 0; 1819ab25eeb5Syz bad_fastroute: 1820ab25eeb5Syz freemsg(mb); 1821f4b3ec61Sdh ifs->ifs_fr_frouteok[1]++; 1822ab25eeb5Syz return -1; 1823ab25eeb5Syz } 1824ab25eeb5Syz 1825ab25eeb5Syz 1826ab25eeb5Syz /* ------------------------------------------------------------------------ */ 1827381a2a9aSdr /* Function: ipf_hook_out */ 1828381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1829381a2a9aSdr /* Parameters: event(I) - pointer to event */ 1830381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 1831ab25eeb5Syz /* */ 1832381a2a9aSdr /* Calling ipf_hook. */ 1833381a2a9aSdr /* ------------------------------------------------------------------------ */ 1834381a2a9aSdr /*ARGSUSED*/ 1835f4b3ec61Sdh int ipf_hook_out(hook_event_token_t token, hook_data_t info, netstack_t *ns) 1836381a2a9aSdr { 1837f4b3ec61Sdh return ipf_hook(info, 1, 0, ns); 1838381a2a9aSdr } 1839381a2a9aSdr 1840381a2a9aSdr /* ------------------------------------------------------------------------ */ 1841381a2a9aSdr /* Function: ipf_hook_in */ 1842381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1843381a2a9aSdr /* Parameters: event(I) - pointer to event */ 1844381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 1845ab25eeb5Syz /* */ 1846381a2a9aSdr /* Calling ipf_hook. */ 1847ab25eeb5Syz /* ------------------------------------------------------------------------ */ 1848381a2a9aSdr /*ARGSUSED*/ 1849f4b3ec61Sdh int ipf_hook_in(hook_event_token_t token, hook_data_t info, netstack_t *ns) 1850ab25eeb5Syz { 1851f4b3ec61Sdh return ipf_hook(info, 0, 0, ns); 1852381a2a9aSdr } 1853ab25eeb5Syz 1854ab25eeb5Syz 1855381a2a9aSdr /* ------------------------------------------------------------------------ */ 1856381a2a9aSdr /* Function: ipf_hook_loop_out */ 1857381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1858381a2a9aSdr /* Parameters: event(I) - pointer to event */ 1859381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 1860381a2a9aSdr /* */ 1861381a2a9aSdr /* Calling ipf_hook. */ 1862381a2a9aSdr /* ------------------------------------------------------------------------ */ 1863381a2a9aSdr /*ARGSUSED*/ 1864f4b3ec61Sdh int ipf_hook_loop_out(hook_event_token_t token, hook_data_t info, 1865f4b3ec61Sdh netstack_t *ns) 1866381a2a9aSdr { 1867f4b3ec61Sdh return ipf_hook(info, 1, 1, ns); 1868381a2a9aSdr } 1869ab25eeb5Syz 1870381a2a9aSdr /* ------------------------------------------------------------------------ */ 1871381a2a9aSdr /* Function: ipf_hook_loop_in */ 1872381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1873381a2a9aSdr /* Parameters: event(I) - pointer to event */ 1874381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 1875381a2a9aSdr /* */ 1876381a2a9aSdr /* Calling ipf_hook. */ 1877381a2a9aSdr /* ------------------------------------------------------------------------ */ 1878381a2a9aSdr /*ARGSUSED*/ 1879f4b3ec61Sdh int ipf_hook_loop_in(hook_event_token_t token, hook_data_t info, 1880f4b3ec61Sdh netstack_t *ns) 1881381a2a9aSdr { 1882f4b3ec61Sdh return ipf_hook(info, 0, 1, ns); 1883381a2a9aSdr } 1884381a2a9aSdr 1885381a2a9aSdr /* ------------------------------------------------------------------------ */ 1886381a2a9aSdr /* Function: ipf_hook */ 1887381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1888381a2a9aSdr /* Parameters: info(I) - pointer to hook information for firewalling */ 1889381a2a9aSdr /* out(I) - whether packet is going in or out */ 1890381a2a9aSdr /* loopback(I) - whether packet is a loopback packet or not */ 1891381a2a9aSdr /* */ 1892381a2a9aSdr /* Stepping stone function between the IP mainline and IPFilter. Extracts */ 1893381a2a9aSdr /* parameters out of the info structure and forms them up to be useful for */ 1894381a2a9aSdr /* calling ipfilter. */ 1895381a2a9aSdr /* ------------------------------------------------------------------------ */ 1896f4b3ec61Sdh int ipf_hook(hook_data_t info, int out, int loopback, netstack_t *ns) 1897381a2a9aSdr { 1898381a2a9aSdr hook_pkt_event_t *fw; 1899381a2a9aSdr int rval, v, hlen; 1900381a2a9aSdr qpktinfo_t qpi; 1901381a2a9aSdr u_short swap; 1902381a2a9aSdr phy_if_t phy; 1903381a2a9aSdr ip_t *ip; 1904381a2a9aSdr 1905381a2a9aSdr fw = (hook_pkt_event_t *)info; 1906381a2a9aSdr 1907381a2a9aSdr ASSERT(fw != NULL); 1908381a2a9aSdr phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp; 1909381a2a9aSdr 1910381a2a9aSdr ip = fw->hpe_hdr; 1911381a2a9aSdr v = ip->ip_v; 1912381a2a9aSdr if (v == IPV4_VERSION) { 1913381a2a9aSdr swap = ntohs(ip->ip_len); 1914381a2a9aSdr ip->ip_len = swap; 1915381a2a9aSdr swap = ntohs(ip->ip_off); 1916381a2a9aSdr ip->ip_off = swap; 1917381a2a9aSdr 1918381a2a9aSdr hlen = IPH_HDR_LENGTH(ip); 1919381a2a9aSdr } else 1920381a2a9aSdr hlen = sizeof (ip6_t); 1921381a2a9aSdr 1922381a2a9aSdr bzero(&qpi, sizeof (qpktinfo_t)); 1923381a2a9aSdr 1924381a2a9aSdr qpi.qpi_m = fw->hpe_mb; 1925381a2a9aSdr qpi.qpi_data = fw->hpe_hdr; 1926381a2a9aSdr qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr; 1927381a2a9aSdr qpi.qpi_ill = (void *)phy; 19281b47e080Sdr qpi.qpi_flags = 0; 19291b47e080Sdr if (fw->hpe_flags & HPE_MULTICAST) 19301b47e080Sdr qpi.qpi_flags |= FI_MBCAST|FI_MULTICAST; 19311b47e080Sdr else if (fw->hpe_flags & HPE_BROADCAST) 19321b47e080Sdr qpi.qpi_flags = FI_MBCAST|FI_BROADCAST; 1933381a2a9aSdr if (loopback) 19341b47e080Sdr qpi.qpi_flags |= FI_NOCKSUM; 1935381a2a9aSdr 1936f4b3ec61Sdh rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, 1937f4b3ec61Sdh &qpi, fw->hpe_mp, ns->netstack_ipf); 1938381a2a9aSdr 1939381a2a9aSdr /* For fastroute cases, fr_check returns 0 with mp set to NULL */ 1940381a2a9aSdr if (rval == 0 && *(fw->hpe_mp) == NULL) 1941381a2a9aSdr rval = 1; 1942381a2a9aSdr 1943381a2a9aSdr /* Notify IP the packet mblk_t and IP header pointers. */ 1944381a2a9aSdr fw->hpe_mb = qpi.qpi_m; 1945381a2a9aSdr fw->hpe_hdr = qpi.qpi_data; 1946381a2a9aSdr if ((rval == 0) && (v == IPV4_VERSION)) { 1947381a2a9aSdr ip = qpi.qpi_data; 1948381a2a9aSdr swap = ntohs(ip->ip_len); 1949381a2a9aSdr ip->ip_len = swap; 1950381a2a9aSdr swap = ntohs(ip->ip_off); 1951381a2a9aSdr ip->ip_off = swap; 1952381a2a9aSdr } 1953381a2a9aSdr return rval; 1954ab25eeb5Syz 1955381a2a9aSdr } 1956ab25eeb5Syz 1957ab25eeb5Syz 1958381a2a9aSdr /* ------------------------------------------------------------------------ */ 1959381a2a9aSdr /* Function: ipf_nic_event_v4 */ 1960381a2a9aSdr /* Returns: int - 0 == no problems encountered */ 1961381a2a9aSdr /* Parameters: event(I) - pointer to event */ 1962381a2a9aSdr /* info(I) - pointer to information about a NIC event */ 1963381a2a9aSdr /* */ 1964381a2a9aSdr /* Function to receive asynchronous NIC events from IP */ 1965381a2a9aSdr /* ------------------------------------------------------------------------ */ 1966381a2a9aSdr /*ARGSUSED*/ 1967f4b3ec61Sdh int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info, 1968f4b3ec61Sdh netstack_t *ns) 1969381a2a9aSdr { 1970381a2a9aSdr struct sockaddr_in *sin; 1971381a2a9aSdr hook_nic_event_t *hn; 1972f4b3ec61Sdh ipf_stack_t *ifs = ns->netstack_ipf; 1973381a2a9aSdr 1974381a2a9aSdr hn = (hook_nic_event_t *)info; 1975381a2a9aSdr 1976381a2a9aSdr switch (hn->hne_event) 1977381a2a9aSdr { 1978381a2a9aSdr case NE_PLUMB : 1979a4cf92b0Sdr frsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, hn->hne_data, 1980a4cf92b0Sdr ifs); 1981381a2a9aSdr fr_natifpsync(IPFSYNC_NEWIFP, (void *)hn->hne_nic, 1982f4b3ec61Sdh hn->hne_data, ifs); 1983381a2a9aSdr fr_statesync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, 1984f4b3ec61Sdh hn->hne_data, ifs); 1985381a2a9aSdr break; 1986381a2a9aSdr 1987381a2a9aSdr case NE_UNPLUMB : 1988f4b3ec61Sdh frsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 1989f4b3ec61Sdh fr_natifpsync(IPFSYNC_OLDIFP, (void *)hn->hne_nic, NULL, ifs); 1990f4b3ec61Sdh fr_statesync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 1991381a2a9aSdr break; 1992381a2a9aSdr 1993381a2a9aSdr case NE_ADDRESS_CHANGE : 1994a4cf92b0Sdr /* 1995a4cf92b0Sdr * We only respond to events for logical interface 0 because 1996a4cf92b0Sdr * IPFilter only uses the first address given to a network 1997a4cf92b0Sdr * interface. We check for hne_lif==1 because the netinfo 1998a4cf92b0Sdr * code maps adds 1 to the lif number so that it can return 1999a4cf92b0Sdr * 0 to indicate "no more lifs" when walking them. 2000a4cf92b0Sdr */ 2001a4cf92b0Sdr if (hn->hne_lif == 1) { 2002a4cf92b0Sdr frsync(IPFSYNC_RESYNC, 4, (void *)hn->hne_nic, NULL, 2003a4cf92b0Sdr ifs); 2004a4cf92b0Sdr sin = hn->hne_data; 2005a4cf92b0Sdr fr_nataddrsync((void *)hn->hne_nic, &sin->sin_addr, 2006a4cf92b0Sdr ifs); 2007a4cf92b0Sdr } 2008381a2a9aSdr break; 2009381a2a9aSdr 2010381a2a9aSdr default : 2011381a2a9aSdr break; 2012ab25eeb5Syz } 2013ab25eeb5Syz 2014381a2a9aSdr return 0; 2015381a2a9aSdr } 2016ab25eeb5Syz 2017381a2a9aSdr 2018381a2a9aSdr /* ------------------------------------------------------------------------ */ 2019381a2a9aSdr /* Function: ipf_nic_event_v6 */ 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_v6(hook_event_token_t event, hook_data_t info, 2028f4b3ec61Sdh netstack_t *ns) 2029381a2a9aSdr { 2030381a2a9aSdr hook_nic_event_t *hn; 2031f4b3ec61Sdh ipf_stack_t *ifs = ns->netstack_ipf; 2032381a2a9aSdr 2033381a2a9aSdr hn = (hook_nic_event_t *)info; 2034381a2a9aSdr 2035381a2a9aSdr switch (hn->hne_event) 2036381a2a9aSdr { 2037381a2a9aSdr case NE_PLUMB : 2038f4b3ec61Sdh frsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, hn->hne_data, ifs); 2039381a2a9aSdr fr_statesync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2040f4b3ec61Sdh hn->hne_data, ifs); 2041381a2a9aSdr break; 2042381a2a9aSdr 2043381a2a9aSdr case NE_UNPLUMB : 2044f4b3ec61Sdh frsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2045f4b3ec61Sdh fr_statesync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2046381a2a9aSdr break; 2047381a2a9aSdr 2048381a2a9aSdr case NE_ADDRESS_CHANGE : 2049381a2a9aSdr break; 2050381a2a9aSdr default : 2051381a2a9aSdr break; 2052381a2a9aSdr } 2053381a2a9aSdr 2054381a2a9aSdr return 0; 2055ab25eeb5Syz } 2056