xref: /titanic_51/usr/src/uts/common/inet/ip/ipdrop.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/stream.h>
31 #include <sys/strsun.h>
32 #include <sys/sunddi.h>
33 #include <sys/kstat.h>
34 #include <sys/kmem.h>
35 #include <net/pfkeyv2.h>
36 #include <inet/common.h>
37 #include <inet/ip.h>
38 #include <inet/ip6.h>
39 #include <inet/ipsec_info.h>
40 #include <inet/ipdrop.h>
41 
42 /*
43  * Packet drop facility.
44  */
45 
46 kstat_t *ip_drop_kstat;
47 struct ip_dropstats *ip_drop_types;
48 
49 /*
50  * Initialize drop facility kstats.
51  */
52 void
53 ip_drop_init(void)
54 {
55 	ip_drop_kstat = kstat_create("ip", 0, "ipdrop", "net",
56 	    KSTAT_TYPE_NAMED, sizeof (*ip_drop_types) / sizeof (kstat_named_t),
57 	    KSTAT_FLAG_PERSISTENT);
58 
59 	if (ip_drop_kstat == NULL)
60 		return;
61 
62 	ip_drop_types = ip_drop_kstat->ks_data;
63 
64 	/* TCP IPsec drop statistics. */
65 	kstat_named_init(&ipdrops_tcp_clear, "tcp_clear", KSTAT_DATA_UINT64);
66 	kstat_named_init(&ipdrops_tcp_secure, "tcp_secure", KSTAT_DATA_UINT64);
67 	kstat_named_init(&ipdrops_tcp_mismatch, "tcp_mismatch",
68 	    KSTAT_DATA_UINT64);
69 	kstat_named_init(&ipdrops_tcp_ipsec_alloc, "tcp_ipsec_alloc",
70 	    KSTAT_DATA_UINT64);
71 
72 	/* SADB-specific drop statistics. */
73 	kstat_named_init(&ipdrops_sadb_inlarval_timeout,
74 	    "sadb_inlarval_timeout", KSTAT_DATA_UINT64);
75 	kstat_named_init(&ipdrops_sadb_inlarval_replace,
76 	    "sadb_inlarval_replace", KSTAT_DATA_UINT64);
77 	kstat_named_init(&ipdrops_sadb_acquire_nomem,
78 	    "sadb_acquire_nomem", KSTAT_DATA_UINT64);
79 	kstat_named_init(&ipdrops_sadb_acquire_toofull,
80 	    "sadb_acquire_toofull", KSTAT_DATA_UINT64);
81 	kstat_named_init(&ipdrops_sadb_acquire_timeout,
82 	    "sadb_acquire_timeout", KSTAT_DATA_UINT64);
83 
84 	/* SPD drop statistics. */
85 	kstat_named_init(&ipdrops_spd_ahesp_diffid, "spd_ahesp_diffid",
86 	    KSTAT_DATA_UINT64);
87 	kstat_named_init(&ipdrops_spd_loopback_mismatch,
88 	    "spd_loopback_mismatch", KSTAT_DATA_UINT64);
89 	kstat_named_init(&ipdrops_spd_explicit, "spd_explicit",
90 	    KSTAT_DATA_UINT64);
91 	kstat_named_init(&ipdrops_spd_got_secure, "spd_got_secure",
92 	    KSTAT_DATA_UINT64);
93 	kstat_named_init(&ipdrops_spd_got_clear, "spd_got_clear",
94 	    KSTAT_DATA_UINT64);
95 	kstat_named_init(&ipdrops_spd_bad_ahalg, "spd_bad_ahalg",
96 	    KSTAT_DATA_UINT64);
97 	kstat_named_init(&ipdrops_spd_got_ah, "spd_got_ah", KSTAT_DATA_UINT64);
98 	kstat_named_init(&ipdrops_spd_bad_espealg, "spd_bad_espealg",
99 	    KSTAT_DATA_UINT64);
100 	kstat_named_init(&ipdrops_spd_bad_espaalg, "spd_bad_espaalg",
101 	    KSTAT_DATA_UINT64);
102 	kstat_named_init(&ipdrops_spd_got_esp, "spd_got_esp",
103 	    KSTAT_DATA_UINT64);
104 	kstat_named_init(&ipdrops_spd_got_selfencap, "spd_got_selfencap",
105 	    KSTAT_DATA_UINT64);
106 	kstat_named_init(&ipdrops_spd_bad_selfencap, "spd_bad_selfencap",
107 	    KSTAT_DATA_UINT64);
108 	kstat_named_init(&ipdrops_spd_nomem, "spd_nomem", KSTAT_DATA_UINT64);
109 	kstat_named_init(&ipdrops_spd_ah_badid, "spd_ah_badid",
110 	    KSTAT_DATA_UINT64);
111 	kstat_named_init(&ipdrops_spd_esp_badid, "spd_esp_badid",
112 	    KSTAT_DATA_UINT64);
113 
114 	/* ESP-specific drop statistics. */
115 
116 	kstat_named_init(&ipdrops_esp_nomem, "esp_nomem", KSTAT_DATA_UINT64);
117 	kstat_named_init(&ipdrops_esp_no_sa, "esp_no_sa", KSTAT_DATA_UINT64);
118 	kstat_named_init(&ipdrops_esp_early_replay, "esp_early_replay",
119 	    KSTAT_DATA_UINT64);
120 	kstat_named_init(&ipdrops_esp_replay, "esp_replay", KSTAT_DATA_UINT64);
121 	kstat_named_init(&ipdrops_esp_bytes_expire, "esp_bytes_expire",
122 	    KSTAT_DATA_UINT64);
123 	kstat_named_init(&ipdrops_esp_bad_padlen, "esp_bad_padlen",
124 	    KSTAT_DATA_UINT64);
125 	kstat_named_init(&ipdrops_esp_bad_padding, "esp_bad_padding",
126 	    KSTAT_DATA_UINT64);
127 	kstat_named_init(&ipdrops_esp_bad_auth, "esp_bad_auth",
128 	    KSTAT_DATA_UINT64);
129 	kstat_named_init(&ipdrops_esp_crypto_failed, "esp_crypto_failed",
130 	    KSTAT_DATA_UINT64);
131 	kstat_named_init(&ipdrops_esp_icmp, "esp_icmp", KSTAT_DATA_UINT64);
132 
133 	/* AH-specific drop statistics. */
134 	kstat_named_init(&ipdrops_ah_nomem, "ah_nomem", KSTAT_DATA_UINT64);
135 	kstat_named_init(&ipdrops_ah_bad_v6_hdrs, "ah_bad_v6_hdrs",
136 	    KSTAT_DATA_UINT64);
137 	kstat_named_init(&ipdrops_ah_bad_v4_opts, "ah_bad_v4_opts",
138 	    KSTAT_DATA_UINT64);
139 	kstat_named_init(&ipdrops_ah_no_sa, "ah_no_sa", KSTAT_DATA_UINT64);
140 	kstat_named_init(&ipdrops_ah_bad_length, "ah_bad_length",
141 	    KSTAT_DATA_UINT64);
142 	kstat_named_init(&ipdrops_ah_bad_auth, "ah_bad_auth",
143 	    KSTAT_DATA_UINT64);
144 	kstat_named_init(&ipdrops_ah_crypto_failed, "ah_crypto_failed",
145 	    KSTAT_DATA_UINT64);
146 	kstat_named_init(&ipdrops_ah_early_replay, "ah_early_replay",
147 	    KSTAT_DATA_UINT64);
148 	kstat_named_init(&ipdrops_ah_replay, "ah_replay", KSTAT_DATA_UINT64);
149 	kstat_named_init(&ipdrops_ah_bytes_expire, "ah_bytes_expire",
150 	    KSTAT_DATA_UINT64);
151 
152 	/* IP-specific drop statistics. */
153 	kstat_named_init(&ipdrops_ip_ipsec_not_loaded, "ip_ipsec_not_loaded",
154 	    KSTAT_DATA_UINT64);
155 
156 	kstat_install(ip_drop_kstat);
157 }
158 
159 void
160 ip_drop_destroy(void)
161 {
162 	kstat_delete(ip_drop_kstat);
163 }
164 
165 /*
166  * Register a packet dropper.
167  */
168 void
169 ip_drop_register(ipdropper_t *ipd, char *name)
170 {
171 	if (ipd->ipd_name != NULL) {
172 		cmn_err(CE_WARN,
173 		    "ip_drop_register: ipdropper %s already registered with %s",
174 		    name, ipd->ipd_name);
175 		return;
176 	}
177 
178 	/* Assume that name is reasonable in length.  This isn't user-land. */
179 	ipd->ipd_name = kmem_alloc(strlen(name) + 1, KM_SLEEP);
180 	(void) strcpy(ipd->ipd_name, name);
181 }
182 
183 /*
184  * Un-register a packet dropper.
185  */
186 void
187 ip_drop_unregister(ipdropper_t *ipd)
188 {
189 	kmem_free(ipd->ipd_name, strlen(ipd->ipd_name) + 1);
190 
191 	ipd->ipd_name = NULL;
192 }
193 
194 /*
195  * Actually drop a packet.  Many things could happen here, but at the least,
196  * the packet will be freemsg()ed.
197  */
198 /* ARGSUSED */
199 void
200 ip_drop_packet(mblk_t *mp, boolean_t inbound, ill_t *arriving,
201     ire_t *outbound_ire, struct kstat_named *counter, ipdropper_t *who_called)
202 {
203 	mblk_t *ipsec_mp = NULL;
204 	ipsec_in_t *ii = NULL;
205 	ipsec_out_t *io = NULL;
206 	ipsec_info_t *in;
207 	uint8_t vers;
208 
209 	if (mp == NULL) {
210 		/*
211 		 * Return immediately - NULL packets should not affect any
212 		 * statistics.
213 		 */
214 		return;
215 	}
216 
217 	if (DB_TYPE(mp) == M_CTL) {
218 		in = (ipsec_info_t *)mp->b_rptr;
219 
220 		if (in->ipsec_info_type == IPSEC_IN)
221 			ii = (ipsec_in_t *)in;
222 		else if (in->ipsec_info_type == IPSEC_OUT)
223 			io = (ipsec_out_t *)in;
224 
225 		/* See if this is an ICMP packet (check for v4/v6). */
226 		vers = (*mp->b_rptr) >> 4;
227 		if (vers != IPV4_VERSION && vers != IPV6_VERSION) {
228 			/*
229 			 * If not, it's some other sort of M_CTL to be freed.
230 			 * For now, treat it like an ordinary packet.
231 			 */
232 			ipsec_mp = mp;
233 			mp = mp->b_cont;
234 		}
235 	}
236 
237 	/* Reality checks */
238 	if (inbound && io != NULL)
239 		cmn_err(CE_WARN,
240 		    "ip_drop_packet: inbound packet with IPSEC_OUT");
241 
242 	if (outbound_ire != NULL && ii != NULL)
243 		cmn_err(CE_WARN,
244 		    "ip_drop_packet: outbound packet with IPSEC_IN");
245 
246 	/* At this point, mp always points to the data. */
247 	/*
248 	 * Can't make the assertion yet - It could be an inbound ICMP
249 	 * message, which is M_CTL but with data in it.
250 	 */
251 	/* ASSERT(mp->b_datap->db_type == M_DATA); */
252 
253 	/* Increment the bean counter, if available. */
254 	if (counter != NULL) {
255 		switch (counter->data_type) {
256 		case KSTAT_DATA_INT32:
257 			counter->value.i32++;
258 			break;
259 		case KSTAT_DATA_UINT32:
260 			counter->value.ui32++;
261 			break;
262 		case KSTAT_DATA_INT64:
263 			counter->value.i64++;
264 			break;
265 		case KSTAT_DATA_UINT64:
266 			counter->value.ui64++;
267 			break;
268 		/* Other types we can't handle for now. */
269 		}
270 
271 		/* TODO?  Copy out kstat name for use in logging. */
272 	}
273 
274 	/* TODO: log the packet details if logging is called for. */
275 	/* TODO: queue the packet onto a snoop-friendly queue. */
276 
277 	/* If I haven't queued the packet or some such nonsense, free it. */
278 	if (ipsec_mp != NULL)
279 		freeb(ipsec_mp);
280 	freemsg(mp);
281 }
282