1/* $USAGI: $ */
2
3/*
4 * Copyright (C)2004 USAGI/WIDE Project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20/*
21 * based on ip.c, iproute.c
22 */
23/*
24 * Authors:
25 *	Masahide NAKAMURA @USAGI
26 */
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <sys/types.h>
32#include <sys/socket.h>
33#include <time.h>
34#include <netdb.h>
35#include <net/if.h>
36#include <linux/netlink.h>
37#include <linux/rtnetlink.h>
38#include <linux/xfrm.h>
39
40#include "utils.h"
41#include "xfrm.h"
42
43#define STRBUF_SIZE	(128)
44#define STRBUF_CAT(buf, str) \
45	do { \
46		int rest = sizeof(buf) - 1 - strlen(buf); \
47		if (rest > 0) { \
48			int len = strlen(str); \
49			if (len > rest) \
50				len = rest; \
51			strncat(buf, str, len); \
52			buf[sizeof(buf) - 1] = '\0'; \
53		} \
54	} while(0);
55
56struct xfrm_filter filter;
57
58static void usage(void) __attribute__((noreturn));
59
60static void usage(void)
61{
62	fprintf(stderr,
63		"Usage: ip xfrm XFRM_OBJECT { COMMAND | help }\n"
64		"where  XFRM_OBJECT := { state | policy | monitor }\n");
65	exit(-1);
66}
67
68/* This is based on utils.c(inet_addr_match) */
69int xfrm_addr_match(xfrm_address_t *x1, xfrm_address_t *x2, int bits)
70{
71	__u32 *a1 = (__u32 *)x1;
72	__u32 *a2 = (__u32 *)x2;
73	int words = bits >> 0x05;
74
75	bits &= 0x1f;
76
77	if (words)
78		if (memcmp(a1, a2, words << 2))
79			return -1;
80
81	if (bits) {
82		__u32 w1, w2;
83		__u32 mask;
84
85		w1 = a1[words];
86		w2 = a2[words];
87
88		mask = htonl((0xffffffff) << (0x20 - bits));
89
90		if ((w1 ^ w2) & mask)
91			return 1;
92	}
93
94	return 0;
95}
96
97struct typeent {
98	const char *t_name;
99	int t_type;
100};
101
102static const struct typeent xfrmproto_types[]= {
103	{ "esp", IPPROTO_ESP }, { "ah", IPPROTO_AH }, { "comp", IPPROTO_COMP },
104	{ NULL, -1 }
105};
106
107int xfrm_xfrmproto_getbyname(char *name)
108{
109	int i;
110
111	for (i = 0; ; i++) {
112		const struct typeent *t = &xfrmproto_types[i];
113		if (!t->t_name || t->t_type == -1)
114			break;
115
116		if (strcmp(t->t_name, name) == 0)
117			return t->t_type;
118	}
119
120	return -1;
121}
122
123const char *strxf_xfrmproto(__u8 proto)
124{
125	int i;
126
127	for (i = 0; ; i++) {
128		const struct typeent *t = &xfrmproto_types[i];
129		if (!t->t_name || t->t_type == -1)
130			break;
131
132		if (t->t_type == proto)
133			return t->t_name;
134	}
135
136	return NULL;
137}
138
139static const struct typeent algo_types[]= {
140	{ "enc", XFRMA_ALG_CRYPT }, { "auth", XFRMA_ALG_AUTH },
141	{ "comp", XFRMA_ALG_COMP }, { NULL, -1 }
142};
143
144int xfrm_algotype_getbyname(char *name)
145{
146	int i;
147
148	for (i = 0; ; i++) {
149		const struct typeent *t = &algo_types[i];
150		if (!t->t_name || t->t_type == -1)
151			break;
152
153		if (strcmp(t->t_name, name) == 0)
154			return t->t_type;
155	}
156
157	return -1;
158}
159
160const char *strxf_algotype(int type)
161{
162	int i;
163
164	for (i = 0; ; i++) {
165		const struct typeent *t = &algo_types[i];
166		if (!t->t_name || t->t_type == -1)
167			break;
168
169		if (t->t_type == type)
170			return t->t_name;
171	}
172
173	return NULL;
174}
175
176const char *strxf_mask8(__u8 mask)
177{
178	static char str[16];
179	const int sn = sizeof(mask) * 8 - 1;
180	__u8 b;
181	int i = 0;
182
183	for (b = (1 << sn); b > 0; b >>= 1)
184		str[i++] = ((b & mask) ? '1' : '0');
185	str[i] = '\0';
186
187	return str;
188}
189
190const char *strxf_mask32(__u32 mask)
191{
192	static char str[16];
193
194	sprintf(str, "%.8x", mask);
195
196	return str;
197}
198
199const char *strxf_share(__u8 share)
200{
201	static char str[32];
202
203	switch (share) {
204	case XFRM_SHARE_ANY:
205		strcpy(str, "any");
206		break;
207	case XFRM_SHARE_SESSION:
208		strcpy(str, "session");
209		break;
210	case XFRM_SHARE_USER:
211		strcpy(str, "user");
212		break;
213	case XFRM_SHARE_UNIQUE:
214		strcpy(str, "unique");
215		break;
216	default:
217		sprintf(str, "%u", share);
218		break;
219	}
220
221	return str;
222}
223
224const char *strxf_proto(__u8 proto)
225{
226	static char buf[32];
227	struct protoent *pp;
228	const char *p;
229
230	pp = getprotobynumber(proto);
231	if (pp)
232		p = pp->p_name;
233	else {
234		sprintf(buf, "%u", proto);
235		p = buf;
236	}
237
238	return p;
239}
240
241void xfrm_id_info_print(xfrm_address_t *saddr, struct xfrm_id *id,
242			__u8 mode, __u32 reqid, __u16 family, int force_spi,
243			FILE *fp, const char *prefix, const char *title)
244{
245	char abuf[256];
246
247	if (title)
248		fprintf(fp, title);
249
250	memset(abuf, '\0', sizeof(abuf));
251	fprintf(fp, "src %s ", rt_addr_n2a(family, sizeof(*saddr),
252					   saddr, abuf, sizeof(abuf)));
253	memset(abuf, '\0', sizeof(abuf));
254	fprintf(fp, "dst %s", rt_addr_n2a(family, sizeof(id->daddr),
255					  &id->daddr, abuf, sizeof(abuf)));
256	fprintf(fp, "%s", _SL_);
257
258	if (prefix)
259		fprintf(fp, prefix);
260	fprintf(fp, "\t");
261
262	fprintf(fp, "proto %s ", strxf_xfrmproto(id->proto));
263
264	if (show_stats > 0 || force_spi || id->spi) {
265		__u32 spi = ntohl(id->spi);
266		fprintf(fp, "spi 0x%08x", spi);
267		if (show_stats > 0)
268			fprintf(fp, "(%u)", spi);
269		fprintf(fp, " ");
270	}
271
272	fprintf(fp, "reqid %u", reqid);
273	if (show_stats > 0)
274		fprintf(fp, "(0x%08x)", reqid);
275	fprintf(fp, " ");
276
277	fprintf(fp, "mode ");
278	switch (mode) {
279	case 0:
280		fprintf(fp, "transport");
281		break;
282	case 1:
283		fprintf(fp, "tunnel");
284		break;
285	default:
286		fprintf(fp, "%u", mode);
287		break;
288	}
289	fprintf(fp, "%s", _SL_);
290}
291
292static const char *strxf_limit(__u64 limit)
293{
294	static char str[32];
295	if (limit == XFRM_INF)
296		strcpy(str, "(INF)");
297	else
298		sprintf(str, "%llu", (unsigned long long) limit);
299
300	return str;
301}
302
303void xfrm_stats_print(struct xfrm_stats *s, FILE *fp, const char *prefix)
304{
305	if (prefix)
306		fprintf(fp, prefix);
307	fprintf(fp, "stats:");
308	fprintf(fp, "%s", _SL_);
309
310	if (prefix)
311		fprintf(fp, prefix);
312	fprintf(fp, "  ");
313	fprintf(fp, "replay-window %u ", s->replay_window);
314	fprintf(fp, "replay %u ", s->replay);
315	fprintf(fp, "failed %u", s->integrity_failed);
316	fprintf(fp, "%s", _SL_);
317}
318
319static const char *strxf_time(__u64 time)
320{
321	static char str[32];
322
323	if (time == 0)
324		strcpy(str, "-");
325	else {
326		time_t t;
327		struct tm *tp;
328
329		/* XXX: treat time in the same manner of kernel's
330		 * net/xfrm/xfrm_{user,state}.c
331		 */
332		t = (long)time;
333		tp = localtime(&t);
334
335		strftime(str, sizeof(str), "%Y-%m-%d %T", tp);
336	}
337
338	return str;
339}
340
341void xfrm_lifetime_print(struct xfrm_lifetime_cfg *cfg,
342			 struct xfrm_lifetime_cur *cur,
343			 FILE *fp, const char *prefix)
344{
345	if (cfg) {
346		if (prefix)
347			fprintf(fp, prefix);
348		fprintf(fp, "lifetime config:");
349		fprintf(fp, "%s", _SL_);
350
351		if (prefix)
352			fprintf(fp, prefix);
353		fprintf(fp, "  ");
354		fprintf(fp, "limit: ");
355		fprintf(fp, "soft ");
356		fprintf(fp, strxf_limit(cfg->soft_byte_limit));
357		fprintf(fp, "(bytes), hard ");
358		fprintf(fp, strxf_limit(cfg->hard_byte_limit));
359		fprintf(fp, "(bytes)");
360		fprintf(fp, "%s", _SL_);
361
362		if (prefix)
363			fprintf(fp, prefix);
364		fprintf(fp, "  ");
365		fprintf(fp, "limit: ");
366		fprintf(fp, "soft ");
367		fprintf(fp, strxf_limit(cfg->soft_packet_limit));
368		fprintf(fp, "(packets), hard ");
369		fprintf(fp, strxf_limit(cfg->hard_packet_limit));
370		fprintf(fp, "(packets)");
371		fprintf(fp, "%s", _SL_);
372
373		if (prefix)
374			fprintf(fp, prefix);
375		fprintf(fp, "  ");
376		fprintf(fp, "expire add: ");
377		fprintf(fp, "soft ");
378		fprintf(fp, "%llu", (unsigned long long) cfg->soft_add_expires_seconds);
379		fprintf(fp, "(sec), hard ");
380		fprintf(fp, "%llu", (unsigned long long) cfg->hard_add_expires_seconds);
381		fprintf(fp, "(sec)");
382		fprintf(fp, "%s", _SL_);
383
384		if (prefix)
385			fprintf(fp, prefix);
386		fprintf(fp, "  ");
387		fprintf(fp, "expire use: ");
388		fprintf(fp, "soft ");
389		fprintf(fp, "%llu", (unsigned long long) cfg->soft_use_expires_seconds);
390		fprintf(fp, "(sec), hard ");
391		fprintf(fp, "%llu", (unsigned long long) cfg->hard_use_expires_seconds);
392		fprintf(fp, "(sec)");
393		fprintf(fp, "%s", _SL_);
394	}
395	if (cur) {
396		if (prefix)
397			fprintf(fp, prefix);
398		fprintf(fp, "lifetime current:");
399		fprintf(fp, "%s", _SL_);
400
401		if (prefix)
402			fprintf(fp, prefix);
403		fprintf(fp, "  ");
404		fprintf(fp, "%llu(bytes), ", (unsigned long long) cur->bytes);
405		fprintf(fp, "%llu(packets)", (unsigned long long) cur->packets);
406		fprintf(fp, "%s", _SL_);
407
408		if (prefix)
409			fprintf(fp, prefix);
410		fprintf(fp, "  ");
411		fprintf(fp, "add %s ", strxf_time(cur->add_time));
412		fprintf(fp, "use %s", strxf_time(cur->use_time));
413		fprintf(fp, "%s", _SL_);
414	}
415}
416
417void xfrm_selector_print(struct xfrm_selector *sel, __u16 family,
418			 FILE *fp, const char *prefix)
419{
420	char abuf[256];
421	__u16 f;
422
423	f = sel->family;
424	if (f == AF_UNSPEC)
425		f = family;
426	if (f == AF_UNSPEC)
427		f = preferred_family;
428
429	if (prefix)
430		fprintf(fp, prefix);
431
432	memset(abuf, '\0', sizeof(abuf));
433	fprintf(fp, "src %s/%u ", rt_addr_n2a(f, sizeof(sel->saddr),
434					      &sel->saddr, abuf, sizeof(abuf)),
435		sel->prefixlen_s);
436
437	memset(abuf, '\0', sizeof(abuf));
438	fprintf(fp, "dst %s/%u ", rt_addr_n2a(f, sizeof(sel->daddr),
439					      &sel->daddr, abuf, sizeof(abuf)),
440		sel->prefixlen_d);
441
442	if (sel->proto)
443		fprintf(fp, "proto %s ", strxf_proto(sel->proto));
444	switch (sel->proto) {
445	case IPPROTO_TCP:
446	case IPPROTO_UDP:
447	case IPPROTO_SCTP:
448	default: /* XXX */
449		if (sel->sport_mask)
450			fprintf(fp, "sport %u ", ntohs(sel->sport));
451		if (sel->dport_mask)
452			fprintf(fp, "dport %u ", ntohs(sel->dport));
453		break;
454	case IPPROTO_ICMP:
455	case IPPROTO_ICMPV6:
456		/* type/code is stored at sport/dport in selector */
457		if (sel->sport_mask)
458			fprintf(fp, "type %u ", ntohs(sel->sport));
459		if (sel->dport_mask)
460			fprintf(fp, "code %u ", ntohs(sel->dport));
461		break;
462	}
463
464	if (sel->ifindex > 0) {
465		char buf[IFNAMSIZ];
466
467		memset(buf, '\0', sizeof(buf));
468		if_indextoname(sel->ifindex, buf);
469		fprintf(fp, "dev %s ", buf);
470	}
471
472	if (show_stats > 0)
473		fprintf(fp, "uid %u", sel->user);
474
475	fprintf(fp, "%s", _SL_);
476}
477
478static void xfrm_algo_print(struct xfrm_algo *algo, int type, int len,
479			    FILE *fp, const char *prefix)
480{
481	int keylen;
482	int i;
483
484	if (prefix)
485		fprintf(fp, prefix);
486
487	fprintf(fp, "%s ", strxf_algotype(type));
488
489	if (len < sizeof(*algo)) {
490		fprintf(fp, "(ERROR truncated)");
491		goto fin;
492	}
493	len -= sizeof(*algo);
494
495	fprintf(fp, "%s ", algo->alg_name);
496
497	keylen = algo->alg_key_len / 8;
498	if (len < keylen) {
499		fprintf(fp, "(ERROR truncated)");
500		goto fin;
501	}
502
503	fprintf(fp, "0x");
504	for (i = 0; i < keylen; i ++)
505		fprintf(fp, "%.2x", (unsigned char)algo->alg_key[i]);
506
507	if (show_stats > 0)
508		fprintf(fp, " (%d bits)", algo->alg_key_len);
509
510 fin:
511	fprintf(fp, "%s", _SL_);
512}
513
514static void xfrm_tmpl_print(struct xfrm_user_tmpl *tmpls, int len,
515			    __u16 family, FILE *fp, const char *prefix)
516{
517	int ntmpls = len / sizeof(struct xfrm_user_tmpl);
518	int i;
519
520	if (ntmpls <= 0) {
521		if (prefix)
522			fprintf(fp, prefix);
523		fprintf(fp, "(ERROR \"tmpl\" truncated)");
524		fprintf(fp, "%s", _SL_);
525		return;
526	}
527
528	for (i = 0; i < ntmpls; i++) {
529		struct xfrm_user_tmpl *tmpl = &tmpls[i];
530
531		if (prefix)
532			fprintf(fp, prefix);
533
534		xfrm_id_info_print(&tmpl->saddr, &tmpl->id, tmpl->mode,
535				   tmpl->reqid, family, 0, fp, prefix, "tmpl ");
536
537		if (show_stats > 0 || tmpl->optional) {
538			if (prefix)
539				fprintf(fp, prefix);
540			fprintf(fp, "\t");
541			switch (tmpl->optional) {
542			case 0:
543				if (show_stats > 0)
544					fprintf(fp, "level required ");
545				break;
546			case 1:
547				fprintf(fp, "level use ");
548				break;
549			default:
550				fprintf(fp, "level %u ", tmpl->optional);
551				break;
552			}
553
554			if (show_stats > 0)
555				fprintf(fp, "share %s ", strxf_share(tmpl->share));
556
557			fprintf(fp, "%s", _SL_);
558		}
559
560		if (show_stats > 0) {
561			if (prefix)
562				fprintf(fp, prefix);
563			fprintf(fp, "\t");
564			fprintf(fp, "%s-mask %s ",
565				strxf_algotype(XFRMA_ALG_CRYPT),
566				strxf_mask32(tmpl->ealgos));
567			fprintf(fp, "%s-mask %s ",
568				strxf_algotype(XFRMA_ALG_AUTH),
569				strxf_mask32(tmpl->aalgos));
570			fprintf(fp, "%s-mask %s",
571				strxf_algotype(XFRMA_ALG_COMP),
572				strxf_mask32(tmpl->calgos));
573
574			fprintf(fp, "%s", _SL_);
575		}
576	}
577}
578
579void xfrm_xfrma_print(struct rtattr *tb[], __u16 family,
580		      FILE *fp, const char *prefix)
581{
582	if (tb[XFRMA_ALG_AUTH]) {
583		struct rtattr *rta = tb[XFRMA_ALG_AUTH];
584		xfrm_algo_print((struct xfrm_algo *) RTA_DATA(rta),
585				XFRMA_ALG_AUTH, RTA_PAYLOAD(rta), fp, prefix);
586	}
587
588	if (tb[XFRMA_ALG_CRYPT]) {
589		struct rtattr *rta = tb[XFRMA_ALG_CRYPT];
590		xfrm_algo_print((struct xfrm_algo *) RTA_DATA(rta),
591				XFRMA_ALG_CRYPT, RTA_PAYLOAD(rta), fp, prefix);
592	}
593
594	if (tb[XFRMA_ALG_COMP]) {
595		struct rtattr *rta = tb[XFRMA_ALG_COMP];
596		xfrm_algo_print((struct xfrm_algo *) RTA_DATA(rta),
597				XFRMA_ALG_COMP, RTA_PAYLOAD(rta), fp, prefix);
598	}
599
600	if (tb[XFRMA_ENCAP]) {
601		struct xfrm_encap_tmpl *e;
602		char abuf[256];
603
604		if (prefix)
605			fprintf(fp, prefix);
606		fprintf(fp, "encap ");
607
608		if (RTA_PAYLOAD(tb[XFRMA_ENCAP]) < sizeof(*e)) {
609			fprintf(fp, "(ERROR truncated)");
610			fprintf(fp, "%s", _SL_);
611			return;
612		}
613		e = (struct xfrm_encap_tmpl *) RTA_DATA(tb[XFRMA_ENCAP]);
614
615		fprintf(fp, "type ");
616		switch (e->encap_type) {
617		case 1:
618			fprintf(fp, "espinudp-nonike ");
619			break;
620		case 2:
621			fprintf(fp, "espinudp ");
622			break;
623		default:
624			fprintf(fp, "%u ", e->encap_type);
625			break;
626		}
627		fprintf(fp, "sport %u ", ntohs(e->encap_sport));
628		fprintf(fp, "dport %u ", ntohs(e->encap_dport));
629
630		memset(abuf, '\0', sizeof(abuf));
631		fprintf(fp, "addr %s",
632			rt_addr_n2a(family, sizeof(e->encap_oa),
633				    &e->encap_oa, abuf, sizeof(abuf)));
634		fprintf(fp, "%s", _SL_);
635	}
636
637	if (tb[XFRMA_TMPL]) {
638		struct rtattr *rta = tb[XFRMA_TMPL];
639		xfrm_tmpl_print((struct xfrm_user_tmpl *) RTA_DATA(rta),
640				RTA_PAYLOAD(rta), family, fp, prefix);
641	}
642}
643
644static int xfrm_selector_iszero(struct xfrm_selector *s)
645{
646	struct xfrm_selector s0;
647
648	memset(&s0, 0, sizeof(s0));
649
650	return (memcmp(&s0, s, sizeof(s0)) == 0);
651}
652
653void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo,
654			    struct rtattr *tb[], FILE *fp, const char *prefix,
655			    const char *title)
656{
657	char buf[STRBUF_SIZE];
658
659	memset(buf, '\0', sizeof(buf));
660
661	xfrm_id_info_print(&xsinfo->saddr, &xsinfo->id, xsinfo->mode,
662			   xsinfo->reqid, xsinfo->family, 1, fp, prefix,
663			   title);
664
665	if (prefix)
666		STRBUF_CAT(buf, prefix);
667	STRBUF_CAT(buf, "\t");
668
669	fprintf(fp, buf);
670	fprintf(fp, "replay-window %u ", xsinfo->replay_window);
671	if (show_stats > 0)
672		fprintf(fp, "seq 0x%08u ", xsinfo->seq);
673	if (show_stats > 0 || xsinfo->flags) {
674		__u8 flags = xsinfo->flags;
675
676		fprintf(fp, "flag ");
677		XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_NOECN, "noecn");
678		XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_DECAP_DSCP, "decap-dscp");
679		if (flags)
680			fprintf(fp, "%x", flags);
681		if (show_stats > 0)
682			fprintf(fp, " (0x%s)", strxf_mask8(flags));
683	}
684	fprintf(fp, "%s", _SL_);
685
686	xfrm_xfrma_print(tb, xsinfo->family, fp, buf);
687
688	if (!xfrm_selector_iszero(&xsinfo->sel)) {
689		char sbuf[STRBUF_SIZE];
690
691		memcpy(sbuf, buf, sizeof(sbuf));
692		STRBUF_CAT(sbuf, "sel ");
693
694		xfrm_selector_print(&xsinfo->sel, xsinfo->family, fp, sbuf);
695	}
696
697	if (show_stats > 0) {
698		xfrm_lifetime_print(&xsinfo->lft, &xsinfo->curlft, fp, buf);
699		xfrm_stats_print(&xsinfo->stats, fp, buf);
700	}
701}
702
703void xfrm_policy_info_print(struct xfrm_userpolicy_info *xpinfo,
704			    struct rtattr *tb[], FILE *fp, const char *prefix,
705			    const char *title)
706{
707	char buf[STRBUF_SIZE];
708
709	memset(buf, '\0', sizeof(buf));
710
711	xfrm_selector_print(&xpinfo->sel, preferred_family, fp, title);
712
713	if (prefix)
714		STRBUF_CAT(buf, prefix);
715	STRBUF_CAT(buf, "\t");
716
717	fprintf(fp, buf);
718	fprintf(fp, "dir ");
719	switch (xpinfo->dir) {
720	case XFRM_POLICY_IN:
721		fprintf(fp, "in");
722		break;
723	case XFRM_POLICY_OUT:
724		fprintf(fp, "out");
725		break;
726	case XFRM_POLICY_FWD:
727		fprintf(fp, "fwd");
728		break;
729	default:
730		fprintf(fp, "%u", xpinfo->dir);
731		break;
732	}
733	fprintf(fp, " ");
734
735	switch (xpinfo->action) {
736	case XFRM_POLICY_ALLOW:
737		if (show_stats > 0)
738			fprintf(fp, "action allow ");
739		break;
740	case XFRM_POLICY_BLOCK:
741		fprintf(fp, "action block ");
742		break;
743	default:
744		fprintf(fp, "action %u ", xpinfo->action);
745		break;
746	}
747
748	if (show_stats)
749		fprintf(fp, "index %u ", xpinfo->index);
750	fprintf(fp, "priority %u ", xpinfo->priority);
751	if (show_stats > 0) {
752		fprintf(fp, "share %s ", strxf_share(xpinfo->share));
753		fprintf(fp, "flag 0x%s", strxf_mask8(xpinfo->flags));
754	}
755	fprintf(fp, "%s", _SL_);
756
757	if (show_stats > 0)
758		xfrm_lifetime_print(&xpinfo->lft, &xpinfo->curlft, fp, buf);
759
760	xfrm_xfrma_print(tb, xpinfo->sel.family, fp, buf);
761}
762
763int xfrm_id_parse(xfrm_address_t *saddr, struct xfrm_id *id, __u16 *family,
764		  int loose, int *argcp, char ***argvp)
765{
766	int argc = *argcp;
767	char **argv = *argvp;
768	inet_prefix dst;
769	inet_prefix src;
770
771	memset(&dst, 0, sizeof(dst));
772	memset(&src, 0, sizeof(src));
773
774	while (1) {
775		if (strcmp(*argv, "src") == 0) {
776			NEXT_ARG();
777
778			get_prefix(&src, *argv, preferred_family);
779			if (src.family == AF_UNSPEC)
780				invarg("\"src\" address family is AF_UNSPEC", *argv);
781			if (family)
782				*family = src.family;
783
784			memcpy(saddr, &src.data, sizeof(*saddr));
785
786			filter.id_src_mask = src.bitlen;
787
788		} else if (strcmp(*argv, "dst") == 0) {
789			NEXT_ARG();
790
791			get_prefix(&dst, *argv, preferred_family);
792			if (dst.family == AF_UNSPEC)
793				invarg("\"dst\" address family is AF_UNSPEC", *argv);
794			if (family)
795				*family = dst.family;
796
797			memcpy(&id->daddr, &dst.data, sizeof(id->daddr));
798
799			filter.id_dst_mask = dst.bitlen;
800
801		} else if (strcmp(*argv, "proto") == 0) {
802			int ret;
803
804			NEXT_ARG();
805
806			ret = xfrm_xfrmproto_getbyname(*argv);
807			if (ret < 0)
808				invarg("\"XFRM_PROTO\" is invalid", *argv);
809
810			id->proto = (__u8)ret;
811
812			filter.id_proto_mask = XFRM_FILTER_MASK_FULL;
813
814		} else if (strcmp(*argv, "spi") == 0) {
815			__u32 spi;
816
817			NEXT_ARG();
818			if (get_u32(&spi, *argv, 0))
819				invarg("\"SPI\" is invalid", *argv);
820
821			spi = htonl(spi);
822			id->spi = spi;
823
824			filter.id_spi_mask = XFRM_FILTER_MASK_FULL;
825
826		} else {
827			PREV_ARG(); /* back track */
828			break;
829		}
830
831		if (!NEXT_ARG_OK())
832			break;
833		NEXT_ARG();
834	}
835
836	if (src.family && dst.family && (src.family != dst.family))
837		invarg("the same address family is required between \"src\" and \"dst\"", *argv);
838
839	if (loose == 0 && id->proto == 0)
840		missarg("XFRM_PROTO");
841	if (argc == *argcp)
842		missarg("ID");
843
844	*argcp = argc;
845	*argvp = argv;
846
847	return 0;
848}
849
850int xfrm_mode_parse(__u8 *mode, int *argcp, char ***argvp)
851{
852	int argc = *argcp;
853	char **argv = *argvp;
854
855	if (matches(*argv, "transport") == 0)
856		*mode = 0;
857	else if (matches(*argv, "tunnel") == 0)
858		*mode = 1;
859	else
860		invarg("\"MODE\" is invalid", *argv);
861
862	*argcp = argc;
863	*argvp = argv;
864
865	return 0;
866}
867
868int xfrm_encap_type_parse(__u16 *type, int *argcp, char ***argvp)
869{
870	int argc = *argcp;
871	char **argv = *argvp;
872
873	if (strcmp(*argv, "espinudp-nonike") == 0)
874		*type = 1;
875	else if (strcmp(*argv, "espinudp") == 0)
876		*type = 2;
877	else
878		invarg("\"ENCAP-TYPE\" is invalid", *argv);
879
880	*argcp = argc;
881	*argvp = argv;
882
883	return 0;
884}
885
886/* NOTE: reqid is used by host-byte order */
887int xfrm_reqid_parse(__u32 *reqid, int *argcp, char ***argvp)
888{
889	int argc = *argcp;
890	char **argv = *argvp;
891
892	if (get_u32(reqid, *argv, 0))
893		invarg("\"REQID\" is invalid", *argv);
894
895	*argcp = argc;
896	*argvp = argv;
897
898	return 0;
899}
900
901static int xfrm_selector_upspec_parse(struct xfrm_selector *sel,
902				      int *argcp, char ***argvp)
903{
904	int argc = *argcp;
905	char **argv = *argvp;
906	char *sportp = NULL;
907	char *dportp = NULL;
908	char *typep = NULL;
909	char *codep = NULL;
910
911	while (1) {
912		if (strcmp(*argv, "proto") == 0) {
913			__u8 upspec;
914
915			NEXT_ARG();
916
917			if (strcmp(*argv, "any") == 0)
918				upspec = 0;
919			else {
920				struct protoent *pp;
921				pp = getprotobyname(*argv);
922				if (pp)
923					upspec = pp->p_proto;
924				else {
925					if (get_u8(&upspec, *argv, 0))
926						invarg("\"PROTO\" is invalid", *argv);
927				}
928			}
929			sel->proto = upspec;
930
931			filter.upspec_proto_mask = XFRM_FILTER_MASK_FULL;
932
933		} else if (strcmp(*argv, "sport") == 0) {
934			sportp = *argv;
935
936			NEXT_ARG();
937
938			if (get_u16(&sel->sport, *argv, 0))
939				invarg("\"PORT\" is invalid", *argv);
940			sel->sport = htons(sel->sport);
941			if (sel->sport)
942				sel->sport_mask = ~((__u16)0);
943
944			filter.upspec_sport_mask = XFRM_FILTER_MASK_FULL;
945
946		} else if (strcmp(*argv, "dport") == 0) {
947			dportp = *argv;
948
949			NEXT_ARG();
950
951			if (get_u16(&sel->dport, *argv, 0))
952				invarg("\"PORT\" is invalid", *argv);
953			sel->dport = htons(sel->dport);
954			if (sel->dport)
955				sel->dport_mask = ~((__u16)0);
956
957			filter.upspec_dport_mask = XFRM_FILTER_MASK_FULL;
958
959		} else if (strcmp(*argv, "type") == 0) {
960			typep = *argv;
961
962			NEXT_ARG();
963
964			if (get_u16(&sel->sport, *argv, 0) ||
965			    (sel->sport & ~((__u16)0xff)))
966				invarg("\"type\" value is invalid", *argv);
967			sel->sport = htons(sel->sport);
968			sel->sport_mask = ~((__u16)0);
969
970			filter.upspec_sport_mask = XFRM_FILTER_MASK_FULL;
971
972
973		} else if (strcmp(*argv, "code") == 0) {
974			codep = *argv;
975
976			NEXT_ARG();
977
978			if (get_u16(&sel->dport, *argv, 0) ||
979			    (sel->dport & ~((__u16)0xff)))
980				invarg("\"code\" value is invalid", *argv);
981			sel->dport = htons(sel->dport);
982			sel->dport_mask = ~((__u16)0);
983
984			filter.upspec_dport_mask = XFRM_FILTER_MASK_FULL;
985
986		} else {
987			PREV_ARG(); /* back track */
988			break;
989		}
990
991		if (!NEXT_ARG_OK())
992			break;
993		NEXT_ARG();
994	}
995	if (argc == *argcp)
996		missarg("UPSPEC");
997	if (sportp || dportp) {
998		switch (sel->proto) {
999		case IPPROTO_TCP:
1000		case IPPROTO_UDP:
1001		case IPPROTO_SCTP:
1002			break;
1003		default:
1004			fprintf(stderr, "\"sport\" and \"dport\" are invalid with proto=%s\n", strxf_proto(sel->proto));
1005			exit(1);
1006		}
1007	}
1008	if (typep || codep) {
1009		switch (sel->proto) {
1010		case IPPROTO_ICMP:
1011		case IPPROTO_ICMPV6:
1012			break;
1013		default:
1014			fprintf(stderr, "\"type\" and \"code\" are invalid with proto=%s\n", strxf_proto(sel->proto));
1015			exit(1);
1016		}
1017	}
1018
1019	*argcp = argc;
1020	*argvp = argv;
1021
1022	return 0;
1023}
1024
1025int xfrm_selector_parse(struct xfrm_selector *sel, int *argcp, char ***argvp)
1026{
1027	int argc = *argcp;
1028	char **argv = *argvp;
1029	inet_prefix dst;
1030	inet_prefix src;
1031	char *upspecp = NULL;
1032
1033	memset(&dst, 0, sizeof(dst));
1034	memset(&src, 0, sizeof(src));
1035
1036	while (1) {
1037		if (strcmp(*argv, "src") == 0) {
1038			NEXT_ARG();
1039
1040			get_prefix(&src, *argv, preferred_family);
1041			if (src.family == AF_UNSPEC)
1042				invarg("\"src\" address family is AF_UNSPEC", *argv);
1043			sel->family = src.family;
1044
1045			memcpy(&sel->saddr, &src.data, sizeof(sel->saddr));
1046			sel->prefixlen_s = src.bitlen;
1047
1048			filter.sel_src_mask = src.bitlen;
1049
1050		} else if (strcmp(*argv, "dst") == 0) {
1051			NEXT_ARG();
1052
1053			get_prefix(&dst, *argv, preferred_family);
1054			if (dst.family == AF_UNSPEC)
1055				invarg("\"dst\" address family is AF_UNSPEC", *argv);
1056			sel->family = dst.family;
1057
1058			memcpy(&sel->daddr, &dst.data, sizeof(sel->daddr));
1059			sel->prefixlen_d = dst.bitlen;
1060
1061			filter.sel_dst_mask = dst.bitlen;
1062
1063		} else if (strcmp(*argv, "dev") == 0) {
1064			int ifindex;
1065
1066			NEXT_ARG();
1067
1068			if (strcmp(*argv, "none") == 0)
1069				ifindex = 0;
1070			else {
1071				ifindex = if_nametoindex(*argv);
1072				if (ifindex <= 0)
1073					invarg("\"DEV\" is invalid", *argv);
1074			}
1075			sel->ifindex = ifindex;
1076
1077			filter.sel_dev_mask = XFRM_FILTER_MASK_FULL;
1078
1079		} else {
1080			if (upspecp) {
1081				PREV_ARG(); /* back track */
1082				break;
1083			} else {
1084				upspecp = *argv;
1085				xfrm_selector_upspec_parse(sel, &argc, &argv);
1086			}
1087		}
1088
1089		if (!NEXT_ARG_OK())
1090			break;
1091
1092		NEXT_ARG();
1093	}
1094
1095	if (src.family && dst.family && (src.family != dst.family))
1096		invarg("the same address family is required between \"src\" and \"dst\"", *argv);
1097
1098	if (argc == *argcp)
1099		missarg("SELECTOR");
1100
1101	*argcp = argc;
1102	*argvp = argv;
1103
1104	return 0;
1105}
1106
1107int xfrm_lifetime_cfg_parse(struct xfrm_lifetime_cfg *lft,
1108			    int *argcp, char ***argvp)
1109{
1110	int argc = *argcp;
1111	char **argv = *argvp;
1112	int ret;
1113
1114	if (strcmp(*argv, "time-soft") == 0) {
1115		NEXT_ARG();
1116		ret = get_u64(&lft->soft_add_expires_seconds, *argv, 0);
1117		if (ret)
1118			invarg("\"time-soft\" value is invalid", *argv);
1119	} else if (strcmp(*argv, "time-hard") == 0) {
1120		NEXT_ARG();
1121		ret = get_u64(&lft->hard_add_expires_seconds, *argv, 0);
1122		if (ret)
1123			invarg("\"time-hard\" value is invalid", *argv);
1124	} else if (strcmp(*argv, "time-use-soft") == 0) {
1125		NEXT_ARG();
1126		ret = get_u64(&lft->soft_use_expires_seconds, *argv, 0);
1127		if (ret)
1128			invarg("\"time-use-soft\" value is invalid", *argv);
1129	} else if (strcmp(*argv, "time-use-hard") == 0) {
1130		NEXT_ARG();
1131		ret = get_u64(&lft->hard_use_expires_seconds, *argv, 0);
1132		if (ret)
1133			invarg("\"time-use-hard\" value is invalid", *argv);
1134	} else if (strcmp(*argv, "byte-soft") == 0) {
1135		NEXT_ARG();
1136		ret = get_u64(&lft->soft_byte_limit, *argv, 0);
1137		if (ret)
1138			invarg("\"byte-soft\" value is invalid", *argv);
1139	} else if (strcmp(*argv, "byte-hard") == 0) {
1140		NEXT_ARG();
1141		ret = get_u64(&lft->hard_byte_limit, *argv, 0);
1142		if (ret)
1143			invarg("\"byte-hard\" value is invalid", *argv);
1144	} else if (strcmp(*argv, "packet-soft") == 0) {
1145		NEXT_ARG();
1146		ret = get_u64(&lft->soft_packet_limit, *argv, 0);
1147		if (ret)
1148			invarg("\"packet-soft\" value is invalid", *argv);
1149	} else if (strcmp(*argv, "packet-hard") == 0) {
1150		NEXT_ARG();
1151		ret = get_u64(&lft->hard_packet_limit, *argv, 0);
1152		if (ret)
1153			invarg("\"packet-hard\" value is invalid", *argv);
1154	} else
1155		invarg("\"LIMIT\" is invalid", *argv);
1156
1157	*argcp = argc;
1158	*argvp = argv;
1159
1160	return 0;
1161}
1162
1163int do_xfrm(int argc, char **argv)
1164{
1165	memset(&filter, 0, sizeof(filter));
1166
1167	if (argc < 1)
1168		usage();
1169
1170	if (matches(*argv, "state") == 0 ||
1171	    matches(*argv, "sa") == 0)
1172		return do_xfrm_state(argc-1, argv+1);
1173	else if (matches(*argv, "policy") == 0)
1174		return do_xfrm_policy(argc-1, argv+1);
1175	else if (matches(*argv, "monitor") == 0)
1176		return do_xfrm_monitor(argc-1, argv+1);
1177	else if (matches(*argv, "help") == 0) {
1178		usage();
1179		fprintf(stderr, "xfrm Object \"%s\" is unknown.\n", *argv);
1180		exit(-1);
1181	}
1182	usage();
1183}
1184