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 * 8ec71f88eSPatrick 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> 25b22a70abSPatrick Mooney #include <sys/strsun.h> 267c478bd9Sstevel@tonic-gate #include <sys/cred.h> 277c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 287c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 297c478bd9Sstevel@tonic-gate #include <sys/ksynch.h> 307c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 31ec71f88eSPatrick Mooney #include <sys/mac_provider.h> 327c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 337c478bd9Sstevel@tonic-gate #include <sys/protosw.h> 347c478bd9Sstevel@tonic-gate #include <sys/socket.h> 357c478bd9Sstevel@tonic-gate #include <sys/dditypes.h> 367c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 37f4b3ec61Sdh #include <sys/zone.h> 387c478bd9Sstevel@tonic-gate #include <net/if.h> 397c478bd9Sstevel@tonic-gate #include <net/af.h> 407c478bd9Sstevel@tonic-gate #include <net/route.h> 417c478bd9Sstevel@tonic-gate #include <netinet/in.h> 427c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h> 437c478bd9Sstevel@tonic-gate #include <netinet/ip.h> 447c478bd9Sstevel@tonic-gate #include <netinet/ip_var.h> 457c478bd9Sstevel@tonic-gate #include <netinet/tcp.h> 467c478bd9Sstevel@tonic-gate #include <netinet/udp.h> 477c478bd9Sstevel@tonic-gate #include <netinet/tcpip.h> 487c478bd9Sstevel@tonic-gate #include <netinet/ip_icmp.h> 49ab25eeb5Syz #include "netinet/ip_compat.h" 507c478bd9Sstevel@tonic-gate #ifdef USE_INET6 517c478bd9Sstevel@tonic-gate # include <netinet/icmp6.h> 527c478bd9Sstevel@tonic-gate #endif 53ab25eeb5Syz #include "netinet/ip_fil.h" 54ab25eeb5Syz #include "netinet/ip_nat.h" 55ab25eeb5Syz #include "netinet/ip_frag.h" 56ab25eeb5Syz #include "netinet/ip_state.h" 57ab25eeb5Syz #include "netinet/ip_auth.h" 58ab25eeb5Syz #include "netinet/ip_proxy.h" 59f4b3ec61Sdh #include "netinet/ipf_stack.h" 607c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOOKUP 61ab25eeb5Syz # include "netinet/ip_lookup.h" 627c478bd9Sstevel@tonic-gate #endif 637c478bd9Sstevel@tonic-gate #include <inet/ip_ire.h> 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate #include <sys/md5.h> 66381a2a9aSdr #include <sys/neti.h> 677c478bd9Sstevel@tonic-gate 68f4b3ec61Sdh static int frzerostats __P((caddr_t, ipf_stack_t *)); 69f4b3ec61Sdh static int fr_setipfloopback __P((int, ipf_stack_t *)); 707ddc9b1aSDarren Reed static int fr_enableipf __P((ipf_stack_t *, int)); 71ab25eeb5Syz static int fr_send_ip __P((fr_info_t *fin, mblk_t *m, mblk_t **mp)); 727ddc9b1aSDarren Reed static int ipf_nic_event_v4 __P((hook_event_token_t, hook_data_t, void *)); 737ddc9b1aSDarren Reed static int ipf_nic_event_v6 __P((hook_event_token_t, hook_data_t, void *)); 747ddc9b1aSDarren Reed static int ipf_hook __P((hook_data_t, int, int, void *)); 757ddc9b1aSDarren Reed static int ipf_hook4_in __P((hook_event_token_t, hook_data_t, void *)); 767ddc9b1aSDarren Reed static int ipf_hook4_out __P((hook_event_token_t, hook_data_t, void *)); 77cbded9aeSdr static int ipf_hook4_loop_out __P((hook_event_token_t, hook_data_t, 787ddc9b1aSDarren Reed void *)); 797ddc9b1aSDarren Reed static int ipf_hook4_loop_in __P((hook_event_token_t, hook_data_t, void *)); 807ddc9b1aSDarren Reed static int ipf_hook4 __P((hook_data_t, int, int, void *)); 817ddc9b1aSDarren Reed static int ipf_hook6_out __P((hook_event_token_t, hook_data_t, void *)); 827ddc9b1aSDarren Reed static int ipf_hook6_in __P((hook_event_token_t, hook_data_t, void *)); 83cbded9aeSdr static int ipf_hook6_loop_out __P((hook_event_token_t, hook_data_t, 847ddc9b1aSDarren Reed void *)); 85cbded9aeSdr static int ipf_hook6_loop_in __P((hook_event_token_t, hook_data_t, 867ddc9b1aSDarren Reed void *)); 877ddc9b1aSDarren Reed static int ipf_hook6 __P((hook_data_t, int, int, void *)); 88b22a70abSPatrick Mooney 89b22a70abSPatrick Mooney static int ipf_hookviona_in __P((hook_event_token_t, hook_data_t, void *)); 90b22a70abSPatrick Mooney static int ipf_hookviona_out __P((hook_event_token_t, hook_data_t, 91b22a70abSPatrick Mooney void *)); 92b22a70abSPatrick Mooney 93f4b3ec61Sdh extern int ipf_geniter __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *)); 94f4b3ec61Sdh extern int ipf_frruleiter __P((void *, int, void *, ipf_stack_t *)); 95f4b3ec61Sdh 96b22a70abSPatrick Mooney static int ipf_hook_protocol_notify __P((hook_notify_cmd_t, void *, 97b22a70abSPatrick Mooney const char *, const char *, const char *)); 98b22a70abSPatrick Mooney static int ipf_hook_instance_notify __P((hook_notify_cmd_t, void *, 99b22a70abSPatrick Mooney const char *, const char *, const char *)); 100b22a70abSPatrick Mooney 1017c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 1027c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 7 103ab25eeb5Syz u_int *ip_ttl_ptr = NULL; 104ab25eeb5Syz u_int *ip_mtudisc = NULL; 1057c478bd9Sstevel@tonic-gate # if SOLARIS2 >= 8 106ab25eeb5Syz int *ip_forwarding = NULL; 107ab25eeb5Syz u_int *ip6_forwarding = NULL; 1087c478bd9Sstevel@tonic-gate # else 109ab25eeb5Syz u_int *ip_forwarding = NULL; 1107c478bd9Sstevel@tonic-gate # endif 1117c478bd9Sstevel@tonic-gate #else 112ab25eeb5Syz u_long *ip_ttl_ptr = NULL; 113ab25eeb5Syz u_long *ip_mtudisc = NULL; 114ab25eeb5Syz u_long *ip_forwarding = NULL; 1157c478bd9Sstevel@tonic-gate #endif 1167c478bd9Sstevel@tonic-gate #endif 1177c478bd9Sstevel@tonic-gate 11894bdecd9SRob Gulewich vmem_t *ipf_minor; /* minor number arena */ 11994bdecd9SRob Gulewich void *ipf_state; /* DDI state */ 12094bdecd9SRob Gulewich 12194bdecd9SRob Gulewich /* 12294bdecd9SRob Gulewich * GZ-controlled and per-zone stacks: 12394bdecd9SRob Gulewich * 12494bdecd9SRob Gulewich * For each non-global zone, we create two ipf stacks: the per-zone stack and 12594bdecd9SRob Gulewich * the GZ-controlled stack. The per-zone stack can be controlled and observed 12694bdecd9SRob Gulewich * from inside the zone or from the global zone. The GZ-controlled stack can 12794bdecd9SRob Gulewich * only be controlled and observed from the global zone (though the rules 12894bdecd9SRob Gulewich * still only affect that non-global zone). 12994bdecd9SRob Gulewich * 13094bdecd9SRob Gulewich * The two hooks are always arranged so that the GZ-controlled stack is always 13194bdecd9SRob Gulewich * "outermost" with respect to the zone. The traffic flow then looks like 13294bdecd9SRob Gulewich * this: 13394bdecd9SRob Gulewich * 13494bdecd9SRob Gulewich * Inbound: 13594bdecd9SRob Gulewich * 13694bdecd9SRob Gulewich * nic ---> [ GZ-controlled rules ] ---> [ per-zone rules ] ---> zone 13794bdecd9SRob Gulewich * 13894bdecd9SRob Gulewich * Outbound: 13994bdecd9SRob Gulewich * 14094bdecd9SRob Gulewich * nic <--- [ GZ-controlled rules ] <--- [ per-zone rules ] <--- zone 14194bdecd9SRob Gulewich */ 14294bdecd9SRob Gulewich 14394bdecd9SRob Gulewich /* IPv4 hook names */ 14494bdecd9SRob Gulewich char *hook4_nicevents = "ipfilter_hook4_nicevents"; 14594bdecd9SRob Gulewich char *hook4_nicevents_gz = "ipfilter_hook4_nicevents_gz"; 14694bdecd9SRob Gulewich char *hook4_in = "ipfilter_hook4_in"; 14794bdecd9SRob Gulewich char *hook4_in_gz = "ipfilter_hook4_in_gz"; 14894bdecd9SRob Gulewich char *hook4_out = "ipfilter_hook4_out"; 14994bdecd9SRob Gulewich char *hook4_out_gz = "ipfilter_hook4_out_gz"; 15094bdecd9SRob Gulewich char *hook4_loop_in = "ipfilter_hook4_loop_in"; 15194bdecd9SRob Gulewich char *hook4_loop_in_gz = "ipfilter_hook4_loop_in_gz"; 15294bdecd9SRob Gulewich char *hook4_loop_out = "ipfilter_hook4_loop_out"; 15394bdecd9SRob Gulewich char *hook4_loop_out_gz = "ipfilter_hook4_loop_out_gz"; 15494bdecd9SRob Gulewich 15594bdecd9SRob Gulewich /* IPv6 hook names */ 15694bdecd9SRob Gulewich char *hook6_nicevents = "ipfilter_hook6_nicevents"; 15794bdecd9SRob Gulewich char *hook6_nicevents_gz = "ipfilter_hook6_nicevents_gz"; 15894bdecd9SRob Gulewich char *hook6_in = "ipfilter_hook6_in"; 15994bdecd9SRob Gulewich char *hook6_in_gz = "ipfilter_hook6_in_gz"; 16094bdecd9SRob Gulewich char *hook6_out = "ipfilter_hook6_out"; 16194bdecd9SRob Gulewich char *hook6_out_gz = "ipfilter_hook6_out_gz"; 16294bdecd9SRob Gulewich char *hook6_loop_in = "ipfilter_hook6_loop_in"; 16394bdecd9SRob Gulewich char *hook6_loop_in_gz = "ipfilter_hook6_loop_in_gz"; 16494bdecd9SRob Gulewich char *hook6_loop_out = "ipfilter_hook6_loop_out"; 16594bdecd9SRob Gulewich char *hook6_loop_out_gz = "ipfilter_hook6_loop_out_gz"; 1667c478bd9Sstevel@tonic-gate 167b22a70abSPatrick Mooney /* viona hook names */ 168b22a70abSPatrick Mooney char *hook_viona_in = "ipfilter_hookviona_in"; 169b22a70abSPatrick Mooney char *hook_viona_in_gz = "ipfilter_hookviona_in_gz"; 170b22a70abSPatrick Mooney char *hook_viona_out = "ipfilter_hookviona_out"; 171b22a70abSPatrick Mooney char *hook_viona_out_gz = "ipfilter_hookviona_out_gz"; 172b22a70abSPatrick Mooney 1737c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 1747c478bd9Sstevel@tonic-gate /* Function: ipldetach */ 1757c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, else error. */ 1767c478bd9Sstevel@tonic-gate /* Parameters: Nil */ 1777c478bd9Sstevel@tonic-gate /* */ 1787c478bd9Sstevel@tonic-gate /* This function is responsible for undoing anything that might have been */ 1797c478bd9Sstevel@tonic-gate /* done in a call to iplattach(). It must be able to clean up from a call */ 1807c478bd9Sstevel@tonic-gate /* to iplattach() that did not succeed. Why might that happen? Someone */ 1817c478bd9Sstevel@tonic-gate /* configures a table to be so large that we cannot allocate enough memory */ 1827c478bd9Sstevel@tonic-gate /* for it. */ 1837c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 184f4b3ec61Sdh int ipldetach(ifs) 185f4b3ec61Sdh ipf_stack_t *ifs; 1867c478bd9Sstevel@tonic-gate { 1877c478bd9Sstevel@tonic-gate 18894bdecd9SRob Gulewich ASSERT(RW_WRITE_HELD(&ifs->ifs_ipf_global.ipf_lk)); 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 1917c478bd9Sstevel@tonic-gate 192f4b3ec61Sdh if (ifs->ifs_fr_control_forwarding & 2) { 193ab25eeb5Syz if (ip_forwarding != NULL) 194ab25eeb5Syz *ip_forwarding = 0; 1957c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 196ab25eeb5Syz if (ip6_forwarding != NULL) 197ab25eeb5Syz *ip6_forwarding = 0; 1987c478bd9Sstevel@tonic-gate #endif 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate #endif 2017c478bd9Sstevel@tonic-gate 202381a2a9aSdr /* 2037ddc9b1aSDarren Reed * This lock needs to be dropped around the net_hook_unregister calls 204381a2a9aSdr * because we can deadlock here with: 205381a2a9aSdr * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs 206381a2a9aSdr * R(hook_family)->R(hei_lock)->R(ipf_global) (active hook running) 207381a2a9aSdr */ 208f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 209381a2a9aSdr 2107ddc9b1aSDarren Reed #define UNDO_HOOK(_f, _b, _e, _h) \ 2117ddc9b1aSDarren Reed do { \ 2127ddc9b1aSDarren Reed if (ifs->_f != NULL) { \ 2137ddc9b1aSDarren Reed if (ifs->_b) { \ 214c6798761SJerry Jelinek int tmp = net_hook_unregister(ifs->_f, \ 215c6798761SJerry Jelinek _e, ifs->_h); \ 216c6798761SJerry Jelinek ifs->_b = (tmp != 0 && tmp != ENXIO); \ 217c6798761SJerry Jelinek if (!ifs->_b && ifs->_h != NULL) { \ 2187ddc9b1aSDarren Reed hook_free(ifs->_h); \ 2197ddc9b1aSDarren Reed ifs->_h = NULL; \ 2207ddc9b1aSDarren Reed } \ 2217ddc9b1aSDarren Reed } else if (ifs->_h != NULL) { \ 2227ddc9b1aSDarren Reed hook_free(ifs->_h); \ 2237ddc9b1aSDarren Reed ifs->_h = NULL; \ 2247ddc9b1aSDarren Reed } \ 2257ddc9b1aSDarren Reed } \ 2267ddc9b1aSDarren Reed _NOTE(CONSTCOND) \ 2277ddc9b1aSDarren Reed } while (0) 2287ddc9b1aSDarren Reed 229381a2a9aSdr /* 230381a2a9aSdr * Remove IPv6 Hooks 231381a2a9aSdr */ 232f4b3ec61Sdh if (ifs->ifs_ipf_ipv6 != NULL) { 2337ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_in, 2347ddc9b1aSDarren Reed NH_PHYSICAL_IN, ifs_ipfhook6_in); 2357ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_out, 2367ddc9b1aSDarren Reed NH_PHYSICAL_OUT, ifs_ipfhook6_out); 2377ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_nic_events, 2387ddc9b1aSDarren Reed NH_NIC_EVENTS, ifs_ipfhook6_nicevents); 2397ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_in, 2407ddc9b1aSDarren Reed NH_LOOPBACK_IN, ifs_ipfhook6_loop_in); 2417ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_out, 2427ddc9b1aSDarren Reed NH_LOOPBACK_OUT, ifs_ipfhook6_loop_out); 2437ddc9b1aSDarren Reed 2447ddc9b1aSDarren Reed if (net_protocol_release(ifs->ifs_ipf_ipv6) != 0) 245381a2a9aSdr goto detach_failed; 246f4b3ec61Sdh ifs->ifs_ipf_ipv6 = NULL; 247381a2a9aSdr } 248381a2a9aSdr 249381a2a9aSdr /* 250381a2a9aSdr * Remove IPv4 Hooks 251381a2a9aSdr */ 252f4b3ec61Sdh if (ifs->ifs_ipf_ipv4 != NULL) { 2537ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_in, 2547ddc9b1aSDarren Reed NH_PHYSICAL_IN, ifs_ipfhook4_in); 2557ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_out, 2567ddc9b1aSDarren Reed NH_PHYSICAL_OUT, ifs_ipfhook4_out); 2577ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_nic_events, 2587ddc9b1aSDarren Reed NH_NIC_EVENTS, ifs_ipfhook4_nicevents); 2597ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_in, 2607ddc9b1aSDarren Reed NH_LOOPBACK_IN, ifs_ipfhook4_loop_in); 2617ddc9b1aSDarren Reed UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_out, 2627ddc9b1aSDarren Reed NH_LOOPBACK_OUT, ifs_ipfhook4_loop_out); 2637ddc9b1aSDarren Reed 2647ddc9b1aSDarren Reed if (net_protocol_release(ifs->ifs_ipf_ipv4) != 0) 265381a2a9aSdr goto detach_failed; 266f4b3ec61Sdh ifs->ifs_ipf_ipv4 = NULL; 267381a2a9aSdr } 268381a2a9aSdr 269b22a70abSPatrick Mooney /* 270b22a70abSPatrick Mooney * Remove notification of viona hooks 271b22a70abSPatrick Mooney */ 272b22a70abSPatrick Mooney net_instance_notify_unregister(ifs->ifs_netid, 273b22a70abSPatrick Mooney ipf_hook_instance_notify); 274b22a70abSPatrick Mooney 2757ddc9b1aSDarren Reed #undef UNDO_HOOK 2767ddc9b1aSDarren Reed 277b22a70abSPatrick Mooney /* 278b22a70abSPatrick Mooney * Normally, viona will unregister itself before ipldetach() is called, 279b22a70abSPatrick Mooney * so these will be no-ops, but out of caution, we try to make sure 280b22a70abSPatrick Mooney * we've removed any of our references. 281b22a70abSPatrick Mooney */ 282b22a70abSPatrick Mooney (void) ipf_hook_protocol_notify(HN_UNREGISTER, ifs, Hn_VIONA, NULL, 283b22a70abSPatrick Mooney NH_PHYSICAL_IN); 284b22a70abSPatrick Mooney (void) ipf_hook_protocol_notify(HN_UNREGISTER, ifs, Hn_VIONA, NULL, 285b22a70abSPatrick Mooney NH_PHYSICAL_OUT); 286b22a70abSPatrick Mooney 287b22a70abSPatrick Mooney { 288b22a70abSPatrick Mooney char netidstr[12]; /* Large enough for INT_MAX + NUL */ 289b22a70abSPatrick Mooney (void) snprintf(netidstr, sizeof (netidstr), "%d", 290b22a70abSPatrick Mooney ifs->ifs_netid); 291b22a70abSPatrick Mooney 292b22a70abSPatrick Mooney /* 293b22a70abSPatrick Mooney * The notify callbacks expect the netid value passed as a 294b22a70abSPatrick Mooney * string in the third argument. To prevent confusion if 295b22a70abSPatrick Mooney * traced, we pass the same value the nethook framework would 296b22a70abSPatrick Mooney * pass, even though the callback does not currently use the 297b22a70abSPatrick Mooney * value. 298b22a70abSPatrick Mooney */ 299b22a70abSPatrick Mooney (void) ipf_hook_instance_notify(HN_UNREGISTER, ifs, netidstr, 300b22a70abSPatrick Mooney NULL, Hn_VIONA); 301b22a70abSPatrick Mooney } 302b22a70abSPatrick Mooney 3037c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 3047c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "ipldetach()\n"); 3057c478bd9Sstevel@tonic-gate #endif 3067c478bd9Sstevel@tonic-gate 307f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 308f4b3ec61Sdh fr_deinitialise(ifs); 3097c478bd9Sstevel@tonic-gate 310f4b3ec61Sdh (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE, ifs); 311f4b3ec61Sdh (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE, ifs); 3127c478bd9Sstevel@tonic-gate 313f4b3ec61Sdh if (ifs->ifs_ipf_locks_done == 1) { 314f4b3ec61Sdh MUTEX_DESTROY(&ifs->ifs_ipf_timeoutlock); 315f4b3ec61Sdh MUTEX_DESTROY(&ifs->ifs_ipf_rw); 316f4b3ec61Sdh RW_DESTROY(&ifs->ifs_ipf_tokens); 317f4b3ec61Sdh RW_DESTROY(&ifs->ifs_ipf_ipidfrag); 318f4b3ec61Sdh ifs->ifs_ipf_locks_done = 0; 3197c478bd9Sstevel@tonic-gate } 320381a2a9aSdr 3217ddc9b1aSDarren Reed if (ifs->ifs_hook4_physical_in || ifs->ifs_hook4_physical_out || 3227ddc9b1aSDarren Reed ifs->ifs_hook4_nic_events || ifs->ifs_hook4_loopback_in || 3237ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_out || ifs->ifs_hook6_nic_events || 3247ddc9b1aSDarren Reed ifs->ifs_hook6_physical_in || ifs->ifs_hook6_physical_out || 3257ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_in || ifs->ifs_hook6_loopback_out) 326381a2a9aSdr return -1; 327381a2a9aSdr 3287c478bd9Sstevel@tonic-gate return 0; 329381a2a9aSdr 330381a2a9aSdr detach_failed: 331f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 332381a2a9aSdr return -1; 3337c478bd9Sstevel@tonic-gate } 3347c478bd9Sstevel@tonic-gate 3357ddc9b1aSDarren Reed int iplattach(ifs) 336f4b3ec61Sdh ipf_stack_t *ifs; 3377c478bd9Sstevel@tonic-gate { 3387c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 3397c478bd9Sstevel@tonic-gate int i; 3407c478bd9Sstevel@tonic-gate #endif 3417ddc9b1aSDarren Reed netid_t id = ifs->ifs_netid; 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 3447c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplattach()\n"); 3457c478bd9Sstevel@tonic-gate #endif 3467c478bd9Sstevel@tonic-gate 34794bdecd9SRob Gulewich ASSERT(RW_WRITE_HELD(&ifs->ifs_ipf_global.ipf_lk)); 348f4b3ec61Sdh ifs->ifs_fr_flags = IPF_LOGGING; 349f4b3ec61Sdh #ifdef _KERNEL 350f4b3ec61Sdh ifs->ifs_fr_update_ipid = 0; 351f4b3ec61Sdh #else 352f4b3ec61Sdh ifs->ifs_fr_update_ipid = 1; 353f4b3ec61Sdh #endif 354f4b3ec61Sdh ifs->ifs_fr_minttl = 4; 355f4b3ec61Sdh ifs->ifs_fr_icmpminfragmtu = 68; 356f4b3ec61Sdh #if defined(IPFILTER_DEFAULT_BLOCK) 357f4b3ec61Sdh ifs->ifs_fr_pass = FR_BLOCK|FR_NOMATCH; 358f4b3ec61Sdh #else 359f4b3ec61Sdh ifs->ifs_fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH; 360f4b3ec61Sdh #endif 3617c478bd9Sstevel@tonic-gate 36214d3298eSAlexandr Nedvedicky bzero((char *)ifs->ifs_frcache, sizeof(ifs->ifs_frcache)); 363f4b3ec61Sdh MUTEX_INIT(&ifs->ifs_ipf_rw, "ipf rw mutex"); 364f4b3ec61Sdh MUTEX_INIT(&ifs->ifs_ipf_timeoutlock, "ipf timeout lock mutex"); 365f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); 366f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_tokens, "ipf token rwlock"); 367f4b3ec61Sdh ifs->ifs_ipf_locks_done = 1; 3687c478bd9Sstevel@tonic-gate 369f4b3ec61Sdh if (fr_initialise(ifs) < 0) 3707c478bd9Sstevel@tonic-gate return -1; 3717c478bd9Sstevel@tonic-gate 37294bdecd9SRob Gulewich /* 37394bdecd9SRob Gulewich * For incoming packets, we want the GZ-controlled hooks to run before 37494bdecd9SRob Gulewich * the per-zone hooks, regardless of what order they're are installed. 37594bdecd9SRob Gulewich * See the "GZ-controlled and per-zone stacks" comment block at the top 37694bdecd9SRob Gulewich * of this file. 37794bdecd9SRob Gulewich */ 37894bdecd9SRob Gulewich #define HOOK_INIT_GZ_BEFORE(x, fn, n, gzn, a) \ 37994bdecd9SRob Gulewich HOOK_INIT(x, fn, ifs->ifs_gz_controlled ? gzn : n, ifs); \ 38094bdecd9SRob Gulewich (x)->h_hint = ifs->ifs_gz_controlled ? HH_BEFORE : HH_AFTER; \ 38194bdecd9SRob Gulewich (x)->h_hintvalue = (uintptr_t) (ifs->ifs_gz_controlled ? n : gzn); 38294bdecd9SRob Gulewich 38394bdecd9SRob Gulewich HOOK_INIT_GZ_BEFORE(ifs->ifs_ipfhook4_nicevents, ipf_nic_event_v4, 38494bdecd9SRob Gulewich hook4_nicevents, hook4_nicevents_gz, ifs); 38594bdecd9SRob Gulewich HOOK_INIT_GZ_BEFORE(ifs->ifs_ipfhook4_in, ipf_hook4_in, 38694bdecd9SRob Gulewich hook4_in, hook4_in_gz, ifs); 38794bdecd9SRob Gulewich HOOK_INIT_GZ_BEFORE(ifs->ifs_ipfhook4_loop_in, ipf_hook4_loop_in, 38894bdecd9SRob Gulewich hook4_loop_in, hook4_loop_in_gz, ifs); 38994bdecd9SRob Gulewich 39094bdecd9SRob Gulewich /* 39194bdecd9SRob Gulewich * For outgoing packets, we want the GZ-controlled hooks to run after 39294bdecd9SRob Gulewich * the per-zone hooks, regardless of what order they're are installed. 39394bdecd9SRob Gulewich * See the "GZ-controlled and per-zone stacks" comment block at the top 39494bdecd9SRob Gulewich * of this file. 39594bdecd9SRob Gulewich */ 39694bdecd9SRob Gulewich #define HOOK_INIT_GZ_AFTER(x, fn, n, gzn, a) \ 39794bdecd9SRob Gulewich HOOK_INIT(x, fn, ifs->ifs_gz_controlled ? gzn : n, ifs); \ 39894bdecd9SRob Gulewich (x)->h_hint = ifs->ifs_gz_controlled ? HH_AFTER : HH_BEFORE; \ 39994bdecd9SRob Gulewich (x)->h_hintvalue = (uintptr_t) (ifs->ifs_gz_controlled ? n : gzn); 40094bdecd9SRob Gulewich 40194bdecd9SRob Gulewich HOOK_INIT_GZ_AFTER(ifs->ifs_ipfhook4_out, ipf_hook4_out, 40294bdecd9SRob Gulewich hook4_out, hook4_out_gz, ifs); 40394bdecd9SRob Gulewich HOOK_INIT_GZ_AFTER(ifs->ifs_ipfhook4_loop_out, ipf_hook4_loop_out, 40494bdecd9SRob Gulewich hook4_loop_out, hook4_loop_out_gz, ifs); 405381a2a9aSdr 406381a2a9aSdr /* 4077ddc9b1aSDarren Reed * If we hold this lock over all of the net_hook_register calls, we 408381a2a9aSdr * can cause a deadlock to occur with the following lock ordering: 409381a2a9aSdr * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs 410381a2a9aSdr * R(hook_family)->R(hei_lock)->R(ipf_global) (packet path) 411381a2a9aSdr */ 412f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 413381a2a9aSdr 414381a2a9aSdr /* 415381a2a9aSdr * Add IPv4 hooks 416381a2a9aSdr */ 4177ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4 = net_protocol_lookup(id, NHF_INET); 418f4b3ec61Sdh if (ifs->ifs_ipf_ipv4 == NULL) 419381a2a9aSdr goto hookup_failed; 420381a2a9aSdr 4217ddc9b1aSDarren Reed ifs->ifs_hook4_nic_events = (net_hook_register(ifs->ifs_ipf_ipv4, 4227ddc9b1aSDarren Reed NH_NIC_EVENTS, ifs->ifs_ipfhook4_nicevents) == 0); 423f4b3ec61Sdh if (!ifs->ifs_hook4_nic_events) 424381a2a9aSdr goto hookup_failed; 425381a2a9aSdr 4267ddc9b1aSDarren Reed ifs->ifs_hook4_physical_in = (net_hook_register(ifs->ifs_ipf_ipv4, 4277ddc9b1aSDarren Reed NH_PHYSICAL_IN, ifs->ifs_ipfhook4_in) == 0); 428f4b3ec61Sdh if (!ifs->ifs_hook4_physical_in) 429381a2a9aSdr goto hookup_failed; 430381a2a9aSdr 4317ddc9b1aSDarren Reed ifs->ifs_hook4_physical_out = (net_hook_register(ifs->ifs_ipf_ipv4, 4327ddc9b1aSDarren Reed NH_PHYSICAL_OUT, ifs->ifs_ipfhook4_out) == 0); 433f4b3ec61Sdh if (!ifs->ifs_hook4_physical_out) 434381a2a9aSdr goto hookup_failed; 435381a2a9aSdr 436f4b3ec61Sdh if (ifs->ifs_ipf_loopback) { 4377ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_in = (net_hook_register( 4387ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN, 4397ddc9b1aSDarren Reed ifs->ifs_ipfhook4_loop_in) == 0); 440f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_in) 441381a2a9aSdr goto hookup_failed; 442381a2a9aSdr 4437ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_out = (net_hook_register( 4447ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT, 4457ddc9b1aSDarren Reed ifs->ifs_ipfhook4_loop_out) == 0); 446f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_out) 447381a2a9aSdr goto hookup_failed; 448381a2a9aSdr } 44994bdecd9SRob Gulewich 450381a2a9aSdr /* 451381a2a9aSdr * Add IPv6 hooks 452381a2a9aSdr */ 4537ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6 = net_protocol_lookup(id, NHF_INET6); 454f4b3ec61Sdh if (ifs->ifs_ipf_ipv6 == NULL) 455381a2a9aSdr goto hookup_failed; 456381a2a9aSdr 45794bdecd9SRob Gulewich HOOK_INIT_GZ_BEFORE(ifs->ifs_ipfhook6_nicevents, ipf_nic_event_v6, 45894bdecd9SRob Gulewich hook6_nicevents, hook6_nicevents_gz, ifs); 45994bdecd9SRob Gulewich HOOK_INIT_GZ_BEFORE(ifs->ifs_ipfhook6_in, ipf_hook6_in, 46094bdecd9SRob Gulewich hook6_in, hook6_in_gz, ifs); 46194bdecd9SRob Gulewich HOOK_INIT_GZ_BEFORE(ifs->ifs_ipfhook6_loop_in, ipf_hook6_loop_in, 46294bdecd9SRob Gulewich hook6_loop_in, hook6_loop_in_gz, ifs); 46394bdecd9SRob Gulewich HOOK_INIT_GZ_AFTER(ifs->ifs_ipfhook6_out, ipf_hook6_out, 46494bdecd9SRob Gulewich hook6_out, hook6_out_gz, ifs); 46594bdecd9SRob Gulewich HOOK_INIT_GZ_AFTER(ifs->ifs_ipfhook6_loop_out, ipf_hook6_loop_out, 46694bdecd9SRob Gulewich hook6_loop_out, hook6_loop_out_gz, ifs); 4677ddc9b1aSDarren Reed 4687ddc9b1aSDarren Reed ifs->ifs_hook6_nic_events = (net_hook_register(ifs->ifs_ipf_ipv6, 4697ddc9b1aSDarren Reed NH_NIC_EVENTS, ifs->ifs_ipfhook6_nicevents) == 0); 470f4b3ec61Sdh if (!ifs->ifs_hook6_nic_events) 471381a2a9aSdr goto hookup_failed; 472381a2a9aSdr 4737ddc9b1aSDarren Reed ifs->ifs_hook6_physical_in = (net_hook_register(ifs->ifs_ipf_ipv6, 4747ddc9b1aSDarren Reed NH_PHYSICAL_IN, ifs->ifs_ipfhook6_in) == 0); 475f4b3ec61Sdh if (!ifs->ifs_hook6_physical_in) 476381a2a9aSdr goto hookup_failed; 477381a2a9aSdr 4787ddc9b1aSDarren Reed ifs->ifs_hook6_physical_out = (net_hook_register(ifs->ifs_ipf_ipv6, 4797ddc9b1aSDarren Reed NH_PHYSICAL_OUT, ifs->ifs_ipfhook6_out) == 0); 480f4b3ec61Sdh if (!ifs->ifs_hook6_physical_out) 481381a2a9aSdr goto hookup_failed; 482381a2a9aSdr 483f4b3ec61Sdh if (ifs->ifs_ipf_loopback) { 4847ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_in = (net_hook_register( 4857ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN, 4867ddc9b1aSDarren Reed ifs->ifs_ipfhook6_loop_in) == 0); 487f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_in) 488381a2a9aSdr goto hookup_failed; 489381a2a9aSdr 4907ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_out = (net_hook_register( 4917ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT, 4927ddc9b1aSDarren Reed ifs->ifs_ipfhook6_loop_out) == 0); 493f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_out) 494381a2a9aSdr goto hookup_failed; 495381a2a9aSdr } 496381a2a9aSdr 497b22a70abSPatrick Mooney /* 498b22a70abSPatrick Mooney * VIONA INET hooks. While the nethook framework allows us to register 499b22a70abSPatrick Mooney * hooks for events that haven't been registered yet, we instead 500b22a70abSPatrick Mooney * register and unregister our hooks in response to notifications 501b22a70abSPatrick Mooney * about the viona hooks from the nethook framework. This prevents 502b22a70abSPatrick Mooney * problems when the viona module gets unloaded while the ipf module 503b22a70abSPatrick Mooney * does not. If we do not unregister our hooks after the viona module 504b22a70abSPatrick Mooney * is unloaded, the viona module cannot later re-register them if it 505b22a70abSPatrick Mooney * gets reloaded. As the ip, vnd, and ipf modules are rarely unloaded 506b22a70abSPatrick Mooney * even on DEBUG kernels, they do not experience this issue. 507b22a70abSPatrick Mooney */ 508b22a70abSPatrick Mooney if (net_instance_notify_register(id, ipf_hook_instance_notify, 509b22a70abSPatrick Mooney ifs) != 0) 510b22a70abSPatrick Mooney goto hookup_failed; 511b22a70abSPatrick Mooney 512381a2a9aSdr /* 513381a2a9aSdr * Reacquire ipf_global, now it is safe. 514381a2a9aSdr */ 515f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 516381a2a9aSdr 5177c478bd9Sstevel@tonic-gate /* Do not use private interface ip_params_arr[] in Solaris 10 */ 5187c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 5217c478bd9Sstevel@tonic-gate ip_forwarding = &ip_g_forward; 5227c478bd9Sstevel@tonic-gate #endif 5237c478bd9Sstevel@tonic-gate /* 5247c478bd9Sstevel@tonic-gate * XXX - There is no terminator for this array, so it is not possible 5257c478bd9Sstevel@tonic-gate * to tell if what we are looking for is missing and go off the end 5267c478bd9Sstevel@tonic-gate * of the array. 5277c478bd9Sstevel@tonic-gate */ 5287c478bd9Sstevel@tonic-gate 529ab25eeb5Syz #if SOLARIS2 <= 8 5307c478bd9Sstevel@tonic-gate for (i = 0; ; i++) { 5317c478bd9Sstevel@tonic-gate if (!strcmp(ip_param_arr[i].ip_param_name, "ip_def_ttl")) { 5327c478bd9Sstevel@tonic-gate ip_ttl_ptr = &ip_param_arr[i].ip_param_value; 5337c478bd9Sstevel@tonic-gate } else if (!strcmp(ip_param_arr[i].ip_param_name, 5347c478bd9Sstevel@tonic-gate "ip_path_mtu_discovery")) { 5357c478bd9Sstevel@tonic-gate ip_mtudisc = &ip_param_arr[i].ip_param_value; 5367c478bd9Sstevel@tonic-gate } 5377c478bd9Sstevel@tonic-gate #if SOLARIS2 < 8 5387c478bd9Sstevel@tonic-gate else if (!strcmp(ip_param_arr[i].ip_param_name, 5397c478bd9Sstevel@tonic-gate "ip_forwarding")) { 5407c478bd9Sstevel@tonic-gate ip_forwarding = &ip_param_arr[i].ip_param_value; 5417c478bd9Sstevel@tonic-gate } 5427c478bd9Sstevel@tonic-gate #else 5437c478bd9Sstevel@tonic-gate else if (!strcmp(ip_param_arr[i].ip_param_name, 5447c478bd9Sstevel@tonic-gate "ip6_forwarding")) { 5457c478bd9Sstevel@tonic-gate ip6_forwarding = &ip_param_arr[i].ip_param_value; 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate #endif 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate if (ip_mtudisc != NULL && ip_ttl_ptr != NULL && 5507c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 5517c478bd9Sstevel@tonic-gate ip6_forwarding != NULL && 5527c478bd9Sstevel@tonic-gate #endif 5537c478bd9Sstevel@tonic-gate ip_forwarding != NULL) 5547c478bd9Sstevel@tonic-gate break; 5557c478bd9Sstevel@tonic-gate } 556ab25eeb5Syz #endif 5577c478bd9Sstevel@tonic-gate 558f4b3ec61Sdh if (ifs->ifs_fr_control_forwarding & 1) { 559ab25eeb5Syz if (ip_forwarding != NULL) 560ab25eeb5Syz *ip_forwarding = 1; 5617c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8 562ab25eeb5Syz if (ip6_forwarding != NULL) 563ab25eeb5Syz *ip6_forwarding = 1; 5647c478bd9Sstevel@tonic-gate #endif 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate #endif 5687c478bd9Sstevel@tonic-gate 569381a2a9aSdr return 0; 570381a2a9aSdr hookup_failed: 571f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 572381a2a9aSdr return -1; 573381a2a9aSdr } 574381a2a9aSdr 575b22a70abSPatrick Mooney /* ------------------------------------------------------------------------ */ 576b22a70abSPatrick Mooney /* 577b22a70abSPatrick Mooney * Called whenever a nethook protocol is registered or unregistered. Currently 578b22a70abSPatrick Mooney * only used to add or remove the hooks for viona. 579b22a70abSPatrick Mooney * 580b22a70abSPatrick Mooney * While the function signature requires returning int, nothing 581b22a70abSPatrick Mooney * in usr/src/uts/common/io/hook.c that invokes the callbacks 582b22a70abSPatrick Mooney * captures the return value (nor is there currently any documentation 583b22a70abSPatrick Mooney * on what return values should be). For now at least, we'll return 0 584b22a70abSPatrick Mooney * on success (or 'not applicable') or an error value. Even if the 585b22a70abSPatrick Mooney * nethook framework doesn't use the return address, it can be observed via 586b22a70abSPatrick Mooney * dtrace if needed. 587b22a70abSPatrick Mooney */ 588b22a70abSPatrick Mooney static int 589b22a70abSPatrick Mooney ipf_hook_protocol_notify(hook_notify_cmd_t command, void *arg, 590b22a70abSPatrick Mooney const char *name, const char *dummy __unused, const char *he_name) 591b22a70abSPatrick Mooney { 592b22a70abSPatrick Mooney ipf_stack_t *ifs = arg; 593b22a70abSPatrick Mooney hook_t **hookpp; 594b22a70abSPatrick Mooney char *hook_name, *hint_name; 595b22a70abSPatrick Mooney hook_func_t hookfn; 596b22a70abSPatrick Mooney boolean_t *hookedp; 597b22a70abSPatrick Mooney hook_hint_t hint; 598b22a70abSPatrick Mooney boolean_t out; 599b22a70abSPatrick Mooney int ret = 0; 600b22a70abSPatrick Mooney 601b22a70abSPatrick Mooney const boolean_t gz = ifs->ifs_gz_controlled; 602b22a70abSPatrick Mooney 603b22a70abSPatrick Mooney /* We currently only care about viona hooks notifications */ 604b22a70abSPatrick Mooney if (strcmp(name, Hn_VIONA) != 0) 605b22a70abSPatrick Mooney return (0); 606b22a70abSPatrick Mooney 607b22a70abSPatrick Mooney if (strcmp(he_name, NH_PHYSICAL_IN) == 0) { 608b22a70abSPatrick Mooney out = B_FALSE; 609b22a70abSPatrick Mooney } else if (strcmp(he_name, NH_PHYSICAL_OUT) == 0) { 610b22a70abSPatrick Mooney out = B_TRUE; 611b22a70abSPatrick Mooney } else { 612b22a70abSPatrick Mooney /* 613b22a70abSPatrick Mooney * If we've added more hook events to viona, we must add 614b22a70abSPatrick Mooney * the corresponding handling here (even if it's just to 615b22a70abSPatrick Mooney * ignore it) to prevent the firewall from not working as 616b22a70abSPatrick Mooney * intended. 617b22a70abSPatrick Mooney */ 618b22a70abSPatrick Mooney cmn_err(CE_PANIC, "%s: unhandled hook event %s", __func__, 619b22a70abSPatrick Mooney he_name); 620b22a70abSPatrick Mooney 621b22a70abSPatrick Mooney return (0); 622b22a70abSPatrick Mooney } 623b22a70abSPatrick Mooney 624b22a70abSPatrick Mooney if (out) { 625b22a70abSPatrick Mooney hookpp = &ifs->ifs_ipfhookviona_out; 626b22a70abSPatrick Mooney hookfn = ipf_hookviona_out; 627b22a70abSPatrick Mooney hookedp = &ifs->ifs_hookviona_physical_out; 628b22a70abSPatrick Mooney name = gz ? hook_viona_out_gz : hook_viona_out; 629b22a70abSPatrick Mooney hint = gz ? HH_AFTER : HH_BEFORE; 630b22a70abSPatrick Mooney hint_name = gz ? hook_viona_out : hook_viona_out_gz; 631b22a70abSPatrick Mooney } else { 632b22a70abSPatrick Mooney hookpp = &ifs->ifs_ipfhookviona_in; 633b22a70abSPatrick Mooney hookfn = ipf_hookviona_in; 634b22a70abSPatrick Mooney hookedp = &ifs->ifs_hookviona_physical_in; 635b22a70abSPatrick Mooney name = gz ? hook_viona_in_gz : hook_viona_in; 636b22a70abSPatrick Mooney hint = gz ? HH_BEFORE : HH_AFTER; 637b22a70abSPatrick Mooney hint_name = gz ? hook_viona_in : hook_viona_in_gz; 638b22a70abSPatrick Mooney } 639b22a70abSPatrick Mooney 640b22a70abSPatrick Mooney switch (command) { 641b22a70abSPatrick Mooney default: 642b22a70abSPatrick Mooney case HN_NONE: 643b22a70abSPatrick Mooney break; 644b22a70abSPatrick Mooney case HN_REGISTER: 645b22a70abSPatrick Mooney HOOK_INIT(*hookpp, hookfn, (char *)name, ifs); 646b22a70abSPatrick Mooney (*hookpp)->h_hint = hint; 647b22a70abSPatrick Mooney (*hookpp)->h_hintvalue = (uintptr_t)hint_name; 648b22a70abSPatrick Mooney ret = net_hook_register(ifs->ifs_ipf_viona, 649b22a70abSPatrick Mooney (char *)he_name, *hookpp); 650b22a70abSPatrick Mooney if (ret != 0) { 651b22a70abSPatrick Mooney cmn_err(CE_NOTE, "%s: could not register hook " 652b22a70abSPatrick Mooney "(hook family=%s hook=%s) err=%d", __func__, 653b22a70abSPatrick Mooney name, he_name, ret); 654b22a70abSPatrick Mooney *hookedp = B_FALSE; 655b22a70abSPatrick Mooney return (ret); 656b22a70abSPatrick Mooney } 657b22a70abSPatrick Mooney *hookedp = B_TRUE; 658b22a70abSPatrick Mooney break; 659b22a70abSPatrick Mooney case HN_UNREGISTER: 660b22a70abSPatrick Mooney if (ifs->ifs_ipf_viona == NULL) 661b22a70abSPatrick Mooney break; 662b22a70abSPatrick Mooney 663b22a70abSPatrick Mooney ret = *hookedp ? net_hook_unregister(ifs->ifs_ipf_viona, 664b22a70abSPatrick Mooney (char *)he_name, *hookpp) : 0; 665b22a70abSPatrick Mooney if ((ret == 0 || ret == ENXIO)) { 666b22a70abSPatrick Mooney if (*hookpp != NULL) { 667b22a70abSPatrick Mooney hook_free(*hookpp); 668b22a70abSPatrick Mooney *hookpp = NULL; 669b22a70abSPatrick Mooney } 670b22a70abSPatrick Mooney *hookedp = B_FALSE; 671b22a70abSPatrick Mooney } 672b22a70abSPatrick Mooney break; 673b22a70abSPatrick Mooney } 674b22a70abSPatrick Mooney 675b22a70abSPatrick Mooney return (ret); 676b22a70abSPatrick Mooney } 677b22a70abSPatrick Mooney 678b22a70abSPatrick Mooney /* 679b22a70abSPatrick Mooney * Called whenever a new nethook instance is created. Currently only used 680b22a70abSPatrick Mooney * with the Hn_VIONA nethooks. Similar to ipf_hook_protocol_notify, the out 681b22a70abSPatrick Mooney * function signature must return an int, though the result is never used. 682b22a70abSPatrick Mooney * We elect to return 0 on success (or not applicable) or a non-zero value 683b22a70abSPatrick Mooney * on error. 684b22a70abSPatrick Mooney */ 685b22a70abSPatrick Mooney static int 686b22a70abSPatrick Mooney ipf_hook_instance_notify(hook_notify_cmd_t command, void *arg, 687b22a70abSPatrick Mooney const char *netid, const char *dummy __unused, const char *instance) 688b22a70abSPatrick Mooney { 689b22a70abSPatrick Mooney ipf_stack_t *ifs = arg; 690b22a70abSPatrick Mooney int ret = 0; 691b22a70abSPatrick Mooney 692b22a70abSPatrick Mooney /* We currently only care about viona hooks */ 693b22a70abSPatrick Mooney if (strcmp(instance, Hn_VIONA) != 0) 694b22a70abSPatrick Mooney return (0); 695b22a70abSPatrick Mooney 696b22a70abSPatrick Mooney switch (command) { 697b22a70abSPatrick Mooney case HN_NONE: 698b22a70abSPatrick Mooney default: 699b22a70abSPatrick Mooney return (0); 700b22a70abSPatrick Mooney case HN_REGISTER: 701b22a70abSPatrick Mooney ifs->ifs_ipf_viona = net_protocol_lookup(ifs->ifs_netid, 702b22a70abSPatrick Mooney NHF_VIONA); 703b22a70abSPatrick Mooney 704b22a70abSPatrick Mooney if (ifs->ifs_ipf_viona == NULL) 705b22a70abSPatrick Mooney return (EPROTONOSUPPORT); 706b22a70abSPatrick Mooney 707b22a70abSPatrick Mooney ret = net_protocol_notify_register(ifs->ifs_ipf_viona, 708b22a70abSPatrick Mooney ipf_hook_protocol_notify, ifs); 709b22a70abSPatrick Mooney VERIFY(ret == 0 || ret == ESHUTDOWN); 710b22a70abSPatrick Mooney break; 711b22a70abSPatrick Mooney case HN_UNREGISTER: 712b22a70abSPatrick Mooney if (ifs->ifs_ipf_viona == NULL) 713b22a70abSPatrick Mooney break; 714b22a70abSPatrick Mooney VERIFY0(net_protocol_notify_unregister(ifs->ifs_ipf_viona, 715b22a70abSPatrick Mooney ipf_hook_protocol_notify)); 716b22a70abSPatrick Mooney VERIFY0(net_protocol_release(ifs->ifs_ipf_viona)); 717b22a70abSPatrick Mooney ifs->ifs_ipf_viona = NULL; 718b22a70abSPatrick Mooney break; 719b22a70abSPatrick Mooney } 720b22a70abSPatrick Mooney 721b22a70abSPatrick Mooney return (ret); 722b22a70abSPatrick Mooney } 723b22a70abSPatrick Mooney 724f4b3ec61Sdh static int fr_setipfloopback(set, ifs) 725381a2a9aSdr int set; 726f4b3ec61Sdh ipf_stack_t *ifs; 727381a2a9aSdr { 728f4b3ec61Sdh if (ifs->ifs_ipf_ipv4 == NULL || ifs->ifs_ipf_ipv6 == NULL) 729381a2a9aSdr return EFAULT; 730381a2a9aSdr 731f4b3ec61Sdh if (set && !ifs->ifs_ipf_loopback) { 732f4b3ec61Sdh ifs->ifs_ipf_loopback = 1; 733381a2a9aSdr 7347ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_in = (net_hook_register( 7357ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN, 7367ddc9b1aSDarren Reed ifs->ifs_ipfhook4_loop_in) == 0); 737f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_in) 738381a2a9aSdr return EINVAL; 739381a2a9aSdr 7407ddc9b1aSDarren Reed ifs->ifs_hook4_loopback_out = (net_hook_register( 7417ddc9b1aSDarren Reed ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT, 7427ddc9b1aSDarren Reed ifs->ifs_ipfhook4_loop_out) == 0); 743f4b3ec61Sdh if (!ifs->ifs_hook4_loopback_out) 744381a2a9aSdr return EINVAL; 745381a2a9aSdr 7467ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_in = (net_hook_register( 7477ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN, 7487ddc9b1aSDarren Reed ifs->ifs_ipfhook6_loop_in) == 0); 749f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_in) 750381a2a9aSdr return EINVAL; 751381a2a9aSdr 7527ddc9b1aSDarren Reed ifs->ifs_hook6_loopback_out = (net_hook_register( 7537ddc9b1aSDarren Reed ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT, 7547ddc9b1aSDarren Reed ifs->ifs_ipfhook6_loop_out) == 0); 755f4b3ec61Sdh if (!ifs->ifs_hook6_loopback_out) 756381a2a9aSdr return EINVAL; 757381a2a9aSdr 758f4b3ec61Sdh } else if (!set && ifs->ifs_ipf_loopback) { 759f4b3ec61Sdh ifs->ifs_ipf_loopback = 0; 760381a2a9aSdr 761f4b3ec61Sdh ifs->ifs_hook4_loopback_in = 7627ddc9b1aSDarren Reed (net_hook_unregister(ifs->ifs_ipf_ipv4, 7637ddc9b1aSDarren Reed NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0); 764f4b3ec61Sdh if (ifs->ifs_hook4_loopback_in) 765381a2a9aSdr return EBUSY; 766381a2a9aSdr 767f4b3ec61Sdh ifs->ifs_hook4_loopback_out = 7687ddc9b1aSDarren Reed (net_hook_unregister(ifs->ifs_ipf_ipv4, 7697ddc9b1aSDarren Reed NH_LOOPBACK_OUT, ifs->ifs_ipfhook4_loop_out) != 0); 770f4b3ec61Sdh if (ifs->ifs_hook4_loopback_out) 771381a2a9aSdr return EBUSY; 772381a2a9aSdr 773f4b3ec61Sdh ifs->ifs_hook6_loopback_in = 7747ddc9b1aSDarren Reed (net_hook_unregister(ifs->ifs_ipf_ipv6, 7757ddc9b1aSDarren Reed NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0); 776f4b3ec61Sdh if (ifs->ifs_hook6_loopback_in) 777381a2a9aSdr return EBUSY; 778381a2a9aSdr 779f4b3ec61Sdh ifs->ifs_hook6_loopback_out = 7807ddc9b1aSDarren Reed (net_hook_unregister(ifs->ifs_ipf_ipv6, 7817ddc9b1aSDarren Reed NH_LOOPBACK_OUT, ifs->ifs_ipfhook6_loop_out) != 0); 782f4b3ec61Sdh if (ifs->ifs_hook6_loopback_out) 783381a2a9aSdr return EBUSY; 784381a2a9aSdr } 7857c478bd9Sstevel@tonic-gate return 0; 7867c478bd9Sstevel@tonic-gate } 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate /* 7907c478bd9Sstevel@tonic-gate * Filter ioctl interface. 7917c478bd9Sstevel@tonic-gate */ 7927c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7937c478bd9Sstevel@tonic-gate int iplioctl(dev, cmd, data, mode, cp, rp) 7947c478bd9Sstevel@tonic-gate dev_t dev; 7957c478bd9Sstevel@tonic-gate int cmd; 7967c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 7 7977c478bd9Sstevel@tonic-gate intptr_t data; 7987c478bd9Sstevel@tonic-gate #else 7997c478bd9Sstevel@tonic-gate int *data; 8007c478bd9Sstevel@tonic-gate #endif 8017c478bd9Sstevel@tonic-gate int mode; 8027c478bd9Sstevel@tonic-gate cred_t *cp; 8037c478bd9Sstevel@tonic-gate int *rp; 8047c478bd9Sstevel@tonic-gate { 8057c478bd9Sstevel@tonic-gate int error = 0, tmp; 8067c478bd9Sstevel@tonic-gate friostat_t fio; 8077c478bd9Sstevel@tonic-gate minor_t unit; 8087c478bd9Sstevel@tonic-gate u_int enable; 809f4b3ec61Sdh ipf_stack_t *ifs; 81094bdecd9SRob Gulewich zoneid_t zid; 81194bdecd9SRob Gulewich ipf_devstate_t *isp; 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 8147c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplioctl(%x,%x,%x,%d,%x,%d)\n", 8157c478bd9Sstevel@tonic-gate dev, cmd, data, mode, cp, rp); 8167c478bd9Sstevel@tonic-gate #endif 8177c478bd9Sstevel@tonic-gate unit = getminor(dev); 81894bdecd9SRob Gulewich 81994bdecd9SRob Gulewich isp = ddi_get_soft_state(ipf_state, unit); 82094bdecd9SRob Gulewich if (isp == NULL) 8217c478bd9Sstevel@tonic-gate return ENXIO; 82294bdecd9SRob Gulewich unit = isp->ipfs_minor; 82394bdecd9SRob Gulewich 82494bdecd9SRob Gulewich zid = crgetzoneid(cp); 82594bdecd9SRob Gulewich if (cmd == SIOCIPFZONESET) { 82694bdecd9SRob Gulewich if (zid == GLOBAL_ZONEID) 82794bdecd9SRob Gulewich return fr_setzoneid(isp, (caddr_t) data); 82894bdecd9SRob Gulewich return EACCES; 82994bdecd9SRob Gulewich } 8307c478bd9Sstevel@tonic-gate 8317ddc9b1aSDarren Reed /* 83294bdecd9SRob Gulewich * ipf_find_stack returns with a read lock on ifs_ipf_global 8337ddc9b1aSDarren Reed */ 83494bdecd9SRob Gulewich ifs = ipf_find_stack(zid, isp); 83594bdecd9SRob Gulewich if (ifs == NULL) 83694bdecd9SRob Gulewich return ENXIO; 837f4b3ec61Sdh 838f4b3ec61Sdh if (ifs->ifs_fr_running <= 0) { 839f4b3ec61Sdh if (unit != IPL_LOGIPF) { 84094bdecd9SRob Gulewich RWLOCK_EXIT(&ifs->ifs_ipf_global); 8417c478bd9Sstevel@tonic-gate return EIO; 842f4b3ec61Sdh } 8437c478bd9Sstevel@tonic-gate if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 844ab25eeb5Syz cmd != SIOCIPFSET && cmd != SIOCFRENB && 845f4b3ec61Sdh cmd != SIOCGETFS && cmd != SIOCGETFF) { 84694bdecd9SRob Gulewich RWLOCK_EXIT(&ifs->ifs_ipf_global); 8477c478bd9Sstevel@tonic-gate return EIO; 848f4b3ec61Sdh } 8497c478bd9Sstevel@tonic-gate } 8507c478bd9Sstevel@tonic-gate 85172680cf5SDarren Reed if (ifs->ifs_fr_enable_active != 0) { 85272680cf5SDarren Reed RWLOCK_EXIT(&ifs->ifs_ipf_global); 85372680cf5SDarren Reed return EBUSY; 85472680cf5SDarren Reed } 8557c478bd9Sstevel@tonic-gate 85667dbe2beSCasper H.S. Dik error = fr_ioctlswitch(unit, (caddr_t)data, cmd, mode, crgetuid(cp), 8577ddc9b1aSDarren Reed curproc, ifs); 8587c478bd9Sstevel@tonic-gate if (error != -1) { 859f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 8607c478bd9Sstevel@tonic-gate return error; 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate error = 0; 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate switch (cmd) 8657c478bd9Sstevel@tonic-gate { 8667c478bd9Sstevel@tonic-gate case SIOCFRENB : 8677c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 8687c478bd9Sstevel@tonic-gate error = EPERM; 8697c478bd9Sstevel@tonic-gate else { 8707c478bd9Sstevel@tonic-gate error = COPYIN((caddr_t)data, (caddr_t)&enable, 8717c478bd9Sstevel@tonic-gate sizeof(enable)); 8727c478bd9Sstevel@tonic-gate if (error != 0) { 8737c478bd9Sstevel@tonic-gate error = EFAULT; 8747c478bd9Sstevel@tonic-gate break; 8757c478bd9Sstevel@tonic-gate } 8767c478bd9Sstevel@tonic-gate 877f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 878f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 879e8d569f4SAlexandr Nedvedicky 880e8d569f4SAlexandr Nedvedicky /* 881e8d569f4SAlexandr Nedvedicky * We must recheck fr_enable_active here, since we've 882e8d569f4SAlexandr Nedvedicky * dropped ifs_ipf_global from R in order to get it 883e8d569f4SAlexandr Nedvedicky * exclusively. 884e8d569f4SAlexandr Nedvedicky */ 885e8d569f4SAlexandr Nedvedicky if (ifs->ifs_fr_enable_active == 0) { 886e8d569f4SAlexandr Nedvedicky ifs->ifs_fr_enable_active = 1; 887e8d569f4SAlexandr Nedvedicky error = fr_enableipf(ifs, enable); 888e8d569f4SAlexandr Nedvedicky ifs->ifs_fr_enable_active = 0; 889e8d569f4SAlexandr Nedvedicky } 8907c478bd9Sstevel@tonic-gate } 8917c478bd9Sstevel@tonic-gate break; 8927c478bd9Sstevel@tonic-gate case SIOCIPFSET : 8937c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) { 8947c478bd9Sstevel@tonic-gate error = EPERM; 8957c478bd9Sstevel@tonic-gate break; 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate /* FALLTHRU */ 8987c478bd9Sstevel@tonic-gate case SIOCIPFGETNEXT : 8997c478bd9Sstevel@tonic-gate case SIOCIPFGET : 900f4b3ec61Sdh error = fr_ipftune(cmd, (void *)data, ifs); 9017c478bd9Sstevel@tonic-gate break; 9027c478bd9Sstevel@tonic-gate case SIOCSETFF : 9037c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 9047c478bd9Sstevel@tonic-gate error = EPERM; 9057c478bd9Sstevel@tonic-gate else { 9067ddc9b1aSDarren Reed error = COPYIN((caddr_t)data, 9077ddc9b1aSDarren Reed (caddr_t)&ifs->ifs_fr_flags, 9087ddc9b1aSDarren Reed sizeof(ifs->ifs_fr_flags)); 9097c478bd9Sstevel@tonic-gate if (error != 0) 9107c478bd9Sstevel@tonic-gate error = EFAULT; 9117c478bd9Sstevel@tonic-gate } 9127c478bd9Sstevel@tonic-gate break; 913381a2a9aSdr case SIOCIPFLP : 914381a2a9aSdr error = COPYIN((caddr_t)data, (caddr_t)&tmp, 915381a2a9aSdr sizeof(tmp)); 916381a2a9aSdr if (error != 0) 917381a2a9aSdr error = EFAULT; 918381a2a9aSdr else 919f4b3ec61Sdh error = fr_setipfloopback(tmp, ifs); 920381a2a9aSdr break; 9217c478bd9Sstevel@tonic-gate case SIOCGETFF : 922f4b3ec61Sdh error = COPYOUT((caddr_t)&ifs->ifs_fr_flags, (caddr_t)data, 9237ddc9b1aSDarren Reed sizeof(ifs->ifs_fr_flags)); 9247c478bd9Sstevel@tonic-gate if (error != 0) 9257c478bd9Sstevel@tonic-gate error = EFAULT; 9267c478bd9Sstevel@tonic-gate break; 9277c478bd9Sstevel@tonic-gate case SIOCFUNCL : 9287c478bd9Sstevel@tonic-gate error = fr_resolvefunc((void *)data); 9297c478bd9Sstevel@tonic-gate break; 9307c478bd9Sstevel@tonic-gate case SIOCINAFR : 9317c478bd9Sstevel@tonic-gate case SIOCRMAFR : 9327c478bd9Sstevel@tonic-gate case SIOCADAFR : 9337c478bd9Sstevel@tonic-gate case SIOCZRLST : 9347c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 9357c478bd9Sstevel@tonic-gate error = EPERM; 9367c478bd9Sstevel@tonic-gate else 9377c478bd9Sstevel@tonic-gate error = frrequest(unit, cmd, (caddr_t)data, 938f4b3ec61Sdh ifs->ifs_fr_active, 1, ifs); 9397c478bd9Sstevel@tonic-gate break; 9407c478bd9Sstevel@tonic-gate case SIOCINIFR : 9417c478bd9Sstevel@tonic-gate case SIOCRMIFR : 9427c478bd9Sstevel@tonic-gate case SIOCADIFR : 9437c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 9447c478bd9Sstevel@tonic-gate error = EPERM; 9457c478bd9Sstevel@tonic-gate else 9467c478bd9Sstevel@tonic-gate error = frrequest(unit, cmd, (caddr_t)data, 947f4b3ec61Sdh 1 - ifs->ifs_fr_active, 1, ifs); 9487c478bd9Sstevel@tonic-gate break; 9497c478bd9Sstevel@tonic-gate case SIOCSWAPA : 9507c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 9517c478bd9Sstevel@tonic-gate error = EPERM; 9527c478bd9Sstevel@tonic-gate else { 953f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_mutex); 95414d3298eSAlexandr Nedvedicky bzero((char *)ifs->ifs_frcache, 95514d3298eSAlexandr Nedvedicky sizeof (ifs->ifs_frcache)); 956f4b3ec61Sdh error = COPYOUT((caddr_t)&ifs->ifs_fr_active, 957f4b3ec61Sdh (caddr_t)data, 958f4b3ec61Sdh sizeof(ifs->ifs_fr_active)); 9597c478bd9Sstevel@tonic-gate if (error != 0) 9607c478bd9Sstevel@tonic-gate error = EFAULT; 9617c478bd9Sstevel@tonic-gate else 962f4b3ec61Sdh ifs->ifs_fr_active = 1 - ifs->ifs_fr_active; 963f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 9647c478bd9Sstevel@tonic-gate } 9657c478bd9Sstevel@tonic-gate break; 9667c478bd9Sstevel@tonic-gate case SIOCGETFS : 967f4b3ec61Sdh fr_getstat(&fio, ifs); 9687c478bd9Sstevel@tonic-gate error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT); 9697c478bd9Sstevel@tonic-gate break; 9707c478bd9Sstevel@tonic-gate case SIOCFRZST : 9717c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 9727c478bd9Sstevel@tonic-gate error = EPERM; 9737c478bd9Sstevel@tonic-gate else 974f4b3ec61Sdh error = fr_zerostats((caddr_t)data, ifs); 9757c478bd9Sstevel@tonic-gate break; 9767c478bd9Sstevel@tonic-gate case SIOCIPFFL : 9777c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 9787c478bd9Sstevel@tonic-gate error = EPERM; 9797c478bd9Sstevel@tonic-gate else { 9807c478bd9Sstevel@tonic-gate error = COPYIN((caddr_t)data, (caddr_t)&tmp, 9817c478bd9Sstevel@tonic-gate sizeof(tmp)); 9827c478bd9Sstevel@tonic-gate if (!error) { 983f4b3ec61Sdh tmp = frflush(unit, 4, tmp, ifs); 9847c478bd9Sstevel@tonic-gate error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 9857ddc9b1aSDarren Reed sizeof(tmp)); 9867c478bd9Sstevel@tonic-gate if (error != 0) 9877c478bd9Sstevel@tonic-gate error = EFAULT; 9887c478bd9Sstevel@tonic-gate } else 9897c478bd9Sstevel@tonic-gate error = EFAULT; 9907c478bd9Sstevel@tonic-gate } 9917c478bd9Sstevel@tonic-gate break; 9927663b816Sml #ifdef USE_INET6 9937663b816Sml case SIOCIPFL6 : 9947663b816Sml if (!(mode & FWRITE)) 9957663b816Sml error = EPERM; 9967663b816Sml else { 9977663b816Sml error = COPYIN((caddr_t)data, (caddr_t)&tmp, 9987663b816Sml sizeof(tmp)); 9997663b816Sml if (!error) { 1000f4b3ec61Sdh tmp = frflush(unit, 6, tmp, ifs); 10017663b816Sml error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 10027ddc9b1aSDarren Reed sizeof(tmp)); 10037663b816Sml if (error != 0) 10047663b816Sml error = EFAULT; 10057663b816Sml } else 10067663b816Sml error = EFAULT; 10077663b816Sml } 10087663b816Sml break; 10097663b816Sml #endif 10107c478bd9Sstevel@tonic-gate case SIOCSTLCK : 10117c478bd9Sstevel@tonic-gate error = COPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 10127c478bd9Sstevel@tonic-gate if (error == 0) { 1013f4b3ec61Sdh ifs->ifs_fr_state_lock = tmp; 1014f4b3ec61Sdh ifs->ifs_fr_nat_lock = tmp; 1015f4b3ec61Sdh ifs->ifs_fr_frag_lock = tmp; 1016f4b3ec61Sdh ifs->ifs_fr_auth_lock = tmp; 10177c478bd9Sstevel@tonic-gate } else 10187c478bd9Sstevel@tonic-gate error = EFAULT; 10197c478bd9Sstevel@tonic-gate break; 10207c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 10217c478bd9Sstevel@tonic-gate case SIOCIPFFB : 10227c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 10237c478bd9Sstevel@tonic-gate error = EPERM; 10247c478bd9Sstevel@tonic-gate else { 1025f4b3ec61Sdh tmp = ipflog_clear(unit, ifs); 10267c478bd9Sstevel@tonic-gate error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 10277c478bd9Sstevel@tonic-gate sizeof(tmp)); 10287c478bd9Sstevel@tonic-gate if (error) 10297c478bd9Sstevel@tonic-gate error = EFAULT; 10307c478bd9Sstevel@tonic-gate } 10317c478bd9Sstevel@tonic-gate break; 10327c478bd9Sstevel@tonic-gate #endif /* IPFILTER_LOG */ 10337c478bd9Sstevel@tonic-gate case SIOCFRSYN : 10347c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) 10357c478bd9Sstevel@tonic-gate error = EPERM; 10367c478bd9Sstevel@tonic-gate else { 1037f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 1038f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 1039381a2a9aSdr 1040f4b3ec61Sdh frsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 1041d6c23f6fSyx fr_natifpsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 1042d6c23f6fSyx fr_nataddrsync(0, NULL, NULL, ifs); 1043f4b3ec61Sdh fr_statesync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 1044381a2a9aSdr error = 0; 10457c478bd9Sstevel@tonic-gate } 10467c478bd9Sstevel@tonic-gate break; 10477c478bd9Sstevel@tonic-gate case SIOCGFRST : 1048f4b3ec61Sdh error = fr_outobj((void *)data, fr_fragstats(ifs), 10497c478bd9Sstevel@tonic-gate IPFOBJ_FRAGSTAT); 10507c478bd9Sstevel@tonic-gate break; 10517c478bd9Sstevel@tonic-gate case FIONREAD : 10527c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 1053f4b3ec61Sdh tmp = (int)ifs->ifs_iplused[IPL_LOGIPF]; 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate error = COPYOUT((caddr_t)&tmp, (caddr_t)data, sizeof(tmp)); 10567c478bd9Sstevel@tonic-gate if (error != 0) 10577c478bd9Sstevel@tonic-gate error = EFAULT; 10587c478bd9Sstevel@tonic-gate #endif 10597c478bd9Sstevel@tonic-gate break; 1060f4b3ec61Sdh case SIOCIPFITER : 106167dbe2beSCasper H.S. Dik error = ipf_frruleiter((caddr_t)data, crgetuid(cp), 10627ddc9b1aSDarren Reed curproc, ifs); 1063f4b3ec61Sdh break; 1064f4b3ec61Sdh 1065f4b3ec61Sdh case SIOCGENITER : 106667dbe2beSCasper H.S. Dik error = ipf_genericiter((caddr_t)data, crgetuid(cp), 10677ddc9b1aSDarren Reed curproc, ifs); 1068f4b3ec61Sdh break; 1069f4b3ec61Sdh 1070f4b3ec61Sdh case SIOCIPFDELTOK : 1071bb1d9de5SJohn Ojemann error = BCOPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 1072bb1d9de5SJohn Ojemann if (error != 0) { 1073bb1d9de5SJohn Ojemann error = EFAULT; 1074bb1d9de5SJohn Ojemann } else { 107567dbe2beSCasper H.S. Dik error = ipf_deltoken(tmp, crgetuid(cp), curproc, ifs); 1076bb1d9de5SJohn Ojemann } 1077f4b3ec61Sdh break; 1078f4b3ec61Sdh 10797c478bd9Sstevel@tonic-gate default : 108033f2fefdSDarren Reed #ifdef IPFDEBUG 10817ddc9b1aSDarren Reed cmn_err(CE_NOTE, "Unknown: cmd 0x%x data %p", 10827ddc9b1aSDarren Reed cmd, (void *)data); 108333f2fefdSDarren Reed #endif 10847c478bd9Sstevel@tonic-gate error = EINVAL; 10857c478bd9Sstevel@tonic-gate break; 10867c478bd9Sstevel@tonic-gate } 1087f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 10887c478bd9Sstevel@tonic-gate return error; 10897c478bd9Sstevel@tonic-gate } 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate 10927ddc9b1aSDarren Reed static int fr_enableipf(ifs, enable) 1093882bd30bSdr ipf_stack_t *ifs; 1094882bd30bSdr int enable; 1095882bd30bSdr { 1096882bd30bSdr int error; 1097882bd30bSdr 109844aaa2b6Sjojemann if (!enable) { 1099882bd30bSdr error = ipldetach(ifs); 1100882bd30bSdr if (error == 0) 1101882bd30bSdr ifs->ifs_fr_running = -1; 11027ddc9b1aSDarren Reed return error; 1103882bd30bSdr } 1104882bd30bSdr 110544aaa2b6Sjojemann if (ifs->ifs_fr_running > 0) 11067ddc9b1aSDarren Reed return 0; 110744aaa2b6Sjojemann 11087ddc9b1aSDarren Reed error = iplattach(ifs); 110944aaa2b6Sjojemann if (error == 0) { 111044aaa2b6Sjojemann if (ifs->ifs_fr_timer_id == NULL) { 111144aaa2b6Sjojemann int hz = drv_usectohz(500000); 111244aaa2b6Sjojemann 111344aaa2b6Sjojemann ifs->ifs_fr_timer_id = timeout(fr_slowtimer, 11147ddc9b1aSDarren Reed (void *)ifs, 11157ddc9b1aSDarren Reed hz); 111644aaa2b6Sjojemann } 111744aaa2b6Sjojemann ifs->ifs_fr_running = 1; 111844aaa2b6Sjojemann } else { 111944aaa2b6Sjojemann (void) ipldetach(ifs); 112044aaa2b6Sjojemann } 11217ddc9b1aSDarren Reed return error; 1122882bd30bSdr } 1123882bd30bSdr 1124882bd30bSdr 1125f4b3ec61Sdh phy_if_t get_unit(name, v, ifs) 1126f4b3ec61Sdh char *name; 1127f4b3ec61Sdh int v; 1128f4b3ec61Sdh ipf_stack_t *ifs; 11297c478bd9Sstevel@tonic-gate { 11307ddc9b1aSDarren Reed net_handle_t nif; 1131381a2a9aSdr 1132381a2a9aSdr if (v == 4) 1133f4b3ec61Sdh nif = ifs->ifs_ipf_ipv4; 1134381a2a9aSdr else if (v == 6) 1135f4b3ec61Sdh nif = ifs->ifs_ipf_ipv6; 1136381a2a9aSdr else 1137381a2a9aSdr return 0; 1138381a2a9aSdr 1139f4b3ec61Sdh return (net_phylookup(nif, name)); 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate /* 11437c478bd9Sstevel@tonic-gate * routines below for saving IP headers to buffer 11447c478bd9Sstevel@tonic-gate */ 11457c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11467c478bd9Sstevel@tonic-gate int iplopen(devp, flags, otype, cred) 11477c478bd9Sstevel@tonic-gate dev_t *devp; 11487c478bd9Sstevel@tonic-gate int flags, otype; 11497c478bd9Sstevel@tonic-gate cred_t *cred; 11507c478bd9Sstevel@tonic-gate { 115194bdecd9SRob Gulewich ipf_devstate_t *isp; 11527c478bd9Sstevel@tonic-gate minor_t min = getminor(*devp); 115394bdecd9SRob Gulewich minor_t minor; 11547c478bd9Sstevel@tonic-gate 11557c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 11567c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplopen(%x,%x,%x,%x)\n", devp, flags, otype, cred); 11577c478bd9Sstevel@tonic-gate #endif 11587c478bd9Sstevel@tonic-gate if (!(otype & OTYP_CHR)) 11597c478bd9Sstevel@tonic-gate return ENXIO; 11607c478bd9Sstevel@tonic-gate 116194bdecd9SRob Gulewich if (IPL_LOGMAX < min) 116294bdecd9SRob Gulewich return ENXIO; 116394bdecd9SRob Gulewich 116494bdecd9SRob Gulewich minor = (minor_t)(uintptr_t)vmem_alloc(ipf_minor, 1, 116594bdecd9SRob Gulewich VM_BESTFIT | VM_SLEEP); 116694bdecd9SRob Gulewich 116794bdecd9SRob Gulewich if (ddi_soft_state_zalloc(ipf_state, minor) != 0) { 116894bdecd9SRob Gulewich vmem_free(ipf_minor, (void *)(uintptr_t)minor, 1); 116994bdecd9SRob Gulewich return ENXIO; 117094bdecd9SRob Gulewich } 117194bdecd9SRob Gulewich 117294bdecd9SRob Gulewich *devp = makedevice(getmajor(*devp), minor); 117394bdecd9SRob Gulewich isp = ddi_get_soft_state(ipf_state, minor); 117494bdecd9SRob Gulewich VERIFY(isp != NULL); 117594bdecd9SRob Gulewich 117694bdecd9SRob Gulewich isp->ipfs_minor = min; 117794bdecd9SRob Gulewich isp->ipfs_zoneid = IPFS_ZONE_UNSET; 117894bdecd9SRob Gulewich 117994bdecd9SRob Gulewich return 0; 11807c478bd9Sstevel@tonic-gate } 11817c478bd9Sstevel@tonic-gate 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11847c478bd9Sstevel@tonic-gate int iplclose(dev, flags, otype, cred) 11857c478bd9Sstevel@tonic-gate dev_t dev; 11867c478bd9Sstevel@tonic-gate int flags, otype; 11877c478bd9Sstevel@tonic-gate cred_t *cred; 11887c478bd9Sstevel@tonic-gate { 11897c478bd9Sstevel@tonic-gate minor_t min = getminor(dev); 11907c478bd9Sstevel@tonic-gate 11917c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 11927c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplclose(%x,%x,%x,%x)\n", dev, flags, otype, cred); 11937c478bd9Sstevel@tonic-gate #endif 11947c478bd9Sstevel@tonic-gate 119594bdecd9SRob Gulewich if (IPL_LOGMAX < min) 119694bdecd9SRob Gulewich return ENXIO; 119794bdecd9SRob Gulewich 119894bdecd9SRob Gulewich ddi_soft_state_free(ipf_state, min); 119994bdecd9SRob Gulewich vmem_free(ipf_minor, (void *)(uintptr_t)min, 1); 120094bdecd9SRob Gulewich 120194bdecd9SRob Gulewich return 0; 12027c478bd9Sstevel@tonic-gate } 12037c478bd9Sstevel@tonic-gate 12047c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 12057c478bd9Sstevel@tonic-gate /* 12067c478bd9Sstevel@tonic-gate * iplread/ipllog 12077c478bd9Sstevel@tonic-gate * both of these must operate with at least splnet() lest they be 12087c478bd9Sstevel@tonic-gate * called during packet processing and cause an inconsistancy to appear in 12097c478bd9Sstevel@tonic-gate * the filter lists. 12107c478bd9Sstevel@tonic-gate */ 12117c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12127c478bd9Sstevel@tonic-gate int iplread(dev, uio, cp) 12137c478bd9Sstevel@tonic-gate dev_t dev; 12147c478bd9Sstevel@tonic-gate register struct uio *uio; 12157c478bd9Sstevel@tonic-gate cred_t *cp; 12167c478bd9Sstevel@tonic-gate { 1217f4b3ec61Sdh ipf_stack_t *ifs; 1218f4b3ec61Sdh int ret; 121994bdecd9SRob Gulewich minor_t unit; 122094bdecd9SRob Gulewich ipf_devstate_t *isp; 122194bdecd9SRob Gulewich 122294bdecd9SRob Gulewich unit = getminor(dev); 122394bdecd9SRob Gulewich isp = ddi_get_soft_state(ipf_state, unit); 122494bdecd9SRob Gulewich if (isp == NULL) 122594bdecd9SRob Gulewich return ENXIO; 122694bdecd9SRob Gulewich unit = isp->ipfs_minor; 122794bdecd9SRob Gulewich 1228f4b3ec61Sdh 12297ddc9b1aSDarren Reed /* 123094bdecd9SRob Gulewich * ipf_find_stack returns with a read lock on ifs_ipf_global 12317ddc9b1aSDarren Reed */ 123294bdecd9SRob Gulewich ifs = ipf_find_stack(crgetzoneid(cp), isp); 123394bdecd9SRob Gulewich if (ifs == NULL) 123494bdecd9SRob Gulewich return ENXIO; 1235f4b3ec61Sdh 12367c478bd9Sstevel@tonic-gate # ifdef IPFDEBUG 12377c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplread(%x,%x,%x)\n", dev, uio, cp); 12387c478bd9Sstevel@tonic-gate # endif 123908ee25aeSdr 1240f4b3ec61Sdh if (ifs->ifs_fr_running < 1) { 124194bdecd9SRob Gulewich RWLOCK_EXIT(&ifs->ifs_ipf_global); 124208ee25aeSdr return EIO; 1243f4b3ec61Sdh } 124408ee25aeSdr 12457c478bd9Sstevel@tonic-gate # ifdef IPFILTER_SYNC 124694bdecd9SRob Gulewich if (unit == IPL_LOGSYNC) { 124794bdecd9SRob Gulewich RWLOCK_EXIT(&ifs->ifs_ipf_global); 12487c478bd9Sstevel@tonic-gate return ipfsync_read(uio); 1249f4b3ec61Sdh } 12507c478bd9Sstevel@tonic-gate # endif 12517c478bd9Sstevel@tonic-gate 125294bdecd9SRob Gulewich ret = ipflog_read(unit, uio, ifs); 125394bdecd9SRob Gulewich RWLOCK_EXIT(&ifs->ifs_ipf_global); 1254f4b3ec61Sdh return ret; 12557c478bd9Sstevel@tonic-gate } 12567c478bd9Sstevel@tonic-gate #endif /* IPFILTER_LOG */ 12577c478bd9Sstevel@tonic-gate 12587c478bd9Sstevel@tonic-gate 12597c478bd9Sstevel@tonic-gate /* 12607c478bd9Sstevel@tonic-gate * iplread/ipllog 12617c478bd9Sstevel@tonic-gate * both of these must operate with at least splnet() lest they be 12627c478bd9Sstevel@tonic-gate * called during packet processing and cause an inconsistancy to appear in 12637c478bd9Sstevel@tonic-gate * the filter lists. 12647c478bd9Sstevel@tonic-gate */ 12657c478bd9Sstevel@tonic-gate int iplwrite(dev, uio, cp) 12667c478bd9Sstevel@tonic-gate dev_t dev; 12677c478bd9Sstevel@tonic-gate register struct uio *uio; 12687c478bd9Sstevel@tonic-gate cred_t *cp; 12697c478bd9Sstevel@tonic-gate { 1270f4b3ec61Sdh ipf_stack_t *ifs; 127194bdecd9SRob Gulewich minor_t unit; 127294bdecd9SRob Gulewich ipf_devstate_t *isp; 127394bdecd9SRob Gulewich 127494bdecd9SRob Gulewich unit = getminor(dev); 127594bdecd9SRob Gulewich isp = ddi_get_soft_state(ipf_state, unit); 127694bdecd9SRob Gulewich if (isp == NULL) 127794bdecd9SRob Gulewich return ENXIO; 127894bdecd9SRob Gulewich unit = isp->ipfs_minor; 1279f4b3ec61Sdh 12807ddc9b1aSDarren Reed /* 128194bdecd9SRob Gulewich * ipf_find_stack returns with a read lock on ifs_ipf_global 12827ddc9b1aSDarren Reed */ 128394bdecd9SRob Gulewich ifs = ipf_find_stack(crgetzoneid(cp), isp); 128494bdecd9SRob Gulewich if (ifs == NULL) 128594bdecd9SRob Gulewich return ENXIO; 1286f4b3ec61Sdh 12877c478bd9Sstevel@tonic-gate #ifdef IPFDEBUG 12887c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iplwrite(%x,%x,%x)\n", dev, uio, cp); 12897c478bd9Sstevel@tonic-gate #endif 129008ee25aeSdr 1291f4b3ec61Sdh if (ifs->ifs_fr_running < 1) { 129294bdecd9SRob Gulewich RWLOCK_EXIT(&ifs->ifs_ipf_global); 129308ee25aeSdr return EIO; 1294f4b3ec61Sdh } 129508ee25aeSdr 1296ab25eeb5Syz #ifdef IPFILTER_SYNC 129794bdecd9SRob Gulewich if (getminor(dev) == IPL_LOGSYNC) { 129894bdecd9SRob Gulewich RWLOCK_EXIT(&ifs->ifs_ipf_global); 1299ab25eeb5Syz return ipfsync_write(uio); 130094bdecd9SRob Gulewich } 13017c478bd9Sstevel@tonic-gate #endif /* IPFILTER_SYNC */ 1302ab25eeb5Syz dev = dev; /* LINT */ 1303ab25eeb5Syz uio = uio; /* LINT */ 1304ab25eeb5Syz cp = cp; /* LINT */ 130594bdecd9SRob Gulewich RWLOCK_EXIT(&ifs->ifs_ipf_global); 1306ab25eeb5Syz return ENXIO; 1307ab25eeb5Syz } 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate 13107c478bd9Sstevel@tonic-gate /* 13117c478bd9Sstevel@tonic-gate * fr_send_reset - this could conceivably be a call to tcp_respond(), but that 13127c478bd9Sstevel@tonic-gate * requires a large amount of setting up and isn't any more efficient. 13137c478bd9Sstevel@tonic-gate */ 13147c478bd9Sstevel@tonic-gate int fr_send_reset(fin) 13157c478bd9Sstevel@tonic-gate fr_info_t *fin; 13167c478bd9Sstevel@tonic-gate { 13177c478bd9Sstevel@tonic-gate tcphdr_t *tcp, *tcp2; 13187c478bd9Sstevel@tonic-gate int tlen, hlen; 13197c478bd9Sstevel@tonic-gate mblk_t *m; 13207c478bd9Sstevel@tonic-gate #ifdef USE_INET6 13217c478bd9Sstevel@tonic-gate ip6_t *ip6; 13227c478bd9Sstevel@tonic-gate #endif 13237c478bd9Sstevel@tonic-gate ip_t *ip; 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate tcp = fin->fin_dp; 13267c478bd9Sstevel@tonic-gate if (tcp->th_flags & TH_RST) 13277c478bd9Sstevel@tonic-gate return -1; 13287c478bd9Sstevel@tonic-gate 13297c478bd9Sstevel@tonic-gate #ifndef IPFILTER_CKSUM 13307c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 13317c478bd9Sstevel@tonic-gate return -1; 13327c478bd9Sstevel@tonic-gate #endif 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate tlen = (tcp->th_flags & (TH_SYN|TH_FIN)) ? 1 : 0; 13357c478bd9Sstevel@tonic-gate #ifdef USE_INET6 13367c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) 13377c478bd9Sstevel@tonic-gate hlen = sizeof(ip6_t); 13387c478bd9Sstevel@tonic-gate else 13397c478bd9Sstevel@tonic-gate #endif 13407c478bd9Sstevel@tonic-gate hlen = sizeof(ip_t); 13417c478bd9Sstevel@tonic-gate hlen += sizeof(*tcp2); 13427c478bd9Sstevel@tonic-gate if ((m = (mblk_t *)allocb(hlen + 64, BPRI_HI)) == NULL) 13437c478bd9Sstevel@tonic-gate return -1; 13447c478bd9Sstevel@tonic-gate 13457c478bd9Sstevel@tonic-gate m->b_rptr += 64; 13467c478bd9Sstevel@tonic-gate MTYPE(m) = M_DATA; 13477c478bd9Sstevel@tonic-gate m->b_wptr = m->b_rptr + hlen; 1348ab25eeb5Syz ip = (ip_t *)m->b_rptr; 1349ab25eeb5Syz bzero((char *)ip, hlen); 13507c478bd9Sstevel@tonic-gate tcp2 = (struct tcphdr *)(m->b_rptr + hlen - sizeof(*tcp2)); 13517c478bd9Sstevel@tonic-gate tcp2->th_dport = tcp->th_sport; 13527c478bd9Sstevel@tonic-gate tcp2->th_sport = tcp->th_dport; 13537c478bd9Sstevel@tonic-gate if (tcp->th_flags & TH_ACK) { 13547c478bd9Sstevel@tonic-gate tcp2->th_seq = tcp->th_ack; 13557c478bd9Sstevel@tonic-gate tcp2->th_flags = TH_RST; 13567c478bd9Sstevel@tonic-gate } else { 13577c478bd9Sstevel@tonic-gate tcp2->th_ack = ntohl(tcp->th_seq); 13587c478bd9Sstevel@tonic-gate tcp2->th_ack += tlen; 13597c478bd9Sstevel@tonic-gate tcp2->th_ack = htonl(tcp2->th_ack); 13607c478bd9Sstevel@tonic-gate tcp2->th_flags = TH_RST|TH_ACK; 13617c478bd9Sstevel@tonic-gate } 13627c478bd9Sstevel@tonic-gate tcp2->th_off = sizeof(struct tcphdr) >> 2; 13637c478bd9Sstevel@tonic-gate 1364ab25eeb5Syz ip->ip_v = fin->fin_v; 13657c478bd9Sstevel@tonic-gate #ifdef USE_INET6 13667c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 13677c478bd9Sstevel@tonic-gate ip6 = (ip6_t *)m->b_rptr; 13687663b816Sml ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 1369d6c23f6fSyx ip6->ip6_src = fin->fin_dst6.in6; 1370d6c23f6fSyx ip6->ip6_dst = fin->fin_src6.in6; 13717c478bd9Sstevel@tonic-gate ip6->ip6_plen = htons(sizeof(*tcp)); 13727c478bd9Sstevel@tonic-gate ip6->ip6_nxt = IPPROTO_TCP; 13737663b816Sml tcp2->th_sum = fr_cksum(m, (ip_t *)ip6, IPPROTO_TCP, tcp2); 13747c478bd9Sstevel@tonic-gate } else 13757c478bd9Sstevel@tonic-gate #endif 13767c478bd9Sstevel@tonic-gate { 13777c478bd9Sstevel@tonic-gate ip->ip_src.s_addr = fin->fin_daddr; 13787c478bd9Sstevel@tonic-gate ip->ip_dst.s_addr = fin->fin_saddr; 13797c478bd9Sstevel@tonic-gate ip->ip_id = fr_nextipid(fin); 13807c478bd9Sstevel@tonic-gate ip->ip_hl = sizeof(*ip) >> 2; 13817c478bd9Sstevel@tonic-gate ip->ip_p = IPPROTO_TCP; 138237b40788Sekozlow ip->ip_len = sizeof(*ip) + sizeof(*tcp); 13837c478bd9Sstevel@tonic-gate ip->ip_tos = fin->fin_ip->ip_tos; 13847c478bd9Sstevel@tonic-gate tcp2->th_sum = fr_cksum(m, ip, IPPROTO_TCP, tcp2); 13857c478bd9Sstevel@tonic-gate } 1386ab25eeb5Syz return fr_send_ip(fin, m, &m); 13877c478bd9Sstevel@tonic-gate } 13887c478bd9Sstevel@tonic-gate 138937b40788Sekozlow /* 139037b40788Sekozlow * Function: fr_send_ip 139137b40788Sekozlow * Returns: 0: success 139237b40788Sekozlow * -1: failed 139337b40788Sekozlow * Parameters: 139437b40788Sekozlow * fin: packet information 139537b40788Sekozlow * m: the message block where ip head starts 139637b40788Sekozlow * 139737b40788Sekozlow * Send a new packet through the IP stack. 139837b40788Sekozlow * 139937b40788Sekozlow * For IPv4 packets, ip_len must be in host byte order, and ip_v, 140037b40788Sekozlow * ip_ttl, ip_off, and ip_sum are ignored (filled in by this 140137b40788Sekozlow * function). 140237b40788Sekozlow * 140337b40788Sekozlow * For IPv6 packets, ip6_flow, ip6_vfc, and ip6_hlim are filled 140437b40788Sekozlow * in by this function. 140537b40788Sekozlow * 140637b40788Sekozlow * All other portions of the packet must be in on-the-wire format. 140737b40788Sekozlow */ 1408ab25eeb5Syz /*ARGSUSED*/ 1409ab25eeb5Syz static int fr_send_ip(fin, m, mpp) 14107c478bd9Sstevel@tonic-gate fr_info_t *fin; 1411ab25eeb5Syz mblk_t *m, **mpp; 14127c478bd9Sstevel@tonic-gate { 1413ab25eeb5Syz qpktinfo_t qpi, *qpip; 1414ab25eeb5Syz fr_info_t fnew; 1415ab25eeb5Syz ip_t *ip; 1416ab25eeb5Syz int i, hlen; 1417f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1418ab25eeb5Syz 1419ab25eeb5Syz ip = (ip_t *)m->b_rptr; 1420ab25eeb5Syz bzero((char *)&fnew, sizeof(fnew)); 14217c478bd9Sstevel@tonic-gate 14227c478bd9Sstevel@tonic-gate #ifdef USE_INET6 14237c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 14247c478bd9Sstevel@tonic-gate ip6_t *ip6; 14257c478bd9Sstevel@tonic-gate 1426ab25eeb5Syz ip6 = (ip6_t *)ip; 14277c478bd9Sstevel@tonic-gate ip6->ip6_vfc = 0x60; 14287c478bd9Sstevel@tonic-gate ip6->ip6_hlim = 127; 1429ab25eeb5Syz fnew.fin_v = 6; 1430ab25eeb5Syz hlen = sizeof(*ip6); 1431923d6102Szf fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen; 14327c478bd9Sstevel@tonic-gate } else 14337c478bd9Sstevel@tonic-gate #endif 14347c478bd9Sstevel@tonic-gate { 1435ab25eeb5Syz fnew.fin_v = 4; 14367c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 10 14377c478bd9Sstevel@tonic-gate ip->ip_ttl = 255; 1438f4b3ec61Sdh if (net_getpmtuenabled(ifs->ifs_ipf_ipv4) == 1) 1439381a2a9aSdr ip->ip_off = htons(IP_DF); 14407c478bd9Sstevel@tonic-gate #else 1441ab25eeb5Syz if (ip_ttl_ptr != NULL) 1442ab25eeb5Syz ip->ip_ttl = (u_char)(*ip_ttl_ptr); 1443ab25eeb5Syz else 1444ab25eeb5Syz ip->ip_ttl = 63; 1445ab25eeb5Syz if (ip_mtudisc != NULL) 1446ab25eeb5Syz ip->ip_off = htons(*ip_mtudisc ? IP_DF : 0); 1447ab25eeb5Syz else 1448ab25eeb5Syz ip->ip_off = htons(IP_DF); 14497c478bd9Sstevel@tonic-gate #endif 1450ab25eeb5Syz /* 1451ab25eeb5Syz * The dance with byte order and ip_len/ip_off is because in 1452ab25eeb5Syz * fr_fastroute, it expects them to be in host byte order but 1453ab25eeb5Syz * ipf_cksum expects them to be in network byte order. 1454ab25eeb5Syz */ 1455ab25eeb5Syz ip->ip_len = htons(ip->ip_len); 14567c478bd9Sstevel@tonic-gate ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip)); 1457ab25eeb5Syz ip->ip_len = ntohs(ip->ip_len); 1458ab25eeb5Syz ip->ip_off = ntohs(ip->ip_off); 1459ab25eeb5Syz hlen = sizeof(*ip); 1460923d6102Szf fnew.fin_plen = ip->ip_len; 14617c478bd9Sstevel@tonic-gate } 1462ab25eeb5Syz 1463ab25eeb5Syz qpip = fin->fin_qpi; 1464ab25eeb5Syz qpi.qpi_off = 0; 1465381a2a9aSdr qpi.qpi_ill = qpip->qpi_ill; 1466ab25eeb5Syz qpi.qpi_m = m; 1467ab25eeb5Syz qpi.qpi_data = ip; 1468ab25eeb5Syz fnew.fin_qpi = &qpi; 1469ab25eeb5Syz fnew.fin_ifp = fin->fin_ifp; 1470*cec263d4SAndy Fiddaman fnew.fin_flx = FI_NOCKSUM | FI_GENERATED; 1471ab25eeb5Syz fnew.fin_m = m; 147290907f62SJohn Ojemann fnew.fin_qfm = m; 1473ab25eeb5Syz fnew.fin_ip = ip; 1474ab25eeb5Syz fnew.fin_mp = mpp; 1475ab25eeb5Syz fnew.fin_hlen = hlen; 1476ab25eeb5Syz fnew.fin_dp = (char *)ip + hlen; 1477f4b3ec61Sdh fnew.fin_ifs = fin->fin_ifs; 1478ab25eeb5Syz (void) fr_makefrip(hlen, ip, &fnew); 1479ab25eeb5Syz 1480ab25eeb5Syz i = fr_fastroute(m, mpp, &fnew, NULL); 14817c478bd9Sstevel@tonic-gate return i; 14827c478bd9Sstevel@tonic-gate } 14837c478bd9Sstevel@tonic-gate 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate int fr_send_icmp_err(type, fin, dst) 14867c478bd9Sstevel@tonic-gate int type; 14877c478bd9Sstevel@tonic-gate fr_info_t *fin; 14887c478bd9Sstevel@tonic-gate int dst; 14897c478bd9Sstevel@tonic-gate { 14907c478bd9Sstevel@tonic-gate struct in_addr dst4; 14917c478bd9Sstevel@tonic-gate struct icmp *icmp; 1492ab25eeb5Syz qpktinfo_t *qpi; 14937c478bd9Sstevel@tonic-gate int hlen, code; 1494381a2a9aSdr phy_if_t phy; 14957c478bd9Sstevel@tonic-gate u_short sz; 14967c478bd9Sstevel@tonic-gate #ifdef USE_INET6 14977c478bd9Sstevel@tonic-gate mblk_t *mb; 14987c478bd9Sstevel@tonic-gate #endif 14997c478bd9Sstevel@tonic-gate mblk_t *m; 15007c478bd9Sstevel@tonic-gate #ifdef USE_INET6 15017c478bd9Sstevel@tonic-gate ip6_t *ip6; 15027c478bd9Sstevel@tonic-gate #endif 15037c478bd9Sstevel@tonic-gate ip_t *ip; 1504f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 15057c478bd9Sstevel@tonic-gate 15067c478bd9Sstevel@tonic-gate if ((type < 0) || (type > ICMP_MAXTYPE)) 15077c478bd9Sstevel@tonic-gate return -1; 15087c478bd9Sstevel@tonic-gate 15097c478bd9Sstevel@tonic-gate code = fin->fin_icode; 15107c478bd9Sstevel@tonic-gate #ifdef USE_INET6 151133f2fefdSDarren Reed if ((code < 0) || (code >= ICMP_MAX_UNREACH)) 15127c478bd9Sstevel@tonic-gate return -1; 15137c478bd9Sstevel@tonic-gate #endif 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate #ifndef IPFILTER_CKSUM 15167c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 15177c478bd9Sstevel@tonic-gate return -1; 15187c478bd9Sstevel@tonic-gate #endif 15197c478bd9Sstevel@tonic-gate 1520ab25eeb5Syz qpi = fin->fin_qpi; 15217c478bd9Sstevel@tonic-gate 15227c478bd9Sstevel@tonic-gate #ifdef USE_INET6 15237c478bd9Sstevel@tonic-gate mb = fin->fin_qfm; 15247c478bd9Sstevel@tonic-gate 15257c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 15267c478bd9Sstevel@tonic-gate sz = sizeof(ip6_t); 15277c478bd9Sstevel@tonic-gate sz += MIN(mb->b_wptr - mb->b_rptr, 512); 15287c478bd9Sstevel@tonic-gate hlen = sizeof(ip6_t); 15297c478bd9Sstevel@tonic-gate type = icmptoicmp6types[type]; 15307c478bd9Sstevel@tonic-gate if (type == ICMP6_DST_UNREACH) 15317c478bd9Sstevel@tonic-gate code = icmptoicmp6unreach[code]; 15327c478bd9Sstevel@tonic-gate } else 15337c478bd9Sstevel@tonic-gate #endif 15347c478bd9Sstevel@tonic-gate { 15357c478bd9Sstevel@tonic-gate if ((fin->fin_p == IPPROTO_ICMP) && 15367c478bd9Sstevel@tonic-gate !(fin->fin_flx & FI_SHORT)) 15377c478bd9Sstevel@tonic-gate switch (ntohs(fin->fin_data[0]) >> 8) 15387c478bd9Sstevel@tonic-gate { 15397c478bd9Sstevel@tonic-gate case ICMP_ECHO : 15407c478bd9Sstevel@tonic-gate case ICMP_TSTAMP : 15417c478bd9Sstevel@tonic-gate case ICMP_IREQ : 15427c478bd9Sstevel@tonic-gate case ICMP_MASKREQ : 15437c478bd9Sstevel@tonic-gate break; 15447c478bd9Sstevel@tonic-gate default : 15457c478bd9Sstevel@tonic-gate return 0; 15467c478bd9Sstevel@tonic-gate } 15477c478bd9Sstevel@tonic-gate 15487c478bd9Sstevel@tonic-gate sz = sizeof(ip_t) * 2; 15497c478bd9Sstevel@tonic-gate sz += 8; /* 64 bits of data */ 15507c478bd9Sstevel@tonic-gate hlen = sizeof(ip_t); 15517c478bd9Sstevel@tonic-gate } 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate sz += offsetof(struct icmp, icmp_ip); 15547c478bd9Sstevel@tonic-gate if ((m = (mblk_t *)allocb((size_t)sz + 64, BPRI_HI)) == NULL) 15557c478bd9Sstevel@tonic-gate return -1; 15567c478bd9Sstevel@tonic-gate MTYPE(m) = M_DATA; 15577c478bd9Sstevel@tonic-gate m->b_rptr += 64; 15587c478bd9Sstevel@tonic-gate m->b_wptr = m->b_rptr + sz; 15597c478bd9Sstevel@tonic-gate bzero((char *)m->b_rptr, (size_t)sz); 1560ab25eeb5Syz ip = (ip_t *)m->b_rptr; 1561ab25eeb5Syz ip->ip_v = fin->fin_v; 15627c478bd9Sstevel@tonic-gate icmp = (struct icmp *)(m->b_rptr + hlen); 15637c478bd9Sstevel@tonic-gate icmp->icmp_type = type & 0xff; 15647c478bd9Sstevel@tonic-gate icmp->icmp_code = code & 0xff; 1565381a2a9aSdr phy = (phy_if_t)qpi->qpi_ill; 1566381a2a9aSdr if (type == ICMP_UNREACH && (phy != 0) && 15677c478bd9Sstevel@tonic-gate fin->fin_icode == ICMP_UNREACH_NEEDFRAG) 1568f4b3ec61Sdh icmp->icmp_nextmtu = net_getmtu(ifs->ifs_ipf_ipv4, phy,0 ); 15697c478bd9Sstevel@tonic-gate 15707c478bd9Sstevel@tonic-gate #ifdef USE_INET6 15717c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) { 15727c478bd9Sstevel@tonic-gate struct in6_addr dst6; 15737c478bd9Sstevel@tonic-gate int csz; 15747c478bd9Sstevel@tonic-gate 15757c478bd9Sstevel@tonic-gate if (dst == 0) { 1576f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1577f4b3ec61Sdh 1578381a2a9aSdr if (fr_ifpaddr(6, FRI_NORMAL, (void *)phy, 1579f4b3ec61Sdh (void *)&dst6, NULL, ifs) == -1) { 15807c478bd9Sstevel@tonic-gate FREE_MB_T(m); 15817c478bd9Sstevel@tonic-gate return -1; 15827c478bd9Sstevel@tonic-gate } 15837c478bd9Sstevel@tonic-gate } else 1584d6c23f6fSyx dst6 = fin->fin_dst6.in6; 15857c478bd9Sstevel@tonic-gate 15867c478bd9Sstevel@tonic-gate csz = sz; 15877c478bd9Sstevel@tonic-gate sz -= sizeof(ip6_t); 15887c478bd9Sstevel@tonic-gate ip6 = (ip6_t *)m->b_rptr; 15897663b816Sml ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 15907c478bd9Sstevel@tonic-gate ip6->ip6_plen = htons((u_short)sz); 15917c478bd9Sstevel@tonic-gate ip6->ip6_nxt = IPPROTO_ICMPV6; 15927c478bd9Sstevel@tonic-gate ip6->ip6_src = dst6; 1593d6c23f6fSyx ip6->ip6_dst = fin->fin_src6.in6; 15947c478bd9Sstevel@tonic-gate sz -= offsetof(struct icmp, icmp_ip); 15957c478bd9Sstevel@tonic-gate bcopy((char *)mb->b_rptr, (char *)&icmp->icmp_ip, sz); 15967c478bd9Sstevel@tonic-gate icmp->icmp_cksum = csz - sizeof(ip6_t); 15977c478bd9Sstevel@tonic-gate } else 15987c478bd9Sstevel@tonic-gate #endif 15997c478bd9Sstevel@tonic-gate { 16007c478bd9Sstevel@tonic-gate ip->ip_hl = sizeof(*ip) >> 2; 16017c478bd9Sstevel@tonic-gate ip->ip_p = IPPROTO_ICMP; 16027c478bd9Sstevel@tonic-gate ip->ip_id = fin->fin_ip->ip_id; 16037c478bd9Sstevel@tonic-gate ip->ip_tos = fin->fin_ip->ip_tos; 160437b40788Sekozlow ip->ip_len = (u_short)sz; 16057c478bd9Sstevel@tonic-gate if (dst == 0) { 1606f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1607f4b3ec61Sdh 1608381a2a9aSdr if (fr_ifpaddr(4, FRI_NORMAL, (void *)phy, 1609f4b3ec61Sdh (void *)&dst4, NULL, ifs) == -1) { 16107c478bd9Sstevel@tonic-gate FREE_MB_T(m); 16117c478bd9Sstevel@tonic-gate return -1; 16127c478bd9Sstevel@tonic-gate } 1613381a2a9aSdr } else { 16147c478bd9Sstevel@tonic-gate dst4 = fin->fin_dst; 1615381a2a9aSdr } 16167c478bd9Sstevel@tonic-gate ip->ip_src = dst4; 16177c478bd9Sstevel@tonic-gate ip->ip_dst = fin->fin_src; 16187c478bd9Sstevel@tonic-gate bcopy((char *)fin->fin_ip, (char *)&icmp->icmp_ip, 16197c478bd9Sstevel@tonic-gate sizeof(*fin->fin_ip)); 16207c478bd9Sstevel@tonic-gate bcopy((char *)fin->fin_ip + fin->fin_hlen, 16217c478bd9Sstevel@tonic-gate (char *)&icmp->icmp_ip + sizeof(*fin->fin_ip), 8); 16227663b816Sml icmp->icmp_ip.ip_len = htons(icmp->icmp_ip.ip_len); 1623ab25eeb5Syz icmp->icmp_ip.ip_off = htons(icmp->icmp_ip.ip_off); 16247c478bd9Sstevel@tonic-gate icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 16257c478bd9Sstevel@tonic-gate sz - sizeof(ip_t)); 16267c478bd9Sstevel@tonic-gate } 16277c478bd9Sstevel@tonic-gate 16287c478bd9Sstevel@tonic-gate /* 16297c478bd9Sstevel@tonic-gate * Need to exit out of these so we don't recursively call rw_enter 16307c478bd9Sstevel@tonic-gate * from fr_qout. 16317c478bd9Sstevel@tonic-gate */ 1632ab25eeb5Syz return fr_send_ip(fin, m, &m); 16337c478bd9Sstevel@tonic-gate } 16347c478bd9Sstevel@tonic-gate 16357c478bd9Sstevel@tonic-gate #include <sys/time.h> 16367c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 16377c478bd9Sstevel@tonic-gate 16387c478bd9Sstevel@tonic-gate #ifndef _KERNEL 16397c478bd9Sstevel@tonic-gate #include <stdio.h> 16407c478bd9Sstevel@tonic-gate #endif 16417c478bd9Sstevel@tonic-gate 16427c478bd9Sstevel@tonic-gate /* 164372680cf5SDarren Reed * Return the first IP Address associated with an interface 164472680cf5SDarren Reed * For IPv6, we walk through the list of logical interfaces and return 164572680cf5SDarren Reed * the address of the first one that isn't a link-local interface. 164672680cf5SDarren Reed * We can't assume that it is :1 because another link-local address 164772680cf5SDarren Reed * may have been assigned there. 16487c478bd9Sstevel@tonic-gate */ 16497c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1650f4b3ec61Sdh int fr_ifpaddr(v, atype, ifptr, inp, inpmask, ifs) 16517c478bd9Sstevel@tonic-gate int v, atype; 1652381a2a9aSdr void *ifptr; 1653381a2a9aSdr struct in_addr *inp, *inpmask; 1654f4b3ec61Sdh ipf_stack_t *ifs; 16557c478bd9Sstevel@tonic-gate { 1656381a2a9aSdr struct sockaddr_in6 v6addr[2]; 1657381a2a9aSdr struct sockaddr_in v4addr[2]; 1658381a2a9aSdr net_ifaddr_t type[2]; 16597ddc9b1aSDarren Reed net_handle_t net_data; 1660381a2a9aSdr phy_if_t phyif; 1661381a2a9aSdr void *array; 1662381a2a9aSdr 1663381a2a9aSdr switch (v) 1664381a2a9aSdr { 1665381a2a9aSdr case 4: 1666f4b3ec61Sdh net_data = ifs->ifs_ipf_ipv4; 1667381a2a9aSdr array = v4addr; 1668381a2a9aSdr break; 1669381a2a9aSdr case 6: 1670f4b3ec61Sdh net_data = ifs->ifs_ipf_ipv6; 1671381a2a9aSdr array = v6addr; 1672381a2a9aSdr break; 1673381a2a9aSdr default: 1674381a2a9aSdr net_data = NULL; 1675381a2a9aSdr break; 1676381a2a9aSdr } 16777c478bd9Sstevel@tonic-gate 1678381a2a9aSdr if (net_data == NULL) 16797c478bd9Sstevel@tonic-gate return -1; 16807c478bd9Sstevel@tonic-gate 1681381a2a9aSdr phyif = (phy_if_t)ifptr; 1682ab25eeb5Syz 1683ab25eeb5Syz switch (atype) 1684ab25eeb5Syz { 1685ab25eeb5Syz case FRI_PEERADDR : 1686381a2a9aSdr type[0] = NA_PEER; 1687ab25eeb5Syz break; 1688381a2a9aSdr 1689381a2a9aSdr case FRI_BROADCAST : 1690381a2a9aSdr type[0] = NA_BROADCAST; 1691381a2a9aSdr break; 1692381a2a9aSdr 1693ab25eeb5Syz default : 1694381a2a9aSdr type[0] = NA_ADDRESS; 1695ab25eeb5Syz break; 1696ab25eeb5Syz } 16977c478bd9Sstevel@tonic-gate 1698381a2a9aSdr type[1] = NA_NETMASK; 1699381a2a9aSdr 1700381a2a9aSdr if (v == 6) { 170172680cf5SDarren Reed lif_if_t idx = 0; 170272680cf5SDarren Reed 170372680cf5SDarren Reed do { 170472680cf5SDarren Reed idx = net_lifgetnext(net_data, phyif, idx); 170572680cf5SDarren Reed if (net_getlifaddr(net_data, phyif, idx, 2, type, 170672680cf5SDarren Reed array) < 0) 170772680cf5SDarren Reed return -1; 170872680cf5SDarren Reed if (!IN6_IS_ADDR_LINKLOCAL(&v6addr[0].sin6_addr) && 170972680cf5SDarren Reed !IN6_IS_ADDR_MULTICAST(&v6addr[0].sin6_addr)) 171072680cf5SDarren Reed break; 171172680cf5SDarren Reed } while (idx != 0); 171272680cf5SDarren Reed 171372680cf5SDarren Reed if (idx == 0) 171472680cf5SDarren Reed return -1; 171572680cf5SDarren Reed 1716381a2a9aSdr return fr_ifpfillv6addr(atype, &v6addr[0], &v6addr[1], 1717381a2a9aSdr inp, inpmask); 17187c478bd9Sstevel@tonic-gate } 171972680cf5SDarren Reed 172072680cf5SDarren Reed if (net_getlifaddr(net_data, phyif, 0, 2, type, array) < 0) 172172680cf5SDarren Reed return -1; 172272680cf5SDarren Reed 1723381a2a9aSdr return fr_ifpfillv4addr(atype, &v4addr[0], &v4addr[1], inp, inpmask); 17247c478bd9Sstevel@tonic-gate } 17257c478bd9Sstevel@tonic-gate 17267c478bd9Sstevel@tonic-gate 17277c478bd9Sstevel@tonic-gate u_32_t fr_newisn(fin) 17287c478bd9Sstevel@tonic-gate fr_info_t *fin; 17297c478bd9Sstevel@tonic-gate { 17307c478bd9Sstevel@tonic-gate static int iss_seq_off = 0; 17317c478bd9Sstevel@tonic-gate u_char hash[16]; 17327c478bd9Sstevel@tonic-gate u_32_t newiss; 17337c478bd9Sstevel@tonic-gate MD5_CTX ctx; 1734f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 17357c478bd9Sstevel@tonic-gate 17367c478bd9Sstevel@tonic-gate /* 17377c478bd9Sstevel@tonic-gate * Compute the base value of the ISS. It is a hash 17387c478bd9Sstevel@tonic-gate * of (saddr, sport, daddr, dport, secret). 17397c478bd9Sstevel@tonic-gate */ 17407c478bd9Sstevel@tonic-gate MD5Init(&ctx); 17417c478bd9Sstevel@tonic-gate 17427c478bd9Sstevel@tonic-gate MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 17437c478bd9Sstevel@tonic-gate sizeof(fin->fin_fi.fi_src)); 17447c478bd9Sstevel@tonic-gate MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 17457c478bd9Sstevel@tonic-gate sizeof(fin->fin_fi.fi_dst)); 17467c478bd9Sstevel@tonic-gate MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 17477c478bd9Sstevel@tonic-gate 1748f4b3ec61Sdh MD5Update(&ctx, ifs->ifs_ipf_iss_secret, sizeof(ifs->ifs_ipf_iss_secret)); 17497c478bd9Sstevel@tonic-gate 17507c478bd9Sstevel@tonic-gate MD5Final(hash, &ctx); 17517c478bd9Sstevel@tonic-gate 17527c478bd9Sstevel@tonic-gate bcopy(hash, &newiss, sizeof(newiss)); 17537c478bd9Sstevel@tonic-gate 17547c478bd9Sstevel@tonic-gate /* 17557c478bd9Sstevel@tonic-gate * Now increment our "timer", and add it in to 17567c478bd9Sstevel@tonic-gate * the computed value. 17577c478bd9Sstevel@tonic-gate * 17587c478bd9Sstevel@tonic-gate * XXX Use `addin'? 17597c478bd9Sstevel@tonic-gate * XXX TCP_ISSINCR too large to use? 17607c478bd9Sstevel@tonic-gate */ 17617c478bd9Sstevel@tonic-gate iss_seq_off += 0x00010000; 17627c478bd9Sstevel@tonic-gate newiss += iss_seq_off; 17637c478bd9Sstevel@tonic-gate return newiss; 17647c478bd9Sstevel@tonic-gate } 17657c478bd9Sstevel@tonic-gate 17667c478bd9Sstevel@tonic-gate 17677c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 17687c478bd9Sstevel@tonic-gate /* Function: fr_nextipid */ 17697c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 17707c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 17717c478bd9Sstevel@tonic-gate /* */ 17727c478bd9Sstevel@tonic-gate /* Returns the next IPv4 ID to use for this packet. */ 17737c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 1774ab25eeb5Syz u_short fr_nextipid(fin) 17757c478bd9Sstevel@tonic-gate fr_info_t *fin; 17767c478bd9Sstevel@tonic-gate { 17777c478bd9Sstevel@tonic-gate static u_short ipid = 0; 17787c478bd9Sstevel@tonic-gate u_short id; 1779f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 17807c478bd9Sstevel@tonic-gate 1781f4b3ec61Sdh MUTEX_ENTER(&ifs->ifs_ipf_rw); 178233f2fefdSDarren Reed if (fin->fin_pktnum != 0) { 178333f2fefdSDarren Reed id = fin->fin_pktnum & 0xffff; 178433f2fefdSDarren Reed } else { 17857c478bd9Sstevel@tonic-gate id = ipid++; 178633f2fefdSDarren Reed } 1787f4b3ec61Sdh MUTEX_EXIT(&ifs->ifs_ipf_rw); 17887c478bd9Sstevel@tonic-gate 17897c478bd9Sstevel@tonic-gate return id; 17907c478bd9Sstevel@tonic-gate } 17917c478bd9Sstevel@tonic-gate 17927c478bd9Sstevel@tonic-gate 17937c478bd9Sstevel@tonic-gate #ifndef IPFILTER_CKSUM 17947c478bd9Sstevel@tonic-gate /* ARGSUSED */ 17957c478bd9Sstevel@tonic-gate #endif 17967c478bd9Sstevel@tonic-gate INLINE void fr_checkv4sum(fin) 17977c478bd9Sstevel@tonic-gate fr_info_t *fin; 17987c478bd9Sstevel@tonic-gate { 17997c478bd9Sstevel@tonic-gate #ifdef IPFILTER_CKSUM 18007c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 18017c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_BAD; 18027c478bd9Sstevel@tonic-gate #endif 18037c478bd9Sstevel@tonic-gate } 18047c478bd9Sstevel@tonic-gate 18057c478bd9Sstevel@tonic-gate 18067c478bd9Sstevel@tonic-gate #ifdef USE_INET6 1807ab25eeb5Syz # ifndef IPFILTER_CKSUM 18087663b816Sml /* ARGSUSED */ 1809ab25eeb5Syz # endif 18107c478bd9Sstevel@tonic-gate INLINE void fr_checkv6sum(fin) 18117c478bd9Sstevel@tonic-gate fr_info_t *fin; 18127c478bd9Sstevel@tonic-gate { 18137c478bd9Sstevel@tonic-gate # ifdef IPFILTER_CKSUM 18147c478bd9Sstevel@tonic-gate if (fr_checkl4sum(fin) == -1) 18157c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_BAD; 18167c478bd9Sstevel@tonic-gate # endif 18177c478bd9Sstevel@tonic-gate } 18187c478bd9Sstevel@tonic-gate #endif /* USE_INET6 */ 1819ab25eeb5Syz 1820ab25eeb5Syz 1821ab25eeb5Syz #if (SOLARIS2 < 7) 1822ab25eeb5Syz void fr_slowtimer() 1823ab25eeb5Syz #else 1824ab25eeb5Syz /*ARGSUSED*/ 1825f4b3ec61Sdh void fr_slowtimer __P((void *arg)) 1826ab25eeb5Syz #endif 1827ab25eeb5Syz { 1828f4b3ec61Sdh ipf_stack_t *ifs = arg; 1829ab25eeb5Syz 183044aaa2b6Sjojemann READ_ENTER(&ifs->ifs_ipf_global); 183144aaa2b6Sjojemann if (ifs->ifs_fr_running != 1) { 183244aaa2b6Sjojemann ifs->ifs_fr_timer_id = NULL; 1833f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 1834ab25eeb5Syz return; 1835ab25eeb5Syz } 1836fd636508Szf ipf_expiretokens(ifs); 1837f4b3ec61Sdh fr_fragexpire(ifs); 1838f4b3ec61Sdh fr_timeoutstate(ifs); 1839f4b3ec61Sdh fr_natexpire(ifs); 1840f4b3ec61Sdh fr_authexpire(ifs); 1841f4b3ec61Sdh ifs->ifs_fr_ticks++; 184244aaa2b6Sjojemann if (ifs->ifs_fr_running == 1) 1843f4b3ec61Sdh ifs->ifs_fr_timer_id = timeout(fr_slowtimer, arg, 1844f4b3ec61Sdh drv_usectohz(500000)); 1845ab25eeb5Syz else 1846f4b3ec61Sdh ifs->ifs_fr_timer_id = NULL; 1847f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 1848ab25eeb5Syz } 1849ab25eeb5Syz 1850ab25eeb5Syz 1851381a2a9aSdr /* ------------------------------------------------------------------------ */ 1852381a2a9aSdr /* Function: fr_pullup */ 1853381a2a9aSdr /* Returns: NULL == pullup failed, else pointer to protocol header */ 1854381a2a9aSdr /* Parameters: m(I) - pointer to buffer where data packet starts */ 1855381a2a9aSdr /* fin(I) - pointer to packet information */ 1856381a2a9aSdr /* len(I) - number of bytes to pullup */ 1857381a2a9aSdr /* */ 1858381a2a9aSdr /* Attempt to move at least len bytes (from the start of the buffer) into a */ 1859381a2a9aSdr /* single buffer for ease of access. Operating system native functions are */ 1860381a2a9aSdr /* used to manage buffers - if necessary. If the entire packet ends up in */ 1861381a2a9aSdr /* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */ 1862381a2a9aSdr /* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ 1863381a2a9aSdr /* and ONLY if the pullup succeeds. */ 1864381a2a9aSdr /* */ 1865381a2a9aSdr /* We assume that 'min' is a pointer to a buffer that is part of the chain */ 1866381a2a9aSdr /* of buffers that starts at *fin->fin_mp. */ 1867381a2a9aSdr /* ------------------------------------------------------------------------ */ 1868381a2a9aSdr void *fr_pullup(min, fin, len) 1869381a2a9aSdr mb_t *min; 1870381a2a9aSdr fr_info_t *fin; 1871381a2a9aSdr int len; 1872381a2a9aSdr { 1873381a2a9aSdr qpktinfo_t *qpi = fin->fin_qpi; 1874381a2a9aSdr int out = fin->fin_out, dpoff, ipoff; 1875381a2a9aSdr mb_t *m = min, *m1, *m2; 1876381a2a9aSdr char *ip; 187708ee25aeSdr uint32_t start, stuff, end, value, flags; 1878f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1879381a2a9aSdr 1880381a2a9aSdr if (m == NULL) 1881381a2a9aSdr return NULL; 1882381a2a9aSdr 1883381a2a9aSdr ip = (char *)fin->fin_ip; 1884381a2a9aSdr if ((fin->fin_flx & FI_COALESCE) != 0) 1885381a2a9aSdr return ip; 1886381a2a9aSdr 1887381a2a9aSdr ipoff = fin->fin_ipoff; 1888381a2a9aSdr if (fin->fin_dp != NULL) 1889381a2a9aSdr dpoff = (char *)fin->fin_dp - (char *)ip; 1890381a2a9aSdr else 1891381a2a9aSdr dpoff = 0; 1892381a2a9aSdr 189340cdc2e8SAlexandr Nedvedicky if (M_LEN(m) < len + ipoff) { 1894381a2a9aSdr 1895381a2a9aSdr /* 1896381a2a9aSdr * pfil_precheck ensures the IP header is on a 32bit 1897381a2a9aSdr * aligned address so simply fail if that isn't currently 1898381a2a9aSdr * the case (should never happen). 1899381a2a9aSdr */ 1900381a2a9aSdr int inc = 0; 1901381a2a9aSdr 1902381a2a9aSdr if (ipoff > 0) { 1903381a2a9aSdr if ((ipoff & 3) != 0) { 1904381a2a9aSdr inc = 4 - (ipoff & 3); 1905381a2a9aSdr if (m->b_rptr - inc >= m->b_datap->db_base) 1906381a2a9aSdr m->b_rptr -= inc; 1907381a2a9aSdr else 1908381a2a9aSdr inc = 0; 1909381a2a9aSdr } 1910381a2a9aSdr } 1911381a2a9aSdr 1912381a2a9aSdr /* 1913381a2a9aSdr * XXX This is here as a work around for a bug with DEBUG 1914381a2a9aSdr * XXX Solaris kernels. The problem is b_prev is used by IP 1915381a2a9aSdr * XXX code as a way to stash the phyint_index for a packet, 1916381a2a9aSdr * XXX this doesn't get reset by IP but freeb does an ASSERT() 1917381a2a9aSdr * XXX for both of these to be NULL. See 6442390. 1918381a2a9aSdr */ 1919381a2a9aSdr m1 = m; 1920381a2a9aSdr m2 = m->b_prev; 1921381a2a9aSdr 1922381a2a9aSdr do { 1923381a2a9aSdr m1->b_next = NULL; 1924381a2a9aSdr m1->b_prev = NULL; 1925381a2a9aSdr m1 = m1->b_cont; 1926381a2a9aSdr } while (m1); 192708ee25aeSdr 192808ee25aeSdr /* 192908ee25aeSdr * Need to preserve checksum information by copying them 193008ee25aeSdr * to newmp which heads the pulluped message. 193108ee25aeSdr */ 1932ec71f88eSPatrick Mooney mac_hcksum_get(m, &start, &stuff, &end, &value, &flags); 193308ee25aeSdr 1934381a2a9aSdr if (pullupmsg(m, len + ipoff + inc) == 0) { 1935f4b3ec61Sdh ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[1]); 1936381a2a9aSdr FREE_MB_T(*fin->fin_mp); 1937381a2a9aSdr *fin->fin_mp = NULL; 1938381a2a9aSdr fin->fin_m = NULL; 1939381a2a9aSdr fin->fin_ip = NULL; 1940381a2a9aSdr fin->fin_dp = NULL; 1941381a2a9aSdr qpi->qpi_data = NULL; 1942381a2a9aSdr return NULL; 1943381a2a9aSdr } 194408ee25aeSdr 1945ec71f88eSPatrick Mooney mac_hcksum_set(m, start, stuff, end, value, flags); 194608ee25aeSdr 1947381a2a9aSdr m->b_prev = m2; 1948381a2a9aSdr m->b_rptr += inc; 1949381a2a9aSdr fin->fin_m = m; 1950381a2a9aSdr ip = MTOD(m, char *) + ipoff; 1951381a2a9aSdr qpi->qpi_data = ip; 1952381a2a9aSdr } 1953381a2a9aSdr 1954f4b3ec61Sdh ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[0]); 1955381a2a9aSdr fin->fin_ip = (ip_t *)ip; 1956381a2a9aSdr if (fin->fin_dp != NULL) 1957381a2a9aSdr fin->fin_dp = (char *)fin->fin_ip + dpoff; 1958381a2a9aSdr 1959381a2a9aSdr if (len == fin->fin_plen) 1960381a2a9aSdr fin->fin_flx |= FI_COALESCE; 1961381a2a9aSdr return ip; 1962381a2a9aSdr } 1963381a2a9aSdr 1964381a2a9aSdr 1965ab25eeb5Syz /* 1966381a2a9aSdr * Function: fr_verifysrc 1967381a2a9aSdr * Returns: int (really boolean) 1968381a2a9aSdr * Parameters: fin - packet information 1969381a2a9aSdr * 1970381a2a9aSdr * Check whether the packet has a valid source address for the interface on 1971381a2a9aSdr * which the packet arrived, implementing the "fr_chksrc" feature. 1972381a2a9aSdr * Returns true iff the packet's source address is valid. 1973381a2a9aSdr */ 1974381a2a9aSdr int fr_verifysrc(fin) 1975381a2a9aSdr fr_info_t *fin; 1976381a2a9aSdr { 19777ddc9b1aSDarren Reed net_handle_t net_data_p; 1978381a2a9aSdr phy_if_t phy_ifdata_routeto; 1979381a2a9aSdr struct sockaddr sin; 1980f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1981381a2a9aSdr 1982381a2a9aSdr if (fin->fin_v == 4) { 1983f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv4; 1984381a2a9aSdr } else if (fin->fin_v == 6) { 1985f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv6; 1986381a2a9aSdr } else { 1987381a2a9aSdr return (0); 1988381a2a9aSdr } 1989381a2a9aSdr 1990381a2a9aSdr /* Get the index corresponding to the if name */ 1991381a2a9aSdr sin.sa_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 1992381a2a9aSdr bcopy(&fin->fin_saddr, &sin.sa_data, sizeof (struct in_addr)); 19937ddc9b1aSDarren Reed phy_ifdata_routeto = net_routeto(net_data_p, &sin, NULL); 1994381a2a9aSdr 1995381a2a9aSdr return (((phy_if_t)fin->fin_ifp == phy_ifdata_routeto) ? 1 : 0); 1996381a2a9aSdr } 1997381a2a9aSdr 1998546c3aa8SJerry Jelinek /* 1999546c3aa8SJerry Jelinek * Return true only if forwarding is enabled on the interface. 2000546c3aa8SJerry Jelinek */ 2001546c3aa8SJerry Jelinek static int 2002546c3aa8SJerry Jelinek fr_forwarding_enabled(phy_if_t phyif, net_handle_t ndp) 2003546c3aa8SJerry Jelinek { 2004546c3aa8SJerry Jelinek lif_if_t lif; 2005546c3aa8SJerry Jelinek 2006546c3aa8SJerry Jelinek for (lif = net_lifgetnext(ndp, phyif, 0); lif > 0; 2007546c3aa8SJerry Jelinek lif = net_lifgetnext(ndp, phyif, lif)) { 2008546c3aa8SJerry Jelinek int res; 2009546c3aa8SJerry Jelinek uint64_t flags; 2010546c3aa8SJerry Jelinek 2011546c3aa8SJerry Jelinek res = net_getlifflags(ndp, phyif, lif, &flags); 2012546c3aa8SJerry Jelinek if (res != 0) 2013546c3aa8SJerry Jelinek return (0); 2014546c3aa8SJerry Jelinek if (flags & IFF_ROUTER) 2015546c3aa8SJerry Jelinek return (1); 2016546c3aa8SJerry Jelinek } 2017546c3aa8SJerry Jelinek 2018546c3aa8SJerry Jelinek return (0); 2019546c3aa8SJerry Jelinek } 2020381a2a9aSdr 2021381a2a9aSdr /* 2022381a2a9aSdr * Function: fr_fastroute 2023381a2a9aSdr * Returns: 0: success; 2024381a2a9aSdr * -1: failed 2025ab25eeb5Syz * Parameters: 2026381a2a9aSdr * mb: the message block where ip head starts 2027381a2a9aSdr * mpp: the pointer to the pointer of the orignal 2028381a2a9aSdr * packet message 2029381a2a9aSdr * fin: packet information 2030381a2a9aSdr * fdp: destination interface information 2031381a2a9aSdr * if it is NULL, no interface information provided. 2032ab25eeb5Syz * 2033ab25eeb5Syz * This function is for fastroute/to/dup-to rules. It calls 2034ab25eeb5Syz * pfil_make_lay2_packet to search route, make lay-2 header 2035ab25eeb5Syz * ,and identify output queue for the IP packet. 2036ab25eeb5Syz * The destination address depends on the following conditions: 2037ab25eeb5Syz * 1: for fastroute rule, fdp is passed in as NULL, so the 2038381a2a9aSdr * destination address is the IP Packet's destination address 2039ab25eeb5Syz * 2: for to/dup-to rule, if an ip address is specified after 2040381a2a9aSdr * the interface name, this address is the as destination 2041381a2a9aSdr * address. Otherwise IP Packet's destination address is used 2042ab25eeb5Syz */ 2043ab25eeb5Syz int fr_fastroute(mb, mpp, fin, fdp) 2044ab25eeb5Syz mblk_t *mb, **mpp; 2045ab25eeb5Syz fr_info_t *fin; 2046ab25eeb5Syz frdest_t *fdp; 2047ab25eeb5Syz { 20487ddc9b1aSDarren Reed net_handle_t net_data_p; 20497ddc9b1aSDarren Reed net_inject_t *inj; 2050ab25eeb5Syz mblk_t *mp = NULL; 2051381a2a9aSdr frentry_t *fr = fin->fin_fr; 2052ab25eeb5Syz qpktinfo_t *qpi; 2053ab25eeb5Syz ip_t *ip; 2054381a2a9aSdr 2055381a2a9aSdr struct sockaddr_in *sin; 2056381a2a9aSdr struct sockaddr_in6 *sin6; 2057381a2a9aSdr struct sockaddr *sinp; 2058f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 2059ab25eeb5Syz #ifndef sparc 2060ab25eeb5Syz u_short __iplen, __ipoff; 2061ab25eeb5Syz #endif 2062381a2a9aSdr 2063381a2a9aSdr if (fin->fin_v == 4) { 2064f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv4; 2065381a2a9aSdr } else if (fin->fin_v == 6) { 2066f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv6; 2067381a2a9aSdr } else { 2068381a2a9aSdr return (-1); 2069381a2a9aSdr } 2070381a2a9aSdr 2071546c3aa8SJerry Jelinek /* Check the src here, fin_ifp is the src interface. */ 2072*cec263d4SAndy Fiddaman if (!(fin->fin_flx & FI_GENERATED) && 2073*cec263d4SAndy Fiddaman !fr_forwarding_enabled((phy_if_t)fin->fin_ifp, net_data_p)) { 2074546c3aa8SJerry Jelinek return (-1); 2075*cec263d4SAndy Fiddaman } 2076546c3aa8SJerry Jelinek 20777ddc9b1aSDarren Reed inj = net_inject_alloc(NETINFO_VERSION); 20787ddc9b1aSDarren Reed if (inj == NULL) 20797ddc9b1aSDarren Reed return -1; 20807ddc9b1aSDarren Reed 2081ab25eeb5Syz ip = fin->fin_ip; 2082ab25eeb5Syz qpi = fin->fin_qpi; 2083ab25eeb5Syz 2084ab25eeb5Syz /* 2085ab25eeb5Syz * If this is a duplicate mblk then we want ip to point at that 2086ab25eeb5Syz * data, not the original, if and only if it is already pointing at 2087ab25eeb5Syz * the current mblk data. 2088381a2a9aSdr * 2089381a2a9aSdr * Otherwise, if it's not a duplicate, and we're not already pointing 2090e6c6c1faSyz * at the current mblk data, then we want to ensure that the data 2091e6c6c1faSyz * points at ip. 2092ab25eeb5Syz */ 2093381a2a9aSdr 2094381a2a9aSdr if ((ip == (ip_t *)qpi->qpi_m->b_rptr) && (qpi->qpi_m != mb)) { 2095ab25eeb5Syz ip = (ip_t *)mb->b_rptr; 2096381a2a9aSdr } else if ((qpi->qpi_m == mb) && (ip != (ip_t *)qpi->qpi_m->b_rptr)) { 2097381a2a9aSdr qpi->qpi_m->b_rptr = (uchar_t *)ip; 2098e6c6c1faSyz qpi->qpi_off = 0; 2099e6c6c1faSyz } 2100ab25eeb5Syz 2101ab25eeb5Syz /* 2102ab25eeb5Syz * If there is another M_PROTO, we don't want it 2103ab25eeb5Syz */ 2104ab25eeb5Syz if (*mpp != mb) { 2105ab25eeb5Syz mp = unlinkb(*mpp); 2106ab25eeb5Syz freeb(*mpp); 2107ab25eeb5Syz *mpp = mp; 2108ab25eeb5Syz } 2109ab25eeb5Syz 21107ddc9b1aSDarren Reed sinp = (struct sockaddr *)&inj->ni_addr; 2111381a2a9aSdr sin = (struct sockaddr_in *)sinp; 2112381a2a9aSdr sin6 = (struct sockaddr_in6 *)sinp; 21137ddc9b1aSDarren Reed bzero((char *)&inj->ni_addr, sizeof (inj->ni_addr)); 21147ddc9b1aSDarren Reed inj->ni_addr.ss_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 21157ddc9b1aSDarren Reed inj->ni_packet = mb; 2116ab25eeb5Syz 2117ab25eeb5Syz /* 2118ab25eeb5Syz * In case we're here due to "to <if>" being used with 2119ab25eeb5Syz * "keep state", check that we're going in the correct 2120ab25eeb5Syz * direction. 2121ab25eeb5Syz */ 2122381a2a9aSdr if (fdp != NULL) { 2123381a2a9aSdr if ((fr != NULL) && (fdp->fd_ifp != NULL) && 2124381a2a9aSdr (fin->fin_rev != 0) && (fdp == &fr->fr_tif)) 2125381a2a9aSdr goto bad_fastroute; 21267ddc9b1aSDarren Reed inj->ni_physical = (phy_if_t)fdp->fd_ifp; 2127ab25eeb5Syz if (fin->fin_v == 4) { 2128381a2a9aSdr sin->sin_addr = fdp->fd_ip; 2129381a2a9aSdr } else { 2130381a2a9aSdr sin6->sin6_addr = fdp->fd_ip6.in6; 2131ab25eeb5Syz } 2132381a2a9aSdr } else { 2133381a2a9aSdr if (fin->fin_v == 4) { 2134381a2a9aSdr sin->sin_addr = ip->ip_dst; 2135381a2a9aSdr } else { 2136381a2a9aSdr sin6->sin6_addr = ((ip6_t *)ip)->ip6_dst; 2137ab25eeb5Syz } 21387ddc9b1aSDarren Reed inj->ni_physical = net_routeto(net_data_p, sinp, NULL); 2139ab25eeb5Syz } 2140ab25eeb5Syz 2141*cec263d4SAndy Fiddaman /* we're checking the destination here */ 2142*cec263d4SAndy Fiddaman if (!(fin->fin_flx & FI_GENERATED) && 2143*cec263d4SAndy Fiddaman !fr_forwarding_enabled(inj->ni_physical, net_data_p)) { 2144546c3aa8SJerry Jelinek goto bad_fastroute; 2145*cec263d4SAndy Fiddaman } 2146546c3aa8SJerry Jelinek 2147edd26dc5Sdr /* 2148edd26dc5Sdr * Clear the hardware checksum flags from packets that we are doing 2149edd26dc5Sdr * input processing on as leaving them set will cause the outgoing 2150edd26dc5Sdr * NIC (if it supports hardware checksum) to calculate them anew, 2151edd26dc5Sdr * using the old (correct) checksums as the pseudo value to start 2152edd26dc5Sdr * from. 2153edd26dc5Sdr */ 2154edd26dc5Sdr if (fin->fin_out == 0) { 2155edd26dc5Sdr DB_CKSUMFLAGS(mb) = 0; 2156edd26dc5Sdr } 2157c793af95Ssangeeta 2158381a2a9aSdr *mpp = mb; 2159ab25eeb5Syz 2160381a2a9aSdr if (fin->fin_out == 0) { 2161381a2a9aSdr void *saveifp; 2162381a2a9aSdr u_32_t pass; 2163ab25eeb5Syz 2164381a2a9aSdr saveifp = fin->fin_ifp; 21657ddc9b1aSDarren Reed fin->fin_ifp = (void *)inj->ni_physical; 2166d3675867Sjojemann fin->fin_flx &= ~FI_STATE; 2167381a2a9aSdr fin->fin_out = 1; 2168381a2a9aSdr (void) fr_acctpkt(fin, &pass); 2169381a2a9aSdr fin->fin_fr = NULL; 2170381a2a9aSdr if (!fr || !(fr->fr_flags & FR_RETMASK)) 2171381a2a9aSdr (void) fr_checkstate(fin, &pass); 2172d3675867Sjojemann if (fr_checknatout(fin, NULL) == -1) 2173381a2a9aSdr goto bad_fastroute; 2174381a2a9aSdr fin->fin_out = 0; 2175381a2a9aSdr fin->fin_ifp = saveifp; 2176381a2a9aSdr } 2177381a2a9aSdr #ifndef sparc 2178381a2a9aSdr if (fin->fin_v == 4) { 2179381a2a9aSdr __iplen = (u_short)ip->ip_len, 2180381a2a9aSdr __ipoff = (u_short)ip->ip_off; 2181ab25eeb5Syz 2182381a2a9aSdr ip->ip_len = htons(__iplen); 2183381a2a9aSdr ip->ip_off = htons(__ipoff); 2184381a2a9aSdr } 2185ab25eeb5Syz #endif 2186381a2a9aSdr 2187381a2a9aSdr if (net_data_p) { 21887ddc9b1aSDarren Reed if (net_inject(net_data_p, NI_DIRECT_OUT, inj) < 0) { 21897ddc9b1aSDarren Reed net_inject_free(inj); 2190381a2a9aSdr return (-1); 2191ab25eeb5Syz } 2192ab25eeb5Syz } 2193381a2a9aSdr 2194f4b3ec61Sdh ifs->ifs_fr_frouteok[0]++; 21957ddc9b1aSDarren Reed net_inject_free(inj); 2196381a2a9aSdr return 0; 2197ab25eeb5Syz bad_fastroute: 21987ddc9b1aSDarren Reed net_inject_free(inj); 2199ab25eeb5Syz freemsg(mb); 2200f4b3ec61Sdh ifs->ifs_fr_frouteok[1]++; 2201ab25eeb5Syz return -1; 2202ab25eeb5Syz } 2203ab25eeb5Syz 2204ab25eeb5Syz 2205ab25eeb5Syz /* ------------------------------------------------------------------------ */ 22067ddc9b1aSDarren Reed /* Function: ipf_hook4_out */ 2207381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 2208381a2a9aSdr /* Parameters: event(I) - pointer to event */ 2209381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 2210ab25eeb5Syz /* */ 2211381a2a9aSdr /* Calling ipf_hook. */ 2212381a2a9aSdr /* ------------------------------------------------------------------------ */ 2213381a2a9aSdr /*ARGSUSED*/ 22147ddc9b1aSDarren Reed int ipf_hook4_out(hook_event_token_t token, hook_data_t info, void *arg) 2215381a2a9aSdr { 22167ddc9b1aSDarren Reed return ipf_hook(info, 1, 0, arg); 2217cbded9aeSdr } 2218cbded9aeSdr /*ARGSUSED*/ 22197ddc9b1aSDarren Reed int ipf_hook6_out(hook_event_token_t token, hook_data_t info, void *arg) 2220cbded9aeSdr { 22217ddc9b1aSDarren Reed return ipf_hook6(info, 1, 0, arg); 2222381a2a9aSdr } 2223381a2a9aSdr 2224381a2a9aSdr /* ------------------------------------------------------------------------ */ 22257ddc9b1aSDarren Reed /* Function: ipf_hook4_in */ 2226381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 2227381a2a9aSdr /* Parameters: event(I) - pointer to event */ 2228381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 2229ab25eeb5Syz /* */ 2230381a2a9aSdr /* Calling ipf_hook. */ 2231ab25eeb5Syz /* ------------------------------------------------------------------------ */ 2232381a2a9aSdr /*ARGSUSED*/ 22337ddc9b1aSDarren Reed int ipf_hook4_in(hook_event_token_t token, hook_data_t info, void *arg) 2234ab25eeb5Syz { 22357ddc9b1aSDarren Reed return ipf_hook(info, 0, 0, arg); 2236cbded9aeSdr } 2237cbded9aeSdr /*ARGSUSED*/ 22387ddc9b1aSDarren Reed int ipf_hook6_in(hook_event_token_t token, hook_data_t info, void *arg) 2239cbded9aeSdr { 22407ddc9b1aSDarren Reed return ipf_hook6(info, 0, 0, arg); 2241381a2a9aSdr } 2242ab25eeb5Syz 2243ab25eeb5Syz 2244381a2a9aSdr /* ------------------------------------------------------------------------ */ 22457ddc9b1aSDarren Reed /* Function: ipf_hook4_loop_out */ 2246381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 2247381a2a9aSdr /* Parameters: event(I) - pointer to event */ 2248381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 2249381a2a9aSdr /* */ 2250381a2a9aSdr /* Calling ipf_hook. */ 2251381a2a9aSdr /* ------------------------------------------------------------------------ */ 2252381a2a9aSdr /*ARGSUSED*/ 22537ddc9b1aSDarren Reed int ipf_hook4_loop_out(hook_event_token_t token, hook_data_t info, void *arg) 2254cbded9aeSdr { 22557ddc9b1aSDarren Reed return ipf_hook(info, 1, FI_NOCKSUM, arg); 2256cbded9aeSdr } 2257cbded9aeSdr /*ARGSUSED*/ 22587ddc9b1aSDarren Reed int ipf_hook6_loop_out(hook_event_token_t token, hook_data_t info, void *arg) 2259381a2a9aSdr { 22607ddc9b1aSDarren Reed return ipf_hook6(info, 1, FI_NOCKSUM, arg); 2261381a2a9aSdr } 2262ab25eeb5Syz 2263b22a70abSPatrick Mooney /* Static constants used by ipf_hook_ether */ 2264b22a70abSPatrick Mooney static uint8_t ipf_eth_bcast_addr[ETHERADDRL] = { 2265b22a70abSPatrick Mooney 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF 2266b22a70abSPatrick Mooney }; 2267b22a70abSPatrick Mooney static uint8_t ipf_eth_ipv4_mcast[3] = { 0x01, 0x00, 0x5E }; 2268b22a70abSPatrick Mooney static uint8_t ipf_eth_ipv6_mcast[2] = { 0x33, 0x33 }; 2269b22a70abSPatrick Mooney 2270b22a70abSPatrick Mooney /* ------------------------------------------------------------------------ */ 2271b22a70abSPatrick Mooney /* Function: ipf_hook_ether */ 2272b22a70abSPatrick Mooney /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 2273b22a70abSPatrick Mooney /* Parameters: token(I) - pointer to event */ 2274b22a70abSPatrick Mooney /* info(I) - pointer to hook information for firewalling */ 2275b22a70abSPatrick Mooney /* */ 2276b22a70abSPatrick Mooney /* The ipf_hook_ether hook is currently private to illumos. It represents */ 2277b22a70abSPatrick Mooney /* a layer 2 datapath generally used by virtual machines. Currently the */ 2278b22a70abSPatrick Mooney /* hook is only used by the viona driver to pass along L2 frames for */ 2279b22a70abSPatrick Mooney /* inspection. It requires that the L2 ethernet header is contained within */ 2280b22a70abSPatrick Mooney /* a single dblk_t (however layers above the L2 header have no restrctions */ 2281b22a70abSPatrick Mooney /* in ipf). ipf does not currently support filtering on L2 fields (e.g. */ 2282b22a70abSPatrick Mooney /* filtering on a MAC address or ethertype), however virtual machines do */ 2283b22a70abSPatrick Mooney /* not have native IP stack instances where ipf traditionally hooks in. */ 2284b22a70abSPatrick Mooney /* Instead this entry point is used to determine if the packet is unicast, */ 2285b22a70abSPatrick Mooney /* broadcast, or multicast. The IPv4 or IPv6 packet is then passed to the */ 2286b22a70abSPatrick Mooney /* traditional ip hooks for filtering. Non IPv4 or non IPv6 packets are */ 2287b22a70abSPatrick Mooney /* not subject to examination. */ 2288b22a70abSPatrick Mooney /* ------------------------------------------------------------------------ */ 2289b22a70abSPatrick Mooney int ipf_hook_ether(hook_event_token_t token, hook_data_t info, void *arg, 2290b22a70abSPatrick Mooney boolean_t out) 2291b22a70abSPatrick Mooney { 2292b22a70abSPatrick Mooney struct ether_header *ethp; 2293b22a70abSPatrick Mooney hook_pkt_event_t *hpe = (hook_pkt_event_t *)info; 2294b22a70abSPatrick Mooney mblk_t *mp; 2295b22a70abSPatrick Mooney size_t offset, len; 2296b22a70abSPatrick Mooney uint16_t etype; 2297b22a70abSPatrick Mooney boolean_t v6; 2298b22a70abSPatrick Mooney 2299b22a70abSPatrick Mooney /* 2300b22a70abSPatrick Mooney * viona will only pass us mblks with the L2 header contained in a 2301b22a70abSPatrick Mooney * single data block. 2302b22a70abSPatrick Mooney */ 2303b22a70abSPatrick Mooney mp = *hpe->hpe_mp; 2304b22a70abSPatrick Mooney len = MBLKL(mp); 2305b22a70abSPatrick Mooney 2306b22a70abSPatrick Mooney VERIFY3S(len, >=, sizeof (struct ether_header)); 2307b22a70abSPatrick Mooney 2308b22a70abSPatrick Mooney ethp = (struct ether_header *)mp->b_rptr; 2309b22a70abSPatrick Mooney if ((etype = ntohs(ethp->ether_type)) == ETHERTYPE_VLAN) { 2310b22a70abSPatrick Mooney struct ether_vlan_header *evh = 2311b22a70abSPatrick Mooney (struct ether_vlan_header *)ethp; 2312b22a70abSPatrick Mooney 2313b22a70abSPatrick Mooney VERIFY3S(len, >=, sizeof (struct ether_vlan_header)); 2314b22a70abSPatrick Mooney 2315b22a70abSPatrick Mooney etype = ntohs(evh->ether_type); 2316b22a70abSPatrick Mooney offset = sizeof (*evh); 2317b22a70abSPatrick Mooney } else { 2318b22a70abSPatrick Mooney offset = sizeof (*ethp); 2319b22a70abSPatrick Mooney } 2320b22a70abSPatrick Mooney 2321b22a70abSPatrick Mooney /* 2322b22a70abSPatrick Mooney * ipf only support filtering IPv4 and IPv6. Ignore other types. 2323b22a70abSPatrick Mooney */ 2324b22a70abSPatrick Mooney if (etype == ETHERTYPE_IP) 2325b22a70abSPatrick Mooney v6 = B_FALSE; 2326b22a70abSPatrick Mooney else if (etype == ETHERTYPE_IPV6) 2327b22a70abSPatrick Mooney v6 = B_TRUE; 2328b22a70abSPatrick Mooney else 2329b22a70abSPatrick Mooney return (0); 2330b22a70abSPatrick Mooney 2331b22a70abSPatrick Mooney if (bcmp(ipf_eth_bcast_addr, ethp, ETHERADDRL) == 0) 2332b22a70abSPatrick Mooney hpe->hpe_flags |= HPE_BROADCAST; 2333b22a70abSPatrick Mooney else if (bcmp(ipf_eth_ipv4_mcast, ethp, 2334b22a70abSPatrick Mooney sizeof (ipf_eth_ipv4_mcast)) == 0) 2335b22a70abSPatrick Mooney hpe->hpe_flags |= HPE_MULTICAST; 2336b22a70abSPatrick Mooney else if (bcmp(ipf_eth_ipv6_mcast, ethp, 2337b22a70abSPatrick Mooney sizeof (ipf_eth_ipv6_mcast)) == 0) 2338b22a70abSPatrick Mooney hpe->hpe_flags |= HPE_MULTICAST; 2339b22a70abSPatrick Mooney 2340b22a70abSPatrick Mooney /* Find the start of the IPv4 or IPv6 header */ 2341b22a70abSPatrick Mooney for (; offset >= len; len = MBLKL(mp)) { 2342b22a70abSPatrick Mooney offset -= len; 2343b22a70abSPatrick Mooney mp = mp->b_cont; 2344b22a70abSPatrick Mooney if (mp == NULL) { 2345b22a70abSPatrick Mooney freemsg(*hpe->hpe_mp); 2346b22a70abSPatrick Mooney *hpe->hpe_mp = NULL; 2347b22a70abSPatrick Mooney return (-1); 2348b22a70abSPatrick Mooney } 2349b22a70abSPatrick Mooney } 2350b22a70abSPatrick Mooney hpe->hpe_mb = mp; 2351b22a70abSPatrick Mooney hpe->hpe_hdr = mp->b_rptr + offset; 2352b22a70abSPatrick Mooney 2353b22a70abSPatrick Mooney return (v6 ? ipf_hook6(info, out, 0, arg) : 2354b22a70abSPatrick Mooney ipf_hook(info, out, 0, arg)); 2355b22a70abSPatrick Mooney } 2356b22a70abSPatrick Mooney 2357b22a70abSPatrick Mooney /* ------------------------------------------------------------------------ */ 2358b22a70abSPatrick Mooney /* Function: ipf_hookviona_{in,out} */ 2359b22a70abSPatrick Mooney /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 2360b22a70abSPatrick Mooney /* Parameters: event(I) - pointer to event */ 2361b22a70abSPatrick Mooney /* info(I) - pointer to hook information for firewalling */ 2362b22a70abSPatrick Mooney /* */ 2363b22a70abSPatrick Mooney /* The viona hooks are private hooks to illumos. They represents a layer 2 */ 2364b22a70abSPatrick Mooney /* datapath generally used to implement virtual machines. */ 2365b22a70abSPatrick Mooney /* along L2 packets. */ 2366b22a70abSPatrick Mooney /* */ 2367b22a70abSPatrick Mooney /* They end up calling the appropriate traditional ip hooks. */ 2368b22a70abSPatrick Mooney /* ------------------------------------------------------------------------ */ 2369b22a70abSPatrick Mooney int 2370b22a70abSPatrick Mooney ipf_hookviona_in(hook_event_token_t token, hook_data_t info, void *arg) 2371b22a70abSPatrick Mooney { 2372b22a70abSPatrick Mooney return (ipf_hook_ether(token, info, arg, B_FALSE)); 2373b22a70abSPatrick Mooney } 2374b22a70abSPatrick Mooney 2375b22a70abSPatrick Mooney int 2376b22a70abSPatrick Mooney ipf_hookviona_out(hook_event_token_t token, hook_data_t info, void *arg) 2377b22a70abSPatrick Mooney { 2378b22a70abSPatrick Mooney return (ipf_hook_ether(token, info, arg, B_TRUE)); 2379b22a70abSPatrick Mooney } 2380b22a70abSPatrick Mooney 2381381a2a9aSdr /* ------------------------------------------------------------------------ */ 238240cdc2e8SAlexandr Nedvedicky /* Function: ipf_hook4_loop_in */ 2383381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 2384381a2a9aSdr /* Parameters: event(I) - pointer to event */ 2385381a2a9aSdr /* info(I) - pointer to hook information for firewalling */ 2386381a2a9aSdr /* */ 2387381a2a9aSdr /* Calling ipf_hook. */ 2388381a2a9aSdr /* ------------------------------------------------------------------------ */ 2389381a2a9aSdr /*ARGSUSED*/ 239040cdc2e8SAlexandr Nedvedicky int ipf_hook4_loop_in(hook_event_token_t token, hook_data_t info, void *arg) 2391cbded9aeSdr { 23927ddc9b1aSDarren Reed return ipf_hook(info, 0, FI_NOCKSUM, arg); 2393cbded9aeSdr } 2394cbded9aeSdr /*ARGSUSED*/ 23957ddc9b1aSDarren Reed int ipf_hook6_loop_in(hook_event_token_t token, hook_data_t info, void *arg) 2396381a2a9aSdr { 23977ddc9b1aSDarren Reed return ipf_hook6(info, 0, FI_NOCKSUM, arg); 2398381a2a9aSdr } 2399381a2a9aSdr 2400381a2a9aSdr /* ------------------------------------------------------------------------ */ 2401381a2a9aSdr /* Function: ipf_hook */ 2402381a2a9aSdr /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 2403381a2a9aSdr /* Parameters: info(I) - pointer to hook information for firewalling */ 2404381a2a9aSdr /* out(I) - whether packet is going in or out */ 2405381a2a9aSdr /* loopback(I) - whether packet is a loopback packet or not */ 2406381a2a9aSdr /* */ 2407381a2a9aSdr /* Stepping stone function between the IP mainline and IPFilter. Extracts */ 2408381a2a9aSdr /* parameters out of the info structure and forms them up to be useful for */ 2409381a2a9aSdr /* calling ipfilter. */ 2410381a2a9aSdr /* ------------------------------------------------------------------------ */ 24117ddc9b1aSDarren Reed int ipf_hook(hook_data_t info, int out, int loopback, void *arg) 2412381a2a9aSdr { 2413381a2a9aSdr hook_pkt_event_t *fw; 24147ddc9b1aSDarren Reed ipf_stack_t *ifs; 2415381a2a9aSdr qpktinfo_t qpi; 24167ddc9b1aSDarren Reed int rval, hlen; 2417381a2a9aSdr u_short swap; 2418381a2a9aSdr phy_if_t phy; 2419381a2a9aSdr ip_t *ip; 2420381a2a9aSdr 24217ddc9b1aSDarren Reed ifs = arg; 2422381a2a9aSdr fw = (hook_pkt_event_t *)info; 2423381a2a9aSdr 2424381a2a9aSdr ASSERT(fw != NULL); 2425381a2a9aSdr phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp; 2426381a2a9aSdr 2427381a2a9aSdr ip = fw->hpe_hdr; 2428cbded9aeSdr swap = ntohs(ip->ip_len); 2429cbded9aeSdr ip->ip_len = swap; 2430cbded9aeSdr swap = ntohs(ip->ip_off); 2431cbded9aeSdr ip->ip_off = swap; 2432cbded9aeSdr hlen = IPH_HDR_LENGTH(ip); 2433381a2a9aSdr 2434381a2a9aSdr qpi.qpi_m = fw->hpe_mb; 2435381a2a9aSdr qpi.qpi_data = fw->hpe_hdr; 2436381a2a9aSdr qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr; 2437381a2a9aSdr qpi.qpi_ill = (void *)phy; 2438cbded9aeSdr qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST); 2439cbded9aeSdr if (qpi.qpi_flags) 2440cbded9aeSdr qpi.qpi_flags |= FI_MBCAST; 2441cbded9aeSdr qpi.qpi_flags |= loopback; 2442381a2a9aSdr 2443f4b3ec61Sdh rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, 24447ddc9b1aSDarren Reed &qpi, fw->hpe_mp, ifs); 2445381a2a9aSdr 2446381a2a9aSdr /* For fastroute cases, fr_check returns 0 with mp set to NULL */ 2447381a2a9aSdr if (rval == 0 && *(fw->hpe_mp) == NULL) 2448381a2a9aSdr rval = 1; 2449381a2a9aSdr 2450cbded9aeSdr /* Notify IP the packet mblk_t and IP header pointers. */ 2451381a2a9aSdr fw->hpe_mb = qpi.qpi_m; 2452381a2a9aSdr fw->hpe_hdr = qpi.qpi_data; 2453cbded9aeSdr if (rval == 0) { 2454381a2a9aSdr ip = qpi.qpi_data; 2455381a2a9aSdr swap = ntohs(ip->ip_len); 2456381a2a9aSdr ip->ip_len = swap; 2457381a2a9aSdr swap = ntohs(ip->ip_off); 2458381a2a9aSdr ip->ip_off = swap; 2459381a2a9aSdr } 2460381a2a9aSdr return rval; 2461ab25eeb5Syz 2462381a2a9aSdr } 24637ddc9b1aSDarren Reed int ipf_hook6(hook_data_t info, int out, int loopback, void *arg) 2464cbded9aeSdr { 2465cbded9aeSdr hook_pkt_event_t *fw; 2466cbded9aeSdr int rval, hlen; 2467cbded9aeSdr qpktinfo_t qpi; 2468cbded9aeSdr phy_if_t phy; 2469cbded9aeSdr 2470cbded9aeSdr fw = (hook_pkt_event_t *)info; 2471cbded9aeSdr 2472cbded9aeSdr ASSERT(fw != NULL); 2473cbded9aeSdr phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp; 2474cbded9aeSdr 2475cbded9aeSdr hlen = sizeof (ip6_t); 2476cbded9aeSdr 2477cbded9aeSdr qpi.qpi_m = fw->hpe_mb; 2478cbded9aeSdr qpi.qpi_data = fw->hpe_hdr; 2479cbded9aeSdr qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr; 2480cbded9aeSdr qpi.qpi_ill = (void *)phy; 2481cbded9aeSdr qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST); 2482cbded9aeSdr if (qpi.qpi_flags) 2483cbded9aeSdr qpi.qpi_flags |= FI_MBCAST; 2484cbded9aeSdr qpi.qpi_flags |= loopback; 2485cbded9aeSdr 2486cbded9aeSdr rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, 24877ddc9b1aSDarren Reed &qpi, fw->hpe_mp, arg); 2488cbded9aeSdr 2489cbded9aeSdr /* For fastroute cases, fr_check returns 0 with mp set to NULL */ 2490cbded9aeSdr if (rval == 0 && *(fw->hpe_mp) == NULL) 2491cbded9aeSdr rval = 1; 2492cbded9aeSdr 2493cbded9aeSdr /* Notify IP the packet mblk_t and IP header pointers. */ 2494cbded9aeSdr fw->hpe_mb = qpi.qpi_m; 2495cbded9aeSdr fw->hpe_hdr = qpi.qpi_data; 2496cbded9aeSdr return rval; 2497cbded9aeSdr } 2498ab25eeb5Syz 2499ab25eeb5Syz 2500381a2a9aSdr /* ------------------------------------------------------------------------ */ 2501381a2a9aSdr /* Function: ipf_nic_event_v4 */ 2502381a2a9aSdr /* Returns: int - 0 == no problems encountered */ 2503381a2a9aSdr /* Parameters: event(I) - pointer to event */ 2504381a2a9aSdr /* info(I) - pointer to information about a NIC event */ 2505381a2a9aSdr /* */ 2506381a2a9aSdr /* Function to receive asynchronous NIC events from IP */ 2507381a2a9aSdr /* ------------------------------------------------------------------------ */ 2508381a2a9aSdr /*ARGSUSED*/ 25097ddc9b1aSDarren Reed int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info, void *arg) 2510381a2a9aSdr { 2511381a2a9aSdr struct sockaddr_in *sin; 2512381a2a9aSdr hook_nic_event_t *hn; 25137ddc9b1aSDarren Reed ipf_stack_t *ifs = arg; 2514e8d569f4SAlexandr Nedvedicky void *new_ifp = NULL; 2515e8d569f4SAlexandr Nedvedicky 2516e8d569f4SAlexandr Nedvedicky if (ifs->ifs_fr_running <= 0) 2517e8d569f4SAlexandr Nedvedicky return (0); 2518381a2a9aSdr 2519381a2a9aSdr hn = (hook_nic_event_t *)info; 2520381a2a9aSdr 2521381a2a9aSdr switch (hn->hne_event) 2522381a2a9aSdr { 2523381a2a9aSdr case NE_PLUMB : 2524a4cf92b0Sdr frsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, hn->hne_data, 2525d6c23f6fSyx ifs); 2526d6c23f6fSyx fr_natifpsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, 2527f4b3ec61Sdh hn->hne_data, ifs); 2528381a2a9aSdr fr_statesync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, 2529f4b3ec61Sdh hn->hne_data, ifs); 2530381a2a9aSdr break; 2531381a2a9aSdr 2532381a2a9aSdr case NE_UNPLUMB : 2533f4b3ec61Sdh frsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 2534d6c23f6fSyx fr_natifpsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, 2535d6c23f6fSyx ifs); 2536f4b3ec61Sdh fr_statesync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 2537381a2a9aSdr break; 2538381a2a9aSdr 2539381a2a9aSdr case NE_ADDRESS_CHANGE : 2540a4cf92b0Sdr /* 2541a4cf92b0Sdr * We only respond to events for logical interface 0 because 2542a4cf92b0Sdr * IPFilter only uses the first address given to a network 2543a4cf92b0Sdr * interface. We check for hne_lif==1 because the netinfo 2544a4cf92b0Sdr * code maps adds 1 to the lif number so that it can return 2545a4cf92b0Sdr * 0 to indicate "no more lifs" when walking them. 2546a4cf92b0Sdr */ 2547a4cf92b0Sdr if (hn->hne_lif == 1) { 2548a4cf92b0Sdr frsync(IPFSYNC_RESYNC, 4, (void *)hn->hne_nic, NULL, 2549a4cf92b0Sdr ifs); 2550a4cf92b0Sdr sin = hn->hne_data; 2551d6c23f6fSyx fr_nataddrsync(4, (void *)hn->hne_nic, &sin->sin_addr, 2552a4cf92b0Sdr ifs); 2553a4cf92b0Sdr } 2554381a2a9aSdr break; 2555381a2a9aSdr 2556e8d569f4SAlexandr Nedvedicky #if SOLARIS2 >= 10 2557e8d569f4SAlexandr Nedvedicky case NE_IFINDEX_CHANGE : 2558e8d569f4SAlexandr Nedvedicky WRITE_ENTER(&ifs->ifs_ipf_mutex); 2559e8d569f4SAlexandr Nedvedicky 2560e8d569f4SAlexandr Nedvedicky if (hn->hne_data != NULL) { 2561e8d569f4SAlexandr Nedvedicky /* 2562e8d569f4SAlexandr Nedvedicky * The netinfo passes interface index as int (hne_data should be 2563e8d569f4SAlexandr Nedvedicky * handled as a pointer to int), which is always 32bit. We need to 2564e8d569f4SAlexandr Nedvedicky * convert it to void pointer here, since interfaces are 2565e8d569f4SAlexandr Nedvedicky * represented as pointers to void in IPF. The pointers are 64 bits 2566e8d569f4SAlexandr Nedvedicky * long on 64bit platforms. Doing something like 2567e8d569f4SAlexandr Nedvedicky * (void *)((int) x) 2568e8d569f4SAlexandr Nedvedicky * will throw warning: 2569e8d569f4SAlexandr Nedvedicky * "cast to pointer from integer of different size" 2570e8d569f4SAlexandr Nedvedicky * during 64bit compilation. 2571e8d569f4SAlexandr Nedvedicky * 2572e8d569f4SAlexandr Nedvedicky * The line below uses (size_t) to typecast int to 2573e8d569f4SAlexandr Nedvedicky * size_t, which might be 64bit/32bit (depending 2574e8d569f4SAlexandr Nedvedicky * on architecture). Once we have proper 64bit/32bit 2575e8d569f4SAlexandr Nedvedicky * type (size_t), we can safely convert it to void pointer. 2576e8d569f4SAlexandr Nedvedicky */ 2577e8d569f4SAlexandr Nedvedicky new_ifp = (void *)(size_t)*((int *)hn->hne_data); 2578e8d569f4SAlexandr Nedvedicky fr_ifindexsync((void *)hn->hne_nic, new_ifp, ifs); 2579e8d569f4SAlexandr Nedvedicky fr_natifindexsync((void *)hn->hne_nic, new_ifp, ifs); 2580e8d569f4SAlexandr Nedvedicky fr_stateifindexsync((void *)hn->hne_nic, new_ifp, ifs); 2581e8d569f4SAlexandr Nedvedicky } 2582e8d569f4SAlexandr Nedvedicky RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2583e8d569f4SAlexandr Nedvedicky break; 2584e8d569f4SAlexandr Nedvedicky #endif 2585e8d569f4SAlexandr Nedvedicky 2586381a2a9aSdr default : 2587381a2a9aSdr break; 2588ab25eeb5Syz } 2589ab25eeb5Syz 2590381a2a9aSdr return 0; 2591381a2a9aSdr } 2592ab25eeb5Syz 2593381a2a9aSdr 2594381a2a9aSdr /* ------------------------------------------------------------------------ */ 2595381a2a9aSdr /* Function: ipf_nic_event_v6 */ 2596381a2a9aSdr /* Returns: int - 0 == no problems encountered */ 2597381a2a9aSdr /* Parameters: event(I) - pointer to event */ 2598381a2a9aSdr /* info(I) - pointer to information about a NIC event */ 2599381a2a9aSdr /* */ 2600381a2a9aSdr /* Function to receive asynchronous NIC events from IP */ 2601381a2a9aSdr /* ------------------------------------------------------------------------ */ 2602381a2a9aSdr /*ARGSUSED*/ 26037ddc9b1aSDarren Reed int ipf_nic_event_v6(hook_event_token_t event, hook_data_t info, void *arg) 2604381a2a9aSdr { 2605d6c23f6fSyx struct sockaddr_in6 *sin6; 2606381a2a9aSdr hook_nic_event_t *hn; 26077ddc9b1aSDarren Reed ipf_stack_t *ifs = arg; 2608e8d569f4SAlexandr Nedvedicky void *new_ifp = NULL; 2609e8d569f4SAlexandr Nedvedicky 2610e8d569f4SAlexandr Nedvedicky if (ifs->ifs_fr_running <= 0) 2611e8d569f4SAlexandr Nedvedicky return (0); 2612381a2a9aSdr 2613381a2a9aSdr hn = (hook_nic_event_t *)info; 2614381a2a9aSdr 2615381a2a9aSdr switch (hn->hne_event) 2616381a2a9aSdr { 2617381a2a9aSdr case NE_PLUMB : 2618d6c23f6fSyx frsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2619d6c23f6fSyx hn->hne_data, ifs); 2620d6c23f6fSyx fr_natifpsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2621d6c23f6fSyx hn->hne_data, ifs); 2622381a2a9aSdr fr_statesync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2623f4b3ec61Sdh hn->hne_data, ifs); 2624381a2a9aSdr break; 2625381a2a9aSdr 2626381a2a9aSdr case NE_UNPLUMB : 2627f4b3ec61Sdh frsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2628d6c23f6fSyx fr_natifpsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, 2629d6c23f6fSyx ifs); 2630f4b3ec61Sdh fr_statesync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2631381a2a9aSdr break; 2632381a2a9aSdr 2633381a2a9aSdr case NE_ADDRESS_CHANGE : 2634d6c23f6fSyx if (hn->hne_lif == 1) { 2635d6c23f6fSyx sin6 = hn->hne_data; 2636d6c23f6fSyx fr_nataddrsync(6, (void *)hn->hne_nic, &sin6->sin6_addr, 2637d6c23f6fSyx ifs); 2638d6c23f6fSyx } 2639381a2a9aSdr break; 2640e8d569f4SAlexandr Nedvedicky 2641e8d569f4SAlexandr Nedvedicky #if SOLARIS2 >= 10 2642e8d569f4SAlexandr Nedvedicky case NE_IFINDEX_CHANGE : 2643e8d569f4SAlexandr Nedvedicky WRITE_ENTER(&ifs->ifs_ipf_mutex); 2644e8d569f4SAlexandr Nedvedicky if (hn->hne_data != NULL) { 2645e8d569f4SAlexandr Nedvedicky /* 2646e8d569f4SAlexandr Nedvedicky * The netinfo passes interface index as int (hne_data should be 2647e8d569f4SAlexandr Nedvedicky * handled as a pointer to int), which is always 32bit. We need to 2648e8d569f4SAlexandr Nedvedicky * convert it to void pointer here, since interfaces are 2649e8d569f4SAlexandr Nedvedicky * represented as pointers to void in IPF. The pointers are 64 bits 2650e8d569f4SAlexandr Nedvedicky * long on 64bit platforms. Doing something like 2651e8d569f4SAlexandr Nedvedicky * (void *)((int) x) 2652e8d569f4SAlexandr Nedvedicky * will throw warning: 2653e8d569f4SAlexandr Nedvedicky * "cast to pointer from integer of different size" 2654e8d569f4SAlexandr Nedvedicky * during 64bit compilation. 2655e8d569f4SAlexandr Nedvedicky * 2656e8d569f4SAlexandr Nedvedicky * The line below uses (size_t) to typecast int to 2657e8d569f4SAlexandr Nedvedicky * size_t, which might be 64bit/32bit (depending 2658e8d569f4SAlexandr Nedvedicky * on architecture). Once we have proper 64bit/32bit 2659e8d569f4SAlexandr Nedvedicky * type (size_t), we can safely convert it to void pointer. 2660e8d569f4SAlexandr Nedvedicky */ 2661e8d569f4SAlexandr Nedvedicky new_ifp = (void *)(size_t)*((int *)hn->hne_data); 2662e8d569f4SAlexandr Nedvedicky fr_ifindexsync((void *)hn->hne_nic, new_ifp, ifs); 2663e8d569f4SAlexandr Nedvedicky fr_natifindexsync((void *)hn->hne_nic, new_ifp, ifs); 2664e8d569f4SAlexandr Nedvedicky fr_stateifindexsync((void *)hn->hne_nic, new_ifp, ifs); 2665e8d569f4SAlexandr Nedvedicky } 2666e8d569f4SAlexandr Nedvedicky RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2667e8d569f4SAlexandr Nedvedicky break; 2668e8d569f4SAlexandr Nedvedicky #endif 2669e8d569f4SAlexandr Nedvedicky 2670381a2a9aSdr default : 2671381a2a9aSdr break; 2672381a2a9aSdr } 2673381a2a9aSdr 2674381a2a9aSdr return 0; 2675ab25eeb5Syz } 2676a1173273SAlexandr Nedvedicky 2677a1173273SAlexandr Nedvedicky /* 2678a1173273SAlexandr Nedvedicky * Functions fr_make_rst(), fr_make_icmp_v4(), fr_make_icmp_v6() 2679a1173273SAlexandr Nedvedicky * are needed in Solaris kernel only. We don't need them in 2680a1173273SAlexandr Nedvedicky * ipftest to pretend the ICMP/RST packet was sent as a response. 2681a1173273SAlexandr Nedvedicky */ 2682a1173273SAlexandr Nedvedicky #if defined(_KERNEL) && (SOLARIS2 >= 10) 2683a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2684a1173273SAlexandr Nedvedicky /* Function: fr_make_rst */ 2685a1173273SAlexandr Nedvedicky /* Returns: int - 0 on success, -1 on failure */ 2686a1173273SAlexandr Nedvedicky /* Parameters: fin(I) - pointer to packet information */ 2687a1173273SAlexandr Nedvedicky /* */ 2688a1173273SAlexandr Nedvedicky /* We must alter the original mblks passed to IPF from IP stack via */ 2689a1173273SAlexandr Nedvedicky /* FW_HOOKS. FW_HOOKS interface is powerfull, but it has some limitations. */ 2690a1173273SAlexandr Nedvedicky /* IPF can basicaly do only these things with mblk representing the packet: */ 2691a1173273SAlexandr Nedvedicky /* leave it as it is (pass the packet) */ 2692a1173273SAlexandr Nedvedicky /* */ 2693a1173273SAlexandr Nedvedicky /* discard it (block the packet) */ 2694a1173273SAlexandr Nedvedicky /* */ 2695a1173273SAlexandr Nedvedicky /* alter it (i.e. NAT) */ 2696a1173273SAlexandr Nedvedicky /* */ 2697a1173273SAlexandr Nedvedicky /* As you can see IPF can not simply discard the mblk and supply a new one */ 2698a1173273SAlexandr Nedvedicky /* instead to IP stack via FW_HOOKS. */ 2699a1173273SAlexandr Nedvedicky /* */ 2700a1173273SAlexandr Nedvedicky /* The return-rst action for packets coming via NIC is handled as follows: */ 2701a1173273SAlexandr Nedvedicky /* mblk with packet is discarded */ 2702a1173273SAlexandr Nedvedicky /* */ 2703a1173273SAlexandr Nedvedicky /* new mblk with RST response is constructed and injected to network */ 2704a1173273SAlexandr Nedvedicky /* */ 2705a1173273SAlexandr Nedvedicky /* IPF can't inject packets to loopback interface, this is just another */ 2706a1173273SAlexandr Nedvedicky /* limitation we have to deal with here. The only option to send RST */ 2707a1173273SAlexandr Nedvedicky /* response to offending TCP packet coming via loopback is to alter it. */ 2708a1173273SAlexandr Nedvedicky /* */ 2709a1173273SAlexandr Nedvedicky /* The fr_make_rst() function alters TCP SYN/FIN packet intercepted on */ 2710a1173273SAlexandr Nedvedicky /* loopback interface into TCP RST packet. fin->fin_mp is pointer to */ 2711a1173273SAlexandr Nedvedicky /* mblk L3 (IP) and L4 (TCP/UDP) packet headers. */ 2712a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2713a1173273SAlexandr Nedvedicky int fr_make_rst(fin) 2714a1173273SAlexandr Nedvedicky fr_info_t *fin; 2715a1173273SAlexandr Nedvedicky { 2716a1173273SAlexandr Nedvedicky uint16_t tmp_port; 2717a1173273SAlexandr Nedvedicky int rv = -1; 2718a1173273SAlexandr Nedvedicky uint32_t old_ack; 2719a1173273SAlexandr Nedvedicky tcphdr_t *tcp = NULL; 2720a1173273SAlexandr Nedvedicky struct in_addr tmp_src; 2721a1173273SAlexandr Nedvedicky #ifdef USE_INET6 2722a1173273SAlexandr Nedvedicky struct in6_addr tmp_src6; 2723a1173273SAlexandr Nedvedicky #endif 2724b22a70abSPatrick Mooney 2725a1173273SAlexandr Nedvedicky ASSERT(fin->fin_p == IPPROTO_TCP); 2726a1173273SAlexandr Nedvedicky 2727a1173273SAlexandr Nedvedicky /* 2728a1173273SAlexandr Nedvedicky * We do not need to adjust chksum, since it is not being checked by 2729a1173273SAlexandr Nedvedicky * Solaris IP stack for loopback clients. 2730a1173273SAlexandr Nedvedicky */ 2731a1173273SAlexandr Nedvedicky if ((fin->fin_v == 4) && (fin->fin_p == IPPROTO_TCP) && 2732a1173273SAlexandr Nedvedicky ((tcp = (tcphdr_t *) fin->fin_dp) != NULL)) { 2733a1173273SAlexandr Nedvedicky 2734a1173273SAlexandr Nedvedicky if (tcp->th_flags & (TH_SYN | TH_FIN)) { 2735a1173273SAlexandr Nedvedicky /* Swap IPv4 addresses. */ 2736a1173273SAlexandr Nedvedicky tmp_src = fin->fin_ip->ip_src; 2737a1173273SAlexandr Nedvedicky fin->fin_ip->ip_src = fin->fin_ip->ip_dst; 2738a1173273SAlexandr Nedvedicky fin->fin_ip->ip_dst = tmp_src; 2739a1173273SAlexandr Nedvedicky 2740a1173273SAlexandr Nedvedicky rv = 0; 2741a1173273SAlexandr Nedvedicky } 2742a1173273SAlexandr Nedvedicky else 2743a1173273SAlexandr Nedvedicky tcp = NULL; 2744a1173273SAlexandr Nedvedicky } 2745a1173273SAlexandr Nedvedicky #ifdef USE_INET6 2746a1173273SAlexandr Nedvedicky else if ((fin->fin_v == 6) && (fin->fin_p == IPPROTO_TCP) && 2747a1173273SAlexandr Nedvedicky ((tcp = (tcphdr_t *) fin->fin_dp) != NULL)) { 2748a1173273SAlexandr Nedvedicky /* 2749a1173273SAlexandr Nedvedicky * We are relying on fact the next header is TCP, which is true 2750a1173273SAlexandr Nedvedicky * for regular TCP packets coming in over loopback. 2751a1173273SAlexandr Nedvedicky */ 2752a1173273SAlexandr Nedvedicky if (tcp->th_flags & (TH_SYN | TH_FIN)) { 2753a1173273SAlexandr Nedvedicky /* Swap IPv6 addresses. */ 2754a1173273SAlexandr Nedvedicky tmp_src6 = fin->fin_ip6->ip6_src; 2755a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_src = fin->fin_ip6->ip6_dst; 2756a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_dst = tmp_src6; 2757a1173273SAlexandr Nedvedicky 2758a1173273SAlexandr Nedvedicky rv = 0; 2759a1173273SAlexandr Nedvedicky } 2760a1173273SAlexandr Nedvedicky else 2761a1173273SAlexandr Nedvedicky tcp = NULL; 2762a1173273SAlexandr Nedvedicky } 2763a1173273SAlexandr Nedvedicky #endif 2764a1173273SAlexandr Nedvedicky 2765a1173273SAlexandr Nedvedicky if (tcp != NULL) { 2766b22a70abSPatrick Mooney /* 2767a1173273SAlexandr Nedvedicky * Adjust TCP header: 2768a1173273SAlexandr Nedvedicky * swap ports, 2769a1173273SAlexandr Nedvedicky * set flags, 2770a1173273SAlexandr Nedvedicky * set correct ACK number 2771a1173273SAlexandr Nedvedicky */ 2772a1173273SAlexandr Nedvedicky tmp_port = tcp->th_sport; 2773a1173273SAlexandr Nedvedicky tcp->th_sport = tcp->th_dport; 2774a1173273SAlexandr Nedvedicky tcp->th_dport = tmp_port; 2775a1173273SAlexandr Nedvedicky old_ack = tcp->th_ack; 2776a1173273SAlexandr Nedvedicky tcp->th_ack = htonl(ntohl(tcp->th_seq) + 1); 2777a1173273SAlexandr Nedvedicky tcp->th_seq = old_ack; 2778a1173273SAlexandr Nedvedicky tcp->th_flags = TH_RST | TH_ACK; 2779a1173273SAlexandr Nedvedicky } 2780a1173273SAlexandr Nedvedicky 2781a1173273SAlexandr Nedvedicky return (rv); 2782a1173273SAlexandr Nedvedicky } 2783a1173273SAlexandr Nedvedicky 2784a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2785a1173273SAlexandr Nedvedicky /* Function: fr_make_icmp_v4 */ 2786a1173273SAlexandr Nedvedicky /* Returns: int - 0 on success, -1 on failure */ 2787a1173273SAlexandr Nedvedicky /* Parameters: fin(I) - pointer to packet information */ 2788a1173273SAlexandr Nedvedicky /* */ 2789a1173273SAlexandr Nedvedicky /* Please read comment at fr_make_icmp() wrapper function to get an idea */ 2790a1173273SAlexandr Nedvedicky /* what is going to happen here and why. Once you read the comment there, */ 2791a1173273SAlexandr Nedvedicky /* continue here with next paragraph. */ 2792a1173273SAlexandr Nedvedicky /* */ 2793a1173273SAlexandr Nedvedicky /* To turn IPv4 packet into ICMPv4 response packet, these things must */ 2794a1173273SAlexandr Nedvedicky /* happen here: */ 2795a1173273SAlexandr Nedvedicky /* (1) Original mblk is copied (duplicated). */ 2796a1173273SAlexandr Nedvedicky /* */ 2797a1173273SAlexandr Nedvedicky /* (2) ICMP header is created. */ 2798a1173273SAlexandr Nedvedicky /* */ 2799a1173273SAlexandr Nedvedicky /* (3) Link ICMP header with copy of original mblk, we have ICMPv4 */ 2800a1173273SAlexandr Nedvedicky /* data ready then. */ 2801a1173273SAlexandr Nedvedicky /* */ 2802a1173273SAlexandr Nedvedicky /* (4) Swap IP addresses in original mblk and adjust IP header data. */ 2803a1173273SAlexandr Nedvedicky /* */ 2804a1173273SAlexandr Nedvedicky /* (5) The mblk containing original packet is trimmed to contain IP */ 2805a1173273SAlexandr Nedvedicky /* header only and ICMP chksum is computed. */ 2806a1173273SAlexandr Nedvedicky /* */ 2807a1173273SAlexandr Nedvedicky /* (6) The ICMP header we have from (3) is linked to original mblk, */ 2808a1173273SAlexandr Nedvedicky /* which now contains new IP header. If original packet was spread */ 2809a1173273SAlexandr Nedvedicky /* over several mblks, only the first mblk is kept. */ 2810a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2811a1173273SAlexandr Nedvedicky static int fr_make_icmp_v4(fin) 2812a1173273SAlexandr Nedvedicky fr_info_t *fin; 2813a1173273SAlexandr Nedvedicky { 2814a1173273SAlexandr Nedvedicky struct in_addr tmp_src; 28156ccacea7SAlexandr Nedvedicky tcphdr_t *tcp; 2816a1173273SAlexandr Nedvedicky struct icmp *icmp; 2817a1173273SAlexandr Nedvedicky mblk_t *mblk_icmp; 2818a1173273SAlexandr Nedvedicky mblk_t *mblk_ip; 2819a1173273SAlexandr Nedvedicky size_t icmp_pld_len; /* octets to append to ICMP header */ 2820a1173273SAlexandr Nedvedicky size_t orig_iphdr_len; /* length of IP header only */ 2821a1173273SAlexandr Nedvedicky uint32_t sum; 2822a1173273SAlexandr Nedvedicky uint16_t *buf; 2823a1173273SAlexandr Nedvedicky int len; 2824a1173273SAlexandr Nedvedicky 2825a1173273SAlexandr Nedvedicky 2826a1173273SAlexandr Nedvedicky if (fin->fin_v != 4) 2827a1173273SAlexandr Nedvedicky return (-1); 2828a1173273SAlexandr Nedvedicky 2829a1173273SAlexandr Nedvedicky /* 2830a1173273SAlexandr Nedvedicky * If we are dealing with TCP, then packet must be SYN/FIN to be routed 2831a1173273SAlexandr Nedvedicky * by IP stack. If it is not SYN/FIN, then we must drop it silently. 2832a1173273SAlexandr Nedvedicky */ 28336ccacea7SAlexandr Nedvedicky tcp = (tcphdr_t *) fin->fin_dp; 28346ccacea7SAlexandr Nedvedicky 2835a1173273SAlexandr Nedvedicky if ((fin->fin_p == IPPROTO_TCP) && 28366ccacea7SAlexandr Nedvedicky ((tcp == NULL) || ((tcp->th_flags & (TH_SYN | TH_FIN)) == 0))) 2837a1173273SAlexandr Nedvedicky return (-1); 2838a1173273SAlexandr Nedvedicky 2839a1173273SAlexandr Nedvedicky /* 2840a1173273SAlexandr Nedvedicky * Step (1) 2841a1173273SAlexandr Nedvedicky * 2842a1173273SAlexandr Nedvedicky * Make copy of original mblk. 2843a1173273SAlexandr Nedvedicky * 2844a1173273SAlexandr Nedvedicky * We want to copy as much data as necessary, not less, not more. The 2845a1173273SAlexandr Nedvedicky * ICMPv4 payload length for unreachable messages is: 2846a1173273SAlexandr Nedvedicky * original IP header + 8 bytes of L4 (if there are any). 2847a1173273SAlexandr Nedvedicky * 2848a1173273SAlexandr Nedvedicky * We determine if there are at least 8 bytes of L4 data following IP 2849a1173273SAlexandr Nedvedicky * header first. 2850a1173273SAlexandr Nedvedicky */ 2851a1173273SAlexandr Nedvedicky icmp_pld_len = (fin->fin_dlen > ICMPERR_ICMPHLEN) ? 2852a1173273SAlexandr Nedvedicky ICMPERR_ICMPHLEN : fin->fin_dlen; 2853a1173273SAlexandr Nedvedicky /* 2854a1173273SAlexandr Nedvedicky * Since we don't want to copy more data than necessary, we must trim 2855a1173273SAlexandr Nedvedicky * the original mblk here. The right way (STREAMish) would be to use 2856a1173273SAlexandr Nedvedicky * adjmsg() to trim it. However we would have to calculate the length 2857a1173273SAlexandr Nedvedicky * argument for adjmsg() from pointers we already have here. 2858a1173273SAlexandr Nedvedicky * 2859a1173273SAlexandr Nedvedicky * Since we have pointers and offsets, it's faster and easier for 2860a1173273SAlexandr Nedvedicky * us to just adjust pointers by hand instead of using adjmsg(). 2861a1173273SAlexandr Nedvedicky */ 2862a1173273SAlexandr Nedvedicky fin->fin_m->b_wptr = (unsigned char *) fin->fin_dp; 2863a1173273SAlexandr Nedvedicky fin->fin_m->b_wptr += icmp_pld_len; 2864a1173273SAlexandr Nedvedicky icmp_pld_len = fin->fin_m->b_wptr - (unsigned char *) fin->fin_ip; 2865a1173273SAlexandr Nedvedicky 2866a1173273SAlexandr Nedvedicky /* 2867a1173273SAlexandr Nedvedicky * Also we don't want to copy any L2 stuff, which might precede IP 2868a1173273SAlexandr Nedvedicky * header, so we have have to set b_rptr to point to the start of IP 2869a1173273SAlexandr Nedvedicky * header. 2870a1173273SAlexandr Nedvedicky */ 2871a1173273SAlexandr Nedvedicky fin->fin_m->b_rptr += fin->fin_ipoff; 2872a1173273SAlexandr Nedvedicky if ((mblk_ip = copyb(fin->fin_m)) == NULL) 2873a1173273SAlexandr Nedvedicky return (-1); 2874a1173273SAlexandr Nedvedicky fin->fin_m->b_rptr -= fin->fin_ipoff; 2875a1173273SAlexandr Nedvedicky 2876a1173273SAlexandr Nedvedicky /* 2877a1173273SAlexandr Nedvedicky * Step (2) 2878a1173273SAlexandr Nedvedicky * 2879a1173273SAlexandr Nedvedicky * Create an ICMP header, which will be appened to original mblk later. 2880a1173273SAlexandr Nedvedicky * ICMP header is just another mblk. 2881a1173273SAlexandr Nedvedicky */ 2882a1173273SAlexandr Nedvedicky mblk_icmp = (mblk_t *) allocb(ICMPERR_ICMPHLEN, BPRI_HI); 2883a1173273SAlexandr Nedvedicky if (mblk_icmp == NULL) { 2884a1173273SAlexandr Nedvedicky FREE_MB_T(mblk_ip); 2885a1173273SAlexandr Nedvedicky return (-1); 2886a1173273SAlexandr Nedvedicky } 2887a1173273SAlexandr Nedvedicky 2888a1173273SAlexandr Nedvedicky MTYPE(mblk_icmp) = M_DATA; 2889a1173273SAlexandr Nedvedicky icmp = (struct icmp *) mblk_icmp->b_wptr; 2890a1173273SAlexandr Nedvedicky icmp->icmp_type = ICMP_UNREACH; 2891a1173273SAlexandr Nedvedicky icmp->icmp_code = fin->fin_icode & 0xFF; 2892a1173273SAlexandr Nedvedicky icmp->icmp_void = 0; 2893a1173273SAlexandr Nedvedicky icmp->icmp_cksum = 0; 2894a1173273SAlexandr Nedvedicky mblk_icmp->b_wptr += ICMPERR_ICMPHLEN; 2895a1173273SAlexandr Nedvedicky 2896a1173273SAlexandr Nedvedicky /* 2897a1173273SAlexandr Nedvedicky * Step (3) 2898a1173273SAlexandr Nedvedicky * 2899a1173273SAlexandr Nedvedicky * Complete ICMP packet - link ICMP header with L4 data from original 2900a1173273SAlexandr Nedvedicky * IP packet. 2901a1173273SAlexandr Nedvedicky */ 2902a1173273SAlexandr Nedvedicky linkb(mblk_icmp, mblk_ip); 2903a1173273SAlexandr Nedvedicky 2904a1173273SAlexandr Nedvedicky /* 2905a1173273SAlexandr Nedvedicky * Step (4) 2906a1173273SAlexandr Nedvedicky * 2907a1173273SAlexandr Nedvedicky * Swap IP addresses and change IP header fields accordingly in 2908a1173273SAlexandr Nedvedicky * original IP packet. 2909a1173273SAlexandr Nedvedicky * 2910a1173273SAlexandr Nedvedicky * There is a rule option return-icmp as a dest for physical 2911a1173273SAlexandr Nedvedicky * interfaces. This option becomes useless for loopback, since IPF box 2912a1173273SAlexandr Nedvedicky * uses same address as a loopback destination. We ignore the option 2913a1173273SAlexandr Nedvedicky * here, the ICMP packet will always look like as it would have been 2914a1173273SAlexandr Nedvedicky * sent from the original destination host. 2915a1173273SAlexandr Nedvedicky */ 2916a1173273SAlexandr Nedvedicky tmp_src = fin->fin_ip->ip_src; 2917a1173273SAlexandr Nedvedicky fin->fin_ip->ip_src = fin->fin_ip->ip_dst; 2918a1173273SAlexandr Nedvedicky fin->fin_ip->ip_dst = tmp_src; 2919a1173273SAlexandr Nedvedicky fin->fin_ip->ip_p = IPPROTO_ICMP; 2920a1173273SAlexandr Nedvedicky fin->fin_ip->ip_sum = 0; 2921a1173273SAlexandr Nedvedicky 2922a1173273SAlexandr Nedvedicky /* 2923a1173273SAlexandr Nedvedicky * Step (5) 2924a1173273SAlexandr Nedvedicky * 2925a1173273SAlexandr Nedvedicky * We trim the orignal mblk to hold IP header only. 2926a1173273SAlexandr Nedvedicky */ 2927a1173273SAlexandr Nedvedicky fin->fin_m->b_wptr = fin->fin_dp; 2928a1173273SAlexandr Nedvedicky orig_iphdr_len = fin->fin_m->b_wptr - 2929a1173273SAlexandr Nedvedicky (fin->fin_m->b_rptr + fin->fin_ipoff); 2930a1173273SAlexandr Nedvedicky fin->fin_ip->ip_len = htons(icmp_pld_len + ICMPERR_ICMPHLEN + 2931a1173273SAlexandr Nedvedicky orig_iphdr_len); 2932a1173273SAlexandr Nedvedicky 2933a1173273SAlexandr Nedvedicky /* 2934a1173273SAlexandr Nedvedicky * ICMP chksum calculation. The data we are calculating chksum for are 2935a1173273SAlexandr Nedvedicky * spread over two mblks, therefore we have to use two for loops. 2936a1173273SAlexandr Nedvedicky * 2937a1173273SAlexandr Nedvedicky * First for loop computes chksum part for ICMP header. 2938a1173273SAlexandr Nedvedicky */ 2939a1173273SAlexandr Nedvedicky buf = (uint16_t *) icmp; 2940a1173273SAlexandr Nedvedicky len = ICMPERR_ICMPHLEN; 2941a1173273SAlexandr Nedvedicky for (sum = 0; len > 1; len -= 2) 2942a1173273SAlexandr Nedvedicky sum += *buf++; 2943a1173273SAlexandr Nedvedicky 2944a1173273SAlexandr Nedvedicky /* 2945a1173273SAlexandr Nedvedicky * Here we add chksum part for ICMP payload. 2946a1173273SAlexandr Nedvedicky */ 2947a1173273SAlexandr Nedvedicky len = icmp_pld_len; 2948a1173273SAlexandr Nedvedicky buf = (uint16_t *) mblk_ip->b_rptr; 2949a1173273SAlexandr Nedvedicky for (; len > 1; len -= 2) 2950a1173273SAlexandr Nedvedicky sum += *buf++; 2951a1173273SAlexandr Nedvedicky 2952a1173273SAlexandr Nedvedicky /* 2953a1173273SAlexandr Nedvedicky * Chksum is done. 2954a1173273SAlexandr Nedvedicky */ 2955a1173273SAlexandr Nedvedicky sum = (sum >> 16) + (sum & 0xffff); 2956a1173273SAlexandr Nedvedicky sum += (sum >> 16); 2957a1173273SAlexandr Nedvedicky icmp->icmp_cksum = ~sum; 2958a1173273SAlexandr Nedvedicky 2959a1173273SAlexandr Nedvedicky /* 2960a1173273SAlexandr Nedvedicky * Step (6) 2961a1173273SAlexandr Nedvedicky * 2962a1173273SAlexandr Nedvedicky * Release all packet mblks, except the first one. 2963a1173273SAlexandr Nedvedicky */ 2964a1173273SAlexandr Nedvedicky if (fin->fin_m->b_cont != NULL) { 2965a1173273SAlexandr Nedvedicky FREE_MB_T(fin->fin_m->b_cont); 2966a1173273SAlexandr Nedvedicky } 2967a1173273SAlexandr Nedvedicky 2968a1173273SAlexandr Nedvedicky /* 2969a1173273SAlexandr Nedvedicky * Append ICMP payload to first mblk, which already contains new IP 2970a1173273SAlexandr Nedvedicky * header. 2971a1173273SAlexandr Nedvedicky */ 2972a1173273SAlexandr Nedvedicky linkb(fin->fin_m, mblk_icmp); 2973a1173273SAlexandr Nedvedicky 2974a1173273SAlexandr Nedvedicky return (0); 2975a1173273SAlexandr Nedvedicky } 2976a1173273SAlexandr Nedvedicky 2977a1173273SAlexandr Nedvedicky #ifdef USE_INET6 2978a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 2979a1173273SAlexandr Nedvedicky /* Function: fr_make_icmp_v6 */ 2980a1173273SAlexandr Nedvedicky /* Returns: int - 0 on success, -1 on failure */ 2981a1173273SAlexandr Nedvedicky /* Parameters: fin(I) - pointer to packet information */ 2982a1173273SAlexandr Nedvedicky /* */ 2983a1173273SAlexandr Nedvedicky /* Please read comment at fr_make_icmp() wrapper function to get an idea */ 2984a1173273SAlexandr Nedvedicky /* what and why is going to happen here. Once you read the comment there, */ 2985a1173273SAlexandr Nedvedicky /* continue here with next paragraph. */ 2986a1173273SAlexandr Nedvedicky /* */ 2987a1173273SAlexandr Nedvedicky /* This function turns IPv6 packet (UDP, TCP, ...) into ICMPv6 response. */ 2988a1173273SAlexandr Nedvedicky /* The algorithm is fairly simple: */ 2989a1173273SAlexandr Nedvedicky /* 1) We need to get copy of complete mblk. */ 2990a1173273SAlexandr Nedvedicky /* */ 2991a1173273SAlexandr Nedvedicky /* 2) New ICMPv6 header is created. */ 2992a1173273SAlexandr Nedvedicky /* */ 2993a1173273SAlexandr Nedvedicky /* 3) The copy of original mblk with packet is linked to ICMPv6 */ 2994a1173273SAlexandr Nedvedicky /* header. */ 2995a1173273SAlexandr Nedvedicky /* */ 2996a1173273SAlexandr Nedvedicky /* 4) The checksum must be adjusted. */ 2997a1173273SAlexandr Nedvedicky /* */ 2998a1173273SAlexandr Nedvedicky /* 5) IP addresses in original mblk are swapped and IP header data */ 2999a1173273SAlexandr Nedvedicky /* are adjusted (protocol number). */ 3000a1173273SAlexandr Nedvedicky /* */ 3001a1173273SAlexandr Nedvedicky /* 6) Original mblk is trimmed to hold IPv6 header only, then it is */ 3002a1173273SAlexandr Nedvedicky /* linked with the ICMPv6 data we got from (3). */ 3003a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 3004a1173273SAlexandr Nedvedicky static int fr_make_icmp_v6(fin) 3005a1173273SAlexandr Nedvedicky fr_info_t *fin; 3006a1173273SAlexandr Nedvedicky { 3007a1173273SAlexandr Nedvedicky struct icmp6_hdr *icmp6; 30086ccacea7SAlexandr Nedvedicky tcphdr_t *tcp; 3009a1173273SAlexandr Nedvedicky struct in6_addr tmp_src6; 3010a1173273SAlexandr Nedvedicky size_t icmp_pld_len; 3011a1173273SAlexandr Nedvedicky mblk_t *mblk_ip, *mblk_icmp; 3012a1173273SAlexandr Nedvedicky 3013a1173273SAlexandr Nedvedicky if (fin->fin_v != 6) 3014a1173273SAlexandr Nedvedicky return (-1); 3015a1173273SAlexandr Nedvedicky 3016a1173273SAlexandr Nedvedicky /* 3017a1173273SAlexandr Nedvedicky * If we are dealing with TCP, then packet must SYN/FIN to be routed by 3018a1173273SAlexandr Nedvedicky * IP stack. If it is not SYN/FIN, then we must drop it silently. 3019a1173273SAlexandr Nedvedicky */ 30206ccacea7SAlexandr Nedvedicky tcp = (tcphdr_t *) fin->fin_dp; 30216ccacea7SAlexandr Nedvedicky 30226ccacea7SAlexandr Nedvedicky if ((fin->fin_p == IPPROTO_TCP) && 30236ccacea7SAlexandr Nedvedicky ((tcp == NULL) || ((tcp->th_flags & (TH_SYN | TH_FIN)) == 0))) 3024a1173273SAlexandr Nedvedicky return (-1); 3025a1173273SAlexandr Nedvedicky 3026a1173273SAlexandr Nedvedicky /* 3027a1173273SAlexandr Nedvedicky * Step (1) 3028a1173273SAlexandr Nedvedicky * 3029a1173273SAlexandr Nedvedicky * We need to copy complete packet in case of IPv6, no trimming is 3030a1173273SAlexandr Nedvedicky * needed (except the L2 headers). 3031a1173273SAlexandr Nedvedicky */ 3032a1173273SAlexandr Nedvedicky icmp_pld_len = M_LEN(fin->fin_m); 3033a1173273SAlexandr Nedvedicky fin->fin_m->b_rptr += fin->fin_ipoff; 3034a1173273SAlexandr Nedvedicky if ((mblk_ip = copyb(fin->fin_m)) == NULL) 3035a1173273SAlexandr Nedvedicky return (-1); 3036a1173273SAlexandr Nedvedicky fin->fin_m->b_rptr -= fin->fin_ipoff; 3037a1173273SAlexandr Nedvedicky 3038a1173273SAlexandr Nedvedicky /* 3039a1173273SAlexandr Nedvedicky * Step (2) 3040a1173273SAlexandr Nedvedicky * 3041a1173273SAlexandr Nedvedicky * Allocate and create ICMP header. 3042a1173273SAlexandr Nedvedicky */ 3043a1173273SAlexandr Nedvedicky mblk_icmp = (mblk_t *) allocb(sizeof (struct icmp6_hdr), 3044a1173273SAlexandr Nedvedicky BPRI_HI); 3045a1173273SAlexandr Nedvedicky 3046a1173273SAlexandr Nedvedicky if (mblk_icmp == NULL) 3047a1173273SAlexandr Nedvedicky return (-1); 3048a1173273SAlexandr Nedvedicky 3049a1173273SAlexandr Nedvedicky MTYPE(mblk_icmp) = M_DATA; 3050a1173273SAlexandr Nedvedicky icmp6 = (struct icmp6_hdr *) mblk_icmp->b_wptr; 3051a1173273SAlexandr Nedvedicky icmp6->icmp6_type = ICMP6_DST_UNREACH; 3052a1173273SAlexandr Nedvedicky icmp6->icmp6_code = fin->fin_icode & 0xFF; 3053a1173273SAlexandr Nedvedicky icmp6->icmp6_data32[0] = 0; 3054a1173273SAlexandr Nedvedicky mblk_icmp->b_wptr += sizeof (struct icmp6_hdr); 3055a1173273SAlexandr Nedvedicky 3056a1173273SAlexandr Nedvedicky /* 3057a1173273SAlexandr Nedvedicky * Step (3) 3058a1173273SAlexandr Nedvedicky * 3059a1173273SAlexandr Nedvedicky * Link the copy of IP packet to ICMP header. 3060a1173273SAlexandr Nedvedicky */ 3061a1173273SAlexandr Nedvedicky linkb(mblk_icmp, mblk_ip); 3062a1173273SAlexandr Nedvedicky 3063a1173273SAlexandr Nedvedicky /* 3064a1173273SAlexandr Nedvedicky * Step (4) 3065a1173273SAlexandr Nedvedicky * 3066a1173273SAlexandr Nedvedicky * Calculate chksum - this is much more easier task than in case of 3067a1173273SAlexandr Nedvedicky * IPv4 - ICMPv6 chksum only covers IP addresses, and payload length. 3068a1173273SAlexandr Nedvedicky * We are making compensation just for change of packet length. 3069a1173273SAlexandr Nedvedicky */ 3070a1173273SAlexandr Nedvedicky icmp6->icmp6_cksum = icmp_pld_len + sizeof (struct icmp6_hdr); 3071a1173273SAlexandr Nedvedicky 3072a1173273SAlexandr Nedvedicky /* 3073a1173273SAlexandr Nedvedicky * Step (5) 3074a1173273SAlexandr Nedvedicky * 3075a1173273SAlexandr Nedvedicky * Swap IP addresses. 3076a1173273SAlexandr Nedvedicky */ 3077a1173273SAlexandr Nedvedicky tmp_src6 = fin->fin_ip6->ip6_src; 3078a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_src = fin->fin_ip6->ip6_dst; 3079a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_dst = tmp_src6; 3080a1173273SAlexandr Nedvedicky 3081a1173273SAlexandr Nedvedicky /* 3082a1173273SAlexandr Nedvedicky * and adjust IP header data. 3083a1173273SAlexandr Nedvedicky */ 3084a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_nxt = IPPROTO_ICMPV6; 3085a1173273SAlexandr Nedvedicky fin->fin_ip6->ip6_plen = htons(icmp_pld_len + sizeof (struct icmp6_hdr)); 3086a1173273SAlexandr Nedvedicky 3087a1173273SAlexandr Nedvedicky /* 3088a1173273SAlexandr Nedvedicky * Step (6) 3089a1173273SAlexandr Nedvedicky * 3090a1173273SAlexandr Nedvedicky * We must release all linked mblks from original packet and keep only 3091a1173273SAlexandr Nedvedicky * the first mblk with IP header to link ICMP data. 3092a1173273SAlexandr Nedvedicky */ 3093a1173273SAlexandr Nedvedicky fin->fin_m->b_wptr = (unsigned char *) fin->fin_ip6 + sizeof (ip6_t); 3094a1173273SAlexandr Nedvedicky 3095a1173273SAlexandr Nedvedicky if (fin->fin_m->b_cont != NULL) { 3096a1173273SAlexandr Nedvedicky FREE_MB_T(fin->fin_m->b_cont); 3097a1173273SAlexandr Nedvedicky } 3098a1173273SAlexandr Nedvedicky 3099a1173273SAlexandr Nedvedicky /* 3100a1173273SAlexandr Nedvedicky * Append ICMP payload to IP header. 3101a1173273SAlexandr Nedvedicky */ 3102a1173273SAlexandr Nedvedicky linkb(fin->fin_m, mblk_icmp); 3103a1173273SAlexandr Nedvedicky 3104a1173273SAlexandr Nedvedicky return (0); 3105a1173273SAlexandr Nedvedicky } 3106a1173273SAlexandr Nedvedicky #endif /* USE_INET6 */ 3107a1173273SAlexandr Nedvedicky 3108a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 3109a1173273SAlexandr Nedvedicky /* Function: fr_make_icmp */ 3110a1173273SAlexandr Nedvedicky /* Returns: int - 0 on success, -1 on failure */ 3111a1173273SAlexandr Nedvedicky /* Parameters: fin(I) - pointer to packet information */ 3112a1173273SAlexandr Nedvedicky /* */ 3113a1173273SAlexandr Nedvedicky /* We must alter the original mblks passed to IPF from IP stack via */ 3114a1173273SAlexandr Nedvedicky /* FW_HOOKS. The reasons why we must alter packet are discussed within */ 3115a1173273SAlexandr Nedvedicky /* comment at fr_make_rst() function. */ 3116a1173273SAlexandr Nedvedicky /* */ 3117a1173273SAlexandr Nedvedicky /* The fr_make_icmp() function acts as a wrapper, which passes the code */ 3118a1173273SAlexandr Nedvedicky /* execution to fr_make_icmp_v4() or fr_make_icmp_v6() depending on */ 3119a1173273SAlexandr Nedvedicky /* protocol version. However there are some details, which are common to */ 3120a1173273SAlexandr Nedvedicky /* both IP versions. The details are going to be explained here. */ 3121a1173273SAlexandr Nedvedicky /* */ 3122a1173273SAlexandr Nedvedicky /* The packet looks as follows: */ 3123a1173273SAlexandr Nedvedicky /* xxx | IP hdr | IP payload ... | */ 3124a1173273SAlexandr Nedvedicky /* ^ ^ ^ ^ */ 3125a1173273SAlexandr Nedvedicky /* | | | | */ 3126a1173273SAlexandr Nedvedicky /* | | | fin_m->b_wptr = fin->fin_dp + fin->fin_dlen */ 3127a1173273SAlexandr Nedvedicky /* | | | */ 3128a1173273SAlexandr Nedvedicky /* | | `- fin_m->fin_dp (in case of IPv4 points to L4 header) */ 3129a1173273SAlexandr Nedvedicky /* | | */ 3130a1173273SAlexandr Nedvedicky /* | `- fin_m->b_rptr + fin_ipoff (fin_ipoff is most likely 0 in case */ 3131a1173273SAlexandr Nedvedicky /* | of loopback) */ 3132a1173273SAlexandr Nedvedicky /* | */ 3133a1173273SAlexandr Nedvedicky /* `- fin_m->b_rptr - points to L2 header in case of physical NIC */ 3134a1173273SAlexandr Nedvedicky /* */ 3135a1173273SAlexandr Nedvedicky /* All relevant IP headers are pulled up into the first mblk. It happened */ 3136a1173273SAlexandr Nedvedicky /* well in advance before the matching rule was found (the rule, which took */ 3137a1173273SAlexandr Nedvedicky /* us here, to fr_make_icmp() function). */ 3138a1173273SAlexandr Nedvedicky /* */ 3139a1173273SAlexandr Nedvedicky /* Both functions will turn packet passed in fin->fin_m mblk into a new */ 3140a1173273SAlexandr Nedvedicky /* packet. New packet will be represented as chain of mblks. */ 3141a1173273SAlexandr Nedvedicky /* orig mblk |- b_cont ---. */ 3142a1173273SAlexandr Nedvedicky /* ^ `-> ICMP hdr |- b_cont--. */ 3143a1173273SAlexandr Nedvedicky /* | ^ `-> duped orig mblk */ 3144a1173273SAlexandr Nedvedicky /* | | ^ */ 3145a1173273SAlexandr Nedvedicky /* `- The original mblk | | */ 3146a1173273SAlexandr Nedvedicky /* will be trimmed to | | */ 3147a1173273SAlexandr Nedvedicky /* to contain IP header | | */ 3148a1173273SAlexandr Nedvedicky /* only | | */ 3149a1173273SAlexandr Nedvedicky /* | | */ 3150a1173273SAlexandr Nedvedicky /* `- This is newly | */ 3151a1173273SAlexandr Nedvedicky /* allocated mblk to | */ 3152a1173273SAlexandr Nedvedicky /* hold ICMPv6 data. | */ 3153a1173273SAlexandr Nedvedicky /* | */ 3154a1173273SAlexandr Nedvedicky /* | */ 3155a1173273SAlexandr Nedvedicky /* | */ 3156a1173273SAlexandr Nedvedicky /* This is the copy of original mblk, it will contain -' */ 3157a1173273SAlexandr Nedvedicky /* orignal IP packet in case of ICMPv6. In case of */ 3158a1173273SAlexandr Nedvedicky /* ICMPv4 it will contain up to 8 bytes of IP payload */ 3159a1173273SAlexandr Nedvedicky /* (TCP/UDP/L4) data from original packet. */ 3160a1173273SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 3161a1173273SAlexandr Nedvedicky int fr_make_icmp(fin) 3162a1173273SAlexandr Nedvedicky fr_info_t *fin; 3163a1173273SAlexandr Nedvedicky { 3164a1173273SAlexandr Nedvedicky int rv; 3165a1173273SAlexandr Nedvedicky 3166a1173273SAlexandr Nedvedicky if (fin->fin_v == 4) 3167a1173273SAlexandr Nedvedicky rv = fr_make_icmp_v4(fin); 3168a1173273SAlexandr Nedvedicky #ifdef USE_INET6 3169a1173273SAlexandr Nedvedicky else if (fin->fin_v == 6) 3170a1173273SAlexandr Nedvedicky rv = fr_make_icmp_v6(fin); 3171a1173273SAlexandr Nedvedicky #endif 3172a1173273SAlexandr Nedvedicky else 3173a1173273SAlexandr Nedvedicky rv = -1; 3174a1173273SAlexandr Nedvedicky 3175a1173273SAlexandr Nedvedicky return (rv); 3176a1173273SAlexandr Nedvedicky } 3177d0dd088cSAlexandr Nedvedicky 3178d0dd088cSAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 3179d0dd088cSAlexandr Nedvedicky /* Function: fr_buf_sum */ 3180d0dd088cSAlexandr Nedvedicky /* Returns: unsigned int - sum of buffer buf */ 3181d0dd088cSAlexandr Nedvedicky /* Parameters: buf - pointer to buf we want to sum up */ 3182d0dd088cSAlexandr Nedvedicky /* len - length of buffer buf */ 3183d0dd088cSAlexandr Nedvedicky /* */ 3184d0dd088cSAlexandr Nedvedicky /* Sums buffer buf. The result is used for chksum calculation. The buf */ 3185d0dd088cSAlexandr Nedvedicky /* argument must be aligned. */ 3186d0dd088cSAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 3187d0dd088cSAlexandr Nedvedicky static uint32_t fr_buf_sum(buf, len) 3188d0dd088cSAlexandr Nedvedicky const void *buf; 3189d0dd088cSAlexandr Nedvedicky unsigned int len; 3190d0dd088cSAlexandr Nedvedicky { 3191d0dd088cSAlexandr Nedvedicky uint32_t sum = 0; 3192d0dd088cSAlexandr Nedvedicky uint16_t *b = (uint16_t *)buf; 3193d0dd088cSAlexandr Nedvedicky 3194d0dd088cSAlexandr Nedvedicky while (len > 1) { 3195d0dd088cSAlexandr Nedvedicky sum += *b++; 3196d0dd088cSAlexandr Nedvedicky len -= 2; 3197d0dd088cSAlexandr Nedvedicky } 3198d0dd088cSAlexandr Nedvedicky 3199d0dd088cSAlexandr Nedvedicky if (len == 1) 3200d0dd088cSAlexandr Nedvedicky sum += htons((*(unsigned char *)b) << 8); 3201d0dd088cSAlexandr Nedvedicky 3202d0dd088cSAlexandr Nedvedicky return (sum); 3203d0dd088cSAlexandr Nedvedicky } 3204d0dd088cSAlexandr Nedvedicky 3205d0dd088cSAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 3206d0dd088cSAlexandr Nedvedicky /* Function: fr_calc_chksum */ 3207d0dd088cSAlexandr Nedvedicky /* Returns: void */ 3208d0dd088cSAlexandr Nedvedicky /* Parameters: fin - pointer to fr_info_t instance with packet data */ 3209d0dd088cSAlexandr Nedvedicky /* pkt - pointer to duplicated packet */ 3210d0dd088cSAlexandr Nedvedicky /* */ 3211d0dd088cSAlexandr Nedvedicky /* Calculates all chksums (L3, L4) for packet pkt. Works for both IP */ 3212d0dd088cSAlexandr Nedvedicky /* versions. */ 3213d0dd088cSAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 3214d0dd088cSAlexandr Nedvedicky void fr_calc_chksum(fin, pkt) 3215d0dd088cSAlexandr Nedvedicky fr_info_t *fin; 3216d0dd088cSAlexandr Nedvedicky mb_t *pkt; 3217d0dd088cSAlexandr Nedvedicky { 3218d0dd088cSAlexandr Nedvedicky struct pseudo_hdr { 3219d0dd088cSAlexandr Nedvedicky union { 3220d0dd088cSAlexandr Nedvedicky struct in_addr in4; 3221d0dd088cSAlexandr Nedvedicky #ifdef USE_INET6 3222d0dd088cSAlexandr Nedvedicky struct in6_addr in6; 3223d0dd088cSAlexandr Nedvedicky #endif 3224d0dd088cSAlexandr Nedvedicky } src_addr; 3225d0dd088cSAlexandr Nedvedicky union { 3226d0dd088cSAlexandr Nedvedicky struct in_addr in4; 3227d0dd088cSAlexandr Nedvedicky #ifdef USE_INET6 3228d0dd088cSAlexandr Nedvedicky struct in6_addr in6; 3229d0dd088cSAlexandr Nedvedicky #endif 3230d0dd088cSAlexandr Nedvedicky } dst_addr; 3231d0dd088cSAlexandr Nedvedicky char zero; 3232d0dd088cSAlexandr Nedvedicky char proto; 3233d0dd088cSAlexandr Nedvedicky uint16_t len; 3234d0dd088cSAlexandr Nedvedicky } phdr; 3235d0dd088cSAlexandr Nedvedicky uint32_t sum, ip_sum; 3236d0dd088cSAlexandr Nedvedicky void *buf; 3237d0dd088cSAlexandr Nedvedicky uint16_t *l4_csum_p; 3238d0dd088cSAlexandr Nedvedicky tcphdr_t *tcp; 3239d0dd088cSAlexandr Nedvedicky udphdr_t *udp; 3240d0dd088cSAlexandr Nedvedicky icmphdr_t *icmp; 3241d0dd088cSAlexandr Nedvedicky #ifdef USE_INET6 3242d0dd088cSAlexandr Nedvedicky struct icmp6_hdr *icmp6; 3243d0dd088cSAlexandr Nedvedicky #endif 3244d0dd088cSAlexandr Nedvedicky ip_t *ip; 3245d0dd088cSAlexandr Nedvedicky unsigned int len; 3246d0dd088cSAlexandr Nedvedicky int pld_len; 3247d0dd088cSAlexandr Nedvedicky 3248d0dd088cSAlexandr Nedvedicky /* 3249d0dd088cSAlexandr Nedvedicky * We need to pullup the packet to the single continuous buffer to avoid 3250d0dd088cSAlexandr Nedvedicky * potential misaligment of b_rptr member in mblk chain. 3251d0dd088cSAlexandr Nedvedicky */ 3252d0dd088cSAlexandr Nedvedicky if (pullupmsg(pkt, -1) == 0) { 3253d0dd088cSAlexandr Nedvedicky cmn_err(CE_WARN, "Failed to pullup loopback pkt -> chksum" 3254d0dd088cSAlexandr Nedvedicky " will not be computed by IPF"); 3255d0dd088cSAlexandr Nedvedicky return; 3256d0dd088cSAlexandr Nedvedicky } 3257d0dd088cSAlexandr Nedvedicky 3258d0dd088cSAlexandr Nedvedicky /* 3259d0dd088cSAlexandr Nedvedicky * It is guaranteed IP header starts right at b_rptr, because we are 3260d0dd088cSAlexandr Nedvedicky * working with a copy of the original packet. 3261d0dd088cSAlexandr Nedvedicky * 3262d0dd088cSAlexandr Nedvedicky * Compute pseudo header chksum for TCP and UDP. 3263d0dd088cSAlexandr Nedvedicky */ 3264d0dd088cSAlexandr Nedvedicky if ((fin->fin_p == IPPROTO_UDP) || 3265d0dd088cSAlexandr Nedvedicky (fin->fin_p == IPPROTO_TCP)) { 3266d0dd088cSAlexandr Nedvedicky bzero(&phdr, sizeof (phdr)); 3267d0dd088cSAlexandr Nedvedicky #ifdef USE_INET6 3268d0dd088cSAlexandr Nedvedicky if (fin->fin_v == 6) { 3269d0dd088cSAlexandr Nedvedicky phdr.src_addr.in6 = fin->fin_srcip6; 3270d0dd088cSAlexandr Nedvedicky phdr.dst_addr.in6 = fin->fin_dstip6; 3271d0dd088cSAlexandr Nedvedicky } else { 3272d0dd088cSAlexandr Nedvedicky phdr.src_addr.in4 = fin->fin_src; 3273d0dd088cSAlexandr Nedvedicky phdr.dst_addr.in4 = fin->fin_dst; 3274d0dd088cSAlexandr Nedvedicky } 3275d0dd088cSAlexandr Nedvedicky #else 3276d0dd088cSAlexandr Nedvedicky phdr.src_addr.in4 = fin->fin_src; 3277d0dd088cSAlexandr Nedvedicky phdr.dst_addr.in4 = fin->fin_dst; 3278d0dd088cSAlexandr Nedvedicky #endif 3279d0dd088cSAlexandr Nedvedicky phdr.zero = (char) 0; 3280d0dd088cSAlexandr Nedvedicky phdr.proto = fin->fin_p; 3281d0dd088cSAlexandr Nedvedicky phdr.len = htons((uint16_t)fin->fin_dlen); 3282d0dd088cSAlexandr Nedvedicky sum = fr_buf_sum(&phdr, (unsigned int)sizeof (phdr)); 3283d0dd088cSAlexandr Nedvedicky } else { 3284d0dd088cSAlexandr Nedvedicky sum = 0; 3285d0dd088cSAlexandr Nedvedicky } 3286d0dd088cSAlexandr Nedvedicky 3287d0dd088cSAlexandr Nedvedicky /* 3288d0dd088cSAlexandr Nedvedicky * Set pointer to the L4 chksum field in the packet, set buf pointer to 3289d0dd088cSAlexandr Nedvedicky * the L4 header start. 3290d0dd088cSAlexandr Nedvedicky */ 3291d0dd088cSAlexandr Nedvedicky switch (fin->fin_p) { 3292d0dd088cSAlexandr Nedvedicky case IPPROTO_UDP: 3293d0dd088cSAlexandr Nedvedicky udp = (udphdr_t *)(pkt->b_rptr + fin->fin_hlen); 3294d0dd088cSAlexandr Nedvedicky l4_csum_p = &udp->uh_sum; 3295d0dd088cSAlexandr Nedvedicky buf = udp; 3296d0dd088cSAlexandr Nedvedicky break; 3297d0dd088cSAlexandr Nedvedicky case IPPROTO_TCP: 3298d0dd088cSAlexandr Nedvedicky tcp = (tcphdr_t *)(pkt->b_rptr + fin->fin_hlen); 3299d0dd088cSAlexandr Nedvedicky l4_csum_p = &tcp->th_sum; 3300d0dd088cSAlexandr Nedvedicky buf = tcp; 3301d0dd088cSAlexandr Nedvedicky break; 3302d0dd088cSAlexandr Nedvedicky case IPPROTO_ICMP: 3303d0dd088cSAlexandr Nedvedicky icmp = (icmphdr_t *)(pkt->b_rptr + fin->fin_hlen); 3304d0dd088cSAlexandr Nedvedicky l4_csum_p = &icmp->icmp_cksum; 3305d0dd088cSAlexandr Nedvedicky buf = icmp; 3306d0dd088cSAlexandr Nedvedicky break; 3307d0dd088cSAlexandr Nedvedicky #ifdef USE_INET6 3308d0dd088cSAlexandr Nedvedicky case IPPROTO_ICMPV6: 3309d0dd088cSAlexandr Nedvedicky icmp6 = (struct icmp6_hdr *)(pkt->b_rptr + fin->fin_hlen); 3310d0dd088cSAlexandr Nedvedicky l4_csum_p = &icmp6->icmp6_cksum; 3311d0dd088cSAlexandr Nedvedicky buf = icmp6; 3312d0dd088cSAlexandr Nedvedicky break; 3313d0dd088cSAlexandr Nedvedicky #endif 3314d0dd088cSAlexandr Nedvedicky default: 3315d0dd088cSAlexandr Nedvedicky l4_csum_p = NULL; 3316d0dd088cSAlexandr Nedvedicky } 3317d0dd088cSAlexandr Nedvedicky 3318d0dd088cSAlexandr Nedvedicky /* 3319d0dd088cSAlexandr Nedvedicky * Compute L4 chksum if needed. 3320d0dd088cSAlexandr Nedvedicky */ 3321d0dd088cSAlexandr Nedvedicky if (l4_csum_p != NULL) { 3322d0dd088cSAlexandr Nedvedicky *l4_csum_p = (uint16_t)0; 3323d0dd088cSAlexandr Nedvedicky pld_len = fin->fin_dlen; 3324d0dd088cSAlexandr Nedvedicky len = pkt->b_wptr - (unsigned char *)buf; 3325d0dd088cSAlexandr Nedvedicky ASSERT(len == pld_len); 3326d0dd088cSAlexandr Nedvedicky /* 3327d0dd088cSAlexandr Nedvedicky * Add payload sum to pseudoheader sum. 3328d0dd088cSAlexandr Nedvedicky */ 3329d0dd088cSAlexandr Nedvedicky sum += fr_buf_sum(buf, len); 3330d0dd088cSAlexandr Nedvedicky while (sum >> 16) 3331d0dd088cSAlexandr Nedvedicky sum = (sum & 0xFFFF) + (sum >> 16); 3332d0dd088cSAlexandr Nedvedicky 3333d0dd088cSAlexandr Nedvedicky *l4_csum_p = ~((uint16_t)sum); 3334d0dd088cSAlexandr Nedvedicky DTRACE_PROBE1(l4_sum, uint16_t, *l4_csum_p); 3335d0dd088cSAlexandr Nedvedicky } 3336d0dd088cSAlexandr Nedvedicky 3337d0dd088cSAlexandr Nedvedicky /* 3338d0dd088cSAlexandr Nedvedicky * The IP header chksum is needed just for IPv4. 3339d0dd088cSAlexandr Nedvedicky */ 3340d0dd088cSAlexandr Nedvedicky if (fin->fin_v == 4) { 3341d0dd088cSAlexandr Nedvedicky /* 3342d0dd088cSAlexandr Nedvedicky * Compute IPv4 header chksum. 3343d0dd088cSAlexandr Nedvedicky */ 3344d0dd088cSAlexandr Nedvedicky ip = (ip_t *)pkt->b_rptr; 3345d0dd088cSAlexandr Nedvedicky ip->ip_sum = (uint16_t)0; 3346d0dd088cSAlexandr Nedvedicky ip_sum = fr_buf_sum(ip, (unsigned int)fin->fin_hlen); 3347d0dd088cSAlexandr Nedvedicky while (ip_sum >> 16) 3348d0dd088cSAlexandr Nedvedicky ip_sum = (ip_sum & 0xFFFF) + (ip_sum >> 16); 3349d0dd088cSAlexandr Nedvedicky 3350d0dd088cSAlexandr Nedvedicky ip->ip_sum = ~((uint16_t)ip_sum); 3351d0dd088cSAlexandr Nedvedicky DTRACE_PROBE1(l3_sum, uint16_t, ip->ip_sum); 3352d0dd088cSAlexandr Nedvedicky } 3353d0dd088cSAlexandr Nedvedicky 3354d0dd088cSAlexandr Nedvedicky return; 3355d0dd088cSAlexandr Nedvedicky } 3356d0dd088cSAlexandr Nedvedicky 3357a1173273SAlexandr Nedvedicky #endif /* _KERNEL && SOLARIS2 >= 10 */ 3358