xref: /onnv-gate/usr/src/uts/common/inet/ip/ipdrop.c (revision 691:dc7dea9823d9)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*691Ssommerfe  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/stream.h>
310Sstevel@tonic-gate #include <sys/strsun.h>
320Sstevel@tonic-gate #include <sys/sunddi.h>
330Sstevel@tonic-gate #include <sys/kstat.h>
340Sstevel@tonic-gate #include <sys/kmem.h>
350Sstevel@tonic-gate #include <net/pfkeyv2.h>
360Sstevel@tonic-gate #include <inet/common.h>
370Sstevel@tonic-gate #include <inet/ip.h>
380Sstevel@tonic-gate #include <inet/ip6.h>
390Sstevel@tonic-gate #include <inet/ipsec_info.h>
400Sstevel@tonic-gate #include <inet/ipdrop.h>
410Sstevel@tonic-gate 
420Sstevel@tonic-gate /*
430Sstevel@tonic-gate  * Packet drop facility.
440Sstevel@tonic-gate  */
450Sstevel@tonic-gate 
460Sstevel@tonic-gate kstat_t *ip_drop_kstat;
470Sstevel@tonic-gate struct ip_dropstats *ip_drop_types;
480Sstevel@tonic-gate 
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate  * Initialize drop facility kstats.
510Sstevel@tonic-gate  */
520Sstevel@tonic-gate void
530Sstevel@tonic-gate ip_drop_init(void)
540Sstevel@tonic-gate {
550Sstevel@tonic-gate 	ip_drop_kstat = kstat_create("ip", 0, "ipdrop", "net",
560Sstevel@tonic-gate 	    KSTAT_TYPE_NAMED, sizeof (*ip_drop_types) / sizeof (kstat_named_t),
570Sstevel@tonic-gate 	    KSTAT_FLAG_PERSISTENT);
580Sstevel@tonic-gate 
590Sstevel@tonic-gate 	if (ip_drop_kstat == NULL)
600Sstevel@tonic-gate 		return;
610Sstevel@tonic-gate 
620Sstevel@tonic-gate 	ip_drop_types = ip_drop_kstat->ks_data;
630Sstevel@tonic-gate 
640Sstevel@tonic-gate 	/* TCP IPsec drop statistics. */
650Sstevel@tonic-gate 	kstat_named_init(&ipdrops_tcp_clear, "tcp_clear", KSTAT_DATA_UINT64);
660Sstevel@tonic-gate 	kstat_named_init(&ipdrops_tcp_secure, "tcp_secure", KSTAT_DATA_UINT64);
670Sstevel@tonic-gate 	kstat_named_init(&ipdrops_tcp_mismatch, "tcp_mismatch",
680Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
690Sstevel@tonic-gate 	kstat_named_init(&ipdrops_tcp_ipsec_alloc, "tcp_ipsec_alloc",
700Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
710Sstevel@tonic-gate 
720Sstevel@tonic-gate 	/* SADB-specific drop statistics. */
730Sstevel@tonic-gate 	kstat_named_init(&ipdrops_sadb_inlarval_timeout,
740Sstevel@tonic-gate 	    "sadb_inlarval_timeout", KSTAT_DATA_UINT64);
750Sstevel@tonic-gate 	kstat_named_init(&ipdrops_sadb_inlarval_replace,
760Sstevel@tonic-gate 	    "sadb_inlarval_replace", KSTAT_DATA_UINT64);
770Sstevel@tonic-gate 	kstat_named_init(&ipdrops_sadb_acquire_nomem,
780Sstevel@tonic-gate 	    "sadb_acquire_nomem", KSTAT_DATA_UINT64);
790Sstevel@tonic-gate 	kstat_named_init(&ipdrops_sadb_acquire_toofull,
800Sstevel@tonic-gate 	    "sadb_acquire_toofull", KSTAT_DATA_UINT64);
810Sstevel@tonic-gate 	kstat_named_init(&ipdrops_sadb_acquire_timeout,
820Sstevel@tonic-gate 	    "sadb_acquire_timeout", KSTAT_DATA_UINT64);
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 	/* SPD drop statistics. */
850Sstevel@tonic-gate 	kstat_named_init(&ipdrops_spd_ahesp_diffid, "spd_ahesp_diffid",
860Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
870Sstevel@tonic-gate 	kstat_named_init(&ipdrops_spd_loopback_mismatch,
880Sstevel@tonic-gate 	    "spd_loopback_mismatch", KSTAT_DATA_UINT64);
890Sstevel@tonic-gate 	kstat_named_init(&ipdrops_spd_explicit, "spd_explicit",
900Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
910Sstevel@tonic-gate 	kstat_named_init(&ipdrops_spd_got_secure, "spd_got_secure",
920Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
930Sstevel@tonic-gate 	kstat_named_init(&ipdrops_spd_got_clear, "spd_got_clear",
940Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
950Sstevel@tonic-gate 	kstat_named_init(&ipdrops_spd_bad_ahalg, "spd_bad_ahalg",
960Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
970Sstevel@tonic-gate 	kstat_named_init(&ipdrops_spd_got_ah, "spd_got_ah", KSTAT_DATA_UINT64);
980Sstevel@tonic-gate 	kstat_named_init(&ipdrops_spd_bad_espealg, "spd_bad_espealg",
990Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
1000Sstevel@tonic-gate 	kstat_named_init(&ipdrops_spd_bad_espaalg, "spd_bad_espaalg",
1010Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
1020Sstevel@tonic-gate 	kstat_named_init(&ipdrops_spd_got_esp, "spd_got_esp",
1030Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
1040Sstevel@tonic-gate 	kstat_named_init(&ipdrops_spd_got_selfencap, "spd_got_selfencap",
1050Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
1060Sstevel@tonic-gate 	kstat_named_init(&ipdrops_spd_bad_selfencap, "spd_bad_selfencap",
1070Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
1080Sstevel@tonic-gate 	kstat_named_init(&ipdrops_spd_nomem, "spd_nomem", KSTAT_DATA_UINT64);
1090Sstevel@tonic-gate 	kstat_named_init(&ipdrops_spd_ah_badid, "spd_ah_badid",
1100Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
1110Sstevel@tonic-gate 	kstat_named_init(&ipdrops_spd_esp_badid, "spd_esp_badid",
1120Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
113*691Ssommerfe 	kstat_named_init(&ipdrops_spd_ah_innermismatch,
114*691Ssommerfe 	    "spd_ah_innermismatch", KSTAT_DATA_UINT64);
115*691Ssommerfe 	kstat_named_init(&ipdrops_spd_esp_innermismatch,
116*691Ssommerfe 	    "spd_esp_innermismatch", KSTAT_DATA_UINT64);
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 	/* ESP-specific drop statistics. */
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	kstat_named_init(&ipdrops_esp_nomem, "esp_nomem", KSTAT_DATA_UINT64);
1210Sstevel@tonic-gate 	kstat_named_init(&ipdrops_esp_no_sa, "esp_no_sa", KSTAT_DATA_UINT64);
1220Sstevel@tonic-gate 	kstat_named_init(&ipdrops_esp_early_replay, "esp_early_replay",
1230Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
1240Sstevel@tonic-gate 	kstat_named_init(&ipdrops_esp_replay, "esp_replay", KSTAT_DATA_UINT64);
1250Sstevel@tonic-gate 	kstat_named_init(&ipdrops_esp_bytes_expire, "esp_bytes_expire",
1260Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
1270Sstevel@tonic-gate 	kstat_named_init(&ipdrops_esp_bad_padlen, "esp_bad_padlen",
1280Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
1290Sstevel@tonic-gate 	kstat_named_init(&ipdrops_esp_bad_padding, "esp_bad_padding",
1300Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
1310Sstevel@tonic-gate 	kstat_named_init(&ipdrops_esp_bad_auth, "esp_bad_auth",
1320Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
1330Sstevel@tonic-gate 	kstat_named_init(&ipdrops_esp_crypto_failed, "esp_crypto_failed",
1340Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
1350Sstevel@tonic-gate 	kstat_named_init(&ipdrops_esp_icmp, "esp_icmp", KSTAT_DATA_UINT64);
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 	/* AH-specific drop statistics. */
1380Sstevel@tonic-gate 	kstat_named_init(&ipdrops_ah_nomem, "ah_nomem", KSTAT_DATA_UINT64);
1390Sstevel@tonic-gate 	kstat_named_init(&ipdrops_ah_bad_v6_hdrs, "ah_bad_v6_hdrs",
1400Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
1410Sstevel@tonic-gate 	kstat_named_init(&ipdrops_ah_bad_v4_opts, "ah_bad_v4_opts",
1420Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
1430Sstevel@tonic-gate 	kstat_named_init(&ipdrops_ah_no_sa, "ah_no_sa", KSTAT_DATA_UINT64);
1440Sstevel@tonic-gate 	kstat_named_init(&ipdrops_ah_bad_length, "ah_bad_length",
1450Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
1460Sstevel@tonic-gate 	kstat_named_init(&ipdrops_ah_bad_auth, "ah_bad_auth",
1470Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
1480Sstevel@tonic-gate 	kstat_named_init(&ipdrops_ah_crypto_failed, "ah_crypto_failed",
1490Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
1500Sstevel@tonic-gate 	kstat_named_init(&ipdrops_ah_early_replay, "ah_early_replay",
1510Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
1520Sstevel@tonic-gate 	kstat_named_init(&ipdrops_ah_replay, "ah_replay", KSTAT_DATA_UINT64);
1530Sstevel@tonic-gate 	kstat_named_init(&ipdrops_ah_bytes_expire, "ah_bytes_expire",
1540Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	/* IP-specific drop statistics. */
1570Sstevel@tonic-gate 	kstat_named_init(&ipdrops_ip_ipsec_not_loaded, "ip_ipsec_not_loaded",
1580Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	kstat_install(ip_drop_kstat);
1610Sstevel@tonic-gate }
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate void
1640Sstevel@tonic-gate ip_drop_destroy(void)
1650Sstevel@tonic-gate {
1660Sstevel@tonic-gate 	kstat_delete(ip_drop_kstat);
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate /*
1700Sstevel@tonic-gate  * Register a packet dropper.
1710Sstevel@tonic-gate  */
1720Sstevel@tonic-gate void
1730Sstevel@tonic-gate ip_drop_register(ipdropper_t *ipd, char *name)
1740Sstevel@tonic-gate {
1750Sstevel@tonic-gate 	if (ipd->ipd_name != NULL) {
1760Sstevel@tonic-gate 		cmn_err(CE_WARN,
1770Sstevel@tonic-gate 		    "ip_drop_register: ipdropper %s already registered with %s",
1780Sstevel@tonic-gate 		    name, ipd->ipd_name);
1790Sstevel@tonic-gate 		return;
1800Sstevel@tonic-gate 	}
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	/* Assume that name is reasonable in length.  This isn't user-land. */
1830Sstevel@tonic-gate 	ipd->ipd_name = kmem_alloc(strlen(name) + 1, KM_SLEEP);
1840Sstevel@tonic-gate 	(void) strcpy(ipd->ipd_name, name);
1850Sstevel@tonic-gate }
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate /*
1880Sstevel@tonic-gate  * Un-register a packet dropper.
1890Sstevel@tonic-gate  */
1900Sstevel@tonic-gate void
1910Sstevel@tonic-gate ip_drop_unregister(ipdropper_t *ipd)
1920Sstevel@tonic-gate {
1930Sstevel@tonic-gate 	kmem_free(ipd->ipd_name, strlen(ipd->ipd_name) + 1);
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	ipd->ipd_name = NULL;
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate /*
1990Sstevel@tonic-gate  * Actually drop a packet.  Many things could happen here, but at the least,
2000Sstevel@tonic-gate  * the packet will be freemsg()ed.
2010Sstevel@tonic-gate  */
2020Sstevel@tonic-gate /* ARGSUSED */
2030Sstevel@tonic-gate void
2040Sstevel@tonic-gate ip_drop_packet(mblk_t *mp, boolean_t inbound, ill_t *arriving,
2050Sstevel@tonic-gate     ire_t *outbound_ire, struct kstat_named *counter, ipdropper_t *who_called)
2060Sstevel@tonic-gate {
2070Sstevel@tonic-gate 	mblk_t *ipsec_mp = NULL;
2080Sstevel@tonic-gate 	ipsec_in_t *ii = NULL;
2090Sstevel@tonic-gate 	ipsec_out_t *io = NULL;
2100Sstevel@tonic-gate 	ipsec_info_t *in;
2110Sstevel@tonic-gate 	uint8_t vers;
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	if (mp == NULL) {
2140Sstevel@tonic-gate 		/*
2150Sstevel@tonic-gate 		 * Return immediately - NULL packets should not affect any
2160Sstevel@tonic-gate 		 * statistics.
2170Sstevel@tonic-gate 		 */
2180Sstevel@tonic-gate 		return;
2190Sstevel@tonic-gate 	}
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	if (DB_TYPE(mp) == M_CTL) {
2220Sstevel@tonic-gate 		in = (ipsec_info_t *)mp->b_rptr;
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 		if (in->ipsec_info_type == IPSEC_IN)
2250Sstevel@tonic-gate 			ii = (ipsec_in_t *)in;
2260Sstevel@tonic-gate 		else if (in->ipsec_info_type == IPSEC_OUT)
2270Sstevel@tonic-gate 			io = (ipsec_out_t *)in;
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 		/* See if this is an ICMP packet (check for v4/v6). */
2300Sstevel@tonic-gate 		vers = (*mp->b_rptr) >> 4;
2310Sstevel@tonic-gate 		if (vers != IPV4_VERSION && vers != IPV6_VERSION) {
2320Sstevel@tonic-gate 			/*
2330Sstevel@tonic-gate 			 * If not, it's some other sort of M_CTL to be freed.
2340Sstevel@tonic-gate 			 * For now, treat it like an ordinary packet.
2350Sstevel@tonic-gate 			 */
2360Sstevel@tonic-gate 			ipsec_mp = mp;
2370Sstevel@tonic-gate 			mp = mp->b_cont;
2380Sstevel@tonic-gate 		}
2390Sstevel@tonic-gate 	}
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	/* Reality checks */
2420Sstevel@tonic-gate 	if (inbound && io != NULL)
2430Sstevel@tonic-gate 		cmn_err(CE_WARN,
2440Sstevel@tonic-gate 		    "ip_drop_packet: inbound packet with IPSEC_OUT");
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	if (outbound_ire != NULL && ii != NULL)
2470Sstevel@tonic-gate 		cmn_err(CE_WARN,
2480Sstevel@tonic-gate 		    "ip_drop_packet: outbound packet with IPSEC_IN");
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	/* At this point, mp always points to the data. */
2510Sstevel@tonic-gate 	/*
2520Sstevel@tonic-gate 	 * Can't make the assertion yet - It could be an inbound ICMP
2530Sstevel@tonic-gate 	 * message, which is M_CTL but with data in it.
2540Sstevel@tonic-gate 	 */
2550Sstevel@tonic-gate 	/* ASSERT(mp->b_datap->db_type == M_DATA); */
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	/* Increment the bean counter, if available. */
2580Sstevel@tonic-gate 	if (counter != NULL) {
2590Sstevel@tonic-gate 		switch (counter->data_type) {
2600Sstevel@tonic-gate 		case KSTAT_DATA_INT32:
2610Sstevel@tonic-gate 			counter->value.i32++;
2620Sstevel@tonic-gate 			break;
2630Sstevel@tonic-gate 		case KSTAT_DATA_UINT32:
2640Sstevel@tonic-gate 			counter->value.ui32++;
2650Sstevel@tonic-gate 			break;
2660Sstevel@tonic-gate 		case KSTAT_DATA_INT64:
2670Sstevel@tonic-gate 			counter->value.i64++;
2680Sstevel@tonic-gate 			break;
2690Sstevel@tonic-gate 		case KSTAT_DATA_UINT64:
2700Sstevel@tonic-gate 			counter->value.ui64++;
2710Sstevel@tonic-gate 			break;
2720Sstevel@tonic-gate 		/* Other types we can't handle for now. */
2730Sstevel@tonic-gate 		}
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 		/* TODO?  Copy out kstat name for use in logging. */
2760Sstevel@tonic-gate 	}
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	/* TODO: log the packet details if logging is called for. */
2790Sstevel@tonic-gate 	/* TODO: queue the packet onto a snoop-friendly queue. */
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	/* If I haven't queued the packet or some such nonsense, free it. */
2820Sstevel@tonic-gate 	if (ipsec_mp != NULL)
2830Sstevel@tonic-gate 		freeb(ipsec_mp);
2840Sstevel@tonic-gate 	freemsg(mp);
2850Sstevel@tonic-gate }
286