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, see <http://www.gnu.org/licenses>.
18  */
19 /*
20  * based on iproute.c
21  */
22 /*
23  * Authors:
24  *	Masahide NAKAMURA @USAGI
25  */
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <netdb.h>
31 #include "utils.h"
32 #include "xfrm.h"
33 #include "ip_common.h"
34 
35 //#define NLMSG_DELETEALL_BUF_SIZE (4096-512)
36 #define NLMSG_DELETEALL_BUF_SIZE 8192
37 
38 /*
39  * Receiving buffer defines:
40  * nlmsg
41  *   data = struct xfrm_usersa_info
42  *   rtattr
43  *   rtattr
44  *   ... (max count of rtattr is XFRM_MAX+1
45  *
46  *  each rtattr data = struct xfrm_algo(dynamic size) or xfrm_address_t
47  */
48 #define NLMSG_BUF_SIZE 4096
49 #define RTA_BUF_SIZE 2048
50 #define XFRM_ALGO_KEY_BUF_SIZE 512
51 #define CTX_BUF_SIZE 256
52 
53 static void usage(void) __attribute__((noreturn));
54 
usage(void)55 static void usage(void)
56 {
57 	fprintf(stderr, "Usage: ip xfrm state { add | update } ID [ ALGO-LIST ] [ mode MODE ]\n");
58 	fprintf(stderr, "        [ mark MARK [ mask MASK ] ] [ reqid REQID ] [ seq SEQ ]\n");
59 	fprintf(stderr, "        [ replay-window SIZE ] [ replay-seq SEQ ] [ replay-oseq SEQ ]\n");
60 	fprintf(stderr, "        [ replay-seq-hi SEQ ] [ replay-oseq-hi SEQ ]\n");
61 	fprintf(stderr, "        [ flag FLAG-LIST ] [ sel SELECTOR ] [ LIMIT-LIST ] [ encap ENCAP ]\n");
62 	fprintf(stderr, "        [ coa ADDR[/PLEN] ] [ ctx CTX ] [ extra-flag EXTRA-FLAG-LIST ]\n");
63 	fprintf(stderr, "Usage: ip xfrm state allocspi ID [ mode MODE ] [ mark MARK [ mask MASK ] ]\n");
64 	fprintf(stderr, "        [ reqid REQID ] [ seq SEQ ] [ min SPI max SPI ]\n");
65 	fprintf(stderr, "Usage: ip xfrm state { delete | get } ID [ mark MARK [ mask MASK ] ]\n");
66 	fprintf(stderr, "Usage: ip xfrm state { deleteall | list } [ ID ] [ mode MODE ] [ reqid REQID ]\n");
67 	fprintf(stderr, "        [ flag FLAG-LIST ]\n");
68 	fprintf(stderr, "Usage: ip xfrm state flush [ proto XFRM-PROTO ]\n");
69 	fprintf(stderr, "Usage: ip xfrm state count\n");
70 	fprintf(stderr, "ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM-PROTO ] [ spi SPI ]\n");
71 	fprintf(stderr, "XFRM-PROTO := ");
72 	fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ESP));
73 	fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_AH));
74 	fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_COMP));
75 	fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ROUTING));
76 	fprintf(stderr, "%s\n", strxf_xfrmproto(IPPROTO_DSTOPTS));
77 	fprintf(stderr, "ALGO-LIST := [ ALGO-LIST ] ALGO\n");
78 	fprintf(stderr, "ALGO := { ");
79 	fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_CRYPT));
80 	fprintf(stderr, "%s", strxf_algotype(XFRMA_ALG_AUTH));
81 	fprintf(stderr, " } ALGO-NAME ALGO-KEYMAT |\n");
82 	fprintf(stderr, "        %s", strxf_algotype(XFRMA_ALG_AUTH_TRUNC));
83 	fprintf(stderr, " ALGO-NAME ALGO-KEYMAT ALGO-TRUNC-LEN |\n");
84 	fprintf(stderr, "        %s", strxf_algotype(XFRMA_ALG_AEAD));
85 	fprintf(stderr, " ALGO-NAME ALGO-KEYMAT ALGO-ICV-LEN |\n");
86 	fprintf(stderr, "        %s", strxf_algotype(XFRMA_ALG_COMP));
87 	fprintf(stderr, " ALGO-NAME\n");
88 	fprintf(stderr, "MODE := transport | tunnel | beet | ro | in_trigger\n");
89 	fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n");
90 	fprintf(stderr, "FLAG := noecn | decap-dscp | nopmtudisc | wildrecv | icmp | af-unspec | align4 | esn\n");
91 	fprintf(stderr, "EXTRA-FLAG-LIST := [ EXTRA-FLAG-LIST ] EXTRA-FLAG\n");
92 	fprintf(stderr, "EXTRA-FLAG := dont-encap-dscp\n");
93 	fprintf(stderr, "SELECTOR := [ src ADDR[/PLEN] ] [ dst ADDR[/PLEN] ] [ dev DEV ] [ UPSPEC ]\n");
94 	fprintf(stderr, "UPSPEC := proto { { ");
95 	fprintf(stderr, "%s | ", strxf_proto(IPPROTO_TCP));
96 	fprintf(stderr, "%s | ", strxf_proto(IPPROTO_UDP));
97 	fprintf(stderr, "%s | ", strxf_proto(IPPROTO_SCTP));
98 	fprintf(stderr, "%s", strxf_proto(IPPROTO_DCCP));
99 	fprintf(stderr, " } [ sport PORT ] [ dport PORT ] |\n");
100 	fprintf(stderr, "                  { ");
101 	fprintf(stderr, "%s | ", strxf_proto(IPPROTO_ICMP));
102 	fprintf(stderr, "%s | ", strxf_proto(IPPROTO_ICMPV6));
103 	fprintf(stderr, "%s", strxf_proto(IPPROTO_MH));
104 	fprintf(stderr, " } [ type NUMBER ] [ code NUMBER ] |\n");
105 	fprintf(stderr, "                  %s", strxf_proto(IPPROTO_GRE));
106 	fprintf(stderr, " [ key { DOTTED-QUAD | NUMBER } ] | PROTO }\n");
107 	fprintf(stderr, "LIMIT-LIST := [ LIMIT-LIST ] limit LIMIT\n");
108 	fprintf(stderr, "LIMIT := { time-soft | time-hard | time-use-soft | time-use-hard } SECONDS |\n");
109 	fprintf(stderr, "         { byte-soft | byte-hard } SIZE | { packet-soft | packet-hard } COUNT\n");
110         fprintf(stderr, "ENCAP := { espinudp | espinudp-nonike } SPORT DPORT OADDR\n");
111 
112 	exit(-1);
113 }
114 
xfrm_algo_parse(struct xfrm_algo * alg,enum xfrm_attr_type_t type,char * name,char * key,char * buf,int max)115 static int xfrm_algo_parse(struct xfrm_algo *alg, enum xfrm_attr_type_t type,
116 			   char *name, char *key, char *buf, int max)
117 {
118 	int len;
119 	int slen = strlen(key);
120 
121 #if 0
122 	/* XXX: verifying both name and key is required! */
123 	fprintf(stderr, "warning: ALGO-NAME/ALGO-KEYMAT values will be sent to the kernel promiscuously! (verifying them isn't implemented yet)\n");
124 #endif
125 
126 	strncpy(alg->alg_name, name, sizeof(alg->alg_name));
127 
128 	if (slen > 2 && strncmp(key, "0x", 2) == 0) {
129 		/* split two chars "0x" from the top */
130 		char *p = key + 2;
131 		int plen = slen - 2;
132 		int i;
133 		int j;
134 
135 		/* Converting hexadecimal numbered string into real key;
136 		 * Convert each two chars into one char(value). If number
137 		 * of the length is odd, add zero on the top for rounding.
138 		 */
139 
140 		/* calculate length of the converted values(real key) */
141 		len = (plen + 1) / 2;
142 		if (len > max)
143 			invarg("ALGO-KEYMAT value makes buffer overflow\n", key);
144 
145 		for (i = - (plen % 2), j = 0; j < len; i += 2, j++) {
146 			char vbuf[3];
147 			__u8 val;
148 
149 			vbuf[0] = i >= 0 ? p[i] : '0';
150 			vbuf[1] = p[i + 1];
151 			vbuf[2] = '\0';
152 
153 			if (get_u8(&val, vbuf, 16))
154 				invarg("ALGO-KEYMAT value is invalid", key);
155 
156 			buf[j] = val;
157 		}
158 	} else {
159 		len = slen;
160 		if (len > 0) {
161 			if (len > max)
162 				invarg("ALGO-KEYMAT value makes buffer overflow\n", key);
163 
164 			memcpy(buf, key, len);
165 		}
166 	}
167 
168 	alg->alg_key_len = len * 8;
169 
170 	return 0;
171 }
172 
xfrm_seq_parse(__u32 * seq,int * argcp,char *** argvp)173 static int xfrm_seq_parse(__u32 *seq, int *argcp, char ***argvp)
174 {
175 	int argc = *argcp;
176 	char **argv = *argvp;
177 
178 	if (get_u32(seq, *argv, 0))
179 		invarg("SEQ value is invalid", *argv);
180 
181 	*seq = htonl(*seq);
182 
183 	*argcp = argc;
184 	*argvp = argv;
185 
186 	return 0;
187 }
188 
xfrm_state_flag_parse(__u8 * flags,int * argcp,char *** argvp)189 static int xfrm_state_flag_parse(__u8 *flags, int *argcp, char ***argvp)
190 {
191 	int argc = *argcp;
192 	char **argv = *argvp;
193 	int len = strlen(*argv);
194 
195 	if (len > 2 && strncmp(*argv, "0x", 2) == 0) {
196 		__u8 val = 0;
197 
198 		if (get_u8(&val, *argv, 16))
199 			invarg("FLAG value is invalid", *argv);
200 		*flags = val;
201 	} else {
202 		while (1) {
203 			if (strcmp(*argv, "noecn") == 0)
204 				*flags |= XFRM_STATE_NOECN;
205 			else if (strcmp(*argv, "decap-dscp") == 0)
206 				*flags |= XFRM_STATE_DECAP_DSCP;
207 			else if (strcmp(*argv, "nopmtudisc") == 0)
208 				*flags |= XFRM_STATE_NOPMTUDISC;
209 			else if (strcmp(*argv, "wildrecv") == 0)
210 				*flags |= XFRM_STATE_WILDRECV;
211 			else if (strcmp(*argv, "icmp") == 0)
212 				*flags |= XFRM_STATE_ICMP;
213 			else if (strcmp(*argv, "af-unspec") == 0)
214 				*flags |= XFRM_STATE_AF_UNSPEC;
215 			else if (strcmp(*argv, "align4") == 0)
216 				*flags |= XFRM_STATE_ALIGN4;
217 			else if (strcmp(*argv, "esn") == 0)
218 				*flags |= XFRM_STATE_ESN;
219 			else {
220 				PREV_ARG(); /* back track */
221 				break;
222 			}
223 
224 			if (!NEXT_ARG_OK())
225 				break;
226 			NEXT_ARG();
227 		}
228 	}
229 
230 	*argcp = argc;
231 	*argvp = argv;
232 
233 	return 0;
234 }
235 
xfrm_state_extra_flag_parse(__u32 * extra_flags,int * argcp,char *** argvp)236 static int xfrm_state_extra_flag_parse(__u32 *extra_flags, int *argcp, char ***argvp)
237 {
238 	int argc = *argcp;
239 	char **argv = *argvp;
240 	int len = strlen(*argv);
241 
242 	if (len > 2 && strncmp(*argv, "0x", 2) == 0) {
243 		__u32 val = 0;
244 
245 		if (get_u32(&val, *argv, 16))
246 			invarg("\"EXTRA-FLAG\" is invalid", *argv);
247 		*extra_flags = val;
248 	} else {
249 		while (1) {
250 			if (strcmp(*argv, "dont-encap-dscp") == 0)
251 				*extra_flags |= XFRM_SA_XFLAG_DONT_ENCAP_DSCP;
252 			else {
253 				PREV_ARG(); /* back track */
254 				break;
255 			}
256 
257 			if (!NEXT_ARG_OK())
258 				break;
259 			NEXT_ARG();
260 		}
261 	}
262 
263 	*argcp = argc;
264 	*argvp = argv;
265 
266 	return 0;
267 }
268 
xfrm_state_modify(int cmd,unsigned flags,int argc,char ** argv)269 static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
270 {
271 	struct rtnl_handle rth;
272 	struct {
273 		struct nlmsghdr	n;
274 		struct xfrm_usersa_info xsinfo;
275 		char  			buf[RTA_BUF_SIZE];
276 	} req;
277 	struct xfrm_replay_state replay;
278 	struct xfrm_replay_state_esn replay_esn;
279 	__u32 replay_window = 0;
280 	__u32 seq = 0, oseq = 0, seq_hi = 0, oseq_hi = 0;
281 	char *idp = NULL;
282 	char *aeadop = NULL;
283 	char *ealgop = NULL;
284 	char *aalgop = NULL;
285 	char *calgop = NULL;
286 	char *coap = NULL;
287 	char *sctxp = NULL;
288 	__u32 extra_flags = 0;
289 	struct xfrm_mark mark = {0, 0};
290 	struct {
291 		struct xfrm_user_sec_ctx sctx;
292 		char    str[CTX_BUF_SIZE];
293 	} ctx;
294 
295 	memset(&req, 0, sizeof(req));
296 	memset(&replay, 0, sizeof(replay));
297 	memset(&replay_esn, 0, sizeof(replay_esn));
298 	memset(&ctx, 0, sizeof(ctx));
299 
300 	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo));
301 	req.n.nlmsg_flags = NLM_F_REQUEST|flags;
302 	req.n.nlmsg_type = cmd;
303 	req.xsinfo.family = preferred_family;
304 
305 	req.xsinfo.lft.soft_byte_limit = XFRM_INF;
306 	req.xsinfo.lft.hard_byte_limit = XFRM_INF;
307 	req.xsinfo.lft.soft_packet_limit = XFRM_INF;
308 	req.xsinfo.lft.hard_packet_limit = XFRM_INF;
309 
310 	while (argc > 0) {
311 		if (strcmp(*argv, "mode") == 0) {
312 			NEXT_ARG();
313 			xfrm_mode_parse(&req.xsinfo.mode, &argc, &argv);
314 		} else if (strcmp(*argv, "mark") == 0) {
315 			xfrm_parse_mark(&mark, &argc, &argv);
316 		} else if (strcmp(*argv, "reqid") == 0) {
317 			NEXT_ARG();
318 			xfrm_reqid_parse(&req.xsinfo.reqid, &argc, &argv);
319 		} else if (strcmp(*argv, "seq") == 0) {
320 			NEXT_ARG();
321 			xfrm_seq_parse(&req.xsinfo.seq, &argc, &argv);
322 		} else if (strcmp(*argv, "replay-window") == 0) {
323 			NEXT_ARG();
324 			if (get_u32(&replay_window, *argv, 0))
325 				invarg("value after \"replay-window\" is invalid", *argv);
326 		} else if (strcmp(*argv, "replay-seq") == 0) {
327 			NEXT_ARG();
328 			if (get_u32(&seq, *argv, 0))
329 				invarg("value after \"replay-seq\" is invalid", *argv);
330 		} else if (strcmp(*argv, "replay-seq-hi") == 0) {
331 			NEXT_ARG();
332 			if (get_u32(&seq_hi, *argv, 0))
333 				invarg("value after \"replay-seq-hi\" is invalid", *argv);
334 		} else if (strcmp(*argv, "replay-oseq") == 0) {
335 			NEXT_ARG();
336 			if (get_u32(&oseq, *argv, 0))
337 				invarg("value after \"replay-oseq\" is invalid", *argv);
338 		} else if (strcmp(*argv, "replay-oseq-hi") == 0) {
339 			NEXT_ARG();
340 			if (get_u32(&oseq_hi, *argv, 0))
341 				invarg("value after \"replay-oseq-hi\" is invalid", *argv);
342 		} else if (strcmp(*argv, "flag") == 0) {
343 			NEXT_ARG();
344 			xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv);
345 		} else if (strcmp(*argv, "extra-flag") == 0) {
346 			NEXT_ARG();
347 			xfrm_state_extra_flag_parse(&extra_flags, &argc, &argv);
348 		} else if (strcmp(*argv, "sel") == 0) {
349 			NEXT_ARG();
350 			preferred_family = AF_UNSPEC;
351 			xfrm_selector_parse(&req.xsinfo.sel, &argc, &argv);
352 			preferred_family = req.xsinfo.sel.family;
353 		} else if (strcmp(*argv, "limit") == 0) {
354 			NEXT_ARG();
355 			xfrm_lifetime_cfg_parse(&req.xsinfo.lft, &argc, &argv);
356 		} else if (strcmp(*argv, "encap") == 0) {
357 			struct xfrm_encap_tmpl encap;
358 			inet_prefix oa;
359 		        NEXT_ARG();
360 			xfrm_encap_type_parse(&encap.encap_type, &argc, &argv);
361 			NEXT_ARG();
362 			if (get_u16(&encap.encap_sport, *argv, 0))
363 				invarg("SPORT value after \"encap\" is invalid", *argv);
364 			encap.encap_sport = htons(encap.encap_sport);
365 			NEXT_ARG();
366 			if (get_u16(&encap.encap_dport, *argv, 0))
367 				invarg("DPORT value after \"encap\" is invalid", *argv);
368 			encap.encap_dport = htons(encap.encap_dport);
369 			NEXT_ARG();
370 			get_addr(&oa, *argv, AF_UNSPEC);
371 			memcpy(&encap.encap_oa, &oa.data, sizeof(encap.encap_oa));
372 			addattr_l(&req.n, sizeof(req.buf), XFRMA_ENCAP,
373 				  (void *)&encap, sizeof(encap));
374 		} else if (strcmp(*argv, "coa") == 0) {
375 			inet_prefix coa;
376 			xfrm_address_t xcoa;
377 
378 			if (coap)
379 				duparg("coa", *argv);
380 			coap = *argv;
381 
382 			NEXT_ARG();
383 
384 			get_prefix(&coa, *argv, preferred_family);
385 			if (coa.family == AF_UNSPEC)
386 				invarg("value after \"coa\" has an unrecognized address family", *argv);
387 			if (coa.bytelen > sizeof(xcoa))
388 				invarg("value after \"coa\" is too large", *argv);
389 
390 			memset(&xcoa, 0, sizeof(xcoa));
391 			memcpy(&xcoa, &coa.data, coa.bytelen);
392 
393 			addattr_l(&req.n, sizeof(req.buf), XFRMA_COADDR,
394 				  (void *)&xcoa, sizeof(xcoa));
395 		} else if (strcmp(*argv, "ctx") == 0) {
396 			char *context;
397 
398 			if (sctxp)
399 				duparg("ctx", *argv);
400 			sctxp = *argv;
401 
402 			NEXT_ARG();
403 			context = *argv;
404 
405 			xfrm_sctx_parse((char *)&ctx.str, context, &ctx.sctx);
406 			addattr_l(&req.n, sizeof(req.buf), XFRMA_SEC_CTX,
407 				  (void *)&ctx, ctx.sctx.len);
408 		} else {
409 			/* try to assume ALGO */
410 			int type = xfrm_algotype_getbyname(*argv);
411 			switch (type) {
412 			case XFRMA_ALG_AEAD:
413 			case XFRMA_ALG_CRYPT:
414 			case XFRMA_ALG_AUTH:
415 			case XFRMA_ALG_AUTH_TRUNC:
416 			case XFRMA_ALG_COMP:
417 			{
418 				/* ALGO */
419 				struct {
420 					union {
421 						struct xfrm_algo alg;
422 						struct xfrm_algo_aead aead;
423 						struct xfrm_algo_auth auth;
424 					} u;
425 					char buf[XFRM_ALGO_KEY_BUF_SIZE];
426 				} alg = {};
427 				int len;
428 				__u32 icvlen, trunclen;
429 				char *name;
430 				char *key = "";
431 				char *buf;
432 
433 				switch (type) {
434 				case XFRMA_ALG_AEAD:
435 					if (ealgop || aalgop || aeadop)
436 						duparg("ALGO-TYPE", *argv);
437 					aeadop = *argv;
438 					break;
439 				case XFRMA_ALG_CRYPT:
440 					if (ealgop || aeadop)
441 						duparg("ALGO-TYPE", *argv);
442 					ealgop = *argv;
443 					break;
444 				case XFRMA_ALG_AUTH:
445 				case XFRMA_ALG_AUTH_TRUNC:
446 					if (aalgop || aeadop)
447 						duparg("ALGO-TYPE", *argv);
448 					aalgop = *argv;
449 					break;
450 				case XFRMA_ALG_COMP:
451 					if (calgop)
452 						duparg("ALGO-TYPE", *argv);
453 					calgop = *argv;
454 					break;
455 				default:
456 					/* not reached */
457 					invarg("ALGO-TYPE value is invalid\n", *argv);
458 				}
459 
460 				if (!NEXT_ARG_OK())
461 					missarg("ALGO-NAME");
462 				NEXT_ARG();
463 				name = *argv;
464 
465 				switch (type) {
466 				case XFRMA_ALG_AEAD:
467 				case XFRMA_ALG_CRYPT:
468 				case XFRMA_ALG_AUTH:
469 				case XFRMA_ALG_AUTH_TRUNC:
470 					if (!NEXT_ARG_OK())
471 						missarg("ALGO-KEYMAT");
472 					NEXT_ARG();
473 					key = *argv;
474 					break;
475 				}
476 
477 				buf = alg.u.alg.alg_key;
478 				len = sizeof(alg.u.alg);
479 
480 				switch (type) {
481 				case XFRMA_ALG_AEAD:
482 					if (!NEXT_ARG_OK())
483 						missarg("ALGO-ICV-LEN");
484 					NEXT_ARG();
485 					if (get_u32(&icvlen, *argv, 0))
486 						invarg("ALGO-ICV-LEN value is invalid",
487 						       *argv);
488 					alg.u.aead.alg_icv_len = icvlen;
489 
490 					buf = alg.u.aead.alg_key;
491 					len = sizeof(alg.u.aead);
492 					break;
493 				case XFRMA_ALG_AUTH_TRUNC:
494 					if (!NEXT_ARG_OK())
495 						missarg("ALGO-TRUNC-LEN");
496 					NEXT_ARG();
497 					if (get_u32(&trunclen, *argv, 0))
498 						invarg("ALGO-TRUNC-LEN value is invalid",
499 						       *argv);
500 					alg.u.auth.alg_trunc_len = trunclen;
501 
502 					buf = alg.u.auth.alg_key;
503 					len = sizeof(alg.u.auth);
504 					break;
505 				}
506 
507 				xfrm_algo_parse((void *)&alg, type, name, key,
508 						buf, sizeof(alg.buf));
509 				len += alg.u.alg.alg_key_len;
510 
511 				addattr_l(&req.n, sizeof(req.buf), type,
512 					  (void *)&alg, len);
513 				break;
514 			}
515 			default:
516 				/* try to assume ID */
517 				if (idp)
518 					invarg("unknown", *argv);
519 				idp = *argv;
520 
521 				/* ID */
522 				xfrm_id_parse(&req.xsinfo.saddr, &req.xsinfo.id,
523 					      &req.xsinfo.family, 0, &argc, &argv);
524 				if (preferred_family == AF_UNSPEC)
525 					preferred_family = req.xsinfo.family;
526 			}
527 		}
528 		argc--; argv++;
529 	}
530 
531 	if (req.xsinfo.flags & XFRM_STATE_ESN &&
532 	    replay_window == 0) {
533 		fprintf(stderr, "Error: esn flag set without replay-window.\n");
534 		exit(-1);
535 	}
536 
537 	if (replay_window > XFRMA_REPLAY_ESN_MAX) {
538 		fprintf(stderr,
539 			"Error: replay-window (%u) > XFRMA_REPLAY_ESN_MAX (%u).\n",
540 			replay_window, XFRMA_REPLAY_ESN_MAX);
541 		exit(-1);
542 	}
543 
544 	if (req.xsinfo.flags & XFRM_STATE_ESN ||
545 	    replay_window > (sizeof(replay.bitmap) * 8)) {
546 		replay_esn.seq = seq;
547 		replay_esn.oseq = oseq;
548 		replay_esn.seq_hi = seq_hi;
549 		replay_esn.oseq_hi = oseq_hi;
550 		replay_esn.replay_window = replay_window;
551 		replay_esn.bmp_len = (replay_window + sizeof(__u32) * 8 - 1) /
552 				     (sizeof(__u32) * 8);
553 		addattr_l(&req.n, sizeof(req.buf), XFRMA_REPLAY_ESN_VAL,
554 			  &replay_esn, sizeof(replay_esn));
555 	} else {
556 		if (seq || oseq) {
557 			replay.seq = seq;
558 			replay.oseq = oseq;
559 			addattr_l(&req.n, sizeof(req.buf), XFRMA_REPLAY_VAL,
560 				  &replay, sizeof(replay));
561 		}
562 		req.xsinfo.replay_window = replay_window;
563 	}
564 
565 	if (extra_flags)
566 		addattr32(&req.n, sizeof(req.buf), XFRMA_SA_EXTRA_FLAGS,
567 			  extra_flags);
568 
569 	if (!idp) {
570 		fprintf(stderr, "Not enough information: ID is required\n");
571 		exit(1);
572 	}
573 
574 	if (mark.m) {
575 		int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK,
576 				  (void *)&mark, sizeof(mark));
577 		if (r < 0) {
578 			fprintf(stderr, "XFRMA_MARK failed\n");
579 			exit(1);
580 		}
581 	}
582 
583 	if (xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) {
584 		switch (req.xsinfo.mode) {
585 		case XFRM_MODE_TRANSPORT:
586 		case XFRM_MODE_TUNNEL:
587 			break;
588 		case XFRM_MODE_BEET:
589 			if (req.xsinfo.id.proto == IPPROTO_ESP)
590 				break;
591 		default:
592 			fprintf(stderr, "MODE value is invalid with XFRM-PROTO value \"%s\"\n",
593 				strxf_xfrmproto(req.xsinfo.id.proto));
594 			exit(1);
595 		}
596 
597 		switch (req.xsinfo.id.proto) {
598 		case IPPROTO_ESP:
599 			if (calgop) {
600 				fprintf(stderr, "ALGO-TYPE value \"%s\" is invalid with XFRM-PROTO value \"%s\"\n",
601 					strxf_algotype(XFRMA_ALG_COMP),
602 					strxf_xfrmproto(req.xsinfo.id.proto));
603 				exit(1);
604 			}
605 			if (!ealgop && !aeadop) {
606 				fprintf(stderr, "ALGO-TYPE value \"%s\" or \"%s\" is required with XFRM-PROTO value \"%s\"\n",
607 					strxf_algotype(XFRMA_ALG_CRYPT),
608 					strxf_algotype(XFRMA_ALG_AEAD),
609 					strxf_xfrmproto(req.xsinfo.id.proto));
610 				exit(1);
611 			}
612 			break;
613 		case IPPROTO_AH:
614 			if (ealgop || aeadop || calgop) {
615 				fprintf(stderr, "ALGO-TYPE values \"%s\", \"%s\", and \"%s\" are invalid with XFRM-PROTO value \"%s\"\n",
616 					strxf_algotype(XFRMA_ALG_CRYPT),
617 					strxf_algotype(XFRMA_ALG_AEAD),
618 					strxf_algotype(XFRMA_ALG_COMP),
619 					strxf_xfrmproto(req.xsinfo.id.proto));
620 				exit(1);
621 			}
622 			if (!aalgop) {
623 				fprintf(stderr, "ALGO-TYPE value \"%s\" or \"%s\" is required with XFRM-PROTO value \"%s\"\n",
624 					strxf_algotype(XFRMA_ALG_AUTH),
625 					strxf_algotype(XFRMA_ALG_AUTH_TRUNC),
626 					strxf_xfrmproto(req.xsinfo.id.proto));
627 				exit(1);
628 			}
629 			break;
630 		case IPPROTO_COMP:
631 			if (ealgop || aalgop || aeadop) {
632 				fprintf(stderr, "ALGO-TYPE values \"%s\", \"%s\", \"%s\", and \"%s\" are invalid with XFRM-PROTO value \"%s\"\n",
633 					strxf_algotype(XFRMA_ALG_CRYPT),
634 					strxf_algotype(XFRMA_ALG_AUTH),
635 					strxf_algotype(XFRMA_ALG_AUTH_TRUNC),
636 					strxf_algotype(XFRMA_ALG_AEAD),
637 					strxf_xfrmproto(req.xsinfo.id.proto));
638 				exit(1);
639 			}
640 			if (!calgop) {
641 				fprintf(stderr, "ALGO-TYPE value \"%s\" is required with XFRM-PROTO value \"%s\"\n",
642 					strxf_algotype(XFRMA_ALG_COMP),
643 					strxf_xfrmproto(req.xsinfo.id.proto));
644 				exit(1);
645 			}
646 			break;
647 		}
648 	} else {
649 		if (ealgop || aalgop || aeadop || calgop) {
650 			fprintf(stderr, "ALGO is invalid with XFRM-PROTO value \"%s\"\n",
651 				strxf_xfrmproto(req.xsinfo.id.proto));
652 			exit(1);
653 		}
654 	}
655 
656 	if (xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) {
657 		switch (req.xsinfo.mode) {
658 		case XFRM_MODE_ROUTEOPTIMIZATION:
659 		case XFRM_MODE_IN_TRIGGER:
660 			break;
661 		case 0:
662 			fprintf(stderr, "\"mode\" is required with XFRM-PROTO value \"%s\"\n",
663 				strxf_xfrmproto(req.xsinfo.id.proto));
664 			exit(1);
665 		default:
666 			fprintf(stderr, "MODE value is invalid with XFRM-PROTO value \"%s\"\n",
667 				strxf_xfrmproto(req.xsinfo.id.proto));
668 			exit(1);
669 		}
670 
671 		if (!coap) {
672 			fprintf(stderr, "\"coa\" is required with XFRM-PROTO value \"%s\"\n",
673 				strxf_xfrmproto(req.xsinfo.id.proto));
674 			exit(1);
675 		}
676 	} else {
677 		if (coap) {
678 			fprintf(stderr, "\"coa\" is invalid with XFRM-PROTO value \"%s\"\n",
679 				strxf_xfrmproto(req.xsinfo.id.proto));
680 			exit(1);
681 		}
682 	}
683 
684 	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
685 		exit(1);
686 
687 	if (req.xsinfo.family == AF_UNSPEC)
688 		req.xsinfo.family = AF_INET;
689 
690 	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
691 		exit(2);
692 
693 	rtnl_close(&rth);
694 
695 	return 0;
696 }
697 
xfrm_state_allocspi(int argc,char ** argv)698 static int xfrm_state_allocspi(int argc, char **argv)
699 {
700 	struct rtnl_handle rth;
701 	struct {
702 		struct nlmsghdr	n;
703 		struct xfrm_userspi_info xspi;
704 		char  			buf[RTA_BUF_SIZE];
705 	} req;
706 	char *idp = NULL;
707 	char *minp = NULL;
708 	char *maxp = NULL;
709 	struct xfrm_mark mark = {0, 0};
710 	char res_buf[NLMSG_BUF_SIZE];
711 	struct nlmsghdr *res_n = (struct nlmsghdr *)res_buf;
712 
713 	memset(res_buf, 0, sizeof(res_buf));
714 
715 	memset(&req, 0, sizeof(req));
716 
717 	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xspi));
718 	req.n.nlmsg_flags = NLM_F_REQUEST;
719 	req.n.nlmsg_type = XFRM_MSG_ALLOCSPI;
720 	req.xspi.info.family = preferred_family;
721 
722 #if 0
723 	req.xsinfo.lft.soft_byte_limit = XFRM_INF;
724 	req.xsinfo.lft.hard_byte_limit = XFRM_INF;
725 	req.xsinfo.lft.soft_packet_limit = XFRM_INF;
726 	req.xsinfo.lft.hard_packet_limit = XFRM_INF;
727 #endif
728 
729 	while (argc > 0) {
730 		if (strcmp(*argv, "mode") == 0) {
731 			NEXT_ARG();
732 			xfrm_mode_parse(&req.xspi.info.mode, &argc, &argv);
733 		} else if (strcmp(*argv, "mark") == 0) {
734 			xfrm_parse_mark(&mark, &argc, &argv);
735 		} else if (strcmp(*argv, "reqid") == 0) {
736 			NEXT_ARG();
737 			xfrm_reqid_parse(&req.xspi.info.reqid, &argc, &argv);
738 		} else if (strcmp(*argv, "seq") == 0) {
739 			NEXT_ARG();
740 			xfrm_seq_parse(&req.xspi.info.seq, &argc, &argv);
741 		} else if (strcmp(*argv, "min") == 0) {
742 			if (minp)
743 				duparg("min", *argv);
744 			minp = *argv;
745 
746 			NEXT_ARG();
747 
748 			if (get_u32(&req.xspi.min, *argv, 0))
749 				invarg("value after \"min\" is invalid", *argv);
750 		} else if (strcmp(*argv, "max") == 0) {
751 			if (maxp)
752 				duparg("max", *argv);
753 			maxp = *argv;
754 
755 			NEXT_ARG();
756 
757 			if (get_u32(&req.xspi.max, *argv, 0))
758 				invarg("value after \"max\" is invalid", *argv);
759 		} else {
760 			/* try to assume ID */
761 			if (idp)
762 				invarg("unknown", *argv);
763 			idp = *argv;
764 
765 			/* ID */
766 			xfrm_id_parse(&req.xspi.info.saddr, &req.xspi.info.id,
767 				      &req.xspi.info.family, 0, &argc, &argv);
768 			if (req.xspi.info.id.spi) {
769 				fprintf(stderr, "\"spi\" is invalid\n");
770 				exit(1);
771 			}
772 			if (preferred_family == AF_UNSPEC)
773 				preferred_family = req.xspi.info.family;
774 		}
775 		argc--; argv++;
776 	}
777 
778 	if (!idp) {
779 		fprintf(stderr, "Not enough information: ID is required\n");
780 		exit(1);
781 	}
782 
783 	if (minp) {
784 		if (!maxp) {
785 			fprintf(stderr, "\"max\" is missing\n");
786 			exit(1);
787 		}
788 		if (req.xspi.min > req.xspi.max) {
789 			fprintf(stderr, "value after \"min\" is larger than value after \"max\"\n");
790 			exit(1);
791 		}
792 	} else {
793 		if (maxp) {
794 			fprintf(stderr, "\"min\" is missing\n");
795 			exit(1);
796 		}
797 
798 		/* XXX: Default value defined in PF_KEY;
799 		 * See kernel's net/key/af_key.c(pfkey_getspi).
800 		 */
801 		req.xspi.min = 0x100;
802 		req.xspi.max = 0x0fffffff;
803 
804 		/* XXX: IPCOMP spi is 16-bits;
805 		 * See kernel's net/xfrm/xfrm_user(verify_userspi_info).
806 		 */
807 		if (req.xspi.info.id.proto == IPPROTO_COMP)
808 			req.xspi.max = 0xffff;
809 	}
810 
811 	if (mark.m & mark.v) {
812 		int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK,
813 				  (void *)&mark, sizeof(mark));
814 		if (r < 0) {
815 			fprintf(stderr, "XFRMA_MARK failed\n");
816 			exit(1);
817 		}
818 	}
819 
820 	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
821 		exit(1);
822 
823 	if (req.xspi.info.family == AF_UNSPEC)
824 		req.xspi.info.family = AF_INET;
825 
826 
827 	if (rtnl_talk(&rth, &req.n, res_n, sizeof(res_buf)) < 0)
828 		exit(2);
829 
830 	if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
831 		fprintf(stderr, "An error :-)\n");
832 		exit(1);
833 	}
834 
835 	rtnl_close(&rth);
836 
837 	return 0;
838 }
839 
xfrm_state_filter_match(struct xfrm_usersa_info * xsinfo)840 static int xfrm_state_filter_match(struct xfrm_usersa_info *xsinfo)
841 {
842 	if (!filter.use)
843 		return 1;
844 
845 	if (filter.id_src_mask)
846 		if (xfrm_addr_match(&xsinfo->saddr, &filter.xsinfo.saddr,
847 				    filter.id_src_mask))
848 			return 0;
849 	if (filter.id_dst_mask)
850 		if (xfrm_addr_match(&xsinfo->id.daddr, &filter.xsinfo.id.daddr,
851 				    filter.id_dst_mask))
852 			return 0;
853 	if ((xsinfo->id.proto^filter.xsinfo.id.proto)&filter.id_proto_mask)
854 		return 0;
855 	if ((xsinfo->id.spi^filter.xsinfo.id.spi)&filter.id_spi_mask)
856 		return 0;
857 	if ((xsinfo->mode^filter.xsinfo.mode)&filter.mode_mask)
858 		return 0;
859 	if ((xsinfo->reqid^filter.xsinfo.reqid)&filter.reqid_mask)
860 		return 0;
861 	if (filter.state_flags_mask)
862 		if ((xsinfo->flags & filter.xsinfo.flags) == 0)
863 			return 0;
864 
865 	return 1;
866 }
867 
xfrm_state_print(const struct sockaddr_nl * who,struct nlmsghdr * n,void * arg)868 int xfrm_state_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
869 		     void *arg)
870 {
871 	FILE *fp = (FILE*)arg;
872 	struct rtattr * tb[XFRMA_MAX+1];
873 	struct rtattr * rta;
874 	struct xfrm_usersa_info *xsinfo = NULL;
875 	struct xfrm_user_expire *xexp = NULL;
876 	struct xfrm_usersa_id	*xsid = NULL;
877 	int len = n->nlmsg_len;
878 
879 	if (n->nlmsg_type != XFRM_MSG_NEWSA &&
880 	    n->nlmsg_type != XFRM_MSG_DELSA &&
881 	    n->nlmsg_type != XFRM_MSG_UPDSA &&
882 	    n->nlmsg_type != XFRM_MSG_EXPIRE) {
883 		fprintf(stderr, "Not a state: %08x %08x %08x\n",
884 			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
885 		return 0;
886 	}
887 
888 	if (n->nlmsg_type == XFRM_MSG_DELSA) {
889 		/* Dont blame me for this .. Herbert made me do it */
890 		xsid = NLMSG_DATA(n);
891 		len -= NLMSG_SPACE(sizeof(*xsid));
892 	} else if (n->nlmsg_type == XFRM_MSG_EXPIRE) {
893 		xexp = NLMSG_DATA(n);
894 		xsinfo = &xexp->state;
895 		len -= NLMSG_SPACE(sizeof(*xexp));
896 	} else {
897 		xexp = NULL;
898 		xsinfo = NLMSG_DATA(n);
899 		len -= NLMSG_SPACE(sizeof(*xsinfo));
900 	}
901 
902 	if (len < 0) {
903 		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
904 		return -1;
905 	}
906 
907 	if (xsinfo && !xfrm_state_filter_match(xsinfo))
908 		return 0;
909 
910 	if (n->nlmsg_type == XFRM_MSG_DELSA)
911 		fprintf(fp, "Deleted ");
912 	else if (n->nlmsg_type == XFRM_MSG_UPDSA)
913 		fprintf(fp, "Updated ");
914 	else if (n->nlmsg_type == XFRM_MSG_EXPIRE)
915 		fprintf(fp, "Expired ");
916 
917 	if (n->nlmsg_type == XFRM_MSG_DELSA)
918 		rta = XFRMSID_RTA(xsid);
919 	else if (n->nlmsg_type == XFRM_MSG_EXPIRE)
920 		rta = XFRMEXP_RTA(xexp);
921 	else
922 		rta = XFRMS_RTA(xsinfo);
923 
924 	parse_rtattr(tb, XFRMA_MAX, rta, len);
925 
926 	if (n->nlmsg_type == XFRM_MSG_DELSA) {
927 		//xfrm_policy_id_print();
928 
929 		if (!tb[XFRMA_SA]) {
930 			fprintf(stderr, "Buggy XFRM_MSG_DELSA: no XFRMA_SA\n");
931 			return -1;
932 		}
933 		if (RTA_PAYLOAD(tb[XFRMA_SA]) < sizeof(*xsinfo)) {
934 			fprintf(stderr, "Buggy XFRM_MSG_DELPOLICY: too short XFRMA_POLICY len\n");
935 			return -1;
936 		}
937 		xsinfo = RTA_DATA(tb[XFRMA_SA]);
938 	}
939 
940 	xfrm_state_info_print(xsinfo, tb, fp, NULL, NULL);
941 
942 	if (n->nlmsg_type == XFRM_MSG_EXPIRE) {
943 		fprintf(fp, "\t");
944 		fprintf(fp, "hard %u", xexp->hard);
945 		fprintf(fp, "%s", _SL_);
946 	}
947 
948 	if (oneline)
949 		fprintf(fp, "\n");
950 	fflush(fp);
951 
952 	return 0;
953 }
954 
xfrm_state_get_or_delete(int argc,char ** argv,int delete)955 static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
956 {
957 	struct rtnl_handle rth;
958 	struct {
959 		struct nlmsghdr	n;
960 		struct xfrm_usersa_id	xsid;
961 		char  			buf[RTA_BUF_SIZE];
962 	} req;
963 	struct xfrm_id id;
964 	char *idp = NULL;
965 	struct xfrm_mark mark = {0, 0};
966 
967 	memset(&req, 0, sizeof(req));
968 
969 	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsid));
970 	req.n.nlmsg_flags = NLM_F_REQUEST;
971 	req.n.nlmsg_type = delete ? XFRM_MSG_DELSA : XFRM_MSG_GETSA;
972 	req.xsid.family = preferred_family;
973 
974 	while (argc > 0) {
975 		xfrm_address_t saddr;
976 
977 		if (strcmp(*argv, "mark") == 0) {
978 			xfrm_parse_mark(&mark, &argc, &argv);
979 		} else {
980 			if (idp)
981 				invarg("unknown", *argv);
982 			idp = *argv;
983 
984 			/* ID */
985 			memset(&id, 0, sizeof(id));
986 			memset(&saddr, 0, sizeof(saddr));
987 			xfrm_id_parse(&saddr, &id, &req.xsid.family, 0,
988 				      &argc, &argv);
989 
990 			memcpy(&req.xsid.daddr, &id.daddr, sizeof(req.xsid.daddr));
991 			req.xsid.spi = id.spi;
992 			req.xsid.proto = id.proto;
993 
994 			addattr_l(&req.n, sizeof(req.buf), XFRMA_SRCADDR,
995 				  (void *)&saddr, sizeof(saddr));
996 		}
997 
998 		argc--; argv++;
999 	}
1000 
1001 	if (mark.m & mark.v) {
1002 		int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK,
1003 				  (void *)&mark, sizeof(mark));
1004 		if (r < 0) {
1005 			fprintf(stderr, "XFRMA_MARK failed\n");
1006 			exit(1);
1007 		}
1008 	}
1009 
1010 	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
1011 		exit(1);
1012 
1013 	if (req.xsid.family == AF_UNSPEC)
1014 		req.xsid.family = AF_INET;
1015 
1016 	if (delete) {
1017 		if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
1018 			exit(2);
1019 	} else {
1020 		char buf[NLMSG_BUF_SIZE];
1021 		struct nlmsghdr *res_n = (struct nlmsghdr *)buf;
1022 
1023 		memset(buf, 0, sizeof(buf));
1024 
1025 		if (rtnl_talk(&rth, &req.n, res_n, sizeof(req)) < 0)
1026 			exit(2);
1027 
1028 		if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
1029 			fprintf(stderr, "An error :-)\n");
1030 			exit(1);
1031 		}
1032 	}
1033 
1034 	rtnl_close(&rth);
1035 
1036 	return 0;
1037 }
1038 
1039 /*
1040  * With an existing state of nlmsg, make new nlmsg for deleting the state
1041  * and store it to buffer.
1042  */
xfrm_state_keep(const struct sockaddr_nl * who,struct nlmsghdr * n,void * arg)1043 static int xfrm_state_keep(const struct sockaddr_nl *who,
1044 			   struct nlmsghdr *n,
1045 			   void *arg)
1046 {
1047 	struct xfrm_buffer *xb = (struct xfrm_buffer *)arg;
1048 	struct rtnl_handle *rth = xb->rth;
1049 	struct xfrm_usersa_info *xsinfo = NLMSG_DATA(n);
1050 	int len = n->nlmsg_len;
1051 	struct nlmsghdr *new_n;
1052 	struct xfrm_usersa_id *xsid;
1053 
1054 	if (n->nlmsg_type != XFRM_MSG_NEWSA) {
1055 		fprintf(stderr, "Not a state: %08x %08x %08x\n",
1056 			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
1057 		return 0;
1058 	}
1059 
1060 	len -= NLMSG_LENGTH(sizeof(*xsinfo));
1061 	if (len < 0) {
1062 		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
1063 		return -1;
1064 	}
1065 
1066 	if (!xfrm_state_filter_match(xsinfo))
1067 		return 0;
1068 
1069 	if (xb->offset > xb->size) {
1070 		fprintf(stderr, "State buffer overflow\n");
1071 		return -1;
1072 	}
1073 
1074 	new_n = (struct nlmsghdr *)(xb->buf + xb->offset);
1075 	new_n->nlmsg_len = NLMSG_LENGTH(sizeof(*xsid));
1076 	new_n->nlmsg_flags = NLM_F_REQUEST;
1077 	new_n->nlmsg_type = XFRM_MSG_DELSA;
1078 	new_n->nlmsg_seq = ++rth->seq;
1079 
1080 	xsid = NLMSG_DATA(new_n);
1081 	xsid->family = xsinfo->family;
1082 	memcpy(&xsid->daddr, &xsinfo->id.daddr, sizeof(xsid->daddr));
1083 	xsid->spi = xsinfo->id.spi;
1084 	xsid->proto = xsinfo->id.proto;
1085 
1086 	addattr_l(new_n, xb->size, XFRMA_SRCADDR, &xsinfo->saddr,
1087 		  sizeof(xsid->daddr));
1088 
1089 	xb->offset += new_n->nlmsg_len;
1090 	xb->nlmsg_count ++;
1091 
1092 	return 0;
1093 }
1094 
xfrm_state_list_or_deleteall(int argc,char ** argv,int deleteall)1095 static int xfrm_state_list_or_deleteall(int argc, char **argv, int deleteall)
1096 {
1097 	char *idp = NULL;
1098 	struct rtnl_handle rth;
1099 
1100 	if(argc > 0)
1101 		filter.use = 1;
1102 	filter.xsinfo.family = preferred_family;
1103 
1104 	while (argc > 0) {
1105 		if (strcmp(*argv, "mode") == 0) {
1106 			NEXT_ARG();
1107 			xfrm_mode_parse(&filter.xsinfo.mode, &argc, &argv);
1108 
1109 			filter.mode_mask = XFRM_FILTER_MASK_FULL;
1110 
1111 		} else if (strcmp(*argv, "reqid") == 0) {
1112 			NEXT_ARG();
1113 			xfrm_reqid_parse(&filter.xsinfo.reqid, &argc, &argv);
1114 
1115 			filter.reqid_mask = XFRM_FILTER_MASK_FULL;
1116 
1117 		} else if (strcmp(*argv, "flag") == 0) {
1118 			NEXT_ARG();
1119 			xfrm_state_flag_parse(&filter.xsinfo.flags, &argc, &argv);
1120 
1121 			filter.state_flags_mask = XFRM_FILTER_MASK_FULL;
1122 
1123 		} else {
1124 			if (idp)
1125 				invarg("unknown", *argv);
1126 			idp = *argv;
1127 
1128 			/* ID */
1129 			xfrm_id_parse(&filter.xsinfo.saddr, &filter.xsinfo.id,
1130 				      &filter.xsinfo.family, 1, &argc, &argv);
1131 			if (preferred_family == AF_UNSPEC)
1132 				preferred_family = filter.xsinfo.family;
1133 		}
1134 		argc--; argv++;
1135 	}
1136 
1137 	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
1138 		exit(1);
1139 
1140 	if (deleteall) {
1141 		struct xfrm_buffer xb;
1142 		char buf[NLMSG_DELETEALL_BUF_SIZE];
1143 		int i;
1144 
1145 		xb.buf = buf;
1146 		xb.size = sizeof(buf);
1147 		xb.rth = &rth;
1148 
1149 		for (i = 0; ; i++) {
1150 			struct {
1151 				struct nlmsghdr n;
1152 				char buf[NLMSG_BUF_SIZE];
1153 			} req = {
1154 				.n.nlmsg_len = NLMSG_HDRLEN,
1155 				.n.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
1156 				.n.nlmsg_type = XFRM_MSG_GETSA,
1157 				.n.nlmsg_seq = rth.dump = ++rth.seq,
1158 			};
1159 
1160 			xb.offset = 0;
1161 			xb.nlmsg_count = 0;
1162 
1163 			if (show_stats > 1)
1164 				fprintf(stderr, "Delete-all round = %d\n", i);
1165 
1166 			if (rtnl_send(&rth, (void *)&req, req.n.nlmsg_len) < 0) {
1167 				perror("Cannot send dump request");
1168 				exit(1);
1169 			}
1170 
1171 			if (rtnl_dump_filter(&rth, xfrm_state_keep, &xb) < 0) {
1172 				fprintf(stderr, "Delete-all terminated\n");
1173 				exit(1);
1174 			}
1175 			if (xb.nlmsg_count == 0) {
1176 				if (show_stats > 1)
1177 					fprintf(stderr, "Delete-all completed\n");
1178 				break;
1179 			}
1180 
1181 			if (rtnl_send_check(&rth, xb.buf, xb.offset) < 0) {
1182 				perror("Failed to send delete-all request\n");
1183 				exit(1);
1184 			}
1185 			if (show_stats > 1)
1186 				fprintf(stderr, "Delete-all nlmsg count = %d\n", xb.nlmsg_count);
1187 
1188 			xb.offset = 0;
1189 			xb.nlmsg_count = 0;
1190 		}
1191 
1192 	} else {
1193 		struct xfrm_address_filter addrfilter = {
1194 			.saddr = filter.xsinfo.saddr,
1195 			.daddr = filter.xsinfo.id.daddr,
1196 			.family = filter.xsinfo.family,
1197 			.splen = filter.id_src_mask,
1198 			.dplen = filter.id_dst_mask,
1199 		};
1200 		struct {
1201 			struct nlmsghdr n;
1202 			char buf[NLMSG_BUF_SIZE];
1203 		} req = {
1204 			.n.nlmsg_len = NLMSG_HDRLEN,
1205 			.n.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
1206 			.n.nlmsg_type = XFRM_MSG_GETSA,
1207 			.n.nlmsg_seq = rth.dump = ++rth.seq,
1208 		};
1209 
1210 		if (filter.xsinfo.id.proto)
1211 			addattr8(&req.n, sizeof(req), XFRMA_PROTO,
1212 				 filter.xsinfo.id.proto);
1213 		addattr_l(&req.n, sizeof(req), XFRMA_ADDRESS_FILTER,
1214 			  &addrfilter, sizeof(addrfilter));
1215 
1216 		if (rtnl_send(&rth, (void *)&req, req.n.nlmsg_len) < 0) {
1217 			perror("Cannot send dump request");
1218 			exit(1);
1219 		}
1220 
1221 		if (rtnl_dump_filter(&rth, xfrm_state_print, stdout) < 0) {
1222 			fprintf(stderr, "Dump terminated\n");
1223 			exit(1);
1224 		}
1225 	}
1226 
1227 	rtnl_close(&rth);
1228 
1229 	exit(0);
1230 }
1231 
print_sadinfo(struct nlmsghdr * n,void * arg)1232 static int print_sadinfo(struct nlmsghdr *n, void *arg)
1233 {
1234 	FILE *fp = (FILE*)arg;
1235 	__u32 *f = NLMSG_DATA(n);
1236 	struct rtattr *tb[XFRMA_SAD_MAX+1];
1237 	struct rtattr *rta;
1238 	__u32 *cnt;
1239 
1240 	int len = n->nlmsg_len;
1241 
1242 	len -= NLMSG_LENGTH(sizeof(__u32));
1243 	if (len < 0) {
1244 		fprintf(stderr, "SADinfo: Wrong len %d\n", len);
1245 		return -1;
1246 	}
1247 
1248 	rta = XFRMSAPD_RTA(f);
1249 	parse_rtattr(tb, XFRMA_SAD_MAX, rta, len);
1250 
1251 	if (tb[XFRMA_SAD_CNT]) {
1252 		fprintf(fp,"\t SAD");
1253 		cnt = (__u32 *)RTA_DATA(tb[XFRMA_SAD_CNT]);
1254 		fprintf(fp," count %d", *cnt);
1255 	} else {
1256 		fprintf(fp,"BAD SAD info returned\n");
1257 		return -1;
1258 	}
1259 
1260 	if (show_stats) {
1261 		if (tb[XFRMA_SAD_HINFO]) {
1262 			struct xfrmu_sadhinfo *si;
1263 
1264 			if (RTA_PAYLOAD(tb[XFRMA_SAD_HINFO]) < sizeof(*si)) {
1265 				fprintf(fp,"BAD SAD length returned\n");
1266 				return -1;
1267 			}
1268 
1269 			si = RTA_DATA(tb[XFRMA_SAD_HINFO]);
1270 			fprintf(fp," (buckets ");
1271 			fprintf(fp,"count %d", si->sadhcnt);
1272 			fprintf(fp," Max %d", si->sadhmcnt);
1273 			fprintf(fp,")");
1274 		}
1275 	}
1276 	fprintf(fp,"\n");
1277 
1278         return 0;
1279 }
1280 
xfrm_sad_getinfo(int argc,char ** argv)1281 static int xfrm_sad_getinfo(int argc, char **argv)
1282 {
1283 	struct rtnl_handle rth;
1284 	struct {
1285 		struct nlmsghdr			n;
1286 		__u32				flags;
1287 		char				ans[64];
1288 	} req;
1289 
1290 	memset(&req, 0, sizeof(req));
1291 	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.flags));
1292 	req.n.nlmsg_flags = NLM_F_REQUEST;
1293 	req.n.nlmsg_type = XFRM_MSG_GETSADINFO;
1294 	req.flags = 0XFFFFFFFF;
1295 
1296 	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
1297 		exit(1);
1298 
1299 	if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
1300 		exit(2);
1301 
1302 	print_sadinfo(&req.n, (void*)stdout);
1303 
1304 	rtnl_close(&rth);
1305 
1306 	return 0;
1307 }
1308 
xfrm_state_flush(int argc,char ** argv)1309 static int xfrm_state_flush(int argc, char **argv)
1310 {
1311 	struct rtnl_handle rth;
1312 	struct {
1313 		struct nlmsghdr			n;
1314 		struct xfrm_usersa_flush	xsf;
1315 	} req;
1316 	char *protop = NULL;
1317 
1318 	memset(&req, 0, sizeof(req));
1319 
1320 	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsf));
1321 	req.n.nlmsg_flags = NLM_F_REQUEST;
1322 	req.n.nlmsg_type = XFRM_MSG_FLUSHSA;
1323 	req.xsf.proto = 0;
1324 
1325 	while (argc > 0) {
1326 		if (strcmp(*argv, "proto") == 0) {
1327 			int ret;
1328 
1329 			if (protop)
1330 				duparg("proto", *argv);
1331 			protop = *argv;
1332 
1333 			NEXT_ARG();
1334 
1335 			ret = xfrm_xfrmproto_getbyname(*argv);
1336 			if (ret < 0)
1337 				invarg("XFRM-PROTO value is invalid", *argv);
1338 
1339 			req.xsf.proto = (__u8)ret;
1340 		} else
1341 			invarg("unknown", *argv);
1342 
1343 		argc--; argv++;
1344 	}
1345 
1346 	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
1347 		exit(1);
1348 
1349 	if (show_stats > 1)
1350 		fprintf(stderr, "Flush state with XFRM-PROTO value \"%s\"\n",
1351 			strxf_xfrmproto(req.xsf.proto));
1352 
1353 	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
1354 		exit(2);
1355 
1356 	rtnl_close(&rth);
1357 
1358 	return 0;
1359 }
1360 
do_xfrm_state(int argc,char ** argv)1361 int do_xfrm_state(int argc, char **argv)
1362 {
1363 	if (argc < 1)
1364 		return xfrm_state_list_or_deleteall(0, NULL, 0);
1365 
1366 	if (matches(*argv, "add") == 0)
1367 		return xfrm_state_modify(XFRM_MSG_NEWSA, 0,
1368 					 argc-1, argv+1);
1369 	if (matches(*argv, "update") == 0)
1370 		return xfrm_state_modify(XFRM_MSG_UPDSA, 0,
1371 					 argc-1, argv+1);
1372 	if (matches(*argv, "allocspi") == 0)
1373 		return xfrm_state_allocspi(argc-1, argv+1);
1374 	if (matches(*argv, "delete") == 0)
1375 		return xfrm_state_get_or_delete(argc-1, argv+1, 1);
1376 	if (matches(*argv, "deleteall") == 0 || matches(*argv, "delall") == 0)
1377 		return xfrm_state_list_or_deleteall(argc-1, argv+1, 1);
1378 	if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
1379 	    || matches(*argv, "lst") == 0)
1380 		return xfrm_state_list_or_deleteall(argc-1, argv+1, 0);
1381 	if (matches(*argv, "get") == 0)
1382 		return xfrm_state_get_or_delete(argc-1, argv+1, 0);
1383 	if (matches(*argv, "flush") == 0)
1384 		return xfrm_state_flush(argc-1, argv+1);
1385 	if (matches(*argv, "count") == 0) {
1386 		return xfrm_sad_getinfo(argc, argv);
1387 	}
1388 	if (matches(*argv, "help") == 0)
1389 		usage();
1390 	fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm state help\".\n", *argv);
1391 	exit(-1);
1392 }
1393