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