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 * 6d0dd088cSAlexandr Nedvedicky * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 794bdecd9SRob Gulewich * 8*ec71f88eSPatrick Mooney * Copyright 2018 Joyent, Inc. 97c478bd9Sstevel@tonic-gate */ 107c478bd9Sstevel@tonic-gate 117c478bd9Sstevel@tonic-gate #if !defined(lint) 12c793af95Ssangeeta static const char sccsid[] = "@(#)ip_fil_solaris.c 1.7 07/22/06 (C) 1993-2000 Darren Reed"; 13ab25eeb5Syz static const char rcsid[] = "@(#)$Id: ip_fil_solaris.c,v 2.62.2.19 2005/07/13 21:40:46 darrenr Exp $"; 147c478bd9Sstevel@tonic-gate #endif 157c478bd9Sstevel@tonic-gate 167c478bd9Sstevel@tonic-gate #include <sys/types.h> 177c478bd9Sstevel@tonic-gate #include <sys/errno.h> 187c478bd9Sstevel@tonic-gate #include <sys/param.h> 197c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 207c478bd9Sstevel@tonic-gate #include <sys/open.h> 217c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 227c478bd9Sstevel@tonic-gate #include <sys/filio.h> 237c478bd9Sstevel@tonic-gate #include <sys/systm.h> 24ab25eeb5Syz #include <sys/strsubr.h> 257c478bd9Sstevel@tonic-gate #include <sys/cred.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> 30*ec71f88eSPatrick Mooney #include <sys/mac_provider.h> 317c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 327c478bd9Sstevel@tonic-gate #include <sys/protosw.h> 337c478bd9Sstevel@tonic-gate #include <sys/socket.h> 347c478bd9Sstevel@tonic-gate #include <sys/dditypes.h> 357c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 36f4b3ec61Sdh #include <sys/zone.h> 377c478bd9Sstevel@tonic-gate #include <net/if.h> 387c478bd9Sstevel@tonic-gate #include <net/af.h> 397c478bd9Sstevel@tonic-gate #include <net/route.h> 407c478bd9Sstevel@tonic-gate #include <netinet/in.h> 417c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h> 427c478bd9Sstevel@tonic-gate #include <netinet/ip.h> 437c478bd9Sstevel@tonic-gate #include <netinet/ip_var.h> 447c478bd9Sstevel@tonic-gate #include <netinet/tcp.h> 457c478bd9Sstevel@tonic-gate #include <netinet/udp.h> 467c478bd9Sstevel@tonic-gate #include <netinet/tcpip.h> 477c478bd9Sstevel@tonic-gate #include <netinet/ip_icmp.h> 48ab25eeb5Syz #include "netinet/ip_compat.h" 497c478bd9Sstevel@tonic-gate #ifdef USE_INET6 507c478bd9Sstevel@tonic-gate # include <netinet/icmp6.h> 517c478bd9Sstevel@tonic-gate #endif 52ab25eeb5Syz #include "netinet/ip_fil.h" 53ab25eeb5Syz #include "netinet/ip_nat.h" 54ab25eeb5Syz #include "netinet/ip_frag.h" 55ab25eeb5Syz #include "netinet/ip_state.h" 56ab25eeb5Syz #include "netinet/ip_auth.h" 57ab25eeb5Syz #include "netinet/ip_proxy.h" 58f4b3ec61Sdh #include "netinet/ipf_stack.h" 597c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOOKUP 60ab25eeb5Syz # include "netinet/ip_lookup.h" 617c478bd9Sstevel@tonic-gate #endif 627c478bd9Sstevel@tonic-gate #include <inet/ip_ire.h> 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate #include <sys/md5.h> 65381a2a9aSdr #include <sys/neti.h> 667c478bd9Sstevel@tonic-gate 67f4b3ec61Sdh static int frzerostats __P((caddr_t, ipf_stack_t *)); 68f4b3ec61Sdh static int fr_setipfloopback __P((int, ipf_stack_t *)); 697ddc9b1aSDarren Reed static int fr_enableipf __P((ipf_stack_t *, int)); 70ab25eeb5Syz static int fr_send_ip __P((fr_info_t *fin, mblk_t *m, mblk_t **mp)); 717ddc9b1aSDarren Reed static int ipf_nic_event_v4 __P((hook_event_token_t, hook_data_t, void *)); 727ddc9b1aSDarren Reed static int ipf_nic_event_v6 __P((hook_event_token_t, hook_data_t, void *)); 737ddc9b1aSDarren Reed static int ipf_hook __P((hook_data_t, int, int, void *)); 747ddc9b1aSDarren Reed static int ipf_hook4_in __P((hook_event_token_t, hook_data_t, void *)); 757ddc9b1aSDarren Reed static int ipf_hook4_out __P((hook_event_token_t, hook_data_t, void *)); 76cbded9aeSdr static int ipf_hook4_loop_out __P((hook_event_token_t, hook_data_t, 777ddc9b1aSDarren Reed void *)); 787ddc9b1aSDarren Reed static int ipf_hook4_loop_in __P((hook_event_token_t, hook_data_t, void *)); 797ddc9b1aSDarren Reed static int ipf_hook4 __P((hook_data_t, int, int, void *)); 807ddc9b1aSDarren Reed static int ipf_hook6_out __P((hook_event_token_t, hook_data_t, void *)); 817ddc9b1aSDarren Reed static int ipf_hook6_in __P((hook_event_token_t, hook_data_t, void *)); 82cbded9aeSdr static int ipf_hook6_loop_out __P((hook_event_token_t, hook_data_t, 837ddc9b1aSDarren Reed void *)); 84cbded9aeSdr static int ipf_hook6_loop_in __P((hook_event_token_t, hook_data_t, 857ddc9b1aSDarren Reed void *)); 867ddc9b1aSDarren Reed static int ipf_hook6 __P((hook_data_t, int, int, void *)); 87f4b3ec61Sdh extern int ipf_geniter __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *)); 88f4b3ec61Sdh extern int ipf_frruleiter __P((void *, int, void *, ipf_stack_t *)); 89f4b3ec61Sdh 907c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 917c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 7 92ab25eeb5Syz u_int *ip_ttl_ptr = NULL; 93ab25eeb5Syz u_int *ip_mtudisc = NULL; 947c478bd9Sstevel@tonic-gate # if SOLARIS2 >= 8 95ab25eeb5Syz int *ip_forwarding = NULL; 96ab25eeb5Syz u_int *ip6_forwarding = NULL; 977c478bd9Sstevel@tonic-gate # else 98ab25eeb5Syz u_int *ip_forwarding = NULL; 997c478bd9Sstevel@tonic-gate # endif 1007c478bd9Sstevel@tonic-gate #else 101ab25eeb5Syz u_long *ip_ttl_ptr = NULL; 102ab25eeb5Syz u_long *ip_mtudisc = NULL; 103ab25eeb5Syz u_long *ip_forwarding = NULL; 1047c478bd9Sstevel@tonic-gate #endif 1057c478bd9Sstevel@tonic-gate #endif 1067c478bd9Sstevel@tonic-gate 10794bdecd9SRob Gulewich vmem_t *ipf_minor; /* minor number arena */ 10894bdecd9SRob Gulewich void *ipf_state; /* DDI state */ 10994bdecd9SRob Gulewich 11094bdecd9SRob Gulewich /* 11194bdecd9SRob Gulewich * GZ-controlled and per-zone stacks: 11294bdecd9SRob Gulewich * 11394bdecd9SRob Gulewich * For each non-global zone, we create two ipf stacks: the per-zone stack and 11494bdecd9SRob Gulewich * the GZ-controlled stack. The per-zone stack can be controlled and observed 11594bdecd9SRob Gulewich * from inside the zone or from the global zone. The GZ-controlled stack can 11694bdecd9SRob Gulewich * only be controlled and observed from the global zone (though the rules 11794bdecd9SRob Gulewich * still only affect that non-global zone). 11894bdecd9SRob Gulewich * 11994bdecd9SRob Gulewich * The two hooks are always arranged so that the GZ-controlled stack is always 12094bdecd9SRob Gulewich * "outermost" with respect to the zone. The traffic flow then looks like 12194bdecd9SRob Gulewich * this: 12294bdecd9SRob Gulewich * 12394bdecd9SRob Gulewich * Inbound: 12494bdecd9SRob Gulewich * 12594bdecd9SRob Gulewich * nic ---> [ GZ-controlled rules ] ---> [ per-zone rules ] ---> zone 12694bdecd9SRob Gulewich * 12794bdecd9SRob Gulewich * Outbound: 12894bdecd9SRob Gulewich * 12994bdecd9SRob Gulewich * nic <--- [ GZ-controlled rules ] <--- [ per-zone rules ] <--- zone 13094bdecd9SRob Gulewich */ 13194bdecd9SRob Gulewich 13294bdecd9SRob Gulewich /* IPv4 hook names */ 13394bdecd9SRob Gulewich char *hook4_nicevents = "ipfilter_hook4_nicevents"; 13494bdecd9SRob Gulewich char *hook4_nicevents_gz = "ipfilter_hook4_nicevents_gz"; 13594bdecd9SRob Gulewich char *hook4_in = "ipfilter_hook4_in"; 13694bdecd9SRob Gulewich char *hook4_in_gz = "ipfilter_hook4_in_gz"; 13794bdecd9SRob Gulewich char *hook4_out = "ipfilter_hook4_out"; 13894bdecd9SRob Gulewich char *hook4_out_gz = "ipfilter_hook4_out_gz"; 13994bdecd9SRob Gulewich char *hook4_loop_in = "ipfilter_hook4_loop_in"; 14094bdecd9SRob Gulewich char *hook4_loop_in_gz = "ipfilter_hook4_loop_in_gz"; 14194bdecd9SRob Gulewich char *hook4_loop_out = "ipfilter_hook4_loop_out"; 14294bdecd9SRob Gulewich char *hook4_loop_out_gz = "ipfilter_hook4_loop_out_gz"; 14394bdecd9SRob Gulewich 14494bdecd9SRob Gulewich /* IPv6 hook names */ 14594bdecd9SRob Gulewich char *hook6_nicevents = "ipfilter_hook6_nicevents"; 14694bdecd9SRob Gulewich char *hook6_nicevents_gz = "ipfilter_hook6_nicevents_gz"; 14794bdecd9SRob Gulewich char *hook6_in = "ipfilter_hook6_in"; 14894bdecd9SRob Gulewich char *hook6_in_gz = "ipfilter_hook6_in_gz"; 14994bdecd9SRob Gulewich char *hook6_out = "ipfilter_hook6_out"; 15094bdecd9SRob Gulewich char *hook6_out_gz = "ipfilter_hook6_out_gz"; 15194bdecd9SRob Gulewich char *hook6_loop_in = "ipfilter_hook6_loop_in"; 15294bdecd9SRob Gulewich char *hook6_loop_in_gz = "ipfilter_hook6_loop_in_gz"; 15394bdecd9SRob Gulewich char *hook6_loop_out = "ipfilter_hook6_loop_out"; 15494bdecd9SRob Gulewich char *hook6_loop_out_gz = "ipfilter_hook6_loop_out_gz"; 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 1577c478bd9Sstevel@tonic-gate /* Function: ipldetach */ 1587c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, else error. */ 1597c478bd9Sstevel@tonic-gate /* Parameters: Nil */ 1607c478bd9Sstevel@tonic-gate /* */ 1617c478bd9Sstevel@tonic-gate /* This function is responsible for undoing anything that might have been */ 1627c478bd9Sstevel@tonic-gate /* done in a call to iplattach(). It must be able to clean up from a call */ 1637c478bd9Sstevel@tonic-gate /* to iplattach() that did not succeed. Why might that happen? Someone */ 1647c478bd9Sstevel@tonic-gate /* configures a table to be so large that we cannot allocate enough memory */ 1657c478bd9Sstevel@tonic-gate /* for it. */ 1667c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 167f4b3ec61Sdh int ipldetach(ifs) 168f4b3ec61Sdh ipf_stack_t *ifs; 1697c478bd9Sstevel@tonic-gate { 1707c478bd9Sstevel@tonic-gate 17194bdecd9SRob Gulewich ASSERT(RW_WRITE_HELD(&ifs->ifs_ipf_global.ipf_lk)); 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 1747c478bd9Sstevel@tonic-gate 175f4b3ec61Sdh if (ifs->ifs_fr_control_forwarding & 2) { 176ab25eeb5Syz if (ip_forwarding != NULL) 177ab25eeb5Syz *ip_forwarding = 0; 1787c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 179ab25eeb5Syz if (ip6_forwarding != NULL) 180ab25eeb5Syz *ip6_forwarding = 0; 1817c478bd9Sstevel@tonic-gate #endif 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate #endif 1847c478bd9Sstevel@tonic-gate 185381a2a9aSdr /* 1867ddc9b1aSDarren Reed * This lock needs to be dropped around the net_hook_unregister calls 187381a2a9aSdr * because we can deadlock here with: 188381a2a9aSdr * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs 189381a2a9aSdr * R(hook_family)->R(hei_lock)->R(ipf_global) (active hook running) 190381a2a9aSdr */ 191f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 192381a2a9aSdr 1937ddc9b1aSDarren Reed #define UNDO_HOOK(_f, _b, _e, _h) \ 1947ddc9b1aSDarren Reed do { \ 1957ddc9b1aSDarren Reed if (ifs->_f != NULL) { \ 1967ddc9b1aSDarren Reed if (ifs->_b) { \ 197c6798761SJerry Jelinek int tmp = net_hook_unregister(ifs->_f, \ 198c6798761SJerry Jelinek _e, ifs->_h); \ 199c6798761SJerry Jelinek ifs->_b = (tmp != 0 && tmp != ENXIO); \ 200c6798761SJerry Jelinek if (!ifs->_b && ifs->_h != NULL) { \ 2017ddc9b1aSDarren Reed hook_free(ifs->_h); \ 2027ddc9b1aSDarren Reed ifs->_h = NULL; \ 2037ddc9b1aSDarren Reed } \ 2047ddc9b1aSDarren Reed } else if (ifs->_h != NULL) { \ 2057ddc9b1aSDarren Reed hook_free(ifs->_h); \ 2067ddc9b1aSDarren Reed ifs->_h = NULL; \ 2077ddc9b1aSDarren Reed } \ 2087ddc9b1aSDarren Reed } \ 2097ddc9b1aSDarren Reed _NOTE(CONSTCOND) \ 2107ddc9b1aSDarren Reed } while (0) 2117ddc9b1aSDarren Reed 212381a2a9aSdr /* 213381a2a9aSdr * Remove IPv6 Hooks 214381a2a9aSdr */ 215f4b3ec61Sdh if (ifs->ifs_ipf_ipv6 != NULL) { 2167ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_in, 2177ddc9b1aSDarren Reed NH_PHYSICAL_IN, ifs_ipfhook6_in); 2187ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_out, 2197ddc9b1aSDarren Reed NH_PHYSICAL_OUT, ifs_ipfhook6_out); 2207ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_nic_events, 2217ddc9b1aSDarren Reed NH_NIC_EVENTS, ifs_ipfhook6_nicevents); 2227ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_in, 2237ddc9b1aSDarren Reed NH_LOOPBACK_IN, ifs_ipfhook6_loop_in); 2247ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_out, 2257ddc9b1aSDarren Reed NH_LOOPBACK_OUT, ifs_ipfhook6_loop_out); 2267ddc9b1aSDarren Reed 2277ddc9b1aSDarren Reed if (net_protocol_release(ifs->ifs_ipf_ipv6) != 0) 228381a2a9aSdr goto detach_failed; 229f4b3ec61Sdh ifs->ifs_ipf_ipv6 = NULL; 230381a2a9aSdr } 231381a2a9aSdr 232381a2a9aSdr /* 233381a2a9aSdr * Remove IPv4 Hooks 234381a2a9aSdr */ 235f4b3ec61Sdh if (ifs->ifs_ipf_ipv4 != NULL) { 2367ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_in, 2377ddc9b1aSDarren Reed NH_PHYSICAL_IN, ifs_ipfhook4_in); 2387ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_out, 2397ddc9b1aSDarren Reed NH_PHYSICAL_OUT, ifs_ipfhook4_out); 2407ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_nic_events, 2417ddc9b1aSDarren Reed NH_NIC_EVENTS, ifs_ipfhook4_nicevents); 2427ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_in, 2437ddc9b1aSDarren Reed NH_LOOPBACK_IN, ifs_ipfhook4_loop_in); 2447ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_out, 2457ddc9b1aSDarren Reed NH_LOOPBACK_OUT, ifs_ipfhook4_loop_out); 2467ddc9b1aSDarren Reed 2477ddc9b1aSDarren Reed if (net_protocol_release(ifs->ifs_ipf_ipv4) != 0) 248381a2a9aSdr goto detach_failed; 249f4b3ec61Sdh ifs->ifs_ipf_ipv4 = NULL; 250381a2a9aSdr } 251381a2a9aSdr 2527ddc9b1aSDarren Reed #undef UNDO_HOOK 2537ddc9b1aSDarren Reed 2547c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 2557c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "ipldetach()\n"); 2567c478bd9Sstevel@tonic-gate #endif 2577c478bd9Sstevel@tonic-gate 258f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 259f4b3ec61Sdh fr_deinitialise(ifs); 2607c478bd9Sstevel@tonic-gate 261f4b3ec61Sdh (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE, ifs); 262f4b3ec61Sdh (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE, ifs); 2637c478bd9Sstevel@tonic-gate 264f4b3ec61Sdh if (ifs->ifs_ipf_locks_done == 1) { 265f4b3ec61Sdh MUTEX_DESTROY(&ifs->ifs_ipf_timeoutlock); 266f4b3ec61Sdh MUTEX_DESTROY(&ifs->ifs_ipf_rw); 267f4b3ec61Sdh RW_DESTROY(&ifs->ifs_ipf_tokens); 268f4b3ec61Sdh RW_DESTROY(&ifs->ifs_ipf_ipidfrag); 269f4b3ec61Sdh ifs->ifs_ipf_locks_done = 0; 2707c478bd9Sstevel@tonic-gate } 271381a2a9aSdr 2727ddc9b1aSDarren Reed if (ifs->ifs_hook4_physical_in || ifs->ifs_hook4_physical_out || 2737ddc9b1aSDarren Reed ifs->ifs_hook4_nic_events || ifs->ifs_hook4_loopback_in || 2747ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_out || ifs->ifs_hook6_nic_events || 2757ddc9b1aSDarren Reed ifs->ifs_hook6_physical_in || ifs->ifs_hook6_physical_out || 2767ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_in || ifs->ifs_hook6_loopback_out) 277381a2a9aSdr return -1; 278381a2a9aSdr 2797c478bd9Sstevel@tonic-gate return 0; 280381a2a9aSdr 281381a2a9aSdr detach_failed: 282f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 283381a2a9aSdr return -1; 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate 2867ddc9b1aSDarren Reed int iplattach(ifs) 287f4b3ec61Sdh ipf_stack_t *ifs; 2887c478bd9Sstevel@tonic-gate { 2897c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 2907c478bd9Sstevel@tonic-gate int i; 2917c478bd9Sstevel@tonic-gate #endif 2927ddc9b1aSDarren Reed netid_t id = ifs->ifs_netid; 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 2957c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplattach()\n"); 2967c478bd9Sstevel@tonic-gate #endif 2977c478bd9Sstevel@tonic-gate 29894bdecd9SRob Gulewich ASSERT(RW_WRITE_HELD(&ifs->ifs_ipf_global.ipf_lk)); 299f4b3ec61Sdh ifs->ifs_fr_flags = IPF_LOGGING; 300f4b3ec61Sdh #ifdef _KERNEL 301f4b3ec61Sdh ifs->ifs_fr_update_ipid = 0; 302f4b3ec61Sdh #else 303f4b3ec61Sdh ifs->ifs_fr_update_ipid = 1; 304f4b3ec61Sdh #endif 305f4b3ec61Sdh ifs->ifs_fr_minttl = 4; 306f4b3ec61Sdh ifs->ifs_fr_icmpminfragmtu = 68; 307f4b3ec61Sdh #if defined(IPFILTER_DEFAULT_BLOCK) 308f4b3ec61Sdh ifs->ifs_fr_pass = FR_BLOCK|FR_NOMATCH; 309f4b3ec61Sdh #else 310f4b3ec61Sdh ifs->ifs_fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH; 311f4b3ec61Sdh #endif 3127c478bd9Sstevel@tonic-gate 31314d3298eSAlexandr Nedvedicky bzero((char *)ifs->ifs_frcache, sizeof(ifs->ifs_frcache)); 314f4b3ec61Sdh MUTEX_INIT(&ifs->ifs_ipf_rw, "ipf rw mutex"); 315f4b3ec61Sdh MUTEX_INIT(&ifs->ifs_ipf_timeoutlock, "ipf timeout lock mutex"); 316f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); 317f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_tokens, "ipf token rwlock"); 318f4b3ec61Sdh ifs->ifs_ipf_locks_done = 1; 3197c478bd9Sstevel@tonic-gate 320f4b3ec61Sdh if (fr_initialise(ifs) < 0) 3217c478bd9Sstevel@tonic-gate return -1; 3227c478bd9Sstevel@tonic-gate 32394bdecd9SRob Gulewich /* 32494bdecd9SRob Gulewich * For incoming packets, we want the GZ-controlled hooks to run before 32594bdecd9SRob Gulewich * the per-zone hooks, regardless of what order they're are installed. 32694bdecd9SRob Gulewich * See the "GZ-controlled and per-zone stacks" comment block at the top 32794bdecd9SRob Gulewich * of this file. 32894bdecd9SRob Gulewich */ 32994bdecd9SRob Gulewich #define HOOK_INIT_GZ_BEFORE(x, fn, n, gzn, a) \ 33094bdecd9SRob Gulewich HOOK_INIT(x, fn, ifs->ifs_gz_controlled ? gzn : n, ifs); \ 33194bdecd9SRob Gulewich (x)->h_hint = ifs->ifs_gz_controlled ? HH_BEFORE : HH_AFTER; \ 33294bdecd9SRob Gulewich (x)->h_hintvalue = (uintptr_t) (ifs->ifs_gz_controlled ? n : gzn); 33394bdecd9SRob Gulewich 33494bdecd9SRob Gulewich HOOK_INIT_GZ_BEFORE(ifs->ifs_ipfhook4_nicevents, ipf_nic_event_v4, 33594bdecd9SRob Gulewich hook4_nicevents, hook4_nicevents_gz, ifs); 33694bdecd9SRob Gulewich HOOK_INIT_GZ_BEFORE(ifs->ifs_ipfhook4_in, ipf_hook4_in, 33794bdecd9SRob Gulewich hook4_in, hook4_in_gz, ifs); 33894bdecd9SRob Gulewich HOOK_INIT_GZ_BEFORE(ifs->ifs_ipfhook4_loop_in, ipf_hook4_loop_in, 33994bdecd9SRob Gulewich hook4_loop_in, hook4_loop_in_gz, ifs); 34094bdecd9SRob Gulewich 34194bdecd9SRob Gulewich /* 34294bdecd9SRob Gulewich * For outgoing packets, we want the GZ-controlled hooks to run after 34394bdecd9SRob Gulewich * the per-zone hooks, regardless of what order they're are installed. 34494bdecd9SRob Gulewich * See the "GZ-controlled and per-zone stacks" comment block at the top 34594bdecd9SRob Gulewich * of this file. 34694bdecd9SRob Gulewich */ 34794bdecd9SRob Gulewich #define HOOK_INIT_GZ_AFTER(x, fn, n, gzn, a) \ 34894bdecd9SRob Gulewich HOOK_INIT(x, fn, ifs->ifs_gz_controlled ? gzn : n, ifs); \ 34994bdecd9SRob Gulewich (x)->h_hint = ifs->ifs_gz_controlled ? HH_AFTER : HH_BEFORE; \ 35094bdecd9SRob Gulewich (x)->h_hintvalue = (uintptr_t) (ifs->ifs_gz_controlled ? n : gzn); 35194bdecd9SRob Gulewich 35294bdecd9SRob Gulewich HOOK_INIT_GZ_AFTER(ifs->ifs_ipfhook4_out, ipf_hook4_out, 35394bdecd9SRob Gulewich hook4_out, hook4_out_gz, ifs); 35494bdecd9SRob Gulewich HOOK_INIT_GZ_AFTER(ifs->ifs_ipfhook4_loop_out, ipf_hook4_loop_out, 35594bdecd9SRob Gulewich hook4_loop_out, hook4_loop_out_gz, ifs); 356381a2a9aSdr 357381a2a9aSdr /* 3587ddc9b1aSDarren Reed * If we hold this lock over all of the net_hook_register calls, we 359381a2a9aSdr * can cause a deadlock to occur with the following lock ordering: 360381a2a9aSdr * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs 361381a2a9aSdr * R(hook_family)->R(hei_lock)->R(ipf_global) (packet path) 362381a2a9aSdr */ 363f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 364381a2a9aSdr 365381a2a9aSdr /* 366381a2a9aSdr * Add IPv4 hooks 367381a2a9aSdr */ 3687ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4 = net_protocol_lookup(id, NHF_INET); 369f4b3ec61Sdh if (ifs->ifs_ipf_ipv4 == NULL) 370381a2a9aSdr goto hookup_failed; 371381a2a9aSdr 3727ddc9b1aSDarren Reed ifs->ifs_hook4_nic_events = (net_hook_register(ifs->ifs_ipf_ipv4, 3737ddc9b1aSDarren Reed NH_NIC_EVENTS, ifs->ifs_ipfhook4_nicevents) == 0); 374f4b3ec61Sdh if (!ifs->ifs_hook4_nic_events) 375381a2a9aSdr goto hookup_failed; 376381a2a9aSdr 3777ddc9b1aSDarren Reed ifs->ifs_hook4_physical_in = (net_hook_register(ifs->ifs_ipf_ipv4, 3787ddc9b1aSDarren Reed NH_PHYSICAL_IN, ifs->ifs_ipfhook4_in) == 0); 379f4b3ec61Sdh if (!ifs->ifs_hook4_physical_in) 380381a2a9aSdr goto hookup_failed; 381381a2a9aSdr 3827ddc9b1aSDarren Reed ifs->ifs_hook4_physical_out = (net_hook_register(ifs->ifs_ipf_ipv4, 3837ddc9b1aSDarren Reed NH_PHYSICAL_OUT, ifs->ifs_ipfhook4_out) == 0); 384f4b3ec61Sdh if (!ifs->ifs_hook4_physical_out) 385381a2a9aSdr goto hookup_failed; 386381a2a9aSdr 387f4b3ec61Sdh if (ifs->ifs_ipf_loopback) { 3887ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_in = (net_hook_register( 3897ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN, 3907ddc9b1aSDarren Reed ifs->ifs_ipfhook4_loop_in) == 0); 391f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_in) 392381a2a9aSdr goto hookup_failed; 393381a2a9aSdr 3947ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_out = (net_hook_register( 3957ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT, 3967ddc9b1aSDarren Reed ifs->ifs_ipfhook4_loop_out) == 0); 397f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_out) 398381a2a9aSdr goto hookup_failed; 399381a2a9aSdr } 40094bdecd9SRob Gulewich 401381a2a9aSdr /* 402381a2a9aSdr * Add IPv6 hooks 403381a2a9aSdr */ 4047ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6 = net_protocol_lookup(id, NHF_INET6); 405f4b3ec61Sdh if (ifs->ifs_ipf_ipv6 == NULL) 406381a2a9aSdr goto hookup_failed; 407381a2a9aSdr 40894bdecd9SRob Gulewich HOOK_INIT_GZ_BEFORE(ifs->ifs_ipfhook6_nicevents, ipf_nic_event_v6, 40994bdecd9SRob Gulewich hook6_nicevents, hook6_nicevents_gz, ifs); 41094bdecd9SRob Gulewich HOOK_INIT_GZ_BEFORE(ifs->ifs_ipfhook6_in, ipf_hook6_in, 41194bdecd9SRob Gulewich hook6_in, hook6_in_gz, ifs); 41294bdecd9SRob Gulewich HOOK_INIT_GZ_BEFORE(ifs->ifs_ipfhook6_loop_in, ipf_hook6_loop_in, 41394bdecd9SRob Gulewich hook6_loop_in, hook6_loop_in_gz, ifs); 41494bdecd9SRob Gulewich HOOK_INIT_GZ_AFTER(ifs->ifs_ipfhook6_out, ipf_hook6_out, 41594bdecd9SRob Gulewich hook6_out, hook6_out_gz, ifs); 41694bdecd9SRob Gulewich HOOK_INIT_GZ_AFTER(ifs->ifs_ipfhook6_loop_out, ipf_hook6_loop_out, 41794bdecd9SRob Gulewich hook6_loop_out, hook6_loop_out_gz, ifs); 4187ddc9b1aSDarren Reed 4197ddc9b1aSDarren Reed ifs->ifs_hook6_nic_events = (net_hook_register(ifs->ifs_ipf_ipv6, 4207ddc9b1aSDarren Reed NH_NIC_EVENTS, ifs->ifs_ipfhook6_nicevents) == 0); 421f4b3ec61Sdh if (!ifs->ifs_hook6_nic_events) 422381a2a9aSdr goto hookup_failed; 423381a2a9aSdr 4247ddc9b1aSDarren Reed ifs->ifs_hook6_physical_in = (net_hook_register(ifs->ifs_ipf_ipv6, 4257ddc9b1aSDarren Reed NH_PHYSICAL_IN, ifs->ifs_ipfhook6_in) == 0); 426f4b3ec61Sdh if (!ifs->ifs_hook6_physical_in) 427381a2a9aSdr goto hookup_failed; 428381a2a9aSdr 4297ddc9b1aSDarren Reed ifs->ifs_hook6_physical_out = (net_hook_register(ifs->ifs_ipf_ipv6, 4307ddc9b1aSDarren Reed NH_PHYSICAL_OUT, ifs->ifs_ipfhook6_out) == 0); 431f4b3ec61Sdh if (!ifs->ifs_hook6_physical_out) 432381a2a9aSdr goto hookup_failed; 433381a2a9aSdr 434f4b3ec61Sdh if (ifs->ifs_ipf_loopback) { 4357ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_in = (net_hook_register( 4367ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN, 4377ddc9b1aSDarren Reed ifs->ifs_ipfhook6_loop_in) == 0); 438f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_in) 439381a2a9aSdr goto hookup_failed; 440381a2a9aSdr 4417ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_out = (net_hook_register( 4427ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT, 4437ddc9b1aSDarren Reed ifs->ifs_ipfhook6_loop_out) == 0); 444f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_out) 445381a2a9aSdr goto hookup_failed; 446381a2a9aSdr } 447381a2a9aSdr 448381a2a9aSdr /* 449381a2a9aSdr * Reacquire ipf_global, now it is safe. 450381a2a9aSdr */ 451f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 452381a2a9aSdr 4537c478bd9Sstevel@tonic-gate /* Do not use private interface ip_params_arr[] in Solaris 10 */ 4547c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 4577c478bd9Sstevel@tonic-gate ip_forwarding = &ip_g_forward; 4587c478bd9Sstevel@tonic-gate #endif 4597c478bd9Sstevel@tonic-gate /* 4607c478bd9Sstevel@tonic-gate * XXX - There is no terminator for this array, so it is not possible 4617c478bd9Sstevel@tonic-gate * to tell if what we are looking for is missing and go off the end 4627c478bd9Sstevel@tonic-gate * of the array. 4637c478bd9Sstevel@tonic-gate */ 4647c478bd9Sstevel@tonic-gate 465ab25eeb5Syz #if SOLARIS2 <= 8 4667c478bd9Sstevel@tonic-gate for (i = 0; ; i++) { 4677c478bd9Sstevel@tonic-gate if (!strcmp(ip_param_arr[i].ip_param_name, "ip_def_ttl")) { 4687c478bd9Sstevel@tonic-gate ip_ttl_ptr = &ip_param_arr[i].ip_param_value; 4697c478bd9Sstevel@tonic-gate } else if (!strcmp(ip_param_arr[i].ip_param_name, 4707c478bd9Sstevel@tonic-gate "ip_path_mtu_discovery")) { 4717c478bd9Sstevel@tonic-gate ip_mtudisc = &ip_param_arr[i].ip_param_value; 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate #if SOLARIS2 < 8 4747c478bd9Sstevel@tonic-gate else if (!strcmp(ip_param_arr[i].ip_param_name, 4757c478bd9Sstevel@tonic-gate "ip_forwarding")) { 4767c478bd9Sstevel@tonic-gate ip_forwarding = &ip_param_arr[i].ip_param_value; 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate #else 4797c478bd9Sstevel@tonic-gate else if (!strcmp(ip_param_arr[i].ip_param_name, 4807c478bd9Sstevel@tonic-gate "ip6_forwarding")) { 4817c478bd9Sstevel@tonic-gate ip6_forwarding = &ip_param_arr[i].ip_param_value; 4827c478bd9Sstevel@tonic-gate } 4837c478bd9Sstevel@tonic-gate #endif 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate if (ip_mtudisc != NULL && ip_ttl_ptr != NULL && 4867c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 4877c478bd9Sstevel@tonic-gate ip6_forwarding != NULL && 4887c478bd9Sstevel@tonic-gate #endif 4897c478bd9Sstevel@tonic-gate ip_forwarding != NULL) 4907c478bd9Sstevel@tonic-gate break; 4917c478bd9Sstevel@tonic-gate } 492ab25eeb5Syz #endif 4937c478bd9Sstevel@tonic-gate 494f4b3ec61Sdh if (ifs->ifs_fr_control_forwarding & 1) { 495ab25eeb5Syz if (ip_forwarding != NULL) 496ab25eeb5Syz *ip_forwarding = 1; 4977c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 498ab25eeb5Syz if (ip6_forwarding != NULL) 499ab25eeb5Syz *ip6_forwarding = 1; 5007c478bd9Sstevel@tonic-gate #endif 5017c478bd9Sstevel@tonic-gate } 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate #endif 5047c478bd9Sstevel@tonic-gate 505381a2a9aSdr return 0; 506381a2a9aSdr hookup_failed: 507f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 508381a2a9aSdr return -1; 509381a2a9aSdr } 510381a2a9aSdr 511f4b3ec61Sdh static int fr_setipfloopback(set, ifs) 512381a2a9aSdr int set; 513f4b3ec61Sdh ipf_stack_t *ifs; 514381a2a9aSdr { 515f4b3ec61Sdh if (ifs->ifs_ipf_ipv4 == NULL || ifs->ifs_ipf_ipv6 == NULL) 516381a2a9aSdr return EFAULT; 517381a2a9aSdr 518f4b3ec61Sdh if (set && !ifs->ifs_ipf_loopback) { 519f4b3ec61Sdh ifs->ifs_ipf_loopback = 1; 520381a2a9aSdr 5217ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_in = (net_hook_register( 5227ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN, 5237ddc9b1aSDarren Reed ifs->ifs_ipfhook4_loop_in) == 0); 524f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_in) 525381a2a9aSdr return EINVAL; 526381a2a9aSdr 5277ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_out = (net_hook_register( 5287ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT, 5297ddc9b1aSDarren Reed ifs->ifs_ipfhook4_loop_out) == 0); 530f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_out) 531381a2a9aSdr return EINVAL; 532381a2a9aSdr 5337ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_in = (net_hook_register( 5347ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN, 5357ddc9b1aSDarren Reed ifs->ifs_ipfhook6_loop_in) == 0); 536f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_in) 537381a2a9aSdr return EINVAL; 538381a2a9aSdr 5397ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_out = (net_hook_register( 5407ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT, 5417ddc9b1aSDarren Reed ifs->ifs_ipfhook6_loop_out) == 0); 542f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_out) 543381a2a9aSdr return EINVAL; 544381a2a9aSdr 545f4b3ec61Sdh } else if (!set && ifs->ifs_ipf_loopback) { 546f4b3ec61Sdh ifs->ifs_ipf_loopback = 0; 547381a2a9aSdr 548f4b3ec61Sdh ifs->ifs_hook4_loopback_in = 5497ddc9b1aSDarren Reed (net_hook_unregister(ifs->ifs_ipf_ipv4, 5507ddc9b1aSDarren Reed NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0); 551f4b3ec61Sdh if (ifs->ifs_hook4_loopback_in) 552381a2a9aSdr return EBUSY; 553381a2a9aSdr 554f4b3ec61Sdh ifs->ifs_hook4_loopback_out = 5557ddc9b1aSDarren Reed (net_hook_unregister(ifs->ifs_ipf_ipv4, 5567ddc9b1aSDarren Reed NH_LOOPBACK_OUT, ifs->ifs_ipfhook4_loop_out) != 0); 557f4b3ec61Sdh if (ifs->ifs_hook4_loopback_out) 558381a2a9aSdr return EBUSY; 559381a2a9aSdr 560f4b3ec61Sdh ifs->ifs_hook6_loopback_in = 5617ddc9b1aSDarren Reed (net_hook_unregister(ifs->ifs_ipf_ipv6, 5627ddc9b1aSDarren Reed NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0); 563f4b3ec61Sdh if (ifs->ifs_hook6_loopback_in) 564381a2a9aSdr return EBUSY; 565381a2a9aSdr 566f4b3ec61Sdh ifs->ifs_hook6_loopback_out = 5677ddc9b1aSDarren Reed (net_hook_unregister(ifs->ifs_ipf_ipv6, 5687ddc9b1aSDarren Reed NH_LOOPBACK_OUT, ifs->ifs_ipfhook6_loop_out) != 0); 569f4b3ec61Sdh if (ifs->ifs_hook6_loopback_out) 570381a2a9aSdr return EBUSY; 571381a2a9aSdr } 5727c478bd9Sstevel@tonic-gate return 0; 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate /* 5777c478bd9Sstevel@tonic-gate * Filter ioctl interface. 5787c478bd9Sstevel@tonic-gate */ 5797c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5807c478bd9Sstevel@tonic-gate int iplioctl(dev, cmd, data, mode, cp, rp) 5817c478bd9Sstevel@tonic-gate dev_t dev; 5827c478bd9Sstevel@tonic-gate int cmd; 5837c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 7 5847c478bd9Sstevel@tonic-gate intptr_t data; 5857c478bd9Sstevel@tonic-gate #else 5867c478bd9Sstevel@tonic-gate int *data; 5877c478bd9Sstevel@tonic-gate #endif 5887c478bd9Sstevel@tonic-gate int mode; 5897c478bd9Sstevel@tonic-gate cred_t *cp; 5907c478bd9Sstevel@tonic-gate int *rp; 5917c478bd9Sstevel@tonic-gate { 5927c478bd9Sstevel@tonic-gate int error = 0, tmp; 5937c478bd9Sstevel@tonic-gate friostat_t fio; 5947c478bd9Sstevel@tonic-gate minor_t unit; 5957c478bd9Sstevel@tonic-gate u_int enable; 596f4b3ec61Sdh ipf_stack_t *ifs; 59794bdecd9SRob Gulewich zoneid_t zid; 59894bdecd9SRob Gulewich ipf_devstate_t *isp; 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 6017c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplioctl(%x,%x,%x,%d,%x,%d)\n", 6027c478bd9Sstevel@tonic-gate dev, cmd, data, mode, cp, rp); 6037c478bd9Sstevel@tonic-gate #endif 6047c478bd9Sstevel@tonic-gate unit = getminor(dev); 60594bdecd9SRob Gulewich 60694bdecd9SRob Gulewich isp = ddi_get_soft_state(ipf_state, unit); 60794bdecd9SRob Gulewich if (isp == NULL) 6087c478bd9Sstevel@tonic-gate return ENXIO; 60994bdecd9SRob Gulewich unit = isp->ipfs_minor; 61094bdecd9SRob Gulewich 61194bdecd9SRob Gulewich zid = crgetzoneid(cp); 61294bdecd9SRob Gulewich if (cmd == SIOCIPFZONESET) { 61394bdecd9SRob Gulewich if (zid == GLOBAL_ZONEID) 61494bdecd9SRob Gulewich return fr_setzoneid(isp, (caddr_t) data); 61594bdecd9SRob Gulewich return EACCES; 61694bdecd9SRob Gulewich } 6177c478bd9Sstevel@tonic-gate 6187ddc9b1aSDarren Reed /* 61994bdecd9SRob Gulewich * ipf_find_stack returns with a read lock on ifs_ipf_global 6207ddc9b1aSDarren Reed */ 62194bdecd9SRob Gulewich ifs = ipf_find_stack(zid, isp); 62294bdecd9SRob Gulewich if (ifs == NULL) 62394bdecd9SRob Gulewich return ENXIO; 624f4b3ec61Sdh 625f4b3ec61Sdh if (ifs->ifs_fr_running <= 0) { 626f4b3ec61Sdh if (unit != IPL_LOGIPF) { 62794bdecd9SRob Gulewich RWLOCK_EXIT(&ifs->ifs_ipf_global); 6287c478bd9Sstevel@tonic-gate return EIO; 629f4b3ec61Sdh } 6307c478bd9Sstevel@tonic-gate if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 631ab25eeb5Syz cmd != SIOCIPFSET && cmd != SIOCFRENB && 632f4b3ec61Sdh cmd != SIOCGETFS && cmd != SIOCGETFF) { 63394bdecd9SRob Gulewich RWLOCK_EXIT(&ifs->ifs_ipf_global); 6347c478bd9Sstevel@tonic-gate return EIO; 635f4b3ec61Sdh } 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate 63872680cf5SDarren Reed if (ifs->ifs_fr_enable_active != 0) { 63972680cf5SDarren Reed RWLOCK_EXIT(&ifs->ifs_ipf_global); 64072680cf5SDarren Reed return EBUSY; 64172680cf5SDarren Reed } 6427c478bd9Sstevel@tonic-gate 64367dbe2beSCasper H.S. Dik error = fr_ioctlswitch(unit, (caddr_t)data, cmd, mode, crgetuid(cp), 6447ddc9b1aSDarren Reed curproc, ifs); 6457c478bd9Sstevel@tonic-gate if (error != -1) { 646f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 6477c478bd9Sstevel@tonic-gate return error; 6487c478bd9Sstevel@tonic-gate } 6497c478bd9Sstevel@tonic-gate error = 0; 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate switch (cmd) 6527c478bd9Sstevel@tonic-gate { 6537c478bd9Sstevel@tonic-gate case SIOCFRENB : 6547c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6557c478bd9Sstevel@tonic-gate error = EPERM; 6567c478bd9Sstevel@tonic-gate else { 6577c478bd9Sstevel@tonic-gate error = COPYIN((caddr_t)data, (caddr_t)&enable, 6587c478bd9Sstevel@tonic-gate sizeof(enable)); 6597c478bd9Sstevel@tonic-gate if (error != 0) { 6607c478bd9Sstevel@tonic-gate error = EFAULT; 6617c478bd9Sstevel@tonic-gate break; 6627c478bd9Sstevel@tonic-gate } 6637c478bd9Sstevel@tonic-gate 664f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 665f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 666e8d569f4SAlexandr Nedvedicky 667e8d569f4SAlexandr Nedvedicky /* 668e8d569f4SAlexandr Nedvedicky * We must recheck fr_enable_active here, since we've 669e8d569f4SAlexandr Nedvedicky * dropped ifs_ipf_global from R in order to get it 670e8d569f4SAlexandr Nedvedicky * exclusively. 671e8d569f4SAlexandr Nedvedicky */ 672e8d569f4SAlexandr Nedvedicky if (ifs->ifs_fr_enable_active == 0) { 673e8d569f4SAlexandr Nedvedicky ifs->ifs_fr_enable_active = 1; 674e8d569f4SAlexandr Nedvedicky error = fr_enableipf(ifs, enable); 675e8d569f4SAlexandr Nedvedicky ifs->ifs_fr_enable_active = 0; 676e8d569f4SAlexandr Nedvedicky } 6777c478bd9Sstevel@tonic-gate } 6787c478bd9Sstevel@tonic-gate break; 6797c478bd9Sstevel@tonic-gate case SIOCIPFSET : 6807c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) { 6817c478bd9Sstevel@tonic-gate error = EPERM; 6827c478bd9Sstevel@tonic-gate break; 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate /* FALLTHRU */ 6857c478bd9Sstevel@tonic-gate case SIOCIPFGETNEXT : 6867c478bd9Sstevel@tonic-gate case SIOCIPFGET : 687f4b3ec61Sdh error = fr_ipftune(cmd, (void *)data, ifs); 6887c478bd9Sstevel@tonic-gate break; 6897c478bd9Sstevel@tonic-gate case SIOCSETFF : 6907c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 6917c478bd9Sstevel@tonic-gate error = EPERM; 6927c478bd9Sstevel@tonic-gate else { 6937ddc9b1aSDarren Reed error = COPYIN((caddr_t)data, 6947ddc9b1aSDarren Reed (caddr_t)&ifs->ifs_fr_flags, 6957ddc9b1aSDarren Reed sizeof(ifs->ifs_fr_flags)); 6967c478bd9Sstevel@tonic-gate if (error != 0) 6977c478bd9Sstevel@tonic-gate error = EFAULT; 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate break; 700381a2a9aSdr case SIOCIPFLP : 701381a2a9aSdr error = COPYIN((caddr_t)data, (caddr_t)&tmp, 702381a2a9aSdr sizeof(tmp)); 703381a2a9aSdr if (error != 0) 704381a2a9aSdr error = EFAULT; 705381a2a9aSdr else 706f4b3ec61Sdh error = fr_setipfloopback(tmp, ifs); 707381a2a9aSdr break; 7087c478bd9Sstevel@tonic-gate case SIOCGETFF : 709f4b3ec61Sdh error = COPYOUT((caddr_t)&ifs->ifs_fr_flags, (caddr_t)data, 7107ddc9b1aSDarren Reed sizeof(ifs->ifs_fr_flags)); 7117c478bd9Sstevel@tonic-gate if (error != 0) 7127c478bd9Sstevel@tonic-gate error = EFAULT; 7137c478bd9Sstevel@tonic-gate break; 7147c478bd9Sstevel@tonic-gate case SIOCFUNCL : 7157c478bd9Sstevel@tonic-gate error = fr_resolvefunc((void *)data); 7167c478bd9Sstevel@tonic-gate break; 7177c478bd9Sstevel@tonic-gate case SIOCINAFR : 7187c478bd9Sstevel@tonic-gate case SIOCRMAFR : 7197c478bd9Sstevel@tonic-gate case SIOCADAFR : 7207c478bd9Sstevel@tonic-gate case SIOCZRLST : 7217c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 7227c478bd9Sstevel@tonic-gate error = EPERM; 7237c478bd9Sstevel@tonic-gate else 7247c478bd9Sstevel@tonic-gate error = frrequest(unit, cmd, (caddr_t)data, 725f4b3ec61Sdh ifs->ifs_fr_active, 1, ifs); 7267c478bd9Sstevel@tonic-gate break; 7277c478bd9Sstevel@tonic-gate case SIOCINIFR : 7287c478bd9Sstevel@tonic-gate case SIOCRMIFR : 7297c478bd9Sstevel@tonic-gate case SIOCADIFR : 7307c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 7317c478bd9Sstevel@tonic-gate error = EPERM; 7327c478bd9Sstevel@tonic-gate else 7337c478bd9Sstevel@tonic-gate error = frrequest(unit, cmd, (caddr_t)data, 734f4b3ec61Sdh 1 - ifs->ifs_fr_active, 1, ifs); 7357c478bd9Sstevel@tonic-gate break; 7367c478bd9Sstevel@tonic-gate case SIOCSWAPA : 7377c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 7387c478bd9Sstevel@tonic-gate error = EPERM; 7397c478bd9Sstevel@tonic-gate else { 740f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_mutex); 74114d3298eSAlexandr Nedvedicky bzero((char *)ifs->ifs_frcache, 74214d3298eSAlexandr Nedvedicky sizeof (ifs->ifs_frcache)); 743f4b3ec61Sdh error = COPYOUT((caddr_t)&ifs->ifs_fr_active, 744f4b3ec61Sdh (caddr_t)data, 745f4b3ec61Sdh sizeof(ifs->ifs_fr_active)); 7467c478bd9Sstevel@tonic-gate if (error != 0) 7477c478bd9Sstevel@tonic-gate error = EFAULT; 7487c478bd9Sstevel@tonic-gate else 749f4b3ec61Sdh ifs->ifs_fr_active = 1 - ifs->ifs_fr_active; 750f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 7517c478bd9Sstevel@tonic-gate } 7527c478bd9Sstevel@tonic-gate break; 7537c478bd9Sstevel@tonic-gate case SIOCGETFS : 754f4b3ec61Sdh fr_getstat(&fio, ifs); 7557c478bd9Sstevel@tonic-gate error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT); 7567c478bd9Sstevel@tonic-gate break; 7577c478bd9Sstevel@tonic-gate case SIOCFRZST : 7587c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 7597c478bd9Sstevel@tonic-gate error = EPERM; 7607c478bd9Sstevel@tonic-gate else 761f4b3ec61Sdh error = fr_zerostats((caddr_t)data, ifs); 7627c478bd9Sstevel@tonic-gate break; 7637c478bd9Sstevel@tonic-gate case SIOCIPFFL : 7647c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 7657c478bd9Sstevel@tonic-gate error = EPERM; 7667c478bd9Sstevel@tonic-gate else { 7677c478bd9Sstevel@tonic-gate error = COPYIN((caddr_t)data, (caddr_t)&tmp, 7687c478bd9Sstevel@tonic-gate sizeof(tmp)); 7697c478bd9Sstevel@tonic-gate if (!error) { 770f4b3ec61Sdh tmp = frflush(unit, 4, tmp, ifs); 7717c478bd9Sstevel@tonic-gate error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 7727ddc9b1aSDarren Reed sizeof(tmp)); 7737c478bd9Sstevel@tonic-gate if (error != 0) 7747c478bd9Sstevel@tonic-gate error = EFAULT; 7757c478bd9Sstevel@tonic-gate } else 7767c478bd9Sstevel@tonic-gate error = EFAULT; 7777c478bd9Sstevel@tonic-gate } 7787c478bd9Sstevel@tonic-gate break; 7797663b816Sml #ifdef USE_INET6 7807663b816Sml case SIOCIPFL6 : 7817663b816Sml if (!(mode & FWRITE)) 7827663b816Sml error = EPERM; 7837663b816Sml else { 7847663b816Sml error = COPYIN((caddr_t)data, (caddr_t)&tmp, 7857663b816Sml sizeof(tmp)); 7867663b816Sml if (!error) { 787f4b3ec61Sdh tmp = frflush(unit, 6, tmp, ifs); 7887663b816Sml error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 7897ddc9b1aSDarren Reed sizeof(tmp)); 7907663b816Sml if (error != 0) 7917663b816Sml error = EFAULT; 7927663b816Sml } else 7937663b816Sml error = EFAULT; 7947663b816Sml } 7957663b816Sml break; 7967663b816Sml #endif 7977c478bd9Sstevel@tonic-gate case SIOCSTLCK : 7987c478bd9Sstevel@tonic-gate error = COPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 7997c478bd9Sstevel@tonic-gate if (error == 0) { 800f4b3ec61Sdh ifs->ifs_fr_state_lock = tmp; 801f4b3ec61Sdh ifs->ifs_fr_nat_lock = tmp; 802f4b3ec61Sdh ifs->ifs_fr_frag_lock = tmp; 803f4b3ec61Sdh ifs->ifs_fr_auth_lock = tmp; 8047c478bd9Sstevel@tonic-gate } else 8057c478bd9Sstevel@tonic-gate error = EFAULT; 8067c478bd9Sstevel@tonic-gate break; 8077c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 8087c478bd9Sstevel@tonic-gate case SIOCIPFFB : 8097c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 8107c478bd9Sstevel@tonic-gate error = EPERM; 8117c478bd9Sstevel@tonic-gate else { 812f4b3ec61Sdh tmp = ipflog_clear(unit, ifs); 8137c478bd9Sstevel@tonic-gate error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 8147c478bd9Sstevel@tonic-gate sizeof(tmp)); 8157c478bd9Sstevel@tonic-gate if (error) 8167c478bd9Sstevel@tonic-gate error = EFAULT; 8177c478bd9Sstevel@tonic-gate } 8187c478bd9Sstevel@tonic-gate break; 8197c478bd9Sstevel@tonic-gate #endif /* IPFILTER_LOG */ 8207c478bd9Sstevel@tonic-gate case SIOCFRSYN : 8217c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 8227c478bd9Sstevel@tonic-gate error = EPERM; 8237c478bd9Sstevel@tonic-gate else { 824f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 825f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 826381a2a9aSdr 827f4b3ec61Sdh frsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 828d6c23f6fSyx fr_natifpsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 829d6c23f6fSyx fr_nataddrsync(0, NULL, NULL, ifs); 830f4b3ec61Sdh fr_statesync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 831381a2a9aSdr error = 0; 8327c478bd9Sstevel@tonic-gate } 8337c478bd9Sstevel@tonic-gate break; 8347c478bd9Sstevel@tonic-gate case SIOCGFRST : 835f4b3ec61Sdh error = fr_outobj((void *)data, fr_fragstats(ifs), 8367c478bd9Sstevel@tonic-gate IPFOBJ_FRAGSTAT); 8377c478bd9Sstevel@tonic-gate break; 8387c478bd9Sstevel@tonic-gate case FIONREAD : 8397c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 840f4b3ec61Sdh tmp = (int)ifs->ifs_iplused[IPL_LOGIPF]; 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate error = COPYOUT((caddr_t)&tmp, (caddr_t)data, sizeof(tmp)); 8437c478bd9Sstevel@tonic-gate if (error != 0) 8447c478bd9Sstevel@tonic-gate error = EFAULT; 8457c478bd9Sstevel@tonic-gate #endif 8467c478bd9Sstevel@tonic-gate break; 847f4b3ec61Sdh case SIOCIPFITER : 84867dbe2beSCasper H.S. Dik error = ipf_frruleiter((caddr_t)data, crgetuid(cp), 8497ddc9b1aSDarren Reed curproc, ifs); 850f4b3ec61Sdh break; 851f4b3ec61Sdh 852f4b3ec61Sdh case SIOCGENITER : 85367dbe2beSCasper H.S. Dik error = ipf_genericiter((caddr_t)data, crgetuid(cp), 8547ddc9b1aSDarren Reed curproc, ifs); 855f4b3ec61Sdh break; 856f4b3ec61Sdh 857f4b3ec61Sdh case SIOCIPFDELTOK : 858bb1d9de5SJohn Ojemann error = BCOPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 859bb1d9de5SJohn Ojemann if (error != 0) { 860bb1d9de5SJohn Ojemann error = EFAULT; 861bb1d9de5SJohn Ojemann } else { 86267dbe2beSCasper H.S. Dik error = ipf_deltoken(tmp, crgetuid(cp), curproc, ifs); 863bb1d9de5SJohn Ojemann } 864f4b3ec61Sdh break; 865f4b3ec61Sdh 8667c478bd9Sstevel@tonic-gate default : 86733f2fefdSDarren Reed #ifdef IPFDEBUG 8687ddc9b1aSDarren Reed cmn_err(CE_NOTE, "Unknown: cmd 0x%x data %p", 8697ddc9b1aSDarren Reed cmd, (void *)data); 87033f2fefdSDarren Reed #endif 8717c478bd9Sstevel@tonic-gate error = EINVAL; 8727c478bd9Sstevel@tonic-gate break; 8737c478bd9Sstevel@tonic-gate } 874f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 8757c478bd9Sstevel@tonic-gate return error; 8767c478bd9Sstevel@tonic-gate } 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate 8797ddc9b1aSDarren Reed static int fr_enableipf(ifs, enable) 880882bd30bSdr ipf_stack_t *ifs; 881882bd30bSdr int enable; 882882bd30bSdr { 883882bd30bSdr int error; 884882bd30bSdr 88544aaa2b6Sjojemann if (!enable) { 886882bd30bSdr error = ipldetach(ifs); 887882bd30bSdr if (error == 0) 888882bd30bSdr ifs->ifs_fr_running = -1; 8897ddc9b1aSDarren Reed return error; 890882bd30bSdr } 891882bd30bSdr 89244aaa2b6Sjojemann if (ifs->ifs_fr_running > 0) 8937ddc9b1aSDarren Reed return 0; 89444aaa2b6Sjojemann 8957ddc9b1aSDarren Reed error = iplattach(ifs); 89644aaa2b6Sjojemann if (error == 0) { 89744aaa2b6Sjojemann if (ifs->ifs_fr_timer_id == NULL) { 89844aaa2b6Sjojemann int hz = drv_usectohz(500000); 89944aaa2b6Sjojemann 90044aaa2b6Sjojemann ifs->ifs_fr_timer_id = timeout(fr_slowtimer, 9017ddc9b1aSDarren Reed (void *)ifs, 9027ddc9b1aSDarren Reed hz); 90344aaa2b6Sjojemann } 90444aaa2b6Sjojemann ifs->ifs_fr_running = 1; 90544aaa2b6Sjojemann } else { 90644aaa2b6Sjojemann (void) ipldetach(ifs); 90744aaa2b6Sjojemann } 9087ddc9b1aSDarren Reed return error; 909882bd30bSdr } 910882bd30bSdr 911882bd30bSdr 912f4b3ec61Sdh phy_if_t get_unit(name, v, ifs) 913f4b3ec61Sdh char *name; 914f4b3ec61Sdh int v; 915f4b3ec61Sdh ipf_stack_t *ifs; 9167c478bd9Sstevel@tonic-gate { 9177ddc9b1aSDarren Reed net_handle_t nif; 918381a2a9aSdr 919381a2a9aSdr if (v == 4) 920f4b3ec61Sdh nif = ifs->ifs_ipf_ipv4; 921381a2a9aSdr else if (v == 6) 922f4b3ec61Sdh nif = ifs->ifs_ipf_ipv6; 923381a2a9aSdr else 924381a2a9aSdr return 0; 925381a2a9aSdr 926f4b3ec61Sdh return (net_phylookup(nif, name)); 9277c478bd9Sstevel@tonic-gate } 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate /* 9307c478bd9Sstevel@tonic-gate * routines below for saving IP headers to buffer 9317c478bd9Sstevel@tonic-gate */ 9327c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9337c478bd9Sstevel@tonic-gate int iplopen(devp, flags, otype, cred) 9347c478bd9Sstevel@tonic-gate dev_t *devp; 9357c478bd9Sstevel@tonic-gate int flags, otype; 9367c478bd9Sstevel@tonic-gate cred_t *cred; 9377c478bd9Sstevel@tonic-gate { 93894bdecd9SRob Gulewich ipf_devstate_t *isp; 9397c478bd9Sstevel@tonic-gate minor_t min = getminor(*devp); 94094bdecd9SRob Gulewich minor_t minor; 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 9437c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplopen(%x,%x,%x,%x)\n", devp, flags, otype, cred); 9447c478bd9Sstevel@tonic-gate #endif 9457c478bd9Sstevel@tonic-gate if (!(otype & OTYP_CHR)) 9467c478bd9Sstevel@tonic-gate return ENXIO; 9477c478bd9Sstevel@tonic-gate 94894bdecd9SRob Gulewich if (IPL_LOGMAX < min) 94994bdecd9SRob Gulewich return ENXIO; 95094bdecd9SRob Gulewich 95194bdecd9SRob Gulewich minor = (minor_t)(uintptr_t)vmem_alloc(ipf_minor, 1, 95294bdecd9SRob Gulewich VM_BESTFIT | VM_SLEEP); 95394bdecd9SRob Gulewich 95494bdecd9SRob Gulewich if (ddi_soft_state_zalloc(ipf_state, minor) != 0) { 95594bdecd9SRob Gulewich vmem_free(ipf_minor, (void *)(uintptr_t)minor, 1); 95694bdecd9SRob Gulewich return ENXIO; 95794bdecd9SRob Gulewich } 95894bdecd9SRob Gulewich 95994bdecd9SRob Gulewich *devp = makedevice(getmajor(*devp), minor); 96094bdecd9SRob Gulewich isp = ddi_get_soft_state(ipf_state, minor); 96194bdecd9SRob Gulewich VERIFY(isp != NULL); 96294bdecd9SRob Gulewich 96394bdecd9SRob Gulewich isp->ipfs_minor = min; 96494bdecd9SRob Gulewich isp->ipfs_zoneid = IPFS_ZONE_UNSET; 96594bdecd9SRob Gulewich 96694bdecd9SRob Gulewich return 0; 9677c478bd9Sstevel@tonic-gate } 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9717c478bd9Sstevel@tonic-gate int iplclose(dev, flags, otype, cred) 9727c478bd9Sstevel@tonic-gate dev_t dev; 9737c478bd9Sstevel@tonic-gate int flags, otype; 9747c478bd9Sstevel@tonic-gate cred_t *cred; 9757c478bd9Sstevel@tonic-gate { 9767c478bd9Sstevel@tonic-gate minor_t min = getminor(dev); 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 9797c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplclose(%x,%x,%x,%x)\n", dev, flags, otype, cred); 9807c478bd9Sstevel@tonic-gate #endif 9817c478bd9Sstevel@tonic-gate 98294bdecd9SRob Gulewich if (IPL_LOGMAX < min) 98394bdecd9SRob Gulewich return ENXIO; 98494bdecd9SRob Gulewich 98594bdecd9SRob Gulewich ddi_soft_state_free(ipf_state, min); 98694bdecd9SRob Gulewich vmem_free(ipf_minor, (void *)(uintptr_t)min, 1); 98794bdecd9SRob Gulewich 98894bdecd9SRob Gulewich return 0; 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 9927c478bd9Sstevel@tonic-gate /* 9937c478bd9Sstevel@tonic-gate * iplread/ipllog 9947c478bd9Sstevel@tonic-gate * both of these must operate with at least splnet() lest they be 9957c478bd9Sstevel@tonic-gate * called during packet processing and cause an inconsistancy to appear in 9967c478bd9Sstevel@tonic-gate * the filter lists. 9977c478bd9Sstevel@tonic-gate */ 9987c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9997c478bd9Sstevel@tonic-gate int iplread(dev, uio, cp) 10007c478bd9Sstevel@tonic-gate dev_t dev; 10017c478bd9Sstevel@tonic-gate register struct uio *uio; 10027c478bd9Sstevel@tonic-gate cred_t *cp; 10037c478bd9Sstevel@tonic-gate { 1004f4b3ec61Sdh ipf_stack_t *ifs; 1005f4b3ec61Sdh int ret; 100694bdecd9SRob Gulewich minor_t unit; 100794bdecd9SRob Gulewich ipf_devstate_t *isp; 100894bdecd9SRob Gulewich 100994bdecd9SRob Gulewich unit = getminor(dev); 101094bdecd9SRob Gulewich isp = ddi_get_soft_state(ipf_state, unit); 101194bdecd9SRob Gulewich if (isp == NULL) 101294bdecd9SRob Gulewich return ENXIO; 101394bdecd9SRob Gulewich unit = isp->ipfs_minor; 101494bdecd9SRob Gulewich 1015f4b3ec61Sdh 10167ddc9b1aSDarren Reed /* 101794bdecd9SRob Gulewich * ipf_find_stack returns with a read lock on ifs_ipf_global 10187ddc9b1aSDarren Reed */ 101994bdecd9SRob Gulewich ifs = ipf_find_stack(crgetzoneid(cp), isp); 102094bdecd9SRob Gulewich if (ifs == NULL) 102194bdecd9SRob Gulewich return ENXIO; 1022f4b3ec61Sdh 10237c478bd9Sstevel@tonic-gate # ifdef IPFDEBUG 10247c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplread(%x,%x,%x)\n", dev, uio, cp); 10257c478bd9Sstevel@tonic-gate # endif 102608ee25aeSdr 1027f4b3ec61Sdh if (ifs->ifs_fr_running < 1) { 102894bdecd9SRob Gulewich RWLOCK_EXIT(&ifs->ifs_ipf_global); 102908ee25aeSdr return EIO; 1030f4b3ec61Sdh } 103108ee25aeSdr 10327c478bd9Sstevel@tonic-gate # ifdef IPFILTER_SYNC 103394bdecd9SRob Gulewich if (unit == IPL_LOGSYNC) { 103494bdecd9SRob Gulewich RWLOCK_EXIT(&ifs->ifs_ipf_global); 10357c478bd9Sstevel@tonic-gate return ipfsync_read(uio); 1036f4b3ec61Sdh } 10377c478bd9Sstevel@tonic-gate # endif 10387c478bd9Sstevel@tonic-gate 103994bdecd9SRob Gulewich ret = ipflog_read(unit, uio, ifs); 104094bdecd9SRob Gulewich RWLOCK_EXIT(&ifs->ifs_ipf_global); 1041f4b3ec61Sdh return ret; 10427c478bd9Sstevel@tonic-gate } 10437c478bd9Sstevel@tonic-gate #endif /* IPFILTER_LOG */ 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate 10467c478bd9Sstevel@tonic-gate /* 10477c478bd9Sstevel@tonic-gate * iplread/ipllog 10487c478bd9Sstevel@tonic-gate * both of these must operate with at least splnet() lest they be 10497c478bd9Sstevel@tonic-gate * called during packet processing and cause an inconsistancy to appear in 10507c478bd9Sstevel@tonic-gate * the filter lists. 10517c478bd9Sstevel@tonic-gate */ 10527c478bd9Sstevel@tonic-gate int iplwrite(dev, uio, cp) 10537c478bd9Sstevel@tonic-gate dev_t dev; 10547c478bd9Sstevel@tonic-gate register struct uio *uio; 10557c478bd9Sstevel@tonic-gate cred_t *cp; 10567c478bd9Sstevel@tonic-gate { 1057f4b3ec61Sdh ipf_stack_t *ifs; 105894bdecd9SRob Gulewich minor_t unit; 105994bdecd9SRob Gulewich ipf_devstate_t *isp; 106094bdecd9SRob Gulewich 106194bdecd9SRob Gulewich unit = getminor(dev); 106294bdecd9SRob Gulewich isp = ddi_get_soft_state(ipf_state, unit); 106394bdecd9SRob Gulewich if (isp == NULL) 106494bdecd9SRob Gulewich return ENXIO; 106594bdecd9SRob Gulewich unit = isp->ipfs_minor; 1066f4b3ec61Sdh 10677ddc9b1aSDarren Reed /* 106894bdecd9SRob Gulewich * ipf_find_stack returns with a read lock on ifs_ipf_global 10697ddc9b1aSDarren Reed */ 107094bdecd9SRob Gulewich ifs = ipf_find_stack(crgetzoneid(cp), isp); 107194bdecd9SRob Gulewich if (ifs == NULL) 107294bdecd9SRob Gulewich return ENXIO; 1073f4b3ec61Sdh 10747c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 10757c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplwrite(%x,%x,%x)\n", dev, uio, cp); 10767c478bd9Sstevel@tonic-gate #endif 107708ee25aeSdr 1078f4b3ec61Sdh if (ifs->ifs_fr_running < 1) { 107994bdecd9SRob Gulewich RWLOCK_EXIT(&ifs->ifs_ipf_global); 108008ee25aeSdr return EIO; 1081f4b3ec61Sdh } 108208ee25aeSdr 1083ab25eeb5Syz #ifdef IPFILTER_SYNC 108494bdecd9SRob Gulewich if (getminor(dev) == IPL_LOGSYNC) { 108594bdecd9SRob Gulewich RWLOCK_EXIT(&ifs->ifs_ipf_global); 1086ab25eeb5Syz return ipfsync_write(uio); 108794bdecd9SRob Gulewich } 10887c478bd9Sstevel@tonic-gate #endif /* IPFILTER_SYNC */ 1089ab25eeb5Syz dev = dev; /* LINT */ 1090ab25eeb5Syz uio = uio; /* LINT */ 1091ab25eeb5Syz cp = cp; /* LINT */ 109294bdecd9SRob Gulewich RWLOCK_EXIT(&ifs->ifs_ipf_global); 1093ab25eeb5Syz return ENXIO; 1094ab25eeb5Syz } 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate /* 10987c478bd9Sstevel@tonic-gate * fr_send_reset - this could conceivably be a call to tcp_respond(), but that 10997c478bd9Sstevel@tonic-gate * requires a large amount of setting up and isn't any more efficient. 11007c478bd9Sstevel@tonic-gate */ 11017c478bd9Sstevel@tonic-gate int fr_send_reset(fin) 11027c478bd9Sstevel@tonic-gate fr_info_t *fin; 11037c478bd9Sstevel@tonic-gate { 11047c478bd9Sstevel@tonic-gate tcphdr_t *tcp, *tcp2; 11057c478bd9Sstevel@tonic-gate int tlen, hlen; 11067c478bd9Sstevel@tonic-gate mblk_t *m; 11077c478bd9Sstevel@tonic-gate #ifdef USE_INET6 11087c478bd9Sstevel@tonic-gate ip6_t *ip6; 11097c478bd9Sstevel@tonic-gate #endif 11107c478bd9Sstevel@tonic-gate ip_t *ip; 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate tcp = fin->fin_dp; 11137c478bd9Sstevel@tonic-gate if (tcp->th_flags & TH_RST) 11147c478bd9Sstevel@tonic-gate return -1; 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate #ifndef IPFILTER_CKSUM 11177c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 11187c478bd9Sstevel@tonic-gate return -1; 11197c478bd9Sstevel@tonic-gate #endif 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate tlen = (tcp->th_flags & (TH_SYN|TH_FIN)) ? 1 : 0; 11227c478bd9Sstevel@tonic-gate #ifdef USE_INET6 11237c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) 11247c478bd9Sstevel@tonic-gate hlen = sizeof(ip6_t); 11257c478bd9Sstevel@tonic-gate else 11267c478bd9Sstevel@tonic-gate #endif 11277c478bd9Sstevel@tonic-gate hlen = sizeof(ip_t); 11287c478bd9Sstevel@tonic-gate hlen += sizeof(*tcp2); 11297c478bd9Sstevel@tonic-gate if ((m = (mblk_t *)allocb(hlen + 64, BPRI_HI)) == NULL) 11307c478bd9Sstevel@tonic-gate return -1; 11317c478bd9Sstevel@tonic-gate 11327c478bd9Sstevel@tonic-gate m->b_rptr += 64; 11337c478bd9Sstevel@tonic-gate MTYPE(m) = M_DATA; 11347c478bd9Sstevel@tonic-gate m->b_wptr = m->b_rptr + hlen; 1135ab25eeb5Syz ip = (ip_t *)m->b_rptr; 1136ab25eeb5Syz bzero((char *)ip, hlen); 11377c478bd9Sstevel@tonic-gate tcp2 = (struct tcphdr *)(m->b_rptr + hlen - sizeof(*tcp2)); 11387c478bd9Sstevel@tonic-gate tcp2->th_dport = tcp->th_sport; 11397c478bd9Sstevel@tonic-gate tcp2->th_sport = tcp->th_dport; 11407c478bd9Sstevel@tonic-gate if (tcp->th_flags & TH_ACK) { 11417c478bd9Sstevel@tonic-gate tcp2->th_seq = tcp->th_ack; 11427c478bd9Sstevel@tonic-gate tcp2->th_flags = TH_RST; 11437c478bd9Sstevel@tonic-gate } else { 11447c478bd9Sstevel@tonic-gate tcp2->th_ack = ntohl(tcp->th_seq); 11457c478bd9Sstevel@tonic-gate tcp2->th_ack += tlen; 11467c478bd9Sstevel@tonic-gate tcp2->th_ack = htonl(tcp2->th_ack); 11477c478bd9Sstevel@tonic-gate tcp2->th_flags = TH_RST|TH_ACK; 11487c478bd9Sstevel@tonic-gate } 11497c478bd9Sstevel@tonic-gate tcp2->th_off = sizeof(struct tcphdr) >> 2; 11507c478bd9Sstevel@tonic-gate 1151ab25eeb5Syz ip->ip_v = fin->fin_v; 11527c478bd9Sstevel@tonic-gate #ifdef USE_INET6 11537c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 11547c478bd9Sstevel@tonic-gate ip6 = (ip6_t *)m->b_rptr; 11557663b816Sml ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 1156d6c23f6fSyx ip6->ip6_src = fin->fin_dst6.in6; 1157d6c23f6fSyx ip6->ip6_dst = fin->fin_src6.in6; 11587c478bd9Sstevel@tonic-gate ip6->ip6_plen = htons(sizeof(*tcp)); 11597c478bd9Sstevel@tonic-gate ip6->ip6_nxt = IPPROTO_TCP; 11607663b816Sml tcp2->th_sum = fr_cksum(m, (ip_t *)ip6, IPPROTO_TCP, tcp2); 11617c478bd9Sstevel@tonic-gate } else 11627c478bd9Sstevel@tonic-gate #endif 11637c478bd9Sstevel@tonic-gate { 11647c478bd9Sstevel@tonic-gate ip->ip_src.s_addr = fin->fin_daddr; 11657c478bd9Sstevel@tonic-gate ip->ip_dst.s_addr = fin->fin_saddr; 11667c478bd9Sstevel@tonic-gate ip->ip_id = fr_nextipid(fin); 11677c478bd9Sstevel@tonic-gate ip->ip_hl = sizeof(*ip) >> 2; 11687c478bd9Sstevel@tonic-gate ip->ip_p = IPPROTO_TCP; 116937b40788Sekozlow ip->ip_len = sizeof(*ip) + sizeof(*tcp); 11707c478bd9Sstevel@tonic-gate ip->ip_tos = fin->fin_ip->ip_tos; 11717c478bd9Sstevel@tonic-gate tcp2->th_sum = fr_cksum(m, ip, IPPROTO_TCP, tcp2); 11727c478bd9Sstevel@tonic-gate } 1173ab25eeb5Syz return fr_send_ip(fin, m, &m); 11747c478bd9Sstevel@tonic-gate } 11757c478bd9Sstevel@tonic-gate 117637b40788Sekozlow /* 117737b40788Sekozlow * Function: fr_send_ip 117837b40788Sekozlow * Returns: 0: success 117937b40788Sekozlow * -1: failed 118037b40788Sekozlow * Parameters: 118137b40788Sekozlow * fin: packet information 118237b40788Sekozlow * m: the message block where ip head starts 118337b40788Sekozlow * 118437b40788Sekozlow * Send a new packet through the IP stack. 118537b40788Sekozlow * 118637b40788Sekozlow * For IPv4 packets, ip_len must be in host byte order, and ip_v, 118737b40788Sekozlow * ip_ttl, ip_off, and ip_sum are ignored (filled in by this 118837b40788Sekozlow * function). 118937b40788Sekozlow * 119037b40788Sekozlow * For IPv6 packets, ip6_flow, ip6_vfc, and ip6_hlim are filled 119137b40788Sekozlow * in by this function. 119237b40788Sekozlow * 119337b40788Sekozlow * All other portions of the packet must be in on-the-wire format. 119437b40788Sekozlow */ 1195ab25eeb5Syz /*ARGSUSED*/ 1196ab25eeb5Syz static int fr_send_ip(fin, m, mpp) 11977c478bd9Sstevel@tonic-gate fr_info_t *fin; 1198ab25eeb5Syz mblk_t *m, **mpp; 11997c478bd9Sstevel@tonic-gate { 1200ab25eeb5Syz qpktinfo_t qpi, *qpip; 1201ab25eeb5Syz fr_info_t fnew; 1202ab25eeb5Syz ip_t *ip; 1203ab25eeb5Syz int i, hlen; 1204f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1205ab25eeb5Syz 1206ab25eeb5Syz ip = (ip_t *)m->b_rptr; 1207ab25eeb5Syz bzero((char *)&fnew, sizeof(fnew)); 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate #ifdef USE_INET6 12107c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 12117c478bd9Sstevel@tonic-gate ip6_t *ip6; 12127c478bd9Sstevel@tonic-gate 1213ab25eeb5Syz ip6 = (ip6_t *)ip; 12147c478bd9Sstevel@tonic-gate ip6->ip6_vfc = 0x60; 12157c478bd9Sstevel@tonic-gate ip6->ip6_hlim = 127; 1216ab25eeb5Syz fnew.fin_v = 6; 1217ab25eeb5Syz hlen = sizeof(*ip6); 1218923d6102Szf fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen; 12197c478bd9Sstevel@tonic-gate } else 12207c478bd9Sstevel@tonic-gate #endif 12217c478bd9Sstevel@tonic-gate { 1222ab25eeb5Syz fnew.fin_v = 4; 12237c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 10 12247c478bd9Sstevel@tonic-gate ip->ip_ttl = 255; 1225f4b3ec61Sdh if (net_getpmtuenabled(ifs->ifs_ipf_ipv4) == 1) 1226381a2a9aSdr ip->ip_off = htons(IP_DF); 12277c478bd9Sstevel@tonic-gate #else 1228ab25eeb5Syz if (ip_ttl_ptr != NULL) 1229ab25eeb5Syz ip->ip_ttl = (u_char)(*ip_ttl_ptr); 1230ab25eeb5Syz else 1231ab25eeb5Syz ip->ip_ttl = 63; 1232ab25eeb5Syz if (ip_mtudisc != NULL) 1233ab25eeb5Syz ip->ip_off = htons(*ip_mtudisc ? IP_DF : 0); 1234ab25eeb5Syz else 1235ab25eeb5Syz ip->ip_off = htons(IP_DF); 12367c478bd9Sstevel@tonic-gate #endif 1237ab25eeb5Syz /* 1238ab25eeb5Syz * The dance with byte order and ip_len/ip_off is because in 1239ab25eeb5Syz * fr_fastroute, it expects them to be in host byte order but 1240ab25eeb5Syz * ipf_cksum expects them to be in network byte order. 1241ab25eeb5Syz */ 1242ab25eeb5Syz ip->ip_len = htons(ip->ip_len); 12437c478bd9Sstevel@tonic-gate ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip)); 1244ab25eeb5Syz ip->ip_len = ntohs(ip->ip_len); 1245ab25eeb5Syz ip->ip_off = ntohs(ip->ip_off); 1246ab25eeb5Syz hlen = sizeof(*ip); 1247923d6102Szf fnew.fin_plen = ip->ip_len; 12487c478bd9Sstevel@tonic-gate } 1249ab25eeb5Syz 1250ab25eeb5Syz qpip = fin->fin_qpi; 1251ab25eeb5Syz qpi.qpi_off = 0; 1252381a2a9aSdr qpi.qpi_ill = qpip->qpi_ill; 1253ab25eeb5Syz qpi.qpi_m = m; 1254ab25eeb5Syz qpi.qpi_data = ip; 1255ab25eeb5Syz fnew.fin_qpi = &qpi; 1256ab25eeb5Syz fnew.fin_ifp = fin->fin_ifp; 1257ab25eeb5Syz fnew.fin_flx = FI_NOCKSUM; 1258ab25eeb5Syz fnew.fin_m = m; 125990907f62SJohn Ojemann fnew.fin_qfm = m; 1260ab25eeb5Syz fnew.fin_ip = ip; 1261ab25eeb5Syz fnew.fin_mp = mpp; 1262ab25eeb5Syz fnew.fin_hlen = hlen; 1263ab25eeb5Syz fnew.fin_dp = (char *)ip + hlen; 1264f4b3ec61Sdh fnew.fin_ifs = fin->fin_ifs; 1265ab25eeb5Syz (void) fr_makefrip(hlen, ip, &fnew); 1266ab25eeb5Syz 1267ab25eeb5Syz i = fr_fastroute(m, mpp, &fnew, NULL); 12687c478bd9Sstevel@tonic-gate return i; 12697c478bd9Sstevel@tonic-gate } 12707c478bd9Sstevel@tonic-gate 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate int fr_send_icmp_err(type, fin, dst) 12737c478bd9Sstevel@tonic-gate int type; 12747c478bd9Sstevel@tonic-gate fr_info_t *fin; 12757c478bd9Sstevel@tonic-gate int dst; 12767c478bd9Sstevel@tonic-gate { 12777c478bd9Sstevel@tonic-gate struct in_addr dst4; 12787c478bd9Sstevel@tonic-gate struct icmp *icmp; 1279ab25eeb5Syz qpktinfo_t *qpi; 12807c478bd9Sstevel@tonic-gate int hlen, code; 1281381a2a9aSdr phy_if_t phy; 12827c478bd9Sstevel@tonic-gate u_short sz; 12837c478bd9Sstevel@tonic-gate #ifdef USE_INET6 12847c478bd9Sstevel@tonic-gate mblk_t *mb; 12857c478bd9Sstevel@tonic-gate #endif 12867c478bd9Sstevel@tonic-gate mblk_t *m; 12877c478bd9Sstevel@tonic-gate #ifdef USE_INET6 12887c478bd9Sstevel@tonic-gate ip6_t *ip6; 12897c478bd9Sstevel@tonic-gate #endif 12907c478bd9Sstevel@tonic-gate ip_t *ip; 1291f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 12927c478bd9Sstevel@tonic-gate 12937c478bd9Sstevel@tonic-gate if ((type < 0) || (type > ICMP_MAXTYPE)) 12947c478bd9Sstevel@tonic-gate return -1; 12957c478bd9Sstevel@tonic-gate 12967c478bd9Sstevel@tonic-gate code = fin->fin_icode; 12977c478bd9Sstevel@tonic-gate #ifdef USE_INET6 129833f2fefdSDarren Reed if ((code < 0) || (code >= ICMP_MAX_UNREACH)) 12997c478bd9Sstevel@tonic-gate return -1; 13007c478bd9Sstevel@tonic-gate #endif 13017c478bd9Sstevel@tonic-gate 13027c478bd9Sstevel@tonic-gate #ifndef IPFILTER_CKSUM 13037c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 13047c478bd9Sstevel@tonic-gate return -1; 13057c478bd9Sstevel@tonic-gate #endif 13067c478bd9Sstevel@tonic-gate 1307ab25eeb5Syz qpi = fin->fin_qpi; 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate #ifdef USE_INET6 13107c478bd9Sstevel@tonic-gate mb = fin->fin_qfm; 13117c478bd9Sstevel@tonic-gate 13127c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 13137c478bd9Sstevel@tonic-gate sz = sizeof(ip6_t); 13147c478bd9Sstevel@tonic-gate sz += MIN(mb->b_wptr - mb->b_rptr, 512); 13157c478bd9Sstevel@tonic-gate hlen = sizeof(ip6_t); 13167c478bd9Sstevel@tonic-gate type = icmptoicmp6types[type]; 13177c478bd9Sstevel@tonic-gate if (type == ICMP6_DST_UNREACH) 13187c478bd9Sstevel@tonic-gate code = icmptoicmp6unreach[code]; 13197c478bd9Sstevel@tonic-gate } else 13207c478bd9Sstevel@tonic-gate #endif 13217c478bd9Sstevel@tonic-gate { 13227c478bd9Sstevel@tonic-gate if ((fin->fin_p == IPPROTO_ICMP) && 13237c478bd9Sstevel@tonic-gate !(fin->fin_flx & FI_SHORT)) 13247c478bd9Sstevel@tonic-gate switch (ntohs(fin->fin_data[0]) >> 8) 13257c478bd9Sstevel@tonic-gate { 13267c478bd9Sstevel@tonic-gate case ICMP_ECHO : 13277c478bd9Sstevel@tonic-gate case ICMP_TSTAMP : 13287c478bd9Sstevel@tonic-gate case ICMP_IREQ : 13297c478bd9Sstevel@tonic-gate case ICMP_MASKREQ : 13307c478bd9Sstevel@tonic-gate break; 13317c478bd9Sstevel@tonic-gate default : 13327c478bd9Sstevel@tonic-gate return 0; 13337c478bd9Sstevel@tonic-gate } 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate sz = sizeof(ip_t) * 2; 13367c478bd9Sstevel@tonic-gate sz += 8; /* 64 bits of data */ 13377c478bd9Sstevel@tonic-gate hlen = sizeof(ip_t); 13387c478bd9Sstevel@tonic-gate } 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate sz += offsetof(struct icmp, icmp_ip); 13417c478bd9Sstevel@tonic-gate if ((m = (mblk_t *)allocb((size_t)sz + 64, BPRI_HI)) == NULL) 13427c478bd9Sstevel@tonic-gate return -1; 13437c478bd9Sstevel@tonic-gate MTYPE(m) = M_DATA; 13447c478bd9Sstevel@tonic-gate m->b_rptr += 64; 13457c478bd9Sstevel@tonic-gate m->b_wptr = m->b_rptr + sz; 13467c478bd9Sstevel@tonic-gate bzero((char *)m->b_rptr, (size_t)sz); 1347ab25eeb5Syz ip = (ip_t *)m->b_rptr; 1348ab25eeb5Syz ip->ip_v = fin->fin_v; 13497c478bd9Sstevel@tonic-gate icmp = (struct icmp *)(m->b_rptr + hlen); 13507c478bd9Sstevel@tonic-gate icmp->icmp_type = type & 0xff; 13517c478bd9Sstevel@tonic-gate icmp->icmp_code = code & 0xff; 1352381a2a9aSdr phy = (phy_if_t)qpi->qpi_ill; 1353381a2a9aSdr if (type == ICMP_UNREACH && (phy != 0) && 13547c478bd9Sstevel@tonic-gate fin->fin_icode == ICMP_UNREACH_NEEDFRAG) 1355f4b3ec61Sdh icmp->icmp_nextmtu = net_getmtu(ifs->ifs_ipf_ipv4, phy,0 ); 13567c478bd9Sstevel@tonic-gate 13577c478bd9Sstevel@tonic-gate #ifdef USE_INET6 13587c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 13597c478bd9Sstevel@tonic-gate struct in6_addr dst6; 13607c478bd9Sstevel@tonic-gate int csz; 13617c478bd9Sstevel@tonic-gate 13627c478bd9Sstevel@tonic-gate if (dst == 0) { 1363f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1364f4b3ec61Sdh 1365381a2a9aSdr if (fr_ifpaddr(6, FRI_NORMAL, (void *)phy, 1366f4b3ec61Sdh (void *)&dst6, NULL, ifs) == -1) { 13677c478bd9Sstevel@tonic-gate FREE_MB_T(m); 13687c478bd9Sstevel@tonic-gate return -1; 13697c478bd9Sstevel@tonic-gate } 13707c478bd9Sstevel@tonic-gate } else 1371d6c23f6fSyx dst6 = fin->fin_dst6.in6; 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate csz = sz; 13747c478bd9Sstevel@tonic-gate sz -= sizeof(ip6_t); 13757c478bd9Sstevel@tonic-gate ip6 = (ip6_t *)m->b_rptr; 13767663b816Sml ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 13777c478bd9Sstevel@tonic-gate ip6->ip6_plen = htons((u_short)sz); 13787c478bd9Sstevel@tonic-gate ip6->ip6_nxt = IPPROTO_ICMPV6; 13797c478bd9Sstevel@tonic-gate ip6->ip6_src = dst6; 1380d6c23f6fSyx ip6->ip6_dst = fin->fin_src6.in6; 13817c478bd9Sstevel@tonic-gate sz -= offsetof(struct icmp, icmp_ip); 13827c478bd9Sstevel@tonic-gate bcopy((char *)mb->b_rptr, (char *)&icmp->icmp_ip, sz); 13837c478bd9Sstevel@tonic-gate icmp->icmp_cksum = csz - sizeof(ip6_t); 13847c478bd9Sstevel@tonic-gate } else 13857c478bd9Sstevel@tonic-gate #endif 13867c478bd9Sstevel@tonic-gate { 13877c478bd9Sstevel@tonic-gate ip->ip_hl = sizeof(*ip) >> 2; 13887c478bd9Sstevel@tonic-gate ip->ip_p = IPPROTO_ICMP; 13897c478bd9Sstevel@tonic-gate ip->ip_id = fin->fin_ip->ip_id; 13907c478bd9Sstevel@tonic-gate ip->ip_tos = fin->fin_ip->ip_tos; 139137b40788Sekozlow ip->ip_len = (u_short)sz; 13927c478bd9Sstevel@tonic-gate if (dst == 0) { 1393f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1394f4b3ec61Sdh 1395381a2a9aSdr if (fr_ifpaddr(4, FRI_NORMAL, (void *)phy, 1396f4b3ec61Sdh (void *)&dst4, NULL, ifs) == -1) { 13977c478bd9Sstevel@tonic-gate FREE_MB_T(m); 13987c478bd9Sstevel@tonic-gate return -1; 13997c478bd9Sstevel@tonic-gate } 1400381a2a9aSdr } else { 14017c478bd9Sstevel@tonic-gate dst4 = fin->fin_dst; 1402381a2a9aSdr } 14037c478bd9Sstevel@tonic-gate ip->ip_src = dst4; 14047c478bd9Sstevel@tonic-gate ip->ip_dst = fin->fin_src; 14057c478bd9Sstevel@tonic-gate bcopy((char *)fin->fin_ip, (char *)&icmp->icmp_ip, 14067c478bd9Sstevel@tonic-gate sizeof(*fin->fin_ip)); 14077c478bd9Sstevel@tonic-gate bcopy((char *)fin->fin_ip + fin->fin_hlen, 14087c478bd9Sstevel@tonic-gate (char *)&icmp->icmp_ip + sizeof(*fin->fin_ip), 8); 14097663b816Sml icmp->icmp_ip.ip_len = htons(icmp->icmp_ip.ip_len); 1410ab25eeb5Syz icmp->icmp_ip.ip_off = htons(icmp->icmp_ip.ip_off); 14117c478bd9Sstevel@tonic-gate icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 14127c478bd9Sstevel@tonic-gate sz - sizeof(ip_t)); 14137c478bd9Sstevel@tonic-gate } 14147c478bd9Sstevel@tonic-gate 14157c478bd9Sstevel@tonic-gate /* 14167c478bd9Sstevel@tonic-gate * Need to exit out of these so we don't recursively call rw_enter 14177c478bd9Sstevel@tonic-gate * from fr_qout. 14187c478bd9Sstevel@tonic-gate */ 1419ab25eeb5Syz return fr_send_ip(fin, m, &m); 14207c478bd9Sstevel@tonic-gate } 14217c478bd9Sstevel@tonic-gate 14227c478bd9Sstevel@tonic-gate #include <sys/time.h> 14237c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 14247c478bd9Sstevel@tonic-gate 14257c478bd9Sstevel@tonic-gate #ifndef _KERNEL 14267c478bd9Sstevel@tonic-gate #include <stdio.h> 14277c478bd9Sstevel@tonic-gate #endif 14287c478bd9Sstevel@tonic-gate 14297c478bd9Sstevel@tonic-gate /* 143072680cf5SDarren Reed * Return the first IP Address associated with an interface 143172680cf5SDarren Reed * For IPv6, we walk through the list of logical interfaces and return 143272680cf5SDarren Reed * the address of the first one that isn't a link-local interface. 143372680cf5SDarren Reed * We can't assume that it is :1 because another link-local address 143472680cf5SDarren Reed * may have been assigned there. 14357c478bd9Sstevel@tonic-gate */ 14367c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1437f4b3ec61Sdh int fr_ifpaddr(v, atype, ifptr, inp, inpmask, ifs) 14387c478bd9Sstevel@tonic-gate int v, atype; 1439381a2a9aSdr void *ifptr; 1440381a2a9aSdr struct in_addr *inp, *inpmask; 1441f4b3ec61Sdh ipf_stack_t *ifs; 14427c478bd9Sstevel@tonic-gate { 1443381a2a9aSdr struct sockaddr_in6 v6addr[2]; 1444381a2a9aSdr struct sockaddr_in v4addr[2]; 1445381a2a9aSdr net_ifaddr_t type[2]; 14467ddc9b1aSDarren Reed net_handle_t net_data; 1447381a2a9aSdr phy_if_t phyif; 1448381a2a9aSdr void *array; 1449381a2a9aSdr 1450381a2a9aSdr switch (v) 1451381a2a9aSdr { 1452381a2a9aSdr case 4: 1453f4b3ec61Sdh net_data = ifs->ifs_ipf_ipv4; 1454381a2a9aSdr array = v4addr; 1455381a2a9aSdr break; 1456381a2a9aSdr case 6: 1457f4b3ec61Sdh net_data = ifs->ifs_ipf_ipv6; 1458381a2a9aSdr array = v6addr; 1459381a2a9aSdr break; 1460381a2a9aSdr default: 1461381a2a9aSdr net_data = NULL; 1462381a2a9aSdr break; 1463381a2a9aSdr } 14647c478bd9Sstevel@tonic-gate 1465381a2a9aSdr if (net_data == NULL) 14667c478bd9Sstevel@tonic-gate return -1; 14677c478bd9Sstevel@tonic-gate 1468381a2a9aSdr phyif = (phy_if_t)ifptr; 1469ab25eeb5Syz 1470ab25eeb5Syz switch (atype) 1471ab25eeb5Syz { 1472ab25eeb5Syz case FRI_PEERADDR : 1473381a2a9aSdr type[0] = NA_PEER; 1474ab25eeb5Syz break; 1475381a2a9aSdr 1476381a2a9aSdr case FRI_BROADCAST : 1477381a2a9aSdr type[0] = NA_BROADCAST; 1478381a2a9aSdr break; 1479381a2a9aSdr 1480ab25eeb5Syz default : 1481381a2a9aSdr type[0] = NA_ADDRESS; 1482ab25eeb5Syz break; 1483ab25eeb5Syz } 14847c478bd9Sstevel@tonic-gate 1485381a2a9aSdr type[1] = NA_NETMASK; 1486381a2a9aSdr 1487381a2a9aSdr if (v == 6) { 148872680cf5SDarren Reed lif_if_t idx = 0; 148972680cf5SDarren Reed 149072680cf5SDarren Reed do { 149172680cf5SDarren Reed idx = net_lifgetnext(net_data, phyif, idx); 149272680cf5SDarren Reed if (net_getlifaddr(net_data, phyif, idx, 2, type, 149372680cf5SDarren Reed array) < 0) 149472680cf5SDarren Reed return -1; 149572680cf5SDarren Reed if (!IN6_IS_ADDR_LINKLOCAL(&v6addr[0].sin6_addr) && 149672680cf5SDarren Reed !IN6_IS_ADDR_MULTICAST(&v6addr[0].sin6_addr)) 149772680cf5SDarren Reed break; 149872680cf5SDarren Reed } while (idx != 0); 149972680cf5SDarren Reed 150072680cf5SDarren Reed if (idx == 0) 150172680cf5SDarren Reed return -1; 150272680cf5SDarren Reed 1503381a2a9aSdr return fr_ifpfillv6addr(atype, &v6addr[0], &v6addr[1], 1504381a2a9aSdr inp, inpmask); 15057c478bd9Sstevel@tonic-gate } 150672680cf5SDarren Reed 150772680cf5SDarren Reed if (net_getlifaddr(net_data, phyif, 0, 2, type, array) < 0) 150872680cf5SDarren Reed return -1; 150972680cf5SDarren Reed 1510381a2a9aSdr return fr_ifpfillv4addr(atype, &v4addr[0], &v4addr[1], inp, inpmask); 15117c478bd9Sstevel@tonic-gate } 15127c478bd9Sstevel@tonic-gate 15137c478bd9Sstevel@tonic-gate 15147c478bd9Sstevel@tonic-gate u_32_t fr_newisn(fin) 15157c478bd9Sstevel@tonic-gate fr_info_t *fin; 15167c478bd9Sstevel@tonic-gate { 15177c478bd9Sstevel@tonic-gate static int iss_seq_off = 0; 15187c478bd9Sstevel@tonic-gate u_char hash[16]; 15197c478bd9Sstevel@tonic-gate u_32_t newiss; 15207c478bd9Sstevel@tonic-gate MD5_CTX ctx; 1521f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 15227c478bd9Sstevel@tonic-gate 15237c478bd9Sstevel@tonic-gate /* 15247c478bd9Sstevel@tonic-gate * Compute the base value of the ISS. It is a hash 15257c478bd9Sstevel@tonic-gate * of (saddr, sport, daddr, dport, secret). 15267c478bd9Sstevel@tonic-gate */ 15277c478bd9Sstevel@tonic-gate MD5Init(&ctx); 15287c478bd9Sstevel@tonic-gate 15297c478bd9Sstevel@tonic-gate MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 15307c478bd9Sstevel@tonic-gate sizeof(fin->fin_fi.fi_src)); 15317c478bd9Sstevel@tonic-gate MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 15327c478bd9Sstevel@tonic-gate sizeof(fin->fin_fi.fi_dst)); 15337c478bd9Sstevel@tonic-gate MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 15347c478bd9Sstevel@tonic-gate 1535f4b3ec61Sdh MD5Update(&ctx, ifs->ifs_ipf_iss_secret, sizeof(ifs->ifs_ipf_iss_secret)); 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate MD5Final(hash, &ctx); 15387c478bd9Sstevel@tonic-gate 15397c478bd9Sstevel@tonic-gate bcopy(hash, &newiss, sizeof(newiss)); 15407c478bd9Sstevel@tonic-gate 15417c478bd9Sstevel@tonic-gate /* 15427c478bd9Sstevel@tonic-gate * Now increment our "timer", and add it in to 15437c478bd9Sstevel@tonic-gate * the computed value. 15447c478bd9Sstevel@tonic-gate * 15457c478bd9Sstevel@tonic-gate * XXX Use `addin'? 15467c478bd9Sstevel@tonic-gate * XXX TCP_ISSINCR too large to use? 15477c478bd9Sstevel@tonic-gate */ 15487c478bd9Sstevel@tonic-gate iss_seq_off += 0x00010000; 15497c478bd9Sstevel@tonic-gate newiss += iss_seq_off; 15507c478bd9Sstevel@tonic-gate return newiss; 15517c478bd9Sstevel@tonic-gate } 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate 15547c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 15557c478bd9Sstevel@tonic-gate /* Function: fr_nextipid */ 15567c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 15577c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 15587c478bd9Sstevel@tonic-gate /* */ 15597c478bd9Sstevel@tonic-gate /* Returns the next IPv4 ID to use for this packet. */ 15607c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 1561ab25eeb5Syz u_short fr_nextipid(fin) 15627c478bd9Sstevel@tonic-gate fr_info_t *fin; 15637c478bd9Sstevel@tonic-gate { 15647c478bd9Sstevel@tonic-gate static u_short ipid = 0; 15657c478bd9Sstevel@tonic-gate u_short id; 1566f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 15677c478bd9Sstevel@tonic-gate 1568f4b3ec61Sdh MUTEX_ENTER(&ifs->ifs_ipf_rw); 156933f2fefdSDarren Reed if (fin->fin_pktnum != 0) { 157033f2fefdSDarren Reed id = fin->fin_pktnum & 0xffff; 157133f2fefdSDarren Reed } else { 15727c478bd9Sstevel@tonic-gate id = ipid++; 157333f2fefdSDarren Reed } 1574f4b3ec61Sdh MUTEX_EXIT(&ifs->ifs_ipf_rw); 15757c478bd9Sstevel@tonic-gate 15767c478bd9Sstevel@tonic-gate return id; 15777c478bd9Sstevel@tonic-gate } 15787c478bd9Sstevel@tonic-gate 15797c478bd9Sstevel@tonic-gate 15807c478bd9Sstevel@tonic-gate #ifndef IPFILTER_CKSUM 15817c478bd9Sstevel@tonic-gate /* ARGSUSED */ 15827c478bd9Sstevel@tonic-gate #endif 15837c478bd9Sstevel@tonic-gate INLINE void fr_checkv4sum(fin) 15847c478bd9Sstevel@tonic-gate fr_info_t *fin; 15857c478bd9Sstevel@tonic-gate { 15867c478bd9Sstevel@tonic-gate #ifdef IPFILTER_CKSUM 15877c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 15887c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_BAD; 15897c478bd9Sstevel@tonic-gate #endif 15907c478bd9Sstevel@tonic-gate } 15917c478bd9Sstevel@tonic-gate 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate #ifdef USE_INET6 1594ab25eeb5Syz # ifndef IPFILTER_CKSUM 15957663b816Sml /* ARGSUSED */ 1596ab25eeb5Syz # endif 15977c478bd9Sstevel@tonic-gate INLINE void fr_checkv6sum(fin) 15987c478bd9Sstevel@tonic-gate fr_info_t *fin; 15997c478bd9Sstevel@tonic-gate { 16007c478bd9Sstevel@tonic-gate # ifdef IPFILTER_CKSUM 16017c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 16027c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_BAD; 16037c478bd9Sstevel@tonic-gate # endif 16047c478bd9Sstevel@tonic-gate } 16057c478bd9Sstevel@tonic-gate #endif /* USE_INET6 */ 1606ab25eeb5Syz 1607ab25eeb5Syz 1608ab25eeb5Syz #if (SOLARIS2 < 7) 1609ab25eeb5Syz void fr_slowtimer() 1610ab25eeb5Syz #else 1611ab25eeb5Syz /*ARGSUSED*/ 1612f4b3ec61Sdh void fr_slowtimer __P((void *arg)) 1613ab25eeb5Syz #endif 1614ab25eeb5Syz { 1615f4b3ec61Sdh ipf_stack_t *ifs = arg; 1616ab25eeb5Syz 161744aaa2b6Sjojemann READ_ENTER(&ifs->ifs_ipf_global); 161844aaa2b6Sjojemann if (ifs->ifs_fr_running != 1) { 161944aaa2b6Sjojemann ifs->ifs_fr_timer_id = NULL; 1620f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 1621ab25eeb5Syz return; 1622ab25eeb5Syz } 1623fd636508Szf ipf_expiretokens(ifs); 1624f4b3ec61Sdh fr_fragexpire(ifs); 1625f4b3ec61Sdh fr_timeoutstate(ifs); 1626f4b3ec61Sdh fr_natexpire(ifs); 1627f4b3ec61Sdh fr_authexpire(ifs); 1628f4b3ec61Sdh ifs->ifs_fr_ticks++; 162944aaa2b6Sjojemann if (ifs->ifs_fr_running == 1) 1630f4b3ec61Sdh ifs->ifs_fr_timer_id = timeout(fr_slowtimer, arg, 1631f4b3ec61Sdh drv_usectohz(500000)); 1632ab25eeb5Syz else 1633f4b3ec61Sdh ifs->ifs_fr_timer_id = NULL; 1634f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 1635ab25eeb5Syz } 1636ab25eeb5Syz 1637ab25eeb5Syz 1638381a2a9aSdr /* ------------------------------------------------------------------------ */ 1639381a2a9aSdr /* Function: fr_pullup */ 1640381a2a9aSdr /* Returns: NULL == pullup failed, else pointer to protocol header */ 1641381a2a9aSdr /* Parameters: m(I) - pointer to buffer where data packet starts */ 1642381a2a9aSdr /* fin(I) - pointer to packet information */ 1643381a2a9aSdr /* len(I) - number of bytes to pullup */ 1644381a2a9aSdr /* */ 1645381a2a9aSdr /* Attempt to move at least len bytes (from the start of the buffer) into a */ 1646381a2a9aSdr /* single buffer for ease of access. Operating system native functions are */ 1647381a2a9aSdr /* used to manage buffers - if necessary. If the entire packet ends up in */ 1648381a2a9aSdr /* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */ 1649381a2a9aSdr /* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ 1650381a2a9aSdr /* and ONLY if the pullup succeeds. */ 1651381a2a9aSdr /* */ 1652381a2a9aSdr /* We assume that 'min' is a pointer to a buffer that is part of the chain */ 1653381a2a9aSdr /* of buffers that starts at *fin->fin_mp. */ 1654381a2a9aSdr /* ------------------------------------------------------------------------ */ 1655381a2a9aSdr void *fr_pullup(min, fin, len) 1656381a2a9aSdr mb_t *min; 1657381a2a9aSdr fr_info_t *fin; 1658381a2a9aSdr int len; 1659381a2a9aSdr { 1660381a2a9aSdr qpktinfo_t *qpi = fin->fin_qpi; 1661381a2a9aSdr int out = fin->fin_out, dpoff, ipoff; 1662381a2a9aSdr mb_t *m = min, *m1, *m2; 1663381a2a9aSdr char *ip; 166408ee25aeSdr uint32_t start, stuff, end, value, flags; 1665f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1666381a2a9aSdr 1667381a2a9aSdr if (m == NULL) 1668381a2a9aSdr return NULL; 1669381a2a9aSdr 1670381a2a9aSdr ip = (char *)fin->fin_ip; 1671381a2a9aSdr if ((fin->fin_flx & FI_COALESCE) != 0) 1672381a2a9aSdr return ip; 1673381a2a9aSdr 1674381a2a9aSdr ipoff = fin->fin_ipoff; 1675381a2a9aSdr if (fin->fin_dp != NULL) 1676381a2a9aSdr dpoff = (char *)fin->fin_dp - (char *)ip; 1677381a2a9aSdr else 1678381a2a9aSdr dpoff = 0; 1679381a2a9aSdr 168040cdc2e8SAlexandr Nedvedicky if (M_LEN(m) < len + ipoff) { 1681381a2a9aSdr 1682381a2a9aSdr /* 1683381a2a9aSdr * pfil_precheck ensures the IP header is on a 32bit 1684381a2a9aSdr * aligned address so simply fail if that isn't currently 1685381a2a9aSdr * the case (should never happen). 1686381a2a9aSdr */ 1687381a2a9aSdr int inc = 0; 1688381a2a9aSdr 1689381a2a9aSdr if (ipoff > 0) { 1690381a2a9aSdr if ((ipoff & 3) != 0) { 1691381a2a9aSdr inc = 4 - (ipoff & 3); 1692381a2a9aSdr if (m->b_rptr - inc >= m->b_datap->db_base) 1693381a2a9aSdr m->b_rptr -= inc; 1694381a2a9aSdr else 1695381a2a9aSdr inc = 0; 1696381a2a9aSdr } 1697381a2a9aSdr } 1698381a2a9aSdr 1699381a2a9aSdr /* 1700381a2a9aSdr * XXX This is here as a work around for a bug with DEBUG 1701381a2a9aSdr * XXX Solaris kernels. The problem is b_prev is used by IP 1702381a2a9aSdr * XXX code as a way to stash the phyint_index for a packet, 1703381a2a9aSdr * XXX this doesn't get reset by IP but freeb does an ASSERT() 1704381a2a9aSdr * XXX for both of these to be NULL. See 6442390. 1705381a2a9aSdr */ 1706381a2a9aSdr m1 = m; 1707381a2a9aSdr m2 = m->b_prev; 1708381a2a9aSdr 1709381a2a9aSdr do { 1710381a2a9aSdr m1->b_next = NULL; 1711381a2a9aSdr m1->b_prev = NULL; 1712381a2a9aSdr m1 = m1->b_cont; 1713381a2a9aSdr } while (m1); 171408ee25aeSdr 171508ee25aeSdr /* 171608ee25aeSdr * Need to preserve checksum information by copying them 171708ee25aeSdr * to newmp which heads the pulluped message. 171808ee25aeSdr */ 1719*ec71f88eSPatrick Mooney mac_hcksum_get(m, &start, &stuff, &end, &value, &flags); 172008ee25aeSdr 1721381a2a9aSdr if (pullupmsg(m, len + ipoff + inc) == 0) { 1722f4b3ec61Sdh ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[1]); 1723381a2a9aSdr FREE_MB_T(*fin->fin_mp); 1724381a2a9aSdr *fin->fin_mp = NULL; 1725381a2a9aSdr fin->fin_m = NULL; 1726381a2a9aSdr fin->fin_ip = NULL; 1727381a2a9aSdr fin->fin_dp = NULL; 1728381a2a9aSdr qpi->qpi_data = NULL; 1729381a2a9aSdr return NULL; 1730381a2a9aSdr } 173108ee25aeSdr 1732*ec71f88eSPatrick Mooney mac_hcksum_set(m, start, stuff, end, value, flags); 173308ee25aeSdr 1734381a2a9aSdr m->b_prev = m2; 1735381a2a9aSdr m->b_rptr += inc; 1736381a2a9aSdr fin->fin_m = m; 1737381a2a9aSdr ip = MTOD(m, char *) + ipoff; 1738381a2a9aSdr qpi->qpi_data = ip; 1739381a2a9aSdr } 1740381a2a9aSdr 1741f4b3ec61Sdh ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[0]); 1742381a2a9aSdr fin->fin_ip = (ip_t *)ip; 1743381a2a9aSdr if (fin->fin_dp != NULL) 1744381a2a9aSdr fin->fin_dp = (char *)fin->fin_ip + dpoff; 1745381a2a9aSdr 1746381a2a9aSdr if (len == fin->fin_plen) 1747381a2a9aSdr fin->fin_flx |= FI_COALESCE; 1748381a2a9aSdr return ip; 1749381a2a9aSdr } 1750381a2a9aSdr 1751381a2a9aSdr 1752ab25eeb5Syz /* 1753381a2a9aSdr * Function: fr_verifysrc 1754381a2a9aSdr * Returns: int (really boolean) 1755381a2a9aSdr * Parameters: fin - packet information 1756381a2a9aSdr * 1757381a2a9aSdr * Check whether the packet has a valid source address for the interface on 1758381a2a9aSdr * which the packet arrived, implementing the "fr_chksrc" feature. 1759381a2a9aSdr * Returns true iff the packet's source address is valid. 1760381a2a9aSdr */ 1761381a2a9aSdr int fr_verifysrc(fin) 1762381a2a9aSdr fr_info_t *fin; 1763381a2a9aSdr { 17647ddc9b1aSDarren Reed net_handle_t net_data_p; 1765381a2a9aSdr phy_if_t phy_ifdata_routeto; 1766381a2a9aSdr struct sockaddr sin; 1767f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1768381a2a9aSdr 1769381a2a9aSdr if (fin->fin_v == 4) { 1770f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv4; 1771381a2a9aSdr } else if (fin->fin_v == 6) { 1772f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv6; 1773381a2a9aSdr } else { 1774381a2a9aSdr return (0); 1775381a2a9aSdr } 1776381a2a9aSdr 1777381a2a9aSdr /* Get the index corresponding to the if name */ 1778381a2a9aSdr sin.sa_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 1779381a2a9aSdr bcopy(&fin->fin_saddr, &sin.sa_data, sizeof (struct in_addr)); 17807ddc9b1aSDarren Reed phy_ifdata_routeto = net_routeto(net_data_p, &sin, NULL); 1781381a2a9aSdr 1782381a2a9aSdr return (((phy_if_t)fin->fin_ifp == phy_ifdata_routeto) ? 1 : 0); 1783381a2a9aSdr } 1784381a2a9aSdr 1785546c3aa8SJerry Jelinek /* 1786546c3aa8SJerry Jelinek * Return true only if forwarding is enabled on the interface. 1787546c3aa8SJerry Jelinek */ 1788546c3aa8SJerry Jelinek static int 1789546c3aa8SJerry Jelinek fr_forwarding_enabled(phy_if_t phyif, net_handle_t ndp) 1790546c3aa8SJerry Jelinek { 1791546c3aa8SJerry Jelinek lif_if_t lif; 1792546c3aa8SJerry Jelinek 1793546c3aa8SJerry Jelinek for (lif = net_lifgetnext(ndp, phyif, 0); lif > 0; 1794546c3aa8SJerry Jelinek lif = net_lifgetnext(ndp, phyif, lif)) { 1795546c3aa8SJerry Jelinek int res; 1796546c3aa8SJerry Jelinek uint64_t flags; 1797546c3aa8SJerry Jelinek 1798546c3aa8SJerry Jelinek res = net_getlifflags(ndp, phyif, lif, &flags); 1799546c3aa8SJerry Jelinek if (res != 0) 1800546c3aa8SJerry Jelinek return (0); 1801546c3aa8SJerry Jelinek if (flags & IFF_ROUTER) 1802546c3aa8SJerry Jelinek return (1); 1803546c3aa8SJerry Jelinek } 1804546c3aa8SJerry Jelinek 1805546c3aa8SJerry Jelinek return (0); 1806546c3aa8SJerry Jelinek } 1807381a2a9aSdr 1808381a2a9aSdr /* 1809381a2a9aSdr * Function: fr_fastroute 1810381a2a9aSdr * Returns: 0: success; 1811381a2a9aSdr * -1: failed 1812ab25eeb5Syz * Parameters: 1813381a2a9aSdr * mb: the message block where ip head starts 1814381a2a9aSdr * mpp: the pointer to the pointer of the orignal 1815381a2a9aSdr * packet message 1816381a2a9aSdr * fin: packet information 1817381a2a9aSdr * fdp: destination interface information 1818381a2a9aSdr * if it is NULL, no interface information provided. 1819ab25eeb5Syz * 1820ab25eeb5Syz * This function is for fastroute/to/dup-to rules. It calls 1821ab25eeb5Syz * pfil_make_lay2_packet to search route, make lay-2 header 1822ab25eeb5Syz * ,and identify output queue for the IP packet. 1823ab25eeb5Syz * The destination address depends on the following conditions: 1824ab25eeb5Syz * 1: for fastroute rule, fdp is passed in as NULL, so the 1825381a2a9aSdr * destination address is the IP Packet's destination address 1826ab25eeb5Syz * 2: for to/dup-to rule, if an ip address is specified after 1827381a2a9aSdr * the interface name, this address is the as destination 1828381a2a9aSdr * address. Otherwise IP Packet's destination address is used 1829ab25eeb5Syz */ 1830ab25eeb5Syz int fr_fastroute(mb, mpp, fin, fdp) 1831ab25eeb5Syz mblk_t *mb, **mpp; 1832ab25eeb5Syz fr_info_t *fin; 1833ab25eeb5Syz frdest_t *fdp; 1834ab25eeb5Syz { 18357ddc9b1aSDarren Reed net_handle_t net_data_p; 18367ddc9b1aSDarren Reed net_inject_t *inj; 1837ab25eeb5Syz mblk_t *mp = NULL; 1838381a2a9aSdr frentry_t *fr = fin->fin_fr; 1839ab25eeb5Syz qpktinfo_t *qpi; 1840ab25eeb5Syz ip_t *ip; 1841381a2a9aSdr 1842381a2a9aSdr struct sockaddr_in *sin; 1843381a2a9aSdr struct sockaddr_in6 *sin6; 1844381a2a9aSdr struct sockaddr *sinp; 1845f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1846ab25eeb5Syz #ifndef sparc 1847ab25eeb5Syz u_short __iplen, __ipoff; 1848ab25eeb5Syz #endif 1849381a2a9aSdr 1850381a2a9aSdr if (fin->fin_v == 4) { 1851f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv4; 1852381a2a9aSdr } else if (fin->fin_v == 6) { 1853f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv6; 1854381a2a9aSdr } else { 1855381a2a9aSdr return (-1); 1856381a2a9aSdr } 1857381a2a9aSdr 1858546c3aa8SJerry Jelinek /* Check the src here, fin_ifp is the src interface. */ 1859546c3aa8SJerry Jelinek if (!fr_forwarding_enabled((phy_if_t)fin->fin_ifp, net_data_p)) 1860546c3aa8SJerry Jelinek return (-1); 1861546c3aa8SJerry Jelinek 18627ddc9b1aSDarren Reed inj = net_inject_alloc(NETINFO_VERSION); 18637ddc9b1aSDarren Reed if (inj == NULL) 18647ddc9b1aSDarren Reed return -1; 18657ddc9b1aSDarren Reed 1866ab25eeb5Syz ip = fin->fin_ip; 1867ab25eeb5Syz qpi = fin->fin_qpi; 1868ab25eeb5Syz 1869ab25eeb5Syz /* 1870ab25eeb5Syz * If this is a duplicate mblk then we want ip to point at that 1871ab25eeb5Syz * data, not the original, if and only if it is already pointing at 1872ab25eeb5Syz * the current mblk data. 1873381a2a9aSdr * 1874381a2a9aSdr * Otherwise, if it's not a duplicate, and we're not already pointing 1875e6c6c1faSyz * at the current mblk data, then we want to ensure that the data 1876e6c6c1faSyz * points at ip. 1877ab25eeb5Syz */ 1878381a2a9aSdr 1879381a2a9aSdr if ((ip == (ip_t *)qpi->qpi_m->b_rptr) && (qpi->qpi_m != mb)) { 1880ab25eeb5Syz ip = (ip_t *)mb->b_rptr; 1881381a2a9aSdr } else if ((qpi->qpi_m == mb) && (ip != (ip_t *)qpi->qpi_m->b_rptr)) { 1882381a2a9aSdr qpi->qpi_m->b_rptr = (uchar_t *)ip; 1883e6c6c1faSyz qpi->qpi_off = 0; 1884e6c6c1faSyz } 1885ab25eeb5Syz 1886ab25eeb5Syz /* 1887ab25eeb5Syz * If there is another M_PROTO, we don't want it 1888ab25eeb5Syz */ 1889ab25eeb5Syz if (*mpp != mb) { 1890ab25eeb5Syz mp = unlinkb(*mpp); 1891ab25eeb5Syz freeb(*mpp); 1892ab25eeb5Syz *mpp = mp; 1893ab25eeb5Syz } 1894ab25eeb5Syz 18957ddc9b1aSDarren Reed sinp = (struct sockaddr *)&inj->ni_addr; 1896381a2a9aSdr sin = (struct sockaddr_in *)sinp; 1897381a2a9aSdr sin6 = (struct sockaddr_in6 *)sinp; 18987ddc9b1aSDarren Reed bzero((char *)&inj->ni_addr, sizeof (inj->ni_addr)); 18997ddc9b1aSDarren Reed inj->ni_addr.ss_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 19007ddc9b1aSDarren Reed inj->ni_packet = mb; 1901ab25eeb5Syz 1902ab25eeb5Syz /* 1903ab25eeb5Syz * In case we're here due to "to <if>" being used with 1904ab25eeb5Syz * "keep state", check that we're going in the correct 1905ab25eeb5Syz * direction. 1906ab25eeb5Syz */ 1907381a2a9aSdr if (fdp != NULL) { 1908381a2a9aSdr if ((fr != NULL) && (fdp->fd_ifp != NULL) && 1909381a2a9aSdr (fin->fin_rev != 0) && (fdp == &fr->fr_tif)) 1910381a2a9aSdr goto bad_fastroute; 19117ddc9b1aSDarren Reed inj->ni_physical = (phy_if_t)fdp->fd_ifp; 1912ab25eeb5Syz if (fin->fin_v == 4) { 1913381a2a9aSdr sin->sin_addr = fdp->fd_ip; 1914381a2a9aSdr } else { 1915381a2a9aSdr sin6->sin6_addr = fdp->fd_ip6.in6; 1916ab25eeb5Syz } 1917381a2a9aSdr } else { 1918381a2a9aSdr if (fin->fin_v == 4) { 1919381a2a9aSdr sin->sin_addr = ip->ip_dst; 1920381a2a9aSdr } else { 1921381a2a9aSdr sin6->sin6_addr = ((ip6_t *)ip)->ip6_dst; 1922ab25eeb5Syz } 19237ddc9b1aSDarren Reed inj->ni_physical = net_routeto(net_data_p, sinp, NULL); 1924ab25eeb5Syz } 1925ab25eeb5Syz 1926546c3aa8SJerry Jelinek /* we're checking the destinatation here */ 1927546c3aa8SJerry Jelinek if (!fr_forwarding_enabled(inj->ni_physical, net_data_p)) 1928546c3aa8SJerry Jelinek goto bad_fastroute; 1929546c3aa8SJerry Jelinek 1930edd26dc5Sdr /* 1931edd26dc5Sdr * Clear the hardware checksum flags from packets that we are doing 1932edd26dc5Sdr * input processing on as leaving them set will cause the outgoing 1933edd26dc5Sdr * NIC (if it supports hardware checksum) to calculate them anew, 1934edd26dc5Sdr * using the old (correct) checksums as the pseudo value to start 1935edd26dc5Sdr * from. 1936edd26dc5Sdr */ 1937edd26dc5Sdr if (fin->fin_out == 0) { 1938edd26dc5Sdr DB_CKSUMFLAGS(mb) = 0; 1939edd26dc5Sdr } 1940c793af95Ssangeeta 1941381a2a9aSdr *mpp = mb; 1942ab25eeb5Syz 1943381a2a9aSdr if (fin->fin_out == 0) { 1944381a2a9aSdr void *saveifp; 1945381a2a9aSdr u_32_t pass; 1946ab25eeb5Syz 1947381a2a9aSdr saveifp = fin->fin_ifp; 19487ddc9b1aSDarren Reed fin->fin_ifp = (void *)inj->ni_physical; 1949d3675867Sjojemann fin->fin_flx &= ~FI_STATE; 1950381a2a9aSdr fin->fin_out = 1; 1951381a2a9aSdr (void) fr_acctpkt(fin, &pass); 1952381a2a9aSdr fin->fin_fr = NULL; 1953381a2a9aSdr if (!fr || !(fr->fr_flags & FR_RETMASK)) 1954381a2a9aSdr (void) fr_checkstate(fin, &pass); 1955d3675867Sjojemann if (fr_checknatout(fin, NULL) == -1) 1956381a2a9aSdr goto bad_fastroute; 1957381a2a9aSdr fin->fin_out = 0; 1958381a2a9aSdr fin->fin_ifp = saveifp; 1959381a2a9aSdr } 1960381a2a9aSdr #ifndef sparc 1961381a2a9aSdr if (fin->fin_v == 4) { 1962381a2a9aSdr __iplen = (u_short)ip->ip_len, 1963381a2a9aSdr __ipoff = (u_short)ip->ip_off; 1964ab25eeb5Syz 1965381a2a9aSdr ip->ip_len = htons(__iplen); 1966381a2a9aSdr ip->ip_off = htons(__ipoff); 1967381a2a9aSdr } 1968ab25eeb5Syz #endif 1969381a2a9aSdr 1970381a2a9aSdr if (net_data_p) { 19717ddc9b1aSDarren Reed if (net_inject(net_data_p, NI_DIRECT_OUT, inj) < 0) { 19727ddc9b1aSDarren Reed net_inject_free(inj); 1973381a2a9aSdr return (-1); 1974ab25eeb5Syz } 1975ab25eeb5Syz } 1976381a2a9aSdr 1977f4b3ec61Sdh ifs->ifs_fr_frouteok[0]++; 19787ddc9b1aSDarren Reed net_inject_free(inj); 1979381a2a9aSdr return 0; 1980ab25eeb5Syz bad_fastroute: 19817ddc9b1aSDarren Reed net_inject_free(inj); 1982ab25eeb5Syz freemsg(mb); 1983f4b3ec61Sdh ifs->ifs_fr_frouteok[1]++; 1984ab25eeb5Syz return -1; 1985ab25eeb5Syz } 1986ab25eeb5Syz 1987ab25eeb5Syz 1988ab25eeb5Syz /* ------------------------------------------------------------------------ */ 19897ddc9b1aSDarren Reed /* Function: ipf_hook4_out */ 1990381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1991381a2a9aSdr /* Parameters: event(I) - pointer to event */ 1992381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 1993ab25eeb5Syz /* */ 1994381a2a9aSdr /* Calling ipf_hook. */ 1995381a2a9aSdr /* ------------------------------------------------------------------------ */ 1996381a2a9aSdr /*ARGSUSED*/ 19977ddc9b1aSDarren Reed int ipf_hook4_out(hook_event_token_t token, hook_data_t info, void *arg) 1998381a2a9aSdr { 19997ddc9b1aSDarren Reed return ipf_hook(info, 1, 0, arg); 2000cbded9aeSdr } 2001cbded9aeSdr /*ARGSUSED*/ 20027ddc9b1aSDarren Reed int ipf_hook6_out(hook_event_token_t token, hook_data_t info, void *arg) 2003cbded9aeSdr { 20047ddc9b1aSDarren Reed return ipf_hook6(info, 1, 0, arg); 2005381a2a9aSdr } 2006381a2a9aSdr 2007381a2a9aSdr /* ------------------------------------------------------------------------ */ 20087ddc9b1aSDarren Reed /* Function: ipf_hook4_in */ 2009381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 2010381a2a9aSdr /* Parameters: event(I) - pointer to event */ 2011381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 2012ab25eeb5Syz /* */ 2013381a2a9aSdr /* Calling ipf_hook. */ 2014ab25eeb5Syz /* ------------------------------------------------------------------------ */ 2015381a2a9aSdr /*ARGSUSED*/ 20167ddc9b1aSDarren Reed int ipf_hook4_in(hook_event_token_t token, hook_data_t info, void *arg) 2017ab25eeb5Syz { 20187ddc9b1aSDarren Reed return ipf_hook(info, 0, 0, arg); 2019cbded9aeSdr } 2020cbded9aeSdr /*ARGSUSED*/ 20217ddc9b1aSDarren Reed int ipf_hook6_in(hook_event_token_t token, hook_data_t info, void *arg) 2022cbded9aeSdr { 20237ddc9b1aSDarren Reed return ipf_hook6(info, 0, 0, arg); 2024381a2a9aSdr } 2025ab25eeb5Syz 2026ab25eeb5Syz 2027381a2a9aSdr /* ------------------------------------------------------------------------ */ 20287ddc9b1aSDarren Reed /* Function: ipf_hook4_loop_out */ 2029381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 2030381a2a9aSdr /* Parameters: event(I) - pointer to event */ 2031381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 2032381a2a9aSdr /* */ 2033381a2a9aSdr /* Calling ipf_hook. */ 2034381a2a9aSdr /* ------------------------------------------------------------------------ */ 2035381a2a9aSdr /*ARGSUSED*/ 20367ddc9b1aSDarren Reed int ipf_hook4_loop_out(hook_event_token_t token, hook_data_t info, void *arg) 2037cbded9aeSdr { 20387ddc9b1aSDarren Reed return ipf_hook(info, 1, FI_NOCKSUM, arg); 2039cbded9aeSdr } 2040cbded9aeSdr /*ARGSUSED*/ 20417ddc9b1aSDarren Reed int ipf_hook6_loop_out(hook_event_token_t token, hook_data_t info, void *arg) 2042381a2a9aSdr { 20437ddc9b1aSDarren Reed return ipf_hook6(info, 1, FI_NOCKSUM, arg); 2044381a2a9aSdr } 2045ab25eeb5Syz 2046381a2a9aSdr /* ------------------------------------------------------------------------ */ 204740cdc2e8SAlexandr Nedvedicky /* Function: ipf_hook4_loop_in */ 2048381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 2049381a2a9aSdr /* Parameters: event(I) - pointer to event */ 2050381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 2051381a2a9aSdr /* */ 2052381a2a9aSdr /* Calling ipf_hook. */ 2053381a2a9aSdr /* ------------------------------------------------------------------------ */ 2054381a2a9aSdr /*ARGSUSED*/ 205540cdc2e8SAlexandr Nedvedicky int ipf_hook4_loop_in(hook_event_token_t token, hook_data_t info, void *arg) 2056cbded9aeSdr { 20577ddc9b1aSDarren Reed return ipf_hook(info, 0, FI_NOCKSUM, arg); 2058cbded9aeSdr } 2059cbded9aeSdr /*ARGSUSED*/ 20607ddc9b1aSDarren Reed int ipf_hook6_loop_in(hook_event_token_t token, hook_data_t info, void *arg) 2061381a2a9aSdr { 20627ddc9b1aSDarren Reed return ipf_hook6(info, 0, FI_NOCKSUM, arg); 2063381a2a9aSdr } 2064381a2a9aSdr 2065381a2a9aSdr /* ------------------------------------------------------------------------ */ 2066381a2a9aSdr /* Function: ipf_hook */ 2067381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 2068381a2a9aSdr /* Parameters: info(I) - pointer to hook information for firewalling */ 2069381a2a9aSdr /* out(I) - whether packet is going in or out */ 2070381a2a9aSdr /* loopback(I) - whether packet is a loopback packet or not */ 2071381a2a9aSdr /* */ 2072381a2a9aSdr /* Stepping stone function between the IP mainline and IPFilter. Extracts */ 2073381a2a9aSdr /* parameters out of the info structure and forms them up to be useful for */ 2074381a2a9aSdr /* calling ipfilter. */ 2075381a2a9aSdr /* ------------------------------------------------------------------------ */ 20767ddc9b1aSDarren Reed int ipf_hook(hook_data_t info, int out, int loopback, void *arg) 2077381a2a9aSdr { 2078381a2a9aSdr hook_pkt_event_t *fw; 20797ddc9b1aSDarren Reed ipf_stack_t *ifs; 2080381a2a9aSdr qpktinfo_t qpi; 20817ddc9b1aSDarren Reed int rval, hlen; 2082381a2a9aSdr u_short swap; 2083381a2a9aSdr phy_if_t phy; 2084381a2a9aSdr ip_t *ip; 2085381a2a9aSdr 20867ddc9b1aSDarren Reed ifs = arg; 2087381a2a9aSdr fw = (hook_pkt_event_t *)info; 2088381a2a9aSdr 2089381a2a9aSdr ASSERT(fw != NULL); 2090381a2a9aSdr phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp; 2091381a2a9aSdr 2092381a2a9aSdr ip = fw->hpe_hdr; 2093cbded9aeSdr swap = ntohs(ip->ip_len); 2094cbded9aeSdr ip->ip_len = swap; 2095cbded9aeSdr swap = ntohs(ip->ip_off); 2096cbded9aeSdr ip->ip_off = swap; 2097cbded9aeSdr hlen = IPH_HDR_LENGTH(ip); 2098381a2a9aSdr 2099381a2a9aSdr qpi.qpi_m = fw->hpe_mb; 2100381a2a9aSdr qpi.qpi_data = fw->hpe_hdr; 2101381a2a9aSdr qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr; 2102381a2a9aSdr qpi.qpi_ill = (void *)phy; 2103cbded9aeSdr qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST); 2104cbded9aeSdr if (qpi.qpi_flags) 2105cbded9aeSdr qpi.qpi_flags |= FI_MBCAST; 2106cbded9aeSdr qpi.qpi_flags |= loopback; 2107381a2a9aSdr 2108f4b3ec61Sdh rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, 21097ddc9b1aSDarren Reed &qpi, fw->hpe_mp, ifs); 2110381a2a9aSdr 2111381a2a9aSdr /* For fastroute cases, fr_check returns 0 with mp set to NULL */ 2112381a2a9aSdr if (rval == 0 && *(fw->hpe_mp) == NULL) 2113381a2a9aSdr rval = 1; 2114381a2a9aSdr 2115cbded9aeSdr /* Notify IP the packet mblk_t and IP header pointers. */ 2116381a2a9aSdr fw->hpe_mb = qpi.qpi_m; 2117381a2a9aSdr fw->hpe_hdr = qpi.qpi_data; 2118cbded9aeSdr if (rval == 0) { 2119381a2a9aSdr ip = qpi.qpi_data; 2120381a2a9aSdr swap = ntohs(ip->ip_len); 2121381a2a9aSdr ip->ip_len = swap; 2122381a2a9aSdr swap = ntohs(ip->ip_off); 2123381a2a9aSdr ip->ip_off = swap; 2124381a2a9aSdr } 2125381a2a9aSdr return rval; 2126ab25eeb5Syz 2127381a2a9aSdr } 21287ddc9b1aSDarren Reed int ipf_hook6(hook_data_t info, int out, int loopback, void *arg) 2129cbded9aeSdr { 2130cbded9aeSdr hook_pkt_event_t *fw; 2131cbded9aeSdr int rval, hlen; 2132cbded9aeSdr qpktinfo_t qpi; 2133cbded9aeSdr phy_if_t phy; 2134cbded9aeSdr 2135cbded9aeSdr fw = (hook_pkt_event_t *)info; 2136cbded9aeSdr 2137cbded9aeSdr ASSERT(fw != NULL); 2138cbded9aeSdr phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp; 2139cbded9aeSdr 2140cbded9aeSdr hlen = sizeof (ip6_t); 2141cbded9aeSdr 2142cbded9aeSdr qpi.qpi_m = fw->hpe_mb; 2143cbded9aeSdr qpi.qpi_data = fw->hpe_hdr; 2144cbded9aeSdr qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr; 2145cbded9aeSdr qpi.qpi_ill = (void *)phy; 2146cbded9aeSdr qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST); 2147cbded9aeSdr if (qpi.qpi_flags) 2148cbded9aeSdr qpi.qpi_flags |= FI_MBCAST; 2149cbded9aeSdr qpi.qpi_flags |= loopback; 2150cbded9aeSdr 2151cbded9aeSdr rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, 21527ddc9b1aSDarren Reed &qpi, fw->hpe_mp, arg); 2153cbded9aeSdr 2154cbded9aeSdr /* For fastroute cases, fr_check returns 0 with mp set to NULL */ 2155cbded9aeSdr if (rval == 0 && *(fw->hpe_mp) == NULL) 2156cbded9aeSdr rval = 1; 2157cbded9aeSdr 2158cbded9aeSdr /* Notify IP the packet mblk_t and IP header pointers. */ 2159cbded9aeSdr fw->hpe_mb = qpi.qpi_m; 2160cbded9aeSdr fw->hpe_hdr = qpi.qpi_data; 2161cbded9aeSdr return rval; 2162cbded9aeSdr } 2163ab25eeb5Syz 2164ab25eeb5Syz 2165381a2a9aSdr /* ------------------------------------------------------------------------ */ 2166381a2a9aSdr /* Function: ipf_nic_event_v4 */ 2167381a2a9aSdr /* Returns: int - 0 == no problems encountered */ 2168381a2a9aSdr /* Parameters: event(I) - pointer to event */ 2169381a2a9aSdr /* info(I) - pointer to information about a NIC event */ 2170381a2a9aSdr /* */ 2171381a2a9aSdr /* Function to receive asynchronous NIC events from IP */ 2172381a2a9aSdr /* ------------------------------------------------------------------------ */ 2173381a2a9aSdr /*ARGSUSED*/ 21747ddc9b1aSDarren Reed int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info, void *arg) 2175381a2a9aSdr { 2176381a2a9aSdr struct sockaddr_in *sin; 2177381a2a9aSdr hook_nic_event_t *hn; 21787ddc9b1aSDarren Reed ipf_stack_t *ifs = arg; 2179e8d569f4SAlexandr Nedvedicky void *new_ifp = NULL; 2180e8d569f4SAlexandr Nedvedicky 2181e8d569f4SAlexandr Nedvedicky if (ifs->ifs_fr_running <= 0) 2182e8d569f4SAlexandr Nedvedicky return (0); 2183381a2a9aSdr 2184381a2a9aSdr hn = (hook_nic_event_t *)info; 2185381a2a9aSdr 2186381a2a9aSdr switch (hn->hne_event) 2187381a2a9aSdr { 2188381a2a9aSdr case NE_PLUMB : 2189a4cf92b0Sdr frsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, hn->hne_data, 2190d6c23f6fSyx ifs); 2191d6c23f6fSyx fr_natifpsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, 2192f4b3ec61Sdh hn->hne_data, ifs); 2193381a2a9aSdr fr_statesync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, 2194f4b3ec61Sdh hn->hne_data, ifs); 2195381a2a9aSdr break; 2196381a2a9aSdr 2197381a2a9aSdr case NE_UNPLUMB : 2198f4b3ec61Sdh frsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 2199d6c23f6fSyx fr_natifpsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, 2200d6c23f6fSyx ifs); 2201f4b3ec61Sdh fr_statesync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 2202381a2a9aSdr break; 2203381a2a9aSdr 2204381a2a9aSdr case NE_ADDRESS_CHANGE : 2205a4cf92b0Sdr /* 2206a4cf92b0Sdr * We only respond to events for logical interface 0 because 2207a4cf92b0Sdr * IPFilter only uses the first address given to a network 2208a4cf92b0Sdr * interface. We check for hne_lif==1 because the netinfo 2209a4cf92b0Sdr * code maps adds 1 to the lif number so that it can return 2210a4cf92b0Sdr * 0 to indicate "no more lifs" when walking them. 2211a4cf92b0Sdr */ 2212a4cf92b0Sdr if (hn->hne_lif == 1) { 2213a4cf92b0Sdr frsync(IPFSYNC_RESYNC, 4, (void *)hn->hne_nic, NULL, 2214a4cf92b0Sdr ifs); 2215a4cf92b0Sdr sin = hn->hne_data; 2216d6c23f6fSyx fr_nataddrsync(4, (void *)hn->hne_nic, &sin->sin_addr, 2217a4cf92b0Sdr ifs); 2218a4cf92b0Sdr } 2219381a2a9aSdr break; 2220381a2a9aSdr 2221e8d569f4SAlexandr Nedvedicky #if SOLARIS2 >= 10 2222e8d569f4SAlexandr Nedvedicky case NE_IFINDEX_CHANGE : 2223e8d569f4SAlexandr Nedvedicky WRITE_ENTER(&ifs->ifs_ipf_mutex); 2224e8d569f4SAlexandr Nedvedicky 2225e8d569f4SAlexandr Nedvedicky if (hn->hne_data != NULL) { 2226e8d569f4SAlexandr Nedvedicky /* 2227e8d569f4SAlexandr Nedvedicky * The netinfo passes interface index as int (hne_data should be 2228e8d569f4SAlexandr Nedvedicky * handled as a pointer to int), which is always 32bit. We need to 2229e8d569f4SAlexandr Nedvedicky * convert it to void pointer here, since interfaces are 2230e8d569f4SAlexandr Nedvedicky * represented as pointers to void in IPF. The pointers are 64 bits 2231e8d569f4SAlexandr Nedvedicky * long on 64bit platforms. Doing something like 2232e8d569f4SAlexandr Nedvedicky * (void *)((int) x) 2233e8d569f4SAlexandr Nedvedicky * will throw warning: 2234e8d569f4SAlexandr Nedvedicky * "cast to pointer from integer of different size" 2235e8d569f4SAlexandr Nedvedicky * during 64bit compilation. 2236e8d569f4SAlexandr Nedvedicky * 2237e8d569f4SAlexandr Nedvedicky * The line below uses (size_t) to typecast int to 2238e8d569f4SAlexandr Nedvedicky * size_t, which might be 64bit/32bit (depending 2239e8d569f4SAlexandr Nedvedicky * on architecture). Once we have proper 64bit/32bit 2240e8d569f4SAlexandr Nedvedicky * type (size_t), we can safely convert it to void pointer. 2241e8d569f4SAlexandr Nedvedicky */ 2242e8d569f4SAlexandr Nedvedicky new_ifp = (void *)(size_t)*((int *)hn->hne_data); 2243e8d569f4SAlexandr Nedvedicky fr_ifindexsync((void *)hn->hne_nic, new_ifp, ifs); 2244e8d569f4SAlexandr Nedvedicky fr_natifindexsync((void *)hn->hne_nic, new_ifp, ifs); 2245e8d569f4SAlexandr Nedvedicky fr_stateifindexsync((void *)hn->hne_nic, new_ifp, ifs); 2246e8d569f4SAlexandr Nedvedicky } 2247e8d569f4SAlexandr Nedvedicky RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2248e8d569f4SAlexandr Nedvedicky break; 2249e8d569f4SAlexandr Nedvedicky #endif 2250e8d569f4SAlexandr Nedvedicky 2251381a2a9aSdr default : 2252381a2a9aSdr break; 2253ab25eeb5Syz } 2254ab25eeb5Syz 2255381a2a9aSdr return 0; 2256381a2a9aSdr } 2257ab25eeb5Syz 2258381a2a9aSdr 2259381a2a9aSdr /* ------------------------------------------------------------------------ */ 2260381a2a9aSdr /* Function: ipf_nic_event_v6 */ 2261381a2a9aSdr /* Returns: int - 0 == no problems encountered */ 2262381a2a9aSdr /* Parameters: event(I) - pointer to event */ 2263381a2a9aSdr /* info(I) - pointer to information about a NIC event */ 2264381a2a9aSdr /* */ 2265381a2a9aSdr /* Function to receive asynchronous NIC events from IP */ 2266381a2a9aSdr /* ------------------------------------------------------------------------ */ 2267381a2a9aSdr /*ARGSUSED*/ 22687ddc9b1aSDarren Reed int ipf_nic_event_v6(hook_event_token_t event, hook_data_t info, void *arg) 2269381a2a9aSdr { 2270d6c23f6fSyx struct sockaddr_in6 *sin6; 2271381a2a9aSdr hook_nic_event_t *hn; 22727ddc9b1aSDarren Reed ipf_stack_t *ifs = arg; 2273e8d569f4SAlexandr Nedvedicky void *new_ifp = NULL; 2274e8d569f4SAlexandr Nedvedicky 2275e8d569f4SAlexandr Nedvedicky if (ifs->ifs_fr_running <= 0) 2276e8d569f4SAlexandr Nedvedicky return (0); 2277381a2a9aSdr 2278381a2a9aSdr hn = (hook_nic_event_t *)info; 2279381a2a9aSdr 2280381a2a9aSdr switch (hn->hne_event) 2281381a2a9aSdr { 2282381a2a9aSdr case NE_PLUMB : 2283d6c23f6fSyx frsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2284d6c23f6fSyx hn->hne_data, ifs); 2285d6c23f6fSyx fr_natifpsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2286d6c23f6fSyx hn->hne_data, ifs); 2287381a2a9aSdr fr_statesync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2288f4b3ec61Sdh hn->hne_data, ifs); 2289381a2a9aSdr break; 2290381a2a9aSdr 2291381a2a9aSdr case NE_UNPLUMB : 2292f4b3ec61Sdh frsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2293d6c23f6fSyx fr_natifpsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, 2294d6c23f6fSyx ifs); 2295f4b3ec61Sdh fr_statesync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2296381a2a9aSdr break; 2297381a2a9aSdr 2298381a2a9aSdr case NE_ADDRESS_CHANGE : 2299d6c23f6fSyx if (hn->hne_lif == 1) { 2300d6c23f6fSyx sin6 = hn->hne_data; 2301d6c23f6fSyx fr_nataddrsync(6, (void *)hn->hne_nic, &sin6->sin6_addr, 2302d6c23f6fSyx ifs); 2303d6c23f6fSyx } 2304381a2a9aSdr break; 2305e8d569f4SAlexandr Nedvedicky 2306e8d569f4SAlexandr Nedvedicky #if SOLARIS2 >= 10 2307e8d569f4SAlexandr Nedvedicky case NE_IFINDEX_CHANGE : 2308e8d569f4SAlexandr Nedvedicky WRITE_ENTER(&ifs->ifs_ipf_mutex); 2309e8d569f4SAlexandr Nedvedicky if (hn->hne_data != NULL) { 2310e8d569f4SAlexandr Nedvedicky /* 2311e8d569f4SAlexandr Nedvedicky * The netinfo passes interface index as int (hne_data should be 2312e8d569f4SAlexandr Nedvedicky * handled as a pointer to int), which is always 32bit. We need to 2313e8d569f4SAlexandr Nedvedicky * convert it to void pointer here, since interfaces are 2314e8d569f4SAlexandr Nedvedicky * represented as pointers to void in IPF. The pointers are 64 bits 2315e8d569f4SAlexandr Nedvedicky * long on 64bit platforms. Doing something like 2316e8d569f4SAlexandr Nedvedicky * (void *)((int) x) 2317e8d569f4SAlexandr Nedvedicky * will throw warning: 2318e8d569f4SAlexandr Nedvedicky * "cast to pointer from integer of different size" 2319e8d569f4SAlexandr Nedvedicky * during 64bit compilation. 2320e8d569f4SAlexandr Nedvedicky * 2321e8d569f4SAlexandr Nedvedicky * The line below uses (size_t) to typecast int to 2322e8d569f4SAlexandr Nedvedicky * size_t, which might be 64bit/32bit (depending 2323e8d569f4SAlexandr Nedvedicky * on architecture). Once we have proper 64bit/32bit 2324e8d569f4SAlexandr Nedvedicky * type (size_t), we can safely convert it to void pointer. 2325e8d569f4SAlexandr Nedvedicky */ 2326e8d569f4SAlexandr Nedvedicky new_ifp = (void *)(size_t)*((int *)hn->hne_data); 2327e8d569f4SAlexandr Nedvedicky fr_ifindexsync((void *)hn->hne_nic, new_ifp, ifs); 2328e8d569f4SAlexandr Nedvedicky fr_natifindexsync((void *)hn->hne_nic, new_ifp, ifs); 2329e8d569f4SAlexandr Nedvedicky fr_stateifindexsync((void *)hn->hne_nic, new_ifp, ifs); 2330e8d569f4SAlexandr Nedvedicky } 2331e8d569f4SAlexandr Nedvedicky RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2332e8d569f4SAlexandr Nedvedicky break; 2333e8d569f4SAlexandr Nedvedicky #endif 2334e8d569f4SAlexandr Nedvedicky 2335381a2a9aSdr default : 2336381a2a9aSdr break; 2337381a2a9aSdr } 2338381a2a9aSdr 2339381a2a9aSdr return 0; 2340ab25eeb5Syz } 2341a1173273SAlexandr Nedvedicky 2342a1173273SAlexandr Nedvedicky /* 2343a1173273SAlexandr Nedvedicky * Functions fr_make_rst(), fr_make_icmp_v4(), fr_make_icmp_v6() 2344a1173273SAlexandr Nedvedicky * are needed in Solaris kernel only. We don't need them in 2345a1173273SAlexandr Nedvedicky * ipftest to pretend the ICMP/RST packet was sent as a response. 2346a1173273SAlexandr Nedvedicky */ 2347a1173273SAlexandr Nedvedicky #if defined(_KERNEL) && (SOLARIS2 >= 10) 2348a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2349a1173273SAlexandr Nedvedicky /* Function: fr_make_rst */ 2350a1173273SAlexandr Nedvedicky /* Returns: int - 0 on success, -1 on failure */ 2351a1173273SAlexandr Nedvedicky /* Parameters: fin(I) - pointer to packet information */ 2352a1173273SAlexandr Nedvedicky /* */ 2353a1173273SAlexandr Nedvedicky /* We must alter the original mblks passed to IPF from IP stack via */ 2354a1173273SAlexandr Nedvedicky /* FW_HOOKS. FW_HOOKS interface is powerfull, but it has some limitations. */ 2355a1173273SAlexandr Nedvedicky /* IPF can basicaly do only these things with mblk representing the packet: */ 2356a1173273SAlexandr Nedvedicky /* leave it as it is (pass the packet) */ 2357a1173273SAlexandr Nedvedicky /* */ 2358a1173273SAlexandr Nedvedicky /* discard it (block the packet) */ 2359a1173273SAlexandr Nedvedicky /* */ 2360a1173273SAlexandr Nedvedicky /* alter it (i.e. NAT) */ 2361a1173273SAlexandr Nedvedicky /* */ 2362a1173273SAlexandr Nedvedicky /* As you can see IPF can not simply discard the mblk and supply a new one */ 2363a1173273SAlexandr Nedvedicky /* instead to IP stack via FW_HOOKS. */ 2364a1173273SAlexandr Nedvedicky /* */ 2365a1173273SAlexandr Nedvedicky /* The return-rst action for packets coming via NIC is handled as follows: */ 2366a1173273SAlexandr Nedvedicky /* mblk with packet is discarded */ 2367a1173273SAlexandr Nedvedicky /* */ 2368a1173273SAlexandr Nedvedicky /* new mblk with RST response is constructed and injected to network */ 2369a1173273SAlexandr Nedvedicky /* */ 2370a1173273SAlexandr Nedvedicky /* IPF can't inject packets to loopback interface, this is just another */ 2371a1173273SAlexandr Nedvedicky /* limitation we have to deal with here. The only option to send RST */ 2372a1173273SAlexandr Nedvedicky /* response to offending TCP packet coming via loopback is to alter it. */ 2373a1173273SAlexandr Nedvedicky /* */ 2374a1173273SAlexandr Nedvedicky /* The fr_make_rst() function alters TCP SYN/FIN packet intercepted on */ 2375a1173273SAlexandr Nedvedicky /* loopback interface into TCP RST packet. fin->fin_mp is pointer to */ 2376a1173273SAlexandr Nedvedicky /* mblk L3 (IP) and L4 (TCP/UDP) packet headers. */ 2377a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2378a1173273SAlexandr Nedvedicky int fr_make_rst(fin) 2379a1173273SAlexandr Nedvedicky fr_info_t *fin; 2380a1173273SAlexandr Nedvedicky { 2381a1173273SAlexandr Nedvedicky uint16_t tmp_port; 2382a1173273SAlexandr Nedvedicky int rv = -1; 2383a1173273SAlexandr Nedvedicky uint32_t old_ack; 2384a1173273SAlexandr Nedvedicky tcphdr_t *tcp = NULL; 2385a1173273SAlexandr Nedvedicky struct in_addr tmp_src; 2386a1173273SAlexandr Nedvedicky #ifdef USE_INET6 2387a1173273SAlexandr Nedvedicky struct in6_addr tmp_src6; 2388a1173273SAlexandr Nedvedicky #endif 2389a1173273SAlexandr Nedvedicky 2390a1173273SAlexandr Nedvedicky ASSERT(fin->fin_p == IPPROTO_TCP); 2391a1173273SAlexandr Nedvedicky 2392a1173273SAlexandr Nedvedicky /* 2393a1173273SAlexandr Nedvedicky * We do not need to adjust chksum, since it is not being checked by 2394a1173273SAlexandr Nedvedicky * Solaris IP stack for loopback clients. 2395a1173273SAlexandr Nedvedicky */ 2396a1173273SAlexandr Nedvedicky if ((fin->fin_v == 4) && (fin->fin_p == IPPROTO_TCP) && 2397a1173273SAlexandr Nedvedicky ((tcp = (tcphdr_t *) fin->fin_dp) != NULL)) { 2398a1173273SAlexandr Nedvedicky 2399a1173273SAlexandr Nedvedicky if (tcp->th_flags & (TH_SYN | TH_FIN)) { 2400a1173273SAlexandr Nedvedicky /* Swap IPv4 addresses. */ 2401a1173273SAlexandr Nedvedicky tmp_src = fin->fin_ip->ip_src; 2402a1173273SAlexandr Nedvedicky fin->fin_ip->ip_src = fin->fin_ip->ip_dst; 2403a1173273SAlexandr Nedvedicky fin->fin_ip->ip_dst = tmp_src; 2404a1173273SAlexandr Nedvedicky 2405a1173273SAlexandr Nedvedicky rv = 0; 2406a1173273SAlexandr Nedvedicky } 2407a1173273SAlexandr Nedvedicky else 2408a1173273SAlexandr Nedvedicky tcp = NULL; 2409a1173273SAlexandr Nedvedicky } 2410a1173273SAlexandr Nedvedicky #ifdef USE_INET6 2411a1173273SAlexandr Nedvedicky else if ((fin->fin_v == 6) && (fin->fin_p == IPPROTO_TCP) && 2412a1173273SAlexandr Nedvedicky ((tcp = (tcphdr_t *) fin->fin_dp) != NULL)) { 2413a1173273SAlexandr Nedvedicky /* 2414a1173273SAlexandr Nedvedicky * We are relying on fact the next header is TCP, which is true 2415a1173273SAlexandr Nedvedicky * for regular TCP packets coming in over loopback. 2416a1173273SAlexandr Nedvedicky */ 2417a1173273SAlexandr Nedvedicky if (tcp->th_flags & (TH_SYN | TH_FIN)) { 2418a1173273SAlexandr Nedvedicky /* Swap IPv6 addresses. */ 2419a1173273SAlexandr Nedvedicky tmp_src6 = fin->fin_ip6->ip6_src; 2420a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_src = fin->fin_ip6->ip6_dst; 2421a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_dst = tmp_src6; 2422a1173273SAlexandr Nedvedicky 2423a1173273SAlexandr Nedvedicky rv = 0; 2424a1173273SAlexandr Nedvedicky } 2425a1173273SAlexandr Nedvedicky else 2426a1173273SAlexandr Nedvedicky tcp = NULL; 2427a1173273SAlexandr Nedvedicky } 2428a1173273SAlexandr Nedvedicky #endif 2429a1173273SAlexandr Nedvedicky 2430a1173273SAlexandr Nedvedicky if (tcp != NULL) { 2431a1173273SAlexandr Nedvedicky /* 2432a1173273SAlexandr Nedvedicky * Adjust TCP header: 2433a1173273SAlexandr Nedvedicky * swap ports, 2434a1173273SAlexandr Nedvedicky * set flags, 2435a1173273SAlexandr Nedvedicky * set correct ACK number 2436a1173273SAlexandr Nedvedicky */ 2437a1173273SAlexandr Nedvedicky tmp_port = tcp->th_sport; 2438a1173273SAlexandr Nedvedicky tcp->th_sport = tcp->th_dport; 2439a1173273SAlexandr Nedvedicky tcp->th_dport = tmp_port; 2440a1173273SAlexandr Nedvedicky old_ack = tcp->th_ack; 2441a1173273SAlexandr Nedvedicky tcp->th_ack = htonl(ntohl(tcp->th_seq) + 1); 2442a1173273SAlexandr Nedvedicky tcp->th_seq = old_ack; 2443a1173273SAlexandr Nedvedicky tcp->th_flags = TH_RST | TH_ACK; 2444a1173273SAlexandr Nedvedicky } 2445a1173273SAlexandr Nedvedicky 2446a1173273SAlexandr Nedvedicky return (rv); 2447a1173273SAlexandr Nedvedicky } 2448a1173273SAlexandr Nedvedicky 2449a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2450a1173273SAlexandr Nedvedicky /* Function: fr_make_icmp_v4 */ 2451a1173273SAlexandr Nedvedicky /* Returns: int - 0 on success, -1 on failure */ 2452a1173273SAlexandr Nedvedicky /* Parameters: fin(I) - pointer to packet information */ 2453a1173273SAlexandr Nedvedicky /* */ 2454a1173273SAlexandr Nedvedicky /* Please read comment at fr_make_icmp() wrapper function to get an idea */ 2455a1173273SAlexandr Nedvedicky /* what is going to happen here and why. Once you read the comment there, */ 2456a1173273SAlexandr Nedvedicky /* continue here with next paragraph. */ 2457a1173273SAlexandr Nedvedicky /* */ 2458a1173273SAlexandr Nedvedicky /* To turn IPv4 packet into ICMPv4 response packet, these things must */ 2459a1173273SAlexandr Nedvedicky /* happen here: */ 2460a1173273SAlexandr Nedvedicky /* (1) Original mblk is copied (duplicated). */ 2461a1173273SAlexandr Nedvedicky /* */ 2462a1173273SAlexandr Nedvedicky /* (2) ICMP header is created. */ 2463a1173273SAlexandr Nedvedicky /* */ 2464a1173273SAlexandr Nedvedicky /* (3) Link ICMP header with copy of original mblk, we have ICMPv4 */ 2465a1173273SAlexandr Nedvedicky /* data ready then. */ 2466a1173273SAlexandr Nedvedicky /* */ 2467a1173273SAlexandr Nedvedicky /* (4) Swap IP addresses in original mblk and adjust IP header data. */ 2468a1173273SAlexandr Nedvedicky /* */ 2469a1173273SAlexandr Nedvedicky /* (5) The mblk containing original packet is trimmed to contain IP */ 2470a1173273SAlexandr Nedvedicky /* header only and ICMP chksum is computed. */ 2471a1173273SAlexandr Nedvedicky /* */ 2472a1173273SAlexandr Nedvedicky /* (6) The ICMP header we have from (3) is linked to original mblk, */ 2473a1173273SAlexandr Nedvedicky /* which now contains new IP header. If original packet was spread */ 2474a1173273SAlexandr Nedvedicky /* over several mblks, only the first mblk is kept. */ 2475a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2476a1173273SAlexandr Nedvedicky static int fr_make_icmp_v4(fin) 2477a1173273SAlexandr Nedvedicky fr_info_t *fin; 2478a1173273SAlexandr Nedvedicky { 2479a1173273SAlexandr Nedvedicky struct in_addr tmp_src; 24806ccacea7SAlexandr Nedvedicky tcphdr_t *tcp; 2481a1173273SAlexandr Nedvedicky struct icmp *icmp; 2482a1173273SAlexandr Nedvedicky mblk_t *mblk_icmp; 2483a1173273SAlexandr Nedvedicky mblk_t *mblk_ip; 2484a1173273SAlexandr Nedvedicky size_t icmp_pld_len; /* octets to append to ICMP header */ 2485a1173273SAlexandr Nedvedicky size_t orig_iphdr_len; /* length of IP header only */ 2486a1173273SAlexandr Nedvedicky uint32_t sum; 2487a1173273SAlexandr Nedvedicky uint16_t *buf; 2488a1173273SAlexandr Nedvedicky int len; 2489a1173273SAlexandr Nedvedicky 2490a1173273SAlexandr Nedvedicky 2491a1173273SAlexandr Nedvedicky if (fin->fin_v != 4) 2492a1173273SAlexandr Nedvedicky return (-1); 2493a1173273SAlexandr Nedvedicky 2494a1173273SAlexandr Nedvedicky /* 2495a1173273SAlexandr Nedvedicky * If we are dealing with TCP, then packet must be SYN/FIN to be routed 2496a1173273SAlexandr Nedvedicky * by IP stack. If it is not SYN/FIN, then we must drop it silently. 2497a1173273SAlexandr Nedvedicky */ 24986ccacea7SAlexandr Nedvedicky tcp = (tcphdr_t *) fin->fin_dp; 24996ccacea7SAlexandr Nedvedicky 2500a1173273SAlexandr Nedvedicky if ((fin->fin_p == IPPROTO_TCP) && 25016ccacea7SAlexandr Nedvedicky ((tcp == NULL) || ((tcp->th_flags & (TH_SYN | TH_FIN)) == 0))) 2502a1173273SAlexandr Nedvedicky return (-1); 2503a1173273SAlexandr Nedvedicky 2504a1173273SAlexandr Nedvedicky /* 2505a1173273SAlexandr Nedvedicky * Step (1) 2506a1173273SAlexandr Nedvedicky * 2507a1173273SAlexandr Nedvedicky * Make copy of original mblk. 2508a1173273SAlexandr Nedvedicky * 2509a1173273SAlexandr Nedvedicky * We want to copy as much data as necessary, not less, not more. The 2510a1173273SAlexandr Nedvedicky * ICMPv4 payload length for unreachable messages is: 2511a1173273SAlexandr Nedvedicky * original IP header + 8 bytes of L4 (if there are any). 2512a1173273SAlexandr Nedvedicky * 2513a1173273SAlexandr Nedvedicky * We determine if there are at least 8 bytes of L4 data following IP 2514a1173273SAlexandr Nedvedicky * header first. 2515a1173273SAlexandr Nedvedicky */ 2516a1173273SAlexandr Nedvedicky icmp_pld_len = (fin->fin_dlen > ICMPERR_ICMPHLEN) ? 2517a1173273SAlexandr Nedvedicky ICMPERR_ICMPHLEN : fin->fin_dlen; 2518a1173273SAlexandr Nedvedicky /* 2519a1173273SAlexandr Nedvedicky * Since we don't want to copy more data than necessary, we must trim 2520a1173273SAlexandr Nedvedicky * the original mblk here. The right way (STREAMish) would be to use 2521a1173273SAlexandr Nedvedicky * adjmsg() to trim it. However we would have to calculate the length 2522a1173273SAlexandr Nedvedicky * argument for adjmsg() from pointers we already have here. 2523a1173273SAlexandr Nedvedicky * 2524a1173273SAlexandr Nedvedicky * Since we have pointers and offsets, it's faster and easier for 2525a1173273SAlexandr Nedvedicky * us to just adjust pointers by hand instead of using adjmsg(). 2526a1173273SAlexandr Nedvedicky */ 2527a1173273SAlexandr Nedvedicky fin->fin_m->b_wptr = (unsigned char *) fin->fin_dp; 2528a1173273SAlexandr Nedvedicky fin->fin_m->b_wptr += icmp_pld_len; 2529a1173273SAlexandr Nedvedicky icmp_pld_len = fin->fin_m->b_wptr - (unsigned char *) fin->fin_ip; 2530a1173273SAlexandr Nedvedicky 2531a1173273SAlexandr Nedvedicky /* 2532a1173273SAlexandr Nedvedicky * Also we don't want to copy any L2 stuff, which might precede IP 2533a1173273SAlexandr Nedvedicky * header, so we have have to set b_rptr to point to the start of IP 2534a1173273SAlexandr Nedvedicky * header. 2535a1173273SAlexandr Nedvedicky */ 2536a1173273SAlexandr Nedvedicky fin->fin_m->b_rptr += fin->fin_ipoff; 2537a1173273SAlexandr Nedvedicky if ((mblk_ip = copyb(fin->fin_m)) == NULL) 2538a1173273SAlexandr Nedvedicky return (-1); 2539a1173273SAlexandr Nedvedicky fin->fin_m->b_rptr -= fin->fin_ipoff; 2540a1173273SAlexandr Nedvedicky 2541a1173273SAlexandr Nedvedicky /* 2542a1173273SAlexandr Nedvedicky * Step (2) 2543a1173273SAlexandr Nedvedicky * 2544a1173273SAlexandr Nedvedicky * Create an ICMP header, which will be appened to original mblk later. 2545a1173273SAlexandr Nedvedicky * ICMP header is just another mblk. 2546a1173273SAlexandr Nedvedicky */ 2547a1173273SAlexandr Nedvedicky mblk_icmp = (mblk_t *) allocb(ICMPERR_ICMPHLEN, BPRI_HI); 2548a1173273SAlexandr Nedvedicky if (mblk_icmp == NULL) { 2549a1173273SAlexandr Nedvedicky FREE_MB_T(mblk_ip); 2550a1173273SAlexandr Nedvedicky return (-1); 2551a1173273SAlexandr Nedvedicky } 2552a1173273SAlexandr Nedvedicky 2553a1173273SAlexandr Nedvedicky MTYPE(mblk_icmp) = M_DATA; 2554a1173273SAlexandr Nedvedicky icmp = (struct icmp *) mblk_icmp->b_wptr; 2555a1173273SAlexandr Nedvedicky icmp->icmp_type = ICMP_UNREACH; 2556a1173273SAlexandr Nedvedicky icmp->icmp_code = fin->fin_icode & 0xFF; 2557a1173273SAlexandr Nedvedicky icmp->icmp_void = 0; 2558a1173273SAlexandr Nedvedicky icmp->icmp_cksum = 0; 2559a1173273SAlexandr Nedvedicky mblk_icmp->b_wptr += ICMPERR_ICMPHLEN; 2560a1173273SAlexandr Nedvedicky 2561a1173273SAlexandr Nedvedicky /* 2562a1173273SAlexandr Nedvedicky * Step (3) 2563a1173273SAlexandr Nedvedicky * 2564a1173273SAlexandr Nedvedicky * Complete ICMP packet - link ICMP header with L4 data from original 2565a1173273SAlexandr Nedvedicky * IP packet. 2566a1173273SAlexandr Nedvedicky */ 2567a1173273SAlexandr Nedvedicky linkb(mblk_icmp, mblk_ip); 2568a1173273SAlexandr Nedvedicky 2569a1173273SAlexandr Nedvedicky /* 2570a1173273SAlexandr Nedvedicky * Step (4) 2571a1173273SAlexandr Nedvedicky * 2572a1173273SAlexandr Nedvedicky * Swap IP addresses and change IP header fields accordingly in 2573a1173273SAlexandr Nedvedicky * original IP packet. 2574a1173273SAlexandr Nedvedicky * 2575a1173273SAlexandr Nedvedicky * There is a rule option return-icmp as a dest for physical 2576a1173273SAlexandr Nedvedicky * interfaces. This option becomes useless for loopback, since IPF box 2577a1173273SAlexandr Nedvedicky * uses same address as a loopback destination. We ignore the option 2578a1173273SAlexandr Nedvedicky * here, the ICMP packet will always look like as it would have been 2579a1173273SAlexandr Nedvedicky * sent from the original destination host. 2580a1173273SAlexandr Nedvedicky */ 2581a1173273SAlexandr Nedvedicky tmp_src = fin->fin_ip->ip_src; 2582a1173273SAlexandr Nedvedicky fin->fin_ip->ip_src = fin->fin_ip->ip_dst; 2583a1173273SAlexandr Nedvedicky fin->fin_ip->ip_dst = tmp_src; 2584a1173273SAlexandr Nedvedicky fin->fin_ip->ip_p = IPPROTO_ICMP; 2585a1173273SAlexandr Nedvedicky fin->fin_ip->ip_sum = 0; 2586a1173273SAlexandr Nedvedicky 2587a1173273SAlexandr Nedvedicky /* 2588a1173273SAlexandr Nedvedicky * Step (5) 2589a1173273SAlexandr Nedvedicky * 2590a1173273SAlexandr Nedvedicky * We trim the orignal mblk to hold IP header only. 2591a1173273SAlexandr Nedvedicky */ 2592a1173273SAlexandr Nedvedicky fin->fin_m->b_wptr = fin->fin_dp; 2593a1173273SAlexandr Nedvedicky orig_iphdr_len = fin->fin_m->b_wptr - 2594a1173273SAlexandr Nedvedicky (fin->fin_m->b_rptr + fin->fin_ipoff); 2595a1173273SAlexandr Nedvedicky fin->fin_ip->ip_len = htons(icmp_pld_len + ICMPERR_ICMPHLEN + 2596a1173273SAlexandr Nedvedicky orig_iphdr_len); 2597a1173273SAlexandr Nedvedicky 2598a1173273SAlexandr Nedvedicky /* 2599a1173273SAlexandr Nedvedicky * ICMP chksum calculation. The data we are calculating chksum for are 2600a1173273SAlexandr Nedvedicky * spread over two mblks, therefore we have to use two for loops. 2601a1173273SAlexandr Nedvedicky * 2602a1173273SAlexandr Nedvedicky * First for loop computes chksum part for ICMP header. 2603a1173273SAlexandr Nedvedicky */ 2604a1173273SAlexandr Nedvedicky buf = (uint16_t *) icmp; 2605a1173273SAlexandr Nedvedicky len = ICMPERR_ICMPHLEN; 2606a1173273SAlexandr Nedvedicky for (sum = 0; len > 1; len -= 2) 2607a1173273SAlexandr Nedvedicky sum += *buf++; 2608a1173273SAlexandr Nedvedicky 2609a1173273SAlexandr Nedvedicky /* 2610a1173273SAlexandr Nedvedicky * Here we add chksum part for ICMP payload. 2611a1173273SAlexandr Nedvedicky */ 2612a1173273SAlexandr Nedvedicky len = icmp_pld_len; 2613a1173273SAlexandr Nedvedicky buf = (uint16_t *) mblk_ip->b_rptr; 2614a1173273SAlexandr Nedvedicky for (; len > 1; len -= 2) 2615a1173273SAlexandr Nedvedicky sum += *buf++; 2616a1173273SAlexandr Nedvedicky 2617a1173273SAlexandr Nedvedicky /* 2618a1173273SAlexandr Nedvedicky * Chksum is done. 2619a1173273SAlexandr Nedvedicky */ 2620a1173273SAlexandr Nedvedicky sum = (sum >> 16) + (sum & 0xffff); 2621a1173273SAlexandr Nedvedicky sum += (sum >> 16); 2622a1173273SAlexandr Nedvedicky icmp->icmp_cksum = ~sum; 2623a1173273SAlexandr Nedvedicky 2624a1173273SAlexandr Nedvedicky /* 2625a1173273SAlexandr Nedvedicky * Step (6) 2626a1173273SAlexandr Nedvedicky * 2627a1173273SAlexandr Nedvedicky * Release all packet mblks, except the first one. 2628a1173273SAlexandr Nedvedicky */ 2629a1173273SAlexandr Nedvedicky if (fin->fin_m->b_cont != NULL) { 2630a1173273SAlexandr Nedvedicky FREE_MB_T(fin->fin_m->b_cont); 2631a1173273SAlexandr Nedvedicky } 2632a1173273SAlexandr Nedvedicky 2633a1173273SAlexandr Nedvedicky /* 2634a1173273SAlexandr Nedvedicky * Append ICMP payload to first mblk, which already contains new IP 2635a1173273SAlexandr Nedvedicky * header. 2636a1173273SAlexandr Nedvedicky */ 2637a1173273SAlexandr Nedvedicky linkb(fin->fin_m, mblk_icmp); 2638a1173273SAlexandr Nedvedicky 2639a1173273SAlexandr Nedvedicky return (0); 2640a1173273SAlexandr Nedvedicky } 2641a1173273SAlexandr Nedvedicky 2642a1173273SAlexandr Nedvedicky #ifdef USE_INET6 2643a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2644a1173273SAlexandr Nedvedicky /* Function: fr_make_icmp_v6 */ 2645a1173273SAlexandr Nedvedicky /* Returns: int - 0 on success, -1 on failure */ 2646a1173273SAlexandr Nedvedicky /* Parameters: fin(I) - pointer to packet information */ 2647a1173273SAlexandr Nedvedicky /* */ 2648a1173273SAlexandr Nedvedicky /* Please read comment at fr_make_icmp() wrapper function to get an idea */ 2649a1173273SAlexandr Nedvedicky /* what and why is going to happen here. Once you read the comment there, */ 2650a1173273SAlexandr Nedvedicky /* continue here with next paragraph. */ 2651a1173273SAlexandr Nedvedicky /* */ 2652a1173273SAlexandr Nedvedicky /* This function turns IPv6 packet (UDP, TCP, ...) into ICMPv6 response. */ 2653a1173273SAlexandr Nedvedicky /* The algorithm is fairly simple: */ 2654a1173273SAlexandr Nedvedicky /* 1) We need to get copy of complete mblk. */ 2655a1173273SAlexandr Nedvedicky /* */ 2656a1173273SAlexandr Nedvedicky /* 2) New ICMPv6 header is created. */ 2657a1173273SAlexandr Nedvedicky /* */ 2658a1173273SAlexandr Nedvedicky /* 3) The copy of original mblk with packet is linked to ICMPv6 */ 2659a1173273SAlexandr Nedvedicky /* header. */ 2660a1173273SAlexandr Nedvedicky /* */ 2661a1173273SAlexandr Nedvedicky /* 4) The checksum must be adjusted. */ 2662a1173273SAlexandr Nedvedicky /* */ 2663a1173273SAlexandr Nedvedicky /* 5) IP addresses in original mblk are swapped and IP header data */ 2664a1173273SAlexandr Nedvedicky /* are adjusted (protocol number). */ 2665a1173273SAlexandr Nedvedicky /* */ 2666a1173273SAlexandr Nedvedicky /* 6) Original mblk is trimmed to hold IPv6 header only, then it is */ 2667a1173273SAlexandr Nedvedicky /* linked with the ICMPv6 data we got from (3). */ 2668a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2669a1173273SAlexandr Nedvedicky static int fr_make_icmp_v6(fin) 2670a1173273SAlexandr Nedvedicky fr_info_t *fin; 2671a1173273SAlexandr Nedvedicky { 2672a1173273SAlexandr Nedvedicky struct icmp6_hdr *icmp6; 26736ccacea7SAlexandr Nedvedicky tcphdr_t *tcp; 2674a1173273SAlexandr Nedvedicky struct in6_addr tmp_src6; 2675a1173273SAlexandr Nedvedicky size_t icmp_pld_len; 2676a1173273SAlexandr Nedvedicky mblk_t *mblk_ip, *mblk_icmp; 2677a1173273SAlexandr Nedvedicky 2678a1173273SAlexandr Nedvedicky if (fin->fin_v != 6) 2679a1173273SAlexandr Nedvedicky return (-1); 2680a1173273SAlexandr Nedvedicky 2681a1173273SAlexandr Nedvedicky /* 2682a1173273SAlexandr Nedvedicky * If we are dealing with TCP, then packet must SYN/FIN to be routed by 2683a1173273SAlexandr Nedvedicky * IP stack. If it is not SYN/FIN, then we must drop it silently. 2684a1173273SAlexandr Nedvedicky */ 26856ccacea7SAlexandr Nedvedicky tcp = (tcphdr_t *) fin->fin_dp; 26866ccacea7SAlexandr Nedvedicky 26876ccacea7SAlexandr Nedvedicky if ((fin->fin_p == IPPROTO_TCP) && 26886ccacea7SAlexandr Nedvedicky ((tcp == NULL) || ((tcp->th_flags & (TH_SYN | TH_FIN)) == 0))) 2689a1173273SAlexandr Nedvedicky return (-1); 2690a1173273SAlexandr Nedvedicky 2691a1173273SAlexandr Nedvedicky /* 2692a1173273SAlexandr Nedvedicky * Step (1) 2693a1173273SAlexandr Nedvedicky * 2694a1173273SAlexandr Nedvedicky * We need to copy complete packet in case of IPv6, no trimming is 2695a1173273SAlexandr Nedvedicky * needed (except the L2 headers). 2696a1173273SAlexandr Nedvedicky */ 2697a1173273SAlexandr Nedvedicky icmp_pld_len = M_LEN(fin->fin_m); 2698a1173273SAlexandr Nedvedicky fin->fin_m->b_rptr += fin->fin_ipoff; 2699a1173273SAlexandr Nedvedicky if ((mblk_ip = copyb(fin->fin_m)) == NULL) 2700a1173273SAlexandr Nedvedicky return (-1); 2701a1173273SAlexandr Nedvedicky fin->fin_m->b_rptr -= fin->fin_ipoff; 2702a1173273SAlexandr Nedvedicky 2703a1173273SAlexandr Nedvedicky /* 2704a1173273SAlexandr Nedvedicky * Step (2) 2705a1173273SAlexandr Nedvedicky * 2706a1173273SAlexandr Nedvedicky * Allocate and create ICMP header. 2707a1173273SAlexandr Nedvedicky */ 2708a1173273SAlexandr Nedvedicky mblk_icmp = (mblk_t *) allocb(sizeof (struct icmp6_hdr), 2709a1173273SAlexandr Nedvedicky BPRI_HI); 2710a1173273SAlexandr Nedvedicky 2711a1173273SAlexandr Nedvedicky if (mblk_icmp == NULL) 2712a1173273SAlexandr Nedvedicky return (-1); 2713a1173273SAlexandr Nedvedicky 2714a1173273SAlexandr Nedvedicky MTYPE(mblk_icmp) = M_DATA; 2715a1173273SAlexandr Nedvedicky icmp6 = (struct icmp6_hdr *) mblk_icmp->b_wptr; 2716a1173273SAlexandr Nedvedicky icmp6->icmp6_type = ICMP6_DST_UNREACH; 2717a1173273SAlexandr Nedvedicky icmp6->icmp6_code = fin->fin_icode & 0xFF; 2718a1173273SAlexandr Nedvedicky icmp6->icmp6_data32[0] = 0; 2719a1173273SAlexandr Nedvedicky mblk_icmp->b_wptr += sizeof (struct icmp6_hdr); 2720a1173273SAlexandr Nedvedicky 2721a1173273SAlexandr Nedvedicky /* 2722a1173273SAlexandr Nedvedicky * Step (3) 2723a1173273SAlexandr Nedvedicky * 2724a1173273SAlexandr Nedvedicky * Link the copy of IP packet to ICMP header. 2725a1173273SAlexandr Nedvedicky */ 2726a1173273SAlexandr Nedvedicky linkb(mblk_icmp, mblk_ip); 2727a1173273SAlexandr Nedvedicky 2728a1173273SAlexandr Nedvedicky /* 2729a1173273SAlexandr Nedvedicky * Step (4) 2730a1173273SAlexandr Nedvedicky * 2731a1173273SAlexandr Nedvedicky * Calculate chksum - this is much more easier task than in case of 2732a1173273SAlexandr Nedvedicky * IPv4 - ICMPv6 chksum only covers IP addresses, and payload length. 2733a1173273SAlexandr Nedvedicky * We are making compensation just for change of packet length. 2734a1173273SAlexandr Nedvedicky */ 2735a1173273SAlexandr Nedvedicky icmp6->icmp6_cksum = icmp_pld_len + sizeof (struct icmp6_hdr); 2736a1173273SAlexandr Nedvedicky 2737a1173273SAlexandr Nedvedicky /* 2738a1173273SAlexandr Nedvedicky * Step (5) 2739a1173273SAlexandr Nedvedicky * 2740a1173273SAlexandr Nedvedicky * Swap IP addresses. 2741a1173273SAlexandr Nedvedicky */ 2742a1173273SAlexandr Nedvedicky tmp_src6 = fin->fin_ip6->ip6_src; 2743a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_src = fin->fin_ip6->ip6_dst; 2744a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_dst = tmp_src6; 2745a1173273SAlexandr Nedvedicky 2746a1173273SAlexandr Nedvedicky /* 2747a1173273SAlexandr Nedvedicky * and adjust IP header data. 2748a1173273SAlexandr Nedvedicky */ 2749a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_nxt = IPPROTO_ICMPV6; 2750a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_plen = htons(icmp_pld_len + sizeof (struct icmp6_hdr)); 2751a1173273SAlexandr Nedvedicky 2752a1173273SAlexandr Nedvedicky /* 2753a1173273SAlexandr Nedvedicky * Step (6) 2754a1173273SAlexandr Nedvedicky * 2755a1173273SAlexandr Nedvedicky * We must release all linked mblks from original packet and keep only 2756a1173273SAlexandr Nedvedicky * the first mblk with IP header to link ICMP data. 2757a1173273SAlexandr Nedvedicky */ 2758a1173273SAlexandr Nedvedicky fin->fin_m->b_wptr = (unsigned char *) fin->fin_ip6 + sizeof (ip6_t); 2759a1173273SAlexandr Nedvedicky 2760a1173273SAlexandr Nedvedicky if (fin->fin_m->b_cont != NULL) { 2761a1173273SAlexandr Nedvedicky FREE_MB_T(fin->fin_m->b_cont); 2762a1173273SAlexandr Nedvedicky } 2763a1173273SAlexandr Nedvedicky 2764a1173273SAlexandr Nedvedicky /* 2765a1173273SAlexandr Nedvedicky * Append ICMP payload to IP header. 2766a1173273SAlexandr Nedvedicky */ 2767a1173273SAlexandr Nedvedicky linkb(fin->fin_m, mblk_icmp); 2768a1173273SAlexandr Nedvedicky 2769a1173273SAlexandr Nedvedicky return (0); 2770a1173273SAlexandr Nedvedicky } 2771a1173273SAlexandr Nedvedicky #endif /* USE_INET6 */ 2772a1173273SAlexandr Nedvedicky 2773a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2774a1173273SAlexandr Nedvedicky /* Function: fr_make_icmp */ 2775a1173273SAlexandr Nedvedicky /* Returns: int - 0 on success, -1 on failure */ 2776a1173273SAlexandr Nedvedicky /* Parameters: fin(I) - pointer to packet information */ 2777a1173273SAlexandr Nedvedicky /* */ 2778a1173273SAlexandr Nedvedicky /* We must alter the original mblks passed to IPF from IP stack via */ 2779a1173273SAlexandr Nedvedicky /* FW_HOOKS. The reasons why we must alter packet are discussed within */ 2780a1173273SAlexandr Nedvedicky /* comment at fr_make_rst() function. */ 2781a1173273SAlexandr Nedvedicky /* */ 2782a1173273SAlexandr Nedvedicky /* The fr_make_icmp() function acts as a wrapper, which passes the code */ 2783a1173273SAlexandr Nedvedicky /* execution to fr_make_icmp_v4() or fr_make_icmp_v6() depending on */ 2784a1173273SAlexandr Nedvedicky /* protocol version. However there are some details, which are common to */ 2785a1173273SAlexandr Nedvedicky /* both IP versions. The details are going to be explained here. */ 2786a1173273SAlexandr Nedvedicky /* */ 2787a1173273SAlexandr Nedvedicky /* The packet looks as follows: */ 2788a1173273SAlexandr Nedvedicky /* xxx | IP hdr | IP payload ... | */ 2789a1173273SAlexandr Nedvedicky /* ^ ^ ^ ^ */ 2790a1173273SAlexandr Nedvedicky /* | | | | */ 2791a1173273SAlexandr Nedvedicky /* | | | fin_m->b_wptr = fin->fin_dp + fin->fin_dlen */ 2792a1173273SAlexandr Nedvedicky /* | | | */ 2793a1173273SAlexandr Nedvedicky /* | | `- fin_m->fin_dp (in case of IPv4 points to L4 header) */ 2794a1173273SAlexandr Nedvedicky /* | | */ 2795a1173273SAlexandr Nedvedicky /* | `- fin_m->b_rptr + fin_ipoff (fin_ipoff is most likely 0 in case */ 2796a1173273SAlexandr Nedvedicky /* | of loopback) */ 2797a1173273SAlexandr Nedvedicky /* | */ 2798a1173273SAlexandr Nedvedicky /* `- fin_m->b_rptr - points to L2 header in case of physical NIC */ 2799a1173273SAlexandr Nedvedicky /* */ 2800a1173273SAlexandr Nedvedicky /* All relevant IP headers are pulled up into the first mblk. It happened */ 2801a1173273SAlexandr Nedvedicky /* well in advance before the matching rule was found (the rule, which took */ 2802a1173273SAlexandr Nedvedicky /* us here, to fr_make_icmp() function). */ 2803a1173273SAlexandr Nedvedicky /* */ 2804a1173273SAlexandr Nedvedicky /* Both functions will turn packet passed in fin->fin_m mblk into a new */ 2805a1173273SAlexandr Nedvedicky /* packet. New packet will be represented as chain of mblks. */ 2806a1173273SAlexandr Nedvedicky /* orig mblk |- b_cont ---. */ 2807a1173273SAlexandr Nedvedicky /* ^ `-> ICMP hdr |- b_cont--. */ 2808a1173273SAlexandr Nedvedicky /* | ^ `-> duped orig mblk */ 2809a1173273SAlexandr Nedvedicky /* | | ^ */ 2810a1173273SAlexandr Nedvedicky /* `- The original mblk | | */ 2811a1173273SAlexandr Nedvedicky /* will be trimmed to | | */ 2812a1173273SAlexandr Nedvedicky /* to contain IP header | | */ 2813a1173273SAlexandr Nedvedicky /* only | | */ 2814a1173273SAlexandr Nedvedicky /* | | */ 2815a1173273SAlexandr Nedvedicky /* `- This is newly | */ 2816a1173273SAlexandr Nedvedicky /* allocated mblk to | */ 2817a1173273SAlexandr Nedvedicky /* hold ICMPv6 data. | */ 2818a1173273SAlexandr Nedvedicky /* | */ 2819a1173273SAlexandr Nedvedicky /* | */ 2820a1173273SAlexandr Nedvedicky /* | */ 2821a1173273SAlexandr Nedvedicky /* This is the copy of original mblk, it will contain -' */ 2822a1173273SAlexandr Nedvedicky /* orignal IP packet in case of ICMPv6. In case of */ 2823a1173273SAlexandr Nedvedicky /* ICMPv4 it will contain up to 8 bytes of IP payload */ 2824a1173273SAlexandr Nedvedicky /* (TCP/UDP/L4) data from original packet. */ 2825a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2826a1173273SAlexandr Nedvedicky int fr_make_icmp(fin) 2827a1173273SAlexandr Nedvedicky fr_info_t *fin; 2828a1173273SAlexandr Nedvedicky { 2829a1173273SAlexandr Nedvedicky int rv; 2830a1173273SAlexandr Nedvedicky 2831a1173273SAlexandr Nedvedicky if (fin->fin_v == 4) 2832a1173273SAlexandr Nedvedicky rv = fr_make_icmp_v4(fin); 2833a1173273SAlexandr Nedvedicky #ifdef USE_INET6 2834a1173273SAlexandr Nedvedicky else if (fin->fin_v == 6) 2835a1173273SAlexandr Nedvedicky rv = fr_make_icmp_v6(fin); 2836a1173273SAlexandr Nedvedicky #endif 2837a1173273SAlexandr Nedvedicky else 2838a1173273SAlexandr Nedvedicky rv = -1; 2839a1173273SAlexandr Nedvedicky 2840a1173273SAlexandr Nedvedicky return (rv); 2841a1173273SAlexandr Nedvedicky } 2842d0dd088cSAlexandr Nedvedicky 2843d0dd088cSAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2844d0dd088cSAlexandr Nedvedicky /* Function: fr_buf_sum */ 2845d0dd088cSAlexandr Nedvedicky /* Returns: unsigned int - sum of buffer buf */ 2846d0dd088cSAlexandr Nedvedicky /* Parameters: buf - pointer to buf we want to sum up */ 2847d0dd088cSAlexandr Nedvedicky /* len - length of buffer buf */ 2848d0dd088cSAlexandr Nedvedicky /* */ 2849d0dd088cSAlexandr Nedvedicky /* Sums buffer buf. The result is used for chksum calculation. The buf */ 2850d0dd088cSAlexandr Nedvedicky /* argument must be aligned. */ 2851d0dd088cSAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2852d0dd088cSAlexandr Nedvedicky static uint32_t fr_buf_sum(buf, len) 2853d0dd088cSAlexandr Nedvedicky const void *buf; 2854d0dd088cSAlexandr Nedvedicky unsigned int len; 2855d0dd088cSAlexandr Nedvedicky { 2856d0dd088cSAlexandr Nedvedicky uint32_t sum = 0; 2857d0dd088cSAlexandr Nedvedicky uint16_t *b = (uint16_t *)buf; 2858d0dd088cSAlexandr Nedvedicky 2859d0dd088cSAlexandr Nedvedicky while (len > 1) { 2860d0dd088cSAlexandr Nedvedicky sum += *b++; 2861d0dd088cSAlexandr Nedvedicky len -= 2; 2862d0dd088cSAlexandr Nedvedicky } 2863d0dd088cSAlexandr Nedvedicky 2864d0dd088cSAlexandr Nedvedicky if (len == 1) 2865d0dd088cSAlexandr Nedvedicky sum += htons((*(unsigned char *)b) << 8); 2866d0dd088cSAlexandr Nedvedicky 2867d0dd088cSAlexandr Nedvedicky return (sum); 2868d0dd088cSAlexandr Nedvedicky } 2869d0dd088cSAlexandr Nedvedicky 2870d0dd088cSAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2871d0dd088cSAlexandr Nedvedicky /* Function: fr_calc_chksum */ 2872d0dd088cSAlexandr Nedvedicky /* Returns: void */ 2873d0dd088cSAlexandr Nedvedicky /* Parameters: fin - pointer to fr_info_t instance with packet data */ 2874d0dd088cSAlexandr Nedvedicky /* pkt - pointer to duplicated packet */ 2875d0dd088cSAlexandr Nedvedicky /* */ 2876d0dd088cSAlexandr Nedvedicky /* Calculates all chksums (L3, L4) for packet pkt. Works for both IP */ 2877d0dd088cSAlexandr Nedvedicky /* versions. */ 2878d0dd088cSAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2879d0dd088cSAlexandr Nedvedicky void fr_calc_chksum(fin, pkt) 2880d0dd088cSAlexandr Nedvedicky fr_info_t *fin; 2881d0dd088cSAlexandr Nedvedicky mb_t *pkt; 2882d0dd088cSAlexandr Nedvedicky { 2883d0dd088cSAlexandr Nedvedicky struct pseudo_hdr { 2884d0dd088cSAlexandr Nedvedicky union { 2885d0dd088cSAlexandr Nedvedicky struct in_addr in4; 2886d0dd088cSAlexandr Nedvedicky #ifdef USE_INET6 2887d0dd088cSAlexandr Nedvedicky struct in6_addr in6; 2888d0dd088cSAlexandr Nedvedicky #endif 2889d0dd088cSAlexandr Nedvedicky } src_addr; 2890d0dd088cSAlexandr Nedvedicky union { 2891d0dd088cSAlexandr Nedvedicky struct in_addr in4; 2892d0dd088cSAlexandr Nedvedicky #ifdef USE_INET6 2893d0dd088cSAlexandr Nedvedicky struct in6_addr in6; 2894d0dd088cSAlexandr Nedvedicky #endif 2895d0dd088cSAlexandr Nedvedicky } dst_addr; 2896d0dd088cSAlexandr Nedvedicky char zero; 2897d0dd088cSAlexandr Nedvedicky char proto; 2898d0dd088cSAlexandr Nedvedicky uint16_t len; 2899d0dd088cSAlexandr Nedvedicky } phdr; 2900d0dd088cSAlexandr Nedvedicky uint32_t sum, ip_sum; 2901d0dd088cSAlexandr Nedvedicky void *buf; 2902d0dd088cSAlexandr Nedvedicky uint16_t *l4_csum_p; 2903d0dd088cSAlexandr Nedvedicky tcphdr_t *tcp; 2904d0dd088cSAlexandr Nedvedicky udphdr_t *udp; 2905d0dd088cSAlexandr Nedvedicky icmphdr_t *icmp; 2906d0dd088cSAlexandr Nedvedicky #ifdef USE_INET6 2907d0dd088cSAlexandr Nedvedicky struct icmp6_hdr *icmp6; 2908d0dd088cSAlexandr Nedvedicky #endif 2909d0dd088cSAlexandr Nedvedicky ip_t *ip; 2910d0dd088cSAlexandr Nedvedicky unsigned int len; 2911d0dd088cSAlexandr Nedvedicky int pld_len; 2912d0dd088cSAlexandr Nedvedicky 2913d0dd088cSAlexandr Nedvedicky /* 2914d0dd088cSAlexandr Nedvedicky * We need to pullup the packet to the single continuous buffer to avoid 2915d0dd088cSAlexandr Nedvedicky * potential misaligment of b_rptr member in mblk chain. 2916d0dd088cSAlexandr Nedvedicky */ 2917d0dd088cSAlexandr Nedvedicky if (pullupmsg(pkt, -1) == 0) { 2918d0dd088cSAlexandr Nedvedicky cmn_err(CE_WARN, "Failed to pullup loopback pkt -> chksum" 2919d0dd088cSAlexandr Nedvedicky " will not be computed by IPF"); 2920d0dd088cSAlexandr Nedvedicky return; 2921d0dd088cSAlexandr Nedvedicky } 2922d0dd088cSAlexandr Nedvedicky 2923d0dd088cSAlexandr Nedvedicky /* 2924d0dd088cSAlexandr Nedvedicky * It is guaranteed IP header starts right at b_rptr, because we are 2925d0dd088cSAlexandr Nedvedicky * working with a copy of the original packet. 2926d0dd088cSAlexandr Nedvedicky * 2927d0dd088cSAlexandr Nedvedicky * Compute pseudo header chksum for TCP and UDP. 2928d0dd088cSAlexandr Nedvedicky */ 2929d0dd088cSAlexandr Nedvedicky if ((fin->fin_p == IPPROTO_UDP) || 2930d0dd088cSAlexandr Nedvedicky (fin->fin_p == IPPROTO_TCP)) { 2931d0dd088cSAlexandr Nedvedicky bzero(&phdr, sizeof (phdr)); 2932d0dd088cSAlexandr Nedvedicky #ifdef USE_INET6 2933d0dd088cSAlexandr Nedvedicky if (fin->fin_v == 6) { 2934d0dd088cSAlexandr Nedvedicky phdr.src_addr.in6 = fin->fin_srcip6; 2935d0dd088cSAlexandr Nedvedicky phdr.dst_addr.in6 = fin->fin_dstip6; 2936d0dd088cSAlexandr Nedvedicky } else { 2937d0dd088cSAlexandr Nedvedicky phdr.src_addr.in4 = fin->fin_src; 2938d0dd088cSAlexandr Nedvedicky phdr.dst_addr.in4 = fin->fin_dst; 2939d0dd088cSAlexandr Nedvedicky } 2940d0dd088cSAlexandr Nedvedicky #else 2941d0dd088cSAlexandr Nedvedicky phdr.src_addr.in4 = fin->fin_src; 2942d0dd088cSAlexandr Nedvedicky phdr.dst_addr.in4 = fin->fin_dst; 2943d0dd088cSAlexandr Nedvedicky #endif 2944d0dd088cSAlexandr Nedvedicky phdr.zero = (char) 0; 2945d0dd088cSAlexandr Nedvedicky phdr.proto = fin->fin_p; 2946d0dd088cSAlexandr Nedvedicky phdr.len = htons((uint16_t)fin->fin_dlen); 2947d0dd088cSAlexandr Nedvedicky sum = fr_buf_sum(&phdr, (unsigned int)sizeof (phdr)); 2948d0dd088cSAlexandr Nedvedicky } else { 2949d0dd088cSAlexandr Nedvedicky sum = 0; 2950d0dd088cSAlexandr Nedvedicky } 2951d0dd088cSAlexandr Nedvedicky 2952d0dd088cSAlexandr Nedvedicky /* 2953d0dd088cSAlexandr Nedvedicky * Set pointer to the L4 chksum field in the packet, set buf pointer to 2954d0dd088cSAlexandr Nedvedicky * the L4 header start. 2955d0dd088cSAlexandr Nedvedicky */ 2956d0dd088cSAlexandr Nedvedicky switch (fin->fin_p) { 2957d0dd088cSAlexandr Nedvedicky case IPPROTO_UDP: 2958d0dd088cSAlexandr Nedvedicky udp = (udphdr_t *)(pkt->b_rptr + fin->fin_hlen); 2959d0dd088cSAlexandr Nedvedicky l4_csum_p = &udp->uh_sum; 2960d0dd088cSAlexandr Nedvedicky buf = udp; 2961d0dd088cSAlexandr Nedvedicky break; 2962d0dd088cSAlexandr Nedvedicky case IPPROTO_TCP: 2963d0dd088cSAlexandr Nedvedicky tcp = (tcphdr_t *)(pkt->b_rptr + fin->fin_hlen); 2964d0dd088cSAlexandr Nedvedicky l4_csum_p = &tcp->th_sum; 2965d0dd088cSAlexandr Nedvedicky buf = tcp; 2966d0dd088cSAlexandr Nedvedicky break; 2967d0dd088cSAlexandr Nedvedicky case IPPROTO_ICMP: 2968d0dd088cSAlexandr Nedvedicky icmp = (icmphdr_t *)(pkt->b_rptr + fin->fin_hlen); 2969d0dd088cSAlexandr Nedvedicky l4_csum_p = &icmp->icmp_cksum; 2970d0dd088cSAlexandr Nedvedicky buf = icmp; 2971d0dd088cSAlexandr Nedvedicky break; 2972d0dd088cSAlexandr Nedvedicky #ifdef USE_INET6 2973d0dd088cSAlexandr Nedvedicky case IPPROTO_ICMPV6: 2974d0dd088cSAlexandr Nedvedicky icmp6 = (struct icmp6_hdr *)(pkt->b_rptr + fin->fin_hlen); 2975d0dd088cSAlexandr Nedvedicky l4_csum_p = &icmp6->icmp6_cksum; 2976d0dd088cSAlexandr Nedvedicky buf = icmp6; 2977d0dd088cSAlexandr Nedvedicky break; 2978d0dd088cSAlexandr Nedvedicky #endif 2979d0dd088cSAlexandr Nedvedicky default: 2980d0dd088cSAlexandr Nedvedicky l4_csum_p = NULL; 2981d0dd088cSAlexandr Nedvedicky } 2982d0dd088cSAlexandr Nedvedicky 2983d0dd088cSAlexandr Nedvedicky /* 2984d0dd088cSAlexandr Nedvedicky * Compute L4 chksum if needed. 2985d0dd088cSAlexandr Nedvedicky */ 2986d0dd088cSAlexandr Nedvedicky if (l4_csum_p != NULL) { 2987d0dd088cSAlexandr Nedvedicky *l4_csum_p = (uint16_t)0; 2988d0dd088cSAlexandr Nedvedicky pld_len = fin->fin_dlen; 2989d0dd088cSAlexandr Nedvedicky len = pkt->b_wptr - (unsigned char *)buf; 2990d0dd088cSAlexandr Nedvedicky ASSERT(len == pld_len); 2991d0dd088cSAlexandr Nedvedicky /* 2992d0dd088cSAlexandr Nedvedicky * Add payload sum to pseudoheader sum. 2993d0dd088cSAlexandr Nedvedicky */ 2994d0dd088cSAlexandr Nedvedicky sum += fr_buf_sum(buf, len); 2995d0dd088cSAlexandr Nedvedicky while (sum >> 16) 2996d0dd088cSAlexandr Nedvedicky sum = (sum & 0xFFFF) + (sum >> 16); 2997d0dd088cSAlexandr Nedvedicky 2998d0dd088cSAlexandr Nedvedicky *l4_csum_p = ~((uint16_t)sum); 2999d0dd088cSAlexandr Nedvedicky DTRACE_PROBE1(l4_sum, uint16_t, *l4_csum_p); 3000d0dd088cSAlexandr Nedvedicky } 3001d0dd088cSAlexandr Nedvedicky 3002d0dd088cSAlexandr Nedvedicky /* 3003d0dd088cSAlexandr Nedvedicky * The IP header chksum is needed just for IPv4. 3004d0dd088cSAlexandr Nedvedicky */ 3005d0dd088cSAlexandr Nedvedicky if (fin->fin_v == 4) { 3006d0dd088cSAlexandr Nedvedicky /* 3007d0dd088cSAlexandr Nedvedicky * Compute IPv4 header chksum. 3008d0dd088cSAlexandr Nedvedicky */ 3009d0dd088cSAlexandr Nedvedicky ip = (ip_t *)pkt->b_rptr; 3010d0dd088cSAlexandr Nedvedicky ip->ip_sum = (uint16_t)0; 3011d0dd088cSAlexandr Nedvedicky ip_sum = fr_buf_sum(ip, (unsigned int)fin->fin_hlen); 3012d0dd088cSAlexandr Nedvedicky while (ip_sum >> 16) 3013d0dd088cSAlexandr Nedvedicky ip_sum = (ip_sum & 0xFFFF) + (ip_sum >> 16); 3014d0dd088cSAlexandr Nedvedicky 3015d0dd088cSAlexandr Nedvedicky ip->ip_sum = ~((uint16_t)ip_sum); 3016d0dd088cSAlexandr Nedvedicky DTRACE_PROBE1(l3_sum, uint16_t, ip->ip_sum); 3017d0dd088cSAlexandr Nedvedicky } 3018d0dd088cSAlexandr Nedvedicky 3019d0dd088cSAlexandr Nedvedicky return; 3020d0dd088cSAlexandr Nedvedicky } 3021d0dd088cSAlexandr Nedvedicky 3022a1173273SAlexandr Nedvedicky #endif /* _KERNEL && SOLARIS2 >= 10 */ 3023