xref: /illumos-gate/usr/src/uts/common/inet/ip/ipdrop.c (revision f00e6aa6)
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 2005 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 	kstat_named_init(&ipdrops_spd_ah_innermismatch,
114 	    "spd_ah_innermismatch", KSTAT_DATA_UINT64);
115 	kstat_named_init(&ipdrops_spd_esp_innermismatch,
116 	    "spd_esp_innermismatch", KSTAT_DATA_UINT64);
117 
118 	/* ESP-specific drop statistics. */
119 
120 	kstat_named_init(&ipdrops_esp_nomem, "esp_nomem", KSTAT_DATA_UINT64);
121 	kstat_named_init(&ipdrops_esp_no_sa, "esp_no_sa", KSTAT_DATA_UINT64);
122 	kstat_named_init(&ipdrops_esp_early_replay, "esp_early_replay",
123 	    KSTAT_DATA_UINT64);
124 	kstat_named_init(&ipdrops_esp_replay, "esp_replay", KSTAT_DATA_UINT64);
125 	kstat_named_init(&ipdrops_esp_bytes_expire, "esp_bytes_expire",
126 	    KSTAT_DATA_UINT64);
127 	kstat_named_init(&ipdrops_esp_bad_padlen, "esp_bad_padlen",
128 	    KSTAT_DATA_UINT64);
129 	kstat_named_init(&ipdrops_esp_bad_padding, "esp_bad_padding",
130 	    KSTAT_DATA_UINT64);
131 	kstat_named_init(&ipdrops_esp_bad_auth, "esp_bad_auth",
132 	    KSTAT_DATA_UINT64);
133 	kstat_named_init(&ipdrops_esp_crypto_failed, "esp_crypto_failed",
134 	    KSTAT_DATA_UINT64);
135 	kstat_named_init(&ipdrops_esp_icmp, "esp_icmp", KSTAT_DATA_UINT64);
136 
137 	/* AH-specific drop statistics. */
138 	kstat_named_init(&ipdrops_ah_nomem, "ah_nomem", KSTAT_DATA_UINT64);
139 	kstat_named_init(&ipdrops_ah_bad_v6_hdrs, "ah_bad_v6_hdrs",
140 	    KSTAT_DATA_UINT64);
141 	kstat_named_init(&ipdrops_ah_bad_v4_opts, "ah_bad_v4_opts",
142 	    KSTAT_DATA_UINT64);
143 	kstat_named_init(&ipdrops_ah_no_sa, "ah_no_sa", KSTAT_DATA_UINT64);
144 	kstat_named_init(&ipdrops_ah_bad_length, "ah_bad_length",
145 	    KSTAT_DATA_UINT64);
146 	kstat_named_init(&ipdrops_ah_bad_auth, "ah_bad_auth",
147 	    KSTAT_DATA_UINT64);
148 	kstat_named_init(&ipdrops_ah_crypto_failed, "ah_crypto_failed",
149 	    KSTAT_DATA_UINT64);
150 	kstat_named_init(&ipdrops_ah_early_replay, "ah_early_replay",
151 	    KSTAT_DATA_UINT64);
152 	kstat_named_init(&ipdrops_ah_replay, "ah_replay", KSTAT_DATA_UINT64);
153 	kstat_named_init(&ipdrops_ah_bytes_expire, "ah_bytes_expire",
154 	    KSTAT_DATA_UINT64);
155 
156 	/* IP-specific drop statistics. */
157 	kstat_named_init(&ipdrops_ip_ipsec_not_loaded, "ip_ipsec_not_loaded",
158 	    KSTAT_DATA_UINT64);
159 
160 	kstat_install(ip_drop_kstat);
161 }
162 
163 void
164 ip_drop_destroy(void)
165 {
166 	kstat_delete(ip_drop_kstat);
167 }
168 
169 /*
170  * Register a packet dropper.
171  */
172 void
173 ip_drop_register(ipdropper_t *ipd, char *name)
174 {
175 	if (ipd->ipd_name != NULL) {
176 		cmn_err(CE_WARN,
177 		    "ip_drop_register: ipdropper %s already registered with %s",
178 		    name, ipd->ipd_name);
179 		return;
180 	}
181 
182 	/* Assume that name is reasonable in length.  This isn't user-land. */
183 	ipd->ipd_name = kmem_alloc(strlen(name) + 1, KM_SLEEP);
184 	(void) strcpy(ipd->ipd_name, name);
185 }
186 
187 /*
188  * Un-register a packet dropper.
189  */
190 void
191 ip_drop_unregister(ipdropper_t *ipd)
192 {
193 	kmem_free(ipd->ipd_name, strlen(ipd->ipd_name) + 1);
194 
195 	ipd->ipd_name = NULL;
196 }
197 
198 /*
199  * Actually drop a packet.  Many things could happen here, but at the least,
200  * the packet will be freemsg()ed.
201  */
202 /* ARGSUSED */
203 void
204 ip_drop_packet(mblk_t *mp, boolean_t inbound, ill_t *arriving,
205     ire_t *outbound_ire, struct kstat_named *counter, ipdropper_t *who_called)
206 {
207 	mblk_t *ipsec_mp = NULL;
208 	ipsec_in_t *ii = NULL;
209 	ipsec_out_t *io = NULL;
210 	ipsec_info_t *in;
211 	uint8_t vers;
212 
213 	if (mp == NULL) {
214 		/*
215 		 * Return immediately - NULL packets should not affect any
216 		 * statistics.
217 		 */
218 		return;
219 	}
220 
221 	if (DB_TYPE(mp) == M_CTL) {
222 		in = (ipsec_info_t *)mp->b_rptr;
223 
224 		if (in->ipsec_info_type == IPSEC_IN)
225 			ii = (ipsec_in_t *)in;
226 		else if (in->ipsec_info_type == IPSEC_OUT)
227 			io = (ipsec_out_t *)in;
228 
229 		/* See if this is an ICMP packet (check for v4/v6). */
230 		vers = (*mp->b_rptr) >> 4;
231 		if (vers != IPV4_VERSION && vers != IPV6_VERSION) {
232 			/*
233 			 * If not, it's some other sort of M_CTL to be freed.
234 			 * For now, treat it like an ordinary packet.
235 			 */
236 			ipsec_mp = mp;
237 			mp = mp->b_cont;
238 		}
239 	}
240 
241 	/* Reality checks */
242 	if (inbound && io != NULL)
243 		cmn_err(CE_WARN,
244 		    "ip_drop_packet: inbound packet with IPSEC_OUT");
245 
246 	if (outbound_ire != NULL && ii != NULL)
247 		cmn_err(CE_WARN,
248 		    "ip_drop_packet: outbound packet with IPSEC_IN");
249 
250 	/* At this point, mp always points to the data. */
251 	/*
252 	 * Can't make the assertion yet - It could be an inbound ICMP
253 	 * message, which is M_CTL but with data in it.
254 	 */
255 	/* ASSERT(mp->b_datap->db_type == M_DATA); */
256 
257 	/* Increment the bean counter, if available. */
258 	if (counter != NULL) {
259 		switch (counter->data_type) {
260 		case KSTAT_DATA_INT32:
261 			counter->value.i32++;
262 			break;
263 		case KSTAT_DATA_UINT32:
264 			counter->value.ui32++;
265 			break;
266 		case KSTAT_DATA_INT64:
267 			counter->value.i64++;
268 			break;
269 		case KSTAT_DATA_UINT64:
270 			counter->value.ui64++;
271 			break;
272 		/* Other types we can't handle for now. */
273 		}
274 
275 		/* TODO?  Copy out kstat name for use in logging. */
276 	}
277 
278 	/* TODO: log the packet details if logging is called for. */
279 	/* TODO: queue the packet onto a snoop-friendly queue. */
280 
281 	/* If I haven't queued the packet or some such nonsense, free it. */
282 	if (ipsec_mp != NULL)
283 		freeb(ipsec_mp);
284 	freemsg(mp);
285 }
286