ip_fil_solaris.c revision 7704:c2487b19c177
1139749Simp/* 2119853Scg * Copyright (C) 1993-2001, 2003 by Darren Reed. 3166426Sjoel * 458756Scg * See the IPFILTER.LICENCE file for details on licencing. 558756Scg * 658756Scg * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 758756Scg * Use is subject to license terms. 858756Scg */ 958756Scg 1058756Scg#if !defined(lint) 1158756Scgstatic const char sccsid[] = "@(#)ip_fil_solaris.c 1.7 07/22/06 (C) 1993-2000 Darren Reed"; 1258756Scgstatic const char rcsid[] = "@(#)$Id: ip_fil_solaris.c,v 2.62.2.19 2005/07/13 21:40:46 darrenr Exp $"; 1358756Scg#endif 1458756Scg 1558756Scg#include <sys/types.h> 1658756Scg#include <sys/errno.h> 1758756Scg#include <sys/param.h> 1858756Scg#include <sys/cpuvar.h> 1958756Scg#include <sys/open.h> 2058756Scg#include <sys/ioctl.h> 2158756Scg#include <sys/filio.h> 2258756Scg#include <sys/systm.h> 2358756Scg#include <sys/strsubr.h> 2458756Scg#include <sys/cred.h> 2558756Scg#include <sys/cred_impl.h> 2658756Scg#include <sys/ddi.h> 2758756Scg#include <sys/sunddi.h> 2858756Scg#include <sys/ksynch.h> 2958756Scg#include <sys/kmem.h> 3058756Scg#include <sys/mkdev.h> 3158756Scg#include <sys/protosw.h> 3258756Scg#include <sys/socket.h> 3358756Scg#include <sys/dditypes.h> 3458756Scg#include <sys/cmn_err.h> 3558756Scg#include <sys/zone.h> 3658756Scg#include <net/if.h> 37110499Snyan#include <net/af.h> 38110499Snyan#include <net/route.h> 3970134Scg#include <netinet/in.h> 4070134Scg#include <netinet/in_systm.h> 4182180Scg#include <netinet/ip.h> 4282180Scg#include <netinet/ip_var.h> 4359323Scg#include <netinet/tcp.h> 4458756Scg#include <netinet/udp.h> 4558756Scg#include <netinet/tcpip.h> 4658756Scg#include <netinet/ip_icmp.h> 4758756Scg#include "netinet/ip_compat.h" 4858756Scg#ifdef USE_INET6 4958756Scg# include <netinet/icmp6.h> 5058756Scg#endif 5158756Scg#include "netinet/ip_fil.h" 5264881Scg#include "netinet/ip_nat.h" 5364881Scg#include "netinet/ip_frag.h" 5464881Scg#include "netinet/ip_state.h" 5564881Scg#include "netinet/ip_auth.h" 5664881Scg#include "netinet/ip_proxy.h" 5764881Scg#include "netinet/ipf_stack.h" 5864881Scg#ifdef IPFILTER_LOOKUP 5964881Scg# include "netinet/ip_lookup.h" 6064881Scg#endif 6164881Scg#include <inet/ip_ire.h> 6258756Scg 6358756Scg#include <sys/md5.h> 64154438Sariff#include <sys/neti.h> 6564881Scg 6664881Scgstatic int frzerostats __P((caddr_t, ipf_stack_t *)); 6764881Scgstatic int fr_setipfloopback __P((int, ipf_stack_t *)); 6864881Scgstatic int fr_enableipf __P((ipf_stack_t *, int)); 6964881Scgstatic int fr_send_ip __P((fr_info_t *fin, mblk_t *m, mblk_t **mp)); 7064881Scgstatic int ipf_nic_event_v4 __P((hook_event_token_t, hook_data_t, void *)); 7164881Scgstatic int ipf_nic_event_v6 __P((hook_event_token_t, hook_data_t, void *)); 7264881Scgstatic int ipf_hook __P((hook_data_t, int, int, void *)); 7364881Scgstatic int ipf_hook4_in __P((hook_event_token_t, hook_data_t, void *)); 7464881Scgstatic int ipf_hook4_out __P((hook_event_token_t, hook_data_t, void *)); 7564881Scgstatic int ipf_hook4_loop_out __P((hook_event_token_t, hook_data_t, 7658756Scg void *)); 7758756Scgstatic int ipf_hook4_loop_in __P((hook_event_token_t, hook_data_t, void *)); 78154438Sariffstatic int ipf_hook4 __P((hook_data_t, int, int, void *)); 7964881Scgstatic int ipf_hook6_out __P((hook_event_token_t, hook_data_t, void *)); 8058756Scgstatic int ipf_hook6_in __P((hook_event_token_t, hook_data_t, void *)); 8158756Scgstatic int ipf_hook6_loop_out __P((hook_event_token_t, hook_data_t, 8258756Scg void *)); 8358756Scgstatic int ipf_hook6_loop_in __P((hook_event_token_t, hook_data_t, 8474763Scg void *)); 8574763Scgstatic int ipf_hook6 __P((hook_data_t, int, int, void *)); 8670134Scgextern int ipf_geniter __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *)); 8770291Scgextern int ipf_frruleiter __P((void *, int, void *, ipf_stack_t *)); 8858756Scg 8958756Scg#if SOLARIS2 < 10 9058756Scg#if SOLARIS2 >= 7 9174763Scgu_int *ip_ttl_ptr = NULL; 9258756Scgu_int *ip_mtudisc = NULL; 9358756Scg# if SOLARIS2 >= 8 9458756Scgint *ip_forwarding = NULL; 9558756Scgu_int *ip6_forwarding = NULL; 9665644Scg# else 9758756Scgu_int *ip_forwarding = NULL; 9858756Scg# endif 9984111Scg#else 100170032Sariffu_long *ip_ttl_ptr = NULL; 101170032Sariffu_long *ip_mtudisc = NULL; 10258756Scgu_long *ip_forwarding = NULL; 10358756Scg#endif 10458756Scg#endif 10558756Scg 10684111Scg 10758756Scg/* ------------------------------------------------------------------------ */ 10858756Scg/* Function: ipldetach */ 10958756Scg/* Returns: int - 0 == success, else error. */ 11058756Scg/* Parameters: Nil */ 11158756Scg/* */ 11258756Scg/* This function is responsible for undoing anything that might have been */ 11358756Scg/* done in a call to iplattach(). It must be able to clean up from a call */ 11458756Scg/* to iplattach() that did not succeed. Why might that happen? Someone */ 11558756Scg/* configures a table to be so large that we cannot allocate enough memory */ 11658756Scg/* for it. */ 11758756Scg/* ------------------------------------------------------------------------ */ 11858756Scgint ipldetach(ifs) 11958756Scgipf_stack_t *ifs; 12058756Scg{ 12158756Scg 12258756Scg ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0); 12358756Scg 12484111Scg#if SOLARIS2 < 10 12558756Scg 12658756Scg if (ifs->ifs_fr_control_forwarding & 2) { 12758756Scg if (ip_forwarding != NULL) 12858756Scg *ip_forwarding = 0; 12958756Scg#if SOLARIS2 >= 8 13058756Scg if (ip6_forwarding != NULL) 13158756Scg *ip6_forwarding = 0; 13258756Scg#endif 13358756Scg } 13458756Scg#endif 13558756Scg 13658756Scg /* 13758756Scg * This lock needs to be dropped around the net_hook_unregister calls 13874763Scg * because we can deadlock here with: 13974763Scg * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs 14074763Scg * R(hook_family)->R(hei_lock)->R(ipf_global) (active hook running) 14174763Scg */ 14274763Scg RWLOCK_EXIT(&ifs->ifs_ipf_global); 14374763Scg 14474763Scg#define UNDO_HOOK(_f, _b, _e, _h) \ 14574763Scg do { \ 14674763Scg if (ifs->_f != NULL) { \ 14774763Scg if (ifs->_b) { \ 14874763Scg ifs->_b = (net_hook_unregister(ifs->_f, \ 14974763Scg _e, ifs->_h) != 0); \ 15058756Scg if (!ifs->_b) { \ 15158756Scg hook_free(ifs->_h); \ 15258756Scg ifs->_h = NULL; \ 15358756Scg } \ 15458756Scg } else if (ifs->_h != NULL) { \ 15558756Scg hook_free(ifs->_h); \ 15658756Scg ifs->_h = NULL; \ 15758756Scg } \ 15858756Scg } \ 15958756Scg _NOTE(CONSTCOND) \ 16058756Scg } while (0) 161108064Ssemenu 162108064Ssemenu /* 163108064Ssemenu * Remove IPv6 Hooks 16458756Scg */ 16558756Scg if (ifs->ifs_ipf_ipv6 != NULL) { 16658756Scg UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_in, 16758756Scg NH_PHYSICAL_IN, ifs_ipfhook6_in); 16858756Scg UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_out, 16958756Scg NH_PHYSICAL_OUT, ifs_ipfhook6_out); 17058756Scg UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_nic_events, 17158756Scg NH_NIC_EVENTS, ifs_ipfhook6_nicevents); 17258756Scg UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_in, 17358756Scg NH_LOOPBACK_IN, ifs_ipfhook6_loop_in); 17458756Scg UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_out, 17558756Scg NH_LOOPBACK_OUT, ifs_ipfhook6_loop_out); 17658756Scg 17758756Scg if (net_protocol_release(ifs->ifs_ipf_ipv6) != 0) 17858756Scg goto detach_failed; 17958756Scg ifs->ifs_ipf_ipv6 = NULL; 18058756Scg } 18158756Scg 18258756Scg /* 18358756Scg * Remove IPv4 Hooks 18458756Scg */ 18558756Scg if (ifs->ifs_ipf_ipv4 != NULL) { 18658756Scg UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_in, 18758756Scg NH_PHYSICAL_IN, ifs_ipfhook4_in); 18858756Scg UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_out, 18958756Scg NH_PHYSICAL_OUT, ifs_ipfhook4_out); 19058756Scg UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_nic_events, 19158756Scg NH_NIC_EVENTS, ifs_ipfhook4_nicevents); 19258756Scg UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_in, 19358756Scg NH_LOOPBACK_IN, ifs_ipfhook4_loop_in); 19458756Scg UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_out, 19558756Scg NH_LOOPBACK_OUT, ifs_ipfhook4_loop_out); 19658756Scg 19758756Scg if (net_protocol_release(ifs->ifs_ipf_ipv4) != 0) 19858756Scg goto detach_failed; 19958756Scg ifs->ifs_ipf_ipv4 = NULL; 20058756Scg } 20158756Scg 20258756Scg#undef UNDO_HOOK 20358756Scg 20458756Scg#ifdef IPFDEBUG 20558756Scg cmn_err(CE_CONT, "ipldetach()\n"); 20658756Scg#endif 20758756Scg 20858756Scg WRITE_ENTER(&ifs->ifs_ipf_global); 20958756Scg fr_deinitialise(ifs); 21058756Scg 21158756Scg (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE, ifs); 21258756Scg (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE, ifs); 21358756Scg 21458756Scg if (ifs->ifs_ipf_locks_done == 1) { 21558756Scg MUTEX_DESTROY(&ifs->ifs_ipf_timeoutlock); 21658756Scg MUTEX_DESTROY(&ifs->ifs_ipf_rw); 21758756Scg RW_DESTROY(&ifs->ifs_ipf_tokens); 21858756Scg RW_DESTROY(&ifs->ifs_ipf_ipidfrag); 21958756Scg ifs->ifs_ipf_locks_done = 0; 22058756Scg } 22158756Scg 22258756Scg if (ifs->ifs_hook4_physical_in || ifs->ifs_hook4_physical_out || 22358756Scg ifs->ifs_hook4_nic_events || ifs->ifs_hook4_loopback_in || 22458756Scg ifs->ifs_hook4_loopback_out || ifs->ifs_hook6_nic_events || 22558756Scg ifs->ifs_hook6_physical_in || ifs->ifs_hook6_physical_out || 22658756Scg ifs->ifs_hook6_loopback_in || ifs->ifs_hook6_loopback_out) 22758756Scg return -1; 22858756Scg 22958756Scg return 0; 23058756Scg 23158756Scgdetach_failed: 23258756Scg WRITE_ENTER(&ifs->ifs_ipf_global); 23358756Scg return -1; 23458756Scg} 23558756Scg 23658756Scgint iplattach(ifs) 23758756Scgipf_stack_t *ifs; 23858756Scg{ 23958756Scg#if SOLARIS2 < 10 24058756Scg int i; 24158756Scg#endif 24258756Scg netid_t id = ifs->ifs_netid; 24358756Scg 24458756Scg#ifdef IPFDEBUG 24558756Scg cmn_err(CE_CONT, "iplattach()\n"); 24658756Scg#endif 24758756Scg 24858756Scg ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0); 24958756Scg ifs->ifs_fr_flags = IPF_LOGGING; 25058756Scg#ifdef _KERNEL 25158756Scg ifs->ifs_fr_update_ipid = 0; 25258756Scg#else 25358756Scg ifs->ifs_fr_update_ipid = 1; 25458756Scg#endif 25558756Scg ifs->ifs_fr_minttl = 4; 25658756Scg ifs->ifs_fr_icmpminfragmtu = 68; 25758756Scg#if defined(IPFILTER_DEFAULT_BLOCK) 25858756Scg ifs->ifs_fr_pass = FR_BLOCK|FR_NOMATCH; 25958756Scg#else 26058756Scg ifs->ifs_fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH; 26158756Scg#endif 26258756Scg 26358756Scg MUTEX_INIT(&ifs->ifs_ipf_rw, "ipf rw mutex"); 26458756Scg MUTEX_INIT(&ifs->ifs_ipf_timeoutlock, "ipf timeout lock mutex"); 26558756Scg RWLOCK_INIT(&ifs->ifs_ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); 26658756Scg RWLOCK_INIT(&ifs->ifs_ipf_tokens, "ipf token rwlock"); 26758756Scg ifs->ifs_ipf_locks_done = 1; 26858756Scg 26958756Scg if (fr_initialise(ifs) < 0) 27058756Scg return -1; 27158756Scg 27258756Scg HOOK_INIT(ifs->ifs_ipfhook4_nicevents, ipf_nic_event_v4, 27358756Scg "ipfilter_hook4_nicevents", ifs); 27458756Scg HOOK_INIT(ifs->ifs_ipfhook4_in, ipf_hook4_in, 27558756Scg "ipfilter_hook4_in", ifs); 27689774Sscottl HOOK_INIT(ifs->ifs_ipfhook4_out, ipf_hook4_out, 27758756Scg "ipfilter_hook4_out", ifs); 27858756Scg HOOK_INIT(ifs->ifs_ipfhook4_loop_in, ipf_hook4_loop_in, 27958756Scg "ipfilter_hook4_loop_in", ifs); 28058756Scg HOOK_INIT(ifs->ifs_ipfhook4_loop_out, ipf_hook4_loop_out, 28158756Scg "ipfilter_hook4_loop_out", ifs); 28258756Scg 28358756Scg /* 28458756Scg * If we hold this lock over all of the net_hook_register calls, we 28558756Scg * can cause a deadlock to occur with the following lock ordering: 28658756Scg * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs 28765644Scg * R(hook_family)->R(hei_lock)->R(ipf_global) (packet path) 28865644Scg */ 28958756Scg RWLOCK_EXIT(&ifs->ifs_ipf_global); 29058756Scg 29158756Scg /* 29258756Scg * Add IPv4 hooks 29384111Scg */ 29458756Scg ifs->ifs_ipf_ipv4 = net_protocol_lookup(id, NHF_INET); 29558756Scg if (ifs->ifs_ipf_ipv4 == NULL) 29658756Scg goto hookup_failed; 29758756Scg 29884111Scg ifs->ifs_hook4_nic_events = (net_hook_register(ifs->ifs_ipf_ipv4, 29958756Scg NH_NIC_EVENTS, ifs->ifs_ipfhook4_nicevents) == 0); 30058756Scg if (!ifs->ifs_hook4_nic_events) 30158756Scg goto hookup_failed; 30258756Scg 30358756Scg ifs->ifs_hook4_physical_in = (net_hook_register(ifs->ifs_ipf_ipv4, 30458756Scg NH_PHYSICAL_IN, ifs->ifs_ipfhook4_in) == 0); 30558756Scg if (!ifs->ifs_hook4_physical_in) 30665644Scg goto hookup_failed; 30765644Scg 30865644Scg ifs->ifs_hook4_physical_out = (net_hook_register(ifs->ifs_ipf_ipv4, 30965644Scg NH_PHYSICAL_OUT, ifs->ifs_ipfhook4_out) == 0); 31065644Scg if (!ifs->ifs_hook4_physical_out) 31158756Scg goto hookup_failed; 31258756Scg 31358756Scg if (ifs->ifs_ipf_loopback) { 31458756Scg ifs->ifs_hook4_loopback_in = (net_hook_register( 31558756Scg ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN, 31658756Scg ifs->ifs_ipfhook4_loop_in) == 0); 31758756Scg if (!ifs->ifs_hook4_loopback_in) 31858756Scg goto hookup_failed; 31958756Scg 320127135Snjl ifs->ifs_hook4_loopback_out = (net_hook_register( 321127135Snjl ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT, 32258756Scg ifs->ifs_ipfhook4_loop_out) == 0); 32358756Scg if (!ifs->ifs_hook4_loopback_out) 324127135Snjl goto hookup_failed; 325127135Snjl } 32658756Scg /* 32758756Scg * Add IPv6 hooks 328127135Snjl */ 329127135Snjl ifs->ifs_ipf_ipv6 = net_protocol_lookup(id, NHF_INET6); 33058756Scg if (ifs->ifs_ipf_ipv6 == NULL) 33158756Scg goto hookup_failed; 332127135Snjl 333127135Snjl HOOK_INIT(ifs->ifs_ipfhook6_nicevents, ipf_nic_event_v6, 33458756Scg "ipfilter_hook6_nicevents", ifs); 33558756Scg HOOK_INIT(ifs->ifs_ipfhook6_in, ipf_hook6_in, 33658756Scg "ipfilter_hook6_in", ifs); 33784111Scg HOOK_INIT(ifs->ifs_ipfhook6_out, ipf_hook6_out, 33858756Scg "ipfilter_hook6_out", ifs); 33958756Scg HOOK_INIT(ifs->ifs_ipfhook6_loop_in, ipf_hook6_loop_in, 34058756Scg "ipfilter_hook6_loop_in", ifs); 34184111Scg HOOK_INIT(ifs->ifs_ipfhook6_loop_out, ipf_hook6_loop_out, 34258756Scg "ipfilter_hook6_loop_out", ifs); 34358756Scg 34458756Scg ifs->ifs_hook6_nic_events = (net_hook_register(ifs->ifs_ipf_ipv6, 34558756Scg NH_NIC_EVENTS, ifs->ifs_ipfhook6_nicevents) == 0); 34658756Scg if (!ifs->ifs_hook6_nic_events) 34758756Scg goto hookup_failed; 34858756Scg 34958756Scg ifs->ifs_hook6_physical_in = (net_hook_register(ifs->ifs_ipf_ipv6, 35058756Scg NH_PHYSICAL_IN, ifs->ifs_ipfhook6_in) == 0); 35158756Scg if (!ifs->ifs_hook6_physical_in) 35258756Scg goto hookup_failed; 35358756Scg 35474763Scg ifs->ifs_hook6_physical_out = (net_hook_register(ifs->ifs_ipf_ipv6, 35558756Scg NH_PHYSICAL_OUT, ifs->ifs_ipfhook6_out) == 0); 35658756Scg if (!ifs->ifs_hook6_physical_out) 35758756Scg goto hookup_failed; 35858756Scg 35958756Scg if (ifs->ifs_ipf_loopback) { 36058756Scg ifs->ifs_hook6_loopback_in = (net_hook_register( 36158756Scg ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN, 36258756Scg ifs->ifs_ipfhook6_loop_in) == 0); 36358756Scg if (!ifs->ifs_hook6_loopback_in) 36458756Scg goto hookup_failed; 365148598Snetchild 366148598Snetchild ifs->ifs_hook6_loopback_out = (net_hook_register( 36770392Scg ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT, 368148598Snetchild ifs->ifs_ipfhook6_loop_out) == 0); 369148598Snetchild if (!ifs->ifs_hook6_loopback_out) 37058756Scg goto hookup_failed; 37170134Scg } 372110499Snyan 37358756Scg /* 37458756Scg * Reacquire ipf_global, now it is safe. 37558756Scg */ 37658756Scg WRITE_ENTER(&ifs->ifs_ipf_global); 37758756Scg 37858756Scg/* Do not use private interface ip_params_arr[] in Solaris 10 */ 37958756Scg#if SOLARIS2 < 10 38058756Scg 38158756Scg#if SOLARIS2 >= 8 382148598Snetchild ip_forwarding = &ip_g_forward; 383148598Snetchild#endif 38470392Scg /* 385148598Snetchild * XXX - There is no terminator for this array, so it is not possible 386148598Snetchild * to tell if what we are looking for is missing and go off the end 38758756Scg * of the array. 38870134Scg */ 389110499Snyan 39058756Scg#if SOLARIS2 <= 8 39158756Scg for (i = 0; ; i++) { 39258756Scg if (!strcmp(ip_param_arr[i].ip_param_name, "ip_def_ttl")) { 39358756Scg ip_ttl_ptr = &ip_param_arr[i].ip_param_value; 39458756Scg } else if (!strcmp(ip_param_arr[i].ip_param_name, 39558756Scg "ip_path_mtu_discovery")) { 39658756Scg ip_mtudisc = &ip_param_arr[i].ip_param_value; 39758756Scg } 39858756Scg#if SOLARIS2 < 8 39958756Scg else if (!strcmp(ip_param_arr[i].ip_param_name, 40074763Scg "ip_forwarding")) { 40158756Scg ip_forwarding = &ip_param_arr[i].ip_param_value; 40258756Scg } 40358756Scg#else 40458756Scg else if (!strcmp(ip_param_arr[i].ip_param_name, 40558756Scg "ip6_forwarding")) { 40658756Scg ip6_forwarding = &ip_param_arr[i].ip_param_value; 40758756Scg } 40858756Scg#endif 40958756Scg 41058756Scg if (ip_mtudisc != NULL && ip_ttl_ptr != NULL && 41158756Scg#if SOLARIS2 >= 8 41258756Scg ip6_forwarding != NULL && 41358756Scg#endif 41458756Scg ip_forwarding != NULL) 41558756Scg break; 41658756Scg } 41758756Scg#endif 41858756Scg 41958756Scg if (ifs->ifs_fr_control_forwarding & 1) { 42058756Scg if (ip_forwarding != NULL) 42158756Scg *ip_forwarding = 1; 42258756Scg#if SOLARIS2 >= 8 42358756Scg if (ip6_forwarding != NULL) 42458756Scg *ip6_forwarding = 1; 42558756Scg#endif 42658756Scg } 42758756Scg 42858756Scg#endif 42958756Scg 43058756Scg return 0; 43158756Scghookup_failed: 43260571Scg WRITE_ENTER(&ifs->ifs_ipf_global); 43360571Scg return -1; 43458756Scg} 43560571Scg 43660571Scgstatic int fr_setipfloopback(set, ifs) 43760571Scgint set; 43858756Scgipf_stack_t *ifs; 43958756Scg{ 44058756Scg if (ifs->ifs_ipf_ipv4 == NULL || ifs->ifs_ipf_ipv6 == NULL) 44158756Scg return EFAULT; 44258756Scg 44358756Scg if (set && !ifs->ifs_ipf_loopback) { 44458756Scg ifs->ifs_ipf_loopback = 1; 44558756Scg 44658756Scg ifs->ifs_hook4_loopback_in = (net_hook_register( 44758756Scg ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN, 44858756Scg ifs->ifs_ipfhook4_loop_in) == 0); 44958756Scg if (!ifs->ifs_hook4_loopback_in) 45058756Scg return EINVAL; 45158756Scg 45258756Scg ifs->ifs_hook4_loopback_out = (net_hook_register( 45358756Scg ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT, 45458756Scg ifs->ifs_ipfhook4_loop_out) == 0); 45558756Scg if (!ifs->ifs_hook4_loopback_out) 45658756Scg return EINVAL; 45758756Scg 45858756Scg ifs->ifs_hook6_loopback_in = (net_hook_register( 45958756Scg ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN, 46058756Scg ifs->ifs_ipfhook6_loop_in) == 0); 46158756Scg if (!ifs->ifs_hook6_loopback_in) 46258756Scg return EINVAL; 46358756Scg 46458756Scg ifs->ifs_hook6_loopback_out = (net_hook_register( 46558756Scg ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT, 46658756Scg ifs->ifs_ipfhook6_loop_out) == 0); 46758756Scg if (!ifs->ifs_hook6_loopback_out) 46858756Scg return EINVAL; 46958756Scg 47058756Scg } else if (!set && ifs->ifs_ipf_loopback) { 47158756Scg ifs->ifs_ipf_loopback = 0; 47258756Scg 47358756Scg ifs->ifs_hook4_loopback_in = 47458756Scg (net_hook_unregister(ifs->ifs_ipf_ipv4, 47558756Scg NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0); 47658756Scg if (ifs->ifs_hook4_loopback_in) 47758756Scg return EBUSY; 47858756Scg 47958756Scg ifs->ifs_hook4_loopback_out = 48058756Scg (net_hook_unregister(ifs->ifs_ipf_ipv4, 48158756Scg NH_LOOPBACK_OUT, ifs->ifs_ipfhook4_loop_out) != 0); 48258756Scg if (ifs->ifs_hook4_loopback_out) 48358756Scg return EBUSY; 48458756Scg 48558756Scg ifs->ifs_hook6_loopback_in = 48658756Scg (net_hook_unregister(ifs->ifs_ipf_ipv6, 48758756Scg NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0); 48858756Scg if (ifs->ifs_hook6_loopback_in) 48958756Scg return EBUSY; 49058756Scg 49158756Scg ifs->ifs_hook6_loopback_out = 49258756Scg (net_hook_unregister(ifs->ifs_ipf_ipv6, 49358756Scg NH_LOOPBACK_OUT, ifs->ifs_ipfhook6_loop_out) != 0); 49458756Scg if (ifs->ifs_hook6_loopback_out) 49558756Scg return EBUSY; 49658756Scg } 49758756Scg return 0; 49858756Scg} 49958756Scg 50058756Scg 50158756Scg/* 50258756Scg * Filter ioctl interface. 50358756Scg */ 50458756Scg/*ARGSUSED*/ 50558756Scgint iplioctl(dev, cmd, data, mode, cp, rp) 50658756Scgdev_t dev; 50758756Scgint cmd; 50858756Scg#if SOLARIS2 >= 7 50958756Scgintptr_t data; 51058756Scg#else 51158756Scgint *data; 51258756Scg#endif 51358756Scgint mode; 51458756Scgcred_t *cp; 51574763Scgint *rp; 51658756Scg{ 51758756Scg int error = 0, tmp; 51858756Scg friostat_t fio; 51958756Scg minor_t unit; 52058756Scg u_int enable; 52158756Scg ipf_stack_t *ifs; 52258756Scg 52358756Scg#ifdef IPFDEBUG 52458756Scg cmn_err(CE_CONT, "iplioctl(%x,%x,%x,%d,%x,%d)\n", 52574763Scg dev, cmd, data, mode, cp, rp); 52670291Scg#endif 52758756Scg unit = getminor(dev); 52858756Scg if (IPL_LOGMAX < unit) 52958756Scg return ENXIO; 53058756Scg 53158756Scg /* 53258756Scg * As we're calling ipf_find_stack in user space, from a given zone 53358756Scg * to find the stack pointer for this zone, there is no need to have 53474763Scg * a hold/refence count here. 53558756Scg */ 53658756Scg ifs = ipf_find_stack(crgetzoneid(cp)); 53758756Scg ASSERT(ifs != NULL); 53858756Scg 53958756Scg if (ifs->ifs_fr_running <= 0) { 54058756Scg if (unit != IPL_LOGIPF) { 54158756Scg return EIO; 54258756Scg } 54358756Scg if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 54474763Scg cmd != SIOCIPFSET && cmd != SIOCFRENB && 54558756Scg cmd != SIOCGETFS && cmd != SIOCGETFF) { 54658756Scg return EIO; 54758756Scg } 54858756Scg } 54958756Scg 55058756Scg READ_ENTER(&ifs->ifs_ipf_global); 55158756Scg 55274763Scg error = fr_ioctlswitch(unit, (caddr_t)data, cmd, mode, cp->cr_uid, 55358756Scg curproc, ifs); 55458756Scg if (error != -1) { 55558756Scg RWLOCK_EXIT(&ifs->ifs_ipf_global); 55670134Scg return error; 55758756Scg } 55858756Scg error = 0; 55974763Scg 56058756Scg switch (cmd) 56158756Scg { 56258756Scg case SIOCFRENB : 56358756Scg if (!(mode & FWRITE)) 56458756Scg error = EPERM; 56558756Scg else { 56658756Scg error = COPYIN((caddr_t)data, (caddr_t)&enable, 567168847Sariff sizeof(enable)); 56858756Scg if (error != 0) { 56965644Scg error = EFAULT; 57058756Scg break; 57158756Scg } 57258756Scg 573110499Snyan RWLOCK_EXIT(&ifs->ifs_ipf_global); 57458756Scg WRITE_ENTER(&ifs->ifs_ipf_global); 57558756Scg error = fr_enableipf(ifs, enable); 57658756Scg } 57758756Scg break; 57870134Scg case SIOCIPFSET : 57958756Scg if (!(mode & FWRITE)) { 58058756Scg error = EPERM; 58158756Scg break; 58258756Scg } 58358756Scg /* FALLTHRU */ 58458756Scg case SIOCIPFGETNEXT : 58558756Scg case SIOCIPFGET : 58658756Scg error = fr_ipftune(cmd, (void *)data, ifs); 58770134Scg break; 58858756Scg case SIOCSETFF : 58958756Scg if (!(mode & FWRITE)) 59058756Scg error = EPERM; 59158756Scg else { 59258756Scg error = COPYIN((caddr_t)data, 59358756Scg (caddr_t)&ifs->ifs_fr_flags, 59458756Scg sizeof(ifs->ifs_fr_flags)); 59558756Scg if (error != 0) 59658756Scg error = EFAULT; 59758756Scg } 59858756Scg break; 59958756Scg case SIOCIPFLP : 60058756Scg error = COPYIN((caddr_t)data, (caddr_t)&tmp, 60170134Scg sizeof(tmp)); 60258756Scg if (error != 0) 60370291Scg error = EFAULT; 60470291Scg else 60570291Scg error = fr_setipfloopback(tmp, ifs); 60670291Scg break; 60758756Scg case SIOCGETFF : 60858756Scg error = COPYOUT((caddr_t)&ifs->ifs_fr_flags, (caddr_t)data, 60958756Scg sizeof(ifs->ifs_fr_flags)); 61070134Scg if (error != 0) 61158756Scg error = EFAULT; 61258756Scg break; 61358756Scg case SIOCFUNCL : 61460958Scg error = fr_resolvefunc((void *)data); 61558756Scg break; 61658756Scg case SIOCINAFR : 61758756Scg case SIOCRMAFR : 61858756Scg case SIOCADAFR : 61970134Scg case SIOCZRLST : 620110499Snyan if (!(mode & FWRITE)) 62158756Scg error = EPERM; 62258756Scg else 62358756Scg error = frrequest(unit, cmd, (caddr_t)data, 62458756Scg ifs->ifs_fr_active, 1, ifs); 62558756Scg break; 62658756Scg case SIOCINIFR : 62758756Scg case SIOCRMIFR : 62858756Scg case SIOCADIFR : 62958756Scg if (!(mode & FWRITE)) 63058756Scg error = EPERM; 63158756Scg else 63258756Scg error = frrequest(unit, cmd, (caddr_t)data, 63358756Scg 1 - ifs->ifs_fr_active, 1, ifs); 63470134Scg break; 63558756Scg case SIOCSWAPA : 63658756Scg if (!(mode & FWRITE)) 63758756Scg error = EPERM; 638110499Snyan else { 63958756Scg WRITE_ENTER(&ifs->ifs_ipf_mutex); 64058756Scg error = COPYOUT((caddr_t)&ifs->ifs_fr_active, 64174763Scg (caddr_t)data, 64270134Scg sizeof(ifs->ifs_fr_active)); 64358756Scg if (error != 0) 64458756Scg error = EFAULT; 64558756Scg else 64658756Scg ifs->ifs_fr_active = 1 - ifs->ifs_fr_active; 64758756Scg RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 64858756Scg } 64970134Scg break; 65070134Scg case SIOCGETFS : 65170134Scg fr_getstat(&fio, ifs); 65270134Scg error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT); 65370134Scg break; 65470134Scg case SIOCFRZST : 65570134Scg if (!(mode & FWRITE)) 65670134Scg error = EPERM; 65770134Scg else 65870134Scg error = fr_zerostats((caddr_t)data, ifs); 65970134Scg break; 66070134Scg case SIOCIPFFL : 66158756Scg if (!(mode & FWRITE)) 66258756Scg error = EPERM; 66358756Scg else { 66474763Scg error = COPYIN((caddr_t)data, (caddr_t)&tmp, 66558756Scg sizeof(tmp)); 66658756Scg if (!error) { 66758756Scg tmp = frflush(unit, 4, tmp, ifs); 66858756Scg error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 66958756Scg sizeof(tmp)); 67058756Scg if (error != 0) 67158756Scg error = EFAULT; 67258756Scg } else 67373151Scg error = EFAULT; 67458756Scg } 67558756Scg break; 67658756Scg#ifdef USE_INET6 67758756Scg case SIOCIPFL6 : 67858756Scg if (!(mode & FWRITE)) 67958756Scg error = EPERM; 68058756Scg else { 68174763Scg error = COPYIN((caddr_t)data, (caddr_t)&tmp, 68258756Scg sizeof(tmp)); 68358756Scg if (!error) { 68458756Scg tmp = frflush(unit, 6, tmp, ifs); 68558756Scg error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 68658756Scg sizeof(tmp)); 68758756Scg if (error != 0) 68858756Scg error = EFAULT; 68958756Scg } else 69058756Scg error = EFAULT; 69158756Scg } 69258756Scg break; 69358756Scg#endif 69458756Scg case SIOCSTLCK : 69558756Scg error = COPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 69658756Scg if (error == 0) { 69758756Scg ifs->ifs_fr_state_lock = tmp; 69858756Scg ifs->ifs_fr_nat_lock = tmp; 69958756Scg ifs->ifs_fr_frag_lock = tmp; 70058756Scg ifs->ifs_fr_auth_lock = tmp; 70158756Scg } else 70258756Scg error = EFAULT; 70358756Scg break; 70458756Scg#ifdef IPFILTER_LOG 70558756Scg case SIOCIPFFB : 70658756Scg if (!(mode & FWRITE)) 70758756Scg error = EPERM; 70858756Scg else { 70958756Scg tmp = ipflog_clear(unit, ifs); 71058756Scg error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 71158756Scg sizeof(tmp)); 71258756Scg if (error) 71358756Scg error = EFAULT; 71458756Scg } 71558756Scg break; 71658756Scg#endif /* IPFILTER_LOG */ 71758756Scg case SIOCFRSYN : 71858756Scg if (!(mode & FWRITE)) 71973151Scg error = EPERM; 72073151Scg else { 72173151Scg RWLOCK_EXIT(&ifs->ifs_ipf_global); 72273151Scg WRITE_ENTER(&ifs->ifs_ipf_global); 72373151Scg 72458756Scg frsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 72558756Scg fr_natifpsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 72658756Scg fr_nataddrsync(0, NULL, NULL, ifs); 72758756Scg fr_statesync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 72858756Scg error = 0; 72958756Scg } 73058756Scg break; 73158756Scg case SIOCGFRST : 73258756Scg error = fr_outobj((void *)data, fr_fragstats(ifs), 73358756Scg IPFOBJ_FRAGSTAT); 73458756Scg break; 73558756Scg case FIONREAD : 73658756Scg#ifdef IPFILTER_LOG 73758756Scg tmp = (int)ifs->ifs_iplused[IPL_LOGIPF]; 73858756Scg 73958756Scg error = COPYOUT((caddr_t)&tmp, (caddr_t)data, sizeof(tmp)); 74058756Scg if (error != 0) 74158756Scg error = EFAULT; 74258756Scg#endif 74358756Scg break; 74458756Scg case SIOCIPFITER : 74574763Scg error = ipf_frruleiter((caddr_t)data, cp->cr_uid, 74658756Scg curproc, ifs); 74758756Scg break; 74858756Scg 74958756Scg case SIOCGENITER : 75058756Scg error = ipf_genericiter((caddr_t)data, cp->cr_uid, 75158756Scg curproc, ifs); 75258756Scg break; 75358756Scg 75458756Scg case SIOCIPFDELTOK : 75558756Scg error = BCOPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 75658756Scg if (error != 0) { 75758756Scg error = EFAULT; 75858756Scg } else { 75958756Scg error = ipf_deltoken(tmp, cp->cr_uid, curproc, ifs); 76058756Scg } 76158756Scg break; 76258756Scg 76358756Scg default : 76458756Scg cmn_err(CE_NOTE, "Unknown: cmd 0x%x data %p", 76558756Scg cmd, (void *)data); 76658756Scg error = EINVAL; 76758756Scg break; 76858756Scg } 76958756Scg RWLOCK_EXIT(&ifs->ifs_ipf_global); 77058756Scg return error; 77158756Scg} 77258756Scg 77358756Scg 77458756Scgstatic int fr_enableipf(ifs, enable) 77570134Scgipf_stack_t *ifs; 77670134Scgint enable; 77770134Scg{ 77870134Scg int error; 77970134Scg 78070134Scg if (!enable) { 78170134Scg error = ipldetach(ifs); 78270134Scg if (error == 0) 78370134Scg ifs->ifs_fr_running = -1; 78470134Scg return error; 78558756Scg } 78658756Scg 78758756Scg if (ifs->ifs_fr_running > 0) 78858756Scg return 0; 78958756Scg 79058756Scg error = iplattach(ifs); 79158756Scg if (error == 0) { 79258756Scg if (ifs->ifs_fr_timer_id == NULL) { 79358756Scg int hz = drv_usectohz(500000); 79458756Scg 79558756Scg ifs->ifs_fr_timer_id = timeout(fr_slowtimer, 79658756Scg (void *)ifs, 79758756Scg hz); 79858756Scg } 79958756Scg ifs->ifs_fr_running = 1; 80058756Scg } else { 80158756Scg (void) ipldetach(ifs); 80258756Scg } 80358756Scg return error; 80458756Scg} 80558756Scg 80658756Scg 80758756Scgphy_if_t get_unit(name, v, ifs) 80858756Scgchar *name; 80970134Scgint v; 81070134Scgipf_stack_t *ifs; 81158756Scg{ 81278564Sgreid net_handle_t nif; 81358756Scg 81458756Scg if (v == 4) 81558756Scg nif = ifs->ifs_ipf_ipv4; 81674763Scg else if (v == 6) 81784111Scg nif = ifs->ifs_ipf_ipv6; 81870134Scg else 81970134Scg return 0; 82070134Scg 82170134Scg return (net_phylookup(nif, name)); 82270134Scg} 82370134Scg 82470134Scg/* 82570134Scg * routines below for saving IP headers to buffer 82670134Scg */ 82770134Scg/*ARGSUSED*/ 82870134Scgint iplopen(devp, flags, otype, cred) 82970134Scgdev_t *devp; 83070134Scgint flags, otype; 83170134Scgcred_t *cred; 83270134Scg{ 83370134Scg minor_t min = getminor(*devp); 83470134Scg 83570134Scg#ifdef IPFDEBUG 83670134Scg cmn_err(CE_CONT, "iplopen(%x,%x,%x,%x)\n", devp, flags, otype, cred); 83770134Scg#endif 83870134Scg if (!(otype & OTYP_CHR)) 83970134Scg return ENXIO; 84070134Scg 84170134Scg min = (IPL_LOGMAX < min) ? ENXIO : 0; 84270134Scg return min; 84370134Scg} 84470134Scg 84570134Scg 84670134Scg/*ARGSUSED*/ 84770134Scgint iplclose(dev, flags, otype, cred) 84870134Scgdev_t dev; 84970134Scgint flags, otype; 85070134Scgcred_t *cred; 851128232Sgreen{ 85270134Scg minor_t min = getminor(dev); 85370134Scg 85470134Scg#ifdef IPFDEBUG 855166904Snetchild cmn_err(CE_CONT, "iplclose(%x,%x,%x,%x)\n", dev, flags, otype, cred); 856166904Snetchild#endif 85770134Scg 85870134Scg min = (IPL_LOGMAX < min) ? ENXIO : 0; 85970134Scg return min; 86084111Scg} 86170134Scg 862117126Sscottl#ifdef IPFILTER_LOG 863117126Sscottl/* 86470134Scg * iplread/ipllog 86570134Scg * both of these must operate with at least splnet() lest they be 86670134Scg * called during packet processing and cause an inconsistancy to appear in 86770134Scg * the filter lists. 86870134Scg */ 86984111Scg/*ARGSUSED*/ 87084111Scgint iplread(dev, uio, cp) 87184111Scgdev_t dev; 87270134Scgregister struct uio *uio; 873126695Smatkcred_t *cp; 87484111Scg{ 875126695Smatk ipf_stack_t *ifs; 876126695Smatk int ret; 87784111Scg 87870134Scg /* 87970134Scg * As we're calling ipf_find_stack in user space, from a given zone 88070134Scg * to find the stack pointer for this zone, there is no need to have 88170134Scg * a hold/refence count here. 88270134Scg */ 88370134Scg ifs = ipf_find_stack(crgetzoneid(cp)); 88470134Scg ASSERT(ifs != NULL); 88570134Scg 88670134Scg# ifdef IPFDEBUG 88770134Scg cmn_err(CE_CONT, "iplread(%x,%x,%x)\n", dev, uio, cp); 88870134Scg# endif 88958756Scg 89058756Scg if (ifs->ifs_fr_running < 1) { 89170134Scg return EIO; 89270134Scg } 89370134Scg 89470134Scg# ifdef IPFILTER_SYNC 89570134Scg if (getminor(dev) == IPL_LOGSYNC) { 89670134Scg return ipfsync_read(uio); 89770134Scg } 89870134Scg# endif 89970134Scg 90070134Scg ret = ipflog_read(getminor(dev), uio, ifs); 90170134Scg return ret; 90270134Scg} 90370134Scg#endif /* IPFILTER_LOG */ 90470134Scg 90570134Scg 90675326Sgreid/* 90775326Sgreid * iplread/ipllog 90875326Sgreid * both of these must operate with at least splnet() lest they be 90975326Sgreid * called during packet processing and cause an inconsistancy to appear in 91075326Sgreid * the filter lists. 91175326Sgreid */ 91275326Sgreidint iplwrite(dev, uio, cp) 91375326Sgreiddev_t dev; 91475326Sgreidregister struct uio *uio; 91575326Sgreidcred_t *cp; 91675326Sgreid{ 91775326Sgreid ipf_stack_t *ifs; 91875326Sgreid 91975326Sgreid /* 92075326Sgreid * As we're calling ipf_find_stack in user space, from a given zone 92175326Sgreid * to find the stack pointer for this zone, there is no need to have 92275326Sgreid * a hold/refence count here. 92375326Sgreid */ 92475326Sgreid ifs = ipf_find_stack(crgetzoneid(cp)); 92575326Sgreid ASSERT(ifs != NULL); 92658756Scg 92758756Scg#ifdef IPFDEBUG 92858756Scg cmn_err(CE_CONT, "iplwrite(%x,%x,%x)\n", dev, uio, cp); 92958756Scg#endif 93065644Scg 93175326Sgreid if (ifs->ifs_fr_running < 1) { 93258756Scg return EIO; 93358756Scg } 93458756Scg 93558756Scg#ifdef IPFILTER_SYNC 93658756Scg if (getminor(dev) == IPL_LOGSYNC) 93758756Scg return ipfsync_write(uio); 93858756Scg#endif /* IPFILTER_SYNC */ 93982180Scg dev = dev; /* LINT */ 94058756Scg uio = uio; /* LINT */ 94158756Scg cp = cp; /* LINT */ 94262483Scg return ENXIO; 943132236Stanimura} 94474763Scg 94562483Scg 94658756Scg/* 94770134Scg * fr_send_reset - this could conceivably be a call to tcp_respond(), but that 94862483Scg * requires a large amount of setting up and isn't any more efficient. 94958756Scg */ 95058756Scgint fr_send_reset(fin) 95158756Scgfr_info_t *fin; 95258756Scg{ 95358756Scg tcphdr_t *tcp, *tcp2; 95458756Scg int tlen, hlen; 95558756Scg mblk_t *m; 95658756Scg#ifdef USE_INET6 95758756Scg ip6_t *ip6; 95858756Scg#endif 95971932Scg ip_t *ip; 96071932Scg 96171932Scg tcp = fin->fin_dp; 96271932Scg if (tcp->th_flags & TH_RST) 96371932Scg return -1; 96471932Scg 96558756Scg#ifndef IPFILTER_CKSUM 96658756Scg if (fr_checkl4sum(fin) == -1) 96758756Scg return -1; 96858756Scg#endif 96958756Scg 97058756Scg tlen = (tcp->th_flags & (TH_SYN|TH_FIN)) ? 1 : 0; 97158756Scg#ifdef USE_INET6 97258756Scg if (fin->fin_v == 6) 97358756Scg hlen = sizeof(ip6_t); 97458756Scg else 975127135Snjl#endif 97658756Scg hlen = sizeof(ip_t); 97758756Scg hlen += sizeof(*tcp2); 97858756Scg if ((m = (mblk_t *)allocb(hlen + 64, BPRI_HI)) == NULL) 97958756Scg return -1; 98058756Scg 98158756Scg m->b_rptr += 64; 98258756Scg MTYPE(m) = M_DATA; 98358756Scg m->b_wptr = m->b_rptr + hlen; 98458756Scg ip = (ip_t *)m->b_rptr; 98558756Scg bzero((char *)ip, hlen); 98658756Scg tcp2 = (struct tcphdr *)(m->b_rptr + hlen - sizeof(*tcp2)); 98758756Scg tcp2->th_dport = tcp->th_sport; 98858756Scg tcp2->th_sport = tcp->th_dport; 98958756Scg if (tcp->th_flags & TH_ACK) { 99058756Scg tcp2->th_seq = tcp->th_ack; 99158756Scg tcp2->th_flags = TH_RST; 99258756Scg } else { 99365644Scg tcp2->th_ack = ntohl(tcp->th_seq); 99465644Scg tcp2->th_ack += tlen; 99565644Scg tcp2->th_ack = htonl(tcp2->th_ack); 99665644Scg tcp2->th_flags = TH_RST|TH_ACK; 99765644Scg } 99865644Scg tcp2->th_off = sizeof(struct tcphdr) >> 2; 99958756Scg 100058756Scg ip->ip_v = fin->fin_v; 100158756Scg#ifdef USE_INET6 100258756Scg if (fin->fin_v == 6) { 100365644Scg ip6 = (ip6_t *)m->b_rptr; 100458756Scg ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 100558756Scg ip6->ip6_src = fin->fin_dst6.in6; 100658756Scg ip6->ip6_dst = fin->fin_src6.in6; 100758756Scg ip6->ip6_plen = htons(sizeof(*tcp)); 100858756Scg ip6->ip6_nxt = IPPROTO_TCP; 100958756Scg tcp2->th_sum = fr_cksum(m, (ip_t *)ip6, IPPROTO_TCP, tcp2); 101058756Scg } else 101182180Scg#endif 101258756Scg { 101358756Scg ip->ip_src.s_addr = fin->fin_daddr; 101458756Scg ip->ip_dst.s_addr = fin->fin_saddr; 1015136410Snjl ip->ip_id = fr_nextipid(fin); 1016 ip->ip_hl = sizeof(*ip) >> 2; 1017 ip->ip_p = IPPROTO_TCP; 1018 ip->ip_len = sizeof(*ip) + sizeof(*tcp); 1019 ip->ip_tos = fin->fin_ip->ip_tos; 1020 tcp2->th_sum = fr_cksum(m, ip, IPPROTO_TCP, tcp2); 1021 } 1022 return fr_send_ip(fin, m, &m); 1023} 1024 1025/* 1026 * Function: fr_send_ip 1027 * Returns: 0: success 1028 * -1: failed 1029 * Parameters: 1030 * fin: packet information 1031 * m: the message block where ip head starts 1032 * 1033 * Send a new packet through the IP stack. 1034 * 1035 * For IPv4 packets, ip_len must be in host byte order, and ip_v, 1036 * ip_ttl, ip_off, and ip_sum are ignored (filled in by this 1037 * function). 1038 * 1039 * For IPv6 packets, ip6_flow, ip6_vfc, and ip6_hlim are filled 1040 * in by this function. 1041 * 1042 * All other portions of the packet must be in on-the-wire format. 1043 */ 1044/*ARGSUSED*/ 1045static int fr_send_ip(fin, m, mpp) 1046fr_info_t *fin; 1047mblk_t *m, **mpp; 1048{ 1049 qpktinfo_t qpi, *qpip; 1050 fr_info_t fnew; 1051 ip_t *ip; 1052 int i, hlen; 1053 ipf_stack_t *ifs = fin->fin_ifs; 1054 1055 ip = (ip_t *)m->b_rptr; 1056 bzero((char *)&fnew, sizeof(fnew)); 1057 1058#ifdef USE_INET6 1059 if (fin->fin_v == 6) { 1060 ip6_t *ip6; 1061 1062 ip6 = (ip6_t *)ip; 1063 ip6->ip6_vfc = 0x60; 1064 ip6->ip6_hlim = 127; 1065 fnew.fin_v = 6; 1066 hlen = sizeof(*ip6); 1067 fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen; 1068 } else 1069#endif 1070 { 1071 fnew.fin_v = 4; 1072#if SOLARIS2 >= 10 1073 ip->ip_ttl = 255; 1074 if (net_getpmtuenabled(ifs->ifs_ipf_ipv4) == 1) 1075 ip->ip_off = htons(IP_DF); 1076#else 1077 if (ip_ttl_ptr != NULL) 1078 ip->ip_ttl = (u_char)(*ip_ttl_ptr); 1079 else 1080 ip->ip_ttl = 63; 1081 if (ip_mtudisc != NULL) 1082 ip->ip_off = htons(*ip_mtudisc ? IP_DF : 0); 1083 else 1084 ip->ip_off = htons(IP_DF); 1085#endif 1086 /* 1087 * The dance with byte order and ip_len/ip_off is because in 1088 * fr_fastroute, it expects them to be in host byte order but 1089 * ipf_cksum expects them to be in network byte order. 1090 */ 1091 ip->ip_len = htons(ip->ip_len); 1092 ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip)); 1093 ip->ip_len = ntohs(ip->ip_len); 1094 ip->ip_off = ntohs(ip->ip_off); 1095 hlen = sizeof(*ip); 1096 fnew.fin_plen = ip->ip_len; 1097 } 1098 1099 qpip = fin->fin_qpi; 1100 qpi.qpi_off = 0; 1101 qpi.qpi_ill = qpip->qpi_ill; 1102 qpi.qpi_m = m; 1103 qpi.qpi_data = ip; 1104 fnew.fin_qpi = &qpi; 1105 fnew.fin_ifp = fin->fin_ifp; 1106 fnew.fin_flx = FI_NOCKSUM; 1107 fnew.fin_m = m; 1108 fnew.fin_qfm = m; 1109 fnew.fin_ip = ip; 1110 fnew.fin_mp = mpp; 1111 fnew.fin_hlen = hlen; 1112 fnew.fin_dp = (char *)ip + hlen; 1113 fnew.fin_ifs = fin->fin_ifs; 1114 (void) fr_makefrip(hlen, ip, &fnew); 1115 1116 i = fr_fastroute(m, mpp, &fnew, NULL); 1117 return i; 1118} 1119 1120 1121int fr_send_icmp_err(type, fin, dst) 1122int type; 1123fr_info_t *fin; 1124int dst; 1125{ 1126 struct in_addr dst4; 1127 struct icmp *icmp; 1128 qpktinfo_t *qpi; 1129 int hlen, code; 1130 phy_if_t phy; 1131 u_short sz; 1132#ifdef USE_INET6 1133 mblk_t *mb; 1134#endif 1135 mblk_t *m; 1136#ifdef USE_INET6 1137 ip6_t *ip6; 1138#endif 1139 ip_t *ip; 1140 ipf_stack_t *ifs = fin->fin_ifs; 1141 1142 if ((type < 0) || (type > ICMP_MAXTYPE)) 1143 return -1; 1144 1145 code = fin->fin_icode; 1146#ifdef USE_INET6 1147 if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) 1148 return -1; 1149#endif 1150 1151#ifndef IPFILTER_CKSUM 1152 if (fr_checkl4sum(fin) == -1) 1153 return -1; 1154#endif 1155 1156 qpi = fin->fin_qpi; 1157 1158#ifdef USE_INET6 1159 mb = fin->fin_qfm; 1160 1161 if (fin->fin_v == 6) { 1162 sz = sizeof(ip6_t); 1163 sz += MIN(mb->b_wptr - mb->b_rptr, 512); 1164 hlen = sizeof(ip6_t); 1165 type = icmptoicmp6types[type]; 1166 if (type == ICMP6_DST_UNREACH) 1167 code = icmptoicmp6unreach[code]; 1168 } else 1169#endif 1170 { 1171 if ((fin->fin_p == IPPROTO_ICMP) && 1172 !(fin->fin_flx & FI_SHORT)) 1173 switch (ntohs(fin->fin_data[0]) >> 8) 1174 { 1175 case ICMP_ECHO : 1176 case ICMP_TSTAMP : 1177 case ICMP_IREQ : 1178 case ICMP_MASKREQ : 1179 break; 1180 default : 1181 return 0; 1182 } 1183 1184 sz = sizeof(ip_t) * 2; 1185 sz += 8; /* 64 bits of data */ 1186 hlen = sizeof(ip_t); 1187 } 1188 1189 sz += offsetof(struct icmp, icmp_ip); 1190 if ((m = (mblk_t *)allocb((size_t)sz + 64, BPRI_HI)) == NULL) 1191 return -1; 1192 MTYPE(m) = M_DATA; 1193 m->b_rptr += 64; 1194 m->b_wptr = m->b_rptr + sz; 1195 bzero((char *)m->b_rptr, (size_t)sz); 1196 ip = (ip_t *)m->b_rptr; 1197 ip->ip_v = fin->fin_v; 1198 icmp = (struct icmp *)(m->b_rptr + hlen); 1199 icmp->icmp_type = type & 0xff; 1200 icmp->icmp_code = code & 0xff; 1201 phy = (phy_if_t)qpi->qpi_ill; 1202 if (type == ICMP_UNREACH && (phy != 0) && 1203 fin->fin_icode == ICMP_UNREACH_NEEDFRAG) 1204 icmp->icmp_nextmtu = net_getmtu(ifs->ifs_ipf_ipv4, phy,0 ); 1205 1206#ifdef USE_INET6 1207 if (fin->fin_v == 6) { 1208 struct in6_addr dst6; 1209 int csz; 1210 1211 if (dst == 0) { 1212 ipf_stack_t *ifs = fin->fin_ifs; 1213 1214 if (fr_ifpaddr(6, FRI_NORMAL, (void *)phy, 1215 (void *)&dst6, NULL, ifs) == -1) { 1216 FREE_MB_T(m); 1217 return -1; 1218 } 1219 } else 1220 dst6 = fin->fin_dst6.in6; 1221 1222 csz = sz; 1223 sz -= sizeof(ip6_t); 1224 ip6 = (ip6_t *)m->b_rptr; 1225 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 1226 ip6->ip6_plen = htons((u_short)sz); 1227 ip6->ip6_nxt = IPPROTO_ICMPV6; 1228 ip6->ip6_src = dst6; 1229 ip6->ip6_dst = fin->fin_src6.in6; 1230 sz -= offsetof(struct icmp, icmp_ip); 1231 bcopy((char *)mb->b_rptr, (char *)&icmp->icmp_ip, sz); 1232 icmp->icmp_cksum = csz - sizeof(ip6_t); 1233 } else 1234#endif 1235 { 1236 ip->ip_hl = sizeof(*ip) >> 2; 1237 ip->ip_p = IPPROTO_ICMP; 1238 ip->ip_id = fin->fin_ip->ip_id; 1239 ip->ip_tos = fin->fin_ip->ip_tos; 1240 ip->ip_len = (u_short)sz; 1241 if (dst == 0) { 1242 ipf_stack_t *ifs = fin->fin_ifs; 1243 1244 if (fr_ifpaddr(4, FRI_NORMAL, (void *)phy, 1245 (void *)&dst4, NULL, ifs) == -1) { 1246 FREE_MB_T(m); 1247 return -1; 1248 } 1249 } else { 1250 dst4 = fin->fin_dst; 1251 } 1252 ip->ip_src = dst4; 1253 ip->ip_dst = fin->fin_src; 1254 bcopy((char *)fin->fin_ip, (char *)&icmp->icmp_ip, 1255 sizeof(*fin->fin_ip)); 1256 bcopy((char *)fin->fin_ip + fin->fin_hlen, 1257 (char *)&icmp->icmp_ip + sizeof(*fin->fin_ip), 8); 1258 icmp->icmp_ip.ip_len = htons(icmp->icmp_ip.ip_len); 1259 icmp->icmp_ip.ip_off = htons(icmp->icmp_ip.ip_off); 1260 icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 1261 sz - sizeof(ip_t)); 1262 } 1263 1264 /* 1265 * Need to exit out of these so we don't recursively call rw_enter 1266 * from fr_qout. 1267 */ 1268 return fr_send_ip(fin, m, &m); 1269} 1270 1271#include <sys/time.h> 1272#include <sys/varargs.h> 1273 1274#ifndef _KERNEL 1275#include <stdio.h> 1276#endif 1277 1278#define NULLADDR_RATE_LIMIT 10 /* 10 seconds */ 1279 1280 1281/* 1282 * Print out warning message at rate-limited speed. 1283 */ 1284static void rate_limit_message(ipf_stack_t *ifs, 1285 int rate, const char *message, ...) 1286{ 1287 static time_t last_time = 0; 1288 time_t now; 1289 va_list args; 1290 char msg_buf[256]; 1291 int need_printed = 0; 1292 1293 now = ddi_get_time(); 1294 1295 /* make sure, no multiple entries */ 1296 ASSERT(MUTEX_NOT_HELD(&(ifs->ifs_ipf_rw.ipf_lk))); 1297 MUTEX_ENTER(&ifs->ifs_ipf_rw); 1298 if (now - last_time >= rate) { 1299 need_printed = 1; 1300 last_time = now; 1301 } 1302 MUTEX_EXIT(&ifs->ifs_ipf_rw); 1303 1304 if (need_printed) { 1305 va_start(args, message); 1306 (void)vsnprintf(msg_buf, 255, message, args); 1307 va_end(args); 1308#ifdef _KERNEL 1309 cmn_err(CE_WARN, msg_buf); 1310#else 1311 fprintf(std_err, msg_buf); 1312#endif 1313 } 1314} 1315 1316/* 1317 * return the first IP Address associated with an interface 1318 */ 1319/*ARGSUSED*/ 1320int fr_ifpaddr(v, atype, ifptr, inp, inpmask, ifs) 1321int v, atype; 1322void *ifptr; 1323struct in_addr *inp, *inpmask; 1324ipf_stack_t *ifs; 1325{ 1326 struct sockaddr_in6 v6addr[2]; 1327 struct sockaddr_in v4addr[2]; 1328 net_ifaddr_t type[2]; 1329 net_handle_t net_data; 1330 phy_if_t phyif; 1331 void *array; 1332 1333 switch (v) 1334 { 1335 case 4: 1336 net_data = ifs->ifs_ipf_ipv4; 1337 array = v4addr; 1338 break; 1339 case 6: 1340 net_data = ifs->ifs_ipf_ipv6; 1341 array = v6addr; 1342 break; 1343 default: 1344 net_data = NULL; 1345 break; 1346 } 1347 1348 if (net_data == NULL) 1349 return -1; 1350 1351 phyif = (phy_if_t)ifptr; 1352 1353 switch (atype) 1354 { 1355 case FRI_PEERADDR : 1356 type[0] = NA_PEER; 1357 break; 1358 1359 case FRI_BROADCAST : 1360 type[0] = NA_BROADCAST; 1361 break; 1362 1363 default : 1364 type[0] = NA_ADDRESS; 1365 break; 1366 } 1367 1368 type[1] = NA_NETMASK; 1369 1370 if (net_getlifaddr(net_data, phyif, 0, 2, type, array) < 0) 1371 return -1; 1372 1373 if (v == 6) { 1374 return fr_ifpfillv6addr(atype, &v6addr[0], &v6addr[1], 1375 inp, inpmask); 1376 } 1377 return fr_ifpfillv4addr(atype, &v4addr[0], &v4addr[1], inp, inpmask); 1378} 1379 1380 1381u_32_t fr_newisn(fin) 1382fr_info_t *fin; 1383{ 1384 static int iss_seq_off = 0; 1385 u_char hash[16]; 1386 u_32_t newiss; 1387 MD5_CTX ctx; 1388 ipf_stack_t *ifs = fin->fin_ifs; 1389 1390 /* 1391 * Compute the base value of the ISS. It is a hash 1392 * of (saddr, sport, daddr, dport, secret). 1393 */ 1394 MD5Init(&ctx); 1395 1396 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 1397 sizeof(fin->fin_fi.fi_src)); 1398 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 1399 sizeof(fin->fin_fi.fi_dst)); 1400 MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 1401 1402 MD5Update(&ctx, ifs->ifs_ipf_iss_secret, sizeof(ifs->ifs_ipf_iss_secret)); 1403 1404 MD5Final(hash, &ctx); 1405 1406 bcopy(hash, &newiss, sizeof(newiss)); 1407 1408 /* 1409 * Now increment our "timer", and add it in to 1410 * the computed value. 1411 * 1412 * XXX Use `addin'? 1413 * XXX TCP_ISSINCR too large to use? 1414 */ 1415 iss_seq_off += 0x00010000; 1416 newiss += iss_seq_off; 1417 return newiss; 1418} 1419 1420 1421/* ------------------------------------------------------------------------ */ 1422/* Function: fr_nextipid */ 1423/* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 1424/* Parameters: fin(I) - pointer to packet information */ 1425/* */ 1426/* Returns the next IPv4 ID to use for this packet. */ 1427/* ------------------------------------------------------------------------ */ 1428u_short fr_nextipid(fin) 1429fr_info_t *fin; 1430{ 1431 static u_short ipid = 0; 1432 ipstate_t *is; 1433 nat_t *nat; 1434 u_short id; 1435 ipf_stack_t *ifs = fin->fin_ifs; 1436 1437 MUTEX_ENTER(&ifs->ifs_ipf_rw); 1438 if (fin->fin_state != NULL) { 1439 is = fin->fin_state; 1440 id = (u_short)(is->is_pkts[(fin->fin_rev << 1) + 1] & 0xffff); 1441 } else if (fin->fin_nat != NULL) { 1442 nat = fin->fin_nat; 1443 id = (u_short)(nat->nat_pkts[fin->fin_out] & 0xffff); 1444 } else 1445 id = ipid++; 1446 MUTEX_EXIT(&ifs->ifs_ipf_rw); 1447 1448 return id; 1449} 1450 1451 1452#ifndef IPFILTER_CKSUM 1453/* ARGSUSED */ 1454#endif 1455INLINE void fr_checkv4sum(fin) 1456fr_info_t *fin; 1457{ 1458#ifdef IPFILTER_CKSUM 1459 if (fr_checkl4sum(fin) == -1) 1460 fin->fin_flx |= FI_BAD; 1461#endif 1462} 1463 1464 1465#ifdef USE_INET6 1466# ifndef IPFILTER_CKSUM 1467/* ARGSUSED */ 1468# endif 1469INLINE void fr_checkv6sum(fin) 1470fr_info_t *fin; 1471{ 1472# ifdef IPFILTER_CKSUM 1473 if (fr_checkl4sum(fin) == -1) 1474 fin->fin_flx |= FI_BAD; 1475# endif 1476} 1477#endif /* USE_INET6 */ 1478 1479 1480#if (SOLARIS2 < 7) 1481void fr_slowtimer() 1482#else 1483/*ARGSUSED*/ 1484void fr_slowtimer __P((void *arg)) 1485#endif 1486{ 1487 ipf_stack_t *ifs = arg; 1488 1489 READ_ENTER(&ifs->ifs_ipf_global); 1490 if (ifs->ifs_fr_running != 1) { 1491 ifs->ifs_fr_timer_id = NULL; 1492 RWLOCK_EXIT(&ifs->ifs_ipf_global); 1493 return; 1494 } 1495 ipf_expiretokens(ifs); 1496 fr_fragexpire(ifs); 1497 fr_timeoutstate(ifs); 1498 fr_natexpire(ifs); 1499 fr_authexpire(ifs); 1500 ifs->ifs_fr_ticks++; 1501 if (ifs->ifs_fr_running == 1) 1502 ifs->ifs_fr_timer_id = timeout(fr_slowtimer, arg, 1503 drv_usectohz(500000)); 1504 else 1505 ifs->ifs_fr_timer_id = NULL; 1506 RWLOCK_EXIT(&ifs->ifs_ipf_global); 1507} 1508 1509 1510/* ------------------------------------------------------------------------ */ 1511/* Function: fr_pullup */ 1512/* Returns: NULL == pullup failed, else pointer to protocol header */ 1513/* Parameters: m(I) - pointer to buffer where data packet starts */ 1514/* fin(I) - pointer to packet information */ 1515/* len(I) - number of bytes to pullup */ 1516/* */ 1517/* Attempt to move at least len bytes (from the start of the buffer) into a */ 1518/* single buffer for ease of access. Operating system native functions are */ 1519/* used to manage buffers - if necessary. If the entire packet ends up in */ 1520/* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */ 1521/* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ 1522/* and ONLY if the pullup succeeds. */ 1523/* */ 1524/* We assume that 'min' is a pointer to a buffer that is part of the chain */ 1525/* of buffers that starts at *fin->fin_mp. */ 1526/* ------------------------------------------------------------------------ */ 1527void *fr_pullup(min, fin, len) 1528mb_t *min; 1529fr_info_t *fin; 1530int len; 1531{ 1532 qpktinfo_t *qpi = fin->fin_qpi; 1533 int out = fin->fin_out, dpoff, ipoff; 1534 mb_t *m = min, *m1, *m2; 1535 char *ip; 1536 uint32_t start, stuff, end, value, flags; 1537 ipf_stack_t *ifs = fin->fin_ifs; 1538 1539 if (m == NULL) 1540 return NULL; 1541 1542 ip = (char *)fin->fin_ip; 1543 if ((fin->fin_flx & FI_COALESCE) != 0) 1544 return ip; 1545 1546 ipoff = fin->fin_ipoff; 1547 if (fin->fin_dp != NULL) 1548 dpoff = (char *)fin->fin_dp - (char *)ip; 1549 else 1550 dpoff = 0; 1551 1552 if (M_LEN(m) < len + ipoff) { 1553 1554 /* 1555 * pfil_precheck ensures the IP header is on a 32bit 1556 * aligned address so simply fail if that isn't currently 1557 * the case (should never happen). 1558 */ 1559 int inc = 0; 1560 1561 if (ipoff > 0) { 1562 if ((ipoff & 3) != 0) { 1563 inc = 4 - (ipoff & 3); 1564 if (m->b_rptr - inc >= m->b_datap->db_base) 1565 m->b_rptr -= inc; 1566 else 1567 inc = 0; 1568 } 1569 } 1570 1571 /* 1572 * XXX This is here as a work around for a bug with DEBUG 1573 * XXX Solaris kernels. The problem is b_prev is used by IP 1574 * XXX code as a way to stash the phyint_index for a packet, 1575 * XXX this doesn't get reset by IP but freeb does an ASSERT() 1576 * XXX for both of these to be NULL. See 6442390. 1577 */ 1578 m1 = m; 1579 m2 = m->b_prev; 1580 1581 do { 1582 m1->b_next = NULL; 1583 m1->b_prev = NULL; 1584 m1 = m1->b_cont; 1585 } while (m1); 1586 1587 /* 1588 * Need to preserve checksum information by copying them 1589 * to newmp which heads the pulluped message. 1590 */ 1591 hcksum_retrieve(m, NULL, NULL, &start, &stuff, &end, 1592 &value, &flags); 1593 1594 if (pullupmsg(m, len + ipoff + inc) == 0) { 1595 ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[1]); 1596 FREE_MB_T(*fin->fin_mp); 1597 *fin->fin_mp = NULL; 1598 fin->fin_m = NULL; 1599 fin->fin_ip = NULL; 1600 fin->fin_dp = NULL; 1601 qpi->qpi_data = NULL; 1602 return NULL; 1603 } 1604 1605 (void) hcksum_assoc(m, NULL, NULL, start, stuff, end, 1606 value, flags, 0); 1607 1608 m->b_prev = m2; 1609 m->b_rptr += inc; 1610 fin->fin_m = m; 1611 ip = MTOD(m, char *) + ipoff; 1612 qpi->qpi_data = ip; 1613 } 1614 1615 ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[0]); 1616 fin->fin_ip = (ip_t *)ip; 1617 if (fin->fin_dp != NULL) 1618 fin->fin_dp = (char *)fin->fin_ip + dpoff; 1619 1620 if (len == fin->fin_plen) 1621 fin->fin_flx |= FI_COALESCE; 1622 return ip; 1623} 1624 1625 1626/* 1627 * Function: fr_verifysrc 1628 * Returns: int (really boolean) 1629 * Parameters: fin - packet information 1630 * 1631 * Check whether the packet has a valid source address for the interface on 1632 * which the packet arrived, implementing the "fr_chksrc" feature. 1633 * Returns true iff the packet's source address is valid. 1634 */ 1635int fr_verifysrc(fin) 1636fr_info_t *fin; 1637{ 1638 net_handle_t net_data_p; 1639 phy_if_t phy_ifdata_routeto; 1640 struct sockaddr sin; 1641 ipf_stack_t *ifs = fin->fin_ifs; 1642 1643 if (fin->fin_v == 4) { 1644 net_data_p = ifs->ifs_ipf_ipv4; 1645 } else if (fin->fin_v == 6) { 1646 net_data_p = ifs->ifs_ipf_ipv6; 1647 } else { 1648 return (0); 1649 } 1650 1651 /* Get the index corresponding to the if name */ 1652 sin.sa_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 1653 bcopy(&fin->fin_saddr, &sin.sa_data, sizeof (struct in_addr)); 1654 phy_ifdata_routeto = net_routeto(net_data_p, &sin, NULL); 1655 1656 return (((phy_if_t)fin->fin_ifp == phy_ifdata_routeto) ? 1 : 0); 1657} 1658 1659 1660/* 1661 * Function: fr_fastroute 1662 * Returns: 0: success; 1663 * -1: failed 1664 * Parameters: 1665 * mb: the message block where ip head starts 1666 * mpp: the pointer to the pointer of the orignal 1667 * packet message 1668 * fin: packet information 1669 * fdp: destination interface information 1670 * if it is NULL, no interface information provided. 1671 * 1672 * This function is for fastroute/to/dup-to rules. It calls 1673 * pfil_make_lay2_packet to search route, make lay-2 header 1674 * ,and identify output queue for the IP packet. 1675 * The destination address depends on the following conditions: 1676 * 1: for fastroute rule, fdp is passed in as NULL, so the 1677 * destination address is the IP Packet's destination address 1678 * 2: for to/dup-to rule, if an ip address is specified after 1679 * the interface name, this address is the as destination 1680 * address. Otherwise IP Packet's destination address is used 1681 */ 1682int fr_fastroute(mb, mpp, fin, fdp) 1683mblk_t *mb, **mpp; 1684fr_info_t *fin; 1685frdest_t *fdp; 1686{ 1687 net_handle_t net_data_p; 1688 net_inject_t *inj; 1689 mblk_t *mp = NULL; 1690 frentry_t *fr = fin->fin_fr; 1691 qpktinfo_t *qpi; 1692 ip_t *ip; 1693 1694 struct sockaddr_in *sin; 1695 struct sockaddr_in6 *sin6; 1696 struct sockaddr *sinp; 1697 ipf_stack_t *ifs = fin->fin_ifs; 1698#ifndef sparc 1699 u_short __iplen, __ipoff; 1700#endif 1701 1702 if (fin->fin_v == 4) { 1703 net_data_p = ifs->ifs_ipf_ipv4; 1704 } else if (fin->fin_v == 6) { 1705 net_data_p = ifs->ifs_ipf_ipv6; 1706 } else { 1707 return (-1); 1708 } 1709 1710 inj = net_inject_alloc(NETINFO_VERSION); 1711 if (inj == NULL) 1712 return -1; 1713 1714 ip = fin->fin_ip; 1715 qpi = fin->fin_qpi; 1716 1717 /* 1718 * If this is a duplicate mblk then we want ip to point at that 1719 * data, not the original, if and only if it is already pointing at 1720 * the current mblk data. 1721 * 1722 * Otherwise, if it's not a duplicate, and we're not already pointing 1723 * at the current mblk data, then we want to ensure that the data 1724 * points at ip. 1725 */ 1726 1727 if ((ip == (ip_t *)qpi->qpi_m->b_rptr) && (qpi->qpi_m != mb)) { 1728 ip = (ip_t *)mb->b_rptr; 1729 } else if ((qpi->qpi_m == mb) && (ip != (ip_t *)qpi->qpi_m->b_rptr)) { 1730 qpi->qpi_m->b_rptr = (uchar_t *)ip; 1731 qpi->qpi_off = 0; 1732 } 1733 1734 /* 1735 * If there is another M_PROTO, we don't want it 1736 */ 1737 if (*mpp != mb) { 1738 mp = unlinkb(*mpp); 1739 freeb(*mpp); 1740 *mpp = mp; 1741 } 1742 1743 sinp = (struct sockaddr *)&inj->ni_addr; 1744 sin = (struct sockaddr_in *)sinp; 1745 sin6 = (struct sockaddr_in6 *)sinp; 1746 bzero((char *)&inj->ni_addr, sizeof (inj->ni_addr)); 1747 inj->ni_addr.ss_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 1748 inj->ni_packet = mb; 1749 1750 /* 1751 * In case we're here due to "to <if>" being used with 1752 * "keep state", check that we're going in the correct 1753 * direction. 1754 */ 1755 if (fdp != NULL) { 1756 if ((fr != NULL) && (fdp->fd_ifp != NULL) && 1757 (fin->fin_rev != 0) && (fdp == &fr->fr_tif)) 1758 goto bad_fastroute; 1759 inj->ni_physical = (phy_if_t)fdp->fd_ifp; 1760 if (fin->fin_v == 4) { 1761 sin->sin_addr = fdp->fd_ip; 1762 } else { 1763 sin6->sin6_addr = fdp->fd_ip6.in6; 1764 } 1765 } else { 1766 if (fin->fin_v == 4) { 1767 sin->sin_addr = ip->ip_dst; 1768 } else { 1769 sin6->sin6_addr = ((ip6_t *)ip)->ip6_dst; 1770 } 1771 inj->ni_physical = net_routeto(net_data_p, sinp, NULL); 1772 } 1773 1774 /* 1775 * Clear the hardware checksum flags from packets that we are doing 1776 * input processing on as leaving them set will cause the outgoing 1777 * NIC (if it supports hardware checksum) to calculate them anew, 1778 * using the old (correct) checksums as the pseudo value to start 1779 * from. 1780 */ 1781 if (fin->fin_out == 0) { 1782 DB_CKSUMFLAGS(mb) = 0; 1783 } 1784 1785 *mpp = mb; 1786 1787 if (fin->fin_out == 0) { 1788 void *saveifp; 1789 u_32_t pass; 1790 1791 saveifp = fin->fin_ifp; 1792 fin->fin_ifp = (void *)inj->ni_physical; 1793 fin->fin_flx &= ~FI_STATE; 1794 fin->fin_out = 1; 1795 (void) fr_acctpkt(fin, &pass); 1796 fin->fin_fr = NULL; 1797 if (!fr || !(fr->fr_flags & FR_RETMASK)) 1798 (void) fr_checkstate(fin, &pass); 1799 if (fr_checknatout(fin, NULL) == -1) 1800 goto bad_fastroute; 1801 fin->fin_out = 0; 1802 fin->fin_ifp = saveifp; 1803 1804 if (fin->fin_nat != NULL) 1805 fr_natderef((nat_t **)&fin->fin_nat, ifs); 1806 } 1807#ifndef sparc 1808 if (fin->fin_v == 4) { 1809 __iplen = (u_short)ip->ip_len, 1810 __ipoff = (u_short)ip->ip_off; 1811 1812 ip->ip_len = htons(__iplen); 1813 ip->ip_off = htons(__ipoff); 1814 } 1815#endif 1816 1817 if (net_data_p) { 1818 if (net_inject(net_data_p, NI_DIRECT_OUT, inj) < 0) { 1819 net_inject_free(inj); 1820 return (-1); 1821 } 1822 } 1823 1824 ifs->ifs_fr_frouteok[0]++; 1825 net_inject_free(inj); 1826 return 0; 1827bad_fastroute: 1828 net_inject_free(inj); 1829 freemsg(mb); 1830 ifs->ifs_fr_frouteok[1]++; 1831 return -1; 1832} 1833 1834 1835/* ------------------------------------------------------------------------ */ 1836/* Function: ipf_hook4_out */ 1837/* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1838/* Parameters: event(I) - pointer to event */ 1839/* info(I) - pointer to hook information for firewalling */ 1840/* */ 1841/* Calling ipf_hook. */ 1842/* ------------------------------------------------------------------------ */ 1843/*ARGSUSED*/ 1844int ipf_hook4_out(hook_event_token_t token, hook_data_t info, void *arg) 1845{ 1846 return ipf_hook(info, 1, 0, arg); 1847} 1848/*ARGSUSED*/ 1849int ipf_hook6_out(hook_event_token_t token, hook_data_t info, void *arg) 1850{ 1851 return ipf_hook6(info, 1, 0, arg); 1852} 1853 1854/* ------------------------------------------------------------------------ */ 1855/* Function: ipf_hook4_in */ 1856/* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1857/* Parameters: event(I) - pointer to event */ 1858/* info(I) - pointer to hook information for firewalling */ 1859/* */ 1860/* Calling ipf_hook. */ 1861/* ------------------------------------------------------------------------ */ 1862/*ARGSUSED*/ 1863int ipf_hook4_in(hook_event_token_t token, hook_data_t info, void *arg) 1864{ 1865 return ipf_hook(info, 0, 0, arg); 1866} 1867/*ARGSUSED*/ 1868int ipf_hook6_in(hook_event_token_t token, hook_data_t info, void *arg) 1869{ 1870 return ipf_hook6(info, 0, 0, arg); 1871} 1872 1873 1874/* ------------------------------------------------------------------------ */ 1875/* Function: ipf_hook4_loop_out */ 1876/* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1877/* Parameters: event(I) - pointer to event */ 1878/* info(I) - pointer to hook information for firewalling */ 1879/* */ 1880/* Calling ipf_hook. */ 1881/* ------------------------------------------------------------------------ */ 1882/*ARGSUSED*/ 1883int ipf_hook4_loop_out(hook_event_token_t token, hook_data_t info, void *arg) 1884{ 1885 return ipf_hook(info, 1, FI_NOCKSUM, arg); 1886} 1887/*ARGSUSED*/ 1888int ipf_hook6_loop_out(hook_event_token_t token, hook_data_t info, void *arg) 1889{ 1890 return ipf_hook6(info, 1, FI_NOCKSUM, arg); 1891} 1892 1893/* ------------------------------------------------------------------------ */ 1894/* Function: ipf_hook4_loop_in */ 1895/* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1896/* Parameters: event(I) - pointer to event */ 1897/* info(I) - pointer to hook information for firewalling */ 1898/* */ 1899/* Calling ipf_hook. */ 1900/* ------------------------------------------------------------------------ */ 1901/*ARGSUSED*/ 1902int ipf_hook4_loop_in(hook_event_token_t token, hook_data_t info, void *arg) 1903{ 1904 return ipf_hook(info, 0, FI_NOCKSUM, arg); 1905} 1906/*ARGSUSED*/ 1907int ipf_hook6_loop_in(hook_event_token_t token, hook_data_t info, void *arg) 1908{ 1909 return ipf_hook6(info, 0, FI_NOCKSUM, arg); 1910} 1911 1912/* ------------------------------------------------------------------------ */ 1913/* Function: ipf_hook */ 1914/* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1915/* Parameters: info(I) - pointer to hook information for firewalling */ 1916/* out(I) - whether packet is going in or out */ 1917/* loopback(I) - whether packet is a loopback packet or not */ 1918/* */ 1919/* Stepping stone function between the IP mainline and IPFilter. Extracts */ 1920/* parameters out of the info structure and forms them up to be useful for */ 1921/* calling ipfilter. */ 1922/* ------------------------------------------------------------------------ */ 1923int ipf_hook(hook_data_t info, int out, int loopback, void *arg) 1924{ 1925 hook_pkt_event_t *fw; 1926 ipf_stack_t *ifs; 1927 qpktinfo_t qpi; 1928 int rval, hlen; 1929 u_short swap; 1930 phy_if_t phy; 1931 ip_t *ip; 1932 1933 ifs = arg; 1934 fw = (hook_pkt_event_t *)info; 1935 1936 ASSERT(fw != NULL); 1937 phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp; 1938 1939 ip = fw->hpe_hdr; 1940 swap = ntohs(ip->ip_len); 1941 ip->ip_len = swap; 1942 swap = ntohs(ip->ip_off); 1943 ip->ip_off = swap; 1944 hlen = IPH_HDR_LENGTH(ip); 1945 1946 qpi.qpi_m = fw->hpe_mb; 1947 qpi.qpi_data = fw->hpe_hdr; 1948 qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr; 1949 qpi.qpi_ill = (void *)phy; 1950 qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST); 1951 if (qpi.qpi_flags) 1952 qpi.qpi_flags |= FI_MBCAST; 1953 qpi.qpi_flags |= loopback; 1954 1955 rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, 1956 &qpi, fw->hpe_mp, ifs); 1957 1958 /* For fastroute cases, fr_check returns 0 with mp set to NULL */ 1959 if (rval == 0 && *(fw->hpe_mp) == NULL) 1960 rval = 1; 1961 1962 /* Notify IP the packet mblk_t and IP header pointers. */ 1963 fw->hpe_mb = qpi.qpi_m; 1964 fw->hpe_hdr = qpi.qpi_data; 1965 if (rval == 0) { 1966 ip = qpi.qpi_data; 1967 swap = ntohs(ip->ip_len); 1968 ip->ip_len = swap; 1969 swap = ntohs(ip->ip_off); 1970 ip->ip_off = swap; 1971 } 1972 return rval; 1973 1974} 1975int ipf_hook6(hook_data_t info, int out, int loopback, void *arg) 1976{ 1977 hook_pkt_event_t *fw; 1978 int rval, hlen; 1979 qpktinfo_t qpi; 1980 phy_if_t phy; 1981 1982 fw = (hook_pkt_event_t *)info; 1983 1984 ASSERT(fw != NULL); 1985 phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp; 1986 1987 hlen = sizeof (ip6_t); 1988 1989 qpi.qpi_m = fw->hpe_mb; 1990 qpi.qpi_data = fw->hpe_hdr; 1991 qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr; 1992 qpi.qpi_ill = (void *)phy; 1993 qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST); 1994 if (qpi.qpi_flags) 1995 qpi.qpi_flags |= FI_MBCAST; 1996 qpi.qpi_flags |= loopback; 1997 1998 rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, 1999 &qpi, fw->hpe_mp, arg); 2000 2001 /* For fastroute cases, fr_check returns 0 with mp set to NULL */ 2002 if (rval == 0 && *(fw->hpe_mp) == NULL) 2003 rval = 1; 2004 2005 /* Notify IP the packet mblk_t and IP header pointers. */ 2006 fw->hpe_mb = qpi.qpi_m; 2007 fw->hpe_hdr = qpi.qpi_data; 2008 return rval; 2009 2010} 2011 2012 2013/* ------------------------------------------------------------------------ */ 2014/* Function: ipf_nic_event_v4 */ 2015/* Returns: int - 0 == no problems encountered */ 2016/* Parameters: event(I) - pointer to event */ 2017/* info(I) - pointer to information about a NIC event */ 2018/* */ 2019/* Function to receive asynchronous NIC events from IP */ 2020/* ------------------------------------------------------------------------ */ 2021/*ARGSUSED*/ 2022int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info, void *arg) 2023{ 2024 struct sockaddr_in *sin; 2025 hook_nic_event_t *hn; 2026 ipf_stack_t *ifs = arg; 2027 2028 hn = (hook_nic_event_t *)info; 2029 2030 switch (hn->hne_event) 2031 { 2032 case NE_PLUMB : 2033 frsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, hn->hne_data, 2034 ifs); 2035 fr_natifpsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, 2036 hn->hne_data, ifs); 2037 fr_statesync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, 2038 hn->hne_data, ifs); 2039 break; 2040 2041 case NE_UNPLUMB : 2042 frsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 2043 fr_natifpsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, 2044 ifs); 2045 fr_statesync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 2046 break; 2047 2048 case NE_ADDRESS_CHANGE : 2049 /* 2050 * We only respond to events for logical interface 0 because 2051 * IPFilter only uses the first address given to a network 2052 * interface. We check for hne_lif==1 because the netinfo 2053 * code maps adds 1 to the lif number so that it can return 2054 * 0 to indicate "no more lifs" when walking them. 2055 */ 2056 if (hn->hne_lif == 1) { 2057 frsync(IPFSYNC_RESYNC, 4, (void *)hn->hne_nic, NULL, 2058 ifs); 2059 sin = hn->hne_data; 2060 fr_nataddrsync(4, (void *)hn->hne_nic, &sin->sin_addr, 2061 ifs); 2062 } 2063 break; 2064 2065 default : 2066 break; 2067 } 2068 2069 return 0; 2070} 2071 2072 2073/* ------------------------------------------------------------------------ */ 2074/* Function: ipf_nic_event_v6 */ 2075/* Returns: int - 0 == no problems encountered */ 2076/* Parameters: event(I) - pointer to event */ 2077/* info(I) - pointer to information about a NIC event */ 2078/* */ 2079/* Function to receive asynchronous NIC events from IP */ 2080/* ------------------------------------------------------------------------ */ 2081/*ARGSUSED*/ 2082int ipf_nic_event_v6(hook_event_token_t event, hook_data_t info, void *arg) 2083{ 2084 struct sockaddr_in6 *sin6; 2085 hook_nic_event_t *hn; 2086 ipf_stack_t *ifs = arg; 2087 2088 hn = (hook_nic_event_t *)info; 2089 2090 switch (hn->hne_event) 2091 { 2092 case NE_PLUMB : 2093 frsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2094 hn->hne_data, ifs); 2095 fr_natifpsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2096 hn->hne_data, ifs); 2097 fr_statesync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2098 hn->hne_data, ifs); 2099 break; 2100 2101 case NE_UNPLUMB : 2102 frsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2103 fr_natifpsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, 2104 ifs); 2105 fr_statesync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2106 break; 2107 2108 case NE_ADDRESS_CHANGE : 2109 if (hn->hne_lif == 1) { 2110 sin6 = hn->hne_data; 2111 fr_nataddrsync(6, (void *)hn->hne_nic, &sin6->sin6_addr, 2112 ifs); 2113 } 2114 break; 2115 default : 2116 break; 2117 } 2118 2119 return 0; 2120} 2121