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