xref: /netbsd-src/usr.bin/netstat/fast_ipsec.c (revision 21e37cc72a480a47828990a439cde7ac9ffaf0c6)
1 /*	$NetBSD: fast_ipsec.c,v 1.5 2004/06/27 01:10:53 jonathan Exp $ */
2 /* 	$FreeBSD: src/tools/tools/crypto/ipsecstats.c,v 1.1.4.1 2003/06/03 00:13:13 sam Exp $ */
3 
4 /*-
5  * Copyright (c) 2003, 2004 Jonathan Stone
6  * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $FreeBSD: src/tools/tools/crypto/ipsecstats.c,v 1.1.4.1 2003/06/03 00:13:13 sam Exp $
31  */
32 
33 #include <sys/cdefs.h>
34 #ifndef lint
35 #ifdef __NetBSD__
36 __RCSID("$NetBSD: fast_ipsec.c,v 1.5 2004/06/27 01:10:53 jonathan Exp $");
37 #endif
38 #endif /* not lint*/
39 
40 /* Kernel headers required, but not included, by netstat.h */
41 #include <sys/types.h>
42 #include <sys/socket.h>
43 
44 /* Kernel headers for sysctl(3). */
45 #include <sys/param.h>
46 #include <sys/sysctl.h>
47 
48 /* Kernel headers for FAST_IPSEC statistics */
49 #include <net/pfkeyv2.h>
50 #include <netipsec/esp_var.h>
51 #include <netipsec/ah_var.h>
52 #include <netipsec/ipip_var.h>
53 #include <netipsec/ipcomp_var.h>
54 #include <netipsec/ipsec_var.h>
55 #include <netipsec/keydb.h>
56 
57 #include <machine/int_fmtio.h>
58 
59 #include <err.h>
60 #include <stdio.h>
61 #include <string.h>
62 
63 #include "netstat.h"
64 
65 /*
66  * Dispatch between fetching and printing (KAME) IPsec statistics,
67  * and FAST_IPSEC statistics, so the rest of netstat need not know
68  * about the vagaries of the two implementations.
69  */
70 void
71 ipsec_switch(u_long off, char * name)
72 {
73 	int status;
74 	size_t slen;
75 
76 	slen = 0;
77 	status = sysctlbyname("net.inet.ipsec.stats", NULL, &slen, NULL, 0);
78 	if (status == 0 && slen == sizeof(struct newipsecstat))
79 		return fast_ipsec_stats(off, name);
80 
81 	return ipsec_stats(off, name);
82 }
83 
84 
85 /*
86  * Table-driven mapping from SADB algorithm codes to string names.
87  */
88 struct alg {
89 	int		a;
90 	const char	*name;
91 };
92 static const struct alg aalgs[] = {
93 	{ SADB_AALG_NONE,	"none", },
94 	{ SADB_AALG_MD5HMAC,	"hmac-md5", },
95 	{ SADB_AALG_SHA1HMAC,	"hmac-sha1", },
96 	{ SADB_X_AALG_MD5,	"md5", },
97 	{ SADB_X_AALG_SHA,	"sha", },
98 	{ SADB_X_AALG_NULL,	"null", },
99 	{ SADB_X_AALG_SHA2_256,	"hmac-sha2-256", },
100 	{ SADB_X_AALG_SHA2_384,	"hmac-sha2-384", },
101 	{ SADB_X_AALG_SHA2_512,	"hmac-sha2-512", },
102 };
103 static const struct alg espalgs[] = {
104 	{ SADB_EALG_NONE,	"none", },
105 	{ SADB_EALG_DESCBC,	"des-cbc", },
106 	{ SADB_EALG_3DESCBC,	"3des-cbc", },
107 	{ SADB_EALG_NULL,	"null", },
108 	{ SADB_X_EALG_CAST128CBC, "cast128-cbc", },
109 	{ SADB_X_EALG_BLOWFISHCBC, "blowfish-cbc", },
110 	{ SADB_X_EALG_RIJNDAELCBC, "aes-cbc", },
111 };
112 static const struct alg ipcompalgs[] = {
113 	{ SADB_X_CALG_NONE,	"none", },
114 	{ SADB_X_CALG_OUI,	"oui", },
115 	{ SADB_X_CALG_DEFLATE,	"deflate", },
116 	{ SADB_X_CALG_LZS,	"lzs", },
117 };
118 #define	N(a)	(sizeof(a)/sizeof(a[0]))
119 
120 static const char*
121 algname(int a, const struct alg algs[], int nalgs)
122 {
123 	static char buf[80];
124 	int i;
125 
126 	for (i = 0; i < nalgs; i++)
127 		if (algs[i].a == a)
128 			return algs[i].name;
129 	snprintf(buf, sizeof(buf), "alg#%u", a);
130 	return buf;
131 }
132 
133 /*
134  * Print the fast_ipsec statistics.
135  * Since NetBSD's netstat(1) seems not to find us for "netstat -s",
136  * but does(?) find KAME, be prepared to be called explicitly from
137  * netstat's main program for "netstat -s"; but silently do nothing
138  * if that happens when we are running on KAME IPsec.
139  */
140 void
141 fast_ipsec_stats(u_long off, char *name)
142 {
143 	struct newipsecstat ipsecstats;
144 	struct ahstat ahstats;
145 	struct espstat espstats;
146 	struct ipcompstat ipcs;
147 	struct ipipstat ipips;
148 	int status;
149 	size_t slen;
150 	int i;
151 
152 	memset(&ipsecstats, 0, sizeof(ipsecstats));
153 	memset(&ahstats, 0, sizeof(ahstats));
154 	memset(&espstats, 0, sizeof(espstats));
155 	memset(&ipcs, 0, sizeof(ipcs));
156 	memset(&ipips, 0, sizeof(ipips));
157 
158 	/* silence check */
159 	status = sysctlbyname("net.inet.ipsec.stats", NULL, &slen, NULL, 0);
160 	if (status != 0)
161 	    return;
162 
163 	slen = sizeof(ipsecstats);
164 	status = sysctlbyname("net.inet.ipsec.stats", &ipsecstats, &slen,
165 			      NULL, 0);
166 	if (status < 0)
167 	  err(1, "net.inet.ipsec.stats");
168 
169 	slen = sizeof (ahstats);
170 	if (sysctlbyname("net.inet.ah.stats", &ahstats, &slen, NULL, 0) < 0)
171 		err(1, "net.inet.ah.stats");
172 	slen = sizeof (espstats);
173 	if (sysctlbyname("net.inet.esp.stats", &espstats, &slen, NULL, 0) < 0)
174 		err(1, "net.inet.esp.stats");
175 	if (sysctlbyname("net.inet.ipcomp.stats", &ipcs, &slen, NULL, 0) < 0)
176 		err(1, "net.inet.ipcomp.stats");
177 	if (sysctlbyname("net.inet.ipip.stats", &ipips, &slen, NULL, 0) < 0)
178 		err(1, "net.inet.ipip.stats");
179 
180 	printf("(Fast) IPsec:\n");
181 
182 #define	STAT(x,fmt)	if ((x) || sflag <= 1) printf("\t%"PRIu64" " fmt "\n", x)
183 	if (ipsecstats.ips_in_polvio+ipsecstats.ips_out_polvio)
184 		printf("\t%"PRIu64" policy violations: %"PRIu64" input %"PRIu64" output\n",
185 		        ipsecstats.ips_in_polvio + ipsecstats.ips_out_polvio,
186 			ipsecstats.ips_in_polvio, ipsecstats.ips_out_polvio);
187 	STAT(ipsecstats.ips_out_nosa, "no SA found (output)");
188 	STAT(ipsecstats.ips_out_nomem, "no memory available (output)");
189 	STAT(ipsecstats.ips_out_noroute, "no route available (output)");
190 	STAT(ipsecstats.ips_out_inval, "generic errors (output)");
191 	STAT(ipsecstats.ips_out_bundlesa, "bundled SA processed (output)");
192 	STAT(ipsecstats.ips_spdcache_lookup, "SPD cache lookups");
193 	STAT(ipsecstats.ips_spdcache_lookup, "SPD cache misses");
194 #undef STAT
195 	printf("\n");
196 
197 	printf("IPsec ah:\n");
198 #define	AHSTAT(x,fmt)	if ((x) || sflag <= 1) printf("\t%"PRIu64" ah " fmt "\n", x)
199 	AHSTAT(ahstats.ahs_input,   "input packets processed");
200 	AHSTAT(ahstats.ahs_output,  "output packets processed");
201 	AHSTAT(ahstats.ahs_hdrops,  "headers too short");
202 	AHSTAT(ahstats.ahs_nopf,    "headers for unsupported address family");
203 	AHSTAT(ahstats.ahs_notdb,   "packets with no SA");
204 	AHSTAT(ahstats.ahs_badkcr, "packets dropped by crypto returning NULL mbuf");
205 	AHSTAT(ahstats.ahs_badauth, "packets with bad authentication");
206 	AHSTAT(ahstats.ahs_noxform, "packets with no xform");
207 	AHSTAT(ahstats.ahs_qfull, "packets dropped due to queue full");
208 	AHSTAT(ahstats.ahs_wrap,  "packets dropped for replay counter wrap");
209 	AHSTAT(ahstats.ahs_replay,  "packets dropped for possible replay");
210 	AHSTAT(ahstats.ahs_badauthl,"packets dropped for bad authenticator length");
211 	AHSTAT(ahstats.ahs_invalid, "packets with an invalid SA");
212 	AHSTAT(ahstats.ahs_toobig,  "packets too big");
213 	AHSTAT(ahstats.ahs_pdrops,  "packets blocked due to policy");
214 	AHSTAT(ahstats.ahs_crypto,  "failed crypto requests");
215 	AHSTAT(ahstats.ahs_tunnel,  "tunnel sanity check failures");
216 
217 	printf("\tah histogram:\n");
218 	for (i = 0; i < AH_ALG_MAX; i++)
219 		if (ahstats.ahs_hist[i])
220 			printf("\t\tah packets with %s: %"PRIu64"\n"
221 				, algname(i, aalgs, N(aalgs))
222 				, ahstats.ahs_hist[i]
223 			);
224 	AHSTAT(ahstats.ahs_ibytes, "bytes received");
225 	AHSTAT(ahstats.ahs_obytes, "bytes transmitted");
226 #undef AHSTAT
227 	printf("\n");
228 
229 	printf("IPsec esp:\n");
230 #define	ESPSTAT(x,fmt) if ((x) || sflag <= 1) printf("\t%"PRIu64" esp " fmt "\n", x)
231 	ESPSTAT(espstats.esps_input,	"input packets processed");
232 	ESPSTAT(espstats.esps_output,	"output packets processed");
233 	ESPSTAT(espstats.esps_hdrops,	"headers too short");
234 	ESPSTAT(espstats.esps_nopf,  "headers for unsupported address family");
235 	ESPSTAT(espstats.esps_notdb,	"packets with no SA");
236 	ESPSTAT(espstats.esps_badkcr,	"packets dropped by crypto returning NULL mbuf");
237 	ESPSTAT(espstats.esps_qfull,	"packets dropped due to queue full");
238 	ESPSTAT(espstats.esps_noxform,	"packets with no xform");
239 	ESPSTAT(espstats.esps_badilen,	"packets with bad ilen");
240 	ESPSTAT(espstats.esps_badenc,	"packets with bad encryption");
241 	ESPSTAT(espstats.esps_badauth,	"packets with bad authentication");
242 	ESPSTAT(espstats.esps_wrap, "packets dropped for replay counter wrap");
243 	ESPSTAT(espstats.esps_replay,	"packets dropped for possible replay");
244 	ESPSTAT(espstats.esps_invalid,	"packets with an invalid SA");
245 	ESPSTAT(espstats.esps_toobig,	"packets too big");
246 	ESPSTAT(espstats.esps_pdrops,	"packets blocked due to policy");
247 	ESPSTAT(espstats.esps_crypto,	"failed crypto requests");
248 	ESPSTAT(espstats.esps_tunnel,	"tunnel sanity check failures");
249 	printf("\tesp histogram:\n");
250 	for (i = 0; i < ESP_ALG_MAX; i++)
251 		if (espstats.esps_hist[i])
252 			printf("\t\tesp packets with %s: %"PRIu64"\n"
253 				, algname(i, espalgs, N(espalgs))
254 				, espstats.esps_hist[i]
255 			);
256 	ESPSTAT(espstats.esps_ibytes, "bytes received");
257 	ESPSTAT(espstats.esps_obytes, "bytes transmitted");
258 #undef ESPSTAT
259 	printf("IPsec ipip:\n");
260 
261 #define	IPIPSTAT(x,fmt) \
262 	if ((x) || sflag <= 1) printf("\t%"PRIu64" ipip " fmt "\n", x)
263 	IPIPSTAT(ipips.ipips_ipackets,	"total input packets");
264 	IPIPSTAT(ipips.ipips_opackets,	"total output packets");
265 	IPIPSTAT(ipips.ipips_hdrops,	"packets too short for header length");
266 	IPIPSTAT(ipips.ipips_qfull,	"packets dropped due to queue full");
267 	IPIPSTAT(ipips.ipips_pdrops,	"packets blocked due to policy");
268 	IPIPSTAT(ipips.ipips_spoof,	"IP spoofing attempts");
269 	IPIPSTAT(ipips.ipips_family,	"protocol family mismatched");
270 	IPIPSTAT(ipips.ipips_unspec,	"missing tunnel-endpoint address");
271 	IPIPSTAT(ipips.ipips_ibytes,	"input bytes received");
272 	IPIPSTAT(ipips.ipips_obytes,	"output bytes procesesed");
273 #undef IPIPSTAT
274 
275 	printf("IPsec ipcomp:\n");
276 #define	IPCOMP(x,fmt) \
277 	if ((x) || sflag <= 1) printf("\t%"PRIu64" ipcomp " fmt "\n", x)
278 
279 	IPCOMP(ipcs.ipcomps_hdrops,	"packets too short for header length");
280 	IPCOMP(ipcs.ipcomps_nopf,	"protocol family not supported");
281 	IPCOMP(ipcs.ipcomps_notdb,	"not db");
282 	IPCOMP(ipcs.ipcomps_badkcr,	"packets dropped by crypto returning NULL mbuf");
283 	IPCOMP(ipcs.ipcomps_qfull,	"queue full");
284         IPCOMP(ipcs.ipcomps_noxform,	"no support for transform");
285 	IPCOMP(ipcs.ipcomps_wrap,  "packets dropped for replay counter wrap");
286 	IPCOMP(ipcs.ipcomps_input,	"input IPcomp packets");
287 	IPCOMP(ipcs.ipcomps_output,	"output IPcomp packets");
288 	IPCOMP(ipcs.ipcomps_invalid,	"specified an invalid TDB");
289 	IPCOMP(ipcs.ipcomps_toobig,	"packets decompressed as too big");
290 	IPCOMP(ipcs.ipcomps_pdrops,	"packets blocked due to policy");
291 	IPCOMP(ipcs.ipcomps_crypto,	"failed crypto requests");
292 
293 	printf("\tIPcomp histogram:\n");
294 	for (i = 0; i < IPCOMP_ALG_MAX; i++)
295 		if (ipcs.ipcomps_hist[i])
296 			printf("\t\tIPcomp packets with %s: %"PRIu64"\n"
297 				, algname(i, ipcompalgs, N(ipcompalgs))
298 				, ipcs.ipcomps_hist[i]
299 			);
300 	IPCOMP(ipcs.ipcomps_ibytes,	"input bytes");
301 	IPCOMP(ipcs.ipcomps_obytes,	"output bytes");
302 #undef IPCOMP
303 }
304