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 26314d3298eSAlexandr Nedvedicky bzero((char *)ifs->ifs_frcache, sizeof(ifs->ifs_frcache)); 264f4b3ec61Sdh MUTEX_INIT(&ifs->ifs_ipf_rw, "ipf rw mutex"); 265f4b3ec61Sdh MUTEX_INIT(&ifs->ifs_ipf_timeoutlock, "ipf timeout lock mutex"); 266f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); 267f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_tokens, "ipf token rwlock"); 268f4b3ec61Sdh ifs->ifs_ipf_locks_done = 1; 2697c478bd9Sstevel@tonic-gate 270f4b3ec61Sdh if (fr_initialise(ifs) < 0) 2717c478bd9Sstevel@tonic-gate return -1; 2727c478bd9Sstevel@tonic-gate 2737ddc9b1aSDarren Reed HOOK_INIT(ifs->ifs_ipfhook4_nicevents, ipf_nic_event_v4, 2747ddc9b1aSDarren Reed "ipfilter_hook4_nicevents", ifs); 2757ddc9b1aSDarren Reed HOOK_INIT(ifs->ifs_ipfhook4_in, ipf_hook4_in, 2767ddc9b1aSDarren Reed "ipfilter_hook4_in", ifs); 2777ddc9b1aSDarren Reed HOOK_INIT(ifs->ifs_ipfhook4_out, ipf_hook4_out, 2787ddc9b1aSDarren Reed "ipfilter_hook4_out", ifs); 27940cdc2e8SAlexandr Nedvedicky HOOK_INIT(ifs->ifs_ipfhook4_loop_in, ipf_hook4_loop_in, 2807ddc9b1aSDarren Reed "ipfilter_hook4_loop_in", ifs); 28140cdc2e8SAlexandr Nedvedicky HOOK_INIT(ifs->ifs_ipfhook4_loop_out, ipf_hook4_loop_out, 2827ddc9b1aSDarren Reed "ipfilter_hook4_loop_out", ifs); 283381a2a9aSdr 284381a2a9aSdr /* 2857ddc9b1aSDarren Reed * If we hold this lock over all of the net_hook_register calls, we 286381a2a9aSdr * can cause a deadlock to occur with the following lock ordering: 287381a2a9aSdr * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs 288381a2a9aSdr * R(hook_family)->R(hei_lock)->R(ipf_global) (packet path) 289381a2a9aSdr */ 290f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 291381a2a9aSdr 292381a2a9aSdr /* 293381a2a9aSdr * Add IPv4 hooks 294381a2a9aSdr */ 2957ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4 = net_protocol_lookup(id, NHF_INET); 296f4b3ec61Sdh if (ifs->ifs_ipf_ipv4 == NULL) 297381a2a9aSdr goto hookup_failed; 298381a2a9aSdr 2997ddc9b1aSDarren Reed ifs->ifs_hook4_nic_events = (net_hook_register(ifs->ifs_ipf_ipv4, 3007ddc9b1aSDarren Reed NH_NIC_EVENTS, ifs->ifs_ipfhook4_nicevents) == 0); 301f4b3ec61Sdh if (!ifs->ifs_hook4_nic_events) 302381a2a9aSdr goto hookup_failed; 303381a2a9aSdr 3047ddc9b1aSDarren Reed ifs->ifs_hook4_physical_in = (net_hook_register(ifs->ifs_ipf_ipv4, 3057ddc9b1aSDarren Reed NH_PHYSICAL_IN, ifs->ifs_ipfhook4_in) == 0); 306f4b3ec61Sdh if (!ifs->ifs_hook4_physical_in) 307381a2a9aSdr goto hookup_failed; 308381a2a9aSdr 3097ddc9b1aSDarren Reed ifs->ifs_hook4_physical_out = (net_hook_register(ifs->ifs_ipf_ipv4, 3107ddc9b1aSDarren Reed NH_PHYSICAL_OUT, ifs->ifs_ipfhook4_out) == 0); 311f4b3ec61Sdh if (!ifs->ifs_hook4_physical_out) 312381a2a9aSdr goto hookup_failed; 313381a2a9aSdr 314f4b3ec61Sdh if (ifs->ifs_ipf_loopback) { 3157ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_in = (net_hook_register( 3167ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN, 3177ddc9b1aSDarren Reed ifs->ifs_ipfhook4_loop_in) == 0); 318f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_in) 319381a2a9aSdr goto hookup_failed; 320381a2a9aSdr 3217ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_out = (net_hook_register( 3227ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT, 3237ddc9b1aSDarren Reed ifs->ifs_ipfhook4_loop_out) == 0); 324f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_out) 325381a2a9aSdr goto hookup_failed; 326381a2a9aSdr } 327381a2a9aSdr /* 328381a2a9aSdr * Add IPv6 hooks 329381a2a9aSdr */ 3307ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6 = net_protocol_lookup(id, NHF_INET6); 331f4b3ec61Sdh if (ifs->ifs_ipf_ipv6 == NULL) 332381a2a9aSdr goto hookup_failed; 333381a2a9aSdr 3347ddc9b1aSDarren Reed HOOK_INIT(ifs->ifs_ipfhook6_nicevents, ipf_nic_event_v6, 3357ddc9b1aSDarren Reed "ipfilter_hook6_nicevents", ifs); 3367ddc9b1aSDarren Reed HOOK_INIT(ifs->ifs_ipfhook6_in, ipf_hook6_in, 3377ddc9b1aSDarren Reed "ipfilter_hook6_in", ifs); 3387ddc9b1aSDarren Reed HOOK_INIT(ifs->ifs_ipfhook6_out, ipf_hook6_out, 3397ddc9b1aSDarren Reed "ipfilter_hook6_out", ifs); 34040cdc2e8SAlexandr Nedvedicky HOOK_INIT(ifs->ifs_ipfhook6_loop_in, ipf_hook6_loop_in, 3417ddc9b1aSDarren Reed "ipfilter_hook6_loop_in", ifs); 34240cdc2e8SAlexandr Nedvedicky HOOK_INIT(ifs->ifs_ipfhook6_loop_out, ipf_hook6_loop_out, 3437ddc9b1aSDarren Reed "ipfilter_hook6_loop_out", ifs); 3447ddc9b1aSDarren Reed 3457ddc9b1aSDarren Reed ifs->ifs_hook6_nic_events = (net_hook_register(ifs->ifs_ipf_ipv6, 3467ddc9b1aSDarren Reed NH_NIC_EVENTS, ifs->ifs_ipfhook6_nicevents) == 0); 347f4b3ec61Sdh if (!ifs->ifs_hook6_nic_events) 348381a2a9aSdr goto hookup_failed; 349381a2a9aSdr 3507ddc9b1aSDarren Reed ifs->ifs_hook6_physical_in = (net_hook_register(ifs->ifs_ipf_ipv6, 3517ddc9b1aSDarren Reed NH_PHYSICAL_IN, ifs->ifs_ipfhook6_in) == 0); 352f4b3ec61Sdh if (!ifs->ifs_hook6_physical_in) 353381a2a9aSdr goto hookup_failed; 354381a2a9aSdr 3557ddc9b1aSDarren Reed ifs->ifs_hook6_physical_out = (net_hook_register(ifs->ifs_ipf_ipv6, 3567ddc9b1aSDarren Reed NH_PHYSICAL_OUT, ifs->ifs_ipfhook6_out) == 0); 357f4b3ec61Sdh if (!ifs->ifs_hook6_physical_out) 358381a2a9aSdr goto hookup_failed; 359381a2a9aSdr 360f4b3ec61Sdh if (ifs->ifs_ipf_loopback) { 3617ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_in = (net_hook_register( 3627ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN, 3637ddc9b1aSDarren Reed ifs->ifs_ipfhook6_loop_in) == 0); 364f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_in) 365381a2a9aSdr goto hookup_failed; 366381a2a9aSdr 3677ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_out = (net_hook_register( 3687ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT, 3697ddc9b1aSDarren Reed ifs->ifs_ipfhook6_loop_out) == 0); 370f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_out) 371381a2a9aSdr goto hookup_failed; 372381a2a9aSdr } 373381a2a9aSdr 374381a2a9aSdr /* 375381a2a9aSdr * Reacquire ipf_global, now it is safe. 376381a2a9aSdr */ 377f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 378381a2a9aSdr 3797c478bd9Sstevel@tonic-gate /* Do not use private interface ip_params_arr[] in Solaris 10 */ 3807c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 3837c478bd9Sstevel@tonic-gate ip_forwarding = &ip_g_forward; 3847c478bd9Sstevel@tonic-gate #endif 3857c478bd9Sstevel@tonic-gate /* 3867c478bd9Sstevel@tonic-gate * XXX - There is no terminator for this array, so it is not possible 3877c478bd9Sstevel@tonic-gate * to tell if what we are looking for is missing and go off the end 3887c478bd9Sstevel@tonic-gate * of the array. 3897c478bd9Sstevel@tonic-gate */ 3907c478bd9Sstevel@tonic-gate 391ab25eeb5Syz #if SOLARIS2 <= 8 3927c478bd9Sstevel@tonic-gate for (i = 0; ; i++) { 3937c478bd9Sstevel@tonic-gate if (!strcmp(ip_param_arr[i].ip_param_name, "ip_def_ttl")) { 3947c478bd9Sstevel@tonic-gate ip_ttl_ptr = &ip_param_arr[i].ip_param_value; 3957c478bd9Sstevel@tonic-gate } else if (!strcmp(ip_param_arr[i].ip_param_name, 3967c478bd9Sstevel@tonic-gate "ip_path_mtu_discovery")) { 3977c478bd9Sstevel@tonic-gate ip_mtudisc = &ip_param_arr[i].ip_param_value; 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate #if SOLARIS2 < 8 4007c478bd9Sstevel@tonic-gate else if (!strcmp(ip_param_arr[i].ip_param_name, 4017c478bd9Sstevel@tonic-gate "ip_forwarding")) { 4027c478bd9Sstevel@tonic-gate ip_forwarding = &ip_param_arr[i].ip_param_value; 4037c478bd9Sstevel@tonic-gate } 4047c478bd9Sstevel@tonic-gate #else 4057c478bd9Sstevel@tonic-gate else if (!strcmp(ip_param_arr[i].ip_param_name, 4067c478bd9Sstevel@tonic-gate "ip6_forwarding")) { 4077c478bd9Sstevel@tonic-gate ip6_forwarding = &ip_param_arr[i].ip_param_value; 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate #endif 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate if (ip_mtudisc != NULL && ip_ttl_ptr != NULL && 4127c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 4137c478bd9Sstevel@tonic-gate ip6_forwarding != NULL && 4147c478bd9Sstevel@tonic-gate #endif 4157c478bd9Sstevel@tonic-gate ip_forwarding != NULL) 4167c478bd9Sstevel@tonic-gate break; 4177c478bd9Sstevel@tonic-gate } 418ab25eeb5Syz #endif 4197c478bd9Sstevel@tonic-gate 420f4b3ec61Sdh if (ifs->ifs_fr_control_forwarding & 1) { 421ab25eeb5Syz if (ip_forwarding != NULL) 422ab25eeb5Syz *ip_forwarding = 1; 4237c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 424ab25eeb5Syz if (ip6_forwarding != NULL) 425ab25eeb5Syz *ip6_forwarding = 1; 4267c478bd9Sstevel@tonic-gate #endif 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate #endif 4307c478bd9Sstevel@tonic-gate 431381a2a9aSdr return 0; 432381a2a9aSdr hookup_failed: 433f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 434381a2a9aSdr return -1; 435381a2a9aSdr } 436381a2a9aSdr 437f4b3ec61Sdh static int fr_setipfloopback(set, ifs) 438381a2a9aSdr int set; 439f4b3ec61Sdh ipf_stack_t *ifs; 440381a2a9aSdr { 441f4b3ec61Sdh if (ifs->ifs_ipf_ipv4 == NULL || ifs->ifs_ipf_ipv6 == NULL) 442381a2a9aSdr return EFAULT; 443381a2a9aSdr 444f4b3ec61Sdh if (set && !ifs->ifs_ipf_loopback) { 445f4b3ec61Sdh ifs->ifs_ipf_loopback = 1; 446381a2a9aSdr 4477ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_in = (net_hook_register( 4487ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN, 4497ddc9b1aSDarren Reed ifs->ifs_ipfhook4_loop_in) == 0); 450f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_in) 451381a2a9aSdr return EINVAL; 452381a2a9aSdr 4537ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_out = (net_hook_register( 4547ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT, 4557ddc9b1aSDarren Reed ifs->ifs_ipfhook4_loop_out) == 0); 456f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_out) 457381a2a9aSdr return EINVAL; 458381a2a9aSdr 4597ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_in = (net_hook_register( 4607ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN, 4617ddc9b1aSDarren Reed ifs->ifs_ipfhook6_loop_in) == 0); 462f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_in) 463381a2a9aSdr return EINVAL; 464381a2a9aSdr 4657ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_out = (net_hook_register( 4667ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT, 4677ddc9b1aSDarren Reed ifs->ifs_ipfhook6_loop_out) == 0); 468f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_out) 469381a2a9aSdr return EINVAL; 470381a2a9aSdr 471f4b3ec61Sdh } else if (!set && ifs->ifs_ipf_loopback) { 472f4b3ec61Sdh ifs->ifs_ipf_loopback = 0; 473381a2a9aSdr 474f4b3ec61Sdh ifs->ifs_hook4_loopback_in = 4757ddc9b1aSDarren Reed (net_hook_unregister(ifs->ifs_ipf_ipv4, 4767ddc9b1aSDarren Reed NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0); 477f4b3ec61Sdh if (ifs->ifs_hook4_loopback_in) 478381a2a9aSdr return EBUSY; 479381a2a9aSdr 480f4b3ec61Sdh ifs->ifs_hook4_loopback_out = 4817ddc9b1aSDarren Reed (net_hook_unregister(ifs->ifs_ipf_ipv4, 4827ddc9b1aSDarren Reed NH_LOOPBACK_OUT, ifs->ifs_ipfhook4_loop_out) != 0); 483f4b3ec61Sdh if (ifs->ifs_hook4_loopback_out) 484381a2a9aSdr return EBUSY; 485381a2a9aSdr 486f4b3ec61Sdh ifs->ifs_hook6_loopback_in = 4877ddc9b1aSDarren Reed (net_hook_unregister(ifs->ifs_ipf_ipv6, 4887ddc9b1aSDarren Reed NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0); 489f4b3ec61Sdh if (ifs->ifs_hook6_loopback_in) 490381a2a9aSdr return EBUSY; 491381a2a9aSdr 492f4b3ec61Sdh ifs->ifs_hook6_loopback_out = 4937ddc9b1aSDarren Reed (net_hook_unregister(ifs->ifs_ipf_ipv6, 4947ddc9b1aSDarren Reed NH_LOOPBACK_OUT, ifs->ifs_ipfhook6_loop_out) != 0); 495f4b3ec61Sdh if (ifs->ifs_hook6_loopback_out) 496381a2a9aSdr return EBUSY; 497381a2a9aSdr } 4987c478bd9Sstevel@tonic-gate return 0; 4997c478bd9Sstevel@tonic-gate } 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate /* 5037c478bd9Sstevel@tonic-gate * Filter ioctl interface. 5047c478bd9Sstevel@tonic-gate */ 5057c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5067c478bd9Sstevel@tonic-gate int iplioctl(dev, cmd, data, mode, cp, rp) 5077c478bd9Sstevel@tonic-gate dev_t dev; 5087c478bd9Sstevel@tonic-gate int cmd; 5097c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 7 5107c478bd9Sstevel@tonic-gate intptr_t data; 5117c478bd9Sstevel@tonic-gate #else 5127c478bd9Sstevel@tonic-gate int *data; 5137c478bd9Sstevel@tonic-gate #endif 5147c478bd9Sstevel@tonic-gate int mode; 5157c478bd9Sstevel@tonic-gate cred_t *cp; 5167c478bd9Sstevel@tonic-gate int *rp; 5177c478bd9Sstevel@tonic-gate { 5187c478bd9Sstevel@tonic-gate int error = 0, tmp; 5197c478bd9Sstevel@tonic-gate friostat_t fio; 5207c478bd9Sstevel@tonic-gate minor_t unit; 5217c478bd9Sstevel@tonic-gate u_int enable; 522f4b3ec61Sdh ipf_stack_t *ifs; 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 5257c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplioctl(%x,%x,%x,%d,%x,%d)\n", 5267c478bd9Sstevel@tonic-gate dev, cmd, data, mode, cp, rp); 5277c478bd9Sstevel@tonic-gate #endif 5287c478bd9Sstevel@tonic-gate unit = getminor(dev); 5297c478bd9Sstevel@tonic-gate if (IPL_LOGMAX < unit) 5307c478bd9Sstevel@tonic-gate return ENXIO; 5317c478bd9Sstevel@tonic-gate 5327ddc9b1aSDarren Reed /* 5337ddc9b1aSDarren Reed * As we're calling ipf_find_stack in user space, from a given zone 5347ddc9b1aSDarren Reed * to find the stack pointer for this zone, there is no need to have 5357ddc9b1aSDarren Reed * a hold/refence count here. 5367ddc9b1aSDarren Reed */ 5377ddc9b1aSDarren Reed ifs = ipf_find_stack(crgetzoneid(cp)); 538f4b3ec61Sdh ASSERT(ifs != NULL); 539f4b3ec61Sdh 540f4b3ec61Sdh if (ifs->ifs_fr_running <= 0) { 541f4b3ec61Sdh if (unit != IPL_LOGIPF) { 5427c478bd9Sstevel@tonic-gate return EIO; 543f4b3ec61Sdh } 5447c478bd9Sstevel@tonic-gate if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 545ab25eeb5Syz cmd != SIOCIPFSET && cmd != SIOCFRENB && 546f4b3ec61Sdh cmd != SIOCGETFS && cmd != SIOCGETFF) { 5477c478bd9Sstevel@tonic-gate return EIO; 548f4b3ec61Sdh } 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate 551f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_global); 55272680cf5SDarren Reed if (ifs->ifs_fr_enable_active != 0) { 55372680cf5SDarren Reed RWLOCK_EXIT(&ifs->ifs_ipf_global); 55472680cf5SDarren Reed return EBUSY; 55572680cf5SDarren Reed } 5567c478bd9Sstevel@tonic-gate 5577ddc9b1aSDarren Reed error = fr_ioctlswitch(unit, (caddr_t)data, cmd, mode, cp->cr_uid, 5587ddc9b1aSDarren Reed curproc, ifs); 5597c478bd9Sstevel@tonic-gate if (error != -1) { 560f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 5617c478bd9Sstevel@tonic-gate return error; 5627c478bd9Sstevel@tonic-gate } 5637c478bd9Sstevel@tonic-gate error = 0; 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate switch (cmd) 5667c478bd9Sstevel@tonic-gate { 5677c478bd9Sstevel@tonic-gate case SIOCFRENB : 5687c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 5697c478bd9Sstevel@tonic-gate error = EPERM; 5707c478bd9Sstevel@tonic-gate else { 5717c478bd9Sstevel@tonic-gate error = COPYIN((caddr_t)data, (caddr_t)&enable, 5727c478bd9Sstevel@tonic-gate sizeof(enable)); 5737c478bd9Sstevel@tonic-gate if (error != 0) { 5747c478bd9Sstevel@tonic-gate error = EFAULT; 5757c478bd9Sstevel@tonic-gate break; 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate 578f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 579f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 580*e8d569f4SAlexandr Nedvedicky 581*e8d569f4SAlexandr Nedvedicky /* 582*e8d569f4SAlexandr Nedvedicky * We must recheck fr_enable_active here, since we've 583*e8d569f4SAlexandr Nedvedicky * dropped ifs_ipf_global from R in order to get it 584*e8d569f4SAlexandr Nedvedicky * exclusively. 585*e8d569f4SAlexandr Nedvedicky */ 586*e8d569f4SAlexandr Nedvedicky if (ifs->ifs_fr_enable_active == 0) { 587*e8d569f4SAlexandr Nedvedicky ifs->ifs_fr_enable_active = 1; 588*e8d569f4SAlexandr Nedvedicky error = fr_enableipf(ifs, enable); 589*e8d569f4SAlexandr Nedvedicky ifs->ifs_fr_enable_active = 0; 590*e8d569f4SAlexandr Nedvedicky } 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate break; 5937c478bd9Sstevel@tonic-gate case SIOCIPFSET : 5947c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) { 5957c478bd9Sstevel@tonic-gate error = EPERM; 5967c478bd9Sstevel@tonic-gate break; 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate /* FALLTHRU */ 5997c478bd9Sstevel@tonic-gate case SIOCIPFGETNEXT : 6007c478bd9Sstevel@tonic-gate case SIOCIPFGET : 601f4b3ec61Sdh error = fr_ipftune(cmd, (void *)data, ifs); 6027c478bd9Sstevel@tonic-gate break; 6037c478bd9Sstevel@tonic-gate case SIOCSETFF : 6047c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6057c478bd9Sstevel@tonic-gate error = EPERM; 6067c478bd9Sstevel@tonic-gate else { 6077ddc9b1aSDarren Reed error = COPYIN((caddr_t)data, 6087ddc9b1aSDarren Reed (caddr_t)&ifs->ifs_fr_flags, 6097ddc9b1aSDarren Reed sizeof(ifs->ifs_fr_flags)); 6107c478bd9Sstevel@tonic-gate if (error != 0) 6117c478bd9Sstevel@tonic-gate error = EFAULT; 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate break; 614381a2a9aSdr case SIOCIPFLP : 615381a2a9aSdr error = COPYIN((caddr_t)data, (caddr_t)&tmp, 616381a2a9aSdr sizeof(tmp)); 617381a2a9aSdr if (error != 0) 618381a2a9aSdr error = EFAULT; 619381a2a9aSdr else 620f4b3ec61Sdh error = fr_setipfloopback(tmp, ifs); 621381a2a9aSdr break; 6227c478bd9Sstevel@tonic-gate case SIOCGETFF : 623f4b3ec61Sdh error = COPYOUT((caddr_t)&ifs->ifs_fr_flags, (caddr_t)data, 6247ddc9b1aSDarren Reed sizeof(ifs->ifs_fr_flags)); 6257c478bd9Sstevel@tonic-gate if (error != 0) 6267c478bd9Sstevel@tonic-gate error = EFAULT; 6277c478bd9Sstevel@tonic-gate break; 6287c478bd9Sstevel@tonic-gate case SIOCFUNCL : 6297c478bd9Sstevel@tonic-gate error = fr_resolvefunc((void *)data); 6307c478bd9Sstevel@tonic-gate break; 6317c478bd9Sstevel@tonic-gate case SIOCINAFR : 6327c478bd9Sstevel@tonic-gate case SIOCRMAFR : 6337c478bd9Sstevel@tonic-gate case SIOCADAFR : 6347c478bd9Sstevel@tonic-gate case SIOCZRLST : 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 ifs->ifs_fr_active, 1, ifs); 6407c478bd9Sstevel@tonic-gate break; 6417c478bd9Sstevel@tonic-gate case SIOCINIFR : 6427c478bd9Sstevel@tonic-gate case SIOCRMIFR : 6437c478bd9Sstevel@tonic-gate case SIOCADIFR : 6447c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6457c478bd9Sstevel@tonic-gate error = EPERM; 6467c478bd9Sstevel@tonic-gate else 6477c478bd9Sstevel@tonic-gate error = frrequest(unit, cmd, (caddr_t)data, 648f4b3ec61Sdh 1 - ifs->ifs_fr_active, 1, ifs); 6497c478bd9Sstevel@tonic-gate break; 6507c478bd9Sstevel@tonic-gate case SIOCSWAPA : 6517c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6527c478bd9Sstevel@tonic-gate error = EPERM; 6537c478bd9Sstevel@tonic-gate else { 654f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_mutex); 65514d3298eSAlexandr Nedvedicky bzero((char *)ifs->ifs_frcache, 65614d3298eSAlexandr Nedvedicky sizeof (ifs->ifs_frcache)); 657f4b3ec61Sdh error = COPYOUT((caddr_t)&ifs->ifs_fr_active, 658f4b3ec61Sdh (caddr_t)data, 659f4b3ec61Sdh sizeof(ifs->ifs_fr_active)); 6607c478bd9Sstevel@tonic-gate if (error != 0) 6617c478bd9Sstevel@tonic-gate error = EFAULT; 6627c478bd9Sstevel@tonic-gate else 663f4b3ec61Sdh ifs->ifs_fr_active = 1 - ifs->ifs_fr_active; 664f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate break; 6677c478bd9Sstevel@tonic-gate case SIOCGETFS : 668f4b3ec61Sdh fr_getstat(&fio, ifs); 6697c478bd9Sstevel@tonic-gate error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT); 6707c478bd9Sstevel@tonic-gate break; 6717c478bd9Sstevel@tonic-gate case SIOCFRZST : 6727c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6737c478bd9Sstevel@tonic-gate error = EPERM; 6747c478bd9Sstevel@tonic-gate else 675f4b3ec61Sdh error = fr_zerostats((caddr_t)data, ifs); 6767c478bd9Sstevel@tonic-gate break; 6777c478bd9Sstevel@tonic-gate case SIOCIPFFL : 6787c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6797c478bd9Sstevel@tonic-gate error = EPERM; 6807c478bd9Sstevel@tonic-gate else { 6817c478bd9Sstevel@tonic-gate error = COPYIN((caddr_t)data, (caddr_t)&tmp, 6827c478bd9Sstevel@tonic-gate sizeof(tmp)); 6837c478bd9Sstevel@tonic-gate if (!error) { 684f4b3ec61Sdh tmp = frflush(unit, 4, tmp, ifs); 6857c478bd9Sstevel@tonic-gate error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 6867ddc9b1aSDarren Reed sizeof(tmp)); 6877c478bd9Sstevel@tonic-gate if (error != 0) 6887c478bd9Sstevel@tonic-gate error = EFAULT; 6897c478bd9Sstevel@tonic-gate } else 6907c478bd9Sstevel@tonic-gate error = EFAULT; 6917c478bd9Sstevel@tonic-gate } 6927c478bd9Sstevel@tonic-gate break; 6937663b816Sml #ifdef USE_INET6 6947663b816Sml case SIOCIPFL6 : 6957663b816Sml if (!(mode & FWRITE)) 6967663b816Sml error = EPERM; 6977663b816Sml else { 6987663b816Sml error = COPYIN((caddr_t)data, (caddr_t)&tmp, 6997663b816Sml sizeof(tmp)); 7007663b816Sml if (!error) { 701f4b3ec61Sdh tmp = frflush(unit, 6, tmp, ifs); 7027663b816Sml error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 7037ddc9b1aSDarren Reed sizeof(tmp)); 7047663b816Sml if (error != 0) 7057663b816Sml error = EFAULT; 7067663b816Sml } else 7077663b816Sml error = EFAULT; 7087663b816Sml } 7097663b816Sml break; 7107663b816Sml #endif 7117c478bd9Sstevel@tonic-gate case SIOCSTLCK : 7127c478bd9Sstevel@tonic-gate error = COPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 7137c478bd9Sstevel@tonic-gate if (error == 0) { 714f4b3ec61Sdh ifs->ifs_fr_state_lock = tmp; 715f4b3ec61Sdh ifs->ifs_fr_nat_lock = tmp; 716f4b3ec61Sdh ifs->ifs_fr_frag_lock = tmp; 717f4b3ec61Sdh ifs->ifs_fr_auth_lock = tmp; 7187c478bd9Sstevel@tonic-gate } else 7197c478bd9Sstevel@tonic-gate error = EFAULT; 7207c478bd9Sstevel@tonic-gate break; 7217c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 7227c478bd9Sstevel@tonic-gate case SIOCIPFFB : 7237c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 7247c478bd9Sstevel@tonic-gate error = EPERM; 7257c478bd9Sstevel@tonic-gate else { 726f4b3ec61Sdh tmp = ipflog_clear(unit, ifs); 7277c478bd9Sstevel@tonic-gate error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 7287c478bd9Sstevel@tonic-gate sizeof(tmp)); 7297c478bd9Sstevel@tonic-gate if (error) 7307c478bd9Sstevel@tonic-gate error = EFAULT; 7317c478bd9Sstevel@tonic-gate } 7327c478bd9Sstevel@tonic-gate break; 7337c478bd9Sstevel@tonic-gate #endif /* IPFILTER_LOG */ 7347c478bd9Sstevel@tonic-gate case SIOCFRSYN : 7357c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 7367c478bd9Sstevel@tonic-gate error = EPERM; 7377c478bd9Sstevel@tonic-gate else { 738f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 739f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 740381a2a9aSdr 741f4b3ec61Sdh frsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 742d6c23f6fSyx fr_natifpsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 743d6c23f6fSyx fr_nataddrsync(0, NULL, NULL, ifs); 744f4b3ec61Sdh fr_statesync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 745381a2a9aSdr error = 0; 7467c478bd9Sstevel@tonic-gate } 7477c478bd9Sstevel@tonic-gate break; 7487c478bd9Sstevel@tonic-gate case SIOCGFRST : 749f4b3ec61Sdh error = fr_outobj((void *)data, fr_fragstats(ifs), 7507c478bd9Sstevel@tonic-gate IPFOBJ_FRAGSTAT); 7517c478bd9Sstevel@tonic-gate break; 7527c478bd9Sstevel@tonic-gate case FIONREAD : 7537c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 754f4b3ec61Sdh tmp = (int)ifs->ifs_iplused[IPL_LOGIPF]; 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate error = COPYOUT((caddr_t)&tmp, (caddr_t)data, sizeof(tmp)); 7577c478bd9Sstevel@tonic-gate if (error != 0) 7587c478bd9Sstevel@tonic-gate error = EFAULT; 7597c478bd9Sstevel@tonic-gate #endif 7607c478bd9Sstevel@tonic-gate break; 761f4b3ec61Sdh case SIOCIPFITER : 7627ddc9b1aSDarren Reed error = ipf_frruleiter((caddr_t)data, cp->cr_uid, 7637ddc9b1aSDarren Reed curproc, ifs); 764f4b3ec61Sdh break; 765f4b3ec61Sdh 766f4b3ec61Sdh case SIOCGENITER : 7677ddc9b1aSDarren Reed error = ipf_genericiter((caddr_t)data, cp->cr_uid, 7687ddc9b1aSDarren Reed curproc, ifs); 769f4b3ec61Sdh break; 770f4b3ec61Sdh 771f4b3ec61Sdh case SIOCIPFDELTOK : 772bb1d9de5SJohn Ojemann error = BCOPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 773bb1d9de5SJohn Ojemann if (error != 0) { 774bb1d9de5SJohn Ojemann error = EFAULT; 775bb1d9de5SJohn Ojemann } else { 776bb1d9de5SJohn Ojemann error = ipf_deltoken(tmp, cp->cr_uid, curproc, ifs); 777bb1d9de5SJohn Ojemann } 778f4b3ec61Sdh break; 779f4b3ec61Sdh 7807c478bd9Sstevel@tonic-gate default : 78133f2fefdSDarren Reed #ifdef IPFDEBUG 7827ddc9b1aSDarren Reed cmn_err(CE_NOTE, "Unknown: cmd 0x%x data %p", 7837ddc9b1aSDarren Reed cmd, (void *)data); 78433f2fefdSDarren Reed #endif 7857c478bd9Sstevel@tonic-gate error = EINVAL; 7867c478bd9Sstevel@tonic-gate break; 7877c478bd9Sstevel@tonic-gate } 788f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 7897c478bd9Sstevel@tonic-gate return error; 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate 7937ddc9b1aSDarren Reed static int fr_enableipf(ifs, enable) 794882bd30bSdr ipf_stack_t *ifs; 795882bd30bSdr int enable; 796882bd30bSdr { 797882bd30bSdr int error; 798882bd30bSdr 79944aaa2b6Sjojemann if (!enable) { 800882bd30bSdr error = ipldetach(ifs); 801882bd30bSdr if (error == 0) 802882bd30bSdr ifs->ifs_fr_running = -1; 8037ddc9b1aSDarren Reed return error; 804882bd30bSdr } 805882bd30bSdr 80644aaa2b6Sjojemann if (ifs->ifs_fr_running > 0) 8077ddc9b1aSDarren Reed return 0; 80844aaa2b6Sjojemann 8097ddc9b1aSDarren Reed error = iplattach(ifs); 81044aaa2b6Sjojemann if (error == 0) { 81144aaa2b6Sjojemann if (ifs->ifs_fr_timer_id == NULL) { 81244aaa2b6Sjojemann int hz = drv_usectohz(500000); 81344aaa2b6Sjojemann 81444aaa2b6Sjojemann ifs->ifs_fr_timer_id = timeout(fr_slowtimer, 8157ddc9b1aSDarren Reed (void *)ifs, 8167ddc9b1aSDarren Reed hz); 81744aaa2b6Sjojemann } 81844aaa2b6Sjojemann ifs->ifs_fr_running = 1; 81944aaa2b6Sjojemann } else { 82044aaa2b6Sjojemann (void) ipldetach(ifs); 82144aaa2b6Sjojemann } 8227ddc9b1aSDarren Reed return error; 823882bd30bSdr } 824882bd30bSdr 825882bd30bSdr 826f4b3ec61Sdh phy_if_t get_unit(name, v, ifs) 827f4b3ec61Sdh char *name; 828f4b3ec61Sdh int v; 829f4b3ec61Sdh ipf_stack_t *ifs; 8307c478bd9Sstevel@tonic-gate { 8317ddc9b1aSDarren Reed net_handle_t nif; 832381a2a9aSdr 833381a2a9aSdr if (v == 4) 834f4b3ec61Sdh nif = ifs->ifs_ipf_ipv4; 835381a2a9aSdr else if (v == 6) 836f4b3ec61Sdh nif = ifs->ifs_ipf_ipv6; 837381a2a9aSdr else 838381a2a9aSdr return 0; 839381a2a9aSdr 840f4b3ec61Sdh return (net_phylookup(nif, name)); 8417c478bd9Sstevel@tonic-gate } 8427c478bd9Sstevel@tonic-gate 8437c478bd9Sstevel@tonic-gate /* 8447c478bd9Sstevel@tonic-gate * routines below for saving IP headers to buffer 8457c478bd9Sstevel@tonic-gate */ 8467c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8477c478bd9Sstevel@tonic-gate int iplopen(devp, flags, otype, cred) 8487c478bd9Sstevel@tonic-gate dev_t *devp; 8497c478bd9Sstevel@tonic-gate int flags, otype; 8507c478bd9Sstevel@tonic-gate cred_t *cred; 8517c478bd9Sstevel@tonic-gate { 8527c478bd9Sstevel@tonic-gate minor_t min = getminor(*devp); 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 8557c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplopen(%x,%x,%x,%x)\n", devp, flags, otype, cred); 8567c478bd9Sstevel@tonic-gate #endif 8577c478bd9Sstevel@tonic-gate if (!(otype & OTYP_CHR)) 8587c478bd9Sstevel@tonic-gate return ENXIO; 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate min = (IPL_LOGMAX < min) ? ENXIO : 0; 8617c478bd9Sstevel@tonic-gate return min; 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8667c478bd9Sstevel@tonic-gate int iplclose(dev, flags, otype, cred) 8677c478bd9Sstevel@tonic-gate dev_t dev; 8687c478bd9Sstevel@tonic-gate int flags, otype; 8697c478bd9Sstevel@tonic-gate cred_t *cred; 8707c478bd9Sstevel@tonic-gate { 8717c478bd9Sstevel@tonic-gate minor_t min = getminor(dev); 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 8747c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplclose(%x,%x,%x,%x)\n", dev, flags, otype, cred); 8757c478bd9Sstevel@tonic-gate #endif 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate min = (IPL_LOGMAX < min) ? ENXIO : 0; 8787c478bd9Sstevel@tonic-gate return min; 8797c478bd9Sstevel@tonic-gate } 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 8827c478bd9Sstevel@tonic-gate /* 8837c478bd9Sstevel@tonic-gate * iplread/ipllog 8847c478bd9Sstevel@tonic-gate * both of these must operate with at least splnet() lest they be 8857c478bd9Sstevel@tonic-gate * called during packet processing and cause an inconsistancy to appear in 8867c478bd9Sstevel@tonic-gate * the filter lists. 8877c478bd9Sstevel@tonic-gate */ 8887c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8897c478bd9Sstevel@tonic-gate int iplread(dev, uio, cp) 8907c478bd9Sstevel@tonic-gate dev_t dev; 8917c478bd9Sstevel@tonic-gate register struct uio *uio; 8927c478bd9Sstevel@tonic-gate cred_t *cp; 8937c478bd9Sstevel@tonic-gate { 894f4b3ec61Sdh ipf_stack_t *ifs; 895f4b3ec61Sdh int ret; 896f4b3ec61Sdh 8977ddc9b1aSDarren Reed /* 8987ddc9b1aSDarren Reed * As we're calling ipf_find_stack in user space, from a given zone 8997ddc9b1aSDarren Reed * to find the stack pointer for this zone, there is no need to have 9007ddc9b1aSDarren Reed * a hold/refence count here. 9017ddc9b1aSDarren Reed */ 9027ddc9b1aSDarren Reed ifs = ipf_find_stack(crgetzoneid(cp)); 903f4b3ec61Sdh ASSERT(ifs != NULL); 904f4b3ec61Sdh 9057c478bd9Sstevel@tonic-gate # ifdef IPFDEBUG 9067c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplread(%x,%x,%x)\n", dev, uio, cp); 9077c478bd9Sstevel@tonic-gate # endif 90808ee25aeSdr 909f4b3ec61Sdh if (ifs->ifs_fr_running < 1) { 91008ee25aeSdr return EIO; 911f4b3ec61Sdh } 91208ee25aeSdr 9137c478bd9Sstevel@tonic-gate # ifdef IPFILTER_SYNC 914f4b3ec61Sdh if (getminor(dev) == IPL_LOGSYNC) { 9157c478bd9Sstevel@tonic-gate return ipfsync_read(uio); 916f4b3ec61Sdh } 9177c478bd9Sstevel@tonic-gate # endif 9187c478bd9Sstevel@tonic-gate 919f4b3ec61Sdh ret = ipflog_read(getminor(dev), uio, ifs); 920f4b3ec61Sdh return ret; 9217c478bd9Sstevel@tonic-gate } 9227c478bd9Sstevel@tonic-gate #endif /* IPFILTER_LOG */ 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate 9257c478bd9Sstevel@tonic-gate /* 9267c478bd9Sstevel@tonic-gate * iplread/ipllog 9277c478bd9Sstevel@tonic-gate * both of these must operate with at least splnet() lest they be 9287c478bd9Sstevel@tonic-gate * called during packet processing and cause an inconsistancy to appear in 9297c478bd9Sstevel@tonic-gate * the filter lists. 9307c478bd9Sstevel@tonic-gate */ 9317c478bd9Sstevel@tonic-gate int iplwrite(dev, uio, cp) 9327c478bd9Sstevel@tonic-gate dev_t dev; 9337c478bd9Sstevel@tonic-gate register struct uio *uio; 9347c478bd9Sstevel@tonic-gate cred_t *cp; 9357c478bd9Sstevel@tonic-gate { 936f4b3ec61Sdh ipf_stack_t *ifs; 937f4b3ec61Sdh 9387ddc9b1aSDarren Reed /* 9397ddc9b1aSDarren Reed * As we're calling ipf_find_stack in user space, from a given zone 9407ddc9b1aSDarren Reed * to find the stack pointer for this zone, there is no need to have 9417ddc9b1aSDarren Reed * a hold/refence count here. 9427ddc9b1aSDarren Reed */ 9437ddc9b1aSDarren Reed ifs = ipf_find_stack(crgetzoneid(cp)); 944f4b3ec61Sdh ASSERT(ifs != NULL); 945f4b3ec61Sdh 9467c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 9477c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplwrite(%x,%x,%x)\n", dev, uio, cp); 9487c478bd9Sstevel@tonic-gate #endif 94908ee25aeSdr 950f4b3ec61Sdh if (ifs->ifs_fr_running < 1) { 95108ee25aeSdr return EIO; 952f4b3ec61Sdh } 95308ee25aeSdr 954ab25eeb5Syz #ifdef IPFILTER_SYNC 955ab25eeb5Syz if (getminor(dev) == IPL_LOGSYNC) 956ab25eeb5Syz return ipfsync_write(uio); 9577c478bd9Sstevel@tonic-gate #endif /* IPFILTER_SYNC */ 958ab25eeb5Syz dev = dev; /* LINT */ 959ab25eeb5Syz uio = uio; /* LINT */ 960ab25eeb5Syz cp = cp; /* LINT */ 961ab25eeb5Syz return ENXIO; 962ab25eeb5Syz } 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate /* 9667c478bd9Sstevel@tonic-gate * fr_send_reset - this could conceivably be a call to tcp_respond(), but that 9677c478bd9Sstevel@tonic-gate * requires a large amount of setting up and isn't any more efficient. 9687c478bd9Sstevel@tonic-gate */ 9697c478bd9Sstevel@tonic-gate int fr_send_reset(fin) 9707c478bd9Sstevel@tonic-gate fr_info_t *fin; 9717c478bd9Sstevel@tonic-gate { 9727c478bd9Sstevel@tonic-gate tcphdr_t *tcp, *tcp2; 9737c478bd9Sstevel@tonic-gate int tlen, hlen; 9747c478bd9Sstevel@tonic-gate mblk_t *m; 9757c478bd9Sstevel@tonic-gate #ifdef USE_INET6 9767c478bd9Sstevel@tonic-gate ip6_t *ip6; 9777c478bd9Sstevel@tonic-gate #endif 9787c478bd9Sstevel@tonic-gate ip_t *ip; 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate tcp = fin->fin_dp; 9817c478bd9Sstevel@tonic-gate if (tcp->th_flags & TH_RST) 9827c478bd9Sstevel@tonic-gate return -1; 9837c478bd9Sstevel@tonic-gate 9847c478bd9Sstevel@tonic-gate #ifndef IPFILTER_CKSUM 9857c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 9867c478bd9Sstevel@tonic-gate return -1; 9877c478bd9Sstevel@tonic-gate #endif 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate tlen = (tcp->th_flags & (TH_SYN|TH_FIN)) ? 1 : 0; 9907c478bd9Sstevel@tonic-gate #ifdef USE_INET6 9917c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) 9927c478bd9Sstevel@tonic-gate hlen = sizeof(ip6_t); 9937c478bd9Sstevel@tonic-gate else 9947c478bd9Sstevel@tonic-gate #endif 9957c478bd9Sstevel@tonic-gate hlen = sizeof(ip_t); 9967c478bd9Sstevel@tonic-gate hlen += sizeof(*tcp2); 9977c478bd9Sstevel@tonic-gate if ((m = (mblk_t *)allocb(hlen + 64, BPRI_HI)) == NULL) 9987c478bd9Sstevel@tonic-gate return -1; 9997c478bd9Sstevel@tonic-gate 10007c478bd9Sstevel@tonic-gate m->b_rptr += 64; 10017c478bd9Sstevel@tonic-gate MTYPE(m) = M_DATA; 10027c478bd9Sstevel@tonic-gate m->b_wptr = m->b_rptr + hlen; 1003ab25eeb5Syz ip = (ip_t *)m->b_rptr; 1004ab25eeb5Syz bzero((char *)ip, hlen); 10057c478bd9Sstevel@tonic-gate tcp2 = (struct tcphdr *)(m->b_rptr + hlen - sizeof(*tcp2)); 10067c478bd9Sstevel@tonic-gate tcp2->th_dport = tcp->th_sport; 10077c478bd9Sstevel@tonic-gate tcp2->th_sport = tcp->th_dport; 10087c478bd9Sstevel@tonic-gate if (tcp->th_flags & TH_ACK) { 10097c478bd9Sstevel@tonic-gate tcp2->th_seq = tcp->th_ack; 10107c478bd9Sstevel@tonic-gate tcp2->th_flags = TH_RST; 10117c478bd9Sstevel@tonic-gate } else { 10127c478bd9Sstevel@tonic-gate tcp2->th_ack = ntohl(tcp->th_seq); 10137c478bd9Sstevel@tonic-gate tcp2->th_ack += tlen; 10147c478bd9Sstevel@tonic-gate tcp2->th_ack = htonl(tcp2->th_ack); 10157c478bd9Sstevel@tonic-gate tcp2->th_flags = TH_RST|TH_ACK; 10167c478bd9Sstevel@tonic-gate } 10177c478bd9Sstevel@tonic-gate tcp2->th_off = sizeof(struct tcphdr) >> 2; 10187c478bd9Sstevel@tonic-gate 1019ab25eeb5Syz ip->ip_v = fin->fin_v; 10207c478bd9Sstevel@tonic-gate #ifdef USE_INET6 10217c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 10227c478bd9Sstevel@tonic-gate ip6 = (ip6_t *)m->b_rptr; 10237663b816Sml ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 1024d6c23f6fSyx ip6->ip6_src = fin->fin_dst6.in6; 1025d6c23f6fSyx ip6->ip6_dst = fin->fin_src6.in6; 10267c478bd9Sstevel@tonic-gate ip6->ip6_plen = htons(sizeof(*tcp)); 10277c478bd9Sstevel@tonic-gate ip6->ip6_nxt = IPPROTO_TCP; 10287663b816Sml tcp2->th_sum = fr_cksum(m, (ip_t *)ip6, IPPROTO_TCP, tcp2); 10297c478bd9Sstevel@tonic-gate } else 10307c478bd9Sstevel@tonic-gate #endif 10317c478bd9Sstevel@tonic-gate { 10327c478bd9Sstevel@tonic-gate ip->ip_src.s_addr = fin->fin_daddr; 10337c478bd9Sstevel@tonic-gate ip->ip_dst.s_addr = fin->fin_saddr; 10347c478bd9Sstevel@tonic-gate ip->ip_id = fr_nextipid(fin); 10357c478bd9Sstevel@tonic-gate ip->ip_hl = sizeof(*ip) >> 2; 10367c478bd9Sstevel@tonic-gate ip->ip_p = IPPROTO_TCP; 103737b40788Sekozlow ip->ip_len = sizeof(*ip) + sizeof(*tcp); 10387c478bd9Sstevel@tonic-gate ip->ip_tos = fin->fin_ip->ip_tos; 10397c478bd9Sstevel@tonic-gate tcp2->th_sum = fr_cksum(m, ip, IPPROTO_TCP, tcp2); 10407c478bd9Sstevel@tonic-gate } 1041ab25eeb5Syz return fr_send_ip(fin, m, &m); 10427c478bd9Sstevel@tonic-gate } 10437c478bd9Sstevel@tonic-gate 104437b40788Sekozlow /* 104537b40788Sekozlow * Function: fr_send_ip 104637b40788Sekozlow * Returns: 0: success 104737b40788Sekozlow * -1: failed 104837b40788Sekozlow * Parameters: 104937b40788Sekozlow * fin: packet information 105037b40788Sekozlow * m: the message block where ip head starts 105137b40788Sekozlow * 105237b40788Sekozlow * Send a new packet through the IP stack. 105337b40788Sekozlow * 105437b40788Sekozlow * For IPv4 packets, ip_len must be in host byte order, and ip_v, 105537b40788Sekozlow * ip_ttl, ip_off, and ip_sum are ignored (filled in by this 105637b40788Sekozlow * function). 105737b40788Sekozlow * 105837b40788Sekozlow * For IPv6 packets, ip6_flow, ip6_vfc, and ip6_hlim are filled 105937b40788Sekozlow * in by this function. 106037b40788Sekozlow * 106137b40788Sekozlow * All other portions of the packet must be in on-the-wire format. 106237b40788Sekozlow */ 1063ab25eeb5Syz /*ARGSUSED*/ 1064ab25eeb5Syz static int fr_send_ip(fin, m, mpp) 10657c478bd9Sstevel@tonic-gate fr_info_t *fin; 1066ab25eeb5Syz mblk_t *m, **mpp; 10677c478bd9Sstevel@tonic-gate { 1068ab25eeb5Syz qpktinfo_t qpi, *qpip; 1069ab25eeb5Syz fr_info_t fnew; 1070ab25eeb5Syz ip_t *ip; 1071ab25eeb5Syz int i, hlen; 1072f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1073ab25eeb5Syz 1074ab25eeb5Syz ip = (ip_t *)m->b_rptr; 1075ab25eeb5Syz bzero((char *)&fnew, sizeof(fnew)); 10767c478bd9Sstevel@tonic-gate 10777c478bd9Sstevel@tonic-gate #ifdef USE_INET6 10787c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 10797c478bd9Sstevel@tonic-gate ip6_t *ip6; 10807c478bd9Sstevel@tonic-gate 1081ab25eeb5Syz ip6 = (ip6_t *)ip; 10827c478bd9Sstevel@tonic-gate ip6->ip6_vfc = 0x60; 10837c478bd9Sstevel@tonic-gate ip6->ip6_hlim = 127; 1084ab25eeb5Syz fnew.fin_v = 6; 1085ab25eeb5Syz hlen = sizeof(*ip6); 1086923d6102Szf fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen; 10877c478bd9Sstevel@tonic-gate } else 10887c478bd9Sstevel@tonic-gate #endif 10897c478bd9Sstevel@tonic-gate { 1090ab25eeb5Syz fnew.fin_v = 4; 10917c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 10 10927c478bd9Sstevel@tonic-gate ip->ip_ttl = 255; 1093f4b3ec61Sdh if (net_getpmtuenabled(ifs->ifs_ipf_ipv4) == 1) 1094381a2a9aSdr ip->ip_off = htons(IP_DF); 10957c478bd9Sstevel@tonic-gate #else 1096ab25eeb5Syz if (ip_ttl_ptr != NULL) 1097ab25eeb5Syz ip->ip_ttl = (u_char)(*ip_ttl_ptr); 1098ab25eeb5Syz else 1099ab25eeb5Syz ip->ip_ttl = 63; 1100ab25eeb5Syz if (ip_mtudisc != NULL) 1101ab25eeb5Syz ip->ip_off = htons(*ip_mtudisc ? IP_DF : 0); 1102ab25eeb5Syz else 1103ab25eeb5Syz ip->ip_off = htons(IP_DF); 11047c478bd9Sstevel@tonic-gate #endif 1105ab25eeb5Syz /* 1106ab25eeb5Syz * The dance with byte order and ip_len/ip_off is because in 1107ab25eeb5Syz * fr_fastroute, it expects them to be in host byte order but 1108ab25eeb5Syz * ipf_cksum expects them to be in network byte order. 1109ab25eeb5Syz */ 1110ab25eeb5Syz ip->ip_len = htons(ip->ip_len); 11117c478bd9Sstevel@tonic-gate ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip)); 1112ab25eeb5Syz ip->ip_len = ntohs(ip->ip_len); 1113ab25eeb5Syz ip->ip_off = ntohs(ip->ip_off); 1114ab25eeb5Syz hlen = sizeof(*ip); 1115923d6102Szf fnew.fin_plen = ip->ip_len; 11167c478bd9Sstevel@tonic-gate } 1117ab25eeb5Syz 1118ab25eeb5Syz qpip = fin->fin_qpi; 1119ab25eeb5Syz qpi.qpi_off = 0; 1120381a2a9aSdr qpi.qpi_ill = qpip->qpi_ill; 1121ab25eeb5Syz qpi.qpi_m = m; 1122ab25eeb5Syz qpi.qpi_data = ip; 1123ab25eeb5Syz fnew.fin_qpi = &qpi; 1124ab25eeb5Syz fnew.fin_ifp = fin->fin_ifp; 1125ab25eeb5Syz fnew.fin_flx = FI_NOCKSUM; 1126ab25eeb5Syz fnew.fin_m = m; 112790907f62SJohn Ojemann fnew.fin_qfm = m; 1128ab25eeb5Syz fnew.fin_ip = ip; 1129ab25eeb5Syz fnew.fin_mp = mpp; 1130ab25eeb5Syz fnew.fin_hlen = hlen; 1131ab25eeb5Syz fnew.fin_dp = (char *)ip + hlen; 1132f4b3ec61Sdh fnew.fin_ifs = fin->fin_ifs; 1133ab25eeb5Syz (void) fr_makefrip(hlen, ip, &fnew); 1134ab25eeb5Syz 1135ab25eeb5Syz i = fr_fastroute(m, mpp, &fnew, NULL); 11367c478bd9Sstevel@tonic-gate return i; 11377c478bd9Sstevel@tonic-gate } 11387c478bd9Sstevel@tonic-gate 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate int fr_send_icmp_err(type, fin, dst) 11417c478bd9Sstevel@tonic-gate int type; 11427c478bd9Sstevel@tonic-gate fr_info_t *fin; 11437c478bd9Sstevel@tonic-gate int dst; 11447c478bd9Sstevel@tonic-gate { 11457c478bd9Sstevel@tonic-gate struct in_addr dst4; 11467c478bd9Sstevel@tonic-gate struct icmp *icmp; 1147ab25eeb5Syz qpktinfo_t *qpi; 11487c478bd9Sstevel@tonic-gate int hlen, code; 1149381a2a9aSdr phy_if_t phy; 11507c478bd9Sstevel@tonic-gate u_short sz; 11517c478bd9Sstevel@tonic-gate #ifdef USE_INET6 11527c478bd9Sstevel@tonic-gate mblk_t *mb; 11537c478bd9Sstevel@tonic-gate #endif 11547c478bd9Sstevel@tonic-gate mblk_t *m; 11557c478bd9Sstevel@tonic-gate #ifdef USE_INET6 11567c478bd9Sstevel@tonic-gate ip6_t *ip6; 11577c478bd9Sstevel@tonic-gate #endif 11587c478bd9Sstevel@tonic-gate ip_t *ip; 1159f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 11607c478bd9Sstevel@tonic-gate 11617c478bd9Sstevel@tonic-gate if ((type < 0) || (type > ICMP_MAXTYPE)) 11627c478bd9Sstevel@tonic-gate return -1; 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate code = fin->fin_icode; 11657c478bd9Sstevel@tonic-gate #ifdef USE_INET6 116633f2fefdSDarren Reed if ((code < 0) || (code >= ICMP_MAX_UNREACH)) 11677c478bd9Sstevel@tonic-gate return -1; 11687c478bd9Sstevel@tonic-gate #endif 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate #ifndef IPFILTER_CKSUM 11717c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 11727c478bd9Sstevel@tonic-gate return -1; 11737c478bd9Sstevel@tonic-gate #endif 11747c478bd9Sstevel@tonic-gate 1175ab25eeb5Syz qpi = fin->fin_qpi; 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate #ifdef USE_INET6 11787c478bd9Sstevel@tonic-gate mb = fin->fin_qfm; 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 11817c478bd9Sstevel@tonic-gate sz = sizeof(ip6_t); 11827c478bd9Sstevel@tonic-gate sz += MIN(mb->b_wptr - mb->b_rptr, 512); 11837c478bd9Sstevel@tonic-gate hlen = sizeof(ip6_t); 11847c478bd9Sstevel@tonic-gate type = icmptoicmp6types[type]; 11857c478bd9Sstevel@tonic-gate if (type == ICMP6_DST_UNREACH) 11867c478bd9Sstevel@tonic-gate code = icmptoicmp6unreach[code]; 11877c478bd9Sstevel@tonic-gate } else 11887c478bd9Sstevel@tonic-gate #endif 11897c478bd9Sstevel@tonic-gate { 11907c478bd9Sstevel@tonic-gate if ((fin->fin_p == IPPROTO_ICMP) && 11917c478bd9Sstevel@tonic-gate !(fin->fin_flx & FI_SHORT)) 11927c478bd9Sstevel@tonic-gate switch (ntohs(fin->fin_data[0]) >> 8) 11937c478bd9Sstevel@tonic-gate { 11947c478bd9Sstevel@tonic-gate case ICMP_ECHO : 11957c478bd9Sstevel@tonic-gate case ICMP_TSTAMP : 11967c478bd9Sstevel@tonic-gate case ICMP_IREQ : 11977c478bd9Sstevel@tonic-gate case ICMP_MASKREQ : 11987c478bd9Sstevel@tonic-gate break; 11997c478bd9Sstevel@tonic-gate default : 12007c478bd9Sstevel@tonic-gate return 0; 12017c478bd9Sstevel@tonic-gate } 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate sz = sizeof(ip_t) * 2; 12047c478bd9Sstevel@tonic-gate sz += 8; /* 64 bits of data */ 12057c478bd9Sstevel@tonic-gate hlen = sizeof(ip_t); 12067c478bd9Sstevel@tonic-gate } 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate sz += offsetof(struct icmp, icmp_ip); 12097c478bd9Sstevel@tonic-gate if ((m = (mblk_t *)allocb((size_t)sz + 64, BPRI_HI)) == NULL) 12107c478bd9Sstevel@tonic-gate return -1; 12117c478bd9Sstevel@tonic-gate MTYPE(m) = M_DATA; 12127c478bd9Sstevel@tonic-gate m->b_rptr += 64; 12137c478bd9Sstevel@tonic-gate m->b_wptr = m->b_rptr + sz; 12147c478bd9Sstevel@tonic-gate bzero((char *)m->b_rptr, (size_t)sz); 1215ab25eeb5Syz ip = (ip_t *)m->b_rptr; 1216ab25eeb5Syz ip->ip_v = fin->fin_v; 12177c478bd9Sstevel@tonic-gate icmp = (struct icmp *)(m->b_rptr + hlen); 12187c478bd9Sstevel@tonic-gate icmp->icmp_type = type & 0xff; 12197c478bd9Sstevel@tonic-gate icmp->icmp_code = code & 0xff; 1220381a2a9aSdr phy = (phy_if_t)qpi->qpi_ill; 1221381a2a9aSdr if (type == ICMP_UNREACH && (phy != 0) && 12227c478bd9Sstevel@tonic-gate fin->fin_icode == ICMP_UNREACH_NEEDFRAG) 1223f4b3ec61Sdh icmp->icmp_nextmtu = net_getmtu(ifs->ifs_ipf_ipv4, phy,0 ); 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate #ifdef USE_INET6 12267c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 12277c478bd9Sstevel@tonic-gate struct in6_addr dst6; 12287c478bd9Sstevel@tonic-gate int csz; 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate if (dst == 0) { 1231f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1232f4b3ec61Sdh 1233381a2a9aSdr if (fr_ifpaddr(6, FRI_NORMAL, (void *)phy, 1234f4b3ec61Sdh (void *)&dst6, NULL, ifs) == -1) { 12357c478bd9Sstevel@tonic-gate FREE_MB_T(m); 12367c478bd9Sstevel@tonic-gate return -1; 12377c478bd9Sstevel@tonic-gate } 12387c478bd9Sstevel@tonic-gate } else 1239d6c23f6fSyx dst6 = fin->fin_dst6.in6; 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate csz = sz; 12427c478bd9Sstevel@tonic-gate sz -= sizeof(ip6_t); 12437c478bd9Sstevel@tonic-gate ip6 = (ip6_t *)m->b_rptr; 12447663b816Sml ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 12457c478bd9Sstevel@tonic-gate ip6->ip6_plen = htons((u_short)sz); 12467c478bd9Sstevel@tonic-gate ip6->ip6_nxt = IPPROTO_ICMPV6; 12477c478bd9Sstevel@tonic-gate ip6->ip6_src = dst6; 1248d6c23f6fSyx ip6->ip6_dst = fin->fin_src6.in6; 12497c478bd9Sstevel@tonic-gate sz -= offsetof(struct icmp, icmp_ip); 12507c478bd9Sstevel@tonic-gate bcopy((char *)mb->b_rptr, (char *)&icmp->icmp_ip, sz); 12517c478bd9Sstevel@tonic-gate icmp->icmp_cksum = csz - sizeof(ip6_t); 12527c478bd9Sstevel@tonic-gate } else 12537c478bd9Sstevel@tonic-gate #endif 12547c478bd9Sstevel@tonic-gate { 12557c478bd9Sstevel@tonic-gate ip->ip_hl = sizeof(*ip) >> 2; 12567c478bd9Sstevel@tonic-gate ip->ip_p = IPPROTO_ICMP; 12577c478bd9Sstevel@tonic-gate ip->ip_id = fin->fin_ip->ip_id; 12587c478bd9Sstevel@tonic-gate ip->ip_tos = fin->fin_ip->ip_tos; 125937b40788Sekozlow ip->ip_len = (u_short)sz; 12607c478bd9Sstevel@tonic-gate if (dst == 0) { 1261f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1262f4b3ec61Sdh 1263381a2a9aSdr if (fr_ifpaddr(4, FRI_NORMAL, (void *)phy, 1264f4b3ec61Sdh (void *)&dst4, NULL, ifs) == -1) { 12657c478bd9Sstevel@tonic-gate FREE_MB_T(m); 12667c478bd9Sstevel@tonic-gate return -1; 12677c478bd9Sstevel@tonic-gate } 1268381a2a9aSdr } else { 12697c478bd9Sstevel@tonic-gate dst4 = fin->fin_dst; 1270381a2a9aSdr } 12717c478bd9Sstevel@tonic-gate ip->ip_src = dst4; 12727c478bd9Sstevel@tonic-gate ip->ip_dst = fin->fin_src; 12737c478bd9Sstevel@tonic-gate bcopy((char *)fin->fin_ip, (char *)&icmp->icmp_ip, 12747c478bd9Sstevel@tonic-gate sizeof(*fin->fin_ip)); 12757c478bd9Sstevel@tonic-gate bcopy((char *)fin->fin_ip + fin->fin_hlen, 12767c478bd9Sstevel@tonic-gate (char *)&icmp->icmp_ip + sizeof(*fin->fin_ip), 8); 12777663b816Sml icmp->icmp_ip.ip_len = htons(icmp->icmp_ip.ip_len); 1278ab25eeb5Syz icmp->icmp_ip.ip_off = htons(icmp->icmp_ip.ip_off); 12797c478bd9Sstevel@tonic-gate icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 12807c478bd9Sstevel@tonic-gate sz - sizeof(ip_t)); 12817c478bd9Sstevel@tonic-gate } 12827c478bd9Sstevel@tonic-gate 12837c478bd9Sstevel@tonic-gate /* 12847c478bd9Sstevel@tonic-gate * Need to exit out of these so we don't recursively call rw_enter 12857c478bd9Sstevel@tonic-gate * from fr_qout. 12867c478bd9Sstevel@tonic-gate */ 1287ab25eeb5Syz return fr_send_ip(fin, m, &m); 12887c478bd9Sstevel@tonic-gate } 12897c478bd9Sstevel@tonic-gate 12907c478bd9Sstevel@tonic-gate #include <sys/time.h> 12917c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 12927c478bd9Sstevel@tonic-gate 12937c478bd9Sstevel@tonic-gate #ifndef _KERNEL 12947c478bd9Sstevel@tonic-gate #include <stdio.h> 12957c478bd9Sstevel@tonic-gate #endif 12967c478bd9Sstevel@tonic-gate 12977c478bd9Sstevel@tonic-gate #define NULLADDR_RATE_LIMIT 10 /* 10 seconds */ 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate 13007c478bd9Sstevel@tonic-gate /* 13017c478bd9Sstevel@tonic-gate * Print out warning message at rate-limited speed. 13027c478bd9Sstevel@tonic-gate */ 1303f4b3ec61Sdh static void rate_limit_message(ipf_stack_t *ifs, 1304f4b3ec61Sdh int rate, const char *message, ...) 13057c478bd9Sstevel@tonic-gate { 13067c478bd9Sstevel@tonic-gate static time_t last_time = 0; 13077c478bd9Sstevel@tonic-gate time_t now; 13087c478bd9Sstevel@tonic-gate va_list args; 13097c478bd9Sstevel@tonic-gate char msg_buf[256]; 13107c478bd9Sstevel@tonic-gate int need_printed = 0; 13117c478bd9Sstevel@tonic-gate 13127c478bd9Sstevel@tonic-gate now = ddi_get_time(); 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate /* make sure, no multiple entries */ 1315f4b3ec61Sdh ASSERT(MUTEX_NOT_HELD(&(ifs->ifs_ipf_rw.ipf_lk))); 1316f4b3ec61Sdh MUTEX_ENTER(&ifs->ifs_ipf_rw); 13177c478bd9Sstevel@tonic-gate if (now - last_time >= rate) { 13187c478bd9Sstevel@tonic-gate need_printed = 1; 13197c478bd9Sstevel@tonic-gate last_time = now; 13207c478bd9Sstevel@tonic-gate } 1321f4b3ec61Sdh MUTEX_EXIT(&ifs->ifs_ipf_rw); 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate if (need_printed) { 13247c478bd9Sstevel@tonic-gate va_start(args, message); 13257c478bd9Sstevel@tonic-gate (void)vsnprintf(msg_buf, 255, message, args); 13267c478bd9Sstevel@tonic-gate va_end(args); 13277c478bd9Sstevel@tonic-gate #ifdef _KERNEL 13287c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, msg_buf); 13297c478bd9Sstevel@tonic-gate #else 13307c478bd9Sstevel@tonic-gate fprintf(std_err, msg_buf); 13317c478bd9Sstevel@tonic-gate #endif 13327c478bd9Sstevel@tonic-gate } 13337c478bd9Sstevel@tonic-gate } 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate /* 133672680cf5SDarren Reed * Return the first IP Address associated with an interface 133772680cf5SDarren Reed * For IPv6, we walk through the list of logical interfaces and return 133872680cf5SDarren Reed * the address of the first one that isn't a link-local interface. 133972680cf5SDarren Reed * We can't assume that it is :1 because another link-local address 134072680cf5SDarren Reed * may have been assigned there. 13417c478bd9Sstevel@tonic-gate */ 13427c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1343f4b3ec61Sdh int fr_ifpaddr(v, atype, ifptr, inp, inpmask, ifs) 13447c478bd9Sstevel@tonic-gate int v, atype; 1345381a2a9aSdr void *ifptr; 1346381a2a9aSdr struct in_addr *inp, *inpmask; 1347f4b3ec61Sdh ipf_stack_t *ifs; 13487c478bd9Sstevel@tonic-gate { 1349381a2a9aSdr struct sockaddr_in6 v6addr[2]; 1350381a2a9aSdr struct sockaddr_in v4addr[2]; 1351381a2a9aSdr net_ifaddr_t type[2]; 13527ddc9b1aSDarren Reed net_handle_t net_data; 1353381a2a9aSdr phy_if_t phyif; 1354381a2a9aSdr void *array; 1355381a2a9aSdr 1356381a2a9aSdr switch (v) 1357381a2a9aSdr { 1358381a2a9aSdr case 4: 1359f4b3ec61Sdh net_data = ifs->ifs_ipf_ipv4; 1360381a2a9aSdr array = v4addr; 1361381a2a9aSdr break; 1362381a2a9aSdr case 6: 1363f4b3ec61Sdh net_data = ifs->ifs_ipf_ipv6; 1364381a2a9aSdr array = v6addr; 1365381a2a9aSdr break; 1366381a2a9aSdr default: 1367381a2a9aSdr net_data = NULL; 1368381a2a9aSdr break; 1369381a2a9aSdr } 13707c478bd9Sstevel@tonic-gate 1371381a2a9aSdr if (net_data == NULL) 13727c478bd9Sstevel@tonic-gate return -1; 13737c478bd9Sstevel@tonic-gate 1374381a2a9aSdr phyif = (phy_if_t)ifptr; 1375ab25eeb5Syz 1376ab25eeb5Syz switch (atype) 1377ab25eeb5Syz { 1378ab25eeb5Syz case FRI_PEERADDR : 1379381a2a9aSdr type[0] = NA_PEER; 1380ab25eeb5Syz break; 1381381a2a9aSdr 1382381a2a9aSdr case FRI_BROADCAST : 1383381a2a9aSdr type[0] = NA_BROADCAST; 1384381a2a9aSdr break; 1385381a2a9aSdr 1386ab25eeb5Syz default : 1387381a2a9aSdr type[0] = NA_ADDRESS; 1388ab25eeb5Syz break; 1389ab25eeb5Syz } 13907c478bd9Sstevel@tonic-gate 1391381a2a9aSdr type[1] = NA_NETMASK; 1392381a2a9aSdr 1393381a2a9aSdr if (v == 6) { 139472680cf5SDarren Reed lif_if_t idx = 0; 139572680cf5SDarren Reed 139672680cf5SDarren Reed do { 139772680cf5SDarren Reed idx = net_lifgetnext(net_data, phyif, idx); 139872680cf5SDarren Reed if (net_getlifaddr(net_data, phyif, idx, 2, type, 139972680cf5SDarren Reed array) < 0) 140072680cf5SDarren Reed return -1; 140172680cf5SDarren Reed if (!IN6_IS_ADDR_LINKLOCAL(&v6addr[0].sin6_addr) && 140272680cf5SDarren Reed !IN6_IS_ADDR_MULTICAST(&v6addr[0].sin6_addr)) 140372680cf5SDarren Reed break; 140472680cf5SDarren Reed } while (idx != 0); 140572680cf5SDarren Reed 140672680cf5SDarren Reed if (idx == 0) 140772680cf5SDarren Reed return -1; 140872680cf5SDarren Reed 1409381a2a9aSdr return fr_ifpfillv6addr(atype, &v6addr[0], &v6addr[1], 1410381a2a9aSdr inp, inpmask); 14117c478bd9Sstevel@tonic-gate } 141272680cf5SDarren Reed 141372680cf5SDarren Reed if (net_getlifaddr(net_data, phyif, 0, 2, type, array) < 0) 141472680cf5SDarren Reed return -1; 141572680cf5SDarren Reed 1416381a2a9aSdr return fr_ifpfillv4addr(atype, &v4addr[0], &v4addr[1], inp, inpmask); 14177c478bd9Sstevel@tonic-gate } 14187c478bd9Sstevel@tonic-gate 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate u_32_t fr_newisn(fin) 14217c478bd9Sstevel@tonic-gate fr_info_t *fin; 14227c478bd9Sstevel@tonic-gate { 14237c478bd9Sstevel@tonic-gate static int iss_seq_off = 0; 14247c478bd9Sstevel@tonic-gate u_char hash[16]; 14257c478bd9Sstevel@tonic-gate u_32_t newiss; 14267c478bd9Sstevel@tonic-gate MD5_CTX ctx; 1427f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 14287c478bd9Sstevel@tonic-gate 14297c478bd9Sstevel@tonic-gate /* 14307c478bd9Sstevel@tonic-gate * Compute the base value of the ISS. It is a hash 14317c478bd9Sstevel@tonic-gate * of (saddr, sport, daddr, dport, secret). 14327c478bd9Sstevel@tonic-gate */ 14337c478bd9Sstevel@tonic-gate MD5Init(&ctx); 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 14367c478bd9Sstevel@tonic-gate sizeof(fin->fin_fi.fi_src)); 14377c478bd9Sstevel@tonic-gate MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 14387c478bd9Sstevel@tonic-gate sizeof(fin->fin_fi.fi_dst)); 14397c478bd9Sstevel@tonic-gate MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 14407c478bd9Sstevel@tonic-gate 1441f4b3ec61Sdh MD5Update(&ctx, ifs->ifs_ipf_iss_secret, sizeof(ifs->ifs_ipf_iss_secret)); 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate MD5Final(hash, &ctx); 14447c478bd9Sstevel@tonic-gate 14457c478bd9Sstevel@tonic-gate bcopy(hash, &newiss, sizeof(newiss)); 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate /* 14487c478bd9Sstevel@tonic-gate * Now increment our "timer", and add it in to 14497c478bd9Sstevel@tonic-gate * the computed value. 14507c478bd9Sstevel@tonic-gate * 14517c478bd9Sstevel@tonic-gate * XXX Use `addin'? 14527c478bd9Sstevel@tonic-gate * XXX TCP_ISSINCR too large to use? 14537c478bd9Sstevel@tonic-gate */ 14547c478bd9Sstevel@tonic-gate iss_seq_off += 0x00010000; 14557c478bd9Sstevel@tonic-gate newiss += iss_seq_off; 14567c478bd9Sstevel@tonic-gate return newiss; 14577c478bd9Sstevel@tonic-gate } 14587c478bd9Sstevel@tonic-gate 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 14617c478bd9Sstevel@tonic-gate /* Function: fr_nextipid */ 14627c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 14637c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 14647c478bd9Sstevel@tonic-gate /* */ 14657c478bd9Sstevel@tonic-gate /* Returns the next IPv4 ID to use for this packet. */ 14667c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 1467ab25eeb5Syz u_short fr_nextipid(fin) 14687c478bd9Sstevel@tonic-gate fr_info_t *fin; 14697c478bd9Sstevel@tonic-gate { 14707c478bd9Sstevel@tonic-gate static u_short ipid = 0; 14717c478bd9Sstevel@tonic-gate u_short id; 1472f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 14737c478bd9Sstevel@tonic-gate 1474f4b3ec61Sdh MUTEX_ENTER(&ifs->ifs_ipf_rw); 147533f2fefdSDarren Reed if (fin->fin_pktnum != 0) { 147633f2fefdSDarren Reed id = fin->fin_pktnum & 0xffff; 147733f2fefdSDarren Reed } else { 14787c478bd9Sstevel@tonic-gate id = ipid++; 147933f2fefdSDarren Reed } 1480f4b3ec61Sdh MUTEX_EXIT(&ifs->ifs_ipf_rw); 14817c478bd9Sstevel@tonic-gate 14827c478bd9Sstevel@tonic-gate return id; 14837c478bd9Sstevel@tonic-gate } 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate 14867c478bd9Sstevel@tonic-gate #ifndef IPFILTER_CKSUM 14877c478bd9Sstevel@tonic-gate /* ARGSUSED */ 14887c478bd9Sstevel@tonic-gate #endif 14897c478bd9Sstevel@tonic-gate INLINE void fr_checkv4sum(fin) 14907c478bd9Sstevel@tonic-gate fr_info_t *fin; 14917c478bd9Sstevel@tonic-gate { 14927c478bd9Sstevel@tonic-gate #ifdef IPFILTER_CKSUM 14937c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 14947c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_BAD; 14957c478bd9Sstevel@tonic-gate #endif 14967c478bd9Sstevel@tonic-gate } 14977c478bd9Sstevel@tonic-gate 14987c478bd9Sstevel@tonic-gate 14997c478bd9Sstevel@tonic-gate #ifdef USE_INET6 1500ab25eeb5Syz # ifndef IPFILTER_CKSUM 15017663b816Sml /* ARGSUSED */ 1502ab25eeb5Syz # endif 15037c478bd9Sstevel@tonic-gate INLINE void fr_checkv6sum(fin) 15047c478bd9Sstevel@tonic-gate fr_info_t *fin; 15057c478bd9Sstevel@tonic-gate { 15067c478bd9Sstevel@tonic-gate # ifdef IPFILTER_CKSUM 15077c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 15087c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_BAD; 15097c478bd9Sstevel@tonic-gate # endif 15107c478bd9Sstevel@tonic-gate } 15117c478bd9Sstevel@tonic-gate #endif /* USE_INET6 */ 1512ab25eeb5Syz 1513ab25eeb5Syz 1514ab25eeb5Syz #if (SOLARIS2 < 7) 1515ab25eeb5Syz void fr_slowtimer() 1516ab25eeb5Syz #else 1517ab25eeb5Syz /*ARGSUSED*/ 1518f4b3ec61Sdh void fr_slowtimer __P((void *arg)) 1519ab25eeb5Syz #endif 1520ab25eeb5Syz { 1521f4b3ec61Sdh ipf_stack_t *ifs = arg; 1522ab25eeb5Syz 152344aaa2b6Sjojemann READ_ENTER(&ifs->ifs_ipf_global); 152444aaa2b6Sjojemann if (ifs->ifs_fr_running != 1) { 152544aaa2b6Sjojemann ifs->ifs_fr_timer_id = NULL; 1526f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 1527ab25eeb5Syz return; 1528ab25eeb5Syz } 1529fd636508Szf ipf_expiretokens(ifs); 1530f4b3ec61Sdh fr_fragexpire(ifs); 1531f4b3ec61Sdh fr_timeoutstate(ifs); 1532f4b3ec61Sdh fr_natexpire(ifs); 1533f4b3ec61Sdh fr_authexpire(ifs); 1534f4b3ec61Sdh ifs->ifs_fr_ticks++; 153544aaa2b6Sjojemann if (ifs->ifs_fr_running == 1) 1536f4b3ec61Sdh ifs->ifs_fr_timer_id = timeout(fr_slowtimer, arg, 1537f4b3ec61Sdh drv_usectohz(500000)); 1538ab25eeb5Syz else 1539f4b3ec61Sdh ifs->ifs_fr_timer_id = NULL; 1540f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 1541ab25eeb5Syz } 1542ab25eeb5Syz 1543ab25eeb5Syz 1544381a2a9aSdr /* ------------------------------------------------------------------------ */ 1545381a2a9aSdr /* Function: fr_pullup */ 1546381a2a9aSdr /* Returns: NULL == pullup failed, else pointer to protocol header */ 1547381a2a9aSdr /* Parameters: m(I) - pointer to buffer where data packet starts */ 1548381a2a9aSdr /* fin(I) - pointer to packet information */ 1549381a2a9aSdr /* len(I) - number of bytes to pullup */ 1550381a2a9aSdr /* */ 1551381a2a9aSdr /* Attempt to move at least len bytes (from the start of the buffer) into a */ 1552381a2a9aSdr /* single buffer for ease of access. Operating system native functions are */ 1553381a2a9aSdr /* used to manage buffers - if necessary. If the entire packet ends up in */ 1554381a2a9aSdr /* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */ 1555381a2a9aSdr /* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ 1556381a2a9aSdr /* and ONLY if the pullup succeeds. */ 1557381a2a9aSdr /* */ 1558381a2a9aSdr /* We assume that 'min' is a pointer to a buffer that is part of the chain */ 1559381a2a9aSdr /* of buffers that starts at *fin->fin_mp. */ 1560381a2a9aSdr /* ------------------------------------------------------------------------ */ 1561381a2a9aSdr void *fr_pullup(min, fin, len) 1562381a2a9aSdr mb_t *min; 1563381a2a9aSdr fr_info_t *fin; 1564381a2a9aSdr int len; 1565381a2a9aSdr { 1566381a2a9aSdr qpktinfo_t *qpi = fin->fin_qpi; 1567381a2a9aSdr int out = fin->fin_out, dpoff, ipoff; 1568381a2a9aSdr mb_t *m = min, *m1, *m2; 1569381a2a9aSdr char *ip; 157008ee25aeSdr uint32_t start, stuff, end, value, flags; 1571f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1572381a2a9aSdr 1573381a2a9aSdr if (m == NULL) 1574381a2a9aSdr return NULL; 1575381a2a9aSdr 1576381a2a9aSdr ip = (char *)fin->fin_ip; 1577381a2a9aSdr if ((fin->fin_flx & FI_COALESCE) != 0) 1578381a2a9aSdr return ip; 1579381a2a9aSdr 1580381a2a9aSdr ipoff = fin->fin_ipoff; 1581381a2a9aSdr if (fin->fin_dp != NULL) 1582381a2a9aSdr dpoff = (char *)fin->fin_dp - (char *)ip; 1583381a2a9aSdr else 1584381a2a9aSdr dpoff = 0; 1585381a2a9aSdr 158640cdc2e8SAlexandr Nedvedicky if (M_LEN(m) < len + ipoff) { 1587381a2a9aSdr 1588381a2a9aSdr /* 1589381a2a9aSdr * pfil_precheck ensures the IP header is on a 32bit 1590381a2a9aSdr * aligned address so simply fail if that isn't currently 1591381a2a9aSdr * the case (should never happen). 1592381a2a9aSdr */ 1593381a2a9aSdr int inc = 0; 1594381a2a9aSdr 1595381a2a9aSdr if (ipoff > 0) { 1596381a2a9aSdr if ((ipoff & 3) != 0) { 1597381a2a9aSdr inc = 4 - (ipoff & 3); 1598381a2a9aSdr if (m->b_rptr - inc >= m->b_datap->db_base) 1599381a2a9aSdr m->b_rptr -= inc; 1600381a2a9aSdr else 1601381a2a9aSdr inc = 0; 1602381a2a9aSdr } 1603381a2a9aSdr } 1604381a2a9aSdr 1605381a2a9aSdr /* 1606381a2a9aSdr * XXX This is here as a work around for a bug with DEBUG 1607381a2a9aSdr * XXX Solaris kernels. The problem is b_prev is used by IP 1608381a2a9aSdr * XXX code as a way to stash the phyint_index for a packet, 1609381a2a9aSdr * XXX this doesn't get reset by IP but freeb does an ASSERT() 1610381a2a9aSdr * XXX for both of these to be NULL. See 6442390. 1611381a2a9aSdr */ 1612381a2a9aSdr m1 = m; 1613381a2a9aSdr m2 = m->b_prev; 1614381a2a9aSdr 1615381a2a9aSdr do { 1616381a2a9aSdr m1->b_next = NULL; 1617381a2a9aSdr m1->b_prev = NULL; 1618381a2a9aSdr m1 = m1->b_cont; 1619381a2a9aSdr } while (m1); 162008ee25aeSdr 162108ee25aeSdr /* 162208ee25aeSdr * Need to preserve checksum information by copying them 162308ee25aeSdr * to newmp which heads the pulluped message. 162408ee25aeSdr */ 162508ee25aeSdr hcksum_retrieve(m, NULL, NULL, &start, &stuff, &end, 162608ee25aeSdr &value, &flags); 162708ee25aeSdr 1628381a2a9aSdr if (pullupmsg(m, len + ipoff + inc) == 0) { 1629f4b3ec61Sdh ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[1]); 1630381a2a9aSdr FREE_MB_T(*fin->fin_mp); 1631381a2a9aSdr *fin->fin_mp = NULL; 1632381a2a9aSdr fin->fin_m = NULL; 1633381a2a9aSdr fin->fin_ip = NULL; 1634381a2a9aSdr fin->fin_dp = NULL; 1635381a2a9aSdr qpi->qpi_data = NULL; 1636381a2a9aSdr return NULL; 1637381a2a9aSdr } 163808ee25aeSdr 163908ee25aeSdr (void) hcksum_assoc(m, NULL, NULL, start, stuff, end, 164008ee25aeSdr value, flags, 0); 164108ee25aeSdr 1642381a2a9aSdr m->b_prev = m2; 1643381a2a9aSdr m->b_rptr += inc; 1644381a2a9aSdr fin->fin_m = m; 1645381a2a9aSdr ip = MTOD(m, char *) + ipoff; 1646381a2a9aSdr qpi->qpi_data = ip; 1647381a2a9aSdr } 1648381a2a9aSdr 1649f4b3ec61Sdh ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[0]); 1650381a2a9aSdr fin->fin_ip = (ip_t *)ip; 1651381a2a9aSdr if (fin->fin_dp != NULL) 1652381a2a9aSdr fin->fin_dp = (char *)fin->fin_ip + dpoff; 1653381a2a9aSdr 1654381a2a9aSdr if (len == fin->fin_plen) 1655381a2a9aSdr fin->fin_flx |= FI_COALESCE; 1656381a2a9aSdr return ip; 1657381a2a9aSdr } 1658381a2a9aSdr 1659381a2a9aSdr 1660ab25eeb5Syz /* 1661381a2a9aSdr * Function: fr_verifysrc 1662381a2a9aSdr * Returns: int (really boolean) 1663381a2a9aSdr * Parameters: fin - packet information 1664381a2a9aSdr * 1665381a2a9aSdr * Check whether the packet has a valid source address for the interface on 1666381a2a9aSdr * which the packet arrived, implementing the "fr_chksrc" feature. 1667381a2a9aSdr * Returns true iff the packet's source address is valid. 1668381a2a9aSdr */ 1669381a2a9aSdr int fr_verifysrc(fin) 1670381a2a9aSdr fr_info_t *fin; 1671381a2a9aSdr { 16727ddc9b1aSDarren Reed net_handle_t net_data_p; 1673381a2a9aSdr phy_if_t phy_ifdata_routeto; 1674381a2a9aSdr struct sockaddr sin; 1675f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1676381a2a9aSdr 1677381a2a9aSdr if (fin->fin_v == 4) { 1678f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv4; 1679381a2a9aSdr } else if (fin->fin_v == 6) { 1680f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv6; 1681381a2a9aSdr } else { 1682381a2a9aSdr return (0); 1683381a2a9aSdr } 1684381a2a9aSdr 1685381a2a9aSdr /* Get the index corresponding to the if name */ 1686381a2a9aSdr sin.sa_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 1687381a2a9aSdr bcopy(&fin->fin_saddr, &sin.sa_data, sizeof (struct in_addr)); 16887ddc9b1aSDarren Reed phy_ifdata_routeto = net_routeto(net_data_p, &sin, NULL); 1689381a2a9aSdr 1690381a2a9aSdr return (((phy_if_t)fin->fin_ifp == phy_ifdata_routeto) ? 1 : 0); 1691381a2a9aSdr } 1692381a2a9aSdr 1693381a2a9aSdr 1694381a2a9aSdr /* 1695381a2a9aSdr * Function: fr_fastroute 1696381a2a9aSdr * Returns: 0: success; 1697381a2a9aSdr * -1: failed 1698ab25eeb5Syz * Parameters: 1699381a2a9aSdr * mb: the message block where ip head starts 1700381a2a9aSdr * mpp: the pointer to the pointer of the orignal 1701381a2a9aSdr * packet message 1702381a2a9aSdr * fin: packet information 1703381a2a9aSdr * fdp: destination interface information 1704381a2a9aSdr * if it is NULL, no interface information provided. 1705ab25eeb5Syz * 1706ab25eeb5Syz * This function is for fastroute/to/dup-to rules. It calls 1707ab25eeb5Syz * pfil_make_lay2_packet to search route, make lay-2 header 1708ab25eeb5Syz * ,and identify output queue for the IP packet. 1709ab25eeb5Syz * The destination address depends on the following conditions: 1710ab25eeb5Syz * 1: for fastroute rule, fdp is passed in as NULL, so the 1711381a2a9aSdr * destination address is the IP Packet's destination address 1712ab25eeb5Syz * 2: for to/dup-to rule, if an ip address is specified after 1713381a2a9aSdr * the interface name, this address is the as destination 1714381a2a9aSdr * address. Otherwise IP Packet's destination address is used 1715ab25eeb5Syz */ 1716ab25eeb5Syz int fr_fastroute(mb, mpp, fin, fdp) 1717ab25eeb5Syz mblk_t *mb, **mpp; 1718ab25eeb5Syz fr_info_t *fin; 1719ab25eeb5Syz frdest_t *fdp; 1720ab25eeb5Syz { 17217ddc9b1aSDarren Reed net_handle_t net_data_p; 17227ddc9b1aSDarren Reed net_inject_t *inj; 1723ab25eeb5Syz mblk_t *mp = NULL; 1724381a2a9aSdr frentry_t *fr = fin->fin_fr; 1725ab25eeb5Syz qpktinfo_t *qpi; 1726ab25eeb5Syz ip_t *ip; 1727381a2a9aSdr 1728381a2a9aSdr struct sockaddr_in *sin; 1729381a2a9aSdr struct sockaddr_in6 *sin6; 1730381a2a9aSdr struct sockaddr *sinp; 1731f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1732ab25eeb5Syz #ifndef sparc 1733ab25eeb5Syz u_short __iplen, __ipoff; 1734ab25eeb5Syz #endif 1735381a2a9aSdr 1736381a2a9aSdr if (fin->fin_v == 4) { 1737f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv4; 1738381a2a9aSdr } else if (fin->fin_v == 6) { 1739f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv6; 1740381a2a9aSdr } else { 1741381a2a9aSdr return (-1); 1742381a2a9aSdr } 1743381a2a9aSdr 17447ddc9b1aSDarren Reed inj = net_inject_alloc(NETINFO_VERSION); 17457ddc9b1aSDarren Reed if (inj == NULL) 17467ddc9b1aSDarren Reed return -1; 17477ddc9b1aSDarren Reed 1748ab25eeb5Syz ip = fin->fin_ip; 1749ab25eeb5Syz qpi = fin->fin_qpi; 1750ab25eeb5Syz 1751ab25eeb5Syz /* 1752ab25eeb5Syz * If this is a duplicate mblk then we want ip to point at that 1753ab25eeb5Syz * data, not the original, if and only if it is already pointing at 1754ab25eeb5Syz * the current mblk data. 1755381a2a9aSdr * 1756381a2a9aSdr * Otherwise, if it's not a duplicate, and we're not already pointing 1757e6c6c1faSyz * at the current mblk data, then we want to ensure that the data 1758e6c6c1faSyz * points at ip. 1759ab25eeb5Syz */ 1760381a2a9aSdr 1761381a2a9aSdr if ((ip == (ip_t *)qpi->qpi_m->b_rptr) && (qpi->qpi_m != mb)) { 1762ab25eeb5Syz ip = (ip_t *)mb->b_rptr; 1763381a2a9aSdr } else if ((qpi->qpi_m == mb) && (ip != (ip_t *)qpi->qpi_m->b_rptr)) { 1764381a2a9aSdr qpi->qpi_m->b_rptr = (uchar_t *)ip; 1765e6c6c1faSyz qpi->qpi_off = 0; 1766e6c6c1faSyz } 1767ab25eeb5Syz 1768ab25eeb5Syz /* 1769ab25eeb5Syz * If there is another M_PROTO, we don't want it 1770ab25eeb5Syz */ 1771ab25eeb5Syz if (*mpp != mb) { 1772ab25eeb5Syz mp = unlinkb(*mpp); 1773ab25eeb5Syz freeb(*mpp); 1774ab25eeb5Syz *mpp = mp; 1775ab25eeb5Syz } 1776ab25eeb5Syz 17777ddc9b1aSDarren Reed sinp = (struct sockaddr *)&inj->ni_addr; 1778381a2a9aSdr sin = (struct sockaddr_in *)sinp; 1779381a2a9aSdr sin6 = (struct sockaddr_in6 *)sinp; 17807ddc9b1aSDarren Reed bzero((char *)&inj->ni_addr, sizeof (inj->ni_addr)); 17817ddc9b1aSDarren Reed inj->ni_addr.ss_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 17827ddc9b1aSDarren Reed inj->ni_packet = mb; 1783ab25eeb5Syz 1784ab25eeb5Syz /* 1785ab25eeb5Syz * In case we're here due to "to <if>" being used with 1786ab25eeb5Syz * "keep state", check that we're going in the correct 1787ab25eeb5Syz * direction. 1788ab25eeb5Syz */ 1789381a2a9aSdr if (fdp != NULL) { 1790381a2a9aSdr if ((fr != NULL) && (fdp->fd_ifp != NULL) && 1791381a2a9aSdr (fin->fin_rev != 0) && (fdp == &fr->fr_tif)) 1792381a2a9aSdr goto bad_fastroute; 17937ddc9b1aSDarren Reed inj->ni_physical = (phy_if_t)fdp->fd_ifp; 1794ab25eeb5Syz if (fin->fin_v == 4) { 1795381a2a9aSdr sin->sin_addr = fdp->fd_ip; 1796381a2a9aSdr } else { 1797381a2a9aSdr sin6->sin6_addr = fdp->fd_ip6.in6; 1798ab25eeb5Syz } 1799381a2a9aSdr } else { 1800381a2a9aSdr if (fin->fin_v == 4) { 1801381a2a9aSdr sin->sin_addr = ip->ip_dst; 1802381a2a9aSdr } else { 1803381a2a9aSdr sin6->sin6_addr = ((ip6_t *)ip)->ip6_dst; 1804ab25eeb5Syz } 18057ddc9b1aSDarren Reed inj->ni_physical = net_routeto(net_data_p, sinp, NULL); 1806ab25eeb5Syz } 1807ab25eeb5Syz 1808edd26dc5Sdr /* 1809edd26dc5Sdr * Clear the hardware checksum flags from packets that we are doing 1810edd26dc5Sdr * input processing on as leaving them set will cause the outgoing 1811edd26dc5Sdr * NIC (if it supports hardware checksum) to calculate them anew, 1812edd26dc5Sdr * using the old (correct) checksums as the pseudo value to start 1813edd26dc5Sdr * from. 1814edd26dc5Sdr */ 1815edd26dc5Sdr if (fin->fin_out == 0) { 1816edd26dc5Sdr DB_CKSUMFLAGS(mb) = 0; 1817edd26dc5Sdr } 1818c793af95Ssangeeta 1819381a2a9aSdr *mpp = mb; 1820ab25eeb5Syz 1821381a2a9aSdr if (fin->fin_out == 0) { 1822381a2a9aSdr void *saveifp; 1823381a2a9aSdr u_32_t pass; 1824ab25eeb5Syz 1825381a2a9aSdr saveifp = fin->fin_ifp; 18267ddc9b1aSDarren Reed fin->fin_ifp = (void *)inj->ni_physical; 1827d3675867Sjojemann fin->fin_flx &= ~FI_STATE; 1828381a2a9aSdr fin->fin_out = 1; 1829381a2a9aSdr (void) fr_acctpkt(fin, &pass); 1830381a2a9aSdr fin->fin_fr = NULL; 1831381a2a9aSdr if (!fr || !(fr->fr_flags & FR_RETMASK)) 1832381a2a9aSdr (void) fr_checkstate(fin, &pass); 1833d3675867Sjojemann if (fr_checknatout(fin, NULL) == -1) 1834381a2a9aSdr goto bad_fastroute; 1835381a2a9aSdr fin->fin_out = 0; 1836381a2a9aSdr fin->fin_ifp = saveifp; 1837381a2a9aSdr } 1838381a2a9aSdr #ifndef sparc 1839381a2a9aSdr if (fin->fin_v == 4) { 1840381a2a9aSdr __iplen = (u_short)ip->ip_len, 1841381a2a9aSdr __ipoff = (u_short)ip->ip_off; 1842ab25eeb5Syz 1843381a2a9aSdr ip->ip_len = htons(__iplen); 1844381a2a9aSdr ip->ip_off = htons(__ipoff); 1845381a2a9aSdr } 1846ab25eeb5Syz #endif 1847381a2a9aSdr 1848381a2a9aSdr if (net_data_p) { 18497ddc9b1aSDarren Reed if (net_inject(net_data_p, NI_DIRECT_OUT, inj) < 0) { 18507ddc9b1aSDarren Reed net_inject_free(inj); 1851381a2a9aSdr return (-1); 1852ab25eeb5Syz } 1853ab25eeb5Syz } 1854381a2a9aSdr 1855f4b3ec61Sdh ifs->ifs_fr_frouteok[0]++; 18567ddc9b1aSDarren Reed net_inject_free(inj); 1857381a2a9aSdr return 0; 1858ab25eeb5Syz bad_fastroute: 18597ddc9b1aSDarren Reed net_inject_free(inj); 1860ab25eeb5Syz freemsg(mb); 1861f4b3ec61Sdh ifs->ifs_fr_frouteok[1]++; 1862ab25eeb5Syz return -1; 1863ab25eeb5Syz } 1864ab25eeb5Syz 1865ab25eeb5Syz 1866ab25eeb5Syz /* ------------------------------------------------------------------------ */ 18677ddc9b1aSDarren Reed /* Function: ipf_hook4_out */ 1868381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1869381a2a9aSdr /* Parameters: event(I) - pointer to event */ 1870381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 1871ab25eeb5Syz /* */ 1872381a2a9aSdr /* Calling ipf_hook. */ 1873381a2a9aSdr /* ------------------------------------------------------------------------ */ 1874381a2a9aSdr /*ARGSUSED*/ 18757ddc9b1aSDarren Reed int ipf_hook4_out(hook_event_token_t token, hook_data_t info, void *arg) 1876381a2a9aSdr { 18777ddc9b1aSDarren Reed return ipf_hook(info, 1, 0, arg); 1878cbded9aeSdr } 1879cbded9aeSdr /*ARGSUSED*/ 18807ddc9b1aSDarren Reed int ipf_hook6_out(hook_event_token_t token, hook_data_t info, void *arg) 1881cbded9aeSdr { 18827ddc9b1aSDarren Reed return ipf_hook6(info, 1, 0, arg); 1883381a2a9aSdr } 1884381a2a9aSdr 1885381a2a9aSdr /* ------------------------------------------------------------------------ */ 18867ddc9b1aSDarren Reed /* Function: ipf_hook4_in */ 1887381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1888381a2a9aSdr /* Parameters: event(I) - pointer to event */ 1889381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 1890ab25eeb5Syz /* */ 1891381a2a9aSdr /* Calling ipf_hook. */ 1892ab25eeb5Syz /* ------------------------------------------------------------------------ */ 1893381a2a9aSdr /*ARGSUSED*/ 18947ddc9b1aSDarren Reed int ipf_hook4_in(hook_event_token_t token, hook_data_t info, void *arg) 1895ab25eeb5Syz { 18967ddc9b1aSDarren Reed return ipf_hook(info, 0, 0, arg); 1897cbded9aeSdr } 1898cbded9aeSdr /*ARGSUSED*/ 18997ddc9b1aSDarren Reed int ipf_hook6_in(hook_event_token_t token, hook_data_t info, void *arg) 1900cbded9aeSdr { 19017ddc9b1aSDarren Reed return ipf_hook6(info, 0, 0, arg); 1902381a2a9aSdr } 1903ab25eeb5Syz 1904ab25eeb5Syz 1905381a2a9aSdr /* ------------------------------------------------------------------------ */ 19067ddc9b1aSDarren Reed /* Function: ipf_hook4_loop_out */ 1907381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1908381a2a9aSdr /* Parameters: event(I) - pointer to event */ 1909381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 1910381a2a9aSdr /* */ 1911381a2a9aSdr /* Calling ipf_hook. */ 1912381a2a9aSdr /* ------------------------------------------------------------------------ */ 1913381a2a9aSdr /*ARGSUSED*/ 19147ddc9b1aSDarren Reed int ipf_hook4_loop_out(hook_event_token_t token, hook_data_t info, void *arg) 1915cbded9aeSdr { 19167ddc9b1aSDarren Reed return ipf_hook(info, 1, FI_NOCKSUM, arg); 1917cbded9aeSdr } 1918cbded9aeSdr /*ARGSUSED*/ 19197ddc9b1aSDarren Reed int ipf_hook6_loop_out(hook_event_token_t token, hook_data_t info, void *arg) 1920381a2a9aSdr { 19217ddc9b1aSDarren Reed return ipf_hook6(info, 1, FI_NOCKSUM, arg); 1922381a2a9aSdr } 1923ab25eeb5Syz 1924381a2a9aSdr /* ------------------------------------------------------------------------ */ 192540cdc2e8SAlexandr Nedvedicky /* Function: ipf_hook4_loop_in */ 1926381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1927381a2a9aSdr /* Parameters: event(I) - pointer to event */ 1928381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 1929381a2a9aSdr /* */ 1930381a2a9aSdr /* Calling ipf_hook. */ 1931381a2a9aSdr /* ------------------------------------------------------------------------ */ 1932381a2a9aSdr /*ARGSUSED*/ 193340cdc2e8SAlexandr Nedvedicky int ipf_hook4_loop_in(hook_event_token_t token, hook_data_t info, void *arg) 1934cbded9aeSdr { 19357ddc9b1aSDarren Reed return ipf_hook(info, 0, FI_NOCKSUM, arg); 1936cbded9aeSdr } 1937cbded9aeSdr /*ARGSUSED*/ 19387ddc9b1aSDarren Reed int ipf_hook6_loop_in(hook_event_token_t token, hook_data_t info, void *arg) 1939381a2a9aSdr { 19407ddc9b1aSDarren Reed return ipf_hook6(info, 0, FI_NOCKSUM, arg); 1941381a2a9aSdr } 1942381a2a9aSdr 1943381a2a9aSdr /* ------------------------------------------------------------------------ */ 1944381a2a9aSdr /* Function: ipf_hook */ 1945381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1946381a2a9aSdr /* Parameters: info(I) - pointer to hook information for firewalling */ 1947381a2a9aSdr /* out(I) - whether packet is going in or out */ 1948381a2a9aSdr /* loopback(I) - whether packet is a loopback packet or not */ 1949381a2a9aSdr /* */ 1950381a2a9aSdr /* Stepping stone function between the IP mainline and IPFilter. Extracts */ 1951381a2a9aSdr /* parameters out of the info structure and forms them up to be useful for */ 1952381a2a9aSdr /* calling ipfilter. */ 1953381a2a9aSdr /* ------------------------------------------------------------------------ */ 19547ddc9b1aSDarren Reed int ipf_hook(hook_data_t info, int out, int loopback, void *arg) 1955381a2a9aSdr { 1956381a2a9aSdr hook_pkt_event_t *fw; 19577ddc9b1aSDarren Reed ipf_stack_t *ifs; 1958381a2a9aSdr qpktinfo_t qpi; 19597ddc9b1aSDarren Reed int rval, hlen; 1960381a2a9aSdr u_short swap; 1961381a2a9aSdr phy_if_t phy; 1962381a2a9aSdr ip_t *ip; 1963381a2a9aSdr 19647ddc9b1aSDarren Reed ifs = arg; 1965381a2a9aSdr fw = (hook_pkt_event_t *)info; 1966381a2a9aSdr 1967381a2a9aSdr ASSERT(fw != NULL); 1968381a2a9aSdr phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp; 1969381a2a9aSdr 1970381a2a9aSdr ip = fw->hpe_hdr; 1971cbded9aeSdr swap = ntohs(ip->ip_len); 1972cbded9aeSdr ip->ip_len = swap; 1973cbded9aeSdr swap = ntohs(ip->ip_off); 1974cbded9aeSdr ip->ip_off = swap; 1975cbded9aeSdr hlen = IPH_HDR_LENGTH(ip); 1976381a2a9aSdr 1977381a2a9aSdr qpi.qpi_m = fw->hpe_mb; 1978381a2a9aSdr qpi.qpi_data = fw->hpe_hdr; 1979381a2a9aSdr qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr; 1980381a2a9aSdr qpi.qpi_ill = (void *)phy; 1981cbded9aeSdr qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST); 1982cbded9aeSdr if (qpi.qpi_flags) 1983cbded9aeSdr qpi.qpi_flags |= FI_MBCAST; 1984cbded9aeSdr qpi.qpi_flags |= loopback; 1985381a2a9aSdr 1986f4b3ec61Sdh rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, 19877ddc9b1aSDarren Reed &qpi, fw->hpe_mp, ifs); 1988381a2a9aSdr 1989381a2a9aSdr /* For fastroute cases, fr_check returns 0 with mp set to NULL */ 1990381a2a9aSdr if (rval == 0 && *(fw->hpe_mp) == NULL) 1991381a2a9aSdr rval = 1; 1992381a2a9aSdr 1993cbded9aeSdr /* Notify IP the packet mblk_t and IP header pointers. */ 1994381a2a9aSdr fw->hpe_mb = qpi.qpi_m; 1995381a2a9aSdr fw->hpe_hdr = qpi.qpi_data; 1996cbded9aeSdr if (rval == 0) { 1997381a2a9aSdr ip = qpi.qpi_data; 1998381a2a9aSdr swap = ntohs(ip->ip_len); 1999381a2a9aSdr ip->ip_len = swap; 2000381a2a9aSdr swap = ntohs(ip->ip_off); 2001381a2a9aSdr ip->ip_off = swap; 2002381a2a9aSdr } 2003381a2a9aSdr return rval; 2004ab25eeb5Syz 2005381a2a9aSdr } 20067ddc9b1aSDarren Reed int ipf_hook6(hook_data_t info, int out, int loopback, void *arg) 2007cbded9aeSdr { 2008cbded9aeSdr hook_pkt_event_t *fw; 2009cbded9aeSdr int rval, hlen; 2010cbded9aeSdr qpktinfo_t qpi; 2011cbded9aeSdr phy_if_t phy; 2012cbded9aeSdr 2013cbded9aeSdr fw = (hook_pkt_event_t *)info; 2014cbded9aeSdr 2015cbded9aeSdr ASSERT(fw != NULL); 2016cbded9aeSdr phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp; 2017cbded9aeSdr 2018cbded9aeSdr hlen = sizeof (ip6_t); 2019cbded9aeSdr 2020cbded9aeSdr qpi.qpi_m = fw->hpe_mb; 2021cbded9aeSdr qpi.qpi_data = fw->hpe_hdr; 2022cbded9aeSdr qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr; 2023cbded9aeSdr qpi.qpi_ill = (void *)phy; 2024cbded9aeSdr qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST); 2025cbded9aeSdr if (qpi.qpi_flags) 2026cbded9aeSdr qpi.qpi_flags |= FI_MBCAST; 2027cbded9aeSdr qpi.qpi_flags |= loopback; 2028cbded9aeSdr 2029cbded9aeSdr rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, 20307ddc9b1aSDarren Reed &qpi, fw->hpe_mp, arg); 2031cbded9aeSdr 2032cbded9aeSdr /* For fastroute cases, fr_check returns 0 with mp set to NULL */ 2033cbded9aeSdr if (rval == 0 && *(fw->hpe_mp) == NULL) 2034cbded9aeSdr rval = 1; 2035cbded9aeSdr 2036cbded9aeSdr /* Notify IP the packet mblk_t and IP header pointers. */ 2037cbded9aeSdr fw->hpe_mb = qpi.qpi_m; 2038cbded9aeSdr fw->hpe_hdr = qpi.qpi_data; 2039cbded9aeSdr return rval; 2040cbded9aeSdr 2041cbded9aeSdr } 2042ab25eeb5Syz 2043ab25eeb5Syz 2044381a2a9aSdr /* ------------------------------------------------------------------------ */ 2045381a2a9aSdr /* Function: ipf_nic_event_v4 */ 2046381a2a9aSdr /* Returns: int - 0 == no problems encountered */ 2047381a2a9aSdr /* Parameters: event(I) - pointer to event */ 2048381a2a9aSdr /* info(I) - pointer to information about a NIC event */ 2049381a2a9aSdr /* */ 2050381a2a9aSdr /* Function to receive asynchronous NIC events from IP */ 2051381a2a9aSdr /* ------------------------------------------------------------------------ */ 2052381a2a9aSdr /*ARGSUSED*/ 20537ddc9b1aSDarren Reed int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info, void *arg) 2054381a2a9aSdr { 2055381a2a9aSdr struct sockaddr_in *sin; 2056381a2a9aSdr hook_nic_event_t *hn; 20577ddc9b1aSDarren Reed ipf_stack_t *ifs = arg; 2058*e8d569f4SAlexandr Nedvedicky void *new_ifp = NULL; 2059*e8d569f4SAlexandr Nedvedicky 2060*e8d569f4SAlexandr Nedvedicky if (ifs->ifs_fr_running <= 0) 2061*e8d569f4SAlexandr Nedvedicky return (0); 2062381a2a9aSdr 2063381a2a9aSdr hn = (hook_nic_event_t *)info; 2064381a2a9aSdr 2065381a2a9aSdr switch (hn->hne_event) 2066381a2a9aSdr { 2067381a2a9aSdr case NE_PLUMB : 2068a4cf92b0Sdr frsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, hn->hne_data, 2069d6c23f6fSyx ifs); 2070d6c23f6fSyx fr_natifpsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, 2071f4b3ec61Sdh hn->hne_data, ifs); 2072381a2a9aSdr fr_statesync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, 2073f4b3ec61Sdh hn->hne_data, ifs); 2074381a2a9aSdr break; 2075381a2a9aSdr 2076381a2a9aSdr case NE_UNPLUMB : 2077f4b3ec61Sdh frsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 2078d6c23f6fSyx fr_natifpsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, 2079d6c23f6fSyx ifs); 2080f4b3ec61Sdh fr_statesync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 2081381a2a9aSdr break; 2082381a2a9aSdr 2083381a2a9aSdr case NE_ADDRESS_CHANGE : 2084a4cf92b0Sdr /* 2085a4cf92b0Sdr * We only respond to events for logical interface 0 because 2086a4cf92b0Sdr * IPFilter only uses the first address given to a network 2087a4cf92b0Sdr * interface. We check for hne_lif==1 because the netinfo 2088a4cf92b0Sdr * code maps adds 1 to the lif number so that it can return 2089a4cf92b0Sdr * 0 to indicate "no more lifs" when walking them. 2090a4cf92b0Sdr */ 2091a4cf92b0Sdr if (hn->hne_lif == 1) { 2092a4cf92b0Sdr frsync(IPFSYNC_RESYNC, 4, (void *)hn->hne_nic, NULL, 2093a4cf92b0Sdr ifs); 2094a4cf92b0Sdr sin = hn->hne_data; 2095d6c23f6fSyx fr_nataddrsync(4, (void *)hn->hne_nic, &sin->sin_addr, 2096a4cf92b0Sdr ifs); 2097a4cf92b0Sdr } 2098381a2a9aSdr break; 2099381a2a9aSdr 2100*e8d569f4SAlexandr Nedvedicky #if SOLARIS2 >= 10 2101*e8d569f4SAlexandr Nedvedicky case NE_IFINDEX_CHANGE : 2102*e8d569f4SAlexandr Nedvedicky WRITE_ENTER(&ifs->ifs_ipf_mutex); 2103*e8d569f4SAlexandr Nedvedicky 2104*e8d569f4SAlexandr Nedvedicky if (hn->hne_data != NULL) { 2105*e8d569f4SAlexandr Nedvedicky /* 2106*e8d569f4SAlexandr Nedvedicky * The netinfo passes interface index as int (hne_data should be 2107*e8d569f4SAlexandr Nedvedicky * handled as a pointer to int), which is always 32bit. We need to 2108*e8d569f4SAlexandr Nedvedicky * convert it to void pointer here, since interfaces are 2109*e8d569f4SAlexandr Nedvedicky * represented as pointers to void in IPF. The pointers are 64 bits 2110*e8d569f4SAlexandr Nedvedicky * long on 64bit platforms. Doing something like 2111*e8d569f4SAlexandr Nedvedicky * (void *)((int) x) 2112*e8d569f4SAlexandr Nedvedicky * will throw warning: 2113*e8d569f4SAlexandr Nedvedicky * "cast to pointer from integer of different size" 2114*e8d569f4SAlexandr Nedvedicky * during 64bit compilation. 2115*e8d569f4SAlexandr Nedvedicky * 2116*e8d569f4SAlexandr Nedvedicky * The line below uses (size_t) to typecast int to 2117*e8d569f4SAlexandr Nedvedicky * size_t, which might be 64bit/32bit (depending 2118*e8d569f4SAlexandr Nedvedicky * on architecture). Once we have proper 64bit/32bit 2119*e8d569f4SAlexandr Nedvedicky * type (size_t), we can safely convert it to void pointer. 2120*e8d569f4SAlexandr Nedvedicky */ 2121*e8d569f4SAlexandr Nedvedicky new_ifp = (void *)(size_t)*((int *)hn->hne_data); 2122*e8d569f4SAlexandr Nedvedicky fr_ifindexsync((void *)hn->hne_nic, new_ifp, ifs); 2123*e8d569f4SAlexandr Nedvedicky fr_natifindexsync((void *)hn->hne_nic, new_ifp, ifs); 2124*e8d569f4SAlexandr Nedvedicky fr_stateifindexsync((void *)hn->hne_nic, new_ifp, ifs); 2125*e8d569f4SAlexandr Nedvedicky } 2126*e8d569f4SAlexandr Nedvedicky RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2127*e8d569f4SAlexandr Nedvedicky break; 2128*e8d569f4SAlexandr Nedvedicky #endif 2129*e8d569f4SAlexandr Nedvedicky 2130381a2a9aSdr default : 2131381a2a9aSdr break; 2132ab25eeb5Syz } 2133ab25eeb5Syz 2134381a2a9aSdr return 0; 2135381a2a9aSdr } 2136ab25eeb5Syz 2137381a2a9aSdr 2138381a2a9aSdr /* ------------------------------------------------------------------------ */ 2139381a2a9aSdr /* Function: ipf_nic_event_v6 */ 2140381a2a9aSdr /* Returns: int - 0 == no problems encountered */ 2141381a2a9aSdr /* Parameters: event(I) - pointer to event */ 2142381a2a9aSdr /* info(I) - pointer to information about a NIC event */ 2143381a2a9aSdr /* */ 2144381a2a9aSdr /* Function to receive asynchronous NIC events from IP */ 2145381a2a9aSdr /* ------------------------------------------------------------------------ */ 2146381a2a9aSdr /*ARGSUSED*/ 21477ddc9b1aSDarren Reed int ipf_nic_event_v6(hook_event_token_t event, hook_data_t info, void *arg) 2148381a2a9aSdr { 2149d6c23f6fSyx struct sockaddr_in6 *sin6; 2150381a2a9aSdr hook_nic_event_t *hn; 21517ddc9b1aSDarren Reed ipf_stack_t *ifs = arg; 2152*e8d569f4SAlexandr Nedvedicky void *new_ifp = NULL; 2153*e8d569f4SAlexandr Nedvedicky 2154*e8d569f4SAlexandr Nedvedicky if (ifs->ifs_fr_running <= 0) 2155*e8d569f4SAlexandr Nedvedicky return (0); 2156381a2a9aSdr 2157381a2a9aSdr hn = (hook_nic_event_t *)info; 2158381a2a9aSdr 2159381a2a9aSdr switch (hn->hne_event) 2160381a2a9aSdr { 2161381a2a9aSdr case NE_PLUMB : 2162d6c23f6fSyx frsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2163d6c23f6fSyx hn->hne_data, ifs); 2164d6c23f6fSyx fr_natifpsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2165d6c23f6fSyx hn->hne_data, ifs); 2166381a2a9aSdr fr_statesync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2167f4b3ec61Sdh hn->hne_data, ifs); 2168381a2a9aSdr break; 2169381a2a9aSdr 2170381a2a9aSdr case NE_UNPLUMB : 2171f4b3ec61Sdh frsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2172d6c23f6fSyx fr_natifpsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, 2173d6c23f6fSyx ifs); 2174f4b3ec61Sdh fr_statesync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2175381a2a9aSdr break; 2176381a2a9aSdr 2177381a2a9aSdr case NE_ADDRESS_CHANGE : 2178d6c23f6fSyx if (hn->hne_lif == 1) { 2179d6c23f6fSyx sin6 = hn->hne_data; 2180d6c23f6fSyx fr_nataddrsync(6, (void *)hn->hne_nic, &sin6->sin6_addr, 2181d6c23f6fSyx ifs); 2182d6c23f6fSyx } 2183381a2a9aSdr break; 2184*e8d569f4SAlexandr Nedvedicky 2185*e8d569f4SAlexandr Nedvedicky #if SOLARIS2 >= 10 2186*e8d569f4SAlexandr Nedvedicky case NE_IFINDEX_CHANGE : 2187*e8d569f4SAlexandr Nedvedicky WRITE_ENTER(&ifs->ifs_ipf_mutex); 2188*e8d569f4SAlexandr Nedvedicky if (hn->hne_data != NULL) { 2189*e8d569f4SAlexandr Nedvedicky /* 2190*e8d569f4SAlexandr Nedvedicky * The netinfo passes interface index as int (hne_data should be 2191*e8d569f4SAlexandr Nedvedicky * handled as a pointer to int), which is always 32bit. We need to 2192*e8d569f4SAlexandr Nedvedicky * convert it to void pointer here, since interfaces are 2193*e8d569f4SAlexandr Nedvedicky * represented as pointers to void in IPF. The pointers are 64 bits 2194*e8d569f4SAlexandr Nedvedicky * long on 64bit platforms. Doing something like 2195*e8d569f4SAlexandr Nedvedicky * (void *)((int) x) 2196*e8d569f4SAlexandr Nedvedicky * will throw warning: 2197*e8d569f4SAlexandr Nedvedicky * "cast to pointer from integer of different size" 2198*e8d569f4SAlexandr Nedvedicky * during 64bit compilation. 2199*e8d569f4SAlexandr Nedvedicky * 2200*e8d569f4SAlexandr Nedvedicky * The line below uses (size_t) to typecast int to 2201*e8d569f4SAlexandr Nedvedicky * size_t, which might be 64bit/32bit (depending 2202*e8d569f4SAlexandr Nedvedicky * on architecture). Once we have proper 64bit/32bit 2203*e8d569f4SAlexandr Nedvedicky * type (size_t), we can safely convert it to void pointer. 2204*e8d569f4SAlexandr Nedvedicky */ 2205*e8d569f4SAlexandr Nedvedicky new_ifp = (void *)(size_t)*((int *)hn->hne_data); 2206*e8d569f4SAlexandr Nedvedicky fr_ifindexsync((void *)hn->hne_nic, new_ifp, ifs); 2207*e8d569f4SAlexandr Nedvedicky fr_natifindexsync((void *)hn->hne_nic, new_ifp, ifs); 2208*e8d569f4SAlexandr Nedvedicky fr_stateifindexsync((void *)hn->hne_nic, new_ifp, ifs); 2209*e8d569f4SAlexandr Nedvedicky } 2210*e8d569f4SAlexandr Nedvedicky RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2211*e8d569f4SAlexandr Nedvedicky break; 2212*e8d569f4SAlexandr Nedvedicky #endif 2213*e8d569f4SAlexandr Nedvedicky 2214381a2a9aSdr default : 2215381a2a9aSdr break; 2216381a2a9aSdr } 2217381a2a9aSdr 2218381a2a9aSdr return 0; 2219ab25eeb5Syz } 2220a1173273SAlexandr Nedvedicky 2221a1173273SAlexandr Nedvedicky /* 2222a1173273SAlexandr Nedvedicky * Functions fr_make_rst(), fr_make_icmp_v4(), fr_make_icmp_v6() 2223a1173273SAlexandr Nedvedicky * are needed in Solaris kernel only. We don't need them in 2224a1173273SAlexandr Nedvedicky * ipftest to pretend the ICMP/RST packet was sent as a response. 2225a1173273SAlexandr Nedvedicky */ 2226a1173273SAlexandr Nedvedicky #if defined(_KERNEL) && (SOLARIS2 >= 10) 2227a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2228a1173273SAlexandr Nedvedicky /* Function: fr_make_rst */ 2229a1173273SAlexandr Nedvedicky /* Returns: int - 0 on success, -1 on failure */ 2230a1173273SAlexandr Nedvedicky /* Parameters: fin(I) - pointer to packet information */ 2231a1173273SAlexandr Nedvedicky /* */ 2232a1173273SAlexandr Nedvedicky /* We must alter the original mblks passed to IPF from IP stack via */ 2233a1173273SAlexandr Nedvedicky /* FW_HOOKS. FW_HOOKS interface is powerfull, but it has some limitations. */ 2234a1173273SAlexandr Nedvedicky /* IPF can basicaly do only these things with mblk representing the packet: */ 2235a1173273SAlexandr Nedvedicky /* leave it as it is (pass the packet) */ 2236a1173273SAlexandr Nedvedicky /* */ 2237a1173273SAlexandr Nedvedicky /* discard it (block the packet) */ 2238a1173273SAlexandr Nedvedicky /* */ 2239a1173273SAlexandr Nedvedicky /* alter it (i.e. NAT) */ 2240a1173273SAlexandr Nedvedicky /* */ 2241a1173273SAlexandr Nedvedicky /* As you can see IPF can not simply discard the mblk and supply a new one */ 2242a1173273SAlexandr Nedvedicky /* instead to IP stack via FW_HOOKS. */ 2243a1173273SAlexandr Nedvedicky /* */ 2244a1173273SAlexandr Nedvedicky /* The return-rst action for packets coming via NIC is handled as follows: */ 2245a1173273SAlexandr Nedvedicky /* mblk with packet is discarded */ 2246a1173273SAlexandr Nedvedicky /* */ 2247a1173273SAlexandr Nedvedicky /* new mblk with RST response is constructed and injected to network */ 2248a1173273SAlexandr Nedvedicky /* */ 2249a1173273SAlexandr Nedvedicky /* IPF can't inject packets to loopback interface, this is just another */ 2250a1173273SAlexandr Nedvedicky /* limitation we have to deal with here. The only option to send RST */ 2251a1173273SAlexandr Nedvedicky /* response to offending TCP packet coming via loopback is to alter it. */ 2252a1173273SAlexandr Nedvedicky /* */ 2253a1173273SAlexandr Nedvedicky /* The fr_make_rst() function alters TCP SYN/FIN packet intercepted on */ 2254a1173273SAlexandr Nedvedicky /* loopback interface into TCP RST packet. fin->fin_mp is pointer to */ 2255a1173273SAlexandr Nedvedicky /* mblk L3 (IP) and L4 (TCP/UDP) packet headers. */ 2256a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2257a1173273SAlexandr Nedvedicky int fr_make_rst(fin) 2258a1173273SAlexandr Nedvedicky fr_info_t *fin; 2259a1173273SAlexandr Nedvedicky { 2260a1173273SAlexandr Nedvedicky uint16_t tmp_port; 2261a1173273SAlexandr Nedvedicky int rv = -1; 2262a1173273SAlexandr Nedvedicky uint32_t old_ack; 2263a1173273SAlexandr Nedvedicky tcphdr_t *tcp = NULL; 2264a1173273SAlexandr Nedvedicky struct in_addr tmp_src; 2265a1173273SAlexandr Nedvedicky #ifdef USE_INET6 2266a1173273SAlexandr Nedvedicky struct in6_addr tmp_src6; 2267a1173273SAlexandr Nedvedicky #endif 2268a1173273SAlexandr Nedvedicky 2269a1173273SAlexandr Nedvedicky ASSERT(fin->fin_p == IPPROTO_TCP); 2270a1173273SAlexandr Nedvedicky 2271a1173273SAlexandr Nedvedicky /* 2272a1173273SAlexandr Nedvedicky * We do not need to adjust chksum, since it is not being checked by 2273a1173273SAlexandr Nedvedicky * Solaris IP stack for loopback clients. 2274a1173273SAlexandr Nedvedicky */ 2275a1173273SAlexandr Nedvedicky if ((fin->fin_v == 4) && (fin->fin_p == IPPROTO_TCP) && 2276a1173273SAlexandr Nedvedicky ((tcp = (tcphdr_t *) fin->fin_dp) != NULL)) { 2277a1173273SAlexandr Nedvedicky 2278a1173273SAlexandr Nedvedicky if (tcp->th_flags & (TH_SYN | TH_FIN)) { 2279a1173273SAlexandr Nedvedicky /* Swap IPv4 addresses. */ 2280a1173273SAlexandr Nedvedicky tmp_src = fin->fin_ip->ip_src; 2281a1173273SAlexandr Nedvedicky fin->fin_ip->ip_src = fin->fin_ip->ip_dst; 2282a1173273SAlexandr Nedvedicky fin->fin_ip->ip_dst = tmp_src; 2283a1173273SAlexandr Nedvedicky 2284a1173273SAlexandr Nedvedicky rv = 0; 2285a1173273SAlexandr Nedvedicky } 2286a1173273SAlexandr Nedvedicky else 2287a1173273SAlexandr Nedvedicky tcp = NULL; 2288a1173273SAlexandr Nedvedicky } 2289a1173273SAlexandr Nedvedicky #ifdef USE_INET6 2290a1173273SAlexandr Nedvedicky else if ((fin->fin_v == 6) && (fin->fin_p == IPPROTO_TCP) && 2291a1173273SAlexandr Nedvedicky ((tcp = (tcphdr_t *) fin->fin_dp) != NULL)) { 2292a1173273SAlexandr Nedvedicky /* 2293a1173273SAlexandr Nedvedicky * We are relying on fact the next header is TCP, which is true 2294a1173273SAlexandr Nedvedicky * for regular TCP packets coming in over loopback. 2295a1173273SAlexandr Nedvedicky */ 2296a1173273SAlexandr Nedvedicky if (tcp->th_flags & (TH_SYN | TH_FIN)) { 2297a1173273SAlexandr Nedvedicky /* Swap IPv6 addresses. */ 2298a1173273SAlexandr Nedvedicky tmp_src6 = fin->fin_ip6->ip6_src; 2299a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_src = fin->fin_ip6->ip6_dst; 2300a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_dst = tmp_src6; 2301a1173273SAlexandr Nedvedicky 2302a1173273SAlexandr Nedvedicky rv = 0; 2303a1173273SAlexandr Nedvedicky } 2304a1173273SAlexandr Nedvedicky else 2305a1173273SAlexandr Nedvedicky tcp = NULL; 2306a1173273SAlexandr Nedvedicky } 2307a1173273SAlexandr Nedvedicky #endif 2308a1173273SAlexandr Nedvedicky 2309a1173273SAlexandr Nedvedicky if (tcp != NULL) { 2310a1173273SAlexandr Nedvedicky /* 2311a1173273SAlexandr Nedvedicky * Adjust TCP header: 2312a1173273SAlexandr Nedvedicky * swap ports, 2313a1173273SAlexandr Nedvedicky * set flags, 2314a1173273SAlexandr Nedvedicky * set correct ACK number 2315a1173273SAlexandr Nedvedicky */ 2316a1173273SAlexandr Nedvedicky tmp_port = tcp->th_sport; 2317a1173273SAlexandr Nedvedicky tcp->th_sport = tcp->th_dport; 2318a1173273SAlexandr Nedvedicky tcp->th_dport = tmp_port; 2319a1173273SAlexandr Nedvedicky old_ack = tcp->th_ack; 2320a1173273SAlexandr Nedvedicky tcp->th_ack = htonl(ntohl(tcp->th_seq) + 1); 2321a1173273SAlexandr Nedvedicky tcp->th_seq = old_ack; 2322a1173273SAlexandr Nedvedicky tcp->th_flags = TH_RST | TH_ACK; 2323a1173273SAlexandr Nedvedicky } 2324a1173273SAlexandr Nedvedicky 2325a1173273SAlexandr Nedvedicky return (rv); 2326a1173273SAlexandr Nedvedicky } 2327a1173273SAlexandr Nedvedicky 2328a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2329a1173273SAlexandr Nedvedicky /* Function: fr_make_icmp_v4 */ 2330a1173273SAlexandr Nedvedicky /* Returns: int - 0 on success, -1 on failure */ 2331a1173273SAlexandr Nedvedicky /* Parameters: fin(I) - pointer to packet information */ 2332a1173273SAlexandr Nedvedicky /* */ 2333a1173273SAlexandr Nedvedicky /* Please read comment at fr_make_icmp() wrapper function to get an idea */ 2334a1173273SAlexandr Nedvedicky /* what is going to happen here and why. Once you read the comment there, */ 2335a1173273SAlexandr Nedvedicky /* continue here with next paragraph. */ 2336a1173273SAlexandr Nedvedicky /* */ 2337a1173273SAlexandr Nedvedicky /* To turn IPv4 packet into ICMPv4 response packet, these things must */ 2338a1173273SAlexandr Nedvedicky /* happen here: */ 2339a1173273SAlexandr Nedvedicky /* (1) Original mblk is copied (duplicated). */ 2340a1173273SAlexandr Nedvedicky /* */ 2341a1173273SAlexandr Nedvedicky /* (2) ICMP header is created. */ 2342a1173273SAlexandr Nedvedicky /* */ 2343a1173273SAlexandr Nedvedicky /* (3) Link ICMP header with copy of original mblk, we have ICMPv4 */ 2344a1173273SAlexandr Nedvedicky /* data ready then. */ 2345a1173273SAlexandr Nedvedicky /* */ 2346a1173273SAlexandr Nedvedicky /* (4) Swap IP addresses in original mblk and adjust IP header data. */ 2347a1173273SAlexandr Nedvedicky /* */ 2348a1173273SAlexandr Nedvedicky /* (5) The mblk containing original packet is trimmed to contain IP */ 2349a1173273SAlexandr Nedvedicky /* header only and ICMP chksum is computed. */ 2350a1173273SAlexandr Nedvedicky /* */ 2351a1173273SAlexandr Nedvedicky /* (6) The ICMP header we have from (3) is linked to original mblk, */ 2352a1173273SAlexandr Nedvedicky /* which now contains new IP header. If original packet was spread */ 2353a1173273SAlexandr Nedvedicky /* over several mblks, only the first mblk is kept. */ 2354a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2355a1173273SAlexandr Nedvedicky static int fr_make_icmp_v4(fin) 2356a1173273SAlexandr Nedvedicky fr_info_t *fin; 2357a1173273SAlexandr Nedvedicky { 2358a1173273SAlexandr Nedvedicky struct in_addr tmp_src; 23596ccacea7SAlexandr Nedvedicky tcphdr_t *tcp; 2360a1173273SAlexandr Nedvedicky struct icmp *icmp; 2361a1173273SAlexandr Nedvedicky mblk_t *mblk_icmp; 2362a1173273SAlexandr Nedvedicky mblk_t *mblk_ip; 2363a1173273SAlexandr Nedvedicky size_t icmp_pld_len; /* octets to append to ICMP header */ 2364a1173273SAlexandr Nedvedicky size_t orig_iphdr_len; /* length of IP header only */ 2365a1173273SAlexandr Nedvedicky uint32_t sum; 2366a1173273SAlexandr Nedvedicky uint16_t *buf; 2367a1173273SAlexandr Nedvedicky int len; 2368a1173273SAlexandr Nedvedicky 2369a1173273SAlexandr Nedvedicky 2370a1173273SAlexandr Nedvedicky if (fin->fin_v != 4) 2371a1173273SAlexandr Nedvedicky return (-1); 2372a1173273SAlexandr Nedvedicky 2373a1173273SAlexandr Nedvedicky /* 2374a1173273SAlexandr Nedvedicky * If we are dealing with TCP, then packet must be SYN/FIN to be routed 2375a1173273SAlexandr Nedvedicky * by IP stack. If it is not SYN/FIN, then we must drop it silently. 2376a1173273SAlexandr Nedvedicky */ 23776ccacea7SAlexandr Nedvedicky tcp = (tcphdr_t *) fin->fin_dp; 23786ccacea7SAlexandr Nedvedicky 2379a1173273SAlexandr Nedvedicky if ((fin->fin_p == IPPROTO_TCP) && 23806ccacea7SAlexandr Nedvedicky ((tcp == NULL) || ((tcp->th_flags & (TH_SYN | TH_FIN)) == 0))) 2381a1173273SAlexandr Nedvedicky return (-1); 2382a1173273SAlexandr Nedvedicky 2383a1173273SAlexandr Nedvedicky /* 2384a1173273SAlexandr Nedvedicky * Step (1) 2385a1173273SAlexandr Nedvedicky * 2386a1173273SAlexandr Nedvedicky * Make copy of original mblk. 2387a1173273SAlexandr Nedvedicky * 2388a1173273SAlexandr Nedvedicky * We want to copy as much data as necessary, not less, not more. The 2389a1173273SAlexandr Nedvedicky * ICMPv4 payload length for unreachable messages is: 2390a1173273SAlexandr Nedvedicky * original IP header + 8 bytes of L4 (if there are any). 2391a1173273SAlexandr Nedvedicky * 2392a1173273SAlexandr Nedvedicky * We determine if there are at least 8 bytes of L4 data following IP 2393a1173273SAlexandr Nedvedicky * header first. 2394a1173273SAlexandr Nedvedicky */ 2395a1173273SAlexandr Nedvedicky icmp_pld_len = (fin->fin_dlen > ICMPERR_ICMPHLEN) ? 2396a1173273SAlexandr Nedvedicky ICMPERR_ICMPHLEN : fin->fin_dlen; 2397a1173273SAlexandr Nedvedicky /* 2398a1173273SAlexandr Nedvedicky * Since we don't want to copy more data than necessary, we must trim 2399a1173273SAlexandr Nedvedicky * the original mblk here. The right way (STREAMish) would be to use 2400a1173273SAlexandr Nedvedicky * adjmsg() to trim it. However we would have to calculate the length 2401a1173273SAlexandr Nedvedicky * argument for adjmsg() from pointers we already have here. 2402a1173273SAlexandr Nedvedicky * 2403a1173273SAlexandr Nedvedicky * Since we have pointers and offsets, it's faster and easier for 2404a1173273SAlexandr Nedvedicky * us to just adjust pointers by hand instead of using adjmsg(). 2405a1173273SAlexandr Nedvedicky */ 2406a1173273SAlexandr Nedvedicky fin->fin_m->b_wptr = (unsigned char *) fin->fin_dp; 2407a1173273SAlexandr Nedvedicky fin->fin_m->b_wptr += icmp_pld_len; 2408a1173273SAlexandr Nedvedicky icmp_pld_len = fin->fin_m->b_wptr - (unsigned char *) fin->fin_ip; 2409a1173273SAlexandr Nedvedicky 2410a1173273SAlexandr Nedvedicky /* 2411a1173273SAlexandr Nedvedicky * Also we don't want to copy any L2 stuff, which might precede IP 2412a1173273SAlexandr Nedvedicky * header, so we have have to set b_rptr to point to the start of IP 2413a1173273SAlexandr Nedvedicky * header. 2414a1173273SAlexandr Nedvedicky */ 2415a1173273SAlexandr Nedvedicky fin->fin_m->b_rptr += fin->fin_ipoff; 2416a1173273SAlexandr Nedvedicky if ((mblk_ip = copyb(fin->fin_m)) == NULL) 2417a1173273SAlexandr Nedvedicky return (-1); 2418a1173273SAlexandr Nedvedicky fin->fin_m->b_rptr -= fin->fin_ipoff; 2419a1173273SAlexandr Nedvedicky 2420a1173273SAlexandr Nedvedicky /* 2421a1173273SAlexandr Nedvedicky * Step (2) 2422a1173273SAlexandr Nedvedicky * 2423a1173273SAlexandr Nedvedicky * Create an ICMP header, which will be appened to original mblk later. 2424a1173273SAlexandr Nedvedicky * ICMP header is just another mblk. 2425a1173273SAlexandr Nedvedicky */ 2426a1173273SAlexandr Nedvedicky mblk_icmp = (mblk_t *) allocb(ICMPERR_ICMPHLEN, BPRI_HI); 2427a1173273SAlexandr Nedvedicky if (mblk_icmp == NULL) { 2428a1173273SAlexandr Nedvedicky FREE_MB_T(mblk_ip); 2429a1173273SAlexandr Nedvedicky return (-1); 2430a1173273SAlexandr Nedvedicky } 2431a1173273SAlexandr Nedvedicky 2432a1173273SAlexandr Nedvedicky MTYPE(mblk_icmp) = M_DATA; 2433a1173273SAlexandr Nedvedicky icmp = (struct icmp *) mblk_icmp->b_wptr; 2434a1173273SAlexandr Nedvedicky icmp->icmp_type = ICMP_UNREACH; 2435a1173273SAlexandr Nedvedicky icmp->icmp_code = fin->fin_icode & 0xFF; 2436a1173273SAlexandr Nedvedicky icmp->icmp_void = 0; 2437a1173273SAlexandr Nedvedicky icmp->icmp_cksum = 0; 2438a1173273SAlexandr Nedvedicky mblk_icmp->b_wptr += ICMPERR_ICMPHLEN; 2439a1173273SAlexandr Nedvedicky 2440a1173273SAlexandr Nedvedicky /* 2441a1173273SAlexandr Nedvedicky * Step (3) 2442a1173273SAlexandr Nedvedicky * 2443a1173273SAlexandr Nedvedicky * Complete ICMP packet - link ICMP header with L4 data from original 2444a1173273SAlexandr Nedvedicky * IP packet. 2445a1173273SAlexandr Nedvedicky */ 2446a1173273SAlexandr Nedvedicky linkb(mblk_icmp, mblk_ip); 2447a1173273SAlexandr Nedvedicky 2448a1173273SAlexandr Nedvedicky /* 2449a1173273SAlexandr Nedvedicky * Step (4) 2450a1173273SAlexandr Nedvedicky * 2451a1173273SAlexandr Nedvedicky * Swap IP addresses and change IP header fields accordingly in 2452a1173273SAlexandr Nedvedicky * original IP packet. 2453a1173273SAlexandr Nedvedicky * 2454a1173273SAlexandr Nedvedicky * There is a rule option return-icmp as a dest for physical 2455a1173273SAlexandr Nedvedicky * interfaces. This option becomes useless for loopback, since IPF box 2456a1173273SAlexandr Nedvedicky * uses same address as a loopback destination. We ignore the option 2457a1173273SAlexandr Nedvedicky * here, the ICMP packet will always look like as it would have been 2458a1173273SAlexandr Nedvedicky * sent from the original destination host. 2459a1173273SAlexandr Nedvedicky */ 2460a1173273SAlexandr Nedvedicky tmp_src = fin->fin_ip->ip_src; 2461a1173273SAlexandr Nedvedicky fin->fin_ip->ip_src = fin->fin_ip->ip_dst; 2462a1173273SAlexandr Nedvedicky fin->fin_ip->ip_dst = tmp_src; 2463a1173273SAlexandr Nedvedicky fin->fin_ip->ip_p = IPPROTO_ICMP; 2464a1173273SAlexandr Nedvedicky fin->fin_ip->ip_sum = 0; 2465a1173273SAlexandr Nedvedicky 2466a1173273SAlexandr Nedvedicky /* 2467a1173273SAlexandr Nedvedicky * Step (5) 2468a1173273SAlexandr Nedvedicky * 2469a1173273SAlexandr Nedvedicky * We trim the orignal mblk to hold IP header only. 2470a1173273SAlexandr Nedvedicky */ 2471a1173273SAlexandr Nedvedicky fin->fin_m->b_wptr = fin->fin_dp; 2472a1173273SAlexandr Nedvedicky orig_iphdr_len = fin->fin_m->b_wptr - 2473a1173273SAlexandr Nedvedicky (fin->fin_m->b_rptr + fin->fin_ipoff); 2474a1173273SAlexandr Nedvedicky fin->fin_ip->ip_len = htons(icmp_pld_len + ICMPERR_ICMPHLEN + 2475a1173273SAlexandr Nedvedicky orig_iphdr_len); 2476a1173273SAlexandr Nedvedicky 2477a1173273SAlexandr Nedvedicky /* 2478a1173273SAlexandr Nedvedicky * ICMP chksum calculation. The data we are calculating chksum for are 2479a1173273SAlexandr Nedvedicky * spread over two mblks, therefore we have to use two for loops. 2480a1173273SAlexandr Nedvedicky * 2481a1173273SAlexandr Nedvedicky * First for loop computes chksum part for ICMP header. 2482a1173273SAlexandr Nedvedicky */ 2483a1173273SAlexandr Nedvedicky buf = (uint16_t *) icmp; 2484a1173273SAlexandr Nedvedicky len = ICMPERR_ICMPHLEN; 2485a1173273SAlexandr Nedvedicky for (sum = 0; len > 1; len -= 2) 2486a1173273SAlexandr Nedvedicky sum += *buf++; 2487a1173273SAlexandr Nedvedicky 2488a1173273SAlexandr Nedvedicky /* 2489a1173273SAlexandr Nedvedicky * Here we add chksum part for ICMP payload. 2490a1173273SAlexandr Nedvedicky */ 2491a1173273SAlexandr Nedvedicky len = icmp_pld_len; 2492a1173273SAlexandr Nedvedicky buf = (uint16_t *) mblk_ip->b_rptr; 2493a1173273SAlexandr Nedvedicky for (; len > 1; len -= 2) 2494a1173273SAlexandr Nedvedicky sum += *buf++; 2495a1173273SAlexandr Nedvedicky 2496a1173273SAlexandr Nedvedicky /* 2497a1173273SAlexandr Nedvedicky * Chksum is done. 2498a1173273SAlexandr Nedvedicky */ 2499a1173273SAlexandr Nedvedicky sum = (sum >> 16) + (sum & 0xffff); 2500a1173273SAlexandr Nedvedicky sum += (sum >> 16); 2501a1173273SAlexandr Nedvedicky icmp->icmp_cksum = ~sum; 2502a1173273SAlexandr Nedvedicky 2503a1173273SAlexandr Nedvedicky /* 2504a1173273SAlexandr Nedvedicky * Step (6) 2505a1173273SAlexandr Nedvedicky * 2506a1173273SAlexandr Nedvedicky * Release all packet mblks, except the first one. 2507a1173273SAlexandr Nedvedicky */ 2508a1173273SAlexandr Nedvedicky if (fin->fin_m->b_cont != NULL) { 2509a1173273SAlexandr Nedvedicky FREE_MB_T(fin->fin_m->b_cont); 2510a1173273SAlexandr Nedvedicky } 2511a1173273SAlexandr Nedvedicky 2512a1173273SAlexandr Nedvedicky /* 2513a1173273SAlexandr Nedvedicky * Append ICMP payload to first mblk, which already contains new IP 2514a1173273SAlexandr Nedvedicky * header. 2515a1173273SAlexandr Nedvedicky */ 2516a1173273SAlexandr Nedvedicky linkb(fin->fin_m, mblk_icmp); 2517a1173273SAlexandr Nedvedicky 2518a1173273SAlexandr Nedvedicky return (0); 2519a1173273SAlexandr Nedvedicky } 2520a1173273SAlexandr Nedvedicky 2521a1173273SAlexandr Nedvedicky #ifdef USE_INET6 2522a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2523a1173273SAlexandr Nedvedicky /* Function: fr_make_icmp_v6 */ 2524a1173273SAlexandr Nedvedicky /* Returns: int - 0 on success, -1 on failure */ 2525a1173273SAlexandr Nedvedicky /* Parameters: fin(I) - pointer to packet information */ 2526a1173273SAlexandr Nedvedicky /* */ 2527a1173273SAlexandr Nedvedicky /* Please read comment at fr_make_icmp() wrapper function to get an idea */ 2528a1173273SAlexandr Nedvedicky /* what and why is going to happen here. Once you read the comment there, */ 2529a1173273SAlexandr Nedvedicky /* continue here with next paragraph. */ 2530a1173273SAlexandr Nedvedicky /* */ 2531a1173273SAlexandr Nedvedicky /* This function turns IPv6 packet (UDP, TCP, ...) into ICMPv6 response. */ 2532a1173273SAlexandr Nedvedicky /* The algorithm is fairly simple: */ 2533a1173273SAlexandr Nedvedicky /* 1) We need to get copy of complete mblk. */ 2534a1173273SAlexandr Nedvedicky /* */ 2535a1173273SAlexandr Nedvedicky /* 2) New ICMPv6 header is created. */ 2536a1173273SAlexandr Nedvedicky /* */ 2537a1173273SAlexandr Nedvedicky /* 3) The copy of original mblk with packet is linked to ICMPv6 */ 2538a1173273SAlexandr Nedvedicky /* header. */ 2539a1173273SAlexandr Nedvedicky /* */ 2540a1173273SAlexandr Nedvedicky /* 4) The checksum must be adjusted. */ 2541a1173273SAlexandr Nedvedicky /* */ 2542a1173273SAlexandr Nedvedicky /* 5) IP addresses in original mblk are swapped and IP header data */ 2543a1173273SAlexandr Nedvedicky /* are adjusted (protocol number). */ 2544a1173273SAlexandr Nedvedicky /* */ 2545a1173273SAlexandr Nedvedicky /* 6) Original mblk is trimmed to hold IPv6 header only, then it is */ 2546a1173273SAlexandr Nedvedicky /* linked with the ICMPv6 data we got from (3). */ 2547a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2548a1173273SAlexandr Nedvedicky static int fr_make_icmp_v6(fin) 2549a1173273SAlexandr Nedvedicky fr_info_t *fin; 2550a1173273SAlexandr Nedvedicky { 2551a1173273SAlexandr Nedvedicky struct icmp6_hdr *icmp6; 25526ccacea7SAlexandr Nedvedicky tcphdr_t *tcp; 2553a1173273SAlexandr Nedvedicky struct in6_addr tmp_src6; 2554a1173273SAlexandr Nedvedicky size_t icmp_pld_len; 2555a1173273SAlexandr Nedvedicky mblk_t *mblk_ip, *mblk_icmp; 2556a1173273SAlexandr Nedvedicky 2557a1173273SAlexandr Nedvedicky if (fin->fin_v != 6) 2558a1173273SAlexandr Nedvedicky return (-1); 2559a1173273SAlexandr Nedvedicky 2560a1173273SAlexandr Nedvedicky /* 2561a1173273SAlexandr Nedvedicky * If we are dealing with TCP, then packet must SYN/FIN to be routed by 2562a1173273SAlexandr Nedvedicky * IP stack. If it is not SYN/FIN, then we must drop it silently. 2563a1173273SAlexandr Nedvedicky */ 25646ccacea7SAlexandr Nedvedicky tcp = (tcphdr_t *) fin->fin_dp; 25656ccacea7SAlexandr Nedvedicky 25666ccacea7SAlexandr Nedvedicky if ((fin->fin_p == IPPROTO_TCP) && 25676ccacea7SAlexandr Nedvedicky ((tcp == NULL) || ((tcp->th_flags & (TH_SYN | TH_FIN)) == 0))) 2568a1173273SAlexandr Nedvedicky return (-1); 2569a1173273SAlexandr Nedvedicky 2570a1173273SAlexandr Nedvedicky /* 2571a1173273SAlexandr Nedvedicky * Step (1) 2572a1173273SAlexandr Nedvedicky * 2573a1173273SAlexandr Nedvedicky * We need to copy complete packet in case of IPv6, no trimming is 2574a1173273SAlexandr Nedvedicky * needed (except the L2 headers). 2575a1173273SAlexandr Nedvedicky */ 2576a1173273SAlexandr Nedvedicky icmp_pld_len = M_LEN(fin->fin_m); 2577a1173273SAlexandr Nedvedicky fin->fin_m->b_rptr += fin->fin_ipoff; 2578a1173273SAlexandr Nedvedicky if ((mblk_ip = copyb(fin->fin_m)) == NULL) 2579a1173273SAlexandr Nedvedicky return (-1); 2580a1173273SAlexandr Nedvedicky fin->fin_m->b_rptr -= fin->fin_ipoff; 2581a1173273SAlexandr Nedvedicky 2582a1173273SAlexandr Nedvedicky /* 2583a1173273SAlexandr Nedvedicky * Step (2) 2584a1173273SAlexandr Nedvedicky * 2585a1173273SAlexandr Nedvedicky * Allocate and create ICMP header. 2586a1173273SAlexandr Nedvedicky */ 2587a1173273SAlexandr Nedvedicky mblk_icmp = (mblk_t *) allocb(sizeof (struct icmp6_hdr), 2588a1173273SAlexandr Nedvedicky BPRI_HI); 2589a1173273SAlexandr Nedvedicky 2590a1173273SAlexandr Nedvedicky if (mblk_icmp == NULL) 2591a1173273SAlexandr Nedvedicky return (-1); 2592a1173273SAlexandr Nedvedicky 2593a1173273SAlexandr Nedvedicky MTYPE(mblk_icmp) = M_DATA; 2594a1173273SAlexandr Nedvedicky icmp6 = (struct icmp6_hdr *) mblk_icmp->b_wptr; 2595a1173273SAlexandr Nedvedicky icmp6->icmp6_type = ICMP6_DST_UNREACH; 2596a1173273SAlexandr Nedvedicky icmp6->icmp6_code = fin->fin_icode & 0xFF; 2597a1173273SAlexandr Nedvedicky icmp6->icmp6_data32[0] = 0; 2598a1173273SAlexandr Nedvedicky mblk_icmp->b_wptr += sizeof (struct icmp6_hdr); 2599a1173273SAlexandr Nedvedicky 2600a1173273SAlexandr Nedvedicky /* 2601a1173273SAlexandr Nedvedicky * Step (3) 2602a1173273SAlexandr Nedvedicky * 2603a1173273SAlexandr Nedvedicky * Link the copy of IP packet to ICMP header. 2604a1173273SAlexandr Nedvedicky */ 2605a1173273SAlexandr Nedvedicky linkb(mblk_icmp, mblk_ip); 2606a1173273SAlexandr Nedvedicky 2607a1173273SAlexandr Nedvedicky /* 2608a1173273SAlexandr Nedvedicky * Step (4) 2609a1173273SAlexandr Nedvedicky * 2610a1173273SAlexandr Nedvedicky * Calculate chksum - this is much more easier task than in case of 2611a1173273SAlexandr Nedvedicky * IPv4 - ICMPv6 chksum only covers IP addresses, and payload length. 2612a1173273SAlexandr Nedvedicky * We are making compensation just for change of packet length. 2613a1173273SAlexandr Nedvedicky */ 2614a1173273SAlexandr Nedvedicky icmp6->icmp6_cksum = icmp_pld_len + sizeof (struct icmp6_hdr); 2615a1173273SAlexandr Nedvedicky 2616a1173273SAlexandr Nedvedicky /* 2617a1173273SAlexandr Nedvedicky * Step (5) 2618a1173273SAlexandr Nedvedicky * 2619a1173273SAlexandr Nedvedicky * Swap IP addresses. 2620a1173273SAlexandr Nedvedicky */ 2621a1173273SAlexandr Nedvedicky tmp_src6 = fin->fin_ip6->ip6_src; 2622a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_src = fin->fin_ip6->ip6_dst; 2623a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_dst = tmp_src6; 2624a1173273SAlexandr Nedvedicky 2625a1173273SAlexandr Nedvedicky /* 2626a1173273SAlexandr Nedvedicky * and adjust IP header data. 2627a1173273SAlexandr Nedvedicky */ 2628a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_nxt = IPPROTO_ICMPV6; 2629a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_plen = htons(icmp_pld_len + sizeof (struct icmp6_hdr)); 2630a1173273SAlexandr Nedvedicky 2631a1173273SAlexandr Nedvedicky /* 2632a1173273SAlexandr Nedvedicky * Step (6) 2633a1173273SAlexandr Nedvedicky * 2634a1173273SAlexandr Nedvedicky * We must release all linked mblks from original packet and keep only 2635a1173273SAlexandr Nedvedicky * the first mblk with IP header to link ICMP data. 2636a1173273SAlexandr Nedvedicky */ 2637a1173273SAlexandr Nedvedicky fin->fin_m->b_wptr = (unsigned char *) fin->fin_ip6 + sizeof (ip6_t); 2638a1173273SAlexandr Nedvedicky 2639a1173273SAlexandr Nedvedicky if (fin->fin_m->b_cont != NULL) { 2640a1173273SAlexandr Nedvedicky FREE_MB_T(fin->fin_m->b_cont); 2641a1173273SAlexandr Nedvedicky } 2642a1173273SAlexandr Nedvedicky 2643a1173273SAlexandr Nedvedicky /* 2644a1173273SAlexandr Nedvedicky * Append ICMP payload to IP header. 2645a1173273SAlexandr Nedvedicky */ 2646a1173273SAlexandr Nedvedicky linkb(fin->fin_m, mblk_icmp); 2647a1173273SAlexandr Nedvedicky 2648a1173273SAlexandr Nedvedicky return (0); 2649a1173273SAlexandr Nedvedicky } 2650a1173273SAlexandr Nedvedicky #endif /* USE_INET6 */ 2651a1173273SAlexandr Nedvedicky 2652a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2653a1173273SAlexandr Nedvedicky /* Function: fr_make_icmp */ 2654a1173273SAlexandr Nedvedicky /* Returns: int - 0 on success, -1 on failure */ 2655a1173273SAlexandr Nedvedicky /* Parameters: fin(I) - pointer to packet information */ 2656a1173273SAlexandr Nedvedicky /* */ 2657a1173273SAlexandr Nedvedicky /* We must alter the original mblks passed to IPF from IP stack via */ 2658a1173273SAlexandr Nedvedicky /* FW_HOOKS. The reasons why we must alter packet are discussed within */ 2659a1173273SAlexandr Nedvedicky /* comment at fr_make_rst() function. */ 2660a1173273SAlexandr Nedvedicky /* */ 2661a1173273SAlexandr Nedvedicky /* The fr_make_icmp() function acts as a wrapper, which passes the code */ 2662a1173273SAlexandr Nedvedicky /* execution to fr_make_icmp_v4() or fr_make_icmp_v6() depending on */ 2663a1173273SAlexandr Nedvedicky /* protocol version. However there are some details, which are common to */ 2664a1173273SAlexandr Nedvedicky /* both IP versions. The details are going to be explained here. */ 2665a1173273SAlexandr Nedvedicky /* */ 2666a1173273SAlexandr Nedvedicky /* The packet looks as follows: */ 2667a1173273SAlexandr Nedvedicky /* xxx | IP hdr | IP payload ... | */ 2668a1173273SAlexandr Nedvedicky /* ^ ^ ^ ^ */ 2669a1173273SAlexandr Nedvedicky /* | | | | */ 2670a1173273SAlexandr Nedvedicky /* | | | fin_m->b_wptr = fin->fin_dp + fin->fin_dlen */ 2671a1173273SAlexandr Nedvedicky /* | | | */ 2672a1173273SAlexandr Nedvedicky /* | | `- fin_m->fin_dp (in case of IPv4 points to L4 header) */ 2673a1173273SAlexandr Nedvedicky /* | | */ 2674a1173273SAlexandr Nedvedicky /* | `- fin_m->b_rptr + fin_ipoff (fin_ipoff is most likely 0 in case */ 2675a1173273SAlexandr Nedvedicky /* | of loopback) */ 2676a1173273SAlexandr Nedvedicky /* | */ 2677a1173273SAlexandr Nedvedicky /* `- fin_m->b_rptr - points to L2 header in case of physical NIC */ 2678a1173273SAlexandr Nedvedicky /* */ 2679a1173273SAlexandr Nedvedicky /* All relevant IP headers are pulled up into the first mblk. It happened */ 2680a1173273SAlexandr Nedvedicky /* well in advance before the matching rule was found (the rule, which took */ 2681a1173273SAlexandr Nedvedicky /* us here, to fr_make_icmp() function). */ 2682a1173273SAlexandr Nedvedicky /* */ 2683a1173273SAlexandr Nedvedicky /* Both functions will turn packet passed in fin->fin_m mblk into a new */ 2684a1173273SAlexandr Nedvedicky /* packet. New packet will be represented as chain of mblks. */ 2685a1173273SAlexandr Nedvedicky /* orig mblk |- b_cont ---. */ 2686a1173273SAlexandr Nedvedicky /* ^ `-> ICMP hdr |- b_cont--. */ 2687a1173273SAlexandr Nedvedicky /* | ^ `-> duped orig mblk */ 2688a1173273SAlexandr Nedvedicky /* | | ^ */ 2689a1173273SAlexandr Nedvedicky /* `- The original mblk | | */ 2690a1173273SAlexandr Nedvedicky /* will be trimmed to | | */ 2691a1173273SAlexandr Nedvedicky /* to contain IP header | | */ 2692a1173273SAlexandr Nedvedicky /* only | | */ 2693a1173273SAlexandr Nedvedicky /* | | */ 2694a1173273SAlexandr Nedvedicky /* `- This is newly | */ 2695a1173273SAlexandr Nedvedicky /* allocated mblk to | */ 2696a1173273SAlexandr Nedvedicky /* hold ICMPv6 data. | */ 2697a1173273SAlexandr Nedvedicky /* | */ 2698a1173273SAlexandr Nedvedicky /* | */ 2699a1173273SAlexandr Nedvedicky /* | */ 2700a1173273SAlexandr Nedvedicky /* This is the copy of original mblk, it will contain -' */ 2701a1173273SAlexandr Nedvedicky /* orignal IP packet in case of ICMPv6. In case of */ 2702a1173273SAlexandr Nedvedicky /* ICMPv4 it will contain up to 8 bytes of IP payload */ 2703a1173273SAlexandr Nedvedicky /* (TCP/UDP/L4) data from original packet. */ 2704a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2705a1173273SAlexandr Nedvedicky int fr_make_icmp(fin) 2706a1173273SAlexandr Nedvedicky fr_info_t *fin; 2707a1173273SAlexandr Nedvedicky { 2708a1173273SAlexandr Nedvedicky int rv; 2709a1173273SAlexandr Nedvedicky 2710a1173273SAlexandr Nedvedicky if (fin->fin_v == 4) 2711a1173273SAlexandr Nedvedicky rv = fr_make_icmp_v4(fin); 2712a1173273SAlexandr Nedvedicky #ifdef USE_INET6 2713a1173273SAlexandr Nedvedicky else if (fin->fin_v == 6) 2714a1173273SAlexandr Nedvedicky rv = fr_make_icmp_v6(fin); 2715a1173273SAlexandr Nedvedicky #endif 2716a1173273SAlexandr Nedvedicky else 2717a1173273SAlexandr Nedvedicky rv = -1; 2718a1173273SAlexandr Nedvedicky 2719a1173273SAlexandr Nedvedicky return (rv); 2720a1173273SAlexandr Nedvedicky } 2721a1173273SAlexandr Nedvedicky #endif /* _KERNEL && SOLARIS2 >= 10 */ 2722