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