1/*	$KAME: ipsec.c,v 1.33 2003/07/25 09:54:32 itojun Exp $	*/
2
3/*-
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 * Copyright (c) 2005 NTT Multimedia Communications Laboratories, Inc.
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/*-
31 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
32 * All rights reserved.
33 *
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
36 * are met:
37 * 1. Redistributions of source code must retain the above copyright
38 *    notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 *    notice, this list of conditions and the following disclaimer in the
41 *    documentation and/or other materials provided with the distribution.
42 * 3. Neither the name of the project nor the names of its contributors
43 *    may be used to endorse or promote products derived from this software
44 *    without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 * SUCH DAMAGE.
57 */
58/*-
59 * Copyright (c) 1983, 1988, 1993
60 *	The Regents of the University of California.  All rights reserved.
61 *
62 * Redistribution and use in source and binary forms, with or without
63 * modification, are permitted provided that the following conditions
64 * are met:
65 * 1. Redistributions of source code must retain the above copyright
66 *    notice, this list of conditions and the following disclaimer.
67 * 2. Redistributions in binary form must reproduce the above copyright
68 *    notice, this list of conditions and the following disclaimer in the
69 *    documentation and/or other materials provided with the distribution.
70 * 3. Neither the name of the University nor the names of its contributors
71 *    may be used to endorse or promote products derived from this software
72 *    without specific prior written permission.
73 *
74 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
75 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
76 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
77 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
78 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
79 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
80 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
81 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
82 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
83 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
84 * SUCH DAMAGE.
85 */
86
87#include <sys/param.h>
88#include <sys/queue.h>
89#include <sys/socket.h>
90#include <sys/socketvar.h>
91
92#include <netinet/in.h>
93
94#ifdef IPSEC
95#include <netipsec/ipsec.h>
96#include <netipsec/ah_var.h>
97#include <netipsec/esp_var.h>
98#include <netipsec/ipcomp_var.h>
99#endif
100
101#include <stdint.h>
102#include <stdio.h>
103#include <stdbool.h>
104#include <string.h>
105#include <unistd.h>
106#include <libxo/xo.h>
107#include "netstat.h"
108
109#ifdef IPSEC
110struct val2str {
111	int val;
112	const char *str;
113};
114
115static struct val2str ipsec_ahnames[] = {
116	{ SADB_AALG_NONE, "none", },
117	{ SADB_AALG_SHA1HMAC, "hmac-sha1", },
118	{ SADB_X_AALG_NULL, "null", },
119	{ SADB_X_AALG_SHA2_256, "hmac-sha2-256", },
120	{ SADB_X_AALG_SHA2_384, "hmac-sha2-384", },
121	{ SADB_X_AALG_SHA2_512, "hmac-sha2-512", },
122	{ SADB_X_AALG_AES_XCBC_MAC, "aes-xcbc-mac", },
123	{ SADB_X_AALG_TCP_MD5, "tcp-md5", },
124	{ SADB_X_AALG_AES128GMAC, "aes-gmac-128", },
125	{ SADB_X_AALG_AES192GMAC, "aes-gmac-192", },
126	{ SADB_X_AALG_AES256GMAC, "aes-gmac-256", },
127	{ -1, NULL },
128};
129
130static struct val2str ipsec_espnames[] = {
131	{ SADB_EALG_NONE, "none", },
132	{ SADB_EALG_NULL, "null", },
133	{ SADB_X_EALG_AESCBC, "aes-cbc", },
134	{ SADB_X_EALG_AESCTR, "aes-ctr", },
135	{ SADB_X_EALG_AESGCM16, "aes-gcm-16", },
136	{ SADB_X_EALG_AESGMAC, "aes-gmac", },
137	{ -1, NULL },
138};
139
140static struct val2str ipsec_compnames[] = {
141	{ SADB_X_CALG_NONE, "none", },
142	{ SADB_X_CALG_OUI, "oui", },
143	{ SADB_X_CALG_DEFLATE, "deflate", },
144	{ SADB_X_CALG_LZS, "lzs", },
145	{ -1, NULL },
146};
147
148static void
149print_ipsecstats(const char *tag, const struct ipsecstat *ipsecstat)
150{
151	xo_open_container(tag);
152
153#define	p(f, m) if (ipsecstat->f || sflag <= 1) \
154	xo_emit(m, (uintmax_t)ipsecstat->f, plural(ipsecstat->f))
155#define	p2(f, m) if (ipsecstat->f || sflag <= 1) \
156	xo_emit(m, (uintmax_t)ipsecstat->f, plurales(ipsecstat->f))
157
158	p(ips_in_polvio, "\t{:dropped-policy-violation/%ju} "
159	    "{N:/inbound packet%s violated process security policy}\n");
160	p(ips_in_nomem, "\t{:dropped-no-memory/%ju} "
161	    "{N:/inbound packet%s failed due to insufficient memory}\n");
162	p(ips_in_inval, "\t{:dropped-invalid/%ju} "
163	    "{N:/invalid inbound packet%s}\n");
164	p(ips_out_polvio, "\t{:discarded-policy-violation/%ju} "
165	    "{N:/outbound packet%s violated process security policy}\n");
166	p(ips_out_nosa, "\t{:discarded-no-sa/%ju} "
167	    "{N:/outbound packet%s with no SA available}\n");
168	p(ips_out_nomem, "\t{:discarded-no-memory/%ju} "
169	    "{N:/outbound packet%s failed due to insufficient memory}\n");
170	p(ips_out_noroute, "\t{:discarded-no-route/%ju} "
171	    "{N:/outbound packet%s with no route available}\n");
172	p(ips_out_inval, "\t{:discarded-invalid/%ju} "
173	    "{N:/invalid outbound packet%s}\n");
174	p(ips_out_bundlesa, "\t{:send-bundled-sa/%ju} "
175	    "{N:/outbound packet%s with bundled SAs}\n");
176	p(ips_spdcache_hits, "\t{:spdcache-hits/%ju} "
177	    "{N:/spd cache hit%s}\n");
178	p2(ips_spdcache_misses, "\t{:spdcache-misses/%ju} "
179	    "{N:/spd cache miss%s}\n");
180	p(ips_clcopied, "\t{:clusters-copied-during-clone/%ju} "
181	    "{N:/cluster%s copied during clone}\n");
182	p(ips_mbinserted, "\t{:mbufs-inserted/%ju} "
183	    "{N:/mbuf%s inserted during makespace}\n");
184#undef p2
185#undef p
186	xo_close_container(tag);
187}
188
189void
190ipsec_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
191{
192	struct ipsecstat ipsecstat;
193	const char *tag;
194
195	if (strcmp(name, "ipsec6") == 0) {
196		if (fetch_stats("net.inet6.ipsec6.ipsecstats", off,&ipsecstat,
197				sizeof(ipsecstat), kread_counters) != 0)
198			return;
199		tag = "ipsec6-statistics";
200	} else {
201		if (fetch_stats("net.inet.ipsec.ipsecstats", off, &ipsecstat,
202				sizeof(ipsecstat), kread_counters) != 0)
203			return;
204		tag = "ipsec-statistics";
205	}
206
207	xo_emit("{T:/%s}:\n", name);
208
209	print_ipsecstats(tag, &ipsecstat);
210}
211
212
213static void print_ahstats(const struct ahstat *ahstat);
214static void print_espstats(const struct espstat *espstat);
215static void print_ipcompstats(const struct ipcompstat *ipcompstat);
216
217/*
218 * Dump IPSEC statistics structure.
219 */
220static void
221ipsec_hist_new(const uint64_t *hist, size_t histmax,
222    const struct val2str *name, const char *title, const char *cname)
223{
224	int first;
225	size_t proto;
226	const struct val2str *p;
227
228	first = 1;
229	for (proto = 0; proto < histmax; proto++) {
230		if (hist[proto] <= 0)
231			continue;
232		if (first) {
233			xo_open_list(cname);
234			xo_emit("\t{T:/%s histogram}:\n", title);
235			first = 0;
236		}
237		xo_open_instance(cname);
238		for (p = name; p && p->str; p++) {
239			if (p->val == (int)proto)
240				break;
241		}
242		if (p && p->str) {
243			xo_emit("\t\t{k:name}: {:count/%ju}\n", p->str,
244			    (uintmax_t)hist[proto]);
245		} else {
246			xo_emit("\t\t#{k:name/%lu}: {:count/%ju}\n",
247			    (unsigned long)proto, (uintmax_t)hist[proto]);
248		}
249		xo_close_instance(cname);
250	}
251	if (!first)
252		xo_close_list(cname);
253}
254
255static void
256print_ahstats(const struct ahstat *ahstat)
257{
258	xo_open_container("ah-statictics");
259
260#define	p(f, n, m) if (ahstat->f || sflag <= 1) \
261	xo_emit("\t{:" n "/%ju} {N:/" m "}\n",	\
262	    (uintmax_t)ahstat->f, plural(ahstat->f))
263#define	hist(f, n, t, c) \
264	ipsec_hist_new((f), sizeof(f)/sizeof(f[0]), (n), (t), (c))
265
266	p(ahs_hdrops, "dropped-short-header",
267	    "packet%s shorter than header shows");
268	p(ahs_nopf, "dropped-bad-protocol",
269	    "packet%s dropped; protocol family not supported");
270	p(ahs_notdb, "dropped-no-tdb", "packet%s dropped; no TDB");
271	p(ahs_badkcr, "dropped-bad-kcr", "packet%s dropped; bad KCR");
272	p(ahs_qfull, "dropped-queue-full", "packet%s dropped; queue full");
273	p(ahs_noxform, "dropped-no-transform",
274	    "packet%s dropped; no transform");
275	p(ahs_wrap, "replay-counter-wraps", "replay counter wrap%s");
276	p(ahs_badauth, "dropped-bad-auth",
277	    "packet%s dropped; bad authentication detected");
278	p(ahs_badauthl, "dropped-bad-auth-level",
279	    "packet%s dropped; bad authentication length");
280	p(ahs_replay, "possile-replay-detected",
281	    "possible replay packet%s detected");
282	p(ahs_input, "received-packets", "packet%s in");
283	p(ahs_output, "send-packets", "packet%s out");
284	p(ahs_invalid, "dropped-bad-tdb", "packet%s dropped; invalid TDB");
285	p(ahs_ibytes, "received-bytes", "byte%s in");
286	p(ahs_obytes, "send-bytes", "byte%s out");
287	p(ahs_toobig, "dropped-too-large",
288	    "packet%s dropped; larger than IP_MAXPACKET");
289	p(ahs_pdrops, "dropped-policy-violation",
290	    "packet%s blocked due to policy");
291	p(ahs_crypto, "crypto-failures", "crypto processing failure%s");
292	p(ahs_tunnel, "tunnel-failures", "tunnel sanity check failure%s");
293	hist(ahstat->ahs_hist, ipsec_ahnames,
294	    "AH output", "ah-output-histogram");
295
296#undef p
297#undef hist
298	xo_close_container("ah-statictics");
299}
300
301void
302ah_stats(u_long off, const char *name, int family __unused, int proto __unused)
303{
304	struct ahstat ahstat;
305
306	if (fetch_stats("net.inet.ah.stats", off, &ahstat,
307	    sizeof(ahstat), kread_counters) != 0)
308		return;
309
310	xo_emit("{T:/%s}:\n", name);
311
312	print_ahstats(&ahstat);
313}
314
315static void
316print_espstats(const struct espstat *espstat)
317{
318	xo_open_container("esp-statictics");
319#define	p(f, n, m) if (espstat->f || sflag <= 1)	\
320	xo_emit("\t{:" n "/%ju} {N:/" m "}\n",		\
321	    (uintmax_t)espstat->f, plural(espstat->f))
322#define	hist(f, n, t, c) \
323	ipsec_hist_new((f), sizeof(f)/sizeof(f[0]), (n), (t), (c));
324
325	p(esps_hdrops, "dropped-short-header",
326	    "packet%s shorter than header shows");
327	p(esps_nopf, "dropped-bad-protocol",
328	    "packet%s dropped; protocol family not supported");
329	p(esps_notdb, "dropped-no-tdb", "packet%s dropped; no TDB");
330	p(esps_badkcr, "dropped-bad-kcr", "packet%s dropped; bad KCR");
331	p(esps_qfull, "dropped-queue-full", "packet%s dropped; queue full");
332	p(esps_noxform, "dropped-no-transform",
333	    "packet%s dropped; no transform");
334	p(esps_badilen, "dropped-bad-length", "packet%s dropped; bad ilen");
335	p(esps_wrap, "replay-counter-wraps", "replay counter wrap%s");
336	p(esps_badenc, "dropped-bad-crypto",
337	    "packet%s dropped; bad encryption detected");
338	p(esps_badauth, "dropped-bad-auth",
339	    "packet%s dropped; bad authentication detected");
340	p(esps_replay, "possible-replay-detected",
341	    "possible replay packet%s detected");
342	p(esps_input, "received-packets", "packet%s in");
343	p(esps_output, "sent-packets", "packet%s out");
344	p(esps_invalid, "dropped-bad-tdb", "packet%s dropped; invalid TDB");
345	p(esps_ibytes, "receive-bytes", "byte%s in");
346	p(esps_obytes, "sent-bytes", "byte%s out");
347	p(esps_toobig, "dropped-too-large",
348	    "packet%s dropped; larger than IP_MAXPACKET");
349	p(esps_pdrops, "dropped-policy-violation",
350	    "packet%s blocked due to policy");
351	p(esps_crypto, "crypto-failures", "crypto processing failure%s");
352	p(esps_tunnel, "tunnel-failures", "tunnel sanity check failure%s");
353	hist(espstat->esps_hist, ipsec_espnames,
354	    "ESP output", "esp-output-histogram");
355
356#undef p
357#undef hist
358	xo_close_container("esp-statictics");
359}
360
361void
362esp_stats(u_long off, const char *name, int family __unused, int proto __unused)
363{
364	struct espstat espstat;
365
366	if (fetch_stats("net.inet.esp.stats", off, &espstat,
367	    sizeof(espstat), kread_counters) != 0)
368		return;
369
370	xo_emit("{T:/%s}:\n", name);
371
372	print_espstats(&espstat);
373}
374
375static void
376print_ipcompstats(const struct ipcompstat *ipcompstat)
377{
378	xo_open_container("ipcomp-statictics");
379
380#define	p(f, n, m) if (ipcompstat->f || sflag <= 1)	\
381	xo_emit("\t{:" n "/%ju} {N:/" m "}\n",		\
382	    (uintmax_t)ipcompstat->f, plural(ipcompstat->f))
383#define	hist(f, n, t, c) \
384	ipsec_hist_new((f), sizeof(f)/sizeof(f[0]), (n), (t), (c));
385
386	p(ipcomps_hdrops, "dropped-short-header",
387	    "packet%s shorter than header shows");
388	p(ipcomps_nopf, "dropped-bad-protocol",
389	    "packet%s dropped; protocol family not supported");
390	p(ipcomps_notdb, "dropped-no-tdb", "packet%s dropped; no TDB");
391	p(ipcomps_badkcr, "dropped-bad-kcr", "packet%s dropped; bad KCR");
392	p(ipcomps_qfull, "dropped-queue-full", "packet%s dropped; queue full");
393	p(ipcomps_noxform, "dropped-no-transform",
394	    "packet%s dropped; no transform");
395	p(ipcomps_wrap, "replay-counter-wraps", "replay counter wrap%s");
396	p(ipcomps_input, "receive-packets", "packet%s in");
397	p(ipcomps_output, "sent-packets", "packet%s out");
398	p(ipcomps_invalid, "dropped-bad-tdb", "packet%s dropped; invalid TDB");
399	p(ipcomps_ibytes, "received-bytes", "byte%s in");
400	p(ipcomps_obytes, "sent-bytes", "byte%s out");
401	p(ipcomps_toobig, "dropped-too-large",
402	    "packet%s dropped; larger than IP_MAXPACKET");
403	p(ipcomps_pdrops, "dropped-policy-violation",
404	    "packet%s blocked due to policy");
405	p(ipcomps_crypto, "crypto-failure", "crypto processing failure%s");
406	hist(ipcompstat->ipcomps_hist, ipsec_compnames,
407	    "COMP output", "comp-output-histogram");
408	p(ipcomps_threshold, "sent-uncompressed-small-packets",
409	    "packet%s sent uncompressed; size < compr. algo. threshold");
410	p(ipcomps_uncompr, "sent-uncompressed-useless-packets",
411	    "packet%s sent uncompressed; compression was useless");
412
413#undef p
414#undef hist
415	xo_close_container("ipcomp-statictics");
416}
417
418void
419ipcomp_stats(u_long off, const char *name, int family __unused,
420    int proto __unused)
421{
422	struct ipcompstat ipcompstat;
423
424	if (fetch_stats("net.inet.ipcomp.stats", off, &ipcompstat,
425	    sizeof(ipcompstat), kread_counters) != 0)
426		return;
427
428	xo_emit("{T:/%s}:\n", name);
429
430	print_ipcompstats(&ipcompstat);
431}
432
433#endif /*IPSEC*/
434