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 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 <netdb.h>
32#include <linux/netlink.h>
33#include <linux/xfrm.h>
34#include "utils.h"
35#include "xfrm.h"
36#include "ip_common.h"
37
38//#define NLMSG_DELETEALL_BUF_SIZE (4096-512)
39#define NLMSG_DELETEALL_BUF_SIZE 8192
40
41/*
42 * Receiving buffer defines:
43 * nlmsg
44 *   data = struct xfrm_userpolicy_info
45 *   rtattr
46 *     data = struct xfrm_user_tmpl[]
47 */
48#define NLMSG_BUF_SIZE 4096
49#define RTA_BUF_SIZE 2048
50#define XFRM_TMPLS_BUF_SIZE 1024
51#define CTX_BUF_SIZE 256
52
53static void usage(void) __attribute__((noreturn));
54
55static void usage(void)
56{
57	fprintf(stderr, "Usage: ip xfrm policy { add | update } SELECTOR dir DIR [ ctx CTX ]\n");
58	fprintf(stderr, "        [ mark MARK [ mask MASK ] ] [ index INDEX ] [ ptype PTYPE ]\n");
59	fprintf(stderr, "        [ action ACTION ] [ priority PRIORITY ] [ flag FLAG-LIST ]\n");
60	fprintf(stderr, "        [ LIMIT-LIST ] [ TMPL-LIST ]\n");
61	fprintf(stderr, "Usage: ip xfrm policy { delete | get } { SELECTOR | index INDEX } dir DIR\n");
62	fprintf(stderr, "        [ ctx CTX ] [ mark MARK [ mask MASK ] ] [ ptype PTYPE ]\n");
63	fprintf(stderr, "Usage: ip xfrm policy { deleteall | list } [ SELECTOR ] [ dir DIR ]\n");
64	fprintf(stderr, "        [ index INDEX ] [ ptype PTYPE ] [ action ACTION ] [ priority PRIORITY ]\n");
65	fprintf(stderr, "        [ flag FLAG-LIST ]\n");
66	fprintf(stderr, "Usage: ip xfrm policy flush [ ptype PTYPE ]\n");
67	fprintf(stderr, "Usage: ip xfrm count\n");
68	fprintf(stderr, "SELECTOR := [ src ADDR[/PLEN] ] [ dst ADDR[/PLEN] ] [ dev DEV ] [ UPSPEC ]\n");
69	fprintf(stderr, "UPSPEC := proto { { ");
70	fprintf(stderr, "%s | ", strxf_proto(IPPROTO_TCP));
71	fprintf(stderr, "%s | ", strxf_proto(IPPROTO_UDP));
72	fprintf(stderr, "%s | ", strxf_proto(IPPROTO_SCTP));
73	fprintf(stderr, "%s", strxf_proto(IPPROTO_DCCP));
74	fprintf(stderr, " } [ sport PORT ] [ dport PORT ] |\n");
75	fprintf(stderr, "                  { ");
76	fprintf(stderr, "%s | ", strxf_proto(IPPROTO_ICMP));
77	fprintf(stderr, "%s | ", strxf_proto(IPPROTO_ICMPV6));
78	fprintf(stderr, "%s", strxf_proto(IPPROTO_MH));
79	fprintf(stderr, " } [ type NUMBER ] [ code NUMBER ] |\n");
80	fprintf(stderr, "                  %s", strxf_proto(IPPROTO_GRE));
81	fprintf(stderr, " [ key { DOTTED-QUAD | NUMBER } ] | PROTO }\n");
82	fprintf(stderr, "DIR := in | out | fwd\n");
83	fprintf(stderr, "PTYPE := main | sub\n");
84	fprintf(stderr, "ACTION := allow | block\n");
85	fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n");
86	fprintf(stderr, "FLAG := localok | icmp\n");
87	fprintf(stderr, "LIMIT-LIST := [ LIMIT-LIST ] limit LIMIT\n");
88	fprintf(stderr, "LIMIT := { time-soft | time-hard | time-use-soft | time-use-hard } SECONDS |\n");
89	fprintf(stderr, "         { byte-soft | byte-hard } SIZE | { packet-soft | packet-hard } COUNT\n");
90	fprintf(stderr, "TMPL-LIST := [ TMPL-LIST ] tmpl TMPL\n");
91	fprintf(stderr, "TMPL := ID [ mode MODE ] [ reqid REQID ] [ level LEVEL ]\n");
92	fprintf(stderr, "ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM-PROTO ] [ spi SPI ]\n");
93	fprintf(stderr, "XFRM-PROTO := ");
94	fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ESP));
95	fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_AH));
96	fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_COMP));
97	fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ROUTING));
98	fprintf(stderr, "%s\n", strxf_xfrmproto(IPPROTO_DSTOPTS));
99 	fprintf(stderr, "MODE := transport | tunnel | ro | in_trigger | beet\n");
100	fprintf(stderr, "LEVEL := required | use\n");
101
102	exit(-1);
103}
104
105static int xfrm_policy_dir_parse(__u8 *dir, int *argcp, char ***argvp)
106{
107	int argc = *argcp;
108	char **argv = *argvp;
109
110	if (strcmp(*argv, "in") == 0)
111		*dir = XFRM_POLICY_IN;
112	else if (strcmp(*argv, "out") == 0)
113		*dir = XFRM_POLICY_OUT;
114	else if (strcmp(*argv, "fwd") == 0)
115		*dir = XFRM_POLICY_FWD;
116	else
117		invarg("\"DIR\" is invalid", *argv);
118
119	*argcp = argc;
120	*argvp = argv;
121
122	return 0;
123}
124
125static int xfrm_policy_ptype_parse(__u8 *ptype, int *argcp, char ***argvp)
126{
127	int argc = *argcp;
128	char **argv = *argvp;
129
130	if (strcmp(*argv, "main") == 0)
131		*ptype = XFRM_POLICY_TYPE_MAIN;
132	else if (strcmp(*argv, "sub") == 0)
133		*ptype = XFRM_POLICY_TYPE_SUB;
134	else
135		invarg("\"PTYPE\" is invalid", *argv);
136
137	*argcp = argc;
138	*argvp = argv;
139
140	return 0;
141}
142
143static int xfrm_policy_flag_parse(__u8 *flags, int *argcp, char ***argvp)
144{
145	int argc = *argcp;
146	char **argv = *argvp;
147	int len = strlen(*argv);
148
149	if (len > 2 && strncmp(*argv, "0x", 2) == 0) {
150		__u8 val = 0;
151
152		if (get_u8(&val, *argv, 16))
153			invarg("\"FLAG\" is invalid", *argv);
154		*flags = val;
155	} else {
156		while (1) {
157			if (strcmp(*argv, "localok") == 0)
158				*flags |= XFRM_POLICY_LOCALOK;
159			else if (strcmp(*argv, "icmp") == 0)
160				*flags |= XFRM_POLICY_ICMP;
161			else {
162				PREV_ARG(); /* back track */
163				break;
164			}
165
166			if (!NEXT_ARG_OK())
167				break;
168			NEXT_ARG();
169		}
170	}
171
172	*argcp = argc;
173	*argvp = argv;
174
175	return 0;
176}
177
178static int xfrm_tmpl_parse(struct xfrm_user_tmpl *tmpl,
179			   int *argcp, char ***argvp)
180{
181	int argc = *argcp;
182	char **argv = *argvp;
183	char *idp = NULL;
184
185	while (1) {
186		if (strcmp(*argv, "mode") == 0) {
187			NEXT_ARG();
188			xfrm_mode_parse(&tmpl->mode,  &argc, &argv);
189		} else if (strcmp(*argv, "reqid") == 0) {
190			NEXT_ARG();
191			xfrm_reqid_parse(&tmpl->reqid, &argc, &argv);
192		} else if (strcmp(*argv, "level") == 0) {
193			NEXT_ARG();
194
195			if (strcmp(*argv, "required") == 0)
196				tmpl->optional = 0;
197			else if (strcmp(*argv, "use") == 0)
198				tmpl->optional = 1;
199			else
200				invarg("\"LEVEL\" is invalid\n", *argv);
201
202		} else {
203			if (idp) {
204				PREV_ARG(); /* back track */
205				break;
206			}
207			idp = *argv;
208			preferred_family = AF_UNSPEC;
209			xfrm_id_parse(&tmpl->saddr, &tmpl->id, &tmpl->family,
210				      0, &argc, &argv);
211			preferred_family = tmpl->family;
212		}
213
214		if (!NEXT_ARG_OK())
215			break;
216
217		NEXT_ARG();
218	}
219	if (argc == *argcp)
220		missarg("TMPL");
221
222	*argcp = argc;
223	*argvp = argv;
224
225	return 0;
226}
227
228int xfrm_sctx_parse(char *ctxstr, char *s,
229			   struct xfrm_user_sec_ctx *sctx)
230{
231	int slen;
232
233	slen = strlen(s) + 1;
234
235	sctx->exttype = XFRMA_SEC_CTX;
236	sctx->ctx_doi = 1;
237	sctx->ctx_alg = 1;
238	sctx->ctx_len = slen;
239	sctx->len = sizeof(struct xfrm_user_sec_ctx) + slen;
240	memcpy(ctxstr, s, slen);
241
242	return 0;
243}
244
245static int xfrm_policy_modify(int cmd, unsigned flags, int argc, char **argv)
246{
247	struct rtnl_handle rth;
248	struct {
249		struct nlmsghdr			n;
250		struct xfrm_userpolicy_info	xpinfo;
251		char				buf[RTA_BUF_SIZE];
252	} req;
253	char *dirp = NULL;
254	char *selp = NULL;
255	char *ptypep = NULL;
256	char *sctxp = NULL;
257	struct xfrm_userpolicy_type upt;
258	char tmpls_buf[XFRM_TMPLS_BUF_SIZE];
259	int tmpls_len = 0;
260	struct xfrm_mark mark = {0, 0};
261	struct {
262		struct xfrm_user_sec_ctx sctx;
263		char	str[CTX_BUF_SIZE];
264	} ctx;
265
266	memset(&req, 0, sizeof(req));
267	memset(&upt, 0, sizeof(upt));
268	memset(&tmpls_buf, 0, sizeof(tmpls_buf));
269	memset(&ctx, 0, sizeof(ctx));
270
271	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpinfo));
272	req.n.nlmsg_flags = NLM_F_REQUEST|flags;
273	req.n.nlmsg_type = cmd;
274	req.xpinfo.sel.family = preferred_family;
275
276	req.xpinfo.lft.soft_byte_limit = XFRM_INF;
277	req.xpinfo.lft.hard_byte_limit = XFRM_INF;
278	req.xpinfo.lft.soft_packet_limit = XFRM_INF;
279	req.xpinfo.lft.hard_packet_limit = XFRM_INF;
280
281	while (argc > 0) {
282		if (strcmp(*argv, "dir") == 0) {
283			if (dirp)
284				duparg("dir", *argv);
285			dirp = *argv;
286
287			NEXT_ARG();
288			xfrm_policy_dir_parse(&req.xpinfo.dir, &argc, &argv);
289		} else if (strcmp(*argv, "ctx") == 0) {
290			char *context;
291
292			if (sctxp)
293				duparg("ctx", *argv);
294			sctxp = *argv;
295			NEXT_ARG();
296			context = *argv;
297			xfrm_sctx_parse((char *)&ctx.str, context, &ctx.sctx);
298		} else if (strcmp(*argv, "mark") == 0) {
299			xfrm_parse_mark(&mark, &argc, &argv);
300		} else if (strcmp(*argv, "index") == 0) {
301			NEXT_ARG();
302			if (get_u32(&req.xpinfo.index, *argv, 0))
303				invarg("\"INDEX\" is invalid", *argv);
304		} else if (strcmp(*argv, "ptype") == 0) {
305			if (ptypep)
306				duparg("ptype", *argv);
307			ptypep = *argv;
308
309			NEXT_ARG();
310			xfrm_policy_ptype_parse(&upt.type, &argc, &argv);
311		} else if (strcmp(*argv, "action") == 0) {
312			NEXT_ARG();
313			if (strcmp(*argv, "allow") == 0)
314				req.xpinfo.action = XFRM_POLICY_ALLOW;
315			else if (strcmp(*argv, "block") == 0)
316				req.xpinfo.action = XFRM_POLICY_BLOCK;
317			else
318				invarg("\"action\" value is invalid\n", *argv);
319		} else if (strcmp(*argv, "priority") == 0) {
320			NEXT_ARG();
321			if (get_u32(&req.xpinfo.priority, *argv, 0))
322				invarg("\"PRIORITY\" is invalid", *argv);
323		} else if (strcmp(*argv, "flag") == 0) {
324			NEXT_ARG();
325			xfrm_policy_flag_parse(&req.xpinfo.flags, &argc,
326					       &argv);
327		} else if (strcmp(*argv, "limit") == 0) {
328			NEXT_ARG();
329			xfrm_lifetime_cfg_parse(&req.xpinfo.lft, &argc, &argv);
330		} else if (strcmp(*argv, "tmpl") == 0) {
331			struct xfrm_user_tmpl *tmpl;
332
333			if (tmpls_len + sizeof(*tmpl) > sizeof(tmpls_buf)) {
334				fprintf(stderr, "Too many tmpls: buffer overflow\n");
335				exit(1);
336			}
337			tmpl = (struct xfrm_user_tmpl *)((char *)tmpls_buf + tmpls_len);
338
339			tmpl->family = preferred_family;
340			tmpl->aalgos = (~(__u32)0);
341			tmpl->ealgos = (~(__u32)0);
342			tmpl->calgos = (~(__u32)0);
343
344			NEXT_ARG();
345			xfrm_tmpl_parse(tmpl, &argc, &argv);
346
347			tmpls_len += sizeof(*tmpl);
348		} else {
349			if (selp)
350				duparg("unknown", *argv);
351			selp = *argv;
352
353			xfrm_selector_parse(&req.xpinfo.sel, &argc, &argv);
354			if (preferred_family == AF_UNSPEC)
355				preferred_family = req.xpinfo.sel.family;
356		}
357
358		argc--; argv++;
359	}
360
361	if (!dirp) {
362		fprintf(stderr, "Not enough information: \"DIR\" is required.\n");
363		exit(1);
364	}
365
366	if (ptypep) {
367		addattr_l(&req.n, sizeof(req), XFRMA_POLICY_TYPE,
368			  (void *)&upt, sizeof(upt));
369	}
370
371	if (tmpls_len > 0) {
372		addattr_l(&req.n, sizeof(req), XFRMA_TMPL,
373			  (void *)tmpls_buf, tmpls_len);
374	}
375
376	if (mark.m & mark.v) {
377		int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK,
378				  (void *)&mark, sizeof(mark));
379		if (r < 0) {
380			fprintf(stderr, "%s: XFRMA_MARK failed\n",__func__);
381			exit(1);
382		}
383	}
384
385	if (sctxp) {
386		addattr_l(&req.n, sizeof(req), XFRMA_SEC_CTX,
387			  (void *)&ctx, ctx.sctx.len);
388	}
389
390	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
391		exit(1);
392
393	if (req.xpinfo.sel.family == AF_UNSPEC)
394		req.xpinfo.sel.family = AF_INET;
395
396	if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
397		exit(2);
398
399	rtnl_close(&rth);
400
401	return 0;
402}
403
404static int xfrm_policy_filter_match(struct xfrm_userpolicy_info *xpinfo,
405				    __u8 ptype)
406{
407	if (!filter.use)
408		return 1;
409
410	if ((xpinfo->dir^filter.xpinfo.dir)&filter.dir_mask)
411		return 0;
412
413	if ((ptype^filter.ptype)&filter.ptype_mask)
414		return 0;
415
416	if (filter.sel_src_mask) {
417		if (xfrm_addr_match(&xpinfo->sel.saddr, &filter.xpinfo.sel.saddr,
418				    filter.sel_src_mask))
419			return 0;
420	}
421
422	if (filter.sel_dst_mask) {
423		if (xfrm_addr_match(&xpinfo->sel.daddr, &filter.xpinfo.sel.daddr,
424				    filter.sel_dst_mask))
425			return 0;
426	}
427
428	if ((xpinfo->sel.ifindex^filter.xpinfo.sel.ifindex)&filter.sel_dev_mask)
429		return 0;
430
431	if ((xpinfo->sel.proto^filter.xpinfo.sel.proto)&filter.upspec_proto_mask)
432		return 0;
433
434	if (filter.upspec_sport_mask) {
435		if ((xpinfo->sel.sport^filter.xpinfo.sel.sport)&filter.upspec_sport_mask)
436			return 0;
437	}
438
439	if (filter.upspec_dport_mask) {
440		if ((xpinfo->sel.dport^filter.xpinfo.sel.dport)&filter.upspec_dport_mask)
441			return 0;
442	}
443
444	if ((xpinfo->index^filter.xpinfo.index)&filter.index_mask)
445		return 0;
446
447	if ((xpinfo->action^filter.xpinfo.action)&filter.action_mask)
448		return 0;
449
450	if ((xpinfo->priority^filter.xpinfo.priority)&filter.priority_mask)
451		return 0;
452
453	if (filter.policy_flags_mask)
454		if ((xpinfo->flags & filter.xpinfo.flags) == 0)
455			return 0;
456
457	return 1;
458}
459
460int xfrm_policy_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
461		      void *arg)
462{
463	struct rtattr * tb[XFRMA_MAX+1];
464	struct rtattr * rta;
465	struct xfrm_userpolicy_info *xpinfo = NULL;
466	struct xfrm_user_polexpire *xpexp = NULL;
467	struct xfrm_userpolicy_id *xpid = NULL;
468	__u8 ptype = XFRM_POLICY_TYPE_MAIN;
469	FILE *fp = (FILE*)arg;
470	int len = n->nlmsg_len;
471
472	if (n->nlmsg_type != XFRM_MSG_NEWPOLICY &&
473	    n->nlmsg_type != XFRM_MSG_DELPOLICY &&
474	    n->nlmsg_type != XFRM_MSG_UPDPOLICY &&
475	    n->nlmsg_type != XFRM_MSG_POLEXPIRE) {
476		fprintf(stderr, "Not a policy: %08x %08x %08x\n",
477			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
478		return 0;
479	}
480
481	if (n->nlmsg_type == XFRM_MSG_DELPOLICY)  {
482		xpid = NLMSG_DATA(n);
483		len -= NLMSG_SPACE(sizeof(*xpid));
484	} else if (n->nlmsg_type == XFRM_MSG_POLEXPIRE) {
485		xpexp = NLMSG_DATA(n);
486		xpinfo = &xpexp->pol;
487		len -= NLMSG_SPACE(sizeof(*xpexp));
488	} else {
489		xpexp = NULL;
490		xpinfo = NLMSG_DATA(n);
491		len -= NLMSG_SPACE(sizeof(*xpinfo));
492	}
493
494	if (len < 0) {
495		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
496		return -1;
497	}
498
499	if (n->nlmsg_type == XFRM_MSG_DELPOLICY)
500		rta = XFRMPID_RTA(xpid);
501	else if (n->nlmsg_type == XFRM_MSG_POLEXPIRE)
502		rta = XFRMPEXP_RTA(xpexp);
503	else
504		rta = XFRMP_RTA(xpinfo);
505
506	parse_rtattr(tb, XFRMA_MAX, rta, len);
507
508	if (tb[XFRMA_POLICY_TYPE]) {
509		struct xfrm_userpolicy_type *upt;
510
511		if (RTA_PAYLOAD(tb[XFRMA_POLICY_TYPE]) < sizeof(*upt)) {
512			fprintf(stderr, "too short XFRMA_POLICY_TYPE len\n");
513			return -1;
514		}
515		upt = (struct xfrm_userpolicy_type *)RTA_DATA(tb[XFRMA_POLICY_TYPE]);
516		ptype = upt->type;
517	}
518
519	if (xpinfo && !xfrm_policy_filter_match(xpinfo, ptype))
520		return 0;
521
522	if (n->nlmsg_type == XFRM_MSG_DELPOLICY)
523		fprintf(fp, "Deleted ");
524	else if (n->nlmsg_type == XFRM_MSG_UPDPOLICY)
525		fprintf(fp, "Updated ");
526	else if (n->nlmsg_type == XFRM_MSG_POLEXPIRE)
527		fprintf(fp, "Expired ");
528
529	if (n->nlmsg_type == XFRM_MSG_DELPOLICY) {
530		//xfrm_policy_id_print();
531		if (!tb[XFRMA_POLICY]) {
532			fprintf(stderr, "Buggy XFRM_MSG_DELPOLICY: no XFRMA_POLICY\n");
533			return -1;
534		}
535		if (RTA_PAYLOAD(tb[XFRMA_POLICY]) < sizeof(*xpinfo)) {
536			fprintf(stderr, "Buggy XFRM_MSG_DELPOLICY: too short XFRMA_POLICY len\n");
537			return -1;
538		}
539		xpinfo = (struct xfrm_userpolicy_info *)RTA_DATA(tb[XFRMA_POLICY]);
540	}
541
542	xfrm_policy_info_print(xpinfo, tb, fp, NULL, NULL);
543
544	if (n->nlmsg_type == XFRM_MSG_POLEXPIRE) {
545		fprintf(fp, "\t");
546		fprintf(fp, "hard %u", xpexp->hard);
547		fprintf(fp, "%s", _SL_);
548	}
549
550	if (oneline)
551		fprintf(fp, "\n");
552	fflush(fp);
553
554	return 0;
555}
556
557static int xfrm_policy_get_or_delete(int argc, char **argv, int delete,
558				     void *res_nlbuf)
559{
560	struct rtnl_handle rth;
561	struct {
562		struct nlmsghdr			n;
563		struct xfrm_userpolicy_id	xpid;
564		char				buf[RTA_BUF_SIZE];
565	} req;
566	char *dirp = NULL;
567	char *selp = NULL;
568	char *indexp = NULL;
569	char *ptypep = NULL;
570	char *sctxp = NULL;
571	struct xfrm_userpolicy_type upt;
572	struct xfrm_mark mark = {0, 0};
573	struct {
574		struct xfrm_user_sec_ctx sctx;
575		char    str[CTX_BUF_SIZE];
576	} ctx;
577
578
579	memset(&req, 0, sizeof(req));
580	memset(&upt, 0, sizeof(upt));
581	memset(&ctx, 0, sizeof(ctx));
582
583	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpid));
584	req.n.nlmsg_flags = NLM_F_REQUEST;
585	req.n.nlmsg_type = delete ? XFRM_MSG_DELPOLICY : XFRM_MSG_GETPOLICY;
586
587	while (argc > 0) {
588		if (strcmp(*argv, "dir") == 0) {
589			if (dirp)
590				duparg("dir", *argv);
591			dirp = *argv;
592
593			NEXT_ARG();
594			xfrm_policy_dir_parse(&req.xpid.dir, &argc, &argv);
595
596		} else if (strcmp(*argv, "ctx") == 0) {
597			char *context;
598
599			if (sctxp)
600				duparg("ctx", *argv);
601			sctxp = *argv;
602			NEXT_ARG();
603			context = *argv;
604			xfrm_sctx_parse((char *)&ctx.str, context, &ctx.sctx);
605		} else if (strcmp(*argv, "mark") == 0) {
606			xfrm_parse_mark(&mark, &argc, &argv);
607		} else if (strcmp(*argv, "index") == 0) {
608			if (indexp)
609				duparg("index", *argv);
610			indexp = *argv;
611
612			NEXT_ARG();
613			if (get_u32(&req.xpid.index, *argv, 0))
614				invarg("\"INDEX\" is invalid", *argv);
615
616		} else if (strcmp(*argv, "ptype") == 0) {
617			if (ptypep)
618				duparg("ptype", *argv);
619			ptypep = *argv;
620
621			NEXT_ARG();
622			xfrm_policy_ptype_parse(&upt.type, &argc, &argv);
623
624		} else {
625			if (selp)
626				invarg("unknown", *argv);
627			selp = *argv;
628
629			xfrm_selector_parse(&req.xpid.sel, &argc, &argv);
630			if (preferred_family == AF_UNSPEC)
631				preferred_family = req.xpid.sel.family;
632
633		}
634
635		argc--; argv++;
636	}
637
638	if (!dirp) {
639		fprintf(stderr, "Not enough information: \"DIR\" is required.\n");
640		exit(1);
641	}
642	if (ptypep) {
643		addattr_l(&req.n, sizeof(req), XFRMA_POLICY_TYPE,
644			  (void *)&upt, sizeof(upt));
645	}
646	if (!selp && !indexp) {
647		fprintf(stderr, "Not enough information: either \"SELECTOR\" or \"INDEX\" is required.\n");
648		exit(1);
649	}
650	if (selp && indexp)
651		duparg2("SELECTOR", "INDEX");
652
653	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
654		exit(1);
655
656	if (req.xpid.sel.family == AF_UNSPEC)
657		req.xpid.sel.family = AF_INET;
658
659	if (mark.m & mark.v) {
660		int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK,
661				  (void *)&mark, sizeof(mark));
662		if (r < 0) {
663			fprintf(stderr, "%s: XFRMA_MARK failed\n",__func__);
664			exit(1);
665		}
666	}
667
668	if (sctxp) {
669		addattr_l(&req.n, sizeof(req), XFRMA_SEC_CTX,
670			  (void *)&ctx, ctx.sctx.len);
671	}
672
673	if (rtnl_talk(&rth, &req.n, 0, 0, res_nlbuf, NULL, NULL) < 0)
674		exit(2);
675
676	rtnl_close(&rth);
677
678	return 0;
679}
680
681static int xfrm_policy_delete(int argc, char **argv)
682{
683	return xfrm_policy_get_or_delete(argc, argv, 1, NULL);
684}
685
686static int xfrm_policy_get(int argc, char **argv)
687{
688	char buf[NLMSG_BUF_SIZE];
689	struct nlmsghdr *n = (struct nlmsghdr *)buf;
690
691	memset(buf, 0, sizeof(buf));
692
693	xfrm_policy_get_or_delete(argc, argv, 0, n);
694
695	if (xfrm_policy_print(NULL, n, (void*)stdout) < 0) {
696		fprintf(stderr, "An error :-)\n");
697		exit(1);
698	}
699
700	return 0;
701}
702
703/*
704 * With an existing policy of nlmsg, make new nlmsg for deleting the policy
705 * and store it to buffer.
706 */
707static int xfrm_policy_keep(const struct sockaddr_nl *who,
708			    struct nlmsghdr *n,
709			    void *arg)
710{
711	struct xfrm_buffer *xb = (struct xfrm_buffer *)arg;
712	struct rtnl_handle *rth = xb->rth;
713	struct xfrm_userpolicy_info *xpinfo = NLMSG_DATA(n);
714	int len = n->nlmsg_len;
715	struct rtattr *tb[XFRMA_MAX+1];
716	__u8 ptype = XFRM_POLICY_TYPE_MAIN;
717	struct nlmsghdr *new_n;
718	struct xfrm_userpolicy_id *xpid;
719
720	if (n->nlmsg_type != XFRM_MSG_NEWPOLICY) {
721		fprintf(stderr, "Not a policy: %08x %08x %08x\n",
722			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
723		return 0;
724	}
725
726	len -= NLMSG_LENGTH(sizeof(*xpinfo));
727	if (len < 0) {
728		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
729		return -1;
730	}
731
732	parse_rtattr(tb, XFRMA_MAX, XFRMP_RTA(xpinfo), len);
733
734	if (tb[XFRMA_POLICY_TYPE]) {
735		struct xfrm_userpolicy_type *upt;
736
737		if (RTA_PAYLOAD(tb[XFRMA_POLICY_TYPE]) < sizeof(*upt)) {
738			fprintf(stderr, "too short XFRMA_POLICY_TYPE len\n");
739			return -1;
740		}
741		upt = (struct xfrm_userpolicy_type *)RTA_DATA(tb[XFRMA_POLICY_TYPE]);
742		ptype = upt->type;
743	}
744
745	if (!xfrm_policy_filter_match(xpinfo, ptype))
746		return 0;
747
748	if (xb->offset > xb->size) {
749		fprintf(stderr, "Policy buffer overflow\n");
750		return -1;
751	}
752
753	new_n = (struct nlmsghdr *)(xb->buf + xb->offset);
754	new_n->nlmsg_len = NLMSG_LENGTH(sizeof(*xpid));
755	new_n->nlmsg_flags = NLM_F_REQUEST;
756	new_n->nlmsg_type = XFRM_MSG_DELPOLICY;
757	new_n->nlmsg_seq = ++rth->seq;
758
759	xpid = NLMSG_DATA(new_n);
760	memcpy(&xpid->sel, &xpinfo->sel, sizeof(xpid->sel));
761	xpid->dir = xpinfo->dir;
762	xpid->index = xpinfo->index;
763
764	xb->offset += new_n->nlmsg_len;
765	xb->nlmsg_count ++;
766
767	return 0;
768}
769
770static int xfrm_policy_list_or_deleteall(int argc, char **argv, int deleteall)
771{
772	char *selp = NULL;
773	struct rtnl_handle rth;
774
775	if (argc > 0)
776		filter.use = 1;
777	filter.xpinfo.sel.family = preferred_family;
778
779	while (argc > 0) {
780		if (strcmp(*argv, "dir") == 0) {
781			NEXT_ARG();
782			xfrm_policy_dir_parse(&filter.xpinfo.dir, &argc, &argv);
783
784			filter.dir_mask = XFRM_FILTER_MASK_FULL;
785
786		} else if (strcmp(*argv, "index") == 0) {
787			NEXT_ARG();
788			if (get_u32(&filter.xpinfo.index, *argv, 0))
789				invarg("\"INDEX\" is invalid", *argv);
790
791			filter.index_mask = XFRM_FILTER_MASK_FULL;
792
793		} else if (strcmp(*argv, "ptype") == 0) {
794			NEXT_ARG();
795			xfrm_policy_ptype_parse(&filter.ptype, &argc, &argv);
796
797			filter.ptype_mask = XFRM_FILTER_MASK_FULL;
798
799		} else if (strcmp(*argv, "action") == 0) {
800			NEXT_ARG();
801			if (strcmp(*argv, "allow") == 0)
802				filter.xpinfo.action = XFRM_POLICY_ALLOW;
803			else if (strcmp(*argv, "block") == 0)
804				filter.xpinfo.action = XFRM_POLICY_BLOCK;
805			else
806				invarg("\"ACTION\" is invalid\n", *argv);
807
808			filter.action_mask = XFRM_FILTER_MASK_FULL;
809
810		} else if (strcmp(*argv, "priority") == 0) {
811			NEXT_ARG();
812			if (get_u32(&filter.xpinfo.priority, *argv, 0))
813				invarg("\"PRIORITY\" is invalid", *argv);
814
815			filter.priority_mask = XFRM_FILTER_MASK_FULL;
816
817		} else if (strcmp(*argv, "flag") == 0) {
818			NEXT_ARG();
819			xfrm_policy_flag_parse(&filter.xpinfo.flags, &argc,
820					       &argv);
821
822			filter.policy_flags_mask = XFRM_FILTER_MASK_FULL;
823
824		} else {
825			if (selp)
826				invarg("unknown", *argv);
827			selp = *argv;
828
829			xfrm_selector_parse(&filter.xpinfo.sel, &argc, &argv);
830			if (preferred_family == AF_UNSPEC)
831				preferred_family = filter.xpinfo.sel.family;
832
833		}
834
835		argc--; argv++;
836	}
837
838	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
839		exit(1);
840
841	if (deleteall) {
842		struct xfrm_buffer xb;
843		char buf[NLMSG_DELETEALL_BUF_SIZE];
844		int i;
845
846		xb.buf = buf;
847		xb.size = sizeof(buf);
848		xb.rth = &rth;
849
850		for (i = 0; ; i++) {
851			xb.offset = 0;
852			xb.nlmsg_count = 0;
853
854			if (show_stats > 1)
855				fprintf(stderr, "Delete-all round = %d\n", i);
856
857			if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETPOLICY) < 0) {
858				perror("Cannot send dump request");
859				exit(1);
860			}
861
862			if (rtnl_dump_filter(&rth, xfrm_policy_keep, &xb, NULL, NULL) < 0) {
863				fprintf(stderr, "Delete-all terminated\n");
864				exit(1);
865			}
866			if (xb.nlmsg_count == 0) {
867				if (show_stats > 1)
868					fprintf(stderr, "Delete-all completed\n");
869				break;
870			}
871
872			if (rtnl_send_check(&rth, xb.buf, xb.offset) < 0) {
873				perror("Failed to send delete-all request");
874				exit(1);
875			}
876			if (show_stats > 1)
877				fprintf(stderr, "Delete-all nlmsg count = %d\n", xb.nlmsg_count);
878
879			xb.offset = 0;
880			xb.nlmsg_count = 0;
881		}
882	} else {
883		if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETPOLICY) < 0) {
884			perror("Cannot send dump request");
885			exit(1);
886		}
887
888		if (rtnl_dump_filter(&rth, xfrm_policy_print, stdout, NULL, NULL) < 0) {
889			fprintf(stderr, "Dump terminated\n");
890			exit(1);
891		}
892	}
893
894	rtnl_close(&rth);
895
896	exit(0);
897}
898
899int print_spdinfo( struct nlmsghdr *n, void *arg)
900{
901	FILE *fp = (FILE*)arg;
902	__u32 *f = NLMSG_DATA(n);
903	struct rtattr * tb[XFRMA_SPD_MAX+1];
904	struct rtattr * rta;
905
906	int len = n->nlmsg_len;
907
908	len -= NLMSG_LENGTH(sizeof(__u32));
909	if (len < 0) {
910		fprintf(stderr, "SPDinfo: Wrong len %d\n", len);
911		return -1;
912	}
913
914	rta = XFRMSAPD_RTA(f);
915	parse_rtattr(tb, XFRMA_SPD_MAX, rta, len);
916
917	fprintf(fp,"\t SPD");
918	if (tb[XFRMA_SPD_INFO]) {
919		struct xfrmu_spdinfo *si;
920
921		if (RTA_PAYLOAD(tb[XFRMA_SPD_INFO]) < sizeof(*si)) {
922			fprintf(stderr, "SPDinfo: Wrong len %d\n", len);
923			return -1;
924		}
925		si = RTA_DATA(tb[XFRMA_SPD_INFO]);
926		fprintf(fp," IN  %d", si->incnt);
927		fprintf(fp," OUT %d", si->outcnt);
928		fprintf(fp," FWD %d", si->fwdcnt);
929
930		if (show_stats) {
931			fprintf(fp," (Sock:");
932			fprintf(fp," IN %d", si->inscnt);
933			fprintf(fp," OUT %d", si->outscnt);
934			fprintf(fp," FWD %d", si->fwdscnt);
935			fprintf(fp,")");
936		}
937
938		fprintf(fp,"\n");
939	}
940	if (show_stats > 1) {
941		struct xfrmu_spdhinfo *sh;
942
943		if (tb[XFRMA_SPD_HINFO]) {
944			if (RTA_PAYLOAD(tb[XFRMA_SPD_HINFO]) < sizeof(*sh)) {
945				fprintf(stderr, "SPDinfo: Wrong len %d\n", len);
946				return -1;
947			}
948			sh = RTA_DATA(tb[XFRMA_SPD_HINFO]);
949			fprintf(fp,"\t SPD buckets:");
950			fprintf(fp," count %d", sh->spdhcnt);
951			fprintf(fp," Max %d", sh->spdhmcnt);
952		}
953	}
954	fprintf(fp,"\n");
955
956        return 0;
957}
958
959static int xfrm_spd_getinfo(int argc, char **argv)
960{
961	struct rtnl_handle rth;
962	struct {
963		struct nlmsghdr			n;
964		__u32				flags;
965		char 				ans[128];
966	} req;
967
968	memset(&req, 0, sizeof(req));
969
970	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(__u32));
971	req.n.nlmsg_flags = NLM_F_REQUEST;
972	req.n.nlmsg_type = XFRM_MSG_GETSPDINFO;
973	req.flags = 0XFFFFFFFF;
974
975	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
976		exit(1);
977
978	if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0)
979		exit(2);
980
981	print_spdinfo(&req.n, (void*)stdout);
982
983	rtnl_close(&rth);
984
985	return 0;
986}
987
988static int xfrm_policy_flush(int argc, char **argv)
989{
990	struct rtnl_handle rth;
991	struct {
992		struct nlmsghdr	n;
993		char		buf[RTA_BUF_SIZE];
994	} req;
995	char *ptypep = NULL;
996	struct xfrm_userpolicy_type upt;
997
998	memset(&req, 0, sizeof(req));
999	memset(&upt, 0, sizeof(upt));
1000
1001	req.n.nlmsg_len = NLMSG_LENGTH(0); /* nlmsg data is nothing */
1002	req.n.nlmsg_flags = NLM_F_REQUEST;
1003	req.n.nlmsg_type = XFRM_MSG_FLUSHPOLICY;
1004
1005	while (argc > 0) {
1006		if (strcmp(*argv, "ptype") == 0) {
1007			if (ptypep)
1008				duparg("ptype", *argv);
1009			ptypep = *argv;
1010
1011			NEXT_ARG();
1012			xfrm_policy_ptype_parse(&upt.type, &argc, &argv);
1013		} else
1014			invarg("unknown", *argv);
1015
1016		argc--; argv++;
1017	}
1018
1019	if (ptypep) {
1020		addattr_l(&req.n, sizeof(req), XFRMA_POLICY_TYPE,
1021			  (void *)&upt, sizeof(upt));
1022	}
1023
1024	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
1025		exit(1);
1026
1027	if (show_stats > 1)
1028		fprintf(stderr, "Flush policy\n");
1029
1030	if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
1031		exit(2);
1032
1033	rtnl_close(&rth);
1034
1035	return 0;
1036}
1037
1038int do_xfrm_policy(int argc, char **argv)
1039{
1040	if (argc < 1)
1041		return xfrm_policy_list_or_deleteall(0, NULL, 0);
1042
1043	if (matches(*argv, "add") == 0)
1044		return xfrm_policy_modify(XFRM_MSG_NEWPOLICY, 0,
1045					  argc-1, argv+1);
1046	if (matches(*argv, "update") == 0)
1047		return xfrm_policy_modify(XFRM_MSG_UPDPOLICY, 0,
1048					  argc-1, argv+1);
1049	if (matches(*argv, "delete") == 0)
1050		return xfrm_policy_delete(argc-1, argv+1);
1051	if (matches(*argv, "deleteall") == 0 || matches(*argv, "delall") == 0)
1052		return xfrm_policy_list_or_deleteall(argc-1, argv+1, 1);
1053	if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
1054	    || matches(*argv, "lst") == 0)
1055		return xfrm_policy_list_or_deleteall(argc-1, argv+1, 0);
1056	if (matches(*argv, "get") == 0)
1057		return xfrm_policy_get(argc-1, argv+1);
1058	if (matches(*argv, "flush") == 0)
1059		return xfrm_policy_flush(argc-1, argv+1);
1060	if (matches(*argv, "count") == 0)
1061		return xfrm_spd_getinfo(argc, argv);
1062	if (matches(*argv, "help") == 0)
1063		usage();
1064	fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm policy help\".\n", *argv);
1065	exit(-1);
1066}
1067