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 * 633f2fefdSDarren Reed * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 77c478bd9Sstevel@tonic-gate * Use is subject to license terms. 87c478bd9Sstevel@tonic-gate */ 97c478bd9Sstevel@tonic-gate 107c478bd9Sstevel@tonic-gate #if !defined(lint) 11c793af95Ssangeeta static const char sccsid[] = "@(#)ip_fil_solaris.c 1.7 07/22/06 (C) 1993-2000 Darren Reed"; 12ab25eeb5Syz static const char rcsid[] = "@(#)$Id: ip_fil_solaris.c,v 2.62.2.19 2005/07/13 21:40:46 darrenr Exp $"; 137c478bd9Sstevel@tonic-gate #endif 147c478bd9Sstevel@tonic-gate 157c478bd9Sstevel@tonic-gate #include <sys/types.h> 167c478bd9Sstevel@tonic-gate #include <sys/errno.h> 177c478bd9Sstevel@tonic-gate #include <sys/param.h> 187c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 197c478bd9Sstevel@tonic-gate #include <sys/open.h> 207c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 217c478bd9Sstevel@tonic-gate #include <sys/filio.h> 227c478bd9Sstevel@tonic-gate #include <sys/systm.h> 23ab25eeb5Syz #include <sys/strsubr.h> 247c478bd9Sstevel@tonic-gate #include <sys/cred.h> 25f4b3ec61Sdh #include <sys/cred_impl.h> 267c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 277c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 287c478bd9Sstevel@tonic-gate #include <sys/ksynch.h> 297c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 307c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 317c478bd9Sstevel@tonic-gate #include <sys/protosw.h> 327c478bd9Sstevel@tonic-gate #include <sys/socket.h> 337c478bd9Sstevel@tonic-gate #include <sys/dditypes.h> 347c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 35f4b3ec61Sdh #include <sys/zone.h> 367c478bd9Sstevel@tonic-gate #include <net/if.h> 377c478bd9Sstevel@tonic-gate #include <net/af.h> 387c478bd9Sstevel@tonic-gate #include <net/route.h> 397c478bd9Sstevel@tonic-gate #include <netinet/in.h> 407c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h> 417c478bd9Sstevel@tonic-gate #include <netinet/ip.h> 427c478bd9Sstevel@tonic-gate #include <netinet/ip_var.h> 437c478bd9Sstevel@tonic-gate #include <netinet/tcp.h> 447c478bd9Sstevel@tonic-gate #include <netinet/udp.h> 457c478bd9Sstevel@tonic-gate #include <netinet/tcpip.h> 467c478bd9Sstevel@tonic-gate #include <netinet/ip_icmp.h> 47ab25eeb5Syz #include "netinet/ip_compat.h" 487c478bd9Sstevel@tonic-gate #ifdef USE_INET6 497c478bd9Sstevel@tonic-gate # include <netinet/icmp6.h> 507c478bd9Sstevel@tonic-gate #endif 51ab25eeb5Syz #include "netinet/ip_fil.h" 52ab25eeb5Syz #include "netinet/ip_nat.h" 53ab25eeb5Syz #include "netinet/ip_frag.h" 54ab25eeb5Syz #include "netinet/ip_state.h" 55ab25eeb5Syz #include "netinet/ip_auth.h" 56ab25eeb5Syz #include "netinet/ip_proxy.h" 57f4b3ec61Sdh #include "netinet/ipf_stack.h" 587c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOOKUP 59ab25eeb5Syz # include "netinet/ip_lookup.h" 607c478bd9Sstevel@tonic-gate #endif 617c478bd9Sstevel@tonic-gate #include <inet/ip_ire.h> 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate #include <sys/md5.h> 64381a2a9aSdr #include <sys/neti.h> 657c478bd9Sstevel@tonic-gate 66f4b3ec61Sdh static int frzerostats __P((caddr_t, ipf_stack_t *)); 67f4b3ec61Sdh static int fr_setipfloopback __P((int, ipf_stack_t *)); 687ddc9b1aSDarren Reed static int fr_enableipf __P((ipf_stack_t *, int)); 69ab25eeb5Syz static int fr_send_ip __P((fr_info_t *fin, mblk_t *m, mblk_t **mp)); 707ddc9b1aSDarren Reed static int ipf_nic_event_v4 __P((hook_event_token_t, hook_data_t, void *)); 717ddc9b1aSDarren Reed static int ipf_nic_event_v6 __P((hook_event_token_t, hook_data_t, void *)); 727ddc9b1aSDarren Reed static int ipf_hook __P((hook_data_t, int, int, void *)); 737ddc9b1aSDarren Reed static int ipf_hook4_in __P((hook_event_token_t, hook_data_t, void *)); 747ddc9b1aSDarren Reed static int ipf_hook4_out __P((hook_event_token_t, hook_data_t, void *)); 75cbded9aeSdr static int ipf_hook4_loop_out __P((hook_event_token_t, hook_data_t, 767ddc9b1aSDarren Reed void *)); 777ddc9b1aSDarren Reed static int ipf_hook4_loop_in __P((hook_event_token_t, hook_data_t, void *)); 787ddc9b1aSDarren Reed static int ipf_hook4 __P((hook_data_t, int, int, void *)); 797ddc9b1aSDarren Reed static int ipf_hook6_out __P((hook_event_token_t, hook_data_t, void *)); 807ddc9b1aSDarren Reed static int ipf_hook6_in __P((hook_event_token_t, hook_data_t, void *)); 81cbded9aeSdr static int ipf_hook6_loop_out __P((hook_event_token_t, hook_data_t, 827ddc9b1aSDarren Reed void *)); 83cbded9aeSdr static int ipf_hook6_loop_in __P((hook_event_token_t, hook_data_t, 847ddc9b1aSDarren Reed void *)); 857ddc9b1aSDarren Reed static int ipf_hook6 __P((hook_data_t, int, int, void *)); 86f4b3ec61Sdh extern int ipf_geniter __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *)); 87f4b3ec61Sdh extern int ipf_frruleiter __P((void *, int, void *, ipf_stack_t *)); 88f4b3ec61Sdh 897c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 907c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 7 91ab25eeb5Syz u_int *ip_ttl_ptr = NULL; 92ab25eeb5Syz u_int *ip_mtudisc = NULL; 937c478bd9Sstevel@tonic-gate # if SOLARIS2 >= 8 94ab25eeb5Syz int *ip_forwarding = NULL; 95ab25eeb5Syz u_int *ip6_forwarding = NULL; 967c478bd9Sstevel@tonic-gate # else 97ab25eeb5Syz u_int *ip_forwarding = NULL; 987c478bd9Sstevel@tonic-gate # endif 997c478bd9Sstevel@tonic-gate #else 100ab25eeb5Syz u_long *ip_ttl_ptr = NULL; 101ab25eeb5Syz u_long *ip_mtudisc = NULL; 102ab25eeb5Syz u_long *ip_forwarding = NULL; 1037c478bd9Sstevel@tonic-gate #endif 1047c478bd9Sstevel@tonic-gate #endif 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 1087c478bd9Sstevel@tonic-gate /* Function: ipldetach */ 1097c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, else error. */ 1107c478bd9Sstevel@tonic-gate /* Parameters: Nil */ 1117c478bd9Sstevel@tonic-gate /* */ 1127c478bd9Sstevel@tonic-gate /* This function is responsible for undoing anything that might have been */ 1137c478bd9Sstevel@tonic-gate /* done in a call to iplattach(). It must be able to clean up from a call */ 1147c478bd9Sstevel@tonic-gate /* to iplattach() that did not succeed. Why might that happen? Someone */ 1157c478bd9Sstevel@tonic-gate /* configures a table to be so large that we cannot allocate enough memory */ 1167c478bd9Sstevel@tonic-gate /* for it. */ 1177c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 118f4b3ec61Sdh int ipldetach(ifs) 119f4b3ec61Sdh ipf_stack_t *ifs; 1207c478bd9Sstevel@tonic-gate { 1217c478bd9Sstevel@tonic-gate 122f4b3ec61Sdh ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0); 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 1257c478bd9Sstevel@tonic-gate 126f4b3ec61Sdh if (ifs->ifs_fr_control_forwarding & 2) { 127ab25eeb5Syz if (ip_forwarding != NULL) 128ab25eeb5Syz *ip_forwarding = 0; 1297c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 130ab25eeb5Syz if (ip6_forwarding != NULL) 131ab25eeb5Syz *ip6_forwarding = 0; 1327c478bd9Sstevel@tonic-gate #endif 1337c478bd9Sstevel@tonic-gate } 1347c478bd9Sstevel@tonic-gate #endif 1357c478bd9Sstevel@tonic-gate 136381a2a9aSdr /* 1377ddc9b1aSDarren Reed * This lock needs to be dropped around the net_hook_unregister calls 138381a2a9aSdr * because we can deadlock here with: 139381a2a9aSdr * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs 140381a2a9aSdr * R(hook_family)->R(hei_lock)->R(ipf_global) (active hook running) 141381a2a9aSdr */ 142f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 143381a2a9aSdr 1447ddc9b1aSDarren Reed #define UNDO_HOOK(_f, _b, _e, _h) \ 1457ddc9b1aSDarren Reed do { \ 1467ddc9b1aSDarren Reed if (ifs->_f != NULL) { \ 1477ddc9b1aSDarren Reed if (ifs->_b) { \ 1487ddc9b1aSDarren Reed ifs->_b = (net_hook_unregister(ifs->_f, \ 1497ddc9b1aSDarren Reed _e, ifs->_h) != 0); \ 1507ddc9b1aSDarren Reed if (!ifs->_b) { \ 1517ddc9b1aSDarren Reed hook_free(ifs->_h); \ 1527ddc9b1aSDarren Reed ifs->_h = NULL; \ 1537ddc9b1aSDarren Reed } \ 1547ddc9b1aSDarren Reed } else if (ifs->_h != NULL) { \ 1557ddc9b1aSDarren Reed hook_free(ifs->_h); \ 1567ddc9b1aSDarren Reed ifs->_h = NULL; \ 1577ddc9b1aSDarren Reed } \ 1587ddc9b1aSDarren Reed } \ 1597ddc9b1aSDarren Reed _NOTE(CONSTCOND) \ 1607ddc9b1aSDarren Reed } while (0) 1617ddc9b1aSDarren Reed 162381a2a9aSdr /* 163381a2a9aSdr * Remove IPv6 Hooks 164381a2a9aSdr */ 165f4b3ec61Sdh if (ifs->ifs_ipf_ipv6 != NULL) { 1667ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_in, 1677ddc9b1aSDarren Reed NH_PHYSICAL_IN, ifs_ipfhook6_in); 1687ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_out, 1697ddc9b1aSDarren Reed NH_PHYSICAL_OUT, ifs_ipfhook6_out); 1707ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_nic_events, 1717ddc9b1aSDarren Reed NH_NIC_EVENTS, ifs_ipfhook6_nicevents); 1727ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_in, 1737ddc9b1aSDarren Reed NH_LOOPBACK_IN, ifs_ipfhook6_loop_in); 1747ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_out, 1757ddc9b1aSDarren Reed NH_LOOPBACK_OUT, ifs_ipfhook6_loop_out); 1767ddc9b1aSDarren Reed 1777ddc9b1aSDarren Reed if (net_protocol_release(ifs->ifs_ipf_ipv6) != 0) 178381a2a9aSdr goto detach_failed; 179f4b3ec61Sdh ifs->ifs_ipf_ipv6 = NULL; 180381a2a9aSdr } 181381a2a9aSdr 182381a2a9aSdr /* 183381a2a9aSdr * Remove IPv4 Hooks 184381a2a9aSdr */ 185f4b3ec61Sdh if (ifs->ifs_ipf_ipv4 != NULL) { 1867ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_in, 1877ddc9b1aSDarren Reed NH_PHYSICAL_IN, ifs_ipfhook4_in); 1887ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_out, 1897ddc9b1aSDarren Reed NH_PHYSICAL_OUT, ifs_ipfhook4_out); 1907ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_nic_events, 1917ddc9b1aSDarren Reed NH_NIC_EVENTS, ifs_ipfhook4_nicevents); 1927ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_in, 1937ddc9b1aSDarren Reed NH_LOOPBACK_IN, ifs_ipfhook4_loop_in); 1947ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_out, 1957ddc9b1aSDarren Reed NH_LOOPBACK_OUT, ifs_ipfhook4_loop_out); 1967ddc9b1aSDarren Reed 1977ddc9b1aSDarren Reed if (net_protocol_release(ifs->ifs_ipf_ipv4) != 0) 198381a2a9aSdr goto detach_failed; 199f4b3ec61Sdh ifs->ifs_ipf_ipv4 = NULL; 200381a2a9aSdr } 201381a2a9aSdr 2027ddc9b1aSDarren Reed #undef UNDO_HOOK 2037ddc9b1aSDarren Reed 2047c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 2057c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "ipldetach()\n"); 2067c478bd9Sstevel@tonic-gate #endif 2077c478bd9Sstevel@tonic-gate 208f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 209f4b3ec61Sdh fr_deinitialise(ifs); 2107c478bd9Sstevel@tonic-gate 211f4b3ec61Sdh (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE, ifs); 212f4b3ec61Sdh (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE, ifs); 2137c478bd9Sstevel@tonic-gate 214f4b3ec61Sdh if (ifs->ifs_ipf_locks_done == 1) { 215f4b3ec61Sdh MUTEX_DESTROY(&ifs->ifs_ipf_timeoutlock); 216f4b3ec61Sdh MUTEX_DESTROY(&ifs->ifs_ipf_rw); 217f4b3ec61Sdh RW_DESTROY(&ifs->ifs_ipf_tokens); 218f4b3ec61Sdh RW_DESTROY(&ifs->ifs_ipf_ipidfrag); 219f4b3ec61Sdh ifs->ifs_ipf_locks_done = 0; 2207c478bd9Sstevel@tonic-gate } 221381a2a9aSdr 2227ddc9b1aSDarren Reed if (ifs->ifs_hook4_physical_in || ifs->ifs_hook4_physical_out || 2237ddc9b1aSDarren Reed ifs->ifs_hook4_nic_events || ifs->ifs_hook4_loopback_in || 2247ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_out || ifs->ifs_hook6_nic_events || 2257ddc9b1aSDarren Reed ifs->ifs_hook6_physical_in || ifs->ifs_hook6_physical_out || 2267ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_in || ifs->ifs_hook6_loopback_out) 227381a2a9aSdr return -1; 228381a2a9aSdr 2297c478bd9Sstevel@tonic-gate return 0; 230381a2a9aSdr 231381a2a9aSdr detach_failed: 232f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 233381a2a9aSdr return -1; 2347c478bd9Sstevel@tonic-gate } 2357c478bd9Sstevel@tonic-gate 2367ddc9b1aSDarren Reed int iplattach(ifs) 237f4b3ec61Sdh ipf_stack_t *ifs; 2387c478bd9Sstevel@tonic-gate { 2397c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 2407c478bd9Sstevel@tonic-gate int i; 2417c478bd9Sstevel@tonic-gate #endif 2427ddc9b1aSDarren Reed netid_t id = ifs->ifs_netid; 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 2457c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplattach()\n"); 2467c478bd9Sstevel@tonic-gate #endif 2477c478bd9Sstevel@tonic-gate 248f4b3ec61Sdh ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0); 249f4b3ec61Sdh ifs->ifs_fr_flags = IPF_LOGGING; 250f4b3ec61Sdh #ifdef _KERNEL 251f4b3ec61Sdh ifs->ifs_fr_update_ipid = 0; 252f4b3ec61Sdh #else 253f4b3ec61Sdh ifs->ifs_fr_update_ipid = 1; 254f4b3ec61Sdh #endif 255f4b3ec61Sdh ifs->ifs_fr_minttl = 4; 256f4b3ec61Sdh ifs->ifs_fr_icmpminfragmtu = 68; 257f4b3ec61Sdh #if defined(IPFILTER_DEFAULT_BLOCK) 258f4b3ec61Sdh ifs->ifs_fr_pass = FR_BLOCK|FR_NOMATCH; 259f4b3ec61Sdh #else 260f4b3ec61Sdh ifs->ifs_fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH; 261f4b3ec61Sdh #endif 2627c478bd9Sstevel@tonic-gate 263f4b3ec61Sdh MUTEX_INIT(&ifs->ifs_ipf_rw, "ipf rw mutex"); 264f4b3ec61Sdh MUTEX_INIT(&ifs->ifs_ipf_timeoutlock, "ipf timeout lock mutex"); 265f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); 266f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_tokens, "ipf token rwlock"); 267f4b3ec61Sdh ifs->ifs_ipf_locks_done = 1; 2687c478bd9Sstevel@tonic-gate 269f4b3ec61Sdh if (fr_initialise(ifs) < 0) 2707c478bd9Sstevel@tonic-gate return -1; 2717c478bd9Sstevel@tonic-gate 2727ddc9b1aSDarren Reed HOOK_INIT(ifs->ifs_ipfhook4_nicevents, ipf_nic_event_v4, 2737ddc9b1aSDarren Reed "ipfilter_hook4_nicevents", ifs); 2747ddc9b1aSDarren Reed HOOK_INIT(ifs->ifs_ipfhook4_in, ipf_hook4_in, 2757ddc9b1aSDarren Reed "ipfilter_hook4_in", ifs); 2767ddc9b1aSDarren Reed HOOK_INIT(ifs->ifs_ipfhook4_out, ipf_hook4_out, 2777ddc9b1aSDarren Reed "ipfilter_hook4_out", ifs); 27840cdc2e8SAlexandr Nedvedicky HOOK_INIT(ifs->ifs_ipfhook4_loop_in, ipf_hook4_loop_in, 2797ddc9b1aSDarren Reed "ipfilter_hook4_loop_in", ifs); 28040cdc2e8SAlexandr Nedvedicky HOOK_INIT(ifs->ifs_ipfhook4_loop_out, ipf_hook4_loop_out, 2817ddc9b1aSDarren Reed "ipfilter_hook4_loop_out", ifs); 282381a2a9aSdr 283381a2a9aSdr /* 2847ddc9b1aSDarren Reed * If we hold this lock over all of the net_hook_register calls, we 285381a2a9aSdr * can cause a deadlock to occur with the following lock ordering: 286381a2a9aSdr * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs 287381a2a9aSdr * R(hook_family)->R(hei_lock)->R(ipf_global) (packet path) 288381a2a9aSdr */ 289f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 290381a2a9aSdr 291381a2a9aSdr /* 292381a2a9aSdr * Add IPv4 hooks 293381a2a9aSdr */ 2947ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4 = net_protocol_lookup(id, NHF_INET); 295f4b3ec61Sdh if (ifs->ifs_ipf_ipv4 == NULL) 296381a2a9aSdr goto hookup_failed; 297381a2a9aSdr 2987ddc9b1aSDarren Reed ifs->ifs_hook4_nic_events = (net_hook_register(ifs->ifs_ipf_ipv4, 2997ddc9b1aSDarren Reed NH_NIC_EVENTS, ifs->ifs_ipfhook4_nicevents) == 0); 300f4b3ec61Sdh if (!ifs->ifs_hook4_nic_events) 301381a2a9aSdr goto hookup_failed; 302381a2a9aSdr 3037ddc9b1aSDarren Reed ifs->ifs_hook4_physical_in = (net_hook_register(ifs->ifs_ipf_ipv4, 3047ddc9b1aSDarren Reed NH_PHYSICAL_IN, ifs->ifs_ipfhook4_in) == 0); 305f4b3ec61Sdh if (!ifs->ifs_hook4_physical_in) 306381a2a9aSdr goto hookup_failed; 307381a2a9aSdr 3087ddc9b1aSDarren Reed ifs->ifs_hook4_physical_out = (net_hook_register(ifs->ifs_ipf_ipv4, 3097ddc9b1aSDarren Reed NH_PHYSICAL_OUT, ifs->ifs_ipfhook4_out) == 0); 310f4b3ec61Sdh if (!ifs->ifs_hook4_physical_out) 311381a2a9aSdr goto hookup_failed; 312381a2a9aSdr 313f4b3ec61Sdh if (ifs->ifs_ipf_loopback) { 3147ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_in = (net_hook_register( 3157ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN, 3167ddc9b1aSDarren Reed ifs->ifs_ipfhook4_loop_in) == 0); 317f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_in) 318381a2a9aSdr goto hookup_failed; 319381a2a9aSdr 3207ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_out = (net_hook_register( 3217ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT, 3227ddc9b1aSDarren Reed ifs->ifs_ipfhook4_loop_out) == 0); 323f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_out) 324381a2a9aSdr goto hookup_failed; 325381a2a9aSdr } 326381a2a9aSdr /* 327381a2a9aSdr * Add IPv6 hooks 328381a2a9aSdr */ 3297ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6 = net_protocol_lookup(id, NHF_INET6); 330f4b3ec61Sdh if (ifs->ifs_ipf_ipv6 == NULL) 331381a2a9aSdr goto hookup_failed; 332381a2a9aSdr 3337ddc9b1aSDarren Reed HOOK_INIT(ifs->ifs_ipfhook6_nicevents, ipf_nic_event_v6, 3347ddc9b1aSDarren Reed "ipfilter_hook6_nicevents", ifs); 3357ddc9b1aSDarren Reed HOOK_INIT(ifs->ifs_ipfhook6_in, ipf_hook6_in, 3367ddc9b1aSDarren Reed "ipfilter_hook6_in", ifs); 3377ddc9b1aSDarren Reed HOOK_INIT(ifs->ifs_ipfhook6_out, ipf_hook6_out, 3387ddc9b1aSDarren Reed "ipfilter_hook6_out", ifs); 33940cdc2e8SAlexandr Nedvedicky HOOK_INIT(ifs->ifs_ipfhook6_loop_in, ipf_hook6_loop_in, 3407ddc9b1aSDarren Reed "ipfilter_hook6_loop_in", ifs); 34140cdc2e8SAlexandr Nedvedicky HOOK_INIT(ifs->ifs_ipfhook6_loop_out, ipf_hook6_loop_out, 3427ddc9b1aSDarren Reed "ipfilter_hook6_loop_out", ifs); 3437ddc9b1aSDarren Reed 3447ddc9b1aSDarren Reed ifs->ifs_hook6_nic_events = (net_hook_register(ifs->ifs_ipf_ipv6, 3457ddc9b1aSDarren Reed NH_NIC_EVENTS, ifs->ifs_ipfhook6_nicevents) == 0); 346f4b3ec61Sdh if (!ifs->ifs_hook6_nic_events) 347381a2a9aSdr goto hookup_failed; 348381a2a9aSdr 3497ddc9b1aSDarren Reed ifs->ifs_hook6_physical_in = (net_hook_register(ifs->ifs_ipf_ipv6, 3507ddc9b1aSDarren Reed NH_PHYSICAL_IN, ifs->ifs_ipfhook6_in) == 0); 351f4b3ec61Sdh if (!ifs->ifs_hook6_physical_in) 352381a2a9aSdr goto hookup_failed; 353381a2a9aSdr 3547ddc9b1aSDarren Reed ifs->ifs_hook6_physical_out = (net_hook_register(ifs->ifs_ipf_ipv6, 3557ddc9b1aSDarren Reed NH_PHYSICAL_OUT, ifs->ifs_ipfhook6_out) == 0); 356f4b3ec61Sdh if (!ifs->ifs_hook6_physical_out) 357381a2a9aSdr goto hookup_failed; 358381a2a9aSdr 359f4b3ec61Sdh if (ifs->ifs_ipf_loopback) { 3607ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_in = (net_hook_register( 3617ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN, 3627ddc9b1aSDarren Reed ifs->ifs_ipfhook6_loop_in) == 0); 363f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_in) 364381a2a9aSdr goto hookup_failed; 365381a2a9aSdr 3667ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_out = (net_hook_register( 3677ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT, 3687ddc9b1aSDarren Reed ifs->ifs_ipfhook6_loop_out) == 0); 369f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_out) 370381a2a9aSdr goto hookup_failed; 371381a2a9aSdr } 372381a2a9aSdr 373381a2a9aSdr /* 374381a2a9aSdr * Reacquire ipf_global, now it is safe. 375381a2a9aSdr */ 376f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 377381a2a9aSdr 3787c478bd9Sstevel@tonic-gate /* Do not use private interface ip_params_arr[] in Solaris 10 */ 3797c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 3827c478bd9Sstevel@tonic-gate ip_forwarding = &ip_g_forward; 3837c478bd9Sstevel@tonic-gate #endif 3847c478bd9Sstevel@tonic-gate /* 3857c478bd9Sstevel@tonic-gate * XXX - There is no terminator for this array, so it is not possible 3867c478bd9Sstevel@tonic-gate * to tell if what we are looking for is missing and go off the end 3877c478bd9Sstevel@tonic-gate * of the array. 3887c478bd9Sstevel@tonic-gate */ 3897c478bd9Sstevel@tonic-gate 390ab25eeb5Syz #if SOLARIS2 <= 8 3917c478bd9Sstevel@tonic-gate for (i = 0; ; i++) { 3927c478bd9Sstevel@tonic-gate if (!strcmp(ip_param_arr[i].ip_param_name, "ip_def_ttl")) { 3937c478bd9Sstevel@tonic-gate ip_ttl_ptr = &ip_param_arr[i].ip_param_value; 3947c478bd9Sstevel@tonic-gate } else if (!strcmp(ip_param_arr[i].ip_param_name, 3957c478bd9Sstevel@tonic-gate "ip_path_mtu_discovery")) { 3967c478bd9Sstevel@tonic-gate ip_mtudisc = &ip_param_arr[i].ip_param_value; 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate #if SOLARIS2 < 8 3997c478bd9Sstevel@tonic-gate else if (!strcmp(ip_param_arr[i].ip_param_name, 4007c478bd9Sstevel@tonic-gate "ip_forwarding")) { 4017c478bd9Sstevel@tonic-gate ip_forwarding = &ip_param_arr[i].ip_param_value; 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate #else 4047c478bd9Sstevel@tonic-gate else if (!strcmp(ip_param_arr[i].ip_param_name, 4057c478bd9Sstevel@tonic-gate "ip6_forwarding")) { 4067c478bd9Sstevel@tonic-gate ip6_forwarding = &ip_param_arr[i].ip_param_value; 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate #endif 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate if (ip_mtudisc != NULL && ip_ttl_ptr != NULL && 4117c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 4127c478bd9Sstevel@tonic-gate ip6_forwarding != NULL && 4137c478bd9Sstevel@tonic-gate #endif 4147c478bd9Sstevel@tonic-gate ip_forwarding != NULL) 4157c478bd9Sstevel@tonic-gate break; 4167c478bd9Sstevel@tonic-gate } 417ab25eeb5Syz #endif 4187c478bd9Sstevel@tonic-gate 419f4b3ec61Sdh if (ifs->ifs_fr_control_forwarding & 1) { 420ab25eeb5Syz if (ip_forwarding != NULL) 421ab25eeb5Syz *ip_forwarding = 1; 4227c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 423ab25eeb5Syz if (ip6_forwarding != NULL) 424ab25eeb5Syz *ip6_forwarding = 1; 4257c478bd9Sstevel@tonic-gate #endif 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate #endif 4297c478bd9Sstevel@tonic-gate 430381a2a9aSdr return 0; 431381a2a9aSdr hookup_failed: 432f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 433381a2a9aSdr return -1; 434381a2a9aSdr } 435381a2a9aSdr 436f4b3ec61Sdh static int fr_setipfloopback(set, ifs) 437381a2a9aSdr int set; 438f4b3ec61Sdh ipf_stack_t *ifs; 439381a2a9aSdr { 440f4b3ec61Sdh if (ifs->ifs_ipf_ipv4 == NULL || ifs->ifs_ipf_ipv6 == NULL) 441381a2a9aSdr return EFAULT; 442381a2a9aSdr 443f4b3ec61Sdh if (set && !ifs->ifs_ipf_loopback) { 444f4b3ec61Sdh ifs->ifs_ipf_loopback = 1; 445381a2a9aSdr 4467ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_in = (net_hook_register( 4477ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN, 4487ddc9b1aSDarren Reed ifs->ifs_ipfhook4_loop_in) == 0); 449f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_in) 450381a2a9aSdr return EINVAL; 451381a2a9aSdr 4527ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_out = (net_hook_register( 4537ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT, 4547ddc9b1aSDarren Reed ifs->ifs_ipfhook4_loop_out) == 0); 455f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_out) 456381a2a9aSdr return EINVAL; 457381a2a9aSdr 4587ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_in = (net_hook_register( 4597ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN, 4607ddc9b1aSDarren Reed ifs->ifs_ipfhook6_loop_in) == 0); 461f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_in) 462381a2a9aSdr return EINVAL; 463381a2a9aSdr 4647ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_out = (net_hook_register( 4657ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT, 4667ddc9b1aSDarren Reed ifs->ifs_ipfhook6_loop_out) == 0); 467f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_out) 468381a2a9aSdr return EINVAL; 469381a2a9aSdr 470f4b3ec61Sdh } else if (!set && ifs->ifs_ipf_loopback) { 471f4b3ec61Sdh ifs->ifs_ipf_loopback = 0; 472381a2a9aSdr 473f4b3ec61Sdh ifs->ifs_hook4_loopback_in = 4747ddc9b1aSDarren Reed (net_hook_unregister(ifs->ifs_ipf_ipv4, 4757ddc9b1aSDarren Reed NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0); 476f4b3ec61Sdh if (ifs->ifs_hook4_loopback_in) 477381a2a9aSdr return EBUSY; 478381a2a9aSdr 479f4b3ec61Sdh ifs->ifs_hook4_loopback_out = 4807ddc9b1aSDarren Reed (net_hook_unregister(ifs->ifs_ipf_ipv4, 4817ddc9b1aSDarren Reed NH_LOOPBACK_OUT, ifs->ifs_ipfhook4_loop_out) != 0); 482f4b3ec61Sdh if (ifs->ifs_hook4_loopback_out) 483381a2a9aSdr return EBUSY; 484381a2a9aSdr 485f4b3ec61Sdh ifs->ifs_hook6_loopback_in = 4867ddc9b1aSDarren Reed (net_hook_unregister(ifs->ifs_ipf_ipv6, 4877ddc9b1aSDarren Reed NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0); 488f4b3ec61Sdh if (ifs->ifs_hook6_loopback_in) 489381a2a9aSdr return EBUSY; 490381a2a9aSdr 491f4b3ec61Sdh ifs->ifs_hook6_loopback_out = 4927ddc9b1aSDarren Reed (net_hook_unregister(ifs->ifs_ipf_ipv6, 4937ddc9b1aSDarren Reed NH_LOOPBACK_OUT, ifs->ifs_ipfhook6_loop_out) != 0); 494f4b3ec61Sdh if (ifs->ifs_hook6_loopback_out) 495381a2a9aSdr return EBUSY; 496381a2a9aSdr } 4977c478bd9Sstevel@tonic-gate return 0; 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate /* 5027c478bd9Sstevel@tonic-gate * Filter ioctl interface. 5037c478bd9Sstevel@tonic-gate */ 5047c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5057c478bd9Sstevel@tonic-gate int iplioctl(dev, cmd, data, mode, cp, rp) 5067c478bd9Sstevel@tonic-gate dev_t dev; 5077c478bd9Sstevel@tonic-gate int cmd; 5087c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 7 5097c478bd9Sstevel@tonic-gate intptr_t data; 5107c478bd9Sstevel@tonic-gate #else 5117c478bd9Sstevel@tonic-gate int *data; 5127c478bd9Sstevel@tonic-gate #endif 5137c478bd9Sstevel@tonic-gate int mode; 5147c478bd9Sstevel@tonic-gate cred_t *cp; 5157c478bd9Sstevel@tonic-gate int *rp; 5167c478bd9Sstevel@tonic-gate { 5177c478bd9Sstevel@tonic-gate int error = 0, tmp; 5187c478bd9Sstevel@tonic-gate friostat_t fio; 5197c478bd9Sstevel@tonic-gate minor_t unit; 5207c478bd9Sstevel@tonic-gate u_int enable; 521f4b3ec61Sdh ipf_stack_t *ifs; 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 5247c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplioctl(%x,%x,%x,%d,%x,%d)\n", 5257c478bd9Sstevel@tonic-gate dev, cmd, data, mode, cp, rp); 5267c478bd9Sstevel@tonic-gate #endif 5277c478bd9Sstevel@tonic-gate unit = getminor(dev); 5287c478bd9Sstevel@tonic-gate if (IPL_LOGMAX < unit) 5297c478bd9Sstevel@tonic-gate return ENXIO; 5307c478bd9Sstevel@tonic-gate 5317ddc9b1aSDarren Reed /* 5327ddc9b1aSDarren Reed * As we're calling ipf_find_stack in user space, from a given zone 5337ddc9b1aSDarren Reed * to find the stack pointer for this zone, there is no need to have 5347ddc9b1aSDarren Reed * a hold/refence count here. 5357ddc9b1aSDarren Reed */ 5367ddc9b1aSDarren Reed ifs = ipf_find_stack(crgetzoneid(cp)); 537f4b3ec61Sdh ASSERT(ifs != NULL); 538f4b3ec61Sdh 539f4b3ec61Sdh if (ifs->ifs_fr_running <= 0) { 540f4b3ec61Sdh if (unit != IPL_LOGIPF) { 5417c478bd9Sstevel@tonic-gate return EIO; 542f4b3ec61Sdh } 5437c478bd9Sstevel@tonic-gate if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 544ab25eeb5Syz cmd != SIOCIPFSET && cmd != SIOCFRENB && 545f4b3ec61Sdh cmd != SIOCGETFS && cmd != SIOCGETFF) { 5467c478bd9Sstevel@tonic-gate return EIO; 547f4b3ec61Sdh } 5487c478bd9Sstevel@tonic-gate } 5497c478bd9Sstevel@tonic-gate 550f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_global); 55172680cf5SDarren Reed if (ifs->ifs_fr_enable_active != 0) { 55272680cf5SDarren Reed RWLOCK_EXIT(&ifs->ifs_ipf_global); 55372680cf5SDarren Reed return EBUSY; 55472680cf5SDarren Reed } 5557c478bd9Sstevel@tonic-gate 5567ddc9b1aSDarren Reed error = fr_ioctlswitch(unit, (caddr_t)data, cmd, mode, cp->cr_uid, 5577ddc9b1aSDarren Reed curproc, ifs); 5587c478bd9Sstevel@tonic-gate if (error != -1) { 559f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 5607c478bd9Sstevel@tonic-gate return error; 5617c478bd9Sstevel@tonic-gate } 5627c478bd9Sstevel@tonic-gate error = 0; 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate switch (cmd) 5657c478bd9Sstevel@tonic-gate { 5667c478bd9Sstevel@tonic-gate case SIOCFRENB : 5677c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 5687c478bd9Sstevel@tonic-gate error = EPERM; 5697c478bd9Sstevel@tonic-gate else { 5707c478bd9Sstevel@tonic-gate error = COPYIN((caddr_t)data, (caddr_t)&enable, 5717c478bd9Sstevel@tonic-gate sizeof(enable)); 5727c478bd9Sstevel@tonic-gate if (error != 0) { 5737c478bd9Sstevel@tonic-gate error = EFAULT; 5747c478bd9Sstevel@tonic-gate break; 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate 577f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 578f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 57972680cf5SDarren Reed ifs->ifs_fr_enable_active = 1; 5807ddc9b1aSDarren Reed error = fr_enableipf(ifs, enable); 58172680cf5SDarren Reed ifs->ifs_fr_enable_active = 0; 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate break; 5847c478bd9Sstevel@tonic-gate case SIOCIPFSET : 5857c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) { 5867c478bd9Sstevel@tonic-gate error = EPERM; 5877c478bd9Sstevel@tonic-gate break; 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate /* FALLTHRU */ 5907c478bd9Sstevel@tonic-gate case SIOCIPFGETNEXT : 5917c478bd9Sstevel@tonic-gate case SIOCIPFGET : 592f4b3ec61Sdh error = fr_ipftune(cmd, (void *)data, ifs); 5937c478bd9Sstevel@tonic-gate break; 5947c478bd9Sstevel@tonic-gate case SIOCSETFF : 5957c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 5967c478bd9Sstevel@tonic-gate error = EPERM; 5977c478bd9Sstevel@tonic-gate else { 5987ddc9b1aSDarren Reed error = COPYIN((caddr_t)data, 5997ddc9b1aSDarren Reed (caddr_t)&ifs->ifs_fr_flags, 6007ddc9b1aSDarren Reed sizeof(ifs->ifs_fr_flags)); 6017c478bd9Sstevel@tonic-gate if (error != 0) 6027c478bd9Sstevel@tonic-gate error = EFAULT; 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate break; 605381a2a9aSdr case SIOCIPFLP : 606381a2a9aSdr error = COPYIN((caddr_t)data, (caddr_t)&tmp, 607381a2a9aSdr sizeof(tmp)); 608381a2a9aSdr if (error != 0) 609381a2a9aSdr error = EFAULT; 610381a2a9aSdr else 611f4b3ec61Sdh error = fr_setipfloopback(tmp, ifs); 612381a2a9aSdr break; 6137c478bd9Sstevel@tonic-gate case SIOCGETFF : 614f4b3ec61Sdh error = COPYOUT((caddr_t)&ifs->ifs_fr_flags, (caddr_t)data, 6157ddc9b1aSDarren Reed sizeof(ifs->ifs_fr_flags)); 6167c478bd9Sstevel@tonic-gate if (error != 0) 6177c478bd9Sstevel@tonic-gate error = EFAULT; 6187c478bd9Sstevel@tonic-gate break; 6197c478bd9Sstevel@tonic-gate case SIOCFUNCL : 6207c478bd9Sstevel@tonic-gate error = fr_resolvefunc((void *)data); 6217c478bd9Sstevel@tonic-gate break; 6227c478bd9Sstevel@tonic-gate case SIOCINAFR : 6237c478bd9Sstevel@tonic-gate case SIOCRMAFR : 6247c478bd9Sstevel@tonic-gate case SIOCADAFR : 6257c478bd9Sstevel@tonic-gate case SIOCZRLST : 6267c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6277c478bd9Sstevel@tonic-gate error = EPERM; 6287c478bd9Sstevel@tonic-gate else 6297c478bd9Sstevel@tonic-gate error = frrequest(unit, cmd, (caddr_t)data, 630f4b3ec61Sdh ifs->ifs_fr_active, 1, ifs); 6317c478bd9Sstevel@tonic-gate break; 6327c478bd9Sstevel@tonic-gate case SIOCINIFR : 6337c478bd9Sstevel@tonic-gate case SIOCRMIFR : 6347c478bd9Sstevel@tonic-gate case SIOCADIFR : 6357c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6367c478bd9Sstevel@tonic-gate error = EPERM; 6377c478bd9Sstevel@tonic-gate else 6387c478bd9Sstevel@tonic-gate error = frrequest(unit, cmd, (caddr_t)data, 639f4b3ec61Sdh 1 - ifs->ifs_fr_active, 1, ifs); 6407c478bd9Sstevel@tonic-gate break; 6417c478bd9Sstevel@tonic-gate case SIOCSWAPA : 6427c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6437c478bd9Sstevel@tonic-gate error = EPERM; 6447c478bd9Sstevel@tonic-gate else { 645f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_mutex); 646f4b3ec61Sdh error = COPYOUT((caddr_t)&ifs->ifs_fr_active, 647f4b3ec61Sdh (caddr_t)data, 648f4b3ec61Sdh sizeof(ifs->ifs_fr_active)); 6497c478bd9Sstevel@tonic-gate if (error != 0) 6507c478bd9Sstevel@tonic-gate error = EFAULT; 6517c478bd9Sstevel@tonic-gate else 652f4b3ec61Sdh ifs->ifs_fr_active = 1 - ifs->ifs_fr_active; 653f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate break; 6567c478bd9Sstevel@tonic-gate case SIOCGETFS : 657f4b3ec61Sdh fr_getstat(&fio, ifs); 6587c478bd9Sstevel@tonic-gate error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT); 6597c478bd9Sstevel@tonic-gate break; 6607c478bd9Sstevel@tonic-gate case SIOCFRZST : 6617c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6627c478bd9Sstevel@tonic-gate error = EPERM; 6637c478bd9Sstevel@tonic-gate else 664f4b3ec61Sdh error = fr_zerostats((caddr_t)data, ifs); 6657c478bd9Sstevel@tonic-gate break; 6667c478bd9Sstevel@tonic-gate case SIOCIPFFL : 6677c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6687c478bd9Sstevel@tonic-gate error = EPERM; 6697c478bd9Sstevel@tonic-gate else { 6707c478bd9Sstevel@tonic-gate error = COPYIN((caddr_t)data, (caddr_t)&tmp, 6717c478bd9Sstevel@tonic-gate sizeof(tmp)); 6727c478bd9Sstevel@tonic-gate if (!error) { 673f4b3ec61Sdh tmp = frflush(unit, 4, tmp, ifs); 6747c478bd9Sstevel@tonic-gate error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 6757ddc9b1aSDarren Reed sizeof(tmp)); 6767c478bd9Sstevel@tonic-gate if (error != 0) 6777c478bd9Sstevel@tonic-gate error = EFAULT; 6787c478bd9Sstevel@tonic-gate } else 6797c478bd9Sstevel@tonic-gate error = EFAULT; 6807c478bd9Sstevel@tonic-gate } 6817c478bd9Sstevel@tonic-gate break; 6827663b816Sml #ifdef USE_INET6 6837663b816Sml case SIOCIPFL6 : 6847663b816Sml if (!(mode & FWRITE)) 6857663b816Sml error = EPERM; 6867663b816Sml else { 6877663b816Sml error = COPYIN((caddr_t)data, (caddr_t)&tmp, 6887663b816Sml sizeof(tmp)); 6897663b816Sml if (!error) { 690f4b3ec61Sdh tmp = frflush(unit, 6, tmp, ifs); 6917663b816Sml error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 6927ddc9b1aSDarren Reed sizeof(tmp)); 6937663b816Sml if (error != 0) 6947663b816Sml error = EFAULT; 6957663b816Sml } else 6967663b816Sml error = EFAULT; 6977663b816Sml } 6987663b816Sml break; 6997663b816Sml #endif 7007c478bd9Sstevel@tonic-gate case SIOCSTLCK : 7017c478bd9Sstevel@tonic-gate error = COPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 7027c478bd9Sstevel@tonic-gate if (error == 0) { 703f4b3ec61Sdh ifs->ifs_fr_state_lock = tmp; 704f4b3ec61Sdh ifs->ifs_fr_nat_lock = tmp; 705f4b3ec61Sdh ifs->ifs_fr_frag_lock = tmp; 706f4b3ec61Sdh ifs->ifs_fr_auth_lock = tmp; 7077c478bd9Sstevel@tonic-gate } else 7087c478bd9Sstevel@tonic-gate error = EFAULT; 7097c478bd9Sstevel@tonic-gate break; 7107c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 7117c478bd9Sstevel@tonic-gate case SIOCIPFFB : 7127c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 7137c478bd9Sstevel@tonic-gate error = EPERM; 7147c478bd9Sstevel@tonic-gate else { 715f4b3ec61Sdh tmp = ipflog_clear(unit, ifs); 7167c478bd9Sstevel@tonic-gate error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 7177c478bd9Sstevel@tonic-gate sizeof(tmp)); 7187c478bd9Sstevel@tonic-gate if (error) 7197c478bd9Sstevel@tonic-gate error = EFAULT; 7207c478bd9Sstevel@tonic-gate } 7217c478bd9Sstevel@tonic-gate break; 7227c478bd9Sstevel@tonic-gate #endif /* IPFILTER_LOG */ 7237c478bd9Sstevel@tonic-gate case SIOCFRSYN : 7247c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 7257c478bd9Sstevel@tonic-gate error = EPERM; 7267c478bd9Sstevel@tonic-gate else { 727f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 728f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 729381a2a9aSdr 730f4b3ec61Sdh frsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 731d6c23f6fSyx fr_natifpsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 732d6c23f6fSyx fr_nataddrsync(0, NULL, NULL, ifs); 733f4b3ec61Sdh fr_statesync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 734381a2a9aSdr error = 0; 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate break; 7377c478bd9Sstevel@tonic-gate case SIOCGFRST : 738f4b3ec61Sdh error = fr_outobj((void *)data, fr_fragstats(ifs), 7397c478bd9Sstevel@tonic-gate IPFOBJ_FRAGSTAT); 7407c478bd9Sstevel@tonic-gate break; 7417c478bd9Sstevel@tonic-gate case FIONREAD : 7427c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 743f4b3ec61Sdh tmp = (int)ifs->ifs_iplused[IPL_LOGIPF]; 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate error = COPYOUT((caddr_t)&tmp, (caddr_t)data, sizeof(tmp)); 7467c478bd9Sstevel@tonic-gate if (error != 0) 7477c478bd9Sstevel@tonic-gate error = EFAULT; 7487c478bd9Sstevel@tonic-gate #endif 7497c478bd9Sstevel@tonic-gate break; 750f4b3ec61Sdh case SIOCIPFITER : 7517ddc9b1aSDarren Reed error = ipf_frruleiter((caddr_t)data, cp->cr_uid, 7527ddc9b1aSDarren Reed curproc, ifs); 753f4b3ec61Sdh break; 754f4b3ec61Sdh 755f4b3ec61Sdh case SIOCGENITER : 7567ddc9b1aSDarren Reed error = ipf_genericiter((caddr_t)data, cp->cr_uid, 7577ddc9b1aSDarren Reed curproc, ifs); 758f4b3ec61Sdh break; 759f4b3ec61Sdh 760f4b3ec61Sdh case SIOCIPFDELTOK : 761bb1d9de5SJohn Ojemann error = BCOPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 762bb1d9de5SJohn Ojemann if (error != 0) { 763bb1d9de5SJohn Ojemann error = EFAULT; 764bb1d9de5SJohn Ojemann } else { 765bb1d9de5SJohn Ojemann error = ipf_deltoken(tmp, cp->cr_uid, curproc, ifs); 766bb1d9de5SJohn Ojemann } 767f4b3ec61Sdh break; 768f4b3ec61Sdh 7697c478bd9Sstevel@tonic-gate default : 77033f2fefdSDarren Reed #ifdef IPFDEBUG 7717ddc9b1aSDarren Reed cmn_err(CE_NOTE, "Unknown: cmd 0x%x data %p", 7727ddc9b1aSDarren Reed cmd, (void *)data); 77333f2fefdSDarren Reed #endif 7747c478bd9Sstevel@tonic-gate error = EINVAL; 7757c478bd9Sstevel@tonic-gate break; 7767c478bd9Sstevel@tonic-gate } 777f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 7787c478bd9Sstevel@tonic-gate return error; 7797c478bd9Sstevel@tonic-gate } 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate 7827ddc9b1aSDarren Reed static int fr_enableipf(ifs, enable) 783882bd30bSdr ipf_stack_t *ifs; 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; 7927ddc9b1aSDarren Reed return error; 793882bd30bSdr } 794882bd30bSdr 79544aaa2b6Sjojemann if (ifs->ifs_fr_running > 0) 7967ddc9b1aSDarren Reed return 0; 79744aaa2b6Sjojemann 7987ddc9b1aSDarren Reed error = iplattach(ifs); 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, 8047ddc9b1aSDarren Reed (void *)ifs, 8057ddc9b1aSDarren Reed hz); 80644aaa2b6Sjojemann } 80744aaa2b6Sjojemann ifs->ifs_fr_running = 1; 80844aaa2b6Sjojemann } else { 80944aaa2b6Sjojemann (void) ipldetach(ifs); 81044aaa2b6Sjojemann } 8117ddc9b1aSDarren Reed return error; 812882bd30bSdr } 813882bd30bSdr 814882bd30bSdr 815f4b3ec61Sdh phy_if_t get_unit(name, v, ifs) 816f4b3ec61Sdh char *name; 817f4b3ec61Sdh int v; 818f4b3ec61Sdh ipf_stack_t *ifs; 8197c478bd9Sstevel@tonic-gate { 8207ddc9b1aSDarren Reed net_handle_t nif; 821381a2a9aSdr 822381a2a9aSdr if (v == 4) 823f4b3ec61Sdh nif = ifs->ifs_ipf_ipv4; 824381a2a9aSdr else if (v == 6) 825f4b3ec61Sdh nif = ifs->ifs_ipf_ipv6; 826381a2a9aSdr else 827381a2a9aSdr return 0; 828381a2a9aSdr 829f4b3ec61Sdh return (net_phylookup(nif, name)); 8307c478bd9Sstevel@tonic-gate } 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate /* 8337c478bd9Sstevel@tonic-gate * routines below for saving IP headers to buffer 8347c478bd9Sstevel@tonic-gate */ 8357c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8367c478bd9Sstevel@tonic-gate int iplopen(devp, flags, otype, cred) 8377c478bd9Sstevel@tonic-gate dev_t *devp; 8387c478bd9Sstevel@tonic-gate int flags, otype; 8397c478bd9Sstevel@tonic-gate cred_t *cred; 8407c478bd9Sstevel@tonic-gate { 8417c478bd9Sstevel@tonic-gate minor_t min = getminor(*devp); 8427c478bd9Sstevel@tonic-gate 8437c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 8447c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplopen(%x,%x,%x,%x)\n", devp, flags, otype, cred); 8457c478bd9Sstevel@tonic-gate #endif 8467c478bd9Sstevel@tonic-gate if (!(otype & OTYP_CHR)) 8477c478bd9Sstevel@tonic-gate return ENXIO; 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate min = (IPL_LOGMAX < min) ? ENXIO : 0; 8507c478bd9Sstevel@tonic-gate return min; 8517c478bd9Sstevel@tonic-gate } 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8557c478bd9Sstevel@tonic-gate int iplclose(dev, flags, otype, cred) 8567c478bd9Sstevel@tonic-gate dev_t dev; 8577c478bd9Sstevel@tonic-gate int flags, otype; 8587c478bd9Sstevel@tonic-gate cred_t *cred; 8597c478bd9Sstevel@tonic-gate { 8607c478bd9Sstevel@tonic-gate minor_t min = getminor(dev); 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 8637c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplclose(%x,%x,%x,%x)\n", dev, flags, otype, cred); 8647c478bd9Sstevel@tonic-gate #endif 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate min = (IPL_LOGMAX < min) ? ENXIO : 0; 8677c478bd9Sstevel@tonic-gate return min; 8687c478bd9Sstevel@tonic-gate } 8697c478bd9Sstevel@tonic-gate 8707c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 8717c478bd9Sstevel@tonic-gate /* 8727c478bd9Sstevel@tonic-gate * iplread/ipllog 8737c478bd9Sstevel@tonic-gate * both of these must operate with at least splnet() lest they be 8747c478bd9Sstevel@tonic-gate * called during packet processing and cause an inconsistancy to appear in 8757c478bd9Sstevel@tonic-gate * the filter lists. 8767c478bd9Sstevel@tonic-gate */ 8777c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8787c478bd9Sstevel@tonic-gate int iplread(dev, uio, cp) 8797c478bd9Sstevel@tonic-gate dev_t dev; 8807c478bd9Sstevel@tonic-gate register struct uio *uio; 8817c478bd9Sstevel@tonic-gate cred_t *cp; 8827c478bd9Sstevel@tonic-gate { 883f4b3ec61Sdh ipf_stack_t *ifs; 884f4b3ec61Sdh int ret; 885f4b3ec61Sdh 8867ddc9b1aSDarren Reed /* 8877ddc9b1aSDarren Reed * As we're calling ipf_find_stack in user space, from a given zone 8887ddc9b1aSDarren Reed * to find the stack pointer for this zone, there is no need to have 8897ddc9b1aSDarren Reed * a hold/refence count here. 8907ddc9b1aSDarren Reed */ 8917ddc9b1aSDarren Reed ifs = ipf_find_stack(crgetzoneid(cp)); 892f4b3ec61Sdh ASSERT(ifs != NULL); 893f4b3ec61Sdh 8947c478bd9Sstevel@tonic-gate # ifdef IPFDEBUG 8957c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplread(%x,%x,%x)\n", dev, uio, cp); 8967c478bd9Sstevel@tonic-gate # endif 89708ee25aeSdr 898f4b3ec61Sdh if (ifs->ifs_fr_running < 1) { 89908ee25aeSdr return EIO; 900f4b3ec61Sdh } 90108ee25aeSdr 9027c478bd9Sstevel@tonic-gate # ifdef IPFILTER_SYNC 903f4b3ec61Sdh if (getminor(dev) == IPL_LOGSYNC) { 9047c478bd9Sstevel@tonic-gate return ipfsync_read(uio); 905f4b3ec61Sdh } 9067c478bd9Sstevel@tonic-gate # endif 9077c478bd9Sstevel@tonic-gate 908f4b3ec61Sdh ret = ipflog_read(getminor(dev), uio, ifs); 909f4b3ec61Sdh return ret; 9107c478bd9Sstevel@tonic-gate } 9117c478bd9Sstevel@tonic-gate #endif /* IPFILTER_LOG */ 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate /* 9157c478bd9Sstevel@tonic-gate * iplread/ipllog 9167c478bd9Sstevel@tonic-gate * both of these must operate with at least splnet() lest they be 9177c478bd9Sstevel@tonic-gate * called during packet processing and cause an inconsistancy to appear in 9187c478bd9Sstevel@tonic-gate * the filter lists. 9197c478bd9Sstevel@tonic-gate */ 9207c478bd9Sstevel@tonic-gate int iplwrite(dev, uio, cp) 9217c478bd9Sstevel@tonic-gate dev_t dev; 9227c478bd9Sstevel@tonic-gate register struct uio *uio; 9237c478bd9Sstevel@tonic-gate cred_t *cp; 9247c478bd9Sstevel@tonic-gate { 925f4b3ec61Sdh ipf_stack_t *ifs; 926f4b3ec61Sdh 9277ddc9b1aSDarren Reed /* 9287ddc9b1aSDarren Reed * As we're calling ipf_find_stack in user space, from a given zone 9297ddc9b1aSDarren Reed * to find the stack pointer for this zone, there is no need to have 9307ddc9b1aSDarren Reed * a hold/refence count here. 9317ddc9b1aSDarren Reed */ 9327ddc9b1aSDarren Reed ifs = ipf_find_stack(crgetzoneid(cp)); 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) { 94008ee25aeSdr return EIO; 941f4b3ec61Sdh } 94208ee25aeSdr 943ab25eeb5Syz #ifdef IPFILTER_SYNC 944ab25eeb5Syz if (getminor(dev) == IPL_LOGSYNC) 945ab25eeb5Syz return ipfsync_write(uio); 9467c478bd9Sstevel@tonic-gate #endif /* IPFILTER_SYNC */ 947ab25eeb5Syz dev = dev; /* LINT */ 948ab25eeb5Syz uio = uio; /* LINT */ 949ab25eeb5Syz cp = cp; /* LINT */ 950ab25eeb5Syz return ENXIO; 951ab25eeb5Syz } 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate /* 9557c478bd9Sstevel@tonic-gate * fr_send_reset - this could conceivably be a call to tcp_respond(), but that 9567c478bd9Sstevel@tonic-gate * requires a large amount of setting up and isn't any more efficient. 9577c478bd9Sstevel@tonic-gate */ 9587c478bd9Sstevel@tonic-gate int fr_send_reset(fin) 9597c478bd9Sstevel@tonic-gate fr_info_t *fin; 9607c478bd9Sstevel@tonic-gate { 9617c478bd9Sstevel@tonic-gate tcphdr_t *tcp, *tcp2; 9627c478bd9Sstevel@tonic-gate int tlen, hlen; 9637c478bd9Sstevel@tonic-gate mblk_t *m; 9647c478bd9Sstevel@tonic-gate #ifdef USE_INET6 9657c478bd9Sstevel@tonic-gate ip6_t *ip6; 9667c478bd9Sstevel@tonic-gate #endif 9677c478bd9Sstevel@tonic-gate ip_t *ip; 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate tcp = fin->fin_dp; 9707c478bd9Sstevel@tonic-gate if (tcp->th_flags & TH_RST) 9717c478bd9Sstevel@tonic-gate return -1; 9727c478bd9Sstevel@tonic-gate 9737c478bd9Sstevel@tonic-gate #ifndef IPFILTER_CKSUM 9747c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 9757c478bd9Sstevel@tonic-gate return -1; 9767c478bd9Sstevel@tonic-gate #endif 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate tlen = (tcp->th_flags & (TH_SYN|TH_FIN)) ? 1 : 0; 9797c478bd9Sstevel@tonic-gate #ifdef USE_INET6 9807c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) 9817c478bd9Sstevel@tonic-gate hlen = sizeof(ip6_t); 9827c478bd9Sstevel@tonic-gate else 9837c478bd9Sstevel@tonic-gate #endif 9847c478bd9Sstevel@tonic-gate hlen = sizeof(ip_t); 9857c478bd9Sstevel@tonic-gate hlen += sizeof(*tcp2); 9867c478bd9Sstevel@tonic-gate if ((m = (mblk_t *)allocb(hlen + 64, BPRI_HI)) == NULL) 9877c478bd9Sstevel@tonic-gate return -1; 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate m->b_rptr += 64; 9907c478bd9Sstevel@tonic-gate MTYPE(m) = M_DATA; 9917c478bd9Sstevel@tonic-gate m->b_wptr = m->b_rptr + hlen; 992ab25eeb5Syz ip = (ip_t *)m->b_rptr; 993ab25eeb5Syz bzero((char *)ip, hlen); 9947c478bd9Sstevel@tonic-gate tcp2 = (struct tcphdr *)(m->b_rptr + hlen - sizeof(*tcp2)); 9957c478bd9Sstevel@tonic-gate tcp2->th_dport = tcp->th_sport; 9967c478bd9Sstevel@tonic-gate tcp2->th_sport = tcp->th_dport; 9977c478bd9Sstevel@tonic-gate if (tcp->th_flags & TH_ACK) { 9987c478bd9Sstevel@tonic-gate tcp2->th_seq = tcp->th_ack; 9997c478bd9Sstevel@tonic-gate tcp2->th_flags = TH_RST; 10007c478bd9Sstevel@tonic-gate } else { 10017c478bd9Sstevel@tonic-gate tcp2->th_ack = ntohl(tcp->th_seq); 10027c478bd9Sstevel@tonic-gate tcp2->th_ack += tlen; 10037c478bd9Sstevel@tonic-gate tcp2->th_ack = htonl(tcp2->th_ack); 10047c478bd9Sstevel@tonic-gate tcp2->th_flags = TH_RST|TH_ACK; 10057c478bd9Sstevel@tonic-gate } 10067c478bd9Sstevel@tonic-gate tcp2->th_off = sizeof(struct tcphdr) >> 2; 10077c478bd9Sstevel@tonic-gate 1008ab25eeb5Syz ip->ip_v = fin->fin_v; 10097c478bd9Sstevel@tonic-gate #ifdef USE_INET6 10107c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 10117c478bd9Sstevel@tonic-gate ip6 = (ip6_t *)m->b_rptr; 10127663b816Sml ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 1013d6c23f6fSyx ip6->ip6_src = fin->fin_dst6.in6; 1014d6c23f6fSyx ip6->ip6_dst = fin->fin_src6.in6; 10157c478bd9Sstevel@tonic-gate ip6->ip6_plen = htons(sizeof(*tcp)); 10167c478bd9Sstevel@tonic-gate ip6->ip6_nxt = IPPROTO_TCP; 10177663b816Sml tcp2->th_sum = fr_cksum(m, (ip_t *)ip6, IPPROTO_TCP, tcp2); 10187c478bd9Sstevel@tonic-gate } else 10197c478bd9Sstevel@tonic-gate #endif 10207c478bd9Sstevel@tonic-gate { 10217c478bd9Sstevel@tonic-gate ip->ip_src.s_addr = fin->fin_daddr; 10227c478bd9Sstevel@tonic-gate ip->ip_dst.s_addr = fin->fin_saddr; 10237c478bd9Sstevel@tonic-gate ip->ip_id = fr_nextipid(fin); 10247c478bd9Sstevel@tonic-gate ip->ip_hl = sizeof(*ip) >> 2; 10257c478bd9Sstevel@tonic-gate ip->ip_p = IPPROTO_TCP; 102637b40788Sekozlow ip->ip_len = sizeof(*ip) + sizeof(*tcp); 10277c478bd9Sstevel@tonic-gate ip->ip_tos = fin->fin_ip->ip_tos; 10287c478bd9Sstevel@tonic-gate tcp2->th_sum = fr_cksum(m, ip, IPPROTO_TCP, tcp2); 10297c478bd9Sstevel@tonic-gate } 1030ab25eeb5Syz return fr_send_ip(fin, m, &m); 10317c478bd9Sstevel@tonic-gate } 10327c478bd9Sstevel@tonic-gate 103337b40788Sekozlow /* 103437b40788Sekozlow * Function: fr_send_ip 103537b40788Sekozlow * Returns: 0: success 103637b40788Sekozlow * -1: failed 103737b40788Sekozlow * Parameters: 103837b40788Sekozlow * fin: packet information 103937b40788Sekozlow * m: the message block where ip head starts 104037b40788Sekozlow * 104137b40788Sekozlow * Send a new packet through the IP stack. 104237b40788Sekozlow * 104337b40788Sekozlow * For IPv4 packets, ip_len must be in host byte order, and ip_v, 104437b40788Sekozlow * ip_ttl, ip_off, and ip_sum are ignored (filled in by this 104537b40788Sekozlow * function). 104637b40788Sekozlow * 104737b40788Sekozlow * For IPv6 packets, ip6_flow, ip6_vfc, and ip6_hlim are filled 104837b40788Sekozlow * in by this function. 104937b40788Sekozlow * 105037b40788Sekozlow * All other portions of the packet must be in on-the-wire format. 105137b40788Sekozlow */ 1052ab25eeb5Syz /*ARGSUSED*/ 1053ab25eeb5Syz static int fr_send_ip(fin, m, mpp) 10547c478bd9Sstevel@tonic-gate fr_info_t *fin; 1055ab25eeb5Syz mblk_t *m, **mpp; 10567c478bd9Sstevel@tonic-gate { 1057ab25eeb5Syz qpktinfo_t qpi, *qpip; 1058ab25eeb5Syz fr_info_t fnew; 1059ab25eeb5Syz ip_t *ip; 1060ab25eeb5Syz int i, hlen; 1061f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1062ab25eeb5Syz 1063ab25eeb5Syz ip = (ip_t *)m->b_rptr; 1064ab25eeb5Syz bzero((char *)&fnew, sizeof(fnew)); 10657c478bd9Sstevel@tonic-gate 10667c478bd9Sstevel@tonic-gate #ifdef USE_INET6 10677c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 10687c478bd9Sstevel@tonic-gate ip6_t *ip6; 10697c478bd9Sstevel@tonic-gate 1070ab25eeb5Syz ip6 = (ip6_t *)ip; 10717c478bd9Sstevel@tonic-gate ip6->ip6_vfc = 0x60; 10727c478bd9Sstevel@tonic-gate ip6->ip6_hlim = 127; 1073ab25eeb5Syz fnew.fin_v = 6; 1074ab25eeb5Syz hlen = sizeof(*ip6); 1075923d6102Szf fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen; 10767c478bd9Sstevel@tonic-gate } else 10777c478bd9Sstevel@tonic-gate #endif 10787c478bd9Sstevel@tonic-gate { 1079ab25eeb5Syz fnew.fin_v = 4; 10807c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 10 10817c478bd9Sstevel@tonic-gate ip->ip_ttl = 255; 1082f4b3ec61Sdh if (net_getpmtuenabled(ifs->ifs_ipf_ipv4) == 1) 1083381a2a9aSdr ip->ip_off = htons(IP_DF); 10847c478bd9Sstevel@tonic-gate #else 1085ab25eeb5Syz if (ip_ttl_ptr != NULL) 1086ab25eeb5Syz ip->ip_ttl = (u_char)(*ip_ttl_ptr); 1087ab25eeb5Syz else 1088ab25eeb5Syz ip->ip_ttl = 63; 1089ab25eeb5Syz if (ip_mtudisc != NULL) 1090ab25eeb5Syz ip->ip_off = htons(*ip_mtudisc ? IP_DF : 0); 1091ab25eeb5Syz else 1092ab25eeb5Syz ip->ip_off = htons(IP_DF); 10937c478bd9Sstevel@tonic-gate #endif 1094ab25eeb5Syz /* 1095ab25eeb5Syz * The dance with byte order and ip_len/ip_off is because in 1096ab25eeb5Syz * fr_fastroute, it expects them to be in host byte order but 1097ab25eeb5Syz * ipf_cksum expects them to be in network byte order. 1098ab25eeb5Syz */ 1099ab25eeb5Syz ip->ip_len = htons(ip->ip_len); 11007c478bd9Sstevel@tonic-gate ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip)); 1101ab25eeb5Syz ip->ip_len = ntohs(ip->ip_len); 1102ab25eeb5Syz ip->ip_off = ntohs(ip->ip_off); 1103ab25eeb5Syz hlen = sizeof(*ip); 1104923d6102Szf fnew.fin_plen = ip->ip_len; 11057c478bd9Sstevel@tonic-gate } 1106ab25eeb5Syz 1107ab25eeb5Syz qpip = fin->fin_qpi; 1108ab25eeb5Syz qpi.qpi_off = 0; 1109381a2a9aSdr qpi.qpi_ill = qpip->qpi_ill; 1110ab25eeb5Syz qpi.qpi_m = m; 1111ab25eeb5Syz qpi.qpi_data = ip; 1112ab25eeb5Syz fnew.fin_qpi = &qpi; 1113ab25eeb5Syz fnew.fin_ifp = fin->fin_ifp; 1114ab25eeb5Syz fnew.fin_flx = FI_NOCKSUM; 1115ab25eeb5Syz fnew.fin_m = m; 111690907f62SJohn Ojemann fnew.fin_qfm = m; 1117ab25eeb5Syz fnew.fin_ip = ip; 1118ab25eeb5Syz fnew.fin_mp = mpp; 1119ab25eeb5Syz fnew.fin_hlen = hlen; 1120ab25eeb5Syz fnew.fin_dp = (char *)ip + hlen; 1121f4b3ec61Sdh fnew.fin_ifs = fin->fin_ifs; 1122ab25eeb5Syz (void) fr_makefrip(hlen, ip, &fnew); 1123ab25eeb5Syz 1124ab25eeb5Syz i = fr_fastroute(m, mpp, &fnew, NULL); 11257c478bd9Sstevel@tonic-gate return i; 11267c478bd9Sstevel@tonic-gate } 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate int fr_send_icmp_err(type, fin, dst) 11307c478bd9Sstevel@tonic-gate int type; 11317c478bd9Sstevel@tonic-gate fr_info_t *fin; 11327c478bd9Sstevel@tonic-gate int dst; 11337c478bd9Sstevel@tonic-gate { 11347c478bd9Sstevel@tonic-gate struct in_addr dst4; 11357c478bd9Sstevel@tonic-gate struct icmp *icmp; 1136ab25eeb5Syz qpktinfo_t *qpi; 11377c478bd9Sstevel@tonic-gate int hlen, code; 1138381a2a9aSdr phy_if_t phy; 11397c478bd9Sstevel@tonic-gate u_short sz; 11407c478bd9Sstevel@tonic-gate #ifdef USE_INET6 11417c478bd9Sstevel@tonic-gate mblk_t *mb; 11427c478bd9Sstevel@tonic-gate #endif 11437c478bd9Sstevel@tonic-gate mblk_t *m; 11447c478bd9Sstevel@tonic-gate #ifdef USE_INET6 11457c478bd9Sstevel@tonic-gate ip6_t *ip6; 11467c478bd9Sstevel@tonic-gate #endif 11477c478bd9Sstevel@tonic-gate ip_t *ip; 1148f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 11497c478bd9Sstevel@tonic-gate 11507c478bd9Sstevel@tonic-gate if ((type < 0) || (type > ICMP_MAXTYPE)) 11517c478bd9Sstevel@tonic-gate return -1; 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate code = fin->fin_icode; 11547c478bd9Sstevel@tonic-gate #ifdef USE_INET6 115533f2fefdSDarren Reed if ((code < 0) || (code >= ICMP_MAX_UNREACH)) 11567c478bd9Sstevel@tonic-gate return -1; 11577c478bd9Sstevel@tonic-gate #endif 11587c478bd9Sstevel@tonic-gate 11597c478bd9Sstevel@tonic-gate #ifndef IPFILTER_CKSUM 11607c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 11617c478bd9Sstevel@tonic-gate return -1; 11627c478bd9Sstevel@tonic-gate #endif 11637c478bd9Sstevel@tonic-gate 1164ab25eeb5Syz qpi = fin->fin_qpi; 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate #ifdef USE_INET6 11677c478bd9Sstevel@tonic-gate mb = fin->fin_qfm; 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 11707c478bd9Sstevel@tonic-gate sz = sizeof(ip6_t); 11717c478bd9Sstevel@tonic-gate sz += MIN(mb->b_wptr - mb->b_rptr, 512); 11727c478bd9Sstevel@tonic-gate hlen = sizeof(ip6_t); 11737c478bd9Sstevel@tonic-gate type = icmptoicmp6types[type]; 11747c478bd9Sstevel@tonic-gate if (type == ICMP6_DST_UNREACH) 11757c478bd9Sstevel@tonic-gate code = icmptoicmp6unreach[code]; 11767c478bd9Sstevel@tonic-gate } else 11777c478bd9Sstevel@tonic-gate #endif 11787c478bd9Sstevel@tonic-gate { 11797c478bd9Sstevel@tonic-gate if ((fin->fin_p == IPPROTO_ICMP) && 11807c478bd9Sstevel@tonic-gate !(fin->fin_flx & FI_SHORT)) 11817c478bd9Sstevel@tonic-gate switch (ntohs(fin->fin_data[0]) >> 8) 11827c478bd9Sstevel@tonic-gate { 11837c478bd9Sstevel@tonic-gate case ICMP_ECHO : 11847c478bd9Sstevel@tonic-gate case ICMP_TSTAMP : 11857c478bd9Sstevel@tonic-gate case ICMP_IREQ : 11867c478bd9Sstevel@tonic-gate case ICMP_MASKREQ : 11877c478bd9Sstevel@tonic-gate break; 11887c478bd9Sstevel@tonic-gate default : 11897c478bd9Sstevel@tonic-gate return 0; 11907c478bd9Sstevel@tonic-gate } 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate sz = sizeof(ip_t) * 2; 11937c478bd9Sstevel@tonic-gate sz += 8; /* 64 bits of data */ 11947c478bd9Sstevel@tonic-gate hlen = sizeof(ip_t); 11957c478bd9Sstevel@tonic-gate } 11967c478bd9Sstevel@tonic-gate 11977c478bd9Sstevel@tonic-gate sz += offsetof(struct icmp, icmp_ip); 11987c478bd9Sstevel@tonic-gate if ((m = (mblk_t *)allocb((size_t)sz + 64, BPRI_HI)) == NULL) 11997c478bd9Sstevel@tonic-gate return -1; 12007c478bd9Sstevel@tonic-gate MTYPE(m) = M_DATA; 12017c478bd9Sstevel@tonic-gate m->b_rptr += 64; 12027c478bd9Sstevel@tonic-gate m->b_wptr = m->b_rptr + sz; 12037c478bd9Sstevel@tonic-gate bzero((char *)m->b_rptr, (size_t)sz); 1204ab25eeb5Syz ip = (ip_t *)m->b_rptr; 1205ab25eeb5Syz ip->ip_v = fin->fin_v; 12067c478bd9Sstevel@tonic-gate icmp = (struct icmp *)(m->b_rptr + hlen); 12077c478bd9Sstevel@tonic-gate icmp->icmp_type = type & 0xff; 12087c478bd9Sstevel@tonic-gate icmp->icmp_code = code & 0xff; 1209381a2a9aSdr phy = (phy_if_t)qpi->qpi_ill; 1210381a2a9aSdr if (type == ICMP_UNREACH && (phy != 0) && 12117c478bd9Sstevel@tonic-gate fin->fin_icode == ICMP_UNREACH_NEEDFRAG) 1212f4b3ec61Sdh icmp->icmp_nextmtu = net_getmtu(ifs->ifs_ipf_ipv4, phy,0 ); 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate #ifdef USE_INET6 12157c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 12167c478bd9Sstevel@tonic-gate struct in6_addr dst6; 12177c478bd9Sstevel@tonic-gate int csz; 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate if (dst == 0) { 1220f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1221f4b3ec61Sdh 1222381a2a9aSdr if (fr_ifpaddr(6, FRI_NORMAL, (void *)phy, 1223f4b3ec61Sdh (void *)&dst6, NULL, ifs) == -1) { 12247c478bd9Sstevel@tonic-gate FREE_MB_T(m); 12257c478bd9Sstevel@tonic-gate return -1; 12267c478bd9Sstevel@tonic-gate } 12277c478bd9Sstevel@tonic-gate } else 1228d6c23f6fSyx dst6 = fin->fin_dst6.in6; 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate csz = sz; 12317c478bd9Sstevel@tonic-gate sz -= sizeof(ip6_t); 12327c478bd9Sstevel@tonic-gate ip6 = (ip6_t *)m->b_rptr; 12337663b816Sml ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 12347c478bd9Sstevel@tonic-gate ip6->ip6_plen = htons((u_short)sz); 12357c478bd9Sstevel@tonic-gate ip6->ip6_nxt = IPPROTO_ICMPV6; 12367c478bd9Sstevel@tonic-gate ip6->ip6_src = dst6; 1237d6c23f6fSyx ip6->ip6_dst = fin->fin_src6.in6; 12387c478bd9Sstevel@tonic-gate sz -= offsetof(struct icmp, icmp_ip); 12397c478bd9Sstevel@tonic-gate bcopy((char *)mb->b_rptr, (char *)&icmp->icmp_ip, sz); 12407c478bd9Sstevel@tonic-gate icmp->icmp_cksum = csz - sizeof(ip6_t); 12417c478bd9Sstevel@tonic-gate } else 12427c478bd9Sstevel@tonic-gate #endif 12437c478bd9Sstevel@tonic-gate { 12447c478bd9Sstevel@tonic-gate ip->ip_hl = sizeof(*ip) >> 2; 12457c478bd9Sstevel@tonic-gate ip->ip_p = IPPROTO_ICMP; 12467c478bd9Sstevel@tonic-gate ip->ip_id = fin->fin_ip->ip_id; 12477c478bd9Sstevel@tonic-gate ip->ip_tos = fin->fin_ip->ip_tos; 124837b40788Sekozlow ip->ip_len = (u_short)sz; 12497c478bd9Sstevel@tonic-gate if (dst == 0) { 1250f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1251f4b3ec61Sdh 1252381a2a9aSdr if (fr_ifpaddr(4, FRI_NORMAL, (void *)phy, 1253f4b3ec61Sdh (void *)&dst4, NULL, ifs) == -1) { 12547c478bd9Sstevel@tonic-gate FREE_MB_T(m); 12557c478bd9Sstevel@tonic-gate return -1; 12567c478bd9Sstevel@tonic-gate } 1257381a2a9aSdr } else { 12587c478bd9Sstevel@tonic-gate dst4 = fin->fin_dst; 1259381a2a9aSdr } 12607c478bd9Sstevel@tonic-gate ip->ip_src = dst4; 12617c478bd9Sstevel@tonic-gate ip->ip_dst = fin->fin_src; 12627c478bd9Sstevel@tonic-gate bcopy((char *)fin->fin_ip, (char *)&icmp->icmp_ip, 12637c478bd9Sstevel@tonic-gate sizeof(*fin->fin_ip)); 12647c478bd9Sstevel@tonic-gate bcopy((char *)fin->fin_ip + fin->fin_hlen, 12657c478bd9Sstevel@tonic-gate (char *)&icmp->icmp_ip + sizeof(*fin->fin_ip), 8); 12667663b816Sml icmp->icmp_ip.ip_len = htons(icmp->icmp_ip.ip_len); 1267ab25eeb5Syz icmp->icmp_ip.ip_off = htons(icmp->icmp_ip.ip_off); 12687c478bd9Sstevel@tonic-gate icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 12697c478bd9Sstevel@tonic-gate sz - sizeof(ip_t)); 12707c478bd9Sstevel@tonic-gate } 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate /* 12737c478bd9Sstevel@tonic-gate * Need to exit out of these so we don't recursively call rw_enter 12747c478bd9Sstevel@tonic-gate * from fr_qout. 12757c478bd9Sstevel@tonic-gate */ 1276ab25eeb5Syz return fr_send_ip(fin, m, &m); 12777c478bd9Sstevel@tonic-gate } 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate #include <sys/time.h> 12807c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 12817c478bd9Sstevel@tonic-gate 12827c478bd9Sstevel@tonic-gate #ifndef _KERNEL 12837c478bd9Sstevel@tonic-gate #include <stdio.h> 12847c478bd9Sstevel@tonic-gate #endif 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate #define NULLADDR_RATE_LIMIT 10 /* 10 seconds */ 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate 12897c478bd9Sstevel@tonic-gate /* 12907c478bd9Sstevel@tonic-gate * Print out warning message at rate-limited speed. 12917c478bd9Sstevel@tonic-gate */ 1292f4b3ec61Sdh static void rate_limit_message(ipf_stack_t *ifs, 1293f4b3ec61Sdh int rate, const char *message, ...) 12947c478bd9Sstevel@tonic-gate { 12957c478bd9Sstevel@tonic-gate static time_t last_time = 0; 12967c478bd9Sstevel@tonic-gate time_t now; 12977c478bd9Sstevel@tonic-gate va_list args; 12987c478bd9Sstevel@tonic-gate char msg_buf[256]; 12997c478bd9Sstevel@tonic-gate int need_printed = 0; 13007c478bd9Sstevel@tonic-gate 13017c478bd9Sstevel@tonic-gate now = ddi_get_time(); 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate /* make sure, no multiple entries */ 1304f4b3ec61Sdh ASSERT(MUTEX_NOT_HELD(&(ifs->ifs_ipf_rw.ipf_lk))); 1305f4b3ec61Sdh MUTEX_ENTER(&ifs->ifs_ipf_rw); 13067c478bd9Sstevel@tonic-gate if (now - last_time >= rate) { 13077c478bd9Sstevel@tonic-gate need_printed = 1; 13087c478bd9Sstevel@tonic-gate last_time = now; 13097c478bd9Sstevel@tonic-gate } 1310f4b3ec61Sdh MUTEX_EXIT(&ifs->ifs_ipf_rw); 13117c478bd9Sstevel@tonic-gate 13127c478bd9Sstevel@tonic-gate if (need_printed) { 13137c478bd9Sstevel@tonic-gate va_start(args, message); 13147c478bd9Sstevel@tonic-gate (void)vsnprintf(msg_buf, 255, message, args); 13157c478bd9Sstevel@tonic-gate va_end(args); 13167c478bd9Sstevel@tonic-gate #ifdef _KERNEL 13177c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, msg_buf); 13187c478bd9Sstevel@tonic-gate #else 13197c478bd9Sstevel@tonic-gate fprintf(std_err, msg_buf); 13207c478bd9Sstevel@tonic-gate #endif 13217c478bd9Sstevel@tonic-gate } 13227c478bd9Sstevel@tonic-gate } 13237c478bd9Sstevel@tonic-gate 13247c478bd9Sstevel@tonic-gate /* 132572680cf5SDarren Reed * Return the first IP Address associated with an interface 132672680cf5SDarren Reed * For IPv6, we walk through the list of logical interfaces and return 132772680cf5SDarren Reed * the address of the first one that isn't a link-local interface. 132872680cf5SDarren Reed * We can't assume that it is :1 because another link-local address 132972680cf5SDarren Reed * may have been assigned there. 13307c478bd9Sstevel@tonic-gate */ 13317c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1332f4b3ec61Sdh int fr_ifpaddr(v, atype, ifptr, inp, inpmask, ifs) 13337c478bd9Sstevel@tonic-gate int v, atype; 1334381a2a9aSdr void *ifptr; 1335381a2a9aSdr struct in_addr *inp, *inpmask; 1336f4b3ec61Sdh ipf_stack_t *ifs; 13377c478bd9Sstevel@tonic-gate { 1338381a2a9aSdr struct sockaddr_in6 v6addr[2]; 1339381a2a9aSdr struct sockaddr_in v4addr[2]; 1340381a2a9aSdr net_ifaddr_t type[2]; 13417ddc9b1aSDarren Reed net_handle_t net_data; 1342381a2a9aSdr phy_if_t phyif; 1343381a2a9aSdr void *array; 1344381a2a9aSdr 1345381a2a9aSdr switch (v) 1346381a2a9aSdr { 1347381a2a9aSdr case 4: 1348f4b3ec61Sdh net_data = ifs->ifs_ipf_ipv4; 1349381a2a9aSdr array = v4addr; 1350381a2a9aSdr break; 1351381a2a9aSdr case 6: 1352f4b3ec61Sdh net_data = ifs->ifs_ipf_ipv6; 1353381a2a9aSdr array = v6addr; 1354381a2a9aSdr break; 1355381a2a9aSdr default: 1356381a2a9aSdr net_data = NULL; 1357381a2a9aSdr break; 1358381a2a9aSdr } 13597c478bd9Sstevel@tonic-gate 1360381a2a9aSdr if (net_data == NULL) 13617c478bd9Sstevel@tonic-gate return -1; 13627c478bd9Sstevel@tonic-gate 1363381a2a9aSdr phyif = (phy_if_t)ifptr; 1364ab25eeb5Syz 1365ab25eeb5Syz switch (atype) 1366ab25eeb5Syz { 1367ab25eeb5Syz case FRI_PEERADDR : 1368381a2a9aSdr type[0] = NA_PEER; 1369ab25eeb5Syz break; 1370381a2a9aSdr 1371381a2a9aSdr case FRI_BROADCAST : 1372381a2a9aSdr type[0] = NA_BROADCAST; 1373381a2a9aSdr break; 1374381a2a9aSdr 1375ab25eeb5Syz default : 1376381a2a9aSdr type[0] = NA_ADDRESS; 1377ab25eeb5Syz break; 1378ab25eeb5Syz } 13797c478bd9Sstevel@tonic-gate 1380381a2a9aSdr type[1] = NA_NETMASK; 1381381a2a9aSdr 1382381a2a9aSdr if (v == 6) { 138372680cf5SDarren Reed lif_if_t idx = 0; 138472680cf5SDarren Reed 138572680cf5SDarren Reed do { 138672680cf5SDarren Reed idx = net_lifgetnext(net_data, phyif, idx); 138772680cf5SDarren Reed if (net_getlifaddr(net_data, phyif, idx, 2, type, 138872680cf5SDarren Reed array) < 0) 138972680cf5SDarren Reed return -1; 139072680cf5SDarren Reed if (!IN6_IS_ADDR_LINKLOCAL(&v6addr[0].sin6_addr) && 139172680cf5SDarren Reed !IN6_IS_ADDR_MULTICAST(&v6addr[0].sin6_addr)) 139272680cf5SDarren Reed break; 139372680cf5SDarren Reed } while (idx != 0); 139472680cf5SDarren Reed 139572680cf5SDarren Reed if (idx == 0) 139672680cf5SDarren Reed return -1; 139772680cf5SDarren Reed 1398381a2a9aSdr return fr_ifpfillv6addr(atype, &v6addr[0], &v6addr[1], 1399381a2a9aSdr inp, inpmask); 14007c478bd9Sstevel@tonic-gate } 140172680cf5SDarren Reed 140272680cf5SDarren Reed if (net_getlifaddr(net_data, phyif, 0, 2, type, array) < 0) 140372680cf5SDarren Reed return -1; 140472680cf5SDarren Reed 1405381a2a9aSdr return fr_ifpfillv4addr(atype, &v4addr[0], &v4addr[1], inp, inpmask); 14067c478bd9Sstevel@tonic-gate } 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate u_32_t fr_newisn(fin) 14107c478bd9Sstevel@tonic-gate fr_info_t *fin; 14117c478bd9Sstevel@tonic-gate { 14127c478bd9Sstevel@tonic-gate static int iss_seq_off = 0; 14137c478bd9Sstevel@tonic-gate u_char hash[16]; 14147c478bd9Sstevel@tonic-gate u_32_t newiss; 14157c478bd9Sstevel@tonic-gate MD5_CTX ctx; 1416f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate /* 14197c478bd9Sstevel@tonic-gate * Compute the base value of the ISS. It is a hash 14207c478bd9Sstevel@tonic-gate * of (saddr, sport, daddr, dport, secret). 14217c478bd9Sstevel@tonic-gate */ 14227c478bd9Sstevel@tonic-gate MD5Init(&ctx); 14237c478bd9Sstevel@tonic-gate 14247c478bd9Sstevel@tonic-gate MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 14257c478bd9Sstevel@tonic-gate sizeof(fin->fin_fi.fi_src)); 14267c478bd9Sstevel@tonic-gate MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 14277c478bd9Sstevel@tonic-gate sizeof(fin->fin_fi.fi_dst)); 14287c478bd9Sstevel@tonic-gate MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 14297c478bd9Sstevel@tonic-gate 1430f4b3ec61Sdh MD5Update(&ctx, ifs->ifs_ipf_iss_secret, sizeof(ifs->ifs_ipf_iss_secret)); 14317c478bd9Sstevel@tonic-gate 14327c478bd9Sstevel@tonic-gate MD5Final(hash, &ctx); 14337c478bd9Sstevel@tonic-gate 14347c478bd9Sstevel@tonic-gate bcopy(hash, &newiss, sizeof(newiss)); 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate /* 14377c478bd9Sstevel@tonic-gate * Now increment our "timer", and add it in to 14387c478bd9Sstevel@tonic-gate * the computed value. 14397c478bd9Sstevel@tonic-gate * 14407c478bd9Sstevel@tonic-gate * XXX Use `addin'? 14417c478bd9Sstevel@tonic-gate * XXX TCP_ISSINCR too large to use? 14427c478bd9Sstevel@tonic-gate */ 14437c478bd9Sstevel@tonic-gate iss_seq_off += 0x00010000; 14447c478bd9Sstevel@tonic-gate newiss += iss_seq_off; 14457c478bd9Sstevel@tonic-gate return newiss; 14467c478bd9Sstevel@tonic-gate } 14477c478bd9Sstevel@tonic-gate 14487c478bd9Sstevel@tonic-gate 14497c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 14507c478bd9Sstevel@tonic-gate /* Function: fr_nextipid */ 14517c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 14527c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 14537c478bd9Sstevel@tonic-gate /* */ 14547c478bd9Sstevel@tonic-gate /* Returns the next IPv4 ID to use for this packet. */ 14557c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 1456ab25eeb5Syz u_short fr_nextipid(fin) 14577c478bd9Sstevel@tonic-gate fr_info_t *fin; 14587c478bd9Sstevel@tonic-gate { 14597c478bd9Sstevel@tonic-gate static u_short ipid = 0; 14607c478bd9Sstevel@tonic-gate u_short id; 1461f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 14627c478bd9Sstevel@tonic-gate 1463f4b3ec61Sdh MUTEX_ENTER(&ifs->ifs_ipf_rw); 146433f2fefdSDarren Reed if (fin->fin_pktnum != 0) { 146533f2fefdSDarren Reed id = fin->fin_pktnum & 0xffff; 146633f2fefdSDarren Reed } else { 14677c478bd9Sstevel@tonic-gate id = ipid++; 146833f2fefdSDarren Reed } 1469f4b3ec61Sdh MUTEX_EXIT(&ifs->ifs_ipf_rw); 14707c478bd9Sstevel@tonic-gate 14717c478bd9Sstevel@tonic-gate return id; 14727c478bd9Sstevel@tonic-gate } 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate 14757c478bd9Sstevel@tonic-gate #ifndef IPFILTER_CKSUM 14767c478bd9Sstevel@tonic-gate /* ARGSUSED */ 14777c478bd9Sstevel@tonic-gate #endif 14787c478bd9Sstevel@tonic-gate INLINE void fr_checkv4sum(fin) 14797c478bd9Sstevel@tonic-gate fr_info_t *fin; 14807c478bd9Sstevel@tonic-gate { 14817c478bd9Sstevel@tonic-gate #ifdef IPFILTER_CKSUM 14827c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 14837c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_BAD; 14847c478bd9Sstevel@tonic-gate #endif 14857c478bd9Sstevel@tonic-gate } 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate 14887c478bd9Sstevel@tonic-gate #ifdef USE_INET6 1489ab25eeb5Syz # ifndef IPFILTER_CKSUM 14907663b816Sml /* ARGSUSED */ 1491ab25eeb5Syz # endif 14927c478bd9Sstevel@tonic-gate INLINE void fr_checkv6sum(fin) 14937c478bd9Sstevel@tonic-gate fr_info_t *fin; 14947c478bd9Sstevel@tonic-gate { 14957c478bd9Sstevel@tonic-gate # ifdef IPFILTER_CKSUM 14967c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 14977c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_BAD; 14987c478bd9Sstevel@tonic-gate # endif 14997c478bd9Sstevel@tonic-gate } 15007c478bd9Sstevel@tonic-gate #endif /* USE_INET6 */ 1501ab25eeb5Syz 1502ab25eeb5Syz 1503ab25eeb5Syz #if (SOLARIS2 < 7) 1504ab25eeb5Syz void fr_slowtimer() 1505ab25eeb5Syz #else 1506ab25eeb5Syz /*ARGSUSED*/ 1507f4b3ec61Sdh void fr_slowtimer __P((void *arg)) 1508ab25eeb5Syz #endif 1509ab25eeb5Syz { 1510f4b3ec61Sdh ipf_stack_t *ifs = arg; 1511ab25eeb5Syz 151244aaa2b6Sjojemann READ_ENTER(&ifs->ifs_ipf_global); 151344aaa2b6Sjojemann if (ifs->ifs_fr_running != 1) { 151444aaa2b6Sjojemann ifs->ifs_fr_timer_id = NULL; 1515f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 1516ab25eeb5Syz return; 1517ab25eeb5Syz } 1518fd636508Szf ipf_expiretokens(ifs); 1519f4b3ec61Sdh fr_fragexpire(ifs); 1520f4b3ec61Sdh fr_timeoutstate(ifs); 1521f4b3ec61Sdh fr_natexpire(ifs); 1522f4b3ec61Sdh fr_authexpire(ifs); 1523f4b3ec61Sdh ifs->ifs_fr_ticks++; 152444aaa2b6Sjojemann if (ifs->ifs_fr_running == 1) 1525f4b3ec61Sdh ifs->ifs_fr_timer_id = timeout(fr_slowtimer, arg, 1526f4b3ec61Sdh drv_usectohz(500000)); 1527ab25eeb5Syz else 1528f4b3ec61Sdh ifs->ifs_fr_timer_id = NULL; 1529f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 1530ab25eeb5Syz } 1531ab25eeb5Syz 1532ab25eeb5Syz 1533381a2a9aSdr /* ------------------------------------------------------------------------ */ 1534381a2a9aSdr /* Function: fr_pullup */ 1535381a2a9aSdr /* Returns: NULL == pullup failed, else pointer to protocol header */ 1536381a2a9aSdr /* Parameters: m(I) - pointer to buffer where data packet starts */ 1537381a2a9aSdr /* fin(I) - pointer to packet information */ 1538381a2a9aSdr /* len(I) - number of bytes to pullup */ 1539381a2a9aSdr /* */ 1540381a2a9aSdr /* Attempt to move at least len bytes (from the start of the buffer) into a */ 1541381a2a9aSdr /* single buffer for ease of access. Operating system native functions are */ 1542381a2a9aSdr /* used to manage buffers - if necessary. If the entire packet ends up in */ 1543381a2a9aSdr /* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */ 1544381a2a9aSdr /* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ 1545381a2a9aSdr /* and ONLY if the pullup succeeds. */ 1546381a2a9aSdr /* */ 1547381a2a9aSdr /* We assume that 'min' is a pointer to a buffer that is part of the chain */ 1548381a2a9aSdr /* of buffers that starts at *fin->fin_mp. */ 1549381a2a9aSdr /* ------------------------------------------------------------------------ */ 1550381a2a9aSdr void *fr_pullup(min, fin, len) 1551381a2a9aSdr mb_t *min; 1552381a2a9aSdr fr_info_t *fin; 1553381a2a9aSdr int len; 1554381a2a9aSdr { 1555381a2a9aSdr qpktinfo_t *qpi = fin->fin_qpi; 1556381a2a9aSdr int out = fin->fin_out, dpoff, ipoff; 1557381a2a9aSdr mb_t *m = min, *m1, *m2; 1558381a2a9aSdr char *ip; 155908ee25aeSdr uint32_t start, stuff, end, value, flags; 1560f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1561381a2a9aSdr 1562381a2a9aSdr if (m == NULL) 1563381a2a9aSdr return NULL; 1564381a2a9aSdr 1565381a2a9aSdr ip = (char *)fin->fin_ip; 1566381a2a9aSdr if ((fin->fin_flx & FI_COALESCE) != 0) 1567381a2a9aSdr return ip; 1568381a2a9aSdr 1569381a2a9aSdr ipoff = fin->fin_ipoff; 1570381a2a9aSdr if (fin->fin_dp != NULL) 1571381a2a9aSdr dpoff = (char *)fin->fin_dp - (char *)ip; 1572381a2a9aSdr else 1573381a2a9aSdr dpoff = 0; 1574381a2a9aSdr 157540cdc2e8SAlexandr Nedvedicky if (M_LEN(m) < len + ipoff) { 1576381a2a9aSdr 1577381a2a9aSdr /* 1578381a2a9aSdr * pfil_precheck ensures the IP header is on a 32bit 1579381a2a9aSdr * aligned address so simply fail if that isn't currently 1580381a2a9aSdr * the case (should never happen). 1581381a2a9aSdr */ 1582381a2a9aSdr int inc = 0; 1583381a2a9aSdr 1584381a2a9aSdr if (ipoff > 0) { 1585381a2a9aSdr if ((ipoff & 3) != 0) { 1586381a2a9aSdr inc = 4 - (ipoff & 3); 1587381a2a9aSdr if (m->b_rptr - inc >= m->b_datap->db_base) 1588381a2a9aSdr m->b_rptr -= inc; 1589381a2a9aSdr else 1590381a2a9aSdr inc = 0; 1591381a2a9aSdr } 1592381a2a9aSdr } 1593381a2a9aSdr 1594381a2a9aSdr /* 1595381a2a9aSdr * XXX This is here as a work around for a bug with DEBUG 1596381a2a9aSdr * XXX Solaris kernels. The problem is b_prev is used by IP 1597381a2a9aSdr * XXX code as a way to stash the phyint_index for a packet, 1598381a2a9aSdr * XXX this doesn't get reset by IP but freeb does an ASSERT() 1599381a2a9aSdr * XXX for both of these to be NULL. See 6442390. 1600381a2a9aSdr */ 1601381a2a9aSdr m1 = m; 1602381a2a9aSdr m2 = m->b_prev; 1603381a2a9aSdr 1604381a2a9aSdr do { 1605381a2a9aSdr m1->b_next = NULL; 1606381a2a9aSdr m1->b_prev = NULL; 1607381a2a9aSdr m1 = m1->b_cont; 1608381a2a9aSdr } while (m1); 160908ee25aeSdr 161008ee25aeSdr /* 161108ee25aeSdr * Need to preserve checksum information by copying them 161208ee25aeSdr * to newmp which heads the pulluped message. 161308ee25aeSdr */ 161408ee25aeSdr hcksum_retrieve(m, NULL, NULL, &start, &stuff, &end, 161508ee25aeSdr &value, &flags); 161608ee25aeSdr 1617381a2a9aSdr if (pullupmsg(m, len + ipoff + inc) == 0) { 1618f4b3ec61Sdh ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[1]); 1619381a2a9aSdr FREE_MB_T(*fin->fin_mp); 1620381a2a9aSdr *fin->fin_mp = NULL; 1621381a2a9aSdr fin->fin_m = NULL; 1622381a2a9aSdr fin->fin_ip = NULL; 1623381a2a9aSdr fin->fin_dp = NULL; 1624381a2a9aSdr qpi->qpi_data = NULL; 1625381a2a9aSdr return NULL; 1626381a2a9aSdr } 162708ee25aeSdr 162808ee25aeSdr (void) hcksum_assoc(m, NULL, NULL, start, stuff, end, 162908ee25aeSdr value, flags, 0); 163008ee25aeSdr 1631381a2a9aSdr m->b_prev = m2; 1632381a2a9aSdr m->b_rptr += inc; 1633381a2a9aSdr fin->fin_m = m; 1634381a2a9aSdr ip = MTOD(m, char *) + ipoff; 1635381a2a9aSdr qpi->qpi_data = ip; 1636381a2a9aSdr } 1637381a2a9aSdr 1638f4b3ec61Sdh ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[0]); 1639381a2a9aSdr fin->fin_ip = (ip_t *)ip; 1640381a2a9aSdr if (fin->fin_dp != NULL) 1641381a2a9aSdr fin->fin_dp = (char *)fin->fin_ip + dpoff; 1642381a2a9aSdr 1643381a2a9aSdr if (len == fin->fin_plen) 1644381a2a9aSdr fin->fin_flx |= FI_COALESCE; 1645381a2a9aSdr return ip; 1646381a2a9aSdr } 1647381a2a9aSdr 1648381a2a9aSdr 1649ab25eeb5Syz /* 1650381a2a9aSdr * Function: fr_verifysrc 1651381a2a9aSdr * Returns: int (really boolean) 1652381a2a9aSdr * Parameters: fin - packet information 1653381a2a9aSdr * 1654381a2a9aSdr * Check whether the packet has a valid source address for the interface on 1655381a2a9aSdr * which the packet arrived, implementing the "fr_chksrc" feature. 1656381a2a9aSdr * Returns true iff the packet's source address is valid. 1657381a2a9aSdr */ 1658381a2a9aSdr int fr_verifysrc(fin) 1659381a2a9aSdr fr_info_t *fin; 1660381a2a9aSdr { 16617ddc9b1aSDarren Reed net_handle_t net_data_p; 1662381a2a9aSdr phy_if_t phy_ifdata_routeto; 1663381a2a9aSdr struct sockaddr sin; 1664f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1665381a2a9aSdr 1666381a2a9aSdr if (fin->fin_v == 4) { 1667f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv4; 1668381a2a9aSdr } else if (fin->fin_v == 6) { 1669f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv6; 1670381a2a9aSdr } else { 1671381a2a9aSdr return (0); 1672381a2a9aSdr } 1673381a2a9aSdr 1674381a2a9aSdr /* Get the index corresponding to the if name */ 1675381a2a9aSdr sin.sa_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 1676381a2a9aSdr bcopy(&fin->fin_saddr, &sin.sa_data, sizeof (struct in_addr)); 16777ddc9b1aSDarren Reed phy_ifdata_routeto = net_routeto(net_data_p, &sin, NULL); 1678381a2a9aSdr 1679381a2a9aSdr return (((phy_if_t)fin->fin_ifp == phy_ifdata_routeto) ? 1 : 0); 1680381a2a9aSdr } 1681381a2a9aSdr 1682381a2a9aSdr 1683381a2a9aSdr /* 1684381a2a9aSdr * Function: fr_fastroute 1685381a2a9aSdr * Returns: 0: success; 1686381a2a9aSdr * -1: failed 1687ab25eeb5Syz * Parameters: 1688381a2a9aSdr * mb: the message block where ip head starts 1689381a2a9aSdr * mpp: the pointer to the pointer of the orignal 1690381a2a9aSdr * packet message 1691381a2a9aSdr * fin: packet information 1692381a2a9aSdr * fdp: destination interface information 1693381a2a9aSdr * if it is NULL, no interface information provided. 1694ab25eeb5Syz * 1695ab25eeb5Syz * This function is for fastroute/to/dup-to rules. It calls 1696ab25eeb5Syz * pfil_make_lay2_packet to search route, make lay-2 header 1697ab25eeb5Syz * ,and identify output queue for the IP packet. 1698ab25eeb5Syz * The destination address depends on the following conditions: 1699ab25eeb5Syz * 1: for fastroute rule, fdp is passed in as NULL, so the 1700381a2a9aSdr * destination address is the IP Packet's destination address 1701ab25eeb5Syz * 2: for to/dup-to rule, if an ip address is specified after 1702381a2a9aSdr * the interface name, this address is the as destination 1703381a2a9aSdr * address. Otherwise IP Packet's destination address is used 1704ab25eeb5Syz */ 1705ab25eeb5Syz int fr_fastroute(mb, mpp, fin, fdp) 1706ab25eeb5Syz mblk_t *mb, **mpp; 1707ab25eeb5Syz fr_info_t *fin; 1708ab25eeb5Syz frdest_t *fdp; 1709ab25eeb5Syz { 17107ddc9b1aSDarren Reed net_handle_t net_data_p; 17117ddc9b1aSDarren Reed net_inject_t *inj; 1712ab25eeb5Syz mblk_t *mp = NULL; 1713381a2a9aSdr frentry_t *fr = fin->fin_fr; 1714ab25eeb5Syz qpktinfo_t *qpi; 1715ab25eeb5Syz ip_t *ip; 1716381a2a9aSdr 1717381a2a9aSdr struct sockaddr_in *sin; 1718381a2a9aSdr struct sockaddr_in6 *sin6; 1719381a2a9aSdr struct sockaddr *sinp; 1720f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1721ab25eeb5Syz #ifndef sparc 1722ab25eeb5Syz u_short __iplen, __ipoff; 1723ab25eeb5Syz #endif 1724381a2a9aSdr 1725381a2a9aSdr if (fin->fin_v == 4) { 1726f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv4; 1727381a2a9aSdr } else if (fin->fin_v == 6) { 1728f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv6; 1729381a2a9aSdr } else { 1730381a2a9aSdr return (-1); 1731381a2a9aSdr } 1732381a2a9aSdr 17337ddc9b1aSDarren Reed inj = net_inject_alloc(NETINFO_VERSION); 17347ddc9b1aSDarren Reed if (inj == NULL) 17357ddc9b1aSDarren Reed return -1; 17367ddc9b1aSDarren Reed 1737ab25eeb5Syz ip = fin->fin_ip; 1738ab25eeb5Syz qpi = fin->fin_qpi; 1739ab25eeb5Syz 1740ab25eeb5Syz /* 1741ab25eeb5Syz * If this is a duplicate mblk then we want ip to point at that 1742ab25eeb5Syz * data, not the original, if and only if it is already pointing at 1743ab25eeb5Syz * the current mblk data. 1744381a2a9aSdr * 1745381a2a9aSdr * Otherwise, if it's not a duplicate, and we're not already pointing 1746e6c6c1faSyz * at the current mblk data, then we want to ensure that the data 1747e6c6c1faSyz * points at ip. 1748ab25eeb5Syz */ 1749381a2a9aSdr 1750381a2a9aSdr if ((ip == (ip_t *)qpi->qpi_m->b_rptr) && (qpi->qpi_m != mb)) { 1751ab25eeb5Syz ip = (ip_t *)mb->b_rptr; 1752381a2a9aSdr } else if ((qpi->qpi_m == mb) && (ip != (ip_t *)qpi->qpi_m->b_rptr)) { 1753381a2a9aSdr qpi->qpi_m->b_rptr = (uchar_t *)ip; 1754e6c6c1faSyz qpi->qpi_off = 0; 1755e6c6c1faSyz } 1756ab25eeb5Syz 1757ab25eeb5Syz /* 1758ab25eeb5Syz * If there is another M_PROTO, we don't want it 1759ab25eeb5Syz */ 1760ab25eeb5Syz if (*mpp != mb) { 1761ab25eeb5Syz mp = unlinkb(*mpp); 1762ab25eeb5Syz freeb(*mpp); 1763ab25eeb5Syz *mpp = mp; 1764ab25eeb5Syz } 1765ab25eeb5Syz 17667ddc9b1aSDarren Reed sinp = (struct sockaddr *)&inj->ni_addr; 1767381a2a9aSdr sin = (struct sockaddr_in *)sinp; 1768381a2a9aSdr sin6 = (struct sockaddr_in6 *)sinp; 17697ddc9b1aSDarren Reed bzero((char *)&inj->ni_addr, sizeof (inj->ni_addr)); 17707ddc9b1aSDarren Reed inj->ni_addr.ss_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 17717ddc9b1aSDarren Reed inj->ni_packet = mb; 1772ab25eeb5Syz 1773ab25eeb5Syz /* 1774ab25eeb5Syz * In case we're here due to "to <if>" being used with 1775ab25eeb5Syz * "keep state", check that we're going in the correct 1776ab25eeb5Syz * direction. 1777ab25eeb5Syz */ 1778381a2a9aSdr if (fdp != NULL) { 1779381a2a9aSdr if ((fr != NULL) && (fdp->fd_ifp != NULL) && 1780381a2a9aSdr (fin->fin_rev != 0) && (fdp == &fr->fr_tif)) 1781381a2a9aSdr goto bad_fastroute; 17827ddc9b1aSDarren Reed inj->ni_physical = (phy_if_t)fdp->fd_ifp; 1783ab25eeb5Syz if (fin->fin_v == 4) { 1784381a2a9aSdr sin->sin_addr = fdp->fd_ip; 1785381a2a9aSdr } else { 1786381a2a9aSdr sin6->sin6_addr = fdp->fd_ip6.in6; 1787ab25eeb5Syz } 1788381a2a9aSdr } else { 1789381a2a9aSdr if (fin->fin_v == 4) { 1790381a2a9aSdr sin->sin_addr = ip->ip_dst; 1791381a2a9aSdr } else { 1792381a2a9aSdr sin6->sin6_addr = ((ip6_t *)ip)->ip6_dst; 1793ab25eeb5Syz } 17947ddc9b1aSDarren Reed inj->ni_physical = net_routeto(net_data_p, sinp, NULL); 1795ab25eeb5Syz } 1796ab25eeb5Syz 1797edd26dc5Sdr /* 1798edd26dc5Sdr * Clear the hardware checksum flags from packets that we are doing 1799edd26dc5Sdr * input processing on as leaving them set will cause the outgoing 1800edd26dc5Sdr * NIC (if it supports hardware checksum) to calculate them anew, 1801edd26dc5Sdr * using the old (correct) checksums as the pseudo value to start 1802edd26dc5Sdr * from. 1803edd26dc5Sdr */ 1804edd26dc5Sdr if (fin->fin_out == 0) { 1805edd26dc5Sdr DB_CKSUMFLAGS(mb) = 0; 1806edd26dc5Sdr } 1807c793af95Ssangeeta 1808381a2a9aSdr *mpp = mb; 1809ab25eeb5Syz 1810381a2a9aSdr if (fin->fin_out == 0) { 1811381a2a9aSdr void *saveifp; 1812381a2a9aSdr u_32_t pass; 1813ab25eeb5Syz 1814381a2a9aSdr saveifp = fin->fin_ifp; 18157ddc9b1aSDarren Reed fin->fin_ifp = (void *)inj->ni_physical; 1816d3675867Sjojemann fin->fin_flx &= ~FI_STATE; 1817381a2a9aSdr fin->fin_out = 1; 1818381a2a9aSdr (void) fr_acctpkt(fin, &pass); 1819381a2a9aSdr fin->fin_fr = NULL; 1820381a2a9aSdr if (!fr || !(fr->fr_flags & FR_RETMASK)) 1821381a2a9aSdr (void) fr_checkstate(fin, &pass); 1822d3675867Sjojemann if (fr_checknatout(fin, NULL) == -1) 1823381a2a9aSdr goto bad_fastroute; 1824381a2a9aSdr fin->fin_out = 0; 1825381a2a9aSdr fin->fin_ifp = saveifp; 1826381a2a9aSdr } 1827381a2a9aSdr #ifndef sparc 1828381a2a9aSdr if (fin->fin_v == 4) { 1829381a2a9aSdr __iplen = (u_short)ip->ip_len, 1830381a2a9aSdr __ipoff = (u_short)ip->ip_off; 1831ab25eeb5Syz 1832381a2a9aSdr ip->ip_len = htons(__iplen); 1833381a2a9aSdr ip->ip_off = htons(__ipoff); 1834381a2a9aSdr } 1835ab25eeb5Syz #endif 1836381a2a9aSdr 1837381a2a9aSdr if (net_data_p) { 18387ddc9b1aSDarren Reed if (net_inject(net_data_p, NI_DIRECT_OUT, inj) < 0) { 18397ddc9b1aSDarren Reed net_inject_free(inj); 1840381a2a9aSdr return (-1); 1841ab25eeb5Syz } 1842ab25eeb5Syz } 1843381a2a9aSdr 1844f4b3ec61Sdh ifs->ifs_fr_frouteok[0]++; 18457ddc9b1aSDarren Reed net_inject_free(inj); 1846381a2a9aSdr return 0; 1847ab25eeb5Syz bad_fastroute: 18487ddc9b1aSDarren Reed net_inject_free(inj); 1849ab25eeb5Syz freemsg(mb); 1850f4b3ec61Sdh ifs->ifs_fr_frouteok[1]++; 1851ab25eeb5Syz return -1; 1852ab25eeb5Syz } 1853ab25eeb5Syz 1854ab25eeb5Syz 1855ab25eeb5Syz /* ------------------------------------------------------------------------ */ 18567ddc9b1aSDarren Reed /* Function: ipf_hook4_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 */ 1860ab25eeb5Syz /* */ 1861381a2a9aSdr /* Calling ipf_hook. */ 1862381a2a9aSdr /* ------------------------------------------------------------------------ */ 1863381a2a9aSdr /*ARGSUSED*/ 18647ddc9b1aSDarren Reed int ipf_hook4_out(hook_event_token_t token, hook_data_t info, void *arg) 1865381a2a9aSdr { 18667ddc9b1aSDarren Reed return ipf_hook(info, 1, 0, arg); 1867cbded9aeSdr } 1868cbded9aeSdr /*ARGSUSED*/ 18697ddc9b1aSDarren Reed int ipf_hook6_out(hook_event_token_t token, hook_data_t info, void *arg) 1870cbded9aeSdr { 18717ddc9b1aSDarren Reed return ipf_hook6(info, 1, 0, arg); 1872381a2a9aSdr } 1873381a2a9aSdr 1874381a2a9aSdr /* ------------------------------------------------------------------------ */ 18757ddc9b1aSDarren Reed /* Function: ipf_hook4_in */ 1876381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1877381a2a9aSdr /* Parameters: event(I) - pointer to event */ 1878381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 1879ab25eeb5Syz /* */ 1880381a2a9aSdr /* Calling ipf_hook. */ 1881ab25eeb5Syz /* ------------------------------------------------------------------------ */ 1882381a2a9aSdr /*ARGSUSED*/ 18837ddc9b1aSDarren Reed int ipf_hook4_in(hook_event_token_t token, hook_data_t info, void *arg) 1884ab25eeb5Syz { 18857ddc9b1aSDarren Reed return ipf_hook(info, 0, 0, arg); 1886cbded9aeSdr } 1887cbded9aeSdr /*ARGSUSED*/ 18887ddc9b1aSDarren Reed int ipf_hook6_in(hook_event_token_t token, hook_data_t info, void *arg) 1889cbded9aeSdr { 18907ddc9b1aSDarren Reed return ipf_hook6(info, 0, 0, arg); 1891381a2a9aSdr } 1892ab25eeb5Syz 1893ab25eeb5Syz 1894381a2a9aSdr /* ------------------------------------------------------------------------ */ 18957ddc9b1aSDarren Reed /* Function: ipf_hook4_loop_out */ 1896381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1897381a2a9aSdr /* Parameters: event(I) - pointer to event */ 1898381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 1899381a2a9aSdr /* */ 1900381a2a9aSdr /* Calling ipf_hook. */ 1901381a2a9aSdr /* ------------------------------------------------------------------------ */ 1902381a2a9aSdr /*ARGSUSED*/ 19037ddc9b1aSDarren Reed int ipf_hook4_loop_out(hook_event_token_t token, hook_data_t info, void *arg) 1904cbded9aeSdr { 19057ddc9b1aSDarren Reed return ipf_hook(info, 1, FI_NOCKSUM, arg); 1906cbded9aeSdr } 1907cbded9aeSdr /*ARGSUSED*/ 19087ddc9b1aSDarren Reed int ipf_hook6_loop_out(hook_event_token_t token, hook_data_t info, void *arg) 1909381a2a9aSdr { 19107ddc9b1aSDarren Reed return ipf_hook6(info, 1, FI_NOCKSUM, arg); 1911381a2a9aSdr } 1912ab25eeb5Syz 1913381a2a9aSdr /* ------------------------------------------------------------------------ */ 191440cdc2e8SAlexandr Nedvedicky /* Function: ipf_hook4_loop_in */ 1915381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1916381a2a9aSdr /* Parameters: event(I) - pointer to event */ 1917381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 1918381a2a9aSdr /* */ 1919381a2a9aSdr /* Calling ipf_hook. */ 1920381a2a9aSdr /* ------------------------------------------------------------------------ */ 1921381a2a9aSdr /*ARGSUSED*/ 192240cdc2e8SAlexandr Nedvedicky int ipf_hook4_loop_in(hook_event_token_t token, hook_data_t info, void *arg) 1923cbded9aeSdr { 19247ddc9b1aSDarren Reed return ipf_hook(info, 0, FI_NOCKSUM, arg); 1925cbded9aeSdr } 1926cbded9aeSdr /*ARGSUSED*/ 19277ddc9b1aSDarren Reed int ipf_hook6_loop_in(hook_event_token_t token, hook_data_t info, void *arg) 1928381a2a9aSdr { 19297ddc9b1aSDarren Reed return ipf_hook6(info, 0, FI_NOCKSUM, arg); 1930381a2a9aSdr } 1931381a2a9aSdr 1932381a2a9aSdr /* ------------------------------------------------------------------------ */ 1933381a2a9aSdr /* Function: ipf_hook */ 1934381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1935381a2a9aSdr /* Parameters: info(I) - pointer to hook information for firewalling */ 1936381a2a9aSdr /* out(I) - whether packet is going in or out */ 1937381a2a9aSdr /* loopback(I) - whether packet is a loopback packet or not */ 1938381a2a9aSdr /* */ 1939381a2a9aSdr /* Stepping stone function between the IP mainline and IPFilter. Extracts */ 1940381a2a9aSdr /* parameters out of the info structure and forms them up to be useful for */ 1941381a2a9aSdr /* calling ipfilter. */ 1942381a2a9aSdr /* ------------------------------------------------------------------------ */ 19437ddc9b1aSDarren Reed int ipf_hook(hook_data_t info, int out, int loopback, void *arg) 1944381a2a9aSdr { 1945381a2a9aSdr hook_pkt_event_t *fw; 19467ddc9b1aSDarren Reed ipf_stack_t *ifs; 1947381a2a9aSdr qpktinfo_t qpi; 19487ddc9b1aSDarren Reed int rval, hlen; 1949381a2a9aSdr u_short swap; 1950381a2a9aSdr phy_if_t phy; 1951381a2a9aSdr ip_t *ip; 1952381a2a9aSdr 19537ddc9b1aSDarren Reed ifs = arg; 1954381a2a9aSdr fw = (hook_pkt_event_t *)info; 1955381a2a9aSdr 1956381a2a9aSdr ASSERT(fw != NULL); 1957381a2a9aSdr phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp; 1958381a2a9aSdr 1959381a2a9aSdr ip = fw->hpe_hdr; 1960cbded9aeSdr swap = ntohs(ip->ip_len); 1961cbded9aeSdr ip->ip_len = swap; 1962cbded9aeSdr swap = ntohs(ip->ip_off); 1963cbded9aeSdr ip->ip_off = swap; 1964cbded9aeSdr hlen = IPH_HDR_LENGTH(ip); 1965381a2a9aSdr 1966381a2a9aSdr qpi.qpi_m = fw->hpe_mb; 1967381a2a9aSdr qpi.qpi_data = fw->hpe_hdr; 1968381a2a9aSdr qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr; 1969381a2a9aSdr qpi.qpi_ill = (void *)phy; 1970cbded9aeSdr qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST); 1971cbded9aeSdr if (qpi.qpi_flags) 1972cbded9aeSdr qpi.qpi_flags |= FI_MBCAST; 1973cbded9aeSdr qpi.qpi_flags |= loopback; 1974381a2a9aSdr 1975f4b3ec61Sdh rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, 19767ddc9b1aSDarren Reed &qpi, fw->hpe_mp, ifs); 1977381a2a9aSdr 1978381a2a9aSdr /* For fastroute cases, fr_check returns 0 with mp set to NULL */ 1979381a2a9aSdr if (rval == 0 && *(fw->hpe_mp) == NULL) 1980381a2a9aSdr rval = 1; 1981381a2a9aSdr 1982cbded9aeSdr /* Notify IP the packet mblk_t and IP header pointers. */ 1983381a2a9aSdr fw->hpe_mb = qpi.qpi_m; 1984381a2a9aSdr fw->hpe_hdr = qpi.qpi_data; 1985cbded9aeSdr if (rval == 0) { 1986381a2a9aSdr ip = qpi.qpi_data; 1987381a2a9aSdr swap = ntohs(ip->ip_len); 1988381a2a9aSdr ip->ip_len = swap; 1989381a2a9aSdr swap = ntohs(ip->ip_off); 1990381a2a9aSdr ip->ip_off = swap; 1991381a2a9aSdr } 1992381a2a9aSdr return rval; 1993ab25eeb5Syz 1994381a2a9aSdr } 19957ddc9b1aSDarren Reed int ipf_hook6(hook_data_t info, int out, int loopback, void *arg) 1996cbded9aeSdr { 1997cbded9aeSdr hook_pkt_event_t *fw; 1998cbded9aeSdr int rval, hlen; 1999cbded9aeSdr qpktinfo_t qpi; 2000cbded9aeSdr phy_if_t phy; 2001cbded9aeSdr 2002cbded9aeSdr fw = (hook_pkt_event_t *)info; 2003cbded9aeSdr 2004cbded9aeSdr ASSERT(fw != NULL); 2005cbded9aeSdr phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp; 2006cbded9aeSdr 2007cbded9aeSdr hlen = sizeof (ip6_t); 2008cbded9aeSdr 2009cbded9aeSdr qpi.qpi_m = fw->hpe_mb; 2010cbded9aeSdr qpi.qpi_data = fw->hpe_hdr; 2011cbded9aeSdr qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr; 2012cbded9aeSdr qpi.qpi_ill = (void *)phy; 2013cbded9aeSdr qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST); 2014cbded9aeSdr if (qpi.qpi_flags) 2015cbded9aeSdr qpi.qpi_flags |= FI_MBCAST; 2016cbded9aeSdr qpi.qpi_flags |= loopback; 2017cbded9aeSdr 2018cbded9aeSdr rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, 20197ddc9b1aSDarren Reed &qpi, fw->hpe_mp, arg); 2020cbded9aeSdr 2021cbded9aeSdr /* For fastroute cases, fr_check returns 0 with mp set to NULL */ 2022cbded9aeSdr if (rval == 0 && *(fw->hpe_mp) == NULL) 2023cbded9aeSdr rval = 1; 2024cbded9aeSdr 2025cbded9aeSdr /* Notify IP the packet mblk_t and IP header pointers. */ 2026cbded9aeSdr fw->hpe_mb = qpi.qpi_m; 2027cbded9aeSdr fw->hpe_hdr = qpi.qpi_data; 2028cbded9aeSdr return rval; 2029cbded9aeSdr 2030cbded9aeSdr } 2031ab25eeb5Syz 2032ab25eeb5Syz 2033381a2a9aSdr /* ------------------------------------------------------------------------ */ 2034381a2a9aSdr /* Function: ipf_nic_event_v4 */ 2035381a2a9aSdr /* Returns: int - 0 == no problems encountered */ 2036381a2a9aSdr /* Parameters: event(I) - pointer to event */ 2037381a2a9aSdr /* info(I) - pointer to information about a NIC event */ 2038381a2a9aSdr /* */ 2039381a2a9aSdr /* Function to receive asynchronous NIC events from IP */ 2040381a2a9aSdr /* ------------------------------------------------------------------------ */ 2041381a2a9aSdr /*ARGSUSED*/ 20427ddc9b1aSDarren Reed int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info, void *arg) 2043381a2a9aSdr { 2044381a2a9aSdr struct sockaddr_in *sin; 2045381a2a9aSdr hook_nic_event_t *hn; 20467ddc9b1aSDarren Reed ipf_stack_t *ifs = arg; 2047381a2a9aSdr 2048381a2a9aSdr hn = (hook_nic_event_t *)info; 2049381a2a9aSdr 2050381a2a9aSdr switch (hn->hne_event) 2051381a2a9aSdr { 2052381a2a9aSdr case NE_PLUMB : 2053a4cf92b0Sdr frsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, hn->hne_data, 2054d6c23f6fSyx ifs); 2055d6c23f6fSyx fr_natifpsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, 2056f4b3ec61Sdh hn->hne_data, ifs); 2057381a2a9aSdr fr_statesync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, 2058f4b3ec61Sdh hn->hne_data, ifs); 2059381a2a9aSdr break; 2060381a2a9aSdr 2061381a2a9aSdr case NE_UNPLUMB : 2062f4b3ec61Sdh frsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 2063d6c23f6fSyx fr_natifpsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, 2064d6c23f6fSyx ifs); 2065f4b3ec61Sdh fr_statesync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 2066381a2a9aSdr break; 2067381a2a9aSdr 2068381a2a9aSdr case NE_ADDRESS_CHANGE : 2069a4cf92b0Sdr /* 2070a4cf92b0Sdr * We only respond to events for logical interface 0 because 2071a4cf92b0Sdr * IPFilter only uses the first address given to a network 2072a4cf92b0Sdr * interface. We check for hne_lif==1 because the netinfo 2073a4cf92b0Sdr * code maps adds 1 to the lif number so that it can return 2074a4cf92b0Sdr * 0 to indicate "no more lifs" when walking them. 2075a4cf92b0Sdr */ 2076a4cf92b0Sdr if (hn->hne_lif == 1) { 2077a4cf92b0Sdr frsync(IPFSYNC_RESYNC, 4, (void *)hn->hne_nic, NULL, 2078a4cf92b0Sdr ifs); 2079a4cf92b0Sdr sin = hn->hne_data; 2080d6c23f6fSyx fr_nataddrsync(4, (void *)hn->hne_nic, &sin->sin_addr, 2081a4cf92b0Sdr ifs); 2082a4cf92b0Sdr } 2083381a2a9aSdr break; 2084381a2a9aSdr 2085381a2a9aSdr default : 2086381a2a9aSdr break; 2087ab25eeb5Syz } 2088ab25eeb5Syz 2089381a2a9aSdr return 0; 2090381a2a9aSdr } 2091ab25eeb5Syz 2092381a2a9aSdr 2093381a2a9aSdr /* ------------------------------------------------------------------------ */ 2094381a2a9aSdr /* Function: ipf_nic_event_v6 */ 2095381a2a9aSdr /* Returns: int - 0 == no problems encountered */ 2096381a2a9aSdr /* Parameters: event(I) - pointer to event */ 2097381a2a9aSdr /* info(I) - pointer to information about a NIC event */ 2098381a2a9aSdr /* */ 2099381a2a9aSdr /* Function to receive asynchronous NIC events from IP */ 2100381a2a9aSdr /* ------------------------------------------------------------------------ */ 2101381a2a9aSdr /*ARGSUSED*/ 21027ddc9b1aSDarren Reed int ipf_nic_event_v6(hook_event_token_t event, hook_data_t info, void *arg) 2103381a2a9aSdr { 2104d6c23f6fSyx struct sockaddr_in6 *sin6; 2105381a2a9aSdr hook_nic_event_t *hn; 21067ddc9b1aSDarren Reed ipf_stack_t *ifs = arg; 2107381a2a9aSdr 2108381a2a9aSdr hn = (hook_nic_event_t *)info; 2109381a2a9aSdr 2110381a2a9aSdr switch (hn->hne_event) 2111381a2a9aSdr { 2112381a2a9aSdr case NE_PLUMB : 2113d6c23f6fSyx frsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2114d6c23f6fSyx hn->hne_data, ifs); 2115d6c23f6fSyx fr_natifpsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2116d6c23f6fSyx hn->hne_data, ifs); 2117381a2a9aSdr fr_statesync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2118f4b3ec61Sdh hn->hne_data, ifs); 2119381a2a9aSdr break; 2120381a2a9aSdr 2121381a2a9aSdr case NE_UNPLUMB : 2122f4b3ec61Sdh frsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2123d6c23f6fSyx fr_natifpsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, 2124d6c23f6fSyx ifs); 2125f4b3ec61Sdh fr_statesync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2126381a2a9aSdr break; 2127381a2a9aSdr 2128381a2a9aSdr case NE_ADDRESS_CHANGE : 2129d6c23f6fSyx if (hn->hne_lif == 1) { 2130d6c23f6fSyx sin6 = hn->hne_data; 2131d6c23f6fSyx fr_nataddrsync(6, (void *)hn->hne_nic, &sin6->sin6_addr, 2132d6c23f6fSyx ifs); 2133d6c23f6fSyx } 2134381a2a9aSdr break; 2135381a2a9aSdr default : 2136381a2a9aSdr break; 2137381a2a9aSdr } 2138381a2a9aSdr 2139381a2a9aSdr return 0; 2140ab25eeb5Syz } 2141a1173273SAlexandr Nedvedicky 2142a1173273SAlexandr Nedvedicky /* 2143a1173273SAlexandr Nedvedicky * Functions fr_make_rst(), fr_make_icmp_v4(), fr_make_icmp_v6() 2144a1173273SAlexandr Nedvedicky * are needed in Solaris kernel only. We don't need them in 2145a1173273SAlexandr Nedvedicky * ipftest to pretend the ICMP/RST packet was sent as a response. 2146a1173273SAlexandr Nedvedicky */ 2147a1173273SAlexandr Nedvedicky #if defined(_KERNEL) && (SOLARIS2 >= 10) 2148a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2149a1173273SAlexandr Nedvedicky /* Function: fr_make_rst */ 2150a1173273SAlexandr Nedvedicky /* Returns: int - 0 on success, -1 on failure */ 2151a1173273SAlexandr Nedvedicky /* Parameters: fin(I) - pointer to packet information */ 2152a1173273SAlexandr Nedvedicky /* */ 2153a1173273SAlexandr Nedvedicky /* We must alter the original mblks passed to IPF from IP stack via */ 2154a1173273SAlexandr Nedvedicky /* FW_HOOKS. FW_HOOKS interface is powerfull, but it has some limitations. */ 2155a1173273SAlexandr Nedvedicky /* IPF can basicaly do only these things with mblk representing the packet: */ 2156a1173273SAlexandr Nedvedicky /* leave it as it is (pass the packet) */ 2157a1173273SAlexandr Nedvedicky /* */ 2158a1173273SAlexandr Nedvedicky /* discard it (block the packet) */ 2159a1173273SAlexandr Nedvedicky /* */ 2160a1173273SAlexandr Nedvedicky /* alter it (i.e. NAT) */ 2161a1173273SAlexandr Nedvedicky /* */ 2162a1173273SAlexandr Nedvedicky /* As you can see IPF can not simply discard the mblk and supply a new one */ 2163a1173273SAlexandr Nedvedicky /* instead to IP stack via FW_HOOKS. */ 2164a1173273SAlexandr Nedvedicky /* */ 2165a1173273SAlexandr Nedvedicky /* The return-rst action for packets coming via NIC is handled as follows: */ 2166a1173273SAlexandr Nedvedicky /* mblk with packet is discarded */ 2167a1173273SAlexandr Nedvedicky /* */ 2168a1173273SAlexandr Nedvedicky /* new mblk with RST response is constructed and injected to network */ 2169a1173273SAlexandr Nedvedicky /* */ 2170a1173273SAlexandr Nedvedicky /* IPF can't inject packets to loopback interface, this is just another */ 2171a1173273SAlexandr Nedvedicky /* limitation we have to deal with here. The only option to send RST */ 2172a1173273SAlexandr Nedvedicky /* response to offending TCP packet coming via loopback is to alter it. */ 2173a1173273SAlexandr Nedvedicky /* */ 2174a1173273SAlexandr Nedvedicky /* The fr_make_rst() function alters TCP SYN/FIN packet intercepted on */ 2175a1173273SAlexandr Nedvedicky /* loopback interface into TCP RST packet. fin->fin_mp is pointer to */ 2176a1173273SAlexandr Nedvedicky /* mblk L3 (IP) and L4 (TCP/UDP) packet headers. */ 2177a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2178a1173273SAlexandr Nedvedicky int fr_make_rst(fin) 2179a1173273SAlexandr Nedvedicky fr_info_t *fin; 2180a1173273SAlexandr Nedvedicky { 2181a1173273SAlexandr Nedvedicky uint16_t tmp_port; 2182a1173273SAlexandr Nedvedicky int rv = -1; 2183a1173273SAlexandr Nedvedicky uint32_t old_ack; 2184a1173273SAlexandr Nedvedicky tcphdr_t *tcp = NULL; 2185a1173273SAlexandr Nedvedicky struct in_addr tmp_src; 2186a1173273SAlexandr Nedvedicky #ifdef USE_INET6 2187a1173273SAlexandr Nedvedicky struct in6_addr tmp_src6; 2188a1173273SAlexandr Nedvedicky #endif 2189a1173273SAlexandr Nedvedicky 2190a1173273SAlexandr Nedvedicky ASSERT(fin->fin_p == IPPROTO_TCP); 2191a1173273SAlexandr Nedvedicky 2192a1173273SAlexandr Nedvedicky /* 2193a1173273SAlexandr Nedvedicky * We do not need to adjust chksum, since it is not being checked by 2194a1173273SAlexandr Nedvedicky * Solaris IP stack for loopback clients. 2195a1173273SAlexandr Nedvedicky */ 2196a1173273SAlexandr Nedvedicky if ((fin->fin_v == 4) && (fin->fin_p == IPPROTO_TCP) && 2197a1173273SAlexandr Nedvedicky ((tcp = (tcphdr_t *) fin->fin_dp) != NULL)) { 2198a1173273SAlexandr Nedvedicky 2199a1173273SAlexandr Nedvedicky if (tcp->th_flags & (TH_SYN | TH_FIN)) { 2200a1173273SAlexandr Nedvedicky /* Swap IPv4 addresses. */ 2201a1173273SAlexandr Nedvedicky tmp_src = fin->fin_ip->ip_src; 2202a1173273SAlexandr Nedvedicky fin->fin_ip->ip_src = fin->fin_ip->ip_dst; 2203a1173273SAlexandr Nedvedicky fin->fin_ip->ip_dst = tmp_src; 2204a1173273SAlexandr Nedvedicky 2205a1173273SAlexandr Nedvedicky rv = 0; 2206a1173273SAlexandr Nedvedicky } 2207a1173273SAlexandr Nedvedicky else 2208a1173273SAlexandr Nedvedicky tcp = NULL; 2209a1173273SAlexandr Nedvedicky } 2210a1173273SAlexandr Nedvedicky #ifdef USE_INET6 2211a1173273SAlexandr Nedvedicky else if ((fin->fin_v == 6) && (fin->fin_p == IPPROTO_TCP) && 2212a1173273SAlexandr Nedvedicky ((tcp = (tcphdr_t *) fin->fin_dp) != NULL)) { 2213a1173273SAlexandr Nedvedicky /* 2214a1173273SAlexandr Nedvedicky * We are relying on fact the next header is TCP, which is true 2215a1173273SAlexandr Nedvedicky * for regular TCP packets coming in over loopback. 2216a1173273SAlexandr Nedvedicky */ 2217a1173273SAlexandr Nedvedicky if (tcp->th_flags & (TH_SYN | TH_FIN)) { 2218a1173273SAlexandr Nedvedicky /* Swap IPv6 addresses. */ 2219a1173273SAlexandr Nedvedicky tmp_src6 = fin->fin_ip6->ip6_src; 2220a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_src = fin->fin_ip6->ip6_dst; 2221a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_dst = tmp_src6; 2222a1173273SAlexandr Nedvedicky 2223a1173273SAlexandr Nedvedicky rv = 0; 2224a1173273SAlexandr Nedvedicky } 2225a1173273SAlexandr Nedvedicky else 2226a1173273SAlexandr Nedvedicky tcp = NULL; 2227a1173273SAlexandr Nedvedicky } 2228a1173273SAlexandr Nedvedicky #endif 2229a1173273SAlexandr Nedvedicky 2230a1173273SAlexandr Nedvedicky if (tcp != NULL) { 2231a1173273SAlexandr Nedvedicky /* 2232a1173273SAlexandr Nedvedicky * Adjust TCP header: 2233a1173273SAlexandr Nedvedicky * swap ports, 2234a1173273SAlexandr Nedvedicky * set flags, 2235a1173273SAlexandr Nedvedicky * set correct ACK number 2236a1173273SAlexandr Nedvedicky */ 2237a1173273SAlexandr Nedvedicky tmp_port = tcp->th_sport; 2238a1173273SAlexandr Nedvedicky tcp->th_sport = tcp->th_dport; 2239a1173273SAlexandr Nedvedicky tcp->th_dport = tmp_port; 2240a1173273SAlexandr Nedvedicky old_ack = tcp->th_ack; 2241a1173273SAlexandr Nedvedicky tcp->th_ack = htonl(ntohl(tcp->th_seq) + 1); 2242a1173273SAlexandr Nedvedicky tcp->th_seq = old_ack; 2243a1173273SAlexandr Nedvedicky tcp->th_flags = TH_RST | TH_ACK; 2244a1173273SAlexandr Nedvedicky } 2245a1173273SAlexandr Nedvedicky 2246a1173273SAlexandr Nedvedicky return (rv); 2247a1173273SAlexandr Nedvedicky } 2248a1173273SAlexandr Nedvedicky 2249a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2250a1173273SAlexandr Nedvedicky /* Function: fr_make_icmp_v4 */ 2251a1173273SAlexandr Nedvedicky /* Returns: int - 0 on success, -1 on failure */ 2252a1173273SAlexandr Nedvedicky /* Parameters: fin(I) - pointer to packet information */ 2253a1173273SAlexandr Nedvedicky /* */ 2254a1173273SAlexandr Nedvedicky /* Please read comment at fr_make_icmp() wrapper function to get an idea */ 2255a1173273SAlexandr Nedvedicky /* what is going to happen here and why. Once you read the comment there, */ 2256a1173273SAlexandr Nedvedicky /* continue here with next paragraph. */ 2257a1173273SAlexandr Nedvedicky /* */ 2258a1173273SAlexandr Nedvedicky /* To turn IPv4 packet into ICMPv4 response packet, these things must */ 2259a1173273SAlexandr Nedvedicky /* happen here: */ 2260a1173273SAlexandr Nedvedicky /* (1) Original mblk is copied (duplicated). */ 2261a1173273SAlexandr Nedvedicky /* */ 2262a1173273SAlexandr Nedvedicky /* (2) ICMP header is created. */ 2263a1173273SAlexandr Nedvedicky /* */ 2264a1173273SAlexandr Nedvedicky /* (3) Link ICMP header with copy of original mblk, we have ICMPv4 */ 2265a1173273SAlexandr Nedvedicky /* data ready then. */ 2266a1173273SAlexandr Nedvedicky /* */ 2267a1173273SAlexandr Nedvedicky /* (4) Swap IP addresses in original mblk and adjust IP header data. */ 2268a1173273SAlexandr Nedvedicky /* */ 2269a1173273SAlexandr Nedvedicky /* (5) The mblk containing original packet is trimmed to contain IP */ 2270a1173273SAlexandr Nedvedicky /* header only and ICMP chksum is computed. */ 2271a1173273SAlexandr Nedvedicky /* */ 2272a1173273SAlexandr Nedvedicky /* (6) The ICMP header we have from (3) is linked to original mblk, */ 2273a1173273SAlexandr Nedvedicky /* which now contains new IP header. If original packet was spread */ 2274a1173273SAlexandr Nedvedicky /* over several mblks, only the first mblk is kept. */ 2275a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2276a1173273SAlexandr Nedvedicky static int fr_make_icmp_v4(fin) 2277a1173273SAlexandr Nedvedicky fr_info_t *fin; 2278a1173273SAlexandr Nedvedicky { 2279a1173273SAlexandr Nedvedicky struct in_addr tmp_src; 2280*6ccacea7SAlexandr Nedvedicky tcphdr_t *tcp; 2281a1173273SAlexandr Nedvedicky struct icmp *icmp; 2282a1173273SAlexandr Nedvedicky mblk_t *mblk_icmp; 2283a1173273SAlexandr Nedvedicky mblk_t *mblk_ip; 2284a1173273SAlexandr Nedvedicky size_t icmp_pld_len; /* octets to append to ICMP header */ 2285a1173273SAlexandr Nedvedicky size_t orig_iphdr_len; /* length of IP header only */ 2286a1173273SAlexandr Nedvedicky uint32_t sum; 2287a1173273SAlexandr Nedvedicky uint16_t *buf; 2288a1173273SAlexandr Nedvedicky int len; 2289a1173273SAlexandr Nedvedicky 2290a1173273SAlexandr Nedvedicky 2291a1173273SAlexandr Nedvedicky if (fin->fin_v != 4) 2292a1173273SAlexandr Nedvedicky return (-1); 2293a1173273SAlexandr Nedvedicky 2294a1173273SAlexandr Nedvedicky /* 2295a1173273SAlexandr Nedvedicky * If we are dealing with TCP, then packet must be SYN/FIN to be routed 2296a1173273SAlexandr Nedvedicky * by IP stack. If it is not SYN/FIN, then we must drop it silently. 2297a1173273SAlexandr Nedvedicky */ 2298*6ccacea7SAlexandr Nedvedicky tcp = (tcphdr_t *) fin->fin_dp; 2299*6ccacea7SAlexandr Nedvedicky 2300a1173273SAlexandr Nedvedicky if ((fin->fin_p == IPPROTO_TCP) && 2301*6ccacea7SAlexandr Nedvedicky ((tcp == NULL) || ((tcp->th_flags & (TH_SYN | TH_FIN)) == 0))) 2302a1173273SAlexandr Nedvedicky return (-1); 2303a1173273SAlexandr Nedvedicky 2304a1173273SAlexandr Nedvedicky /* 2305a1173273SAlexandr Nedvedicky * Step (1) 2306a1173273SAlexandr Nedvedicky * 2307a1173273SAlexandr Nedvedicky * Make copy of original mblk. 2308a1173273SAlexandr Nedvedicky * 2309a1173273SAlexandr Nedvedicky * We want to copy as much data as necessary, not less, not more. The 2310a1173273SAlexandr Nedvedicky * ICMPv4 payload length for unreachable messages is: 2311a1173273SAlexandr Nedvedicky * original IP header + 8 bytes of L4 (if there are any). 2312a1173273SAlexandr Nedvedicky * 2313a1173273SAlexandr Nedvedicky * We determine if there are at least 8 bytes of L4 data following IP 2314a1173273SAlexandr Nedvedicky * header first. 2315a1173273SAlexandr Nedvedicky */ 2316a1173273SAlexandr Nedvedicky icmp_pld_len = (fin->fin_dlen > ICMPERR_ICMPHLEN) ? 2317a1173273SAlexandr Nedvedicky ICMPERR_ICMPHLEN : fin->fin_dlen; 2318a1173273SAlexandr Nedvedicky /* 2319a1173273SAlexandr Nedvedicky * Since we don't want to copy more data than necessary, we must trim 2320a1173273SAlexandr Nedvedicky * the original mblk here. The right way (STREAMish) would be to use 2321a1173273SAlexandr Nedvedicky * adjmsg() to trim it. However we would have to calculate the length 2322a1173273SAlexandr Nedvedicky * argument for adjmsg() from pointers we already have here. 2323a1173273SAlexandr Nedvedicky * 2324a1173273SAlexandr Nedvedicky * Since we have pointers and offsets, it's faster and easier for 2325a1173273SAlexandr Nedvedicky * us to just adjust pointers by hand instead of using adjmsg(). 2326a1173273SAlexandr Nedvedicky */ 2327a1173273SAlexandr Nedvedicky fin->fin_m->b_wptr = (unsigned char *) fin->fin_dp; 2328a1173273SAlexandr Nedvedicky fin->fin_m->b_wptr += icmp_pld_len; 2329a1173273SAlexandr Nedvedicky icmp_pld_len = fin->fin_m->b_wptr - (unsigned char *) fin->fin_ip; 2330a1173273SAlexandr Nedvedicky 2331a1173273SAlexandr Nedvedicky /* 2332a1173273SAlexandr Nedvedicky * Also we don't want to copy any L2 stuff, which might precede IP 2333a1173273SAlexandr Nedvedicky * header, so we have have to set b_rptr to point to the start of IP 2334a1173273SAlexandr Nedvedicky * header. 2335a1173273SAlexandr Nedvedicky */ 2336a1173273SAlexandr Nedvedicky fin->fin_m->b_rptr += fin->fin_ipoff; 2337a1173273SAlexandr Nedvedicky if ((mblk_ip = copyb(fin->fin_m)) == NULL) 2338a1173273SAlexandr Nedvedicky return (-1); 2339a1173273SAlexandr Nedvedicky fin->fin_m->b_rptr -= fin->fin_ipoff; 2340a1173273SAlexandr Nedvedicky 2341a1173273SAlexandr Nedvedicky /* 2342a1173273SAlexandr Nedvedicky * Step (2) 2343a1173273SAlexandr Nedvedicky * 2344a1173273SAlexandr Nedvedicky * Create an ICMP header, which will be appened to original mblk later. 2345a1173273SAlexandr Nedvedicky * ICMP header is just another mblk. 2346a1173273SAlexandr Nedvedicky */ 2347a1173273SAlexandr Nedvedicky mblk_icmp = (mblk_t *) allocb(ICMPERR_ICMPHLEN, BPRI_HI); 2348a1173273SAlexandr Nedvedicky if (mblk_icmp == NULL) { 2349a1173273SAlexandr Nedvedicky FREE_MB_T(mblk_ip); 2350a1173273SAlexandr Nedvedicky return (-1); 2351a1173273SAlexandr Nedvedicky } 2352a1173273SAlexandr Nedvedicky 2353a1173273SAlexandr Nedvedicky MTYPE(mblk_icmp) = M_DATA; 2354a1173273SAlexandr Nedvedicky icmp = (struct icmp *) mblk_icmp->b_wptr; 2355a1173273SAlexandr Nedvedicky icmp->icmp_type = ICMP_UNREACH; 2356a1173273SAlexandr Nedvedicky icmp->icmp_code = fin->fin_icode & 0xFF; 2357a1173273SAlexandr Nedvedicky icmp->icmp_void = 0; 2358a1173273SAlexandr Nedvedicky icmp->icmp_cksum = 0; 2359a1173273SAlexandr Nedvedicky mblk_icmp->b_wptr += ICMPERR_ICMPHLEN; 2360a1173273SAlexandr Nedvedicky 2361a1173273SAlexandr Nedvedicky /* 2362a1173273SAlexandr Nedvedicky * Step (3) 2363a1173273SAlexandr Nedvedicky * 2364a1173273SAlexandr Nedvedicky * Complete ICMP packet - link ICMP header with L4 data from original 2365a1173273SAlexandr Nedvedicky * IP packet. 2366a1173273SAlexandr Nedvedicky */ 2367a1173273SAlexandr Nedvedicky linkb(mblk_icmp, mblk_ip); 2368a1173273SAlexandr Nedvedicky 2369a1173273SAlexandr Nedvedicky /* 2370a1173273SAlexandr Nedvedicky * Step (4) 2371a1173273SAlexandr Nedvedicky * 2372a1173273SAlexandr Nedvedicky * Swap IP addresses and change IP header fields accordingly in 2373a1173273SAlexandr Nedvedicky * original IP packet. 2374a1173273SAlexandr Nedvedicky * 2375a1173273SAlexandr Nedvedicky * There is a rule option return-icmp as a dest for physical 2376a1173273SAlexandr Nedvedicky * interfaces. This option becomes useless for loopback, since IPF box 2377a1173273SAlexandr Nedvedicky * uses same address as a loopback destination. We ignore the option 2378a1173273SAlexandr Nedvedicky * here, the ICMP packet will always look like as it would have been 2379a1173273SAlexandr Nedvedicky * sent from the original destination host. 2380a1173273SAlexandr Nedvedicky */ 2381a1173273SAlexandr Nedvedicky tmp_src = fin->fin_ip->ip_src; 2382a1173273SAlexandr Nedvedicky fin->fin_ip->ip_src = fin->fin_ip->ip_dst; 2383a1173273SAlexandr Nedvedicky fin->fin_ip->ip_dst = tmp_src; 2384a1173273SAlexandr Nedvedicky fin->fin_ip->ip_p = IPPROTO_ICMP; 2385a1173273SAlexandr Nedvedicky fin->fin_ip->ip_sum = 0; 2386a1173273SAlexandr Nedvedicky 2387a1173273SAlexandr Nedvedicky /* 2388a1173273SAlexandr Nedvedicky * Step (5) 2389a1173273SAlexandr Nedvedicky * 2390a1173273SAlexandr Nedvedicky * We trim the orignal mblk to hold IP header only. 2391a1173273SAlexandr Nedvedicky */ 2392a1173273SAlexandr Nedvedicky fin->fin_m->b_wptr = fin->fin_dp; 2393a1173273SAlexandr Nedvedicky orig_iphdr_len = fin->fin_m->b_wptr - 2394a1173273SAlexandr Nedvedicky (fin->fin_m->b_rptr + fin->fin_ipoff); 2395a1173273SAlexandr Nedvedicky fin->fin_ip->ip_len = htons(icmp_pld_len + ICMPERR_ICMPHLEN + 2396a1173273SAlexandr Nedvedicky orig_iphdr_len); 2397a1173273SAlexandr Nedvedicky 2398a1173273SAlexandr Nedvedicky /* 2399a1173273SAlexandr Nedvedicky * ICMP chksum calculation. The data we are calculating chksum for are 2400a1173273SAlexandr Nedvedicky * spread over two mblks, therefore we have to use two for loops. 2401a1173273SAlexandr Nedvedicky * 2402a1173273SAlexandr Nedvedicky * First for loop computes chksum part for ICMP header. 2403a1173273SAlexandr Nedvedicky */ 2404a1173273SAlexandr Nedvedicky buf = (uint16_t *) icmp; 2405a1173273SAlexandr Nedvedicky len = ICMPERR_ICMPHLEN; 2406a1173273SAlexandr Nedvedicky for (sum = 0; len > 1; len -= 2) 2407a1173273SAlexandr Nedvedicky sum += *buf++; 2408a1173273SAlexandr Nedvedicky 2409a1173273SAlexandr Nedvedicky /* 2410a1173273SAlexandr Nedvedicky * Here we add chksum part for ICMP payload. 2411a1173273SAlexandr Nedvedicky */ 2412a1173273SAlexandr Nedvedicky len = icmp_pld_len; 2413a1173273SAlexandr Nedvedicky buf = (uint16_t *) mblk_ip->b_rptr; 2414a1173273SAlexandr Nedvedicky for (; len > 1; len -= 2) 2415a1173273SAlexandr Nedvedicky sum += *buf++; 2416a1173273SAlexandr Nedvedicky 2417a1173273SAlexandr Nedvedicky /* 2418a1173273SAlexandr Nedvedicky * Chksum is done. 2419a1173273SAlexandr Nedvedicky */ 2420a1173273SAlexandr Nedvedicky sum = (sum >> 16) + (sum & 0xffff); 2421a1173273SAlexandr Nedvedicky sum += (sum >> 16); 2422a1173273SAlexandr Nedvedicky icmp->icmp_cksum = ~sum; 2423a1173273SAlexandr Nedvedicky 2424a1173273SAlexandr Nedvedicky /* 2425a1173273SAlexandr Nedvedicky * Step (6) 2426a1173273SAlexandr Nedvedicky * 2427a1173273SAlexandr Nedvedicky * Release all packet mblks, except the first one. 2428a1173273SAlexandr Nedvedicky */ 2429a1173273SAlexandr Nedvedicky if (fin->fin_m->b_cont != NULL) { 2430a1173273SAlexandr Nedvedicky FREE_MB_T(fin->fin_m->b_cont); 2431a1173273SAlexandr Nedvedicky } 2432a1173273SAlexandr Nedvedicky 2433a1173273SAlexandr Nedvedicky /* 2434a1173273SAlexandr Nedvedicky * Append ICMP payload to first mblk, which already contains new IP 2435a1173273SAlexandr Nedvedicky * header. 2436a1173273SAlexandr Nedvedicky */ 2437a1173273SAlexandr Nedvedicky linkb(fin->fin_m, mblk_icmp); 2438a1173273SAlexandr Nedvedicky 2439a1173273SAlexandr Nedvedicky return (0); 2440a1173273SAlexandr Nedvedicky } 2441a1173273SAlexandr Nedvedicky 2442a1173273SAlexandr Nedvedicky #ifdef USE_INET6 2443a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2444a1173273SAlexandr Nedvedicky /* Function: fr_make_icmp_v6 */ 2445a1173273SAlexandr Nedvedicky /* Returns: int - 0 on success, -1 on failure */ 2446a1173273SAlexandr Nedvedicky /* Parameters: fin(I) - pointer to packet information */ 2447a1173273SAlexandr Nedvedicky /* */ 2448a1173273SAlexandr Nedvedicky /* Please read comment at fr_make_icmp() wrapper function to get an idea */ 2449a1173273SAlexandr Nedvedicky /* what and why is going to happen here. Once you read the comment there, */ 2450a1173273SAlexandr Nedvedicky /* continue here with next paragraph. */ 2451a1173273SAlexandr Nedvedicky /* */ 2452a1173273SAlexandr Nedvedicky /* This function turns IPv6 packet (UDP, TCP, ...) into ICMPv6 response. */ 2453a1173273SAlexandr Nedvedicky /* The algorithm is fairly simple: */ 2454a1173273SAlexandr Nedvedicky /* 1) We need to get copy of complete mblk. */ 2455a1173273SAlexandr Nedvedicky /* */ 2456a1173273SAlexandr Nedvedicky /* 2) New ICMPv6 header is created. */ 2457a1173273SAlexandr Nedvedicky /* */ 2458a1173273SAlexandr Nedvedicky /* 3) The copy of original mblk with packet is linked to ICMPv6 */ 2459a1173273SAlexandr Nedvedicky /* header. */ 2460a1173273SAlexandr Nedvedicky /* */ 2461a1173273SAlexandr Nedvedicky /* 4) The checksum must be adjusted. */ 2462a1173273SAlexandr Nedvedicky /* */ 2463a1173273SAlexandr Nedvedicky /* 5) IP addresses in original mblk are swapped and IP header data */ 2464a1173273SAlexandr Nedvedicky /* are adjusted (protocol number). */ 2465a1173273SAlexandr Nedvedicky /* */ 2466a1173273SAlexandr Nedvedicky /* 6) Original mblk is trimmed to hold IPv6 header only, then it is */ 2467a1173273SAlexandr Nedvedicky /* linked with the ICMPv6 data we got from (3). */ 2468a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2469a1173273SAlexandr Nedvedicky static int fr_make_icmp_v6(fin) 2470a1173273SAlexandr Nedvedicky fr_info_t *fin; 2471a1173273SAlexandr Nedvedicky { 2472a1173273SAlexandr Nedvedicky struct icmp6_hdr *icmp6; 2473*6ccacea7SAlexandr Nedvedicky tcphdr_t *tcp; 2474a1173273SAlexandr Nedvedicky struct in6_addr tmp_src6; 2475a1173273SAlexandr Nedvedicky size_t icmp_pld_len; 2476a1173273SAlexandr Nedvedicky mblk_t *mblk_ip, *mblk_icmp; 2477a1173273SAlexandr Nedvedicky 2478a1173273SAlexandr Nedvedicky if (fin->fin_v != 6) 2479a1173273SAlexandr Nedvedicky return (-1); 2480a1173273SAlexandr Nedvedicky 2481a1173273SAlexandr Nedvedicky /* 2482a1173273SAlexandr Nedvedicky * If we are dealing with TCP, then packet must SYN/FIN to be routed by 2483a1173273SAlexandr Nedvedicky * IP stack. If it is not SYN/FIN, then we must drop it silently. 2484a1173273SAlexandr Nedvedicky */ 2485*6ccacea7SAlexandr Nedvedicky tcp = (tcphdr_t *) fin->fin_dp; 2486*6ccacea7SAlexandr Nedvedicky 2487*6ccacea7SAlexandr Nedvedicky if ((fin->fin_p == IPPROTO_TCP) && 2488*6ccacea7SAlexandr Nedvedicky ((tcp == NULL) || ((tcp->th_flags & (TH_SYN | TH_FIN)) == 0))) 2489a1173273SAlexandr Nedvedicky return (-1); 2490a1173273SAlexandr Nedvedicky 2491a1173273SAlexandr Nedvedicky /* 2492a1173273SAlexandr Nedvedicky * Step (1) 2493a1173273SAlexandr Nedvedicky * 2494a1173273SAlexandr Nedvedicky * We need to copy complete packet in case of IPv6, no trimming is 2495a1173273SAlexandr Nedvedicky * needed (except the L2 headers). 2496a1173273SAlexandr Nedvedicky */ 2497a1173273SAlexandr Nedvedicky icmp_pld_len = M_LEN(fin->fin_m); 2498a1173273SAlexandr Nedvedicky fin->fin_m->b_rptr += fin->fin_ipoff; 2499a1173273SAlexandr Nedvedicky if ((mblk_ip = copyb(fin->fin_m)) == NULL) 2500a1173273SAlexandr Nedvedicky return (-1); 2501a1173273SAlexandr Nedvedicky fin->fin_m->b_rptr -= fin->fin_ipoff; 2502a1173273SAlexandr Nedvedicky 2503a1173273SAlexandr Nedvedicky /* 2504a1173273SAlexandr Nedvedicky * Step (2) 2505a1173273SAlexandr Nedvedicky * 2506a1173273SAlexandr Nedvedicky * Allocate and create ICMP header. 2507a1173273SAlexandr Nedvedicky */ 2508a1173273SAlexandr Nedvedicky mblk_icmp = (mblk_t *) allocb(sizeof (struct icmp6_hdr), 2509a1173273SAlexandr Nedvedicky BPRI_HI); 2510a1173273SAlexandr Nedvedicky 2511a1173273SAlexandr Nedvedicky if (mblk_icmp == NULL) 2512a1173273SAlexandr Nedvedicky return (-1); 2513a1173273SAlexandr Nedvedicky 2514a1173273SAlexandr Nedvedicky MTYPE(mblk_icmp) = M_DATA; 2515a1173273SAlexandr Nedvedicky icmp6 = (struct icmp6_hdr *) mblk_icmp->b_wptr; 2516a1173273SAlexandr Nedvedicky icmp6->icmp6_type = ICMP6_DST_UNREACH; 2517a1173273SAlexandr Nedvedicky icmp6->icmp6_code = fin->fin_icode & 0xFF; 2518a1173273SAlexandr Nedvedicky icmp6->icmp6_data32[0] = 0; 2519a1173273SAlexandr Nedvedicky mblk_icmp->b_wptr += sizeof (struct icmp6_hdr); 2520a1173273SAlexandr Nedvedicky 2521a1173273SAlexandr Nedvedicky /* 2522a1173273SAlexandr Nedvedicky * Step (3) 2523a1173273SAlexandr Nedvedicky * 2524a1173273SAlexandr Nedvedicky * Link the copy of IP packet to ICMP header. 2525a1173273SAlexandr Nedvedicky */ 2526a1173273SAlexandr Nedvedicky linkb(mblk_icmp, mblk_ip); 2527a1173273SAlexandr Nedvedicky 2528a1173273SAlexandr Nedvedicky /* 2529a1173273SAlexandr Nedvedicky * Step (4) 2530a1173273SAlexandr Nedvedicky * 2531a1173273SAlexandr Nedvedicky * Calculate chksum - this is much more easier task than in case of 2532a1173273SAlexandr Nedvedicky * IPv4 - ICMPv6 chksum only covers IP addresses, and payload length. 2533a1173273SAlexandr Nedvedicky * We are making compensation just for change of packet length. 2534a1173273SAlexandr Nedvedicky */ 2535a1173273SAlexandr Nedvedicky icmp6->icmp6_cksum = icmp_pld_len + sizeof (struct icmp6_hdr); 2536a1173273SAlexandr Nedvedicky 2537a1173273SAlexandr Nedvedicky /* 2538a1173273SAlexandr Nedvedicky * Step (5) 2539a1173273SAlexandr Nedvedicky * 2540a1173273SAlexandr Nedvedicky * Swap IP addresses. 2541a1173273SAlexandr Nedvedicky */ 2542a1173273SAlexandr Nedvedicky tmp_src6 = fin->fin_ip6->ip6_src; 2543a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_src = fin->fin_ip6->ip6_dst; 2544a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_dst = tmp_src6; 2545a1173273SAlexandr Nedvedicky 2546a1173273SAlexandr Nedvedicky /* 2547a1173273SAlexandr Nedvedicky * and adjust IP header data. 2548a1173273SAlexandr Nedvedicky */ 2549a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_nxt = IPPROTO_ICMPV6; 2550a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_plen = htons(icmp_pld_len + sizeof (struct icmp6_hdr)); 2551a1173273SAlexandr Nedvedicky 2552a1173273SAlexandr Nedvedicky /* 2553a1173273SAlexandr Nedvedicky * Step (6) 2554a1173273SAlexandr Nedvedicky * 2555a1173273SAlexandr Nedvedicky * We must release all linked mblks from original packet and keep only 2556a1173273SAlexandr Nedvedicky * the first mblk with IP header to link ICMP data. 2557a1173273SAlexandr Nedvedicky */ 2558a1173273SAlexandr Nedvedicky fin->fin_m->b_wptr = (unsigned char *) fin->fin_ip6 + sizeof (ip6_t); 2559a1173273SAlexandr Nedvedicky 2560a1173273SAlexandr Nedvedicky if (fin->fin_m->b_cont != NULL) { 2561a1173273SAlexandr Nedvedicky FREE_MB_T(fin->fin_m->b_cont); 2562a1173273SAlexandr Nedvedicky } 2563a1173273SAlexandr Nedvedicky 2564a1173273SAlexandr Nedvedicky /* 2565a1173273SAlexandr Nedvedicky * Append ICMP payload to IP header. 2566a1173273SAlexandr Nedvedicky */ 2567a1173273SAlexandr Nedvedicky linkb(fin->fin_m, mblk_icmp); 2568a1173273SAlexandr Nedvedicky 2569a1173273SAlexandr Nedvedicky return (0); 2570a1173273SAlexandr Nedvedicky } 2571a1173273SAlexandr Nedvedicky #endif /* USE_INET6 */ 2572a1173273SAlexandr Nedvedicky 2573a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2574a1173273SAlexandr Nedvedicky /* Function: fr_make_icmp */ 2575a1173273SAlexandr Nedvedicky /* Returns: int - 0 on success, -1 on failure */ 2576a1173273SAlexandr Nedvedicky /* Parameters: fin(I) - pointer to packet information */ 2577a1173273SAlexandr Nedvedicky /* */ 2578a1173273SAlexandr Nedvedicky /* We must alter the original mblks passed to IPF from IP stack via */ 2579a1173273SAlexandr Nedvedicky /* FW_HOOKS. The reasons why we must alter packet are discussed within */ 2580a1173273SAlexandr Nedvedicky /* comment at fr_make_rst() function. */ 2581a1173273SAlexandr Nedvedicky /* */ 2582a1173273SAlexandr Nedvedicky /* The fr_make_icmp() function acts as a wrapper, which passes the code */ 2583a1173273SAlexandr Nedvedicky /* execution to fr_make_icmp_v4() or fr_make_icmp_v6() depending on */ 2584a1173273SAlexandr Nedvedicky /* protocol version. However there are some details, which are common to */ 2585a1173273SAlexandr Nedvedicky /* both IP versions. The details are going to be explained here. */ 2586a1173273SAlexandr Nedvedicky /* */ 2587a1173273SAlexandr Nedvedicky /* The packet looks as follows: */ 2588a1173273SAlexandr Nedvedicky /* xxx | IP hdr | IP payload ... | */ 2589a1173273SAlexandr Nedvedicky /* ^ ^ ^ ^ */ 2590a1173273SAlexandr Nedvedicky /* | | | | */ 2591a1173273SAlexandr Nedvedicky /* | | | fin_m->b_wptr = fin->fin_dp + fin->fin_dlen */ 2592a1173273SAlexandr Nedvedicky /* | | | */ 2593a1173273SAlexandr Nedvedicky /* | | `- fin_m->fin_dp (in case of IPv4 points to L4 header) */ 2594a1173273SAlexandr Nedvedicky /* | | */ 2595a1173273SAlexandr Nedvedicky /* | `- fin_m->b_rptr + fin_ipoff (fin_ipoff is most likely 0 in case */ 2596a1173273SAlexandr Nedvedicky /* | of loopback) */ 2597a1173273SAlexandr Nedvedicky /* | */ 2598a1173273SAlexandr Nedvedicky /* `- fin_m->b_rptr - points to L2 header in case of physical NIC */ 2599a1173273SAlexandr Nedvedicky /* */ 2600a1173273SAlexandr Nedvedicky /* All relevant IP headers are pulled up into the first mblk. It happened */ 2601a1173273SAlexandr Nedvedicky /* well in advance before the matching rule was found (the rule, which took */ 2602a1173273SAlexandr Nedvedicky /* us here, to fr_make_icmp() function). */ 2603a1173273SAlexandr Nedvedicky /* */ 2604a1173273SAlexandr Nedvedicky /* Both functions will turn packet passed in fin->fin_m mblk into a new */ 2605a1173273SAlexandr Nedvedicky /* packet. New packet will be represented as chain of mblks. */ 2606a1173273SAlexandr Nedvedicky /* orig mblk |- b_cont ---. */ 2607a1173273SAlexandr Nedvedicky /* ^ `-> ICMP hdr |- b_cont--. */ 2608a1173273SAlexandr Nedvedicky /* | ^ `-> duped orig mblk */ 2609a1173273SAlexandr Nedvedicky /* | | ^ */ 2610a1173273SAlexandr Nedvedicky /* `- The original mblk | | */ 2611a1173273SAlexandr Nedvedicky /* will be trimmed to | | */ 2612a1173273SAlexandr Nedvedicky /* to contain IP header | | */ 2613a1173273SAlexandr Nedvedicky /* only | | */ 2614a1173273SAlexandr Nedvedicky /* | | */ 2615a1173273SAlexandr Nedvedicky /* `- This is newly | */ 2616a1173273SAlexandr Nedvedicky /* allocated mblk to | */ 2617a1173273SAlexandr Nedvedicky /* hold ICMPv6 data. | */ 2618a1173273SAlexandr Nedvedicky /* | */ 2619a1173273SAlexandr Nedvedicky /* | */ 2620a1173273SAlexandr Nedvedicky /* | */ 2621a1173273SAlexandr Nedvedicky /* This is the copy of original mblk, it will contain -' */ 2622a1173273SAlexandr Nedvedicky /* orignal IP packet in case of ICMPv6. In case of */ 2623a1173273SAlexandr Nedvedicky /* ICMPv4 it will contain up to 8 bytes of IP payload */ 2624a1173273SAlexandr Nedvedicky /* (TCP/UDP/L4) data from original packet. */ 2625a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2626a1173273SAlexandr Nedvedicky int fr_make_icmp(fin) 2627a1173273SAlexandr Nedvedicky fr_info_t *fin; 2628a1173273SAlexandr Nedvedicky { 2629a1173273SAlexandr Nedvedicky int rv; 2630a1173273SAlexandr Nedvedicky 2631a1173273SAlexandr Nedvedicky if (fin->fin_v == 4) 2632a1173273SAlexandr Nedvedicky rv = fr_make_icmp_v4(fin); 2633a1173273SAlexandr Nedvedicky #ifdef USE_INET6 2634a1173273SAlexandr Nedvedicky else if (fin->fin_v == 6) 2635a1173273SAlexandr Nedvedicky rv = fr_make_icmp_v6(fin); 2636a1173273SAlexandr Nedvedicky #endif 2637a1173273SAlexandr Nedvedicky else 2638a1173273SAlexandr Nedvedicky rv = -1; 2639a1173273SAlexandr Nedvedicky 2640a1173273SAlexandr Nedvedicky return (rv); 2641a1173273SAlexandr Nedvedicky } 2642a1173273SAlexandr Nedvedicky #endif /* _KERNEL && SOLARIS2 >= 10 */ 2643