12393Syz155240 /*
22393Syz155240 * Copyright (C) 1993-2001, 2003 by Darren Reed.
32393Syz155240 *
42393Syz155240 * See the IPFILTER.LICENCE file for details on licencing.
52393Syz155240 *
6*12358SAlexandr.Nedvedicky@Sun.COM * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
72393Syz155240 */
82393Syz155240
92393Syz155240 #if !defined(lint)
102535Ssangeeta static const char sccsid[] = "@(#)ip_fil_solaris.c 1.7 07/22/06 (C) 1993-2000 Darren Reed";
112393Syz155240 static const char rcsid[] = "@(#)$Id: ip_fil_solaris.c,v 2.62.2.19 2005/07/13 21:40:46 darrenr Exp $";
122393Syz155240 #endif
132393Syz155240
142393Syz155240 #include <sys/types.h>
152393Syz155240 #include <sys/errno.h>
162393Syz155240 #include <sys/param.h>
172393Syz155240 #include <sys/cpuvar.h>
182393Syz155240 #include <sys/open.h>
192393Syz155240 #include <sys/ioctl.h>
202393Syz155240 #include <sys/filio.h>
212393Syz155240 #include <sys/systm.h>
222393Syz155240 #include <sys/strsubr.h>
232393Syz155240 #include <sys/cred.h>
242393Syz155240 #include <sys/ddi.h>
252393Syz155240 #include <sys/sunddi.h>
262393Syz155240 #include <sys/ksynch.h>
272393Syz155240 #include <sys/kmem.h>
282393Syz155240 #include <sys/mkdev.h>
292393Syz155240 #include <sys/protosw.h>
302393Syz155240 #include <sys/socket.h>
312393Syz155240 #include <sys/dditypes.h>
322393Syz155240 #include <sys/cmn_err.h>
333448Sdh155122 #include <sys/zone.h>
342393Syz155240 #include <net/if.h>
352393Syz155240 #include <net/af.h>
362393Syz155240 #include <net/route.h>
372393Syz155240 #include <netinet/in.h>
382393Syz155240 #include <netinet/in_systm.h>
392393Syz155240 #include <netinet/ip.h>
402393Syz155240 #include <netinet/ip_var.h>
412393Syz155240 #include <netinet/tcp.h>
422393Syz155240 #include <netinet/udp.h>
432393Syz155240 #include <netinet/tcpip.h>
442393Syz155240 #include <netinet/ip_icmp.h>
452393Syz155240 #include "netinet/ip_compat.h"
462393Syz155240 #ifdef USE_INET6
472393Syz155240 # include <netinet/icmp6.h>
482393Syz155240 #endif
492393Syz155240 #include "netinet/ip_fil.h"
502393Syz155240 #include "netinet/ip_nat.h"
512393Syz155240 #include "netinet/ip_frag.h"
522393Syz155240 #include "netinet/ip_state.h"
532393Syz155240 #include "netinet/ip_auth.h"
542393Syz155240 #include "netinet/ip_proxy.h"
553448Sdh155122 #include "netinet/ipf_stack.h"
562393Syz155240 #ifdef IPFILTER_LOOKUP
572393Syz155240 # include "netinet/ip_lookup.h"
582393Syz155240 #endif
592393Syz155240 #include <inet/ip_ire.h>
602393Syz155240
612393Syz155240 #include <sys/md5.h>
622958Sdr146992 #include <sys/neti.h>
632393Syz155240
643448Sdh155122 static int frzerostats __P((caddr_t, ipf_stack_t *));
653448Sdh155122 static int fr_setipfloopback __P((int, ipf_stack_t *));
667513SDarren.Reed@Sun.COM static int fr_enableipf __P((ipf_stack_t *, int));
672393Syz155240 static int fr_send_ip __P((fr_info_t *fin, mblk_t *m, mblk_t **mp));
687513SDarren.Reed@Sun.COM static int ipf_nic_event_v4 __P((hook_event_token_t, hook_data_t, void *));
697513SDarren.Reed@Sun.COM static int ipf_nic_event_v6 __P((hook_event_token_t, hook_data_t, void *));
707513SDarren.Reed@Sun.COM static int ipf_hook __P((hook_data_t, int, int, void *));
717513SDarren.Reed@Sun.COM static int ipf_hook4_in __P((hook_event_token_t, hook_data_t, void *));
727513SDarren.Reed@Sun.COM static int ipf_hook4_out __P((hook_event_token_t, hook_data_t, void *));
737131Sdr146992 static int ipf_hook4_loop_out __P((hook_event_token_t, hook_data_t,
747513SDarren.Reed@Sun.COM void *));
757513SDarren.Reed@Sun.COM static int ipf_hook4_loop_in __P((hook_event_token_t, hook_data_t, void *));
767513SDarren.Reed@Sun.COM static int ipf_hook4 __P((hook_data_t, int, int, void *));
777513SDarren.Reed@Sun.COM static int ipf_hook6_out __P((hook_event_token_t, hook_data_t, void *));
787513SDarren.Reed@Sun.COM static int ipf_hook6_in __P((hook_event_token_t, hook_data_t, void *));
797131Sdr146992 static int ipf_hook6_loop_out __P((hook_event_token_t, hook_data_t,
807513SDarren.Reed@Sun.COM void *));
817131Sdr146992 static int ipf_hook6_loop_in __P((hook_event_token_t, hook_data_t,
827513SDarren.Reed@Sun.COM void *));
837513SDarren.Reed@Sun.COM static int ipf_hook6 __P((hook_data_t, int, int, void *));
843448Sdh155122 extern int ipf_geniter __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *));
853448Sdh155122 extern int ipf_frruleiter __P((void *, int, void *, ipf_stack_t *));
862958Sdr146992
872393Syz155240 #if SOLARIS2 < 10
882393Syz155240 #if SOLARIS2 >= 7
892393Syz155240 u_int *ip_ttl_ptr = NULL;
902393Syz155240 u_int *ip_mtudisc = NULL;
912393Syz155240 # if SOLARIS2 >= 8
922393Syz155240 int *ip_forwarding = NULL;
932393Syz155240 u_int *ip6_forwarding = NULL;
942393Syz155240 # else
952393Syz155240 u_int *ip_forwarding = NULL;
962393Syz155240 # endif
972393Syz155240 #else
982393Syz155240 u_long *ip_ttl_ptr = NULL;
992393Syz155240 u_long *ip_mtudisc = NULL;
1002393Syz155240 u_long *ip_forwarding = NULL;
1012393Syz155240 #endif
1022393Syz155240 #endif
1032393Syz155240
1042393Syz155240
1052393Syz155240 /* ------------------------------------------------------------------------ */
1062393Syz155240 /* Function: ipldetach */
1072393Syz155240 /* Returns: int - 0 == success, else error. */
1082393Syz155240 /* Parameters: Nil */
1092393Syz155240 /* */
1102393Syz155240 /* This function is responsible for undoing anything that might have been */
1112393Syz155240 /* done in a call to iplattach(). It must be able to clean up from a call */
1122393Syz155240 /* to iplattach() that did not succeed. Why might that happen? Someone */
1132393Syz155240 /* configures a table to be so large that we cannot allocate enough memory */
1142393Syz155240 /* for it. */
1152393Syz155240 /* ------------------------------------------------------------------------ */
ipldetach(ifs)1163448Sdh155122 int ipldetach(ifs)
1173448Sdh155122 ipf_stack_t *ifs;
1182393Syz155240 {
1192393Syz155240
1203448Sdh155122 ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0);
1212393Syz155240
1222393Syz155240 #if SOLARIS2 < 10
1232393Syz155240
1243448Sdh155122 if (ifs->ifs_fr_control_forwarding & 2) {
1252393Syz155240 if (ip_forwarding != NULL)
1262393Syz155240 *ip_forwarding = 0;
1272393Syz155240 #if SOLARIS2 >= 8
1282393Syz155240 if (ip6_forwarding != NULL)
1292393Syz155240 *ip6_forwarding = 0;
1302393Syz155240 #endif
1312393Syz155240 }
1322393Syz155240 #endif
1332393Syz155240
1342958Sdr146992 /*
1357513SDarren.Reed@Sun.COM * This lock needs to be dropped around the net_hook_unregister calls
1362958Sdr146992 * because we can deadlock here with:
1372958Sdr146992 * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs
1382958Sdr146992 * R(hook_family)->R(hei_lock)->R(ipf_global) (active hook running)
1392958Sdr146992 */
1403448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_global);
1412958Sdr146992
1427513SDarren.Reed@Sun.COM #define UNDO_HOOK(_f, _b, _e, _h) \
1437513SDarren.Reed@Sun.COM do { \
1447513SDarren.Reed@Sun.COM if (ifs->_f != NULL) { \
1457513SDarren.Reed@Sun.COM if (ifs->_b) { \
1467513SDarren.Reed@Sun.COM ifs->_b = (net_hook_unregister(ifs->_f, \
1477513SDarren.Reed@Sun.COM _e, ifs->_h) != 0); \
1487513SDarren.Reed@Sun.COM if (!ifs->_b) { \
1497513SDarren.Reed@Sun.COM hook_free(ifs->_h); \
1507513SDarren.Reed@Sun.COM ifs->_h = NULL; \
1517513SDarren.Reed@Sun.COM } \
1527513SDarren.Reed@Sun.COM } else if (ifs->_h != NULL) { \
1537513SDarren.Reed@Sun.COM hook_free(ifs->_h); \
1547513SDarren.Reed@Sun.COM ifs->_h = NULL; \
1557513SDarren.Reed@Sun.COM } \
1567513SDarren.Reed@Sun.COM } \
1577513SDarren.Reed@Sun.COM _NOTE(CONSTCOND) \
1587513SDarren.Reed@Sun.COM } while (0)
1597513SDarren.Reed@Sun.COM
1602958Sdr146992 /*
1612958Sdr146992 * Remove IPv6 Hooks
1622958Sdr146992 */
1633448Sdh155122 if (ifs->ifs_ipf_ipv6 != NULL) {
1647513SDarren.Reed@Sun.COM UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_in,
1657513SDarren.Reed@Sun.COM NH_PHYSICAL_IN, ifs_ipfhook6_in);
1667513SDarren.Reed@Sun.COM UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_out,
1677513SDarren.Reed@Sun.COM NH_PHYSICAL_OUT, ifs_ipfhook6_out);
1687513SDarren.Reed@Sun.COM UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_nic_events,
1697513SDarren.Reed@Sun.COM NH_NIC_EVENTS, ifs_ipfhook6_nicevents);
1707513SDarren.Reed@Sun.COM UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_in,
1717513SDarren.Reed@Sun.COM NH_LOOPBACK_IN, ifs_ipfhook6_loop_in);
1727513SDarren.Reed@Sun.COM UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_out,
1737513SDarren.Reed@Sun.COM NH_LOOPBACK_OUT, ifs_ipfhook6_loop_out);
1742958Sdr146992
1757513SDarren.Reed@Sun.COM if (net_protocol_release(ifs->ifs_ipf_ipv6) != 0)
1762958Sdr146992 goto detach_failed;
1773448Sdh155122 ifs->ifs_ipf_ipv6 = NULL;
1782958Sdr146992 }
1792958Sdr146992
1802958Sdr146992 /*
1812958Sdr146992 * Remove IPv4 Hooks
1822958Sdr146992 */
1833448Sdh155122 if (ifs->ifs_ipf_ipv4 != NULL) {
1847513SDarren.Reed@Sun.COM UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_in,
1857513SDarren.Reed@Sun.COM NH_PHYSICAL_IN, ifs_ipfhook4_in);
1867513SDarren.Reed@Sun.COM UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_out,
1877513SDarren.Reed@Sun.COM NH_PHYSICAL_OUT, ifs_ipfhook4_out);
1887513SDarren.Reed@Sun.COM UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_nic_events,
1897513SDarren.Reed@Sun.COM NH_NIC_EVENTS, ifs_ipfhook4_nicevents);
1907513SDarren.Reed@Sun.COM UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_in,
1917513SDarren.Reed@Sun.COM NH_LOOPBACK_IN, ifs_ipfhook4_loop_in);
1927513SDarren.Reed@Sun.COM UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_out,
1937513SDarren.Reed@Sun.COM NH_LOOPBACK_OUT, ifs_ipfhook4_loop_out);
1942958Sdr146992
1957513SDarren.Reed@Sun.COM if (net_protocol_release(ifs->ifs_ipf_ipv4) != 0)
1962958Sdr146992 goto detach_failed;
1973448Sdh155122 ifs->ifs_ipf_ipv4 = NULL;
1982958Sdr146992 }
1992958Sdr146992
2007513SDarren.Reed@Sun.COM #undef UNDO_HOOK
2017513SDarren.Reed@Sun.COM
2022393Syz155240 #ifdef IPFDEBUG
2032393Syz155240 cmn_err(CE_CONT, "ipldetach()\n");
2042393Syz155240 #endif
2052393Syz155240
2063448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_global);
2073448Sdh155122 fr_deinitialise(ifs);
2082393Syz155240
2093448Sdh155122 (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE, ifs);
2103448Sdh155122 (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE, ifs);
2112393Syz155240
2123448Sdh155122 if (ifs->ifs_ipf_locks_done == 1) {
2133448Sdh155122 MUTEX_DESTROY(&ifs->ifs_ipf_timeoutlock);
2143448Sdh155122 MUTEX_DESTROY(&ifs->ifs_ipf_rw);
2153448Sdh155122 RW_DESTROY(&ifs->ifs_ipf_tokens);
2163448Sdh155122 RW_DESTROY(&ifs->ifs_ipf_ipidfrag);
2173448Sdh155122 ifs->ifs_ipf_locks_done = 0;
2182393Syz155240 }
2192958Sdr146992
2207513SDarren.Reed@Sun.COM if (ifs->ifs_hook4_physical_in || ifs->ifs_hook4_physical_out ||
2217513SDarren.Reed@Sun.COM ifs->ifs_hook4_nic_events || ifs->ifs_hook4_loopback_in ||
2227513SDarren.Reed@Sun.COM ifs->ifs_hook4_loopback_out || ifs->ifs_hook6_nic_events ||
2237513SDarren.Reed@Sun.COM ifs->ifs_hook6_physical_in || ifs->ifs_hook6_physical_out ||
2247513SDarren.Reed@Sun.COM ifs->ifs_hook6_loopback_in || ifs->ifs_hook6_loopback_out)
2252958Sdr146992 return -1;
2262958Sdr146992
2272393Syz155240 return 0;
2282958Sdr146992
2292958Sdr146992 detach_failed:
2303448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_global);
2312958Sdr146992 return -1;
2322393Syz155240 }
2332393Syz155240
iplattach(ifs)2347513SDarren.Reed@Sun.COM int iplattach(ifs)
2353448Sdh155122 ipf_stack_t *ifs;
2362393Syz155240 {
2372393Syz155240 #if SOLARIS2 < 10
2382393Syz155240 int i;
2392393Syz155240 #endif
2407513SDarren.Reed@Sun.COM netid_t id = ifs->ifs_netid;
2412393Syz155240
2422393Syz155240 #ifdef IPFDEBUG
2432393Syz155240 cmn_err(CE_CONT, "iplattach()\n");
2442393Syz155240 #endif
2452393Syz155240
2463448Sdh155122 ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0);
2473448Sdh155122 ifs->ifs_fr_flags = IPF_LOGGING;
2483448Sdh155122 #ifdef _KERNEL
2493448Sdh155122 ifs->ifs_fr_update_ipid = 0;
2503448Sdh155122 #else
2513448Sdh155122 ifs->ifs_fr_update_ipid = 1;
2523448Sdh155122 #endif
2533448Sdh155122 ifs->ifs_fr_minttl = 4;
2543448Sdh155122 ifs->ifs_fr_icmpminfragmtu = 68;
2553448Sdh155122 #if defined(IPFILTER_DEFAULT_BLOCK)
2563448Sdh155122 ifs->ifs_fr_pass = FR_BLOCK|FR_NOMATCH;
2573448Sdh155122 #else
2583448Sdh155122 ifs->ifs_fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH;
2593448Sdh155122 #endif
2602393Syz155240
26110587SAlexandr.Nedvedicky@Sun.COM bzero((char *)ifs->ifs_frcache, sizeof(ifs->ifs_frcache));
2623448Sdh155122 MUTEX_INIT(&ifs->ifs_ipf_rw, "ipf rw mutex");
2633448Sdh155122 MUTEX_INIT(&ifs->ifs_ipf_timeoutlock, "ipf timeout lock mutex");
2643448Sdh155122 RWLOCK_INIT(&ifs->ifs_ipf_ipidfrag, "ipf IP NAT-Frag rwlock");
2653448Sdh155122 RWLOCK_INIT(&ifs->ifs_ipf_tokens, "ipf token rwlock");
2663448Sdh155122 ifs->ifs_ipf_locks_done = 1;
2672393Syz155240
2683448Sdh155122 if (fr_initialise(ifs) < 0)
2692393Syz155240 return -1;
2702393Syz155240
2717513SDarren.Reed@Sun.COM HOOK_INIT(ifs->ifs_ipfhook4_nicevents, ipf_nic_event_v4,
2727513SDarren.Reed@Sun.COM "ipfilter_hook4_nicevents", ifs);
2737513SDarren.Reed@Sun.COM HOOK_INIT(ifs->ifs_ipfhook4_in, ipf_hook4_in,
2747513SDarren.Reed@Sun.COM "ipfilter_hook4_in", ifs);
2757513SDarren.Reed@Sun.COM HOOK_INIT(ifs->ifs_ipfhook4_out, ipf_hook4_out,
2767513SDarren.Reed@Sun.COM "ipfilter_hook4_out", ifs);
2777704SAlexandr.Nedvedicky@Sun.COM HOOK_INIT(ifs->ifs_ipfhook4_loop_in, ipf_hook4_loop_in,
2787513SDarren.Reed@Sun.COM "ipfilter_hook4_loop_in", ifs);
2797704SAlexandr.Nedvedicky@Sun.COM HOOK_INIT(ifs->ifs_ipfhook4_loop_out, ipf_hook4_loop_out,
2807513SDarren.Reed@Sun.COM "ipfilter_hook4_loop_out", ifs);
2812958Sdr146992
2822958Sdr146992 /*
2837513SDarren.Reed@Sun.COM * If we hold this lock over all of the net_hook_register calls, we
2842958Sdr146992 * can cause a deadlock to occur with the following lock ordering:
2852958Sdr146992 * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs
2862958Sdr146992 * R(hook_family)->R(hei_lock)->R(ipf_global) (packet path)
2872958Sdr146992 */
2883448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_global);
2892958Sdr146992
2902958Sdr146992 /*
2912958Sdr146992 * Add IPv4 hooks
2922958Sdr146992 */
2937513SDarren.Reed@Sun.COM ifs->ifs_ipf_ipv4 = net_protocol_lookup(id, NHF_INET);
2943448Sdh155122 if (ifs->ifs_ipf_ipv4 == NULL)
2952958Sdr146992 goto hookup_failed;
2962958Sdr146992
2977513SDarren.Reed@Sun.COM ifs->ifs_hook4_nic_events = (net_hook_register(ifs->ifs_ipf_ipv4,
2987513SDarren.Reed@Sun.COM NH_NIC_EVENTS, ifs->ifs_ipfhook4_nicevents) == 0);
2993448Sdh155122 if (!ifs->ifs_hook4_nic_events)
3002958Sdr146992 goto hookup_failed;
3012958Sdr146992
3027513SDarren.Reed@Sun.COM ifs->ifs_hook4_physical_in = (net_hook_register(ifs->ifs_ipf_ipv4,
3037513SDarren.Reed@Sun.COM NH_PHYSICAL_IN, ifs->ifs_ipfhook4_in) == 0);
3043448Sdh155122 if (!ifs->ifs_hook4_physical_in)
3052958Sdr146992 goto hookup_failed;
3062958Sdr146992
3077513SDarren.Reed@Sun.COM ifs->ifs_hook4_physical_out = (net_hook_register(ifs->ifs_ipf_ipv4,
3087513SDarren.Reed@Sun.COM NH_PHYSICAL_OUT, ifs->ifs_ipfhook4_out) == 0);
3093448Sdh155122 if (!ifs->ifs_hook4_physical_out)
3102958Sdr146992 goto hookup_failed;
3112958Sdr146992
3123448Sdh155122 if (ifs->ifs_ipf_loopback) {
3137513SDarren.Reed@Sun.COM ifs->ifs_hook4_loopback_in = (net_hook_register(
3147513SDarren.Reed@Sun.COM ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN,
3157513SDarren.Reed@Sun.COM ifs->ifs_ipfhook4_loop_in) == 0);
3163448Sdh155122 if (!ifs->ifs_hook4_loopback_in)
3172958Sdr146992 goto hookup_failed;
3182958Sdr146992
3197513SDarren.Reed@Sun.COM ifs->ifs_hook4_loopback_out = (net_hook_register(
3207513SDarren.Reed@Sun.COM ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT,
3217513SDarren.Reed@Sun.COM ifs->ifs_ipfhook4_loop_out) == 0);
3223448Sdh155122 if (!ifs->ifs_hook4_loopback_out)
3232958Sdr146992 goto hookup_failed;
3242958Sdr146992 }
3252958Sdr146992 /*
3262958Sdr146992 * Add IPv6 hooks
3272958Sdr146992 */
3287513SDarren.Reed@Sun.COM ifs->ifs_ipf_ipv6 = net_protocol_lookup(id, NHF_INET6);
3293448Sdh155122 if (ifs->ifs_ipf_ipv6 == NULL)
3302958Sdr146992 goto hookup_failed;
3312958Sdr146992
3327513SDarren.Reed@Sun.COM HOOK_INIT(ifs->ifs_ipfhook6_nicevents, ipf_nic_event_v6,
3337513SDarren.Reed@Sun.COM "ipfilter_hook6_nicevents", ifs);
3347513SDarren.Reed@Sun.COM HOOK_INIT(ifs->ifs_ipfhook6_in, ipf_hook6_in,
3357513SDarren.Reed@Sun.COM "ipfilter_hook6_in", ifs);
3367513SDarren.Reed@Sun.COM HOOK_INIT(ifs->ifs_ipfhook6_out, ipf_hook6_out,
3377513SDarren.Reed@Sun.COM "ipfilter_hook6_out", ifs);
3387704SAlexandr.Nedvedicky@Sun.COM HOOK_INIT(ifs->ifs_ipfhook6_loop_in, ipf_hook6_loop_in,
3397513SDarren.Reed@Sun.COM "ipfilter_hook6_loop_in", ifs);
3407704SAlexandr.Nedvedicky@Sun.COM HOOK_INIT(ifs->ifs_ipfhook6_loop_out, ipf_hook6_loop_out,
3417513SDarren.Reed@Sun.COM "ipfilter_hook6_loop_out", ifs);
3427131Sdr146992
3437513SDarren.Reed@Sun.COM ifs->ifs_hook6_nic_events = (net_hook_register(ifs->ifs_ipf_ipv6,
3447513SDarren.Reed@Sun.COM NH_NIC_EVENTS, ifs->ifs_ipfhook6_nicevents) == 0);
3453448Sdh155122 if (!ifs->ifs_hook6_nic_events)
3463448Sdh155122 goto hookup_failed;
3473448Sdh155122
3487513SDarren.Reed@Sun.COM ifs->ifs_hook6_physical_in = (net_hook_register(ifs->ifs_ipf_ipv6,
3497513SDarren.Reed@Sun.COM NH_PHYSICAL_IN, ifs->ifs_ipfhook6_in) == 0);
3503448Sdh155122 if (!ifs->ifs_hook6_physical_in)
3512958Sdr146992 goto hookup_failed;
3522958Sdr146992
3537513SDarren.Reed@Sun.COM ifs->ifs_hook6_physical_out = (net_hook_register(ifs->ifs_ipf_ipv6,
3547513SDarren.Reed@Sun.COM NH_PHYSICAL_OUT, ifs->ifs_ipfhook6_out) == 0);
3553448Sdh155122 if (!ifs->ifs_hook6_physical_out)
3562958Sdr146992 goto hookup_failed;
3572958Sdr146992
3583448Sdh155122 if (ifs->ifs_ipf_loopback) {
3597513SDarren.Reed@Sun.COM ifs->ifs_hook6_loopback_in = (net_hook_register(
3607513SDarren.Reed@Sun.COM ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN,
3617513SDarren.Reed@Sun.COM ifs->ifs_ipfhook6_loop_in) == 0);
3623448Sdh155122 if (!ifs->ifs_hook6_loopback_in)
3632958Sdr146992 goto hookup_failed;
3642958Sdr146992
3657513SDarren.Reed@Sun.COM ifs->ifs_hook6_loopback_out = (net_hook_register(
3667513SDarren.Reed@Sun.COM ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT,
3677513SDarren.Reed@Sun.COM ifs->ifs_ipfhook6_loop_out) == 0);
3683448Sdh155122 if (!ifs->ifs_hook6_loopback_out)
3692958Sdr146992 goto hookup_failed;
3702958Sdr146992 }
3712958Sdr146992
3722958Sdr146992 /*
3732958Sdr146992 * Reacquire ipf_global, now it is safe.
3742958Sdr146992 */
3753448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_global);
3762958Sdr146992
3772393Syz155240 /* Do not use private interface ip_params_arr[] in Solaris 10 */
3782393Syz155240 #if SOLARIS2 < 10
3792393Syz155240
3802393Syz155240 #if SOLARIS2 >= 8
3812393Syz155240 ip_forwarding = &ip_g_forward;
3822393Syz155240 #endif
3832393Syz155240 /*
3842393Syz155240 * XXX - There is no terminator for this array, so it is not possible
3852393Syz155240 * to tell if what we are looking for is missing and go off the end
3862393Syz155240 * of the array.
3872393Syz155240 */
3882393Syz155240
3892393Syz155240 #if SOLARIS2 <= 8
3902393Syz155240 for (i = 0; ; i++) {
3912393Syz155240 if (!strcmp(ip_param_arr[i].ip_param_name, "ip_def_ttl")) {
3922393Syz155240 ip_ttl_ptr = &ip_param_arr[i].ip_param_value;
3932393Syz155240 } else if (!strcmp(ip_param_arr[i].ip_param_name,
3942393Syz155240 "ip_path_mtu_discovery")) {
3952393Syz155240 ip_mtudisc = &ip_param_arr[i].ip_param_value;
3962393Syz155240 }
3972393Syz155240 #if SOLARIS2 < 8
3982393Syz155240 else if (!strcmp(ip_param_arr[i].ip_param_name,
3992393Syz155240 "ip_forwarding")) {
4002393Syz155240 ip_forwarding = &ip_param_arr[i].ip_param_value;
4012393Syz155240 }
4022393Syz155240 #else
4032393Syz155240 else if (!strcmp(ip_param_arr[i].ip_param_name,
4042393Syz155240 "ip6_forwarding")) {
4052393Syz155240 ip6_forwarding = &ip_param_arr[i].ip_param_value;
4062393Syz155240 }
4072393Syz155240 #endif
4082393Syz155240
4092393Syz155240 if (ip_mtudisc != NULL && ip_ttl_ptr != NULL &&
4102393Syz155240 #if SOLARIS2 >= 8
4112393Syz155240 ip6_forwarding != NULL &&
4122393Syz155240 #endif
4132393Syz155240 ip_forwarding != NULL)
4142393Syz155240 break;
4152393Syz155240 }
4162393Syz155240 #endif
4172393Syz155240
4183448Sdh155122 if (ifs->ifs_fr_control_forwarding & 1) {
4192393Syz155240 if (ip_forwarding != NULL)
4202393Syz155240 *ip_forwarding = 1;
4212393Syz155240 #if SOLARIS2 >= 8
4222393Syz155240 if (ip6_forwarding != NULL)
4232393Syz155240 *ip6_forwarding = 1;
4242393Syz155240 #endif
4252393Syz155240 }
4262393Syz155240
4272393Syz155240 #endif
4282393Syz155240
4292393Syz155240 return 0;
4302958Sdr146992 hookup_failed:
4313448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_global);
4322958Sdr146992 return -1;
4332958Sdr146992 }
4342958Sdr146992
fr_setipfloopback(set,ifs)4353448Sdh155122 static int fr_setipfloopback(set, ifs)
4362958Sdr146992 int set;
4373448Sdh155122 ipf_stack_t *ifs;
4382958Sdr146992 {
4393448Sdh155122 if (ifs->ifs_ipf_ipv4 == NULL || ifs->ifs_ipf_ipv6 == NULL)
4402958Sdr146992 return EFAULT;
4412958Sdr146992
4423448Sdh155122 if (set && !ifs->ifs_ipf_loopback) {
4433448Sdh155122 ifs->ifs_ipf_loopback = 1;
4442958Sdr146992
4457513SDarren.Reed@Sun.COM ifs->ifs_hook4_loopback_in = (net_hook_register(
4467513SDarren.Reed@Sun.COM ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN,
4477513SDarren.Reed@Sun.COM ifs->ifs_ipfhook4_loop_in) == 0);
4483448Sdh155122 if (!ifs->ifs_hook4_loopback_in)
4492958Sdr146992 return EINVAL;
4502958Sdr146992
4517513SDarren.Reed@Sun.COM ifs->ifs_hook4_loopback_out = (net_hook_register(
4527513SDarren.Reed@Sun.COM ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT,
4537513SDarren.Reed@Sun.COM ifs->ifs_ipfhook4_loop_out) == 0);
4543448Sdh155122 if (!ifs->ifs_hook4_loopback_out)
4552958Sdr146992 return EINVAL;
4562958Sdr146992
4577513SDarren.Reed@Sun.COM ifs->ifs_hook6_loopback_in = (net_hook_register(
4587513SDarren.Reed@Sun.COM ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN,
4597513SDarren.Reed@Sun.COM ifs->ifs_ipfhook6_loop_in) == 0);
4603448Sdh155122 if (!ifs->ifs_hook6_loopback_in)
4612958Sdr146992 return EINVAL;
4622958Sdr146992
4637513SDarren.Reed@Sun.COM ifs->ifs_hook6_loopback_out = (net_hook_register(
4647513SDarren.Reed@Sun.COM ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT,
4657513SDarren.Reed@Sun.COM ifs->ifs_ipfhook6_loop_out) == 0);
4663448Sdh155122 if (!ifs->ifs_hook6_loopback_out)
4672958Sdr146992 return EINVAL;
4682958Sdr146992
4693448Sdh155122 } else if (!set && ifs->ifs_ipf_loopback) {
4703448Sdh155122 ifs->ifs_ipf_loopback = 0;
4712958Sdr146992
4723448Sdh155122 ifs->ifs_hook4_loopback_in =
4737513SDarren.Reed@Sun.COM (net_hook_unregister(ifs->ifs_ipf_ipv4,
4747513SDarren.Reed@Sun.COM NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0);
4753448Sdh155122 if (ifs->ifs_hook4_loopback_in)
4762958Sdr146992 return EBUSY;
4772958Sdr146992
4783448Sdh155122 ifs->ifs_hook4_loopback_out =
4797513SDarren.Reed@Sun.COM (net_hook_unregister(ifs->ifs_ipf_ipv4,
4807513SDarren.Reed@Sun.COM NH_LOOPBACK_OUT, ifs->ifs_ipfhook4_loop_out) != 0);
4813448Sdh155122 if (ifs->ifs_hook4_loopback_out)
4822958Sdr146992 return EBUSY;
4832958Sdr146992
4843448Sdh155122 ifs->ifs_hook6_loopback_in =
4857513SDarren.Reed@Sun.COM (net_hook_unregister(ifs->ifs_ipf_ipv6,
4867513SDarren.Reed@Sun.COM NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0);
4873448Sdh155122 if (ifs->ifs_hook6_loopback_in)
4882958Sdr146992 return EBUSY;
4892958Sdr146992
4903448Sdh155122 ifs->ifs_hook6_loopback_out =
4917513SDarren.Reed@Sun.COM (net_hook_unregister(ifs->ifs_ipf_ipv6,
4927513SDarren.Reed@Sun.COM NH_LOOPBACK_OUT, ifs->ifs_ipfhook6_loop_out) != 0);
4933448Sdh155122 if (ifs->ifs_hook6_loopback_out)
4942958Sdr146992 return EBUSY;
4952958Sdr146992 }
4962958Sdr146992 return 0;
4972393Syz155240 }
4982393Syz155240
4992393Syz155240
5002393Syz155240 /*
5012393Syz155240 * Filter ioctl interface.
5022393Syz155240 */
5032393Syz155240 /*ARGSUSED*/
iplioctl(dev,cmd,data,mode,cp,rp)5042393Syz155240 int iplioctl(dev, cmd, data, mode, cp, rp)
5052393Syz155240 dev_t dev;
5062393Syz155240 int cmd;
5072393Syz155240 #if SOLARIS2 >= 7
5082393Syz155240 intptr_t data;
5092393Syz155240 #else
5102393Syz155240 int *data;
5112393Syz155240 #endif
5122393Syz155240 int mode;
5132393Syz155240 cred_t *cp;
5142393Syz155240 int *rp;
5152393Syz155240 {
5162393Syz155240 int error = 0, tmp;
5172393Syz155240 friostat_t fio;
5182393Syz155240 minor_t unit;
5192393Syz155240 u_int enable;
5203448Sdh155122 ipf_stack_t *ifs;
5212393Syz155240
5222393Syz155240 #ifdef IPFDEBUG
5232393Syz155240 cmn_err(CE_CONT, "iplioctl(%x,%x,%x,%d,%x,%d)\n",
5242393Syz155240 dev, cmd, data, mode, cp, rp);
5252393Syz155240 #endif
5262393Syz155240 unit = getminor(dev);
5272393Syz155240 if (IPL_LOGMAX < unit)
5282393Syz155240 return ENXIO;
5292393Syz155240
5307513SDarren.Reed@Sun.COM /*
5317513SDarren.Reed@Sun.COM * As we're calling ipf_find_stack in user space, from a given zone
5327513SDarren.Reed@Sun.COM * to find the stack pointer for this zone, there is no need to have
5337513SDarren.Reed@Sun.COM * a hold/refence count here.
5347513SDarren.Reed@Sun.COM */
5357513SDarren.Reed@Sun.COM ifs = ipf_find_stack(crgetzoneid(cp));
5363448Sdh155122 ASSERT(ifs != NULL);
5373448Sdh155122
5383448Sdh155122 if (ifs->ifs_fr_running <= 0) {
5393448Sdh155122 if (unit != IPL_LOGIPF) {
5402393Syz155240 return EIO;
5413448Sdh155122 }
5422393Syz155240 if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET &&
5432393Syz155240 cmd != SIOCIPFSET && cmd != SIOCFRENB &&
5443448Sdh155122 cmd != SIOCGETFS && cmd != SIOCGETFF) {
5452393Syz155240 return EIO;
5463448Sdh155122 }
5472393Syz155240 }
5482393Syz155240
5493448Sdh155122 READ_ENTER(&ifs->ifs_ipf_global);
5509876SDarren.Reed@Sun.COM if (ifs->ifs_fr_enable_active != 0) {
5519876SDarren.Reed@Sun.COM RWLOCK_EXIT(&ifs->ifs_ipf_global);
5529876SDarren.Reed@Sun.COM return EBUSY;
5539876SDarren.Reed@Sun.COM }
5542393Syz155240
55511134SCasper.Dik@Sun.COM error = fr_ioctlswitch(unit, (caddr_t)data, cmd, mode, crgetuid(cp),
5567513SDarren.Reed@Sun.COM curproc, ifs);
5572393Syz155240 if (error != -1) {
5583448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_global);
5592393Syz155240 return error;
5602393Syz155240 }
5612393Syz155240 error = 0;
5622393Syz155240
5632393Syz155240 switch (cmd)
5642393Syz155240 {
5652393Syz155240 case SIOCFRENB :
5662393Syz155240 if (!(mode & FWRITE))
5672393Syz155240 error = EPERM;
5682393Syz155240 else {
5692393Syz155240 error = COPYIN((caddr_t)data, (caddr_t)&enable,
5702393Syz155240 sizeof(enable));
5712393Syz155240 if (error != 0) {
5722393Syz155240 error = EFAULT;
5732393Syz155240 break;
5742393Syz155240 }
5752393Syz155240
5763448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_global);
5773448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_global);
57811105SAlexandr.Nedvedicky@Sun.COM
57911105SAlexandr.Nedvedicky@Sun.COM /*
58011105SAlexandr.Nedvedicky@Sun.COM * We must recheck fr_enable_active here, since we've
58111105SAlexandr.Nedvedicky@Sun.COM * dropped ifs_ipf_global from R in order to get it
58211105SAlexandr.Nedvedicky@Sun.COM * exclusively.
58311105SAlexandr.Nedvedicky@Sun.COM */
58411105SAlexandr.Nedvedicky@Sun.COM if (ifs->ifs_fr_enable_active == 0) {
58511105SAlexandr.Nedvedicky@Sun.COM ifs->ifs_fr_enable_active = 1;
58611105SAlexandr.Nedvedicky@Sun.COM error = fr_enableipf(ifs, enable);
58711105SAlexandr.Nedvedicky@Sun.COM ifs->ifs_fr_enable_active = 0;
58811105SAlexandr.Nedvedicky@Sun.COM }
5892393Syz155240 }
5902393Syz155240 break;
5912393Syz155240 case SIOCIPFSET :
5922393Syz155240 if (!(mode & FWRITE)) {
5932393Syz155240 error = EPERM;
5942393Syz155240 break;
5952393Syz155240 }
5962393Syz155240 /* FALLTHRU */
5972393Syz155240 case SIOCIPFGETNEXT :
5982393Syz155240 case SIOCIPFGET :
5993448Sdh155122 error = fr_ipftune(cmd, (void *)data, ifs);
6002393Syz155240 break;
6012393Syz155240 case SIOCSETFF :
6022393Syz155240 if (!(mode & FWRITE))
6032393Syz155240 error = EPERM;
6042393Syz155240 else {
6057513SDarren.Reed@Sun.COM error = COPYIN((caddr_t)data,
6067513SDarren.Reed@Sun.COM (caddr_t)&ifs->ifs_fr_flags,
6077513SDarren.Reed@Sun.COM sizeof(ifs->ifs_fr_flags));
6082393Syz155240 if (error != 0)
6092393Syz155240 error = EFAULT;
6102393Syz155240 }
6112393Syz155240 break;
6122958Sdr146992 case SIOCIPFLP :
6132958Sdr146992 error = COPYIN((caddr_t)data, (caddr_t)&tmp,
6142958Sdr146992 sizeof(tmp));
6152958Sdr146992 if (error != 0)
6162958Sdr146992 error = EFAULT;
6172958Sdr146992 else
6183448Sdh155122 error = fr_setipfloopback(tmp, ifs);
6192958Sdr146992 break;
6202393Syz155240 case SIOCGETFF :
6213448Sdh155122 error = COPYOUT((caddr_t)&ifs->ifs_fr_flags, (caddr_t)data,
6227513SDarren.Reed@Sun.COM sizeof(ifs->ifs_fr_flags));
6232393Syz155240 if (error != 0)
6242393Syz155240 error = EFAULT;
6252393Syz155240 break;
6262393Syz155240 case SIOCFUNCL :
6272393Syz155240 error = fr_resolvefunc((void *)data);
6282393Syz155240 break;
6292393Syz155240 case SIOCINAFR :
6302393Syz155240 case SIOCRMAFR :
6312393Syz155240 case SIOCADAFR :
6322393Syz155240 case SIOCZRLST :
6332393Syz155240 if (!(mode & FWRITE))
6342393Syz155240 error = EPERM;
6352393Syz155240 else
6362393Syz155240 error = frrequest(unit, cmd, (caddr_t)data,
6373448Sdh155122 ifs->ifs_fr_active, 1, ifs);
6382393Syz155240 break;
6392393Syz155240 case SIOCINIFR :
6402393Syz155240 case SIOCRMIFR :
6412393Syz155240 case SIOCADIFR :
6422393Syz155240 if (!(mode & FWRITE))
6432393Syz155240 error = EPERM;
6442393Syz155240 else
6452393Syz155240 error = frrequest(unit, cmd, (caddr_t)data,
6463448Sdh155122 1 - ifs->ifs_fr_active, 1, ifs);
6472393Syz155240 break;
6482393Syz155240 case SIOCSWAPA :
6492393Syz155240 if (!(mode & FWRITE))
6502393Syz155240 error = EPERM;
6512393Syz155240 else {
6523448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_mutex);
65310587SAlexandr.Nedvedicky@Sun.COM bzero((char *)ifs->ifs_frcache,
65410587SAlexandr.Nedvedicky@Sun.COM sizeof (ifs->ifs_frcache));
6553448Sdh155122 error = COPYOUT((caddr_t)&ifs->ifs_fr_active,
6563448Sdh155122 (caddr_t)data,
6573448Sdh155122 sizeof(ifs->ifs_fr_active));
6582393Syz155240 if (error != 0)
6592393Syz155240 error = EFAULT;
6602393Syz155240 else
6613448Sdh155122 ifs->ifs_fr_active = 1 - ifs->ifs_fr_active;
6623448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
6632393Syz155240 }
6642393Syz155240 break;
6652393Syz155240 case SIOCGETFS :
6663448Sdh155122 fr_getstat(&fio, ifs);
6672393Syz155240 error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT);
6682393Syz155240 break;
6692393Syz155240 case SIOCFRZST :
6702393Syz155240 if (!(mode & FWRITE))
6712393Syz155240 error = EPERM;
6722393Syz155240 else
6733448Sdh155122 error = fr_zerostats((caddr_t)data, ifs);
6742393Syz155240 break;
6752393Syz155240 case SIOCIPFFL :
6762393Syz155240 if (!(mode & FWRITE))
6772393Syz155240 error = EPERM;
6782393Syz155240 else {
6792393Syz155240 error = COPYIN((caddr_t)data, (caddr_t)&tmp,
6802393Syz155240 sizeof(tmp));
6812393Syz155240 if (!error) {
6823448Sdh155122 tmp = frflush(unit, 4, tmp, ifs);
6832393Syz155240 error = COPYOUT((caddr_t)&tmp, (caddr_t)data,
6847513SDarren.Reed@Sun.COM sizeof(tmp));
6852393Syz155240 if (error != 0)
6862393Syz155240 error = EFAULT;
6872393Syz155240 } else
6882393Syz155240 error = EFAULT;
6892393Syz155240 }
6902393Syz155240 break;
6912393Syz155240 #ifdef USE_INET6
6922393Syz155240 case SIOCIPFL6 :
6932393Syz155240 if (!(mode & FWRITE))
6942393Syz155240 error = EPERM;
6952393Syz155240 else {
6962393Syz155240 error = COPYIN((caddr_t)data, (caddr_t)&tmp,
6972393Syz155240 sizeof(tmp));
6982393Syz155240 if (!error) {
6993448Sdh155122 tmp = frflush(unit, 6, tmp, ifs);
7002393Syz155240 error = COPYOUT((caddr_t)&tmp, (caddr_t)data,
7017513SDarren.Reed@Sun.COM sizeof(tmp));
7022393Syz155240 if (error != 0)
7032393Syz155240 error = EFAULT;
7042393Syz155240 } else
7052393Syz155240 error = EFAULT;
7062393Syz155240 }
7072393Syz155240 break;
7082393Syz155240 #endif
7092393Syz155240 case SIOCSTLCK :
7102393Syz155240 error = COPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp));
7112393Syz155240 if (error == 0) {
7123448Sdh155122 ifs->ifs_fr_state_lock = tmp;
7133448Sdh155122 ifs->ifs_fr_nat_lock = tmp;
7143448Sdh155122 ifs->ifs_fr_frag_lock = tmp;
7153448Sdh155122 ifs->ifs_fr_auth_lock = tmp;
7162393Syz155240 } else
7172393Syz155240 error = EFAULT;
7182393Syz155240 break;
7192393Syz155240 #ifdef IPFILTER_LOG
7202393Syz155240 case SIOCIPFFB :
7212393Syz155240 if (!(mode & FWRITE))
7222393Syz155240 error = EPERM;
7232393Syz155240 else {
7243448Sdh155122 tmp = ipflog_clear(unit, ifs);
7252393Syz155240 error = COPYOUT((caddr_t)&tmp, (caddr_t)data,
7262393Syz155240 sizeof(tmp));
7272393Syz155240 if (error)
7282393Syz155240 error = EFAULT;
7292393Syz155240 }
7302393Syz155240 break;
7312393Syz155240 #endif /* IPFILTER_LOG */
7322393Syz155240 case SIOCFRSYN :
7332393Syz155240 if (!(mode & FWRITE))
7342393Syz155240 error = EPERM;
7352393Syz155240 else {
7363448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_global);
7373448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_global);
7382958Sdr146992
7393448Sdh155122 frsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs);
7407176Syx160601 fr_natifpsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs);
7417176Syx160601 fr_nataddrsync(0, NULL, NULL, ifs);
7423448Sdh155122 fr_statesync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs);
7432958Sdr146992 error = 0;
7442393Syz155240 }
7452393Syz155240 break;
7462393Syz155240 case SIOCGFRST :
7473448Sdh155122 error = fr_outobj((void *)data, fr_fragstats(ifs),
7482393Syz155240 IPFOBJ_FRAGSTAT);
7492393Syz155240 break;
7502393Syz155240 case FIONREAD :
7512393Syz155240 #ifdef IPFILTER_LOG
7523448Sdh155122 tmp = (int)ifs->ifs_iplused[IPL_LOGIPF];
7532393Syz155240
7542393Syz155240 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, sizeof(tmp));
7552393Syz155240 if (error != 0)
7562393Syz155240 error = EFAULT;
7572393Syz155240 #endif
7582393Syz155240 break;
7593448Sdh155122 case SIOCIPFITER :
76011134SCasper.Dik@Sun.COM error = ipf_frruleiter((caddr_t)data, crgetuid(cp),
7617513SDarren.Reed@Sun.COM curproc, ifs);
7623448Sdh155122 break;
7633448Sdh155122
7643448Sdh155122 case SIOCGENITER :
76511134SCasper.Dik@Sun.COM error = ipf_genericiter((caddr_t)data, crgetuid(cp),
7667513SDarren.Reed@Sun.COM curproc, ifs);
7673448Sdh155122 break;
7683448Sdh155122
7693448Sdh155122 case SIOCIPFDELTOK :
7707433SJohn.Ojemann@Sun.COM error = BCOPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp));
7717433SJohn.Ojemann@Sun.COM if (error != 0) {
7727433SJohn.Ojemann@Sun.COM error = EFAULT;
7737433SJohn.Ojemann@Sun.COM } else {
77411134SCasper.Dik@Sun.COM error = ipf_deltoken(tmp, crgetuid(cp), curproc, ifs);
7757433SJohn.Ojemann@Sun.COM }
7763448Sdh155122 break;
7773448Sdh155122
7782393Syz155240 default :
7798624SDarren.Reed@Sun.COM #ifdef IPFDEBUG
7807513SDarren.Reed@Sun.COM cmn_err(CE_NOTE, "Unknown: cmd 0x%x data %p",
7817513SDarren.Reed@Sun.COM cmd, (void *)data);
7828624SDarren.Reed@Sun.COM #endif
7832393Syz155240 error = EINVAL;
7842393Syz155240 break;
7852393Syz155240 }
7863448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_global);
7872393Syz155240 return error;
7882393Syz155240 }
7892393Syz155240
7902393Syz155240
fr_enableipf(ifs,enable)7917513SDarren.Reed@Sun.COM static int fr_enableipf(ifs, enable)
7924477Sdr146992 ipf_stack_t *ifs;
7934477Sdr146992 int enable;
7944477Sdr146992 {
7954477Sdr146992 int error;
7964477Sdr146992
7976274Sjojemann if (!enable) {
7984477Sdr146992 error = ipldetach(ifs);
7994477Sdr146992 if (error == 0)
8004477Sdr146992 ifs->ifs_fr_running = -1;
8017513SDarren.Reed@Sun.COM return error;
8024477Sdr146992 }
8034477Sdr146992
8046274Sjojemann if (ifs->ifs_fr_running > 0)
8057513SDarren.Reed@Sun.COM return 0;
8066274Sjojemann
8077513SDarren.Reed@Sun.COM error = iplattach(ifs);
8086274Sjojemann if (error == 0) {
8096274Sjojemann if (ifs->ifs_fr_timer_id == NULL) {
8106274Sjojemann int hz = drv_usectohz(500000);
8116274Sjojemann
8126274Sjojemann ifs->ifs_fr_timer_id = timeout(fr_slowtimer,
8137513SDarren.Reed@Sun.COM (void *)ifs,
8147513SDarren.Reed@Sun.COM hz);
8156274Sjojemann }
8166274Sjojemann ifs->ifs_fr_running = 1;
8176274Sjojemann } else {
8186274Sjojemann (void) ipldetach(ifs);
8196274Sjojemann }
8207513SDarren.Reed@Sun.COM return error;
8214477Sdr146992 }
8224477Sdr146992
8234477Sdr146992
get_unit(name,v,ifs)8243448Sdh155122 phy_if_t get_unit(name, v, ifs)
8253448Sdh155122 char *name;
8263448Sdh155122 int v;
8273448Sdh155122 ipf_stack_t *ifs;
8282393Syz155240 {
8297513SDarren.Reed@Sun.COM net_handle_t nif;
8302958Sdr146992
8312958Sdr146992 if (v == 4)
8323448Sdh155122 nif = ifs->ifs_ipf_ipv4;
8332958Sdr146992 else if (v == 6)
8343448Sdh155122 nif = ifs->ifs_ipf_ipv6;
8352958Sdr146992 else
8362958Sdr146992 return 0;
8372393Syz155240
8383448Sdh155122 return (net_phylookup(nif, name));
8392393Syz155240 }
8402393Syz155240
8412393Syz155240 /*
8422393Syz155240 * routines below for saving IP headers to buffer
8432393Syz155240 */
8442393Syz155240 /*ARGSUSED*/
iplopen(devp,flags,otype,cred)8452393Syz155240 int iplopen(devp, flags, otype, cred)
8462393Syz155240 dev_t *devp;
8472393Syz155240 int flags, otype;
8482393Syz155240 cred_t *cred;
8492393Syz155240 {
8502393Syz155240 minor_t min = getminor(*devp);
8512393Syz155240
8522393Syz155240 #ifdef IPFDEBUG
8532393Syz155240 cmn_err(CE_CONT, "iplopen(%x,%x,%x,%x)\n", devp, flags, otype, cred);
8542393Syz155240 #endif
8552393Syz155240 if (!(otype & OTYP_CHR))
8562393Syz155240 return ENXIO;
8572393Syz155240
8582393Syz155240 min = (IPL_LOGMAX < min) ? ENXIO : 0;
8592393Syz155240 return min;
8602393Syz155240 }
8612393Syz155240
8622393Syz155240
8632393Syz155240 /*ARGSUSED*/
iplclose(dev,flags,otype,cred)8642393Syz155240 int iplclose(dev, flags, otype, cred)
8652393Syz155240 dev_t dev;
8662393Syz155240 int flags, otype;
8672393Syz155240 cred_t *cred;
8682393Syz155240 {
8692393Syz155240 minor_t min = getminor(dev);
8702393Syz155240
8712393Syz155240 #ifdef IPFDEBUG
8722393Syz155240 cmn_err(CE_CONT, "iplclose(%x,%x,%x,%x)\n", dev, flags, otype, cred);
8732393Syz155240 #endif
8742393Syz155240
8752393Syz155240 min = (IPL_LOGMAX < min) ? ENXIO : 0;
8762393Syz155240 return min;
8772393Syz155240 }
8782393Syz155240
8792393Syz155240 #ifdef IPFILTER_LOG
8802393Syz155240 /*
8812393Syz155240 * iplread/ipllog
8822393Syz155240 * both of these must operate with at least splnet() lest they be
8832393Syz155240 * called during packet processing and cause an inconsistancy to appear in
8842393Syz155240 * the filter lists.
8852393Syz155240 */
8862393Syz155240 /*ARGSUSED*/
iplread(dev,uio,cp)8872393Syz155240 int iplread(dev, uio, cp)
8882393Syz155240 dev_t dev;
8892393Syz155240 register struct uio *uio;
8902393Syz155240 cred_t *cp;
8912393Syz155240 {
8923448Sdh155122 ipf_stack_t *ifs;
8933448Sdh155122 int ret;
8943448Sdh155122
8957513SDarren.Reed@Sun.COM /*
8967513SDarren.Reed@Sun.COM * As we're calling ipf_find_stack in user space, from a given zone
8977513SDarren.Reed@Sun.COM * to find the stack pointer for this zone, there is no need to have
8987513SDarren.Reed@Sun.COM * a hold/refence count here.
8997513SDarren.Reed@Sun.COM */
9007513SDarren.Reed@Sun.COM ifs = ipf_find_stack(crgetzoneid(cp));
9013448Sdh155122 ASSERT(ifs != NULL);
9023448Sdh155122
9032393Syz155240 # ifdef IPFDEBUG
9042393Syz155240 cmn_err(CE_CONT, "iplread(%x,%x,%x)\n", dev, uio, cp);
9052393Syz155240 # endif
9063007Sdr146992
9073448Sdh155122 if (ifs->ifs_fr_running < 1) {
9083007Sdr146992 return EIO;
9093448Sdh155122 }
9103007Sdr146992
9112393Syz155240 # ifdef IPFILTER_SYNC
9123448Sdh155122 if (getminor(dev) == IPL_LOGSYNC) {
9132393Syz155240 return ipfsync_read(uio);
9143448Sdh155122 }
9152393Syz155240 # endif
9162393Syz155240
9173448Sdh155122 ret = ipflog_read(getminor(dev), uio, ifs);
9183448Sdh155122 return ret;
9192393Syz155240 }
9202393Syz155240 #endif /* IPFILTER_LOG */
9212393Syz155240
9222393Syz155240
9232393Syz155240 /*
9242393Syz155240 * iplread/ipllog
9252393Syz155240 * both of these must operate with at least splnet() lest they be
9262393Syz155240 * called during packet processing and cause an inconsistancy to appear in
9272393Syz155240 * the filter lists.
9282393Syz155240 */
iplwrite(dev,uio,cp)9292393Syz155240 int iplwrite(dev, uio, cp)
9302393Syz155240 dev_t dev;
9312393Syz155240 register struct uio *uio;
9322393Syz155240 cred_t *cp;
9332393Syz155240 {
9343448Sdh155122 ipf_stack_t *ifs;
9353448Sdh155122
9367513SDarren.Reed@Sun.COM /*
9377513SDarren.Reed@Sun.COM * As we're calling ipf_find_stack in user space, from a given zone
9387513SDarren.Reed@Sun.COM * to find the stack pointer for this zone, there is no need to have
9397513SDarren.Reed@Sun.COM * a hold/refence count here.
9407513SDarren.Reed@Sun.COM */
9417513SDarren.Reed@Sun.COM ifs = ipf_find_stack(crgetzoneid(cp));
9423448Sdh155122 ASSERT(ifs != NULL);
9433448Sdh155122
9442393Syz155240 #ifdef IPFDEBUG
9452393Syz155240 cmn_err(CE_CONT, "iplwrite(%x,%x,%x)\n", dev, uio, cp);
9462393Syz155240 #endif
9473007Sdr146992
9483448Sdh155122 if (ifs->ifs_fr_running < 1) {
9493007Sdr146992 return EIO;
9503448Sdh155122 }
9513007Sdr146992
9522393Syz155240 #ifdef IPFILTER_SYNC
9532393Syz155240 if (getminor(dev) == IPL_LOGSYNC)
9542393Syz155240 return ipfsync_write(uio);
9552393Syz155240 #endif /* IPFILTER_SYNC */
9562393Syz155240 dev = dev; /* LINT */
9572393Syz155240 uio = uio; /* LINT */
9582393Syz155240 cp = cp; /* LINT */
9592393Syz155240 return ENXIO;
9602393Syz155240 }
9612393Syz155240
9622393Syz155240
9632393Syz155240 /*
9642393Syz155240 * fr_send_reset - this could conceivably be a call to tcp_respond(), but that
9652393Syz155240 * requires a large amount of setting up and isn't any more efficient.
9662393Syz155240 */
fr_send_reset(fin)9672393Syz155240 int fr_send_reset(fin)
9682393Syz155240 fr_info_t *fin;
9692393Syz155240 {
9702393Syz155240 tcphdr_t *tcp, *tcp2;
9712393Syz155240 int tlen, hlen;
9722393Syz155240 mblk_t *m;
9732393Syz155240 #ifdef USE_INET6
9742393Syz155240 ip6_t *ip6;
9752393Syz155240 #endif
9762393Syz155240 ip_t *ip;
9772393Syz155240
9782393Syz155240 tcp = fin->fin_dp;
9792393Syz155240 if (tcp->th_flags & TH_RST)
9802393Syz155240 return -1;
9812393Syz155240
9822393Syz155240 #ifndef IPFILTER_CKSUM
9832393Syz155240 if (fr_checkl4sum(fin) == -1)
9842393Syz155240 return -1;
9852393Syz155240 #endif
9862393Syz155240
9872393Syz155240 tlen = (tcp->th_flags & (TH_SYN|TH_FIN)) ? 1 : 0;
9882393Syz155240 #ifdef USE_INET6
9892393Syz155240 if (fin->fin_v == 6)
9902393Syz155240 hlen = sizeof(ip6_t);
9912393Syz155240 else
9922393Syz155240 #endif
9932393Syz155240 hlen = sizeof(ip_t);
9942393Syz155240 hlen += sizeof(*tcp2);
9952393Syz155240 if ((m = (mblk_t *)allocb(hlen + 64, BPRI_HI)) == NULL)
9962393Syz155240 return -1;
9972393Syz155240
9982393Syz155240 m->b_rptr += 64;
9992393Syz155240 MTYPE(m) = M_DATA;
10002393Syz155240 m->b_wptr = m->b_rptr + hlen;
10012393Syz155240 ip = (ip_t *)m->b_rptr;
10022393Syz155240 bzero((char *)ip, hlen);
10032393Syz155240 tcp2 = (struct tcphdr *)(m->b_rptr + hlen - sizeof(*tcp2));
10042393Syz155240 tcp2->th_dport = tcp->th_sport;
10052393Syz155240 tcp2->th_sport = tcp->th_dport;
10062393Syz155240 if (tcp->th_flags & TH_ACK) {
10072393Syz155240 tcp2->th_seq = tcp->th_ack;
10082393Syz155240 tcp2->th_flags = TH_RST;
10092393Syz155240 } else {
10102393Syz155240 tcp2->th_ack = ntohl(tcp->th_seq);
10112393Syz155240 tcp2->th_ack += tlen;
10122393Syz155240 tcp2->th_ack = htonl(tcp2->th_ack);
10132393Syz155240 tcp2->th_flags = TH_RST|TH_ACK;
10142393Syz155240 }
10152393Syz155240 tcp2->th_off = sizeof(struct tcphdr) >> 2;
10162393Syz155240
10172393Syz155240 ip->ip_v = fin->fin_v;
10182393Syz155240 #ifdef USE_INET6
10192393Syz155240 if (fin->fin_v == 6) {
10202393Syz155240 ip6 = (ip6_t *)m->b_rptr;
10212393Syz155240 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
10227176Syx160601 ip6->ip6_src = fin->fin_dst6.in6;
10237176Syx160601 ip6->ip6_dst = fin->fin_src6.in6;
10242393Syz155240 ip6->ip6_plen = htons(sizeof(*tcp));
10252393Syz155240 ip6->ip6_nxt = IPPROTO_TCP;
10262393Syz155240 tcp2->th_sum = fr_cksum(m, (ip_t *)ip6, IPPROTO_TCP, tcp2);
10272393Syz155240 } else
10282393Syz155240 #endif
10292393Syz155240 {
10302393Syz155240 ip->ip_src.s_addr = fin->fin_daddr;
10312393Syz155240 ip->ip_dst.s_addr = fin->fin_saddr;
10322393Syz155240 ip->ip_id = fr_nextipid(fin);
10332393Syz155240 ip->ip_hl = sizeof(*ip) >> 2;
10342393Syz155240 ip->ip_p = IPPROTO_TCP;
10352393Syz155240 ip->ip_len = sizeof(*ip) + sizeof(*tcp);
10362393Syz155240 ip->ip_tos = fin->fin_ip->ip_tos;
10372393Syz155240 tcp2->th_sum = fr_cksum(m, ip, IPPROTO_TCP, tcp2);
10382393Syz155240 }
10392393Syz155240 return fr_send_ip(fin, m, &m);
10402393Syz155240 }
10412393Syz155240
10422393Syz155240 /*
10432393Syz155240 * Function: fr_send_ip
10442393Syz155240 * Returns: 0: success
10452393Syz155240 * -1: failed
10462393Syz155240 * Parameters:
10472393Syz155240 * fin: packet information
10482393Syz155240 * m: the message block where ip head starts
10492393Syz155240 *
10502393Syz155240 * Send a new packet through the IP stack.
10512393Syz155240 *
10522393Syz155240 * For IPv4 packets, ip_len must be in host byte order, and ip_v,
10532393Syz155240 * ip_ttl, ip_off, and ip_sum are ignored (filled in by this
10542393Syz155240 * function).
10552393Syz155240 *
10562393Syz155240 * For IPv6 packets, ip6_flow, ip6_vfc, and ip6_hlim are filled
10572393Syz155240 * in by this function.
10582393Syz155240 *
10592393Syz155240 * All other portions of the packet must be in on-the-wire format.
10602393Syz155240 */
10612393Syz155240 /*ARGSUSED*/
fr_send_ip(fin,m,mpp)10622393Syz155240 static int fr_send_ip(fin, m, mpp)
10632393Syz155240 fr_info_t *fin;
10642393Syz155240 mblk_t *m, **mpp;
10652393Syz155240 {
10662393Syz155240 qpktinfo_t qpi, *qpip;
10672393Syz155240 fr_info_t fnew;
10682393Syz155240 ip_t *ip;
10692393Syz155240 int i, hlen;
10703448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs;
10712393Syz155240
10722393Syz155240 ip = (ip_t *)m->b_rptr;
10732393Syz155240 bzero((char *)&fnew, sizeof(fnew));
10742393Syz155240
10752393Syz155240 #ifdef USE_INET6
10762393Syz155240 if (fin->fin_v == 6) {
10772393Syz155240 ip6_t *ip6;
10782393Syz155240
10792393Syz155240 ip6 = (ip6_t *)ip;
10802393Syz155240 ip6->ip6_vfc = 0x60;
10812393Syz155240 ip6->ip6_hlim = 127;
10822393Syz155240 fnew.fin_v = 6;
10832393Syz155240 hlen = sizeof(*ip6);
10842596Szf203873 fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen;
10852393Syz155240 } else
10862393Syz155240 #endif
10872393Syz155240 {
10882393Syz155240 fnew.fin_v = 4;
10892393Syz155240 #if SOLARIS2 >= 10
10902393Syz155240 ip->ip_ttl = 255;
10913448Sdh155122 if (net_getpmtuenabled(ifs->ifs_ipf_ipv4) == 1)
10922958Sdr146992 ip->ip_off = htons(IP_DF);
10932393Syz155240 #else
10942393Syz155240 if (ip_ttl_ptr != NULL)
10952393Syz155240 ip->ip_ttl = (u_char)(*ip_ttl_ptr);
10962393Syz155240 else
10972393Syz155240 ip->ip_ttl = 63;
10982393Syz155240 if (ip_mtudisc != NULL)
10992393Syz155240 ip->ip_off = htons(*ip_mtudisc ? IP_DF : 0);
11002393Syz155240 else
11012393Syz155240 ip->ip_off = htons(IP_DF);
11022393Syz155240 #endif
11032393Syz155240 /*
11042393Syz155240 * The dance with byte order and ip_len/ip_off is because in
11052393Syz155240 * fr_fastroute, it expects them to be in host byte order but
11062393Syz155240 * ipf_cksum expects them to be in network byte order.
11072393Syz155240 */
11082393Syz155240 ip->ip_len = htons(ip->ip_len);
11092393Syz155240 ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip));
11102393Syz155240 ip->ip_len = ntohs(ip->ip_len);
11112393Syz155240 ip->ip_off = ntohs(ip->ip_off);
11122393Syz155240 hlen = sizeof(*ip);
11132596Szf203873 fnew.fin_plen = ip->ip_len;
11142393Syz155240 }
11152393Syz155240
11162393Syz155240 qpip = fin->fin_qpi;
11172393Syz155240 qpi.qpi_off = 0;
11182958Sdr146992 qpi.qpi_ill = qpip->qpi_ill;
11192393Syz155240 qpi.qpi_m = m;
11202393Syz155240 qpi.qpi_data = ip;
11212393Syz155240 fnew.fin_qpi = &qpi;
11222393Syz155240 fnew.fin_ifp = fin->fin_ifp;
11232393Syz155240 fnew.fin_flx = FI_NOCKSUM;
11242393Syz155240 fnew.fin_m = m;
11257333SJohn.Ojemann@Sun.COM fnew.fin_qfm = m;
11262393Syz155240 fnew.fin_ip = ip;
11272393Syz155240 fnew.fin_mp = mpp;
11282393Syz155240 fnew.fin_hlen = hlen;
11292393Syz155240 fnew.fin_dp = (char *)ip + hlen;
11303448Sdh155122 fnew.fin_ifs = fin->fin_ifs;
11312393Syz155240 (void) fr_makefrip(hlen, ip, &fnew);
11322393Syz155240
11332393Syz155240 i = fr_fastroute(m, mpp, &fnew, NULL);
11342393Syz155240 return i;
11352393Syz155240 }
11362393Syz155240
11372393Syz155240
fr_send_icmp_err(type,fin,dst)11382393Syz155240 int fr_send_icmp_err(type, fin, dst)
11392393Syz155240 int type;
11402393Syz155240 fr_info_t *fin;
11412393Syz155240 int dst;
11422393Syz155240 {
11432393Syz155240 struct in_addr dst4;
11442393Syz155240 struct icmp *icmp;
11452393Syz155240 qpktinfo_t *qpi;
11462393Syz155240 int hlen, code;
11472958Sdr146992 phy_if_t phy;
11482393Syz155240 u_short sz;
11492393Syz155240 #ifdef USE_INET6
11502393Syz155240 mblk_t *mb;
11512393Syz155240 #endif
11522393Syz155240 mblk_t *m;
11532393Syz155240 #ifdef USE_INET6
11542393Syz155240 ip6_t *ip6;
11552393Syz155240 #endif
11562393Syz155240 ip_t *ip;
11573448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs;
11582393Syz155240
11592393Syz155240 if ((type < 0) || (type > ICMP_MAXTYPE))
11602393Syz155240 return -1;
11612393Syz155240
11622393Syz155240 code = fin->fin_icode;
11632393Syz155240 #ifdef USE_INET6
11648624SDarren.Reed@Sun.COM if ((code < 0) || (code >= ICMP_MAX_UNREACH))
11652393Syz155240 return -1;
11662393Syz155240 #endif
11672393Syz155240
11682393Syz155240 #ifndef IPFILTER_CKSUM
11692393Syz155240 if (fr_checkl4sum(fin) == -1)
11702393Syz155240 return -1;
11712393Syz155240 #endif
11722393Syz155240
11732393Syz155240 qpi = fin->fin_qpi;
11742393Syz155240
11752393Syz155240 #ifdef USE_INET6
11762393Syz155240 mb = fin->fin_qfm;
11772393Syz155240
11782393Syz155240 if (fin->fin_v == 6) {
11792393Syz155240 sz = sizeof(ip6_t);
11802393Syz155240 sz += MIN(mb->b_wptr - mb->b_rptr, 512);
11812393Syz155240 hlen = sizeof(ip6_t);
11822393Syz155240 type = icmptoicmp6types[type];
11832393Syz155240 if (type == ICMP6_DST_UNREACH)
11842393Syz155240 code = icmptoicmp6unreach[code];
11852393Syz155240 } else
11862393Syz155240 #endif
11872393Syz155240 {
11882393Syz155240 if ((fin->fin_p == IPPROTO_ICMP) &&
11892393Syz155240 !(fin->fin_flx & FI_SHORT))
11902393Syz155240 switch (ntohs(fin->fin_data[0]) >> 8)
11912393Syz155240 {
11922393Syz155240 case ICMP_ECHO :
11932393Syz155240 case ICMP_TSTAMP :
11942393Syz155240 case ICMP_IREQ :
11952393Syz155240 case ICMP_MASKREQ :
11962393Syz155240 break;
11972393Syz155240 default :
11982393Syz155240 return 0;
11992393Syz155240 }
12002393Syz155240
12012393Syz155240 sz = sizeof(ip_t) * 2;
12022393Syz155240 sz += 8; /* 64 bits of data */
12032393Syz155240 hlen = sizeof(ip_t);
12042393Syz155240 }
12052393Syz155240
12062393Syz155240 sz += offsetof(struct icmp, icmp_ip);
12072393Syz155240 if ((m = (mblk_t *)allocb((size_t)sz + 64, BPRI_HI)) == NULL)
12082393Syz155240 return -1;
12092393Syz155240 MTYPE(m) = M_DATA;
12102393Syz155240 m->b_rptr += 64;
12112393Syz155240 m->b_wptr = m->b_rptr + sz;
12122393Syz155240 bzero((char *)m->b_rptr, (size_t)sz);
12132393Syz155240 ip = (ip_t *)m->b_rptr;
12142393Syz155240 ip->ip_v = fin->fin_v;
12152393Syz155240 icmp = (struct icmp *)(m->b_rptr + hlen);
12162393Syz155240 icmp->icmp_type = type & 0xff;
12172393Syz155240 icmp->icmp_code = code & 0xff;
12182958Sdr146992 phy = (phy_if_t)qpi->qpi_ill;
12192958Sdr146992 if (type == ICMP_UNREACH && (phy != 0) &&
12202393Syz155240 fin->fin_icode == ICMP_UNREACH_NEEDFRAG)
12213448Sdh155122 icmp->icmp_nextmtu = net_getmtu(ifs->ifs_ipf_ipv4, phy,0 );
12222393Syz155240
12232393Syz155240 #ifdef USE_INET6
12242393Syz155240 if (fin->fin_v == 6) {
12252393Syz155240 struct in6_addr dst6;
12262393Syz155240 int csz;
12272393Syz155240
12282393Syz155240 if (dst == 0) {
12293448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs;
12303448Sdh155122
12312958Sdr146992 if (fr_ifpaddr(6, FRI_NORMAL, (void *)phy,
12323448Sdh155122 (void *)&dst6, NULL, ifs) == -1) {
12332393Syz155240 FREE_MB_T(m);
12342393Syz155240 return -1;
12352393Syz155240 }
12362393Syz155240 } else
12377176Syx160601 dst6 = fin->fin_dst6.in6;
12382393Syz155240
12392393Syz155240 csz = sz;
12402393Syz155240 sz -= sizeof(ip6_t);
12412393Syz155240 ip6 = (ip6_t *)m->b_rptr;
12422393Syz155240 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
12432393Syz155240 ip6->ip6_plen = htons((u_short)sz);
12442393Syz155240 ip6->ip6_nxt = IPPROTO_ICMPV6;
12452393Syz155240 ip6->ip6_src = dst6;
12467176Syx160601 ip6->ip6_dst = fin->fin_src6.in6;
12472393Syz155240 sz -= offsetof(struct icmp, icmp_ip);
12482393Syz155240 bcopy((char *)mb->b_rptr, (char *)&icmp->icmp_ip, sz);
12492393Syz155240 icmp->icmp_cksum = csz - sizeof(ip6_t);
12502393Syz155240 } else
12512393Syz155240 #endif
12522393Syz155240 {
12532393Syz155240 ip->ip_hl = sizeof(*ip) >> 2;
12542393Syz155240 ip->ip_p = IPPROTO_ICMP;
12552393Syz155240 ip->ip_id = fin->fin_ip->ip_id;
12562393Syz155240 ip->ip_tos = fin->fin_ip->ip_tos;
12572393Syz155240 ip->ip_len = (u_short)sz;
12582393Syz155240 if (dst == 0) {
12593448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs;
12603448Sdh155122
12612958Sdr146992 if (fr_ifpaddr(4, FRI_NORMAL, (void *)phy,
12623448Sdh155122 (void *)&dst4, NULL, ifs) == -1) {
12632393Syz155240 FREE_MB_T(m);
12642393Syz155240 return -1;
12652393Syz155240 }
12662958Sdr146992 } else {
12672393Syz155240 dst4 = fin->fin_dst;
12682958Sdr146992 }
12692393Syz155240 ip->ip_src = dst4;
12702393Syz155240 ip->ip_dst = fin->fin_src;
12712393Syz155240 bcopy((char *)fin->fin_ip, (char *)&icmp->icmp_ip,
12722393Syz155240 sizeof(*fin->fin_ip));
12732393Syz155240 bcopy((char *)fin->fin_ip + fin->fin_hlen,
12742393Syz155240 (char *)&icmp->icmp_ip + sizeof(*fin->fin_ip), 8);
12752393Syz155240 icmp->icmp_ip.ip_len = htons(icmp->icmp_ip.ip_len);
12762393Syz155240 icmp->icmp_ip.ip_off = htons(icmp->icmp_ip.ip_off);
12772393Syz155240 icmp->icmp_cksum = ipf_cksum((u_short *)icmp,
12782393Syz155240 sz - sizeof(ip_t));
12792393Syz155240 }
12802393Syz155240
12812393Syz155240 /*
12822393Syz155240 * Need to exit out of these so we don't recursively call rw_enter
12832393Syz155240 * from fr_qout.
12842393Syz155240 */
12852393Syz155240 return fr_send_ip(fin, m, &m);
12862393Syz155240 }
12872393Syz155240
12882393Syz155240 #include <sys/time.h>
12892393Syz155240 #include <sys/varargs.h>
12902393Syz155240
12912393Syz155240 #ifndef _KERNEL
12922393Syz155240 #include <stdio.h>
12932393Syz155240 #endif
12942393Syz155240
12952393Syz155240 #define NULLADDR_RATE_LIMIT 10 /* 10 seconds */
12962393Syz155240
12972393Syz155240
12982393Syz155240 /*
12992393Syz155240 * Print out warning message at rate-limited speed.
13002393Syz155240 */
rate_limit_message(ipf_stack_t * ifs,int rate,const char * message,...)13013448Sdh155122 static void rate_limit_message(ipf_stack_t *ifs,
13023448Sdh155122 int rate, const char *message, ...)
13032393Syz155240 {
13042393Syz155240 static time_t last_time = 0;
13052393Syz155240 time_t now;
13062393Syz155240 va_list args;
13072393Syz155240 char msg_buf[256];
13082393Syz155240 int need_printed = 0;
13092393Syz155240
13102393Syz155240 now = ddi_get_time();
13112393Syz155240
13122393Syz155240 /* make sure, no multiple entries */
13133448Sdh155122 ASSERT(MUTEX_NOT_HELD(&(ifs->ifs_ipf_rw.ipf_lk)));
13143448Sdh155122 MUTEX_ENTER(&ifs->ifs_ipf_rw);
13152393Syz155240 if (now - last_time >= rate) {
13162393Syz155240 need_printed = 1;
13172393Syz155240 last_time = now;
13182393Syz155240 }
13193448Sdh155122 MUTEX_EXIT(&ifs->ifs_ipf_rw);
13202393Syz155240
13212393Syz155240 if (need_printed) {
13222393Syz155240 va_start(args, message);
13232393Syz155240 (void)vsnprintf(msg_buf, 255, message, args);
13242393Syz155240 va_end(args);
13252393Syz155240 #ifdef _KERNEL
13262393Syz155240 cmn_err(CE_WARN, msg_buf);
13272393Syz155240 #else
13282393Syz155240 fprintf(std_err, msg_buf);
13292393Syz155240 #endif
13302393Syz155240 }
13312393Syz155240 }
13322393Syz155240
13332393Syz155240 /*
13349876SDarren.Reed@Sun.COM * Return the first IP Address associated with an interface
13359876SDarren.Reed@Sun.COM * For IPv6, we walk through the list of logical interfaces and return
13369876SDarren.Reed@Sun.COM * the address of the first one that isn't a link-local interface.
13379876SDarren.Reed@Sun.COM * We can't assume that it is :1 because another link-local address
13389876SDarren.Reed@Sun.COM * may have been assigned there.
13392393Syz155240 */
13402393Syz155240 /*ARGSUSED*/
fr_ifpaddr(v,atype,ifptr,inp,inpmask,ifs)13413448Sdh155122 int fr_ifpaddr(v, atype, ifptr, inp, inpmask, ifs)
13422393Syz155240 int v, atype;
13432958Sdr146992 void *ifptr;
13442958Sdr146992 struct in_addr *inp, *inpmask;
13453448Sdh155122 ipf_stack_t *ifs;
13462393Syz155240 {
13472958Sdr146992 struct sockaddr_in6 v6addr[2];
13482958Sdr146992 struct sockaddr_in v4addr[2];
13492958Sdr146992 net_ifaddr_t type[2];
13507513SDarren.Reed@Sun.COM net_handle_t net_data;
13512958Sdr146992 phy_if_t phyif;
13522958Sdr146992 void *array;
13532393Syz155240
13542958Sdr146992 switch (v)
13552958Sdr146992 {
13562958Sdr146992 case 4:
13573448Sdh155122 net_data = ifs->ifs_ipf_ipv4;
13582958Sdr146992 array = v4addr;
13592958Sdr146992 break;
13602958Sdr146992 case 6:
13613448Sdh155122 net_data = ifs->ifs_ipf_ipv6;
13622958Sdr146992 array = v6addr;
13632958Sdr146992 break;
13642958Sdr146992 default:
13652958Sdr146992 net_data = NULL;
13662958Sdr146992 break;
13672958Sdr146992 }
13682958Sdr146992
13692958Sdr146992 if (net_data == NULL)
13702393Syz155240 return -1;
13712393Syz155240
13722958Sdr146992 phyif = (phy_if_t)ifptr;
13732393Syz155240
13742393Syz155240 switch (atype)
13752393Syz155240 {
13762958Sdr146992 case FRI_PEERADDR :
13772958Sdr146992 type[0] = NA_PEER;
13782393Syz155240 break;
13792958Sdr146992
13802958Sdr146992 case FRI_BROADCAST :
13812958Sdr146992 type[0] = NA_BROADCAST;
13822393Syz155240 break;
13832958Sdr146992
13842393Syz155240 default :
13852958Sdr146992 type[0] = NA_ADDRESS;
13862393Syz155240 break;
13872393Syz155240 }
13882958Sdr146992
13892958Sdr146992 type[1] = NA_NETMASK;
13902393Syz155240
13919876SDarren.Reed@Sun.COM if (v == 6) {
13929876SDarren.Reed@Sun.COM lif_if_t idx = 0;
13939876SDarren.Reed@Sun.COM
13949876SDarren.Reed@Sun.COM do {
13959876SDarren.Reed@Sun.COM idx = net_lifgetnext(net_data, phyif, idx);
13969876SDarren.Reed@Sun.COM if (net_getlifaddr(net_data, phyif, idx, 2, type,
13979876SDarren.Reed@Sun.COM array) < 0)
13989876SDarren.Reed@Sun.COM return -1;
13999876SDarren.Reed@Sun.COM if (!IN6_IS_ADDR_LINKLOCAL(&v6addr[0].sin6_addr) &&
14009876SDarren.Reed@Sun.COM !IN6_IS_ADDR_MULTICAST(&v6addr[0].sin6_addr))
14019876SDarren.Reed@Sun.COM break;
14029876SDarren.Reed@Sun.COM } while (idx != 0);
14039876SDarren.Reed@Sun.COM
14049876SDarren.Reed@Sun.COM if (idx == 0)
14059876SDarren.Reed@Sun.COM return -1;
14069876SDarren.Reed@Sun.COM
14079876SDarren.Reed@Sun.COM return fr_ifpfillv6addr(atype, &v6addr[0], &v6addr[1],
14089876SDarren.Reed@Sun.COM inp, inpmask);
14099876SDarren.Reed@Sun.COM }
14109876SDarren.Reed@Sun.COM
14112958Sdr146992 if (net_getlifaddr(net_data, phyif, 0, 2, type, array) < 0)
14122393Syz155240 return -1;
14132958Sdr146992
14142958Sdr146992 return fr_ifpfillv4addr(atype, &v4addr[0], &v4addr[1], inp, inpmask);
14152393Syz155240 }
14162393Syz155240
14172393Syz155240
fr_newisn(fin)14182393Syz155240 u_32_t fr_newisn(fin)
14192393Syz155240 fr_info_t *fin;
14202393Syz155240 {
14212393Syz155240 static int iss_seq_off = 0;
14222393Syz155240 u_char hash[16];
14232393Syz155240 u_32_t newiss;
14242393Syz155240 MD5_CTX ctx;
14253448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs;
14262393Syz155240
14272393Syz155240 /*
14282393Syz155240 * Compute the base value of the ISS. It is a hash
14292393Syz155240 * of (saddr, sport, daddr, dport, secret).
14302393Syz155240 */
14312393Syz155240 MD5Init(&ctx);
14322393Syz155240
14332393Syz155240 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
14342393Syz155240 sizeof(fin->fin_fi.fi_src));
14352393Syz155240 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
14362393Syz155240 sizeof(fin->fin_fi.fi_dst));
14372393Syz155240 MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
14382393Syz155240
14393448Sdh155122 MD5Update(&ctx, ifs->ifs_ipf_iss_secret, sizeof(ifs->ifs_ipf_iss_secret));
14402393Syz155240
14412393Syz155240 MD5Final(hash, &ctx);
14422393Syz155240
14432393Syz155240 bcopy(hash, &newiss, sizeof(newiss));
14442393Syz155240
14452393Syz155240 /*
14462393Syz155240 * Now increment our "timer", and add it in to
14472393Syz155240 * the computed value.
14482393Syz155240 *
14492393Syz155240 * XXX Use `addin'?
14502393Syz155240 * XXX TCP_ISSINCR too large to use?
14512393Syz155240 */
14522393Syz155240 iss_seq_off += 0x00010000;
14532393Syz155240 newiss += iss_seq_off;
14542393Syz155240 return newiss;
14552393Syz155240 }
14562393Syz155240
14572393Syz155240
14582393Syz155240 /* ------------------------------------------------------------------------ */
14592393Syz155240 /* Function: fr_nextipid */
14602393Syz155240 /* Returns: int - 0 == success, -1 == error (packet should be droppped) */
14612393Syz155240 /* Parameters: fin(I) - pointer to packet information */
14622393Syz155240 /* */
14632393Syz155240 /* Returns the next IPv4 ID to use for this packet. */
14642393Syz155240 /* ------------------------------------------------------------------------ */
fr_nextipid(fin)14652393Syz155240 u_short fr_nextipid(fin)
14662393Syz155240 fr_info_t *fin;
14672393Syz155240 {
14682393Syz155240 static u_short ipid = 0;
14692393Syz155240 u_short id;
14703448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs;
14712393Syz155240
14723448Sdh155122 MUTEX_ENTER(&ifs->ifs_ipf_rw);
14738624SDarren.Reed@Sun.COM if (fin->fin_pktnum != 0) {
14748624SDarren.Reed@Sun.COM id = fin->fin_pktnum & 0xffff;
14758624SDarren.Reed@Sun.COM } else {
14762393Syz155240 id = ipid++;
14778624SDarren.Reed@Sun.COM }
14783448Sdh155122 MUTEX_EXIT(&ifs->ifs_ipf_rw);
14792393Syz155240
14802393Syz155240 return id;
14812393Syz155240 }
14822393Syz155240
14832393Syz155240
14842393Syz155240 #ifndef IPFILTER_CKSUM
14852393Syz155240 /* ARGSUSED */
14862393Syz155240 #endif
fr_checkv4sum(fin)14872393Syz155240 INLINE void fr_checkv4sum(fin)
14882393Syz155240 fr_info_t *fin;
14892393Syz155240 {
14902393Syz155240 #ifdef IPFILTER_CKSUM
14912393Syz155240 if (fr_checkl4sum(fin) == -1)
14922393Syz155240 fin->fin_flx |= FI_BAD;
14932393Syz155240 #endif
14942393Syz155240 }
14952393Syz155240
14962393Syz155240
14972393Syz155240 #ifdef USE_INET6
14982393Syz155240 # ifndef IPFILTER_CKSUM
14992393Syz155240 /* ARGSUSED */
15002393Syz155240 # endif
fr_checkv6sum(fin)15012393Syz155240 INLINE void fr_checkv6sum(fin)
15022393Syz155240 fr_info_t *fin;
15032393Syz155240 {
15042393Syz155240 # ifdef IPFILTER_CKSUM
15052393Syz155240 if (fr_checkl4sum(fin) == -1)
15062393Syz155240 fin->fin_flx |= FI_BAD;
15072393Syz155240 # endif
15082393Syz155240 }
15092393Syz155240 #endif /* USE_INET6 */
15102393Syz155240
15112393Syz155240
15122393Syz155240 #if (SOLARIS2 < 7)
fr_slowtimer()15132393Syz155240 void fr_slowtimer()
15142393Syz155240 #else
15152393Syz155240 /*ARGSUSED*/
15163448Sdh155122 void fr_slowtimer __P((void *arg))
15172393Syz155240 #endif
15182393Syz155240 {
15193448Sdh155122 ipf_stack_t *ifs = arg;
15202393Syz155240
15216274Sjojemann READ_ENTER(&ifs->ifs_ipf_global);
15226274Sjojemann if (ifs->ifs_fr_running != 1) {
15236274Sjojemann ifs->ifs_fr_timer_id = NULL;
15243448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_global);
15252393Syz155240 return;
15262393Syz155240 }
15275941Szf203873 ipf_expiretokens(ifs);
15283448Sdh155122 fr_fragexpire(ifs);
15293448Sdh155122 fr_timeoutstate(ifs);
15303448Sdh155122 fr_natexpire(ifs);
15313448Sdh155122 fr_authexpire(ifs);
15323448Sdh155122 ifs->ifs_fr_ticks++;
15336274Sjojemann if (ifs->ifs_fr_running == 1)
15343448Sdh155122 ifs->ifs_fr_timer_id = timeout(fr_slowtimer, arg,
15353448Sdh155122 drv_usectohz(500000));
15362393Syz155240 else
15373448Sdh155122 ifs->ifs_fr_timer_id = NULL;
15383448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_global);
15392393Syz155240 }
15402393Syz155240
15412393Syz155240
15422393Syz155240 /* ------------------------------------------------------------------------ */
15432393Syz155240 /* Function: fr_pullup */
15442393Syz155240 /* Returns: NULL == pullup failed, else pointer to protocol header */
15452393Syz155240 /* Parameters: m(I) - pointer to buffer where data packet starts */
15462393Syz155240 /* fin(I) - pointer to packet information */
15472393Syz155240 /* len(I) - number of bytes to pullup */
15482393Syz155240 /* */
15492393Syz155240 /* Attempt to move at least len bytes (from the start of the buffer) into a */
15502393Syz155240 /* single buffer for ease of access. Operating system native functions are */
15512393Syz155240 /* used to manage buffers - if necessary. If the entire packet ends up in */
15522393Syz155240 /* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */
15532393Syz155240 /* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */
15542393Syz155240 /* and ONLY if the pullup succeeds. */
15552393Syz155240 /* */
15562393Syz155240 /* We assume that 'min' is a pointer to a buffer that is part of the chain */
15572393Syz155240 /* of buffers that starts at *fin->fin_mp. */
15582393Syz155240 /* ------------------------------------------------------------------------ */
fr_pullup(min,fin,len)15592393Syz155240 void *fr_pullup(min, fin, len)
15602393Syz155240 mb_t *min;
15612393Syz155240 fr_info_t *fin;
15622393Syz155240 int len;
15632393Syz155240 {
15642393Syz155240 qpktinfo_t *qpi = fin->fin_qpi;
15652393Syz155240 int out = fin->fin_out, dpoff, ipoff;
15662958Sdr146992 mb_t *m = min, *m1, *m2;
15672393Syz155240 char *ip;
15683007Sdr146992 uint32_t start, stuff, end, value, flags;
15693448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs;
15702393Syz155240
15712393Syz155240 if (m == NULL)
15722393Syz155240 return NULL;
15732393Syz155240
15742393Syz155240 ip = (char *)fin->fin_ip;
15752393Syz155240 if ((fin->fin_flx & FI_COALESCE) != 0)
15762393Syz155240 return ip;
15772393Syz155240
15782393Syz155240 ipoff = fin->fin_ipoff;
15792393Syz155240 if (fin->fin_dp != NULL)
15802393Syz155240 dpoff = (char *)fin->fin_dp - (char *)ip;
15812393Syz155240 else
15822393Syz155240 dpoff = 0;
15832393Syz155240
15847704SAlexandr.Nedvedicky@Sun.COM if (M_LEN(m) < len + ipoff) {
15852393Syz155240
15862393Syz155240 /*
15872393Syz155240 * pfil_precheck ensures the IP header is on a 32bit
15882393Syz155240 * aligned address so simply fail if that isn't currently
15892393Syz155240 * the case (should never happen).
15902393Syz155240 */
15912393Syz155240 int inc = 0;
15922393Syz155240
15932393Syz155240 if (ipoff > 0) {
15942393Syz155240 if ((ipoff & 3) != 0) {
15952393Syz155240 inc = 4 - (ipoff & 3);
15962393Syz155240 if (m->b_rptr - inc >= m->b_datap->db_base)
15972393Syz155240 m->b_rptr -= inc;
15982393Syz155240 else
15992393Syz155240 inc = 0;
16002393Syz155240 }
16012393Syz155240 }
16022958Sdr146992
16032958Sdr146992 /*
16042958Sdr146992 * XXX This is here as a work around for a bug with DEBUG
16052958Sdr146992 * XXX Solaris kernels. The problem is b_prev is used by IP
16062958Sdr146992 * XXX code as a way to stash the phyint_index for a packet,
16072958Sdr146992 * XXX this doesn't get reset by IP but freeb does an ASSERT()
16082958Sdr146992 * XXX for both of these to be NULL. See 6442390.
16092958Sdr146992 */
16102958Sdr146992 m1 = m;
16112958Sdr146992 m2 = m->b_prev;
16122958Sdr146992
16132958Sdr146992 do {
16142958Sdr146992 m1->b_next = NULL;
16152958Sdr146992 m1->b_prev = NULL;
16162958Sdr146992 m1 = m1->b_cont;
16172958Sdr146992 } while (m1);
16183007Sdr146992
16193007Sdr146992 /*
16203007Sdr146992 * Need to preserve checksum information by copying them
16213007Sdr146992 * to newmp which heads the pulluped message.
16223007Sdr146992 */
16233007Sdr146992 hcksum_retrieve(m, NULL, NULL, &start, &stuff, &end,
16243007Sdr146992 &value, &flags);
16253007Sdr146992
16262393Syz155240 if (pullupmsg(m, len + ipoff + inc) == 0) {
16273448Sdh155122 ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[1]);
16282393Syz155240 FREE_MB_T(*fin->fin_mp);
16292393Syz155240 *fin->fin_mp = NULL;
16302393Syz155240 fin->fin_m = NULL;
16312393Syz155240 fin->fin_ip = NULL;
16322393Syz155240 fin->fin_dp = NULL;
16332393Syz155240 qpi->qpi_data = NULL;
16342393Syz155240 return NULL;
16352393Syz155240 }
16363007Sdr146992
16373007Sdr146992 (void) hcksum_assoc(m, NULL, NULL, start, stuff, end,
16383007Sdr146992 value, flags, 0);
16393007Sdr146992
16402958Sdr146992 m->b_prev = m2;
16412393Syz155240 m->b_rptr += inc;
16422393Syz155240 fin->fin_m = m;
16432393Syz155240 ip = MTOD(m, char *) + ipoff;
16442393Syz155240 qpi->qpi_data = ip;
16452393Syz155240 }
16462393Syz155240
16473448Sdh155122 ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[0]);
16482393Syz155240 fin->fin_ip = (ip_t *)ip;
16492393Syz155240 if (fin->fin_dp != NULL)
16502393Syz155240 fin->fin_dp = (char *)fin->fin_ip + dpoff;
16512393Syz155240
16522393Syz155240 if (len == fin->fin_plen)
16532393Syz155240 fin->fin_flx |= FI_COALESCE;
16542393Syz155240 return ip;
16552393Syz155240 }
16562958Sdr146992
16572958Sdr146992
16582958Sdr146992 /*
16592958Sdr146992 * Function: fr_verifysrc
16602958Sdr146992 * Returns: int (really boolean)
16612958Sdr146992 * Parameters: fin - packet information
16622958Sdr146992 *
16632958Sdr146992 * Check whether the packet has a valid source address for the interface on
16642958Sdr146992 * which the packet arrived, implementing the "fr_chksrc" feature.
16652958Sdr146992 * Returns true iff the packet's source address is valid.
16662958Sdr146992 */
fr_verifysrc(fin)16672958Sdr146992 int fr_verifysrc(fin)
16682958Sdr146992 fr_info_t *fin;
16692958Sdr146992 {
16707513SDarren.Reed@Sun.COM net_handle_t net_data_p;
16712958Sdr146992 phy_if_t phy_ifdata_routeto;
16722958Sdr146992 struct sockaddr sin;
16733448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs;
16742958Sdr146992
16752958Sdr146992 if (fin->fin_v == 4) {
16763448Sdh155122 net_data_p = ifs->ifs_ipf_ipv4;
16772958Sdr146992 } else if (fin->fin_v == 6) {
16783448Sdh155122 net_data_p = ifs->ifs_ipf_ipv6;
16792958Sdr146992 } else {
16802958Sdr146992 return (0);
16812958Sdr146992 }
16822958Sdr146992
16832958Sdr146992 /* Get the index corresponding to the if name */
16842958Sdr146992 sin.sa_family = (fin->fin_v == 4) ? AF_INET : AF_INET6;
16852958Sdr146992 bcopy(&fin->fin_saddr, &sin.sa_data, sizeof (struct in_addr));
16867513SDarren.Reed@Sun.COM phy_ifdata_routeto = net_routeto(net_data_p, &sin, NULL);
16872958Sdr146992
16882958Sdr146992 return (((phy_if_t)fin->fin_ifp == phy_ifdata_routeto) ? 1 : 0);
16892958Sdr146992 }
16902958Sdr146992
16912958Sdr146992
16922958Sdr146992 /*
16932958Sdr146992 * Function: fr_fastroute
16942958Sdr146992 * Returns: 0: success;
16952958Sdr146992 * -1: failed
16962958Sdr146992 * Parameters:
16972958Sdr146992 * mb: the message block where ip head starts
16982958Sdr146992 * mpp: the pointer to the pointer of the orignal
16992958Sdr146992 * packet message
17002958Sdr146992 * fin: packet information
17012958Sdr146992 * fdp: destination interface information
17022958Sdr146992 * if it is NULL, no interface information provided.
17032958Sdr146992 *
17042958Sdr146992 * This function is for fastroute/to/dup-to rules. It calls
17052958Sdr146992 * pfil_make_lay2_packet to search route, make lay-2 header
17062958Sdr146992 * ,and identify output queue for the IP packet.
17072958Sdr146992 * The destination address depends on the following conditions:
17082958Sdr146992 * 1: for fastroute rule, fdp is passed in as NULL, so the
17092958Sdr146992 * destination address is the IP Packet's destination address
17102958Sdr146992 * 2: for to/dup-to rule, if an ip address is specified after
17112958Sdr146992 * the interface name, this address is the as destination
17122958Sdr146992 * address. Otherwise IP Packet's destination address is used
17132958Sdr146992 */
fr_fastroute(mb,mpp,fin,fdp)17142958Sdr146992 int fr_fastroute(mb, mpp, fin, fdp)
17152958Sdr146992 mblk_t *mb, **mpp;
17162958Sdr146992 fr_info_t *fin;
17172958Sdr146992 frdest_t *fdp;
17182958Sdr146992 {
17197513SDarren.Reed@Sun.COM net_handle_t net_data_p;
17207513SDarren.Reed@Sun.COM net_inject_t *inj;
17212958Sdr146992 mblk_t *mp = NULL;
17222958Sdr146992 frentry_t *fr = fin->fin_fr;
17232958Sdr146992 qpktinfo_t *qpi;
17242958Sdr146992 ip_t *ip;
17252958Sdr146992
17262958Sdr146992 struct sockaddr_in *sin;
17272958Sdr146992 struct sockaddr_in6 *sin6;
17282958Sdr146992 struct sockaddr *sinp;
17293448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs;
17302958Sdr146992 #ifndef sparc
17312958Sdr146992 u_short __iplen, __ipoff;
17322958Sdr146992 #endif
17332958Sdr146992
17342958Sdr146992 if (fin->fin_v == 4) {
17353448Sdh155122 net_data_p = ifs->ifs_ipf_ipv4;
17362958Sdr146992 } else if (fin->fin_v == 6) {
17373448Sdh155122 net_data_p = ifs->ifs_ipf_ipv6;
17382958Sdr146992 } else {
17392958Sdr146992 return (-1);
17402958Sdr146992 }
17412958Sdr146992
17427513SDarren.Reed@Sun.COM inj = net_inject_alloc(NETINFO_VERSION);
17437513SDarren.Reed@Sun.COM if (inj == NULL)
17447513SDarren.Reed@Sun.COM return -1;
17457513SDarren.Reed@Sun.COM
17462958Sdr146992 ip = fin->fin_ip;
17472958Sdr146992 qpi = fin->fin_qpi;
17482958Sdr146992
17492958Sdr146992 /*
17502958Sdr146992 * If this is a duplicate mblk then we want ip to point at that
17512958Sdr146992 * data, not the original, if and only if it is already pointing at
17522958Sdr146992 * the current mblk data.
17532958Sdr146992 *
17542958Sdr146992 * Otherwise, if it's not a duplicate, and we're not already pointing
17552958Sdr146992 * at the current mblk data, then we want to ensure that the data
17562958Sdr146992 * points at ip.
17572958Sdr146992 */
17582958Sdr146992
17592958Sdr146992 if ((ip == (ip_t *)qpi->qpi_m->b_rptr) && (qpi->qpi_m != mb)) {
17602958Sdr146992 ip = (ip_t *)mb->b_rptr;
17612958Sdr146992 } else if ((qpi->qpi_m == mb) && (ip != (ip_t *)qpi->qpi_m->b_rptr)) {
17622958Sdr146992 qpi->qpi_m->b_rptr = (uchar_t *)ip;
17632958Sdr146992 qpi->qpi_off = 0;
17642958Sdr146992 }
17652958Sdr146992
17662958Sdr146992 /*
17672958Sdr146992 * If there is another M_PROTO, we don't want it
17682958Sdr146992 */
17692958Sdr146992 if (*mpp != mb) {
17702958Sdr146992 mp = unlinkb(*mpp);
17712958Sdr146992 freeb(*mpp);
17722958Sdr146992 *mpp = mp;
17732958Sdr146992 }
17742958Sdr146992
17757513SDarren.Reed@Sun.COM sinp = (struct sockaddr *)&inj->ni_addr;
17762958Sdr146992 sin = (struct sockaddr_in *)sinp;
17772958Sdr146992 sin6 = (struct sockaddr_in6 *)sinp;
17787513SDarren.Reed@Sun.COM bzero((char *)&inj->ni_addr, sizeof (inj->ni_addr));
17797513SDarren.Reed@Sun.COM inj->ni_addr.ss_family = (fin->fin_v == 4) ? AF_INET : AF_INET6;
17807513SDarren.Reed@Sun.COM inj->ni_packet = mb;
17812958Sdr146992
17822958Sdr146992 /*
17832958Sdr146992 * In case we're here due to "to <if>" being used with
17842958Sdr146992 * "keep state", check that we're going in the correct
17852958Sdr146992 * direction.
17862958Sdr146992 */
17872958Sdr146992 if (fdp != NULL) {
17882958Sdr146992 if ((fr != NULL) && (fdp->fd_ifp != NULL) &&
17892958Sdr146992 (fin->fin_rev != 0) && (fdp == &fr->fr_tif))
17902958Sdr146992 goto bad_fastroute;
17917513SDarren.Reed@Sun.COM inj->ni_physical = (phy_if_t)fdp->fd_ifp;
17922958Sdr146992 if (fin->fin_v == 4) {
17932958Sdr146992 sin->sin_addr = fdp->fd_ip;
17942958Sdr146992 } else {
17952958Sdr146992 sin6->sin6_addr = fdp->fd_ip6.in6;
17962958Sdr146992 }
17972958Sdr146992 } else {
17982958Sdr146992 if (fin->fin_v == 4) {
17992958Sdr146992 sin->sin_addr = ip->ip_dst;
18002958Sdr146992 } else {
18012958Sdr146992 sin6->sin6_addr = ((ip6_t *)ip)->ip6_dst;
18022958Sdr146992 }
18037513SDarren.Reed@Sun.COM inj->ni_physical = net_routeto(net_data_p, sinp, NULL);
18042958Sdr146992 }
18052958Sdr146992
18064482Sdr146992 /*
18074482Sdr146992 * Clear the hardware checksum flags from packets that we are doing
18084482Sdr146992 * input processing on as leaving them set will cause the outgoing
18094482Sdr146992 * NIC (if it supports hardware checksum) to calculate them anew,
18104482Sdr146992 * using the old (correct) checksums as the pseudo value to start
18114482Sdr146992 * from.
18124482Sdr146992 */
18134482Sdr146992 if (fin->fin_out == 0) {
18144482Sdr146992 DB_CKSUMFLAGS(mb) = 0;
18154482Sdr146992 }
18162958Sdr146992
18172958Sdr146992 *mpp = mb;
18182958Sdr146992
18192958Sdr146992 if (fin->fin_out == 0) {
18202958Sdr146992 void *saveifp;
18212958Sdr146992 u_32_t pass;
18222958Sdr146992
18232958Sdr146992 saveifp = fin->fin_ifp;
18247513SDarren.Reed@Sun.COM fin->fin_ifp = (void *)inj->ni_physical;
18253894Sjojemann fin->fin_flx &= ~FI_STATE;
18262958Sdr146992 fin->fin_out = 1;
18272958Sdr146992 (void) fr_acctpkt(fin, &pass);
18282958Sdr146992 fin->fin_fr = NULL;
18292958Sdr146992 if (!fr || !(fr->fr_flags & FR_RETMASK))
18302958Sdr146992 (void) fr_checkstate(fin, &pass);
18313894Sjojemann if (fr_checknatout(fin, NULL) == -1)
18322958Sdr146992 goto bad_fastroute;
18332958Sdr146992 fin->fin_out = 0;
18342958Sdr146992 fin->fin_ifp = saveifp;
18352958Sdr146992 }
18362958Sdr146992 #ifndef sparc
18372958Sdr146992 if (fin->fin_v == 4) {
18382958Sdr146992 __iplen = (u_short)ip->ip_len,
18392958Sdr146992 __ipoff = (u_short)ip->ip_off;
18402958Sdr146992
18412958Sdr146992 ip->ip_len = htons(__iplen);
18422958Sdr146992 ip->ip_off = htons(__ipoff);
18432958Sdr146992 }
18442958Sdr146992 #endif
18452958Sdr146992
18462958Sdr146992 if (net_data_p) {
18477513SDarren.Reed@Sun.COM if (net_inject(net_data_p, NI_DIRECT_OUT, inj) < 0) {
18487513SDarren.Reed@Sun.COM net_inject_free(inj);
18492958Sdr146992 return (-1);
18502958Sdr146992 }
18512958Sdr146992 }
18522958Sdr146992
18533448Sdh155122 ifs->ifs_fr_frouteok[0]++;
18547513SDarren.Reed@Sun.COM net_inject_free(inj);
18552958Sdr146992 return 0;
18562958Sdr146992 bad_fastroute:
18577513SDarren.Reed@Sun.COM net_inject_free(inj);
18582958Sdr146992 freemsg(mb);
18593448Sdh155122 ifs->ifs_fr_frouteok[1]++;
18602958Sdr146992 return -1;
18612958Sdr146992 }
18622958Sdr146992
18632958Sdr146992
18642958Sdr146992 /* ------------------------------------------------------------------------ */
18657513SDarren.Reed@Sun.COM /* Function: ipf_hook4_out */
18662958Sdr146992 /* Returns: int - 0 == packet ok, else problem, free packet if not done */
18672958Sdr146992 /* Parameters: event(I) - pointer to event */
18682958Sdr146992 /* info(I) - pointer to hook information for firewalling */
18692958Sdr146992 /* */
18702958Sdr146992 /* Calling ipf_hook. */
18712958Sdr146992 /* ------------------------------------------------------------------------ */
18722958Sdr146992 /*ARGSUSED*/
ipf_hook4_out(hook_event_token_t token,hook_data_t info,void * arg)18737513SDarren.Reed@Sun.COM int ipf_hook4_out(hook_event_token_t token, hook_data_t info, void *arg)
18742958Sdr146992 {
18757513SDarren.Reed@Sun.COM return ipf_hook(info, 1, 0, arg);
18767131Sdr146992 }
18777131Sdr146992 /*ARGSUSED*/
ipf_hook6_out(hook_event_token_t token,hook_data_t info,void * arg)18787513SDarren.Reed@Sun.COM int ipf_hook6_out(hook_event_token_t token, hook_data_t info, void *arg)
18797131Sdr146992 {
18807513SDarren.Reed@Sun.COM return ipf_hook6(info, 1, 0, arg);
18812958Sdr146992 }
18822958Sdr146992
18832958Sdr146992 /* ------------------------------------------------------------------------ */
18847513SDarren.Reed@Sun.COM /* Function: ipf_hook4_in */
18852958Sdr146992 /* Returns: int - 0 == packet ok, else problem, free packet if not done */
18862958Sdr146992 /* Parameters: event(I) - pointer to event */
18872958Sdr146992 /* info(I) - pointer to hook information for firewalling */
18882958Sdr146992 /* */
18892958Sdr146992 /* Calling ipf_hook. */
18902958Sdr146992 /* ------------------------------------------------------------------------ */
18912958Sdr146992 /*ARGSUSED*/
ipf_hook4_in(hook_event_token_t token,hook_data_t info,void * arg)18927513SDarren.Reed@Sun.COM int ipf_hook4_in(hook_event_token_t token, hook_data_t info, void *arg)
18932958Sdr146992 {
18947513SDarren.Reed@Sun.COM return ipf_hook(info, 0, 0, arg);
18957131Sdr146992 }
18967131Sdr146992 /*ARGSUSED*/
ipf_hook6_in(hook_event_token_t token,hook_data_t info,void * arg)18977513SDarren.Reed@Sun.COM int ipf_hook6_in(hook_event_token_t token, hook_data_t info, void *arg)
18987131Sdr146992 {
18997513SDarren.Reed@Sun.COM return ipf_hook6(info, 0, 0, arg);
19002958Sdr146992 }
19012958Sdr146992
19022958Sdr146992
19032958Sdr146992 /* ------------------------------------------------------------------------ */
19047513SDarren.Reed@Sun.COM /* Function: ipf_hook4_loop_out */
19052958Sdr146992 /* Returns: int - 0 == packet ok, else problem, free packet if not done */
19062958Sdr146992 /* Parameters: event(I) - pointer to event */
19072958Sdr146992 /* info(I) - pointer to hook information for firewalling */
19082958Sdr146992 /* */
19092958Sdr146992 /* Calling ipf_hook. */
19102958Sdr146992 /* ------------------------------------------------------------------------ */
19112958Sdr146992 /*ARGSUSED*/
ipf_hook4_loop_out(hook_event_token_t token,hook_data_t info,void * arg)19127513SDarren.Reed@Sun.COM int ipf_hook4_loop_out(hook_event_token_t token, hook_data_t info, void *arg)
19132958Sdr146992 {
19147513SDarren.Reed@Sun.COM return ipf_hook(info, 1, FI_NOCKSUM, arg);
19157131Sdr146992 }
19167131Sdr146992 /*ARGSUSED*/
ipf_hook6_loop_out(hook_event_token_t token,hook_data_t info,void * arg)19177513SDarren.Reed@Sun.COM int ipf_hook6_loop_out(hook_event_token_t token, hook_data_t info, void *arg)
19187131Sdr146992 {
19197513SDarren.Reed@Sun.COM return ipf_hook6(info, 1, FI_NOCKSUM, arg);
19202958Sdr146992 }
19212958Sdr146992
19222958Sdr146992 /* ------------------------------------------------------------------------ */
19237704SAlexandr.Nedvedicky@Sun.COM /* Function: ipf_hook4_loop_in */
19242958Sdr146992 /* Returns: int - 0 == packet ok, else problem, free packet if not done */
19252958Sdr146992 /* Parameters: event(I) - pointer to event */
19262958Sdr146992 /* info(I) - pointer to hook information for firewalling */
19272958Sdr146992 /* */
19282958Sdr146992 /* Calling ipf_hook. */
19292958Sdr146992 /* ------------------------------------------------------------------------ */
19302958Sdr146992 /*ARGSUSED*/
ipf_hook4_loop_in(hook_event_token_t token,hook_data_t info,void * arg)19317704SAlexandr.Nedvedicky@Sun.COM int ipf_hook4_loop_in(hook_event_token_t token, hook_data_t info, void *arg)
19322958Sdr146992 {
19337513SDarren.Reed@Sun.COM return ipf_hook(info, 0, FI_NOCKSUM, arg);
19347131Sdr146992 }
19357131Sdr146992 /*ARGSUSED*/
ipf_hook6_loop_in(hook_event_token_t token,hook_data_t info,void * arg)19367513SDarren.Reed@Sun.COM int ipf_hook6_loop_in(hook_event_token_t token, hook_data_t info, void *arg)
19377131Sdr146992 {
19387513SDarren.Reed@Sun.COM return ipf_hook6(info, 0, FI_NOCKSUM, arg);
19392958Sdr146992 }
19402958Sdr146992
19412958Sdr146992 /* ------------------------------------------------------------------------ */
19422958Sdr146992 /* Function: ipf_hook */
19432958Sdr146992 /* Returns: int - 0 == packet ok, else problem, free packet if not done */
19442958Sdr146992 /* Parameters: info(I) - pointer to hook information for firewalling */
19452958Sdr146992 /* out(I) - whether packet is going in or out */
19462958Sdr146992 /* loopback(I) - whether packet is a loopback packet or not */
19472958Sdr146992 /* */
19482958Sdr146992 /* Stepping stone function between the IP mainline and IPFilter. Extracts */
19492958Sdr146992 /* parameters out of the info structure and forms them up to be useful for */
19502958Sdr146992 /* calling ipfilter. */
19512958Sdr146992 /* ------------------------------------------------------------------------ */
ipf_hook(hook_data_t info,int out,int loopback,void * arg)19527513SDarren.Reed@Sun.COM int ipf_hook(hook_data_t info, int out, int loopback, void *arg)
19532958Sdr146992 {
19542958Sdr146992 hook_pkt_event_t *fw;
19557513SDarren.Reed@Sun.COM ipf_stack_t *ifs;
19567513SDarren.Reed@Sun.COM qpktinfo_t qpi;
19577131Sdr146992 int rval, hlen;
19582958Sdr146992 u_short swap;
19592958Sdr146992 phy_if_t phy;
19602958Sdr146992 ip_t *ip;
19612958Sdr146992
19627513SDarren.Reed@Sun.COM ifs = arg;
19632958Sdr146992 fw = (hook_pkt_event_t *)info;
19642958Sdr146992
19652958Sdr146992 ASSERT(fw != NULL);
19662958Sdr146992 phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp;
19672958Sdr146992
19682958Sdr146992 ip = fw->hpe_hdr;
19697131Sdr146992 swap = ntohs(ip->ip_len);
19707131Sdr146992 ip->ip_len = swap;
19717131Sdr146992 swap = ntohs(ip->ip_off);
19727131Sdr146992 ip->ip_off = swap;
19737131Sdr146992 hlen = IPH_HDR_LENGTH(ip);
19742958Sdr146992
19752958Sdr146992 qpi.qpi_m = fw->hpe_mb;
19762958Sdr146992 qpi.qpi_data = fw->hpe_hdr;
19772958Sdr146992 qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr;
19782958Sdr146992 qpi.qpi_ill = (void *)phy;
19797131Sdr146992 qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST);
19807131Sdr146992 if (qpi.qpi_flags)
19817131Sdr146992 qpi.qpi_flags |= FI_MBCAST;
19827131Sdr146992 qpi.qpi_flags |= loopback;
19832958Sdr146992
19843448Sdh155122 rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out,
19857513SDarren.Reed@Sun.COM &qpi, fw->hpe_mp, ifs);
19862958Sdr146992
19872958Sdr146992 /* For fastroute cases, fr_check returns 0 with mp set to NULL */
19882958Sdr146992 if (rval == 0 && *(fw->hpe_mp) == NULL)
19892958Sdr146992 rval = 1;
19902958Sdr146992
19917131Sdr146992 /* Notify IP the packet mblk_t and IP header pointers. */
19922958Sdr146992 fw->hpe_mb = qpi.qpi_m;
19932958Sdr146992 fw->hpe_hdr = qpi.qpi_data;
19947131Sdr146992 if (rval == 0) {
19952958Sdr146992 ip = qpi.qpi_data;
19962958Sdr146992 swap = ntohs(ip->ip_len);
19972958Sdr146992 ip->ip_len = swap;
19982958Sdr146992 swap = ntohs(ip->ip_off);
19992958Sdr146992 ip->ip_off = swap;
20002958Sdr146992 }
20012958Sdr146992 return rval;
20022958Sdr146992
20032958Sdr146992 }
ipf_hook6(hook_data_t info,int out,int loopback,void * arg)20047513SDarren.Reed@Sun.COM int ipf_hook6(hook_data_t info, int out, int loopback, void *arg)
20057131Sdr146992 {
20067131Sdr146992 hook_pkt_event_t *fw;
20077131Sdr146992 int rval, hlen;
20087131Sdr146992 qpktinfo_t qpi;
20097131Sdr146992 phy_if_t phy;
20107131Sdr146992
20117131Sdr146992 fw = (hook_pkt_event_t *)info;
20127131Sdr146992
20137131Sdr146992 ASSERT(fw != NULL);
20147131Sdr146992 phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp;
20157131Sdr146992
20167131Sdr146992 hlen = sizeof (ip6_t);
20177131Sdr146992
20187131Sdr146992 qpi.qpi_m = fw->hpe_mb;
20197131Sdr146992 qpi.qpi_data = fw->hpe_hdr;
20207131Sdr146992 qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr;
20217131Sdr146992 qpi.qpi_ill = (void *)phy;
20227131Sdr146992 qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST);
20237131Sdr146992 if (qpi.qpi_flags)
20247131Sdr146992 qpi.qpi_flags |= FI_MBCAST;
20257131Sdr146992 qpi.qpi_flags |= loopback;
20267131Sdr146992
20277131Sdr146992 rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out,
20287513SDarren.Reed@Sun.COM &qpi, fw->hpe_mp, arg);
20297131Sdr146992
20307131Sdr146992 /* For fastroute cases, fr_check returns 0 with mp set to NULL */
20317131Sdr146992 if (rval == 0 && *(fw->hpe_mp) == NULL)
20327131Sdr146992 rval = 1;
20337131Sdr146992
20347131Sdr146992 /* Notify IP the packet mblk_t and IP header pointers. */
20357131Sdr146992 fw->hpe_mb = qpi.qpi_m;
20367131Sdr146992 fw->hpe_hdr = qpi.qpi_data;
20377131Sdr146992 return rval;
20387131Sdr146992
20397131Sdr146992 }
20402958Sdr146992
20412958Sdr146992
20422958Sdr146992 /* ------------------------------------------------------------------------ */
20432958Sdr146992 /* Function: ipf_nic_event_v4 */
20442958Sdr146992 /* Returns: int - 0 == no problems encountered */
20452958Sdr146992 /* Parameters: event(I) - pointer to event */
20462958Sdr146992 /* info(I) - pointer to information about a NIC event */
20472958Sdr146992 /* */
20482958Sdr146992 /* Function to receive asynchronous NIC events from IP */
20492958Sdr146992 /* ------------------------------------------------------------------------ */
20502958Sdr146992 /*ARGSUSED*/
ipf_nic_event_v4(hook_event_token_t event,hook_data_t info,void * arg)20517513SDarren.Reed@Sun.COM int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info, void *arg)
20522958Sdr146992 {
20532958Sdr146992 struct sockaddr_in *sin;
20542958Sdr146992 hook_nic_event_t *hn;
20557513SDarren.Reed@Sun.COM ipf_stack_t *ifs = arg;
205611105SAlexandr.Nedvedicky@Sun.COM void *new_ifp = NULL;
205711105SAlexandr.Nedvedicky@Sun.COM
205811105SAlexandr.Nedvedicky@Sun.COM if (ifs->ifs_fr_running <= 0)
205911105SAlexandr.Nedvedicky@Sun.COM return (0);
20602958Sdr146992
20612958Sdr146992 hn = (hook_nic_event_t *)info;
20622958Sdr146992
20632958Sdr146992 switch (hn->hne_event)
20642958Sdr146992 {
20652958Sdr146992 case NE_PLUMB :
20664118Sdr146992 frsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, hn->hne_data,
20677176Syx160601 ifs);
20687176Syx160601 fr_natifpsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic,
20693448Sdh155122 hn->hne_data, ifs);
20702958Sdr146992 fr_statesync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic,
20713448Sdh155122 hn->hne_data, ifs);
20722958Sdr146992 break;
20732958Sdr146992
20742958Sdr146992 case NE_UNPLUMB :
20753448Sdh155122 frsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs);
20767176Syx160601 fr_natifpsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL,
20777176Syx160601 ifs);
20783448Sdh155122 fr_statesync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs);
20792958Sdr146992 break;
20802958Sdr146992
20812958Sdr146992 case NE_ADDRESS_CHANGE :
20824118Sdr146992 /*
20834118Sdr146992 * We only respond to events for logical interface 0 because
20844118Sdr146992 * IPFilter only uses the first address given to a network
20854118Sdr146992 * interface. We check for hne_lif==1 because the netinfo
20864118Sdr146992 * code maps adds 1 to the lif number so that it can return
20874118Sdr146992 * 0 to indicate "no more lifs" when walking them.
20884118Sdr146992 */
20894118Sdr146992 if (hn->hne_lif == 1) {
20904118Sdr146992 frsync(IPFSYNC_RESYNC, 4, (void *)hn->hne_nic, NULL,
20914118Sdr146992 ifs);
20924118Sdr146992 sin = hn->hne_data;
20937176Syx160601 fr_nataddrsync(4, (void *)hn->hne_nic, &sin->sin_addr,
20944118Sdr146992 ifs);
20954118Sdr146992 }
20962958Sdr146992 break;
20972958Sdr146992
209811105SAlexandr.Nedvedicky@Sun.COM #if SOLARIS2 >= 10
209911105SAlexandr.Nedvedicky@Sun.COM case NE_IFINDEX_CHANGE :
210011105SAlexandr.Nedvedicky@Sun.COM WRITE_ENTER(&ifs->ifs_ipf_mutex);
210111105SAlexandr.Nedvedicky@Sun.COM
210211105SAlexandr.Nedvedicky@Sun.COM if (hn->hne_data != NULL) {
210311105SAlexandr.Nedvedicky@Sun.COM /*
210411105SAlexandr.Nedvedicky@Sun.COM * The netinfo passes interface index as int (hne_data should be
210511105SAlexandr.Nedvedicky@Sun.COM * handled as a pointer to int), which is always 32bit. We need to
210611105SAlexandr.Nedvedicky@Sun.COM * convert it to void pointer here, since interfaces are
210711105SAlexandr.Nedvedicky@Sun.COM * represented as pointers to void in IPF. The pointers are 64 bits
210811105SAlexandr.Nedvedicky@Sun.COM * long on 64bit platforms. Doing something like
210911105SAlexandr.Nedvedicky@Sun.COM * (void *)((int) x)
211011105SAlexandr.Nedvedicky@Sun.COM * will throw warning:
211111105SAlexandr.Nedvedicky@Sun.COM * "cast to pointer from integer of different size"
211211105SAlexandr.Nedvedicky@Sun.COM * during 64bit compilation.
211311105SAlexandr.Nedvedicky@Sun.COM *
211411105SAlexandr.Nedvedicky@Sun.COM * The line below uses (size_t) to typecast int to
211511105SAlexandr.Nedvedicky@Sun.COM * size_t, which might be 64bit/32bit (depending
211611105SAlexandr.Nedvedicky@Sun.COM * on architecture). Once we have proper 64bit/32bit
211711105SAlexandr.Nedvedicky@Sun.COM * type (size_t), we can safely convert it to void pointer.
211811105SAlexandr.Nedvedicky@Sun.COM */
211911105SAlexandr.Nedvedicky@Sun.COM new_ifp = (void *)(size_t)*((int *)hn->hne_data);
212011105SAlexandr.Nedvedicky@Sun.COM fr_ifindexsync((void *)hn->hne_nic, new_ifp, ifs);
212111105SAlexandr.Nedvedicky@Sun.COM fr_natifindexsync((void *)hn->hne_nic, new_ifp, ifs);
212211105SAlexandr.Nedvedicky@Sun.COM fr_stateifindexsync((void *)hn->hne_nic, new_ifp, ifs);
212311105SAlexandr.Nedvedicky@Sun.COM }
212411105SAlexandr.Nedvedicky@Sun.COM RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
212511105SAlexandr.Nedvedicky@Sun.COM break;
212611105SAlexandr.Nedvedicky@Sun.COM #endif
212711105SAlexandr.Nedvedicky@Sun.COM
21282958Sdr146992 default :
21292958Sdr146992 break;
21302958Sdr146992 }
21312958Sdr146992
21322958Sdr146992 return 0;
21332958Sdr146992 }
21342958Sdr146992
21352958Sdr146992
21362958Sdr146992 /* ------------------------------------------------------------------------ */
21372958Sdr146992 /* Function: ipf_nic_event_v6 */
21382958Sdr146992 /* Returns: int - 0 == no problems encountered */
21392958Sdr146992 /* Parameters: event(I) - pointer to event */
21402958Sdr146992 /* info(I) - pointer to information about a NIC event */
21412958Sdr146992 /* */
21422958Sdr146992 /* Function to receive asynchronous NIC events from IP */
21432958Sdr146992 /* ------------------------------------------------------------------------ */
21442958Sdr146992 /*ARGSUSED*/
ipf_nic_event_v6(hook_event_token_t event,hook_data_t info,void * arg)21457513SDarren.Reed@Sun.COM int ipf_nic_event_v6(hook_event_token_t event, hook_data_t info, void *arg)
21462958Sdr146992 {
21477176Syx160601 struct sockaddr_in6 *sin6;
21482958Sdr146992 hook_nic_event_t *hn;
21497513SDarren.Reed@Sun.COM ipf_stack_t *ifs = arg;
215011105SAlexandr.Nedvedicky@Sun.COM void *new_ifp = NULL;
215111105SAlexandr.Nedvedicky@Sun.COM
215211105SAlexandr.Nedvedicky@Sun.COM if (ifs->ifs_fr_running <= 0)
215311105SAlexandr.Nedvedicky@Sun.COM return (0);
21542958Sdr146992
21552958Sdr146992 hn = (hook_nic_event_t *)info;
21562958Sdr146992
21572958Sdr146992 switch (hn->hne_event)
21582958Sdr146992 {
21592958Sdr146992 case NE_PLUMB :
21607176Syx160601 frsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic,
21617176Syx160601 hn->hne_data, ifs);
21627176Syx160601 fr_natifpsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic,
21637176Syx160601 hn->hne_data, ifs);
21642958Sdr146992 fr_statesync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic,
21653448Sdh155122 hn->hne_data, ifs);
21662958Sdr146992 break;
21672958Sdr146992
21682958Sdr146992 case NE_UNPLUMB :
21693448Sdh155122 frsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs);
21707176Syx160601 fr_natifpsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL,
21717176Syx160601 ifs);
21723448Sdh155122 fr_statesync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs);
21732958Sdr146992 break;
21742958Sdr146992
21752958Sdr146992 case NE_ADDRESS_CHANGE :
21767176Syx160601 if (hn->hne_lif == 1) {
21777176Syx160601 sin6 = hn->hne_data;
21787176Syx160601 fr_nataddrsync(6, (void *)hn->hne_nic, &sin6->sin6_addr,
21797176Syx160601 ifs);
21807176Syx160601 }
21812958Sdr146992 break;
218211105SAlexandr.Nedvedicky@Sun.COM
218311105SAlexandr.Nedvedicky@Sun.COM #if SOLARIS2 >= 10
218411105SAlexandr.Nedvedicky@Sun.COM case NE_IFINDEX_CHANGE :
218511105SAlexandr.Nedvedicky@Sun.COM WRITE_ENTER(&ifs->ifs_ipf_mutex);
218611105SAlexandr.Nedvedicky@Sun.COM if (hn->hne_data != NULL) {
218711105SAlexandr.Nedvedicky@Sun.COM /*
218811105SAlexandr.Nedvedicky@Sun.COM * The netinfo passes interface index as int (hne_data should be
218911105SAlexandr.Nedvedicky@Sun.COM * handled as a pointer to int), which is always 32bit. We need to
219011105SAlexandr.Nedvedicky@Sun.COM * convert it to void pointer here, since interfaces are
219111105SAlexandr.Nedvedicky@Sun.COM * represented as pointers to void in IPF. The pointers are 64 bits
219211105SAlexandr.Nedvedicky@Sun.COM * long on 64bit platforms. Doing something like
219311105SAlexandr.Nedvedicky@Sun.COM * (void *)((int) x)
219411105SAlexandr.Nedvedicky@Sun.COM * will throw warning:
219511105SAlexandr.Nedvedicky@Sun.COM * "cast to pointer from integer of different size"
219611105SAlexandr.Nedvedicky@Sun.COM * during 64bit compilation.
219711105SAlexandr.Nedvedicky@Sun.COM *
219811105SAlexandr.Nedvedicky@Sun.COM * The line below uses (size_t) to typecast int to
219911105SAlexandr.Nedvedicky@Sun.COM * size_t, which might be 64bit/32bit (depending
220011105SAlexandr.Nedvedicky@Sun.COM * on architecture). Once we have proper 64bit/32bit
220111105SAlexandr.Nedvedicky@Sun.COM * type (size_t), we can safely convert it to void pointer.
220211105SAlexandr.Nedvedicky@Sun.COM */
220311105SAlexandr.Nedvedicky@Sun.COM new_ifp = (void *)(size_t)*((int *)hn->hne_data);
220411105SAlexandr.Nedvedicky@Sun.COM fr_ifindexsync((void *)hn->hne_nic, new_ifp, ifs);
220511105SAlexandr.Nedvedicky@Sun.COM fr_natifindexsync((void *)hn->hne_nic, new_ifp, ifs);
220611105SAlexandr.Nedvedicky@Sun.COM fr_stateifindexsync((void *)hn->hne_nic, new_ifp, ifs);
220711105SAlexandr.Nedvedicky@Sun.COM }
220811105SAlexandr.Nedvedicky@Sun.COM RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
220911105SAlexandr.Nedvedicky@Sun.COM break;
221011105SAlexandr.Nedvedicky@Sun.COM #endif
221111105SAlexandr.Nedvedicky@Sun.COM
22122958Sdr146992 default :
22132958Sdr146992 break;
22142958Sdr146992 }
22152958Sdr146992
22162958Sdr146992 return 0;
22172958Sdr146992 }
22189695SAlexandr.Nedvedicky@Sun.COM
22199695SAlexandr.Nedvedicky@Sun.COM /*
22209695SAlexandr.Nedvedicky@Sun.COM * Functions fr_make_rst(), fr_make_icmp_v4(), fr_make_icmp_v6()
22219695SAlexandr.Nedvedicky@Sun.COM * are needed in Solaris kernel only. We don't need them in
22229695SAlexandr.Nedvedicky@Sun.COM * ipftest to pretend the ICMP/RST packet was sent as a response.
22239695SAlexandr.Nedvedicky@Sun.COM */
22249695SAlexandr.Nedvedicky@Sun.COM #if defined(_KERNEL) && (SOLARIS2 >= 10)
22259695SAlexandr.Nedvedicky@Sun.COM /* ------------------------------------------------------------------------ */
22269695SAlexandr.Nedvedicky@Sun.COM /* Function: fr_make_rst */
22279695SAlexandr.Nedvedicky@Sun.COM /* Returns: int - 0 on success, -1 on failure */
22289695SAlexandr.Nedvedicky@Sun.COM /* Parameters: fin(I) - pointer to packet information */
22299695SAlexandr.Nedvedicky@Sun.COM /* */
22309695SAlexandr.Nedvedicky@Sun.COM /* We must alter the original mblks passed to IPF from IP stack via */
22319695SAlexandr.Nedvedicky@Sun.COM /* FW_HOOKS. FW_HOOKS interface is powerfull, but it has some limitations. */
22329695SAlexandr.Nedvedicky@Sun.COM /* IPF can basicaly do only these things with mblk representing the packet: */
22339695SAlexandr.Nedvedicky@Sun.COM /* leave it as it is (pass the packet) */
22349695SAlexandr.Nedvedicky@Sun.COM /* */
22359695SAlexandr.Nedvedicky@Sun.COM /* discard it (block the packet) */
22369695SAlexandr.Nedvedicky@Sun.COM /* */
22379695SAlexandr.Nedvedicky@Sun.COM /* alter it (i.e. NAT) */
22389695SAlexandr.Nedvedicky@Sun.COM /* */
22399695SAlexandr.Nedvedicky@Sun.COM /* As you can see IPF can not simply discard the mblk and supply a new one */
22409695SAlexandr.Nedvedicky@Sun.COM /* instead to IP stack via FW_HOOKS. */
22419695SAlexandr.Nedvedicky@Sun.COM /* */
22429695SAlexandr.Nedvedicky@Sun.COM /* The return-rst action for packets coming via NIC is handled as follows: */
22439695SAlexandr.Nedvedicky@Sun.COM /* mblk with packet is discarded */
22449695SAlexandr.Nedvedicky@Sun.COM /* */
22459695SAlexandr.Nedvedicky@Sun.COM /* new mblk with RST response is constructed and injected to network */
22469695SAlexandr.Nedvedicky@Sun.COM /* */
22479695SAlexandr.Nedvedicky@Sun.COM /* IPF can't inject packets to loopback interface, this is just another */
22489695SAlexandr.Nedvedicky@Sun.COM /* limitation we have to deal with here. The only option to send RST */
22499695SAlexandr.Nedvedicky@Sun.COM /* response to offending TCP packet coming via loopback is to alter it. */
22509695SAlexandr.Nedvedicky@Sun.COM /* */
22519695SAlexandr.Nedvedicky@Sun.COM /* The fr_make_rst() function alters TCP SYN/FIN packet intercepted on */
22529695SAlexandr.Nedvedicky@Sun.COM /* loopback interface into TCP RST packet. fin->fin_mp is pointer to */
22539695SAlexandr.Nedvedicky@Sun.COM /* mblk L3 (IP) and L4 (TCP/UDP) packet headers. */
22549695SAlexandr.Nedvedicky@Sun.COM /* ------------------------------------------------------------------------ */
fr_make_rst(fin)22559695SAlexandr.Nedvedicky@Sun.COM int fr_make_rst(fin)
22569695SAlexandr.Nedvedicky@Sun.COM fr_info_t *fin;
22579695SAlexandr.Nedvedicky@Sun.COM {
22589695SAlexandr.Nedvedicky@Sun.COM uint16_t tmp_port;
22599695SAlexandr.Nedvedicky@Sun.COM int rv = -1;
22609695SAlexandr.Nedvedicky@Sun.COM uint32_t old_ack;
22619695SAlexandr.Nedvedicky@Sun.COM tcphdr_t *tcp = NULL;
22629695SAlexandr.Nedvedicky@Sun.COM struct in_addr tmp_src;
22639695SAlexandr.Nedvedicky@Sun.COM #ifdef USE_INET6
22649695SAlexandr.Nedvedicky@Sun.COM struct in6_addr tmp_src6;
22659695SAlexandr.Nedvedicky@Sun.COM #endif
22669695SAlexandr.Nedvedicky@Sun.COM
22679695SAlexandr.Nedvedicky@Sun.COM ASSERT(fin->fin_p == IPPROTO_TCP);
22689695SAlexandr.Nedvedicky@Sun.COM
22699695SAlexandr.Nedvedicky@Sun.COM /*
22709695SAlexandr.Nedvedicky@Sun.COM * We do not need to adjust chksum, since it is not being checked by
22719695SAlexandr.Nedvedicky@Sun.COM * Solaris IP stack for loopback clients.
22729695SAlexandr.Nedvedicky@Sun.COM */
22739695SAlexandr.Nedvedicky@Sun.COM if ((fin->fin_v == 4) && (fin->fin_p == IPPROTO_TCP) &&
22749695SAlexandr.Nedvedicky@Sun.COM ((tcp = (tcphdr_t *) fin->fin_dp) != NULL)) {
22759695SAlexandr.Nedvedicky@Sun.COM
22769695SAlexandr.Nedvedicky@Sun.COM if (tcp->th_flags & (TH_SYN | TH_FIN)) {
22779695SAlexandr.Nedvedicky@Sun.COM /* Swap IPv4 addresses. */
22789695SAlexandr.Nedvedicky@Sun.COM tmp_src = fin->fin_ip->ip_src;
22799695SAlexandr.Nedvedicky@Sun.COM fin->fin_ip->ip_src = fin->fin_ip->ip_dst;
22809695SAlexandr.Nedvedicky@Sun.COM fin->fin_ip->ip_dst = tmp_src;
22819695SAlexandr.Nedvedicky@Sun.COM
22829695SAlexandr.Nedvedicky@Sun.COM rv = 0;
22839695SAlexandr.Nedvedicky@Sun.COM }
22849695SAlexandr.Nedvedicky@Sun.COM else
22859695SAlexandr.Nedvedicky@Sun.COM tcp = NULL;
22869695SAlexandr.Nedvedicky@Sun.COM }
22879695SAlexandr.Nedvedicky@Sun.COM #ifdef USE_INET6
22889695SAlexandr.Nedvedicky@Sun.COM else if ((fin->fin_v == 6) && (fin->fin_p == IPPROTO_TCP) &&
22899695SAlexandr.Nedvedicky@Sun.COM ((tcp = (tcphdr_t *) fin->fin_dp) != NULL)) {
22909695SAlexandr.Nedvedicky@Sun.COM /*
22919695SAlexandr.Nedvedicky@Sun.COM * We are relying on fact the next header is TCP, which is true
22929695SAlexandr.Nedvedicky@Sun.COM * for regular TCP packets coming in over loopback.
22939695SAlexandr.Nedvedicky@Sun.COM */
22949695SAlexandr.Nedvedicky@Sun.COM if (tcp->th_flags & (TH_SYN | TH_FIN)) {
22959695SAlexandr.Nedvedicky@Sun.COM /* Swap IPv6 addresses. */
22969695SAlexandr.Nedvedicky@Sun.COM tmp_src6 = fin->fin_ip6->ip6_src;
22979695SAlexandr.Nedvedicky@Sun.COM fin->fin_ip6->ip6_src = fin->fin_ip6->ip6_dst;
22989695SAlexandr.Nedvedicky@Sun.COM fin->fin_ip6->ip6_dst = tmp_src6;
22999695SAlexandr.Nedvedicky@Sun.COM
23009695SAlexandr.Nedvedicky@Sun.COM rv = 0;
23019695SAlexandr.Nedvedicky@Sun.COM }
23029695SAlexandr.Nedvedicky@Sun.COM else
23039695SAlexandr.Nedvedicky@Sun.COM tcp = NULL;
23049695SAlexandr.Nedvedicky@Sun.COM }
23059695SAlexandr.Nedvedicky@Sun.COM #endif
23069695SAlexandr.Nedvedicky@Sun.COM
23079695SAlexandr.Nedvedicky@Sun.COM if (tcp != NULL) {
23089695SAlexandr.Nedvedicky@Sun.COM /*
23099695SAlexandr.Nedvedicky@Sun.COM * Adjust TCP header:
23109695SAlexandr.Nedvedicky@Sun.COM * swap ports,
23119695SAlexandr.Nedvedicky@Sun.COM * set flags,
23129695SAlexandr.Nedvedicky@Sun.COM * set correct ACK number
23139695SAlexandr.Nedvedicky@Sun.COM */
23149695SAlexandr.Nedvedicky@Sun.COM tmp_port = tcp->th_sport;
23159695SAlexandr.Nedvedicky@Sun.COM tcp->th_sport = tcp->th_dport;
23169695SAlexandr.Nedvedicky@Sun.COM tcp->th_dport = tmp_port;
23179695SAlexandr.Nedvedicky@Sun.COM old_ack = tcp->th_ack;
23189695SAlexandr.Nedvedicky@Sun.COM tcp->th_ack = htonl(ntohl(tcp->th_seq) + 1);
23199695SAlexandr.Nedvedicky@Sun.COM tcp->th_seq = old_ack;
23209695SAlexandr.Nedvedicky@Sun.COM tcp->th_flags = TH_RST | TH_ACK;
23219695SAlexandr.Nedvedicky@Sun.COM }
23229695SAlexandr.Nedvedicky@Sun.COM
23239695SAlexandr.Nedvedicky@Sun.COM return (rv);
23249695SAlexandr.Nedvedicky@Sun.COM }
23259695SAlexandr.Nedvedicky@Sun.COM
23269695SAlexandr.Nedvedicky@Sun.COM /* ------------------------------------------------------------------------ */
23279695SAlexandr.Nedvedicky@Sun.COM /* Function: fr_make_icmp_v4 */
23289695SAlexandr.Nedvedicky@Sun.COM /* Returns: int - 0 on success, -1 on failure */
23299695SAlexandr.Nedvedicky@Sun.COM /* Parameters: fin(I) - pointer to packet information */
23309695SAlexandr.Nedvedicky@Sun.COM /* */
23319695SAlexandr.Nedvedicky@Sun.COM /* Please read comment at fr_make_icmp() wrapper function to get an idea */
23329695SAlexandr.Nedvedicky@Sun.COM /* what is going to happen here and why. Once you read the comment there, */
23339695SAlexandr.Nedvedicky@Sun.COM /* continue here with next paragraph. */
23349695SAlexandr.Nedvedicky@Sun.COM /* */
23359695SAlexandr.Nedvedicky@Sun.COM /* To turn IPv4 packet into ICMPv4 response packet, these things must */
23369695SAlexandr.Nedvedicky@Sun.COM /* happen here: */
23379695SAlexandr.Nedvedicky@Sun.COM /* (1) Original mblk is copied (duplicated). */
23389695SAlexandr.Nedvedicky@Sun.COM /* */
23399695SAlexandr.Nedvedicky@Sun.COM /* (2) ICMP header is created. */
23409695SAlexandr.Nedvedicky@Sun.COM /* */
23419695SAlexandr.Nedvedicky@Sun.COM /* (3) Link ICMP header with copy of original mblk, we have ICMPv4 */
23429695SAlexandr.Nedvedicky@Sun.COM /* data ready then. */
23439695SAlexandr.Nedvedicky@Sun.COM /* */
23449695SAlexandr.Nedvedicky@Sun.COM /* (4) Swap IP addresses in original mblk and adjust IP header data. */
23459695SAlexandr.Nedvedicky@Sun.COM /* */
23469695SAlexandr.Nedvedicky@Sun.COM /* (5) The mblk containing original packet is trimmed to contain IP */
23479695SAlexandr.Nedvedicky@Sun.COM /* header only and ICMP chksum is computed. */
23489695SAlexandr.Nedvedicky@Sun.COM /* */
23499695SAlexandr.Nedvedicky@Sun.COM /* (6) The ICMP header we have from (3) is linked to original mblk, */
23509695SAlexandr.Nedvedicky@Sun.COM /* which now contains new IP header. If original packet was spread */
23519695SAlexandr.Nedvedicky@Sun.COM /* over several mblks, only the first mblk is kept. */
23529695SAlexandr.Nedvedicky@Sun.COM /* ------------------------------------------------------------------------ */
fr_make_icmp_v4(fin)23539695SAlexandr.Nedvedicky@Sun.COM static int fr_make_icmp_v4(fin)
23549695SAlexandr.Nedvedicky@Sun.COM fr_info_t *fin;
23559695SAlexandr.Nedvedicky@Sun.COM {
23569695SAlexandr.Nedvedicky@Sun.COM struct in_addr tmp_src;
23579888SAlexandr.Nedvedicky@Sun.COM tcphdr_t *tcp;
23589695SAlexandr.Nedvedicky@Sun.COM struct icmp *icmp;
23599695SAlexandr.Nedvedicky@Sun.COM mblk_t *mblk_icmp;
23609695SAlexandr.Nedvedicky@Sun.COM mblk_t *mblk_ip;
23619695SAlexandr.Nedvedicky@Sun.COM size_t icmp_pld_len; /* octets to append to ICMP header */
23629695SAlexandr.Nedvedicky@Sun.COM size_t orig_iphdr_len; /* length of IP header only */
23639695SAlexandr.Nedvedicky@Sun.COM uint32_t sum;
23649695SAlexandr.Nedvedicky@Sun.COM uint16_t *buf;
23659695SAlexandr.Nedvedicky@Sun.COM int len;
23669695SAlexandr.Nedvedicky@Sun.COM
23679695SAlexandr.Nedvedicky@Sun.COM
23689695SAlexandr.Nedvedicky@Sun.COM if (fin->fin_v != 4)
23699695SAlexandr.Nedvedicky@Sun.COM return (-1);
23709695SAlexandr.Nedvedicky@Sun.COM
23719695SAlexandr.Nedvedicky@Sun.COM /*
23729695SAlexandr.Nedvedicky@Sun.COM * If we are dealing with TCP, then packet must be SYN/FIN to be routed
23739695SAlexandr.Nedvedicky@Sun.COM * by IP stack. If it is not SYN/FIN, then we must drop it silently.
23749695SAlexandr.Nedvedicky@Sun.COM */
23759888SAlexandr.Nedvedicky@Sun.COM tcp = (tcphdr_t *) fin->fin_dp;
23769888SAlexandr.Nedvedicky@Sun.COM
23779695SAlexandr.Nedvedicky@Sun.COM if ((fin->fin_p == IPPROTO_TCP) &&
23789888SAlexandr.Nedvedicky@Sun.COM ((tcp == NULL) || ((tcp->th_flags & (TH_SYN | TH_FIN)) == 0)))
23799695SAlexandr.Nedvedicky@Sun.COM return (-1);
23809695SAlexandr.Nedvedicky@Sun.COM
23819695SAlexandr.Nedvedicky@Sun.COM /*
23829695SAlexandr.Nedvedicky@Sun.COM * Step (1)
23839695SAlexandr.Nedvedicky@Sun.COM *
23849695SAlexandr.Nedvedicky@Sun.COM * Make copy of original mblk.
23859695SAlexandr.Nedvedicky@Sun.COM *
23869695SAlexandr.Nedvedicky@Sun.COM * We want to copy as much data as necessary, not less, not more. The
23879695SAlexandr.Nedvedicky@Sun.COM * ICMPv4 payload length for unreachable messages is:
23889695SAlexandr.Nedvedicky@Sun.COM * original IP header + 8 bytes of L4 (if there are any).
23899695SAlexandr.Nedvedicky@Sun.COM *
23909695SAlexandr.Nedvedicky@Sun.COM * We determine if there are at least 8 bytes of L4 data following IP
23919695SAlexandr.Nedvedicky@Sun.COM * header first.
23929695SAlexandr.Nedvedicky@Sun.COM */
23939695SAlexandr.Nedvedicky@Sun.COM icmp_pld_len = (fin->fin_dlen > ICMPERR_ICMPHLEN) ?
23949695SAlexandr.Nedvedicky@Sun.COM ICMPERR_ICMPHLEN : fin->fin_dlen;
23959695SAlexandr.Nedvedicky@Sun.COM /*
23969695SAlexandr.Nedvedicky@Sun.COM * Since we don't want to copy more data than necessary, we must trim
23979695SAlexandr.Nedvedicky@Sun.COM * the original mblk here. The right way (STREAMish) would be to use
23989695SAlexandr.Nedvedicky@Sun.COM * adjmsg() to trim it. However we would have to calculate the length
23999695SAlexandr.Nedvedicky@Sun.COM * argument for adjmsg() from pointers we already have here.
24009695SAlexandr.Nedvedicky@Sun.COM *
24019695SAlexandr.Nedvedicky@Sun.COM * Since we have pointers and offsets, it's faster and easier for
24029695SAlexandr.Nedvedicky@Sun.COM * us to just adjust pointers by hand instead of using adjmsg().
24039695SAlexandr.Nedvedicky@Sun.COM */
24049695SAlexandr.Nedvedicky@Sun.COM fin->fin_m->b_wptr = (unsigned char *) fin->fin_dp;
24059695SAlexandr.Nedvedicky@Sun.COM fin->fin_m->b_wptr += icmp_pld_len;
24069695SAlexandr.Nedvedicky@Sun.COM icmp_pld_len = fin->fin_m->b_wptr - (unsigned char *) fin->fin_ip;
24079695SAlexandr.Nedvedicky@Sun.COM
24089695SAlexandr.Nedvedicky@Sun.COM /*
24099695SAlexandr.Nedvedicky@Sun.COM * Also we don't want to copy any L2 stuff, which might precede IP
24109695SAlexandr.Nedvedicky@Sun.COM * header, so we have have to set b_rptr to point to the start of IP
24119695SAlexandr.Nedvedicky@Sun.COM * header.
24129695SAlexandr.Nedvedicky@Sun.COM */
24139695SAlexandr.Nedvedicky@Sun.COM fin->fin_m->b_rptr += fin->fin_ipoff;
24149695SAlexandr.Nedvedicky@Sun.COM if ((mblk_ip = copyb(fin->fin_m)) == NULL)
24159695SAlexandr.Nedvedicky@Sun.COM return (-1);
24169695SAlexandr.Nedvedicky@Sun.COM fin->fin_m->b_rptr -= fin->fin_ipoff;
24179695SAlexandr.Nedvedicky@Sun.COM
24189695SAlexandr.Nedvedicky@Sun.COM /*
24199695SAlexandr.Nedvedicky@Sun.COM * Step (2)
24209695SAlexandr.Nedvedicky@Sun.COM *
24219695SAlexandr.Nedvedicky@Sun.COM * Create an ICMP header, which will be appened to original mblk later.
24229695SAlexandr.Nedvedicky@Sun.COM * ICMP header is just another mblk.
24239695SAlexandr.Nedvedicky@Sun.COM */
24249695SAlexandr.Nedvedicky@Sun.COM mblk_icmp = (mblk_t *) allocb(ICMPERR_ICMPHLEN, BPRI_HI);
24259695SAlexandr.Nedvedicky@Sun.COM if (mblk_icmp == NULL) {
24269695SAlexandr.Nedvedicky@Sun.COM FREE_MB_T(mblk_ip);
24279695SAlexandr.Nedvedicky@Sun.COM return (-1);
24289695SAlexandr.Nedvedicky@Sun.COM }
24299695SAlexandr.Nedvedicky@Sun.COM
24309695SAlexandr.Nedvedicky@Sun.COM MTYPE(mblk_icmp) = M_DATA;
24319695SAlexandr.Nedvedicky@Sun.COM icmp = (struct icmp *) mblk_icmp->b_wptr;
24329695SAlexandr.Nedvedicky@Sun.COM icmp->icmp_type = ICMP_UNREACH;
24339695SAlexandr.Nedvedicky@Sun.COM icmp->icmp_code = fin->fin_icode & 0xFF;
24349695SAlexandr.Nedvedicky@Sun.COM icmp->icmp_void = 0;
24359695SAlexandr.Nedvedicky@Sun.COM icmp->icmp_cksum = 0;
24369695SAlexandr.Nedvedicky@Sun.COM mblk_icmp->b_wptr += ICMPERR_ICMPHLEN;
24379695SAlexandr.Nedvedicky@Sun.COM
24389695SAlexandr.Nedvedicky@Sun.COM /*
24399695SAlexandr.Nedvedicky@Sun.COM * Step (3)
24409695SAlexandr.Nedvedicky@Sun.COM *
24419695SAlexandr.Nedvedicky@Sun.COM * Complete ICMP packet - link ICMP header with L4 data from original
24429695SAlexandr.Nedvedicky@Sun.COM * IP packet.
24439695SAlexandr.Nedvedicky@Sun.COM */
24449695SAlexandr.Nedvedicky@Sun.COM linkb(mblk_icmp, mblk_ip);
24459695SAlexandr.Nedvedicky@Sun.COM
24469695SAlexandr.Nedvedicky@Sun.COM /*
24479695SAlexandr.Nedvedicky@Sun.COM * Step (4)
24489695SAlexandr.Nedvedicky@Sun.COM *
24499695SAlexandr.Nedvedicky@Sun.COM * Swap IP addresses and change IP header fields accordingly in
24509695SAlexandr.Nedvedicky@Sun.COM * original IP packet.
24519695SAlexandr.Nedvedicky@Sun.COM *
24529695SAlexandr.Nedvedicky@Sun.COM * There is a rule option return-icmp as a dest for physical
24539695SAlexandr.Nedvedicky@Sun.COM * interfaces. This option becomes useless for loopback, since IPF box
24549695SAlexandr.Nedvedicky@Sun.COM * uses same address as a loopback destination. We ignore the option
24559695SAlexandr.Nedvedicky@Sun.COM * here, the ICMP packet will always look like as it would have been
24569695SAlexandr.Nedvedicky@Sun.COM * sent from the original destination host.
24579695SAlexandr.Nedvedicky@Sun.COM */
24589695SAlexandr.Nedvedicky@Sun.COM tmp_src = fin->fin_ip->ip_src;
24599695SAlexandr.Nedvedicky@Sun.COM fin->fin_ip->ip_src = fin->fin_ip->ip_dst;
24609695SAlexandr.Nedvedicky@Sun.COM fin->fin_ip->ip_dst = tmp_src;
24619695SAlexandr.Nedvedicky@Sun.COM fin->fin_ip->ip_p = IPPROTO_ICMP;
24629695SAlexandr.Nedvedicky@Sun.COM fin->fin_ip->ip_sum = 0;
24639695SAlexandr.Nedvedicky@Sun.COM
24649695SAlexandr.Nedvedicky@Sun.COM /*
24659695SAlexandr.Nedvedicky@Sun.COM * Step (5)
24669695SAlexandr.Nedvedicky@Sun.COM *
24679695SAlexandr.Nedvedicky@Sun.COM * We trim the orignal mblk to hold IP header only.
24689695SAlexandr.Nedvedicky@Sun.COM */
24699695SAlexandr.Nedvedicky@Sun.COM fin->fin_m->b_wptr = fin->fin_dp;
24709695SAlexandr.Nedvedicky@Sun.COM orig_iphdr_len = fin->fin_m->b_wptr -
24719695SAlexandr.Nedvedicky@Sun.COM (fin->fin_m->b_rptr + fin->fin_ipoff);
24729695SAlexandr.Nedvedicky@Sun.COM fin->fin_ip->ip_len = htons(icmp_pld_len + ICMPERR_ICMPHLEN +
24739695SAlexandr.Nedvedicky@Sun.COM orig_iphdr_len);
24749695SAlexandr.Nedvedicky@Sun.COM
24759695SAlexandr.Nedvedicky@Sun.COM /*
24769695SAlexandr.Nedvedicky@Sun.COM * ICMP chksum calculation. The data we are calculating chksum for are
24779695SAlexandr.Nedvedicky@Sun.COM * spread over two mblks, therefore we have to use two for loops.
24789695SAlexandr.Nedvedicky@Sun.COM *
24799695SAlexandr.Nedvedicky@Sun.COM * First for loop computes chksum part for ICMP header.
24809695SAlexandr.Nedvedicky@Sun.COM */
24819695SAlexandr.Nedvedicky@Sun.COM buf = (uint16_t *) icmp;
24829695SAlexandr.Nedvedicky@Sun.COM len = ICMPERR_ICMPHLEN;
24839695SAlexandr.Nedvedicky@Sun.COM for (sum = 0; len > 1; len -= 2)
24849695SAlexandr.Nedvedicky@Sun.COM sum += *buf++;
24859695SAlexandr.Nedvedicky@Sun.COM
24869695SAlexandr.Nedvedicky@Sun.COM /*
24879695SAlexandr.Nedvedicky@Sun.COM * Here we add chksum part for ICMP payload.
24889695SAlexandr.Nedvedicky@Sun.COM */
24899695SAlexandr.Nedvedicky@Sun.COM len = icmp_pld_len;
24909695SAlexandr.Nedvedicky@Sun.COM buf = (uint16_t *) mblk_ip->b_rptr;
24919695SAlexandr.Nedvedicky@Sun.COM for (; len > 1; len -= 2)
24929695SAlexandr.Nedvedicky@Sun.COM sum += *buf++;
24939695SAlexandr.Nedvedicky@Sun.COM
24949695SAlexandr.Nedvedicky@Sun.COM /*
24959695SAlexandr.Nedvedicky@Sun.COM * Chksum is done.
24969695SAlexandr.Nedvedicky@Sun.COM */
24979695SAlexandr.Nedvedicky@Sun.COM sum = (sum >> 16) + (sum & 0xffff);
24989695SAlexandr.Nedvedicky@Sun.COM sum += (sum >> 16);
24999695SAlexandr.Nedvedicky@Sun.COM icmp->icmp_cksum = ~sum;
25009695SAlexandr.Nedvedicky@Sun.COM
25019695SAlexandr.Nedvedicky@Sun.COM /*
25029695SAlexandr.Nedvedicky@Sun.COM * Step (6)
25039695SAlexandr.Nedvedicky@Sun.COM *
25049695SAlexandr.Nedvedicky@Sun.COM * Release all packet mblks, except the first one.
25059695SAlexandr.Nedvedicky@Sun.COM */
25069695SAlexandr.Nedvedicky@Sun.COM if (fin->fin_m->b_cont != NULL) {
25079695SAlexandr.Nedvedicky@Sun.COM FREE_MB_T(fin->fin_m->b_cont);
25089695SAlexandr.Nedvedicky@Sun.COM }
25099695SAlexandr.Nedvedicky@Sun.COM
25109695SAlexandr.Nedvedicky@Sun.COM /*
25119695SAlexandr.Nedvedicky@Sun.COM * Append ICMP payload to first mblk, which already contains new IP
25129695SAlexandr.Nedvedicky@Sun.COM * header.
25139695SAlexandr.Nedvedicky@Sun.COM */
25149695SAlexandr.Nedvedicky@Sun.COM linkb(fin->fin_m, mblk_icmp);
25159695SAlexandr.Nedvedicky@Sun.COM
25169695SAlexandr.Nedvedicky@Sun.COM return (0);
25179695SAlexandr.Nedvedicky@Sun.COM }
25189695SAlexandr.Nedvedicky@Sun.COM
25199695SAlexandr.Nedvedicky@Sun.COM #ifdef USE_INET6
25209695SAlexandr.Nedvedicky@Sun.COM /* ------------------------------------------------------------------------ */
25219695SAlexandr.Nedvedicky@Sun.COM /* Function: fr_make_icmp_v6 */
25229695SAlexandr.Nedvedicky@Sun.COM /* Returns: int - 0 on success, -1 on failure */
25239695SAlexandr.Nedvedicky@Sun.COM /* Parameters: fin(I) - pointer to packet information */
25249695SAlexandr.Nedvedicky@Sun.COM /* */
25259695SAlexandr.Nedvedicky@Sun.COM /* Please read comment at fr_make_icmp() wrapper function to get an idea */
25269695SAlexandr.Nedvedicky@Sun.COM /* what and why is going to happen here. Once you read the comment there, */
25279695SAlexandr.Nedvedicky@Sun.COM /* continue here with next paragraph. */
25289695SAlexandr.Nedvedicky@Sun.COM /* */
25299695SAlexandr.Nedvedicky@Sun.COM /* This function turns IPv6 packet (UDP, TCP, ...) into ICMPv6 response. */
25309695SAlexandr.Nedvedicky@Sun.COM /* The algorithm is fairly simple: */
25319695SAlexandr.Nedvedicky@Sun.COM /* 1) We need to get copy of complete mblk. */
25329695SAlexandr.Nedvedicky@Sun.COM /* */
25339695SAlexandr.Nedvedicky@Sun.COM /* 2) New ICMPv6 header is created. */
25349695SAlexandr.Nedvedicky@Sun.COM /* */
25359695SAlexandr.Nedvedicky@Sun.COM /* 3) The copy of original mblk with packet is linked to ICMPv6 */
25369695SAlexandr.Nedvedicky@Sun.COM /* header. */
25379695SAlexandr.Nedvedicky@Sun.COM /* */
25389695SAlexandr.Nedvedicky@Sun.COM /* 4) The checksum must be adjusted. */
25399695SAlexandr.Nedvedicky@Sun.COM /* */
25409695SAlexandr.Nedvedicky@Sun.COM /* 5) IP addresses in original mblk are swapped and IP header data */
25419695SAlexandr.Nedvedicky@Sun.COM /* are adjusted (protocol number). */
25429695SAlexandr.Nedvedicky@Sun.COM /* */
25439695SAlexandr.Nedvedicky@Sun.COM /* 6) Original mblk is trimmed to hold IPv6 header only, then it is */
25449695SAlexandr.Nedvedicky@Sun.COM /* linked with the ICMPv6 data we got from (3). */
25459695SAlexandr.Nedvedicky@Sun.COM /* ------------------------------------------------------------------------ */
fr_make_icmp_v6(fin)25469695SAlexandr.Nedvedicky@Sun.COM static int fr_make_icmp_v6(fin)
25479695SAlexandr.Nedvedicky@Sun.COM fr_info_t *fin;
25489695SAlexandr.Nedvedicky@Sun.COM {
25499695SAlexandr.Nedvedicky@Sun.COM struct icmp6_hdr *icmp6;
25509888SAlexandr.Nedvedicky@Sun.COM tcphdr_t *tcp;
25519695SAlexandr.Nedvedicky@Sun.COM struct in6_addr tmp_src6;
25529695SAlexandr.Nedvedicky@Sun.COM size_t icmp_pld_len;
25539695SAlexandr.Nedvedicky@Sun.COM mblk_t *mblk_ip, *mblk_icmp;
25549695SAlexandr.Nedvedicky@Sun.COM
25559695SAlexandr.Nedvedicky@Sun.COM if (fin->fin_v != 6)
25569695SAlexandr.Nedvedicky@Sun.COM return (-1);
25579695SAlexandr.Nedvedicky@Sun.COM
25589695SAlexandr.Nedvedicky@Sun.COM /*
25599695SAlexandr.Nedvedicky@Sun.COM * If we are dealing with TCP, then packet must SYN/FIN to be routed by
25609695SAlexandr.Nedvedicky@Sun.COM * IP stack. If it is not SYN/FIN, then we must drop it silently.
25619695SAlexandr.Nedvedicky@Sun.COM */
25629888SAlexandr.Nedvedicky@Sun.COM tcp = (tcphdr_t *) fin->fin_dp;
25639888SAlexandr.Nedvedicky@Sun.COM
25649888SAlexandr.Nedvedicky@Sun.COM if ((fin->fin_p == IPPROTO_TCP) &&
25659888SAlexandr.Nedvedicky@Sun.COM ((tcp == NULL) || ((tcp->th_flags & (TH_SYN | TH_FIN)) == 0)))
25669695SAlexandr.Nedvedicky@Sun.COM return (-1);
25679695SAlexandr.Nedvedicky@Sun.COM
25689695SAlexandr.Nedvedicky@Sun.COM /*
25699695SAlexandr.Nedvedicky@Sun.COM * Step (1)
25709695SAlexandr.Nedvedicky@Sun.COM *
25719695SAlexandr.Nedvedicky@Sun.COM * We need to copy complete packet in case of IPv6, no trimming is
25729695SAlexandr.Nedvedicky@Sun.COM * needed (except the L2 headers).
25739695SAlexandr.Nedvedicky@Sun.COM */
25749695SAlexandr.Nedvedicky@Sun.COM icmp_pld_len = M_LEN(fin->fin_m);
25759695SAlexandr.Nedvedicky@Sun.COM fin->fin_m->b_rptr += fin->fin_ipoff;
25769695SAlexandr.Nedvedicky@Sun.COM if ((mblk_ip = copyb(fin->fin_m)) == NULL)
25779695SAlexandr.Nedvedicky@Sun.COM return (-1);
25789695SAlexandr.Nedvedicky@Sun.COM fin->fin_m->b_rptr -= fin->fin_ipoff;
25799695SAlexandr.Nedvedicky@Sun.COM
25809695SAlexandr.Nedvedicky@Sun.COM /*
25819695SAlexandr.Nedvedicky@Sun.COM * Step (2)
25829695SAlexandr.Nedvedicky@Sun.COM *
25839695SAlexandr.Nedvedicky@Sun.COM * Allocate and create ICMP header.
25849695SAlexandr.Nedvedicky@Sun.COM */
25859695SAlexandr.Nedvedicky@Sun.COM mblk_icmp = (mblk_t *) allocb(sizeof (struct icmp6_hdr),
25869695SAlexandr.Nedvedicky@Sun.COM BPRI_HI);
25879695SAlexandr.Nedvedicky@Sun.COM
25889695SAlexandr.Nedvedicky@Sun.COM if (mblk_icmp == NULL)
25899695SAlexandr.Nedvedicky@Sun.COM return (-1);
25909695SAlexandr.Nedvedicky@Sun.COM
25919695SAlexandr.Nedvedicky@Sun.COM MTYPE(mblk_icmp) = M_DATA;
25929695SAlexandr.Nedvedicky@Sun.COM icmp6 = (struct icmp6_hdr *) mblk_icmp->b_wptr;
25939695SAlexandr.Nedvedicky@Sun.COM icmp6->icmp6_type = ICMP6_DST_UNREACH;
25949695SAlexandr.Nedvedicky@Sun.COM icmp6->icmp6_code = fin->fin_icode & 0xFF;
25959695SAlexandr.Nedvedicky@Sun.COM icmp6->icmp6_data32[0] = 0;
25969695SAlexandr.Nedvedicky@Sun.COM mblk_icmp->b_wptr += sizeof (struct icmp6_hdr);
25979695SAlexandr.Nedvedicky@Sun.COM
25989695SAlexandr.Nedvedicky@Sun.COM /*
25999695SAlexandr.Nedvedicky@Sun.COM * Step (3)
26009695SAlexandr.Nedvedicky@Sun.COM *
26019695SAlexandr.Nedvedicky@Sun.COM * Link the copy of IP packet to ICMP header.
26029695SAlexandr.Nedvedicky@Sun.COM */
26039695SAlexandr.Nedvedicky@Sun.COM linkb(mblk_icmp, mblk_ip);
26049695SAlexandr.Nedvedicky@Sun.COM
26059695SAlexandr.Nedvedicky@Sun.COM /*
26069695SAlexandr.Nedvedicky@Sun.COM * Step (4)
26079695SAlexandr.Nedvedicky@Sun.COM *
26089695SAlexandr.Nedvedicky@Sun.COM * Calculate chksum - this is much more easier task than in case of
26099695SAlexandr.Nedvedicky@Sun.COM * IPv4 - ICMPv6 chksum only covers IP addresses, and payload length.
26109695SAlexandr.Nedvedicky@Sun.COM * We are making compensation just for change of packet length.
26119695SAlexandr.Nedvedicky@Sun.COM */
26129695SAlexandr.Nedvedicky@Sun.COM icmp6->icmp6_cksum = icmp_pld_len + sizeof (struct icmp6_hdr);
26139695SAlexandr.Nedvedicky@Sun.COM
26149695SAlexandr.Nedvedicky@Sun.COM /*
26159695SAlexandr.Nedvedicky@Sun.COM * Step (5)
26169695SAlexandr.Nedvedicky@Sun.COM *
26179695SAlexandr.Nedvedicky@Sun.COM * Swap IP addresses.
26189695SAlexandr.Nedvedicky@Sun.COM */
26199695SAlexandr.Nedvedicky@Sun.COM tmp_src6 = fin->fin_ip6->ip6_src;
26209695SAlexandr.Nedvedicky@Sun.COM fin->fin_ip6->ip6_src = fin->fin_ip6->ip6_dst;
26219695SAlexandr.Nedvedicky@Sun.COM fin->fin_ip6->ip6_dst = tmp_src6;
26229695SAlexandr.Nedvedicky@Sun.COM
26239695SAlexandr.Nedvedicky@Sun.COM /*
26249695SAlexandr.Nedvedicky@Sun.COM * and adjust IP header data.
26259695SAlexandr.Nedvedicky@Sun.COM */
26269695SAlexandr.Nedvedicky@Sun.COM fin->fin_ip6->ip6_nxt = IPPROTO_ICMPV6;
26279695SAlexandr.Nedvedicky@Sun.COM fin->fin_ip6->ip6_plen = htons(icmp_pld_len + sizeof (struct icmp6_hdr));
26289695SAlexandr.Nedvedicky@Sun.COM
26299695SAlexandr.Nedvedicky@Sun.COM /*
26309695SAlexandr.Nedvedicky@Sun.COM * Step (6)
26319695SAlexandr.Nedvedicky@Sun.COM *
26329695SAlexandr.Nedvedicky@Sun.COM * We must release all linked mblks from original packet and keep only
26339695SAlexandr.Nedvedicky@Sun.COM * the first mblk with IP header to link ICMP data.
26349695SAlexandr.Nedvedicky@Sun.COM */
26359695SAlexandr.Nedvedicky@Sun.COM fin->fin_m->b_wptr = (unsigned char *) fin->fin_ip6 + sizeof (ip6_t);
26369695SAlexandr.Nedvedicky@Sun.COM
26379695SAlexandr.Nedvedicky@Sun.COM if (fin->fin_m->b_cont != NULL) {
26389695SAlexandr.Nedvedicky@Sun.COM FREE_MB_T(fin->fin_m->b_cont);
26399695SAlexandr.Nedvedicky@Sun.COM }
26409695SAlexandr.Nedvedicky@Sun.COM
26419695SAlexandr.Nedvedicky@Sun.COM /*
26429695SAlexandr.Nedvedicky@Sun.COM * Append ICMP payload to IP header.
26439695SAlexandr.Nedvedicky@Sun.COM */
26449695SAlexandr.Nedvedicky@Sun.COM linkb(fin->fin_m, mblk_icmp);
26459695SAlexandr.Nedvedicky@Sun.COM
26469695SAlexandr.Nedvedicky@Sun.COM return (0);
26479695SAlexandr.Nedvedicky@Sun.COM }
26489695SAlexandr.Nedvedicky@Sun.COM #endif /* USE_INET6 */
26499695SAlexandr.Nedvedicky@Sun.COM
26509695SAlexandr.Nedvedicky@Sun.COM /* ------------------------------------------------------------------------ */
26519695SAlexandr.Nedvedicky@Sun.COM /* Function: fr_make_icmp */
26529695SAlexandr.Nedvedicky@Sun.COM /* Returns: int - 0 on success, -1 on failure */
26539695SAlexandr.Nedvedicky@Sun.COM /* Parameters: fin(I) - pointer to packet information */
26549695SAlexandr.Nedvedicky@Sun.COM /* */
26559695SAlexandr.Nedvedicky@Sun.COM /* We must alter the original mblks passed to IPF from IP stack via */
26569695SAlexandr.Nedvedicky@Sun.COM /* FW_HOOKS. The reasons why we must alter packet are discussed within */
26579695SAlexandr.Nedvedicky@Sun.COM /* comment at fr_make_rst() function. */
26589695SAlexandr.Nedvedicky@Sun.COM /* */
26599695SAlexandr.Nedvedicky@Sun.COM /* The fr_make_icmp() function acts as a wrapper, which passes the code */
26609695SAlexandr.Nedvedicky@Sun.COM /* execution to fr_make_icmp_v4() or fr_make_icmp_v6() depending on */
26619695SAlexandr.Nedvedicky@Sun.COM /* protocol version. However there are some details, which are common to */
26629695SAlexandr.Nedvedicky@Sun.COM /* both IP versions. The details are going to be explained here. */
26639695SAlexandr.Nedvedicky@Sun.COM /* */
26649695SAlexandr.Nedvedicky@Sun.COM /* The packet looks as follows: */
26659695SAlexandr.Nedvedicky@Sun.COM /* xxx | IP hdr | IP payload ... | */
26669695SAlexandr.Nedvedicky@Sun.COM /* ^ ^ ^ ^ */
26679695SAlexandr.Nedvedicky@Sun.COM /* | | | | */
26689695SAlexandr.Nedvedicky@Sun.COM /* | | | fin_m->b_wptr = fin->fin_dp + fin->fin_dlen */
26699695SAlexandr.Nedvedicky@Sun.COM /* | | | */
26709695SAlexandr.Nedvedicky@Sun.COM /* | | `- fin_m->fin_dp (in case of IPv4 points to L4 header) */
26719695SAlexandr.Nedvedicky@Sun.COM /* | | */
26729695SAlexandr.Nedvedicky@Sun.COM /* | `- fin_m->b_rptr + fin_ipoff (fin_ipoff is most likely 0 in case */
26739695SAlexandr.Nedvedicky@Sun.COM /* | of loopback) */
26749695SAlexandr.Nedvedicky@Sun.COM /* | */
26759695SAlexandr.Nedvedicky@Sun.COM /* `- fin_m->b_rptr - points to L2 header in case of physical NIC */
26769695SAlexandr.Nedvedicky@Sun.COM /* */
26779695SAlexandr.Nedvedicky@Sun.COM /* All relevant IP headers are pulled up into the first mblk. It happened */
26789695SAlexandr.Nedvedicky@Sun.COM /* well in advance before the matching rule was found (the rule, which took */
26799695SAlexandr.Nedvedicky@Sun.COM /* us here, to fr_make_icmp() function). */
26809695SAlexandr.Nedvedicky@Sun.COM /* */
26819695SAlexandr.Nedvedicky@Sun.COM /* Both functions will turn packet passed in fin->fin_m mblk into a new */
26829695SAlexandr.Nedvedicky@Sun.COM /* packet. New packet will be represented as chain of mblks. */
26839695SAlexandr.Nedvedicky@Sun.COM /* orig mblk |- b_cont ---. */
26849695SAlexandr.Nedvedicky@Sun.COM /* ^ `-> ICMP hdr |- b_cont--. */
26859695SAlexandr.Nedvedicky@Sun.COM /* | ^ `-> duped orig mblk */
26869695SAlexandr.Nedvedicky@Sun.COM /* | | ^ */
26879695SAlexandr.Nedvedicky@Sun.COM /* `- The original mblk | | */
26889695SAlexandr.Nedvedicky@Sun.COM /* will be trimmed to | | */
26899695SAlexandr.Nedvedicky@Sun.COM /* to contain IP header | | */
26909695SAlexandr.Nedvedicky@Sun.COM /* only | | */
26919695SAlexandr.Nedvedicky@Sun.COM /* | | */
26929695SAlexandr.Nedvedicky@Sun.COM /* `- This is newly | */
26939695SAlexandr.Nedvedicky@Sun.COM /* allocated mblk to | */
26949695SAlexandr.Nedvedicky@Sun.COM /* hold ICMPv6 data. | */
26959695SAlexandr.Nedvedicky@Sun.COM /* | */
26969695SAlexandr.Nedvedicky@Sun.COM /* | */
26979695SAlexandr.Nedvedicky@Sun.COM /* | */
26989695SAlexandr.Nedvedicky@Sun.COM /* This is the copy of original mblk, it will contain -' */
26999695SAlexandr.Nedvedicky@Sun.COM /* orignal IP packet in case of ICMPv6. In case of */
27009695SAlexandr.Nedvedicky@Sun.COM /* ICMPv4 it will contain up to 8 bytes of IP payload */
27019695SAlexandr.Nedvedicky@Sun.COM /* (TCP/UDP/L4) data from original packet. */
27029695SAlexandr.Nedvedicky@Sun.COM /* ------------------------------------------------------------------------ */
fr_make_icmp(fin)27039695SAlexandr.Nedvedicky@Sun.COM int fr_make_icmp(fin)
27049695SAlexandr.Nedvedicky@Sun.COM fr_info_t *fin;
27059695SAlexandr.Nedvedicky@Sun.COM {
27069695SAlexandr.Nedvedicky@Sun.COM int rv;
27079695SAlexandr.Nedvedicky@Sun.COM
27089695SAlexandr.Nedvedicky@Sun.COM if (fin->fin_v == 4)
27099695SAlexandr.Nedvedicky@Sun.COM rv = fr_make_icmp_v4(fin);
27109695SAlexandr.Nedvedicky@Sun.COM #ifdef USE_INET6
27119695SAlexandr.Nedvedicky@Sun.COM else if (fin->fin_v == 6)
27129695SAlexandr.Nedvedicky@Sun.COM rv = fr_make_icmp_v6(fin);
27139695SAlexandr.Nedvedicky@Sun.COM #endif
27149695SAlexandr.Nedvedicky@Sun.COM else
27159695SAlexandr.Nedvedicky@Sun.COM rv = -1;
27169695SAlexandr.Nedvedicky@Sun.COM
27179695SAlexandr.Nedvedicky@Sun.COM return (rv);
27189695SAlexandr.Nedvedicky@Sun.COM }
2719*12358SAlexandr.Nedvedicky@Sun.COM
2720*12358SAlexandr.Nedvedicky@Sun.COM /* ------------------------------------------------------------------------ */
2721*12358SAlexandr.Nedvedicky@Sun.COM /* Function: fr_buf_sum */
2722*12358SAlexandr.Nedvedicky@Sun.COM /* Returns: unsigned int - sum of buffer buf */
2723*12358SAlexandr.Nedvedicky@Sun.COM /* Parameters: buf - pointer to buf we want to sum up */
2724*12358SAlexandr.Nedvedicky@Sun.COM /* len - length of buffer buf */
2725*12358SAlexandr.Nedvedicky@Sun.COM /* */
2726*12358SAlexandr.Nedvedicky@Sun.COM /* Sums buffer buf. The result is used for chksum calculation. The buf */
2727*12358SAlexandr.Nedvedicky@Sun.COM /* argument must be aligned. */
2728*12358SAlexandr.Nedvedicky@Sun.COM /* ------------------------------------------------------------------------ */
fr_buf_sum(buf,len)2729*12358SAlexandr.Nedvedicky@Sun.COM static uint32_t fr_buf_sum(buf, len)
2730*12358SAlexandr.Nedvedicky@Sun.COM const void *buf;
2731*12358SAlexandr.Nedvedicky@Sun.COM unsigned int len;
2732*12358SAlexandr.Nedvedicky@Sun.COM {
2733*12358SAlexandr.Nedvedicky@Sun.COM uint32_t sum = 0;
2734*12358SAlexandr.Nedvedicky@Sun.COM uint16_t *b = (uint16_t *)buf;
2735*12358SAlexandr.Nedvedicky@Sun.COM
2736*12358SAlexandr.Nedvedicky@Sun.COM while (len > 1) {
2737*12358SAlexandr.Nedvedicky@Sun.COM sum += *b++;
2738*12358SAlexandr.Nedvedicky@Sun.COM len -= 2;
2739*12358SAlexandr.Nedvedicky@Sun.COM }
2740*12358SAlexandr.Nedvedicky@Sun.COM
2741*12358SAlexandr.Nedvedicky@Sun.COM if (len == 1)
2742*12358SAlexandr.Nedvedicky@Sun.COM sum += htons((*(unsigned char *)b) << 8);
2743*12358SAlexandr.Nedvedicky@Sun.COM
2744*12358SAlexandr.Nedvedicky@Sun.COM return (sum);
2745*12358SAlexandr.Nedvedicky@Sun.COM }
2746*12358SAlexandr.Nedvedicky@Sun.COM
2747*12358SAlexandr.Nedvedicky@Sun.COM /* ------------------------------------------------------------------------ */
2748*12358SAlexandr.Nedvedicky@Sun.COM /* Function: fr_calc_chksum */
2749*12358SAlexandr.Nedvedicky@Sun.COM /* Returns: void */
2750*12358SAlexandr.Nedvedicky@Sun.COM /* Parameters: fin - pointer to fr_info_t instance with packet data */
2751*12358SAlexandr.Nedvedicky@Sun.COM /* pkt - pointer to duplicated packet */
2752*12358SAlexandr.Nedvedicky@Sun.COM /* */
2753*12358SAlexandr.Nedvedicky@Sun.COM /* Calculates all chksums (L3, L4) for packet pkt. Works for both IP */
2754*12358SAlexandr.Nedvedicky@Sun.COM /* versions. */
2755*12358SAlexandr.Nedvedicky@Sun.COM /* ------------------------------------------------------------------------ */
fr_calc_chksum(fin,pkt)2756*12358SAlexandr.Nedvedicky@Sun.COM void fr_calc_chksum(fin, pkt)
2757*12358SAlexandr.Nedvedicky@Sun.COM fr_info_t *fin;
2758*12358SAlexandr.Nedvedicky@Sun.COM mb_t *pkt;
2759*12358SAlexandr.Nedvedicky@Sun.COM {
2760*12358SAlexandr.Nedvedicky@Sun.COM struct pseudo_hdr {
2761*12358SAlexandr.Nedvedicky@Sun.COM union {
2762*12358SAlexandr.Nedvedicky@Sun.COM struct in_addr in4;
2763*12358SAlexandr.Nedvedicky@Sun.COM #ifdef USE_INET6
2764*12358SAlexandr.Nedvedicky@Sun.COM struct in6_addr in6;
2765*12358SAlexandr.Nedvedicky@Sun.COM #endif
2766*12358SAlexandr.Nedvedicky@Sun.COM } src_addr;
2767*12358SAlexandr.Nedvedicky@Sun.COM union {
2768*12358SAlexandr.Nedvedicky@Sun.COM struct in_addr in4;
2769*12358SAlexandr.Nedvedicky@Sun.COM #ifdef USE_INET6
2770*12358SAlexandr.Nedvedicky@Sun.COM struct in6_addr in6;
2771*12358SAlexandr.Nedvedicky@Sun.COM #endif
2772*12358SAlexandr.Nedvedicky@Sun.COM } dst_addr;
2773*12358SAlexandr.Nedvedicky@Sun.COM char zero;
2774*12358SAlexandr.Nedvedicky@Sun.COM char proto;
2775*12358SAlexandr.Nedvedicky@Sun.COM uint16_t len;
2776*12358SAlexandr.Nedvedicky@Sun.COM } phdr;
2777*12358SAlexandr.Nedvedicky@Sun.COM uint32_t sum, ip_sum;
2778*12358SAlexandr.Nedvedicky@Sun.COM void *buf;
2779*12358SAlexandr.Nedvedicky@Sun.COM uint16_t *l4_csum_p;
2780*12358SAlexandr.Nedvedicky@Sun.COM tcphdr_t *tcp;
2781*12358SAlexandr.Nedvedicky@Sun.COM udphdr_t *udp;
2782*12358SAlexandr.Nedvedicky@Sun.COM icmphdr_t *icmp;
2783*12358SAlexandr.Nedvedicky@Sun.COM #ifdef USE_INET6
2784*12358SAlexandr.Nedvedicky@Sun.COM struct icmp6_hdr *icmp6;
2785*12358SAlexandr.Nedvedicky@Sun.COM #endif
2786*12358SAlexandr.Nedvedicky@Sun.COM ip_t *ip;
2787*12358SAlexandr.Nedvedicky@Sun.COM unsigned int len;
2788*12358SAlexandr.Nedvedicky@Sun.COM int pld_len;
2789*12358SAlexandr.Nedvedicky@Sun.COM
2790*12358SAlexandr.Nedvedicky@Sun.COM /*
2791*12358SAlexandr.Nedvedicky@Sun.COM * We need to pullup the packet to the single continuous buffer to avoid
2792*12358SAlexandr.Nedvedicky@Sun.COM * potential misaligment of b_rptr member in mblk chain.
2793*12358SAlexandr.Nedvedicky@Sun.COM */
2794*12358SAlexandr.Nedvedicky@Sun.COM if (pullupmsg(pkt, -1) == 0) {
2795*12358SAlexandr.Nedvedicky@Sun.COM cmn_err(CE_WARN, "Failed to pullup loopback pkt -> chksum"
2796*12358SAlexandr.Nedvedicky@Sun.COM " will not be computed by IPF");
2797*12358SAlexandr.Nedvedicky@Sun.COM return;
2798*12358SAlexandr.Nedvedicky@Sun.COM }
2799*12358SAlexandr.Nedvedicky@Sun.COM
2800*12358SAlexandr.Nedvedicky@Sun.COM /*
2801*12358SAlexandr.Nedvedicky@Sun.COM * It is guaranteed IP header starts right at b_rptr, because we are
2802*12358SAlexandr.Nedvedicky@Sun.COM * working with a copy of the original packet.
2803*12358SAlexandr.Nedvedicky@Sun.COM *
2804*12358SAlexandr.Nedvedicky@Sun.COM * Compute pseudo header chksum for TCP and UDP.
2805*12358SAlexandr.Nedvedicky@Sun.COM */
2806*12358SAlexandr.Nedvedicky@Sun.COM if ((fin->fin_p == IPPROTO_UDP) ||
2807*12358SAlexandr.Nedvedicky@Sun.COM (fin->fin_p == IPPROTO_TCP)) {
2808*12358SAlexandr.Nedvedicky@Sun.COM bzero(&phdr, sizeof (phdr));
2809*12358SAlexandr.Nedvedicky@Sun.COM #ifdef USE_INET6
2810*12358SAlexandr.Nedvedicky@Sun.COM if (fin->fin_v == 6) {
2811*12358SAlexandr.Nedvedicky@Sun.COM phdr.src_addr.in6 = fin->fin_srcip6;
2812*12358SAlexandr.Nedvedicky@Sun.COM phdr.dst_addr.in6 = fin->fin_dstip6;
2813*12358SAlexandr.Nedvedicky@Sun.COM } else {
2814*12358SAlexandr.Nedvedicky@Sun.COM phdr.src_addr.in4 = fin->fin_src;
2815*12358SAlexandr.Nedvedicky@Sun.COM phdr.dst_addr.in4 = fin->fin_dst;
2816*12358SAlexandr.Nedvedicky@Sun.COM }
2817*12358SAlexandr.Nedvedicky@Sun.COM #else
2818*12358SAlexandr.Nedvedicky@Sun.COM phdr.src_addr.in4 = fin->fin_src;
2819*12358SAlexandr.Nedvedicky@Sun.COM phdr.dst_addr.in4 = fin->fin_dst;
2820*12358SAlexandr.Nedvedicky@Sun.COM #endif
2821*12358SAlexandr.Nedvedicky@Sun.COM phdr.zero = (char) 0;
2822*12358SAlexandr.Nedvedicky@Sun.COM phdr.proto = fin->fin_p;
2823*12358SAlexandr.Nedvedicky@Sun.COM phdr.len = htons((uint16_t)fin->fin_dlen);
2824*12358SAlexandr.Nedvedicky@Sun.COM sum = fr_buf_sum(&phdr, (unsigned int)sizeof (phdr));
2825*12358SAlexandr.Nedvedicky@Sun.COM } else {
2826*12358SAlexandr.Nedvedicky@Sun.COM sum = 0;
2827*12358SAlexandr.Nedvedicky@Sun.COM }
2828*12358SAlexandr.Nedvedicky@Sun.COM
2829*12358SAlexandr.Nedvedicky@Sun.COM /*
2830*12358SAlexandr.Nedvedicky@Sun.COM * Set pointer to the L4 chksum field in the packet, set buf pointer to
2831*12358SAlexandr.Nedvedicky@Sun.COM * the L4 header start.
2832*12358SAlexandr.Nedvedicky@Sun.COM */
2833*12358SAlexandr.Nedvedicky@Sun.COM switch (fin->fin_p) {
2834*12358SAlexandr.Nedvedicky@Sun.COM case IPPROTO_UDP:
2835*12358SAlexandr.Nedvedicky@Sun.COM udp = (udphdr_t *)(pkt->b_rptr + fin->fin_hlen);
2836*12358SAlexandr.Nedvedicky@Sun.COM l4_csum_p = &udp->uh_sum;
2837*12358SAlexandr.Nedvedicky@Sun.COM buf = udp;
2838*12358SAlexandr.Nedvedicky@Sun.COM break;
2839*12358SAlexandr.Nedvedicky@Sun.COM case IPPROTO_TCP:
2840*12358SAlexandr.Nedvedicky@Sun.COM tcp = (tcphdr_t *)(pkt->b_rptr + fin->fin_hlen);
2841*12358SAlexandr.Nedvedicky@Sun.COM l4_csum_p = &tcp->th_sum;
2842*12358SAlexandr.Nedvedicky@Sun.COM buf = tcp;
2843*12358SAlexandr.Nedvedicky@Sun.COM break;
2844*12358SAlexandr.Nedvedicky@Sun.COM case IPPROTO_ICMP:
2845*12358SAlexandr.Nedvedicky@Sun.COM icmp = (icmphdr_t *)(pkt->b_rptr + fin->fin_hlen);
2846*12358SAlexandr.Nedvedicky@Sun.COM l4_csum_p = &icmp->icmp_cksum;
2847*12358SAlexandr.Nedvedicky@Sun.COM buf = icmp;
2848*12358SAlexandr.Nedvedicky@Sun.COM break;
2849*12358SAlexandr.Nedvedicky@Sun.COM #ifdef USE_INET6
2850*12358SAlexandr.Nedvedicky@Sun.COM case IPPROTO_ICMPV6:
2851*12358SAlexandr.Nedvedicky@Sun.COM icmp6 = (struct icmp6_hdr *)(pkt->b_rptr + fin->fin_hlen);
2852*12358SAlexandr.Nedvedicky@Sun.COM l4_csum_p = &icmp6->icmp6_cksum;
2853*12358SAlexandr.Nedvedicky@Sun.COM buf = icmp6;
2854*12358SAlexandr.Nedvedicky@Sun.COM break;
2855*12358SAlexandr.Nedvedicky@Sun.COM #endif
2856*12358SAlexandr.Nedvedicky@Sun.COM default:
2857*12358SAlexandr.Nedvedicky@Sun.COM l4_csum_p = NULL;
2858*12358SAlexandr.Nedvedicky@Sun.COM }
2859*12358SAlexandr.Nedvedicky@Sun.COM
2860*12358SAlexandr.Nedvedicky@Sun.COM /*
2861*12358SAlexandr.Nedvedicky@Sun.COM * Compute L4 chksum if needed.
2862*12358SAlexandr.Nedvedicky@Sun.COM */
2863*12358SAlexandr.Nedvedicky@Sun.COM if (l4_csum_p != NULL) {
2864*12358SAlexandr.Nedvedicky@Sun.COM *l4_csum_p = (uint16_t)0;
2865*12358SAlexandr.Nedvedicky@Sun.COM pld_len = fin->fin_dlen;
2866*12358SAlexandr.Nedvedicky@Sun.COM len = pkt->b_wptr - (unsigned char *)buf;
2867*12358SAlexandr.Nedvedicky@Sun.COM ASSERT(len == pld_len);
2868*12358SAlexandr.Nedvedicky@Sun.COM /*
2869*12358SAlexandr.Nedvedicky@Sun.COM * Add payload sum to pseudoheader sum.
2870*12358SAlexandr.Nedvedicky@Sun.COM */
2871*12358SAlexandr.Nedvedicky@Sun.COM sum += fr_buf_sum(buf, len);
2872*12358SAlexandr.Nedvedicky@Sun.COM while (sum >> 16)
2873*12358SAlexandr.Nedvedicky@Sun.COM sum = (sum & 0xFFFF) + (sum >> 16);
2874*12358SAlexandr.Nedvedicky@Sun.COM
2875*12358SAlexandr.Nedvedicky@Sun.COM *l4_csum_p = ~((uint16_t)sum);
2876*12358SAlexandr.Nedvedicky@Sun.COM DTRACE_PROBE1(l4_sum, uint16_t, *l4_csum_p);
2877*12358SAlexandr.Nedvedicky@Sun.COM }
2878*12358SAlexandr.Nedvedicky@Sun.COM
2879*12358SAlexandr.Nedvedicky@Sun.COM /*
2880*12358SAlexandr.Nedvedicky@Sun.COM * The IP header chksum is needed just for IPv4.
2881*12358SAlexandr.Nedvedicky@Sun.COM */
2882*12358SAlexandr.Nedvedicky@Sun.COM if (fin->fin_v == 4) {
2883*12358SAlexandr.Nedvedicky@Sun.COM /*
2884*12358SAlexandr.Nedvedicky@Sun.COM * Compute IPv4 header chksum.
2885*12358SAlexandr.Nedvedicky@Sun.COM */
2886*12358SAlexandr.Nedvedicky@Sun.COM ip = (ip_t *)pkt->b_rptr;
2887*12358SAlexandr.Nedvedicky@Sun.COM ip->ip_sum = (uint16_t)0;
2888*12358SAlexandr.Nedvedicky@Sun.COM ip_sum = fr_buf_sum(ip, (unsigned int)fin->fin_hlen);
2889*12358SAlexandr.Nedvedicky@Sun.COM while (ip_sum >> 16)
2890*12358SAlexandr.Nedvedicky@Sun.COM ip_sum = (ip_sum & 0xFFFF) + (ip_sum >> 16);
2891*12358SAlexandr.Nedvedicky@Sun.COM
2892*12358SAlexandr.Nedvedicky@Sun.COM ip->ip_sum = ~((uint16_t)ip_sum);
2893*12358SAlexandr.Nedvedicky@Sun.COM DTRACE_PROBE1(l3_sum, uint16_t, ip->ip_sum);
2894*12358SAlexandr.Nedvedicky@Sun.COM }
2895*12358SAlexandr.Nedvedicky@Sun.COM
2896*12358SAlexandr.Nedvedicky@Sun.COM return;
2897*12358SAlexandr.Nedvedicky@Sun.COM }
2898*12358SAlexandr.Nedvedicky@Sun.COM
28999695SAlexandr.Nedvedicky@Sun.COM #endif /* _KERNEL && SOLARIS2 >= 10 */
2900