xfrm_state.c revision dc8867d0ff6202559c05a8fb8f7c16829360af28
1/* $USAGI: $ */ 2 3/* 4 * Copyright (C)2004 USAGI/WIDE Project 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20/* 21 * based on iproute.c 22 */ 23/* 24 * Authors: 25 * Masahide NAKAMURA @USAGI 26 */ 27 28#include <stdio.h> 29#include <stdlib.h> 30#include <string.h> 31#include <netdb.h> 32#include <linux/xfrm.h> 33#include "utils.h" 34#include "xfrm.h" 35#include "ip_common.h" 36 37//#define NLMSG_DELETEALL_BUF_SIZE (4096-512) 38#define NLMSG_DELETEALL_BUF_SIZE 8192 39 40/* 41 * Receiving buffer defines: 42 * nlmsg 43 * data = struct xfrm_usersa_info 44 * rtattr 45 * rtattr 46 * ... (max count of rtattr is XFRM_MAX+1 47 * 48 * each rtattr data = struct xfrm_algo(dynamic size) or xfrm_address_t 49 */ 50#define NLMSG_BUF_SIZE 4096 51#define RTA_BUF_SIZE 2048 52#define XFRM_ALGO_KEY_BUF_SIZE 512 53#define CTX_BUF_SIZE 256 54 55static void usage(void) __attribute__((noreturn)); 56 57static void usage(void) 58{ 59 fprintf(stderr, "Usage: ip xfrm state { add | update } ID [ ALGO-LIST ] [ mode MODE ]\n"); 60 fprintf(stderr, " [ mark MARK [ mask MASK ] ] [ reqid REQID ] [ seq SEQ ]\n"); 61 fprintf(stderr, " [ replay-window SIZE ] [ replay-seq SEQ ] [ replay-oseq 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\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 116static 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 strncpy(buf, key, len); 166 } 167 } 168 169 alg->alg_key_len = len * 8; 170 171 return 0; 172} 173 174static 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 190static 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 { 219 PREV_ARG(); /* back track */ 220 break; 221 } 222 223 if (!NEXT_ARG_OK()) 224 break; 225 NEXT_ARG(); 226 } 227 } 228 229 *argcp = argc; 230 *argvp = argv; 231 232 return 0; 233} 234 235static int xfrm_state_extra_flag_parse(__u32 *extra_flags, int *argcp, char ***argvp) 236{ 237 int argc = *argcp; 238 char **argv = *argvp; 239 int len = strlen(*argv); 240 241 if (len > 2 && strncmp(*argv, "0x", 2) == 0) { 242 __u32 val = 0; 243 244 if (get_u32(&val, *argv, 16)) 245 invarg("\"EXTRA-FLAG\" is invalid", *argv); 246 *extra_flags = val; 247 } else { 248 while (1) { 249 if (strcmp(*argv, "dont-encap-dscp") == 0) 250 *extra_flags |= XFRM_SA_XFLAG_DONT_ENCAP_DSCP; 251 else { 252 PREV_ARG(); /* back track */ 253 break; 254 } 255 256 if (!NEXT_ARG_OK()) 257 break; 258 NEXT_ARG(); 259 } 260 } 261 262 *argcp = argc; 263 *argvp = argv; 264 265 return 0; 266} 267 268static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv) 269{ 270 struct rtnl_handle rth; 271 struct { 272 struct nlmsghdr n; 273 struct xfrm_usersa_info xsinfo; 274 char buf[RTA_BUF_SIZE]; 275 } req; 276 struct xfrm_replay_state replay; 277 char *idp = NULL; 278 char *aeadop = NULL; 279 char *ealgop = NULL; 280 char *aalgop = NULL; 281 char *calgop = NULL; 282 char *coap = NULL; 283 char *sctxp = NULL; 284 __u32 extra_flags = 0; 285 struct xfrm_mark mark = {0, 0}; 286 struct { 287 struct xfrm_user_sec_ctx sctx; 288 char str[CTX_BUF_SIZE]; 289 } ctx; 290 291 memset(&req, 0, sizeof(req)); 292 memset(&replay, 0, sizeof(replay)); 293 memset(&ctx, 0, sizeof(ctx)); 294 295 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo)); 296 req.n.nlmsg_flags = NLM_F_REQUEST|flags; 297 req.n.nlmsg_type = cmd; 298 req.xsinfo.family = preferred_family; 299 300 req.xsinfo.lft.soft_byte_limit = XFRM_INF; 301 req.xsinfo.lft.hard_byte_limit = XFRM_INF; 302 req.xsinfo.lft.soft_packet_limit = XFRM_INF; 303 req.xsinfo.lft.hard_packet_limit = XFRM_INF; 304 305 while (argc > 0) { 306 if (strcmp(*argv, "mode") == 0) { 307 NEXT_ARG(); 308 xfrm_mode_parse(&req.xsinfo.mode, &argc, &argv); 309 } else if (strcmp(*argv, "mark") == 0) { 310 xfrm_parse_mark(&mark, &argc, &argv); 311 } else if (strcmp(*argv, "reqid") == 0) { 312 NEXT_ARG(); 313 xfrm_reqid_parse(&req.xsinfo.reqid, &argc, &argv); 314 } else if (strcmp(*argv, "seq") == 0) { 315 NEXT_ARG(); 316 xfrm_seq_parse(&req.xsinfo.seq, &argc, &argv); 317 } else if (strcmp(*argv, "replay-window") == 0) { 318 NEXT_ARG(); 319 if (get_u8(&req.xsinfo.replay_window, *argv, 0)) 320 invarg("value after \"replay-window\" is invalid", *argv); 321 } else if (strcmp(*argv, "replay-seq") == 0) { 322 NEXT_ARG(); 323 if (get_u32(&replay.seq, *argv, 0)) 324 invarg("value after \"replay-seq\" is invalid", *argv); 325 } else if (strcmp(*argv, "replay-oseq") == 0) { 326 NEXT_ARG(); 327 if (get_u32(&replay.oseq, *argv, 0)) 328 invarg("value after \"replay-oseq\" is invalid", *argv); 329 } else if (strcmp(*argv, "flag") == 0) { 330 NEXT_ARG(); 331 xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv); 332 } else if (strcmp(*argv, "extra-flag") == 0) { 333 NEXT_ARG(); 334 xfrm_state_extra_flag_parse(&extra_flags, &argc, &argv); 335 } else if (strcmp(*argv, "sel") == 0) { 336 NEXT_ARG(); 337 preferred_family = AF_UNSPEC; 338 xfrm_selector_parse(&req.xsinfo.sel, &argc, &argv); 339 preferred_family = req.xsinfo.sel.family; 340 } else if (strcmp(*argv, "limit") == 0) { 341 NEXT_ARG(); 342 xfrm_lifetime_cfg_parse(&req.xsinfo.lft, &argc, &argv); 343 } else if (strcmp(*argv, "encap") == 0) { 344 struct xfrm_encap_tmpl encap; 345 inet_prefix oa; 346 NEXT_ARG(); 347 xfrm_encap_type_parse(&encap.encap_type, &argc, &argv); 348 NEXT_ARG(); 349 if (get_u16(&encap.encap_sport, *argv, 0)) 350 invarg("SPORT value after \"encap\" is invalid", *argv); 351 encap.encap_sport = htons(encap.encap_sport); 352 NEXT_ARG(); 353 if (get_u16(&encap.encap_dport, *argv, 0)) 354 invarg("DPORT value after \"encap\" is invalid", *argv); 355 encap.encap_dport = htons(encap.encap_dport); 356 NEXT_ARG(); 357 get_addr(&oa, *argv, AF_UNSPEC); 358 memcpy(&encap.encap_oa, &oa.data, sizeof(encap.encap_oa)); 359 addattr_l(&req.n, sizeof(req.buf), XFRMA_ENCAP, 360 (void *)&encap, sizeof(encap)); 361 } else if (strcmp(*argv, "coa") == 0) { 362 inet_prefix coa; 363 xfrm_address_t xcoa; 364 365 if (coap) 366 duparg("coa", *argv); 367 coap = *argv; 368 369 NEXT_ARG(); 370 371 get_prefix(&coa, *argv, preferred_family); 372 if (coa.family == AF_UNSPEC) 373 invarg("value after \"coa\" has an unrecognized address family", *argv); 374 if (coa.bytelen > sizeof(xcoa)) 375 invarg("value after \"coa\" is too large", *argv); 376 377 memset(&xcoa, 0, sizeof(xcoa)); 378 memcpy(&xcoa, &coa.data, coa.bytelen); 379 380 addattr_l(&req.n, sizeof(req.buf), XFRMA_COADDR, 381 (void *)&xcoa, sizeof(xcoa)); 382 } else if (strcmp(*argv, "ctx") == 0) { 383 char *context; 384 385 if (sctxp) 386 duparg("ctx", *argv); 387 sctxp = *argv; 388 389 NEXT_ARG(); 390 context = *argv; 391 392 xfrm_sctx_parse((char *)&ctx.str, context, &ctx.sctx); 393 addattr_l(&req.n, sizeof(req.buf), XFRMA_SEC_CTX, 394 (void *)&ctx, ctx.sctx.len); 395 } else { 396 /* try to assume ALGO */ 397 int type = xfrm_algotype_getbyname(*argv); 398 switch (type) { 399 case XFRMA_ALG_AEAD: 400 case XFRMA_ALG_CRYPT: 401 case XFRMA_ALG_AUTH: 402 case XFRMA_ALG_AUTH_TRUNC: 403 case XFRMA_ALG_COMP: 404 { 405 /* ALGO */ 406 struct { 407 union { 408 struct xfrm_algo alg; 409 struct xfrm_algo_aead aead; 410 struct xfrm_algo_auth auth; 411 } u; 412 char buf[XFRM_ALGO_KEY_BUF_SIZE]; 413 } alg = {}; 414 int len; 415 __u32 icvlen, trunclen; 416 char *name; 417 char *key = ""; 418 char *buf; 419 420 switch (type) { 421 case XFRMA_ALG_AEAD: 422 if (ealgop || aalgop || aeadop) 423 duparg("ALGO-TYPE", *argv); 424 aeadop = *argv; 425 break; 426 case XFRMA_ALG_CRYPT: 427 if (ealgop || aeadop) 428 duparg("ALGO-TYPE", *argv); 429 ealgop = *argv; 430 break; 431 case XFRMA_ALG_AUTH: 432 case XFRMA_ALG_AUTH_TRUNC: 433 if (aalgop || aeadop) 434 duparg("ALGO-TYPE", *argv); 435 aalgop = *argv; 436 break; 437 case XFRMA_ALG_COMP: 438 if (calgop) 439 duparg("ALGO-TYPE", *argv); 440 calgop = *argv; 441 break; 442 default: 443 /* not reached */ 444 invarg("ALGO-TYPE value is invalid\n", *argv); 445 } 446 447 if (!NEXT_ARG_OK()) 448 missarg("ALGO-NAME"); 449 NEXT_ARG(); 450 name = *argv; 451 452 switch (type) { 453 case XFRMA_ALG_AEAD: 454 case XFRMA_ALG_CRYPT: 455 case XFRMA_ALG_AUTH: 456 case XFRMA_ALG_AUTH_TRUNC: 457 if (!NEXT_ARG_OK()) 458 missarg("ALGO-KEYMAT"); 459 NEXT_ARG(); 460 key = *argv; 461 break; 462 } 463 464 buf = alg.u.alg.alg_key; 465 len = sizeof(alg.u.alg); 466 467 switch (type) { 468 case XFRMA_ALG_AEAD: 469 if (!NEXT_ARG_OK()) 470 missarg("ALGO-ICV-LEN"); 471 NEXT_ARG(); 472 if (get_u32(&icvlen, *argv, 0)) 473 invarg("ALGO-ICV-LEN value is invalid", 474 *argv); 475 alg.u.aead.alg_icv_len = icvlen; 476 477 buf = alg.u.aead.alg_key; 478 len = sizeof(alg.u.aead); 479 break; 480 case XFRMA_ALG_AUTH_TRUNC: 481 if (!NEXT_ARG_OK()) 482 missarg("ALGO-TRUNC-LEN"); 483 NEXT_ARG(); 484 if (get_u32(&trunclen, *argv, 0)) 485 invarg("ALGO-TRUNC-LEN value is invalid", 486 *argv); 487 alg.u.auth.alg_trunc_len = trunclen; 488 489 buf = alg.u.auth.alg_key; 490 len = sizeof(alg.u.auth); 491 break; 492 } 493 494 xfrm_algo_parse((void *)&alg, type, name, key, 495 buf, sizeof(alg.buf)); 496 len += alg.u.alg.alg_key_len; 497 498 addattr_l(&req.n, sizeof(req.buf), type, 499 (void *)&alg, len); 500 break; 501 } 502 default: 503 /* try to assume ID */ 504 if (idp) 505 invarg("unknown", *argv); 506 idp = *argv; 507 508 /* ID */ 509 xfrm_id_parse(&req.xsinfo.saddr, &req.xsinfo.id, 510 &req.xsinfo.family, 0, &argc, &argv); 511 if (preferred_family == AF_UNSPEC) 512 preferred_family = req.xsinfo.family; 513 } 514 } 515 argc--; argv++; 516 } 517 518 if (replay.seq || replay.oseq) 519 addattr_l(&req.n, sizeof(req.buf), XFRMA_REPLAY_VAL, 520 (void *)&replay, sizeof(replay)); 521 522 if (extra_flags) 523 addattr32(&req.n, sizeof(req.buf), XFRMA_SA_EXTRA_FLAGS, 524 extra_flags); 525 526 if (!idp) { 527 fprintf(stderr, "Not enough information: ID is required\n"); 528 exit(1); 529 } 530 531 if (mark.m & mark.v) { 532 int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK, 533 (void *)&mark, sizeof(mark)); 534 if (r < 0) { 535 fprintf(stderr, "XFRMA_MARK failed\n"); 536 exit(1); 537 } 538 } 539 540 if (xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) { 541 switch (req.xsinfo.mode) { 542 case XFRM_MODE_TRANSPORT: 543 case XFRM_MODE_TUNNEL: 544 break; 545 case XFRM_MODE_BEET: 546 if (req.xsinfo.id.proto == IPPROTO_ESP) 547 break; 548 default: 549 fprintf(stderr, "MODE value is invalid with XFRM-PROTO value \"%s\"\n", 550 strxf_xfrmproto(req.xsinfo.id.proto)); 551 exit(1); 552 } 553 554 switch (req.xsinfo.id.proto) { 555 case IPPROTO_ESP: 556 if (calgop) { 557 fprintf(stderr, "ALGO-TYPE value \"%s\" is invalid with XFRM-PROTO value \"%s\"\n", 558 strxf_algotype(XFRMA_ALG_COMP), 559 strxf_xfrmproto(req.xsinfo.id.proto)); 560 exit(1); 561 } 562 if (!ealgop && !aeadop) { 563 fprintf(stderr, "ALGO-TYPE value \"%s\" or \"%s\" is required with XFRM-PROTO value \"%s\"\n", 564 strxf_algotype(XFRMA_ALG_CRYPT), 565 strxf_algotype(XFRMA_ALG_AEAD), 566 strxf_xfrmproto(req.xsinfo.id.proto)); 567 exit(1); 568 } 569 break; 570 case IPPROTO_AH: 571 if (ealgop || aeadop || calgop) { 572 fprintf(stderr, "ALGO-TYPE values \"%s\", \"%s\", and \"%s\" are invalid with XFRM-PROTO value \"%s\"\n", 573 strxf_algotype(XFRMA_ALG_CRYPT), 574 strxf_algotype(XFRMA_ALG_AEAD), 575 strxf_algotype(XFRMA_ALG_COMP), 576 strxf_xfrmproto(req.xsinfo.id.proto)); 577 exit(1); 578 } 579 if (!aalgop) { 580 fprintf(stderr, "ALGO-TYPE value \"%s\" or \"%s\" is required with XFRM-PROTO value \"%s\"\n", 581 strxf_algotype(XFRMA_ALG_AUTH), 582 strxf_algotype(XFRMA_ALG_AUTH_TRUNC), 583 strxf_xfrmproto(req.xsinfo.id.proto)); 584 exit(1); 585 } 586 break; 587 case IPPROTO_COMP: 588 if (ealgop || aalgop || aeadop) { 589 fprintf(stderr, "ALGO-TYPE values \"%s\", \"%s\", \"%s\", and \"%s\" are invalid with XFRM-PROTO value \"%s\"\n", 590 strxf_algotype(XFRMA_ALG_CRYPT), 591 strxf_algotype(XFRMA_ALG_AUTH), 592 strxf_algotype(XFRMA_ALG_AUTH_TRUNC), 593 strxf_algotype(XFRMA_ALG_AEAD), 594 strxf_xfrmproto(req.xsinfo.id.proto)); 595 exit(1); 596 } 597 if (!calgop) { 598 fprintf(stderr, "ALGO-TYPE value \"%s\" is required with XFRM-PROTO value \"%s\"\n", 599 strxf_algotype(XFRMA_ALG_COMP), 600 strxf_xfrmproto(req.xsinfo.id.proto)); 601 exit(1); 602 } 603 break; 604 } 605 } else { 606 if (ealgop || aalgop || aeadop || calgop) { 607 fprintf(stderr, "ALGO is invalid with XFRM-PROTO value \"%s\"\n", 608 strxf_xfrmproto(req.xsinfo.id.proto)); 609 exit(1); 610 } 611 } 612 613 if (xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) { 614 switch (req.xsinfo.mode) { 615 case XFRM_MODE_ROUTEOPTIMIZATION: 616 case XFRM_MODE_IN_TRIGGER: 617 break; 618 case 0: 619 fprintf(stderr, "\"mode\" is required with XFRM-PROTO value \"%s\"\n", 620 strxf_xfrmproto(req.xsinfo.id.proto)); 621 exit(1); 622 default: 623 fprintf(stderr, "MODE value is invalid with XFRM-PROTO value \"%s\"\n", 624 strxf_xfrmproto(req.xsinfo.id.proto)); 625 exit(1); 626 } 627 628 if (!coap) { 629 fprintf(stderr, "\"coa\" is required with XFRM-PROTO value \"%s\"\n", 630 strxf_xfrmproto(req.xsinfo.id.proto)); 631 exit(1); 632 } 633 } else { 634 if (coap) { 635 fprintf(stderr, "\"coa\" is invalid with XFRM-PROTO value \"%s\"\n", 636 strxf_xfrmproto(req.xsinfo.id.proto)); 637 exit(1); 638 } 639 } 640 641 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) 642 exit(1); 643 644 if (req.xsinfo.family == AF_UNSPEC) 645 req.xsinfo.family = AF_INET; 646 647 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) 648 exit(2); 649 650 rtnl_close(&rth); 651 652 return 0; 653} 654 655static int xfrm_state_allocspi(int argc, char **argv) 656{ 657 struct rtnl_handle rth; 658 struct { 659 struct nlmsghdr n; 660 struct xfrm_userspi_info xspi; 661 char buf[RTA_BUF_SIZE]; 662 } req; 663 char *idp = NULL; 664 char *minp = NULL; 665 char *maxp = NULL; 666 struct xfrm_mark mark = {0, 0}; 667 char res_buf[NLMSG_BUF_SIZE]; 668 struct nlmsghdr *res_n = (struct nlmsghdr *)res_buf; 669 670 memset(res_buf, 0, sizeof(res_buf)); 671 672 memset(&req, 0, sizeof(req)); 673 674 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xspi)); 675 req.n.nlmsg_flags = NLM_F_REQUEST; 676 req.n.nlmsg_type = XFRM_MSG_ALLOCSPI; 677 req.xspi.info.family = preferred_family; 678 679#if 0 680 req.xsinfo.lft.soft_byte_limit = XFRM_INF; 681 req.xsinfo.lft.hard_byte_limit = XFRM_INF; 682 req.xsinfo.lft.soft_packet_limit = XFRM_INF; 683 req.xsinfo.lft.hard_packet_limit = XFRM_INF; 684#endif 685 686 while (argc > 0) { 687 if (strcmp(*argv, "mode") == 0) { 688 NEXT_ARG(); 689 xfrm_mode_parse(&req.xspi.info.mode, &argc, &argv); 690 } else if (strcmp(*argv, "mark") == 0) { 691 xfrm_parse_mark(&mark, &argc, &argv); 692 } else if (strcmp(*argv, "reqid") == 0) { 693 NEXT_ARG(); 694 xfrm_reqid_parse(&req.xspi.info.reqid, &argc, &argv); 695 } else if (strcmp(*argv, "seq") == 0) { 696 NEXT_ARG(); 697 xfrm_seq_parse(&req.xspi.info.seq, &argc, &argv); 698 } else if (strcmp(*argv, "min") == 0) { 699 if (minp) 700 duparg("min", *argv); 701 minp = *argv; 702 703 NEXT_ARG(); 704 705 if (get_u32(&req.xspi.min, *argv, 0)) 706 invarg("value after \"min\" is invalid", *argv); 707 } else if (strcmp(*argv, "max") == 0) { 708 if (maxp) 709 duparg("max", *argv); 710 maxp = *argv; 711 712 NEXT_ARG(); 713 714 if (get_u32(&req.xspi.max, *argv, 0)) 715 invarg("value after \"max\" is invalid", *argv); 716 } else { 717 /* try to assume ID */ 718 if (idp) 719 invarg("unknown", *argv); 720 idp = *argv; 721 722 /* ID */ 723 xfrm_id_parse(&req.xspi.info.saddr, &req.xspi.info.id, 724 &req.xspi.info.family, 0, &argc, &argv); 725 if (req.xspi.info.id.spi) { 726 fprintf(stderr, "\"spi\" is invalid\n"); 727 exit(1); 728 } 729 if (preferred_family == AF_UNSPEC) 730 preferred_family = req.xspi.info.family; 731 } 732 argc--; argv++; 733 } 734 735 if (!idp) { 736 fprintf(stderr, "Not enough information: ID is required\n"); 737 exit(1); 738 } 739 740 if (minp) { 741 if (!maxp) { 742 fprintf(stderr, "\"max\" is missing\n"); 743 exit(1); 744 } 745 if (req.xspi.min > req.xspi.max) { 746 fprintf(stderr, "value after \"min\" is larger than value after \"max\"\n"); 747 exit(1); 748 } 749 } else { 750 if (maxp) { 751 fprintf(stderr, "\"min\" is missing\n"); 752 exit(1); 753 } 754 755 /* XXX: Default value defined in PF_KEY; 756 * See kernel's net/key/af_key.c(pfkey_getspi). 757 */ 758 req.xspi.min = 0x100; 759 req.xspi.max = 0x0fffffff; 760 761 /* XXX: IPCOMP spi is 16-bits; 762 * See kernel's net/xfrm/xfrm_user(verify_userspi_info). 763 */ 764 if (req.xspi.info.id.proto == IPPROTO_COMP) 765 req.xspi.max = 0xffff; 766 } 767 768 if (mark.m & mark.v) { 769 int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK, 770 (void *)&mark, sizeof(mark)); 771 if (r < 0) { 772 fprintf(stderr, "XFRMA_MARK failed\n"); 773 exit(1); 774 } 775 } 776 777 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) 778 exit(1); 779 780 if (req.xspi.info.family == AF_UNSPEC) 781 req.xspi.info.family = AF_INET; 782 783 784 if (rtnl_talk(&rth, &req.n, 0, 0, res_n) < 0) 785 exit(2); 786 787 if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) { 788 fprintf(stderr, "An error :-)\n"); 789 exit(1); 790 } 791 792 rtnl_close(&rth); 793 794 return 0; 795} 796 797static int xfrm_state_filter_match(struct xfrm_usersa_info *xsinfo) 798{ 799 if (!filter.use) 800 return 1; 801 802 if (filter.id_src_mask) 803 if (xfrm_addr_match(&xsinfo->saddr, &filter.xsinfo.saddr, 804 filter.id_src_mask)) 805 return 0; 806 if (filter.id_dst_mask) 807 if (xfrm_addr_match(&xsinfo->id.daddr, &filter.xsinfo.id.daddr, 808 filter.id_dst_mask)) 809 return 0; 810 if ((xsinfo->id.proto^filter.xsinfo.id.proto)&filter.id_proto_mask) 811 return 0; 812 if ((xsinfo->id.spi^filter.xsinfo.id.spi)&filter.id_spi_mask) 813 return 0; 814 if ((xsinfo->mode^filter.xsinfo.mode)&filter.mode_mask) 815 return 0; 816 if ((xsinfo->reqid^filter.xsinfo.reqid)&filter.reqid_mask) 817 return 0; 818 if (filter.state_flags_mask) 819 if ((xsinfo->flags & filter.xsinfo.flags) == 0) 820 return 0; 821 822 return 1; 823} 824 825int xfrm_state_print(const struct sockaddr_nl *who, struct nlmsghdr *n, 826 void *arg) 827{ 828 FILE *fp = (FILE*)arg; 829 struct rtattr * tb[XFRMA_MAX+1]; 830 struct rtattr * rta; 831 struct xfrm_usersa_info *xsinfo = NULL; 832 struct xfrm_user_expire *xexp = NULL; 833 struct xfrm_usersa_id *xsid = NULL; 834 int len = n->nlmsg_len; 835 836 if (n->nlmsg_type != XFRM_MSG_NEWSA && 837 n->nlmsg_type != XFRM_MSG_DELSA && 838 n->nlmsg_type != XFRM_MSG_UPDSA && 839 n->nlmsg_type != XFRM_MSG_EXPIRE) { 840 fprintf(stderr, "Not a state: %08x %08x %08x\n", 841 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); 842 return 0; 843 } 844 845 if (n->nlmsg_type == XFRM_MSG_DELSA) { 846 /* Dont blame me for this .. Herbert made me do it */ 847 xsid = NLMSG_DATA(n); 848 len -= NLMSG_SPACE(sizeof(*xsid)); 849 } else if (n->nlmsg_type == XFRM_MSG_EXPIRE) { 850 xexp = NLMSG_DATA(n); 851 xsinfo = &xexp->state; 852 len -= NLMSG_SPACE(sizeof(*xexp)); 853 } else { 854 xexp = NULL; 855 xsinfo = NLMSG_DATA(n); 856 len -= NLMSG_SPACE(sizeof(*xsinfo)); 857 } 858 859 if (len < 0) { 860 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); 861 return -1; 862 } 863 864 if (xsinfo && !xfrm_state_filter_match(xsinfo)) 865 return 0; 866 867 if (n->nlmsg_type == XFRM_MSG_DELSA) 868 fprintf(fp, "Deleted "); 869 else if (n->nlmsg_type == XFRM_MSG_UPDSA) 870 fprintf(fp, "Updated "); 871 else if (n->nlmsg_type == XFRM_MSG_EXPIRE) 872 fprintf(fp, "Expired "); 873 874 if (n->nlmsg_type == XFRM_MSG_DELSA) 875 rta = XFRMSID_RTA(xsid); 876 else if (n->nlmsg_type == XFRM_MSG_EXPIRE) 877 rta = XFRMEXP_RTA(xexp); 878 else 879 rta = XFRMS_RTA(xsinfo); 880 881 parse_rtattr(tb, XFRMA_MAX, rta, len); 882 883 if (n->nlmsg_type == XFRM_MSG_DELSA) { 884 //xfrm_policy_id_print(); 885 886 if (!tb[XFRMA_SA]) { 887 fprintf(stderr, "Buggy XFRM_MSG_DELSA: no XFRMA_SA\n"); 888 return -1; 889 } 890 if (RTA_PAYLOAD(tb[XFRMA_SA]) < sizeof(*xsinfo)) { 891 fprintf(stderr, "Buggy XFRM_MSG_DELPOLICY: too short XFRMA_POLICY len\n"); 892 return -1; 893 } 894 xsinfo = RTA_DATA(tb[XFRMA_SA]); 895 } 896 897 xfrm_state_info_print(xsinfo, tb, fp, NULL, NULL); 898 899 if (n->nlmsg_type == XFRM_MSG_EXPIRE) { 900 fprintf(fp, "\t"); 901 fprintf(fp, "hard %u", xexp->hard); 902 fprintf(fp, "%s", _SL_); 903 } 904 905 if (oneline) 906 fprintf(fp, "\n"); 907 fflush(fp); 908 909 return 0; 910} 911 912static int xfrm_state_get_or_delete(int argc, char **argv, int delete) 913{ 914 struct rtnl_handle rth; 915 struct { 916 struct nlmsghdr n; 917 struct xfrm_usersa_id xsid; 918 char buf[RTA_BUF_SIZE]; 919 } req; 920 struct xfrm_id id; 921 char *idp = NULL; 922 struct xfrm_mark mark = {0, 0}; 923 924 memset(&req, 0, sizeof(req)); 925 926 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsid)); 927 req.n.nlmsg_flags = NLM_F_REQUEST; 928 req.n.nlmsg_type = delete ? XFRM_MSG_DELSA : XFRM_MSG_GETSA; 929 req.xsid.family = preferred_family; 930 931 while (argc > 0) { 932 xfrm_address_t saddr; 933 934 if (strcmp(*argv, "mark") == 0) { 935 xfrm_parse_mark(&mark, &argc, &argv); 936 } else { 937 if (idp) 938 invarg("unknown", *argv); 939 idp = *argv; 940 941 /* ID */ 942 memset(&id, 0, sizeof(id)); 943 memset(&saddr, 0, sizeof(saddr)); 944 xfrm_id_parse(&saddr, &id, &req.xsid.family, 0, 945 &argc, &argv); 946 947 memcpy(&req.xsid.daddr, &id.daddr, sizeof(req.xsid.daddr)); 948 req.xsid.spi = id.spi; 949 req.xsid.proto = id.proto; 950 951 addattr_l(&req.n, sizeof(req.buf), XFRMA_SRCADDR, 952 (void *)&saddr, sizeof(saddr)); 953 } 954 955 argc--; argv++; 956 } 957 958 if (mark.m & mark.v) { 959 int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK, 960 (void *)&mark, sizeof(mark)); 961 if (r < 0) { 962 fprintf(stderr, "XFRMA_MARK failed\n"); 963 exit(1); 964 } 965 } 966 967 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) 968 exit(1); 969 970 if (req.xsid.family == AF_UNSPEC) 971 req.xsid.family = AF_INET; 972 973 if (delete) { 974 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) 975 exit(2); 976 } else { 977 char buf[NLMSG_BUF_SIZE]; 978 struct nlmsghdr *res_n = (struct nlmsghdr *)buf; 979 980 memset(buf, 0, sizeof(buf)); 981 982 if (rtnl_talk(&rth, &req.n, 0, 0, res_n) < 0) 983 exit(2); 984 985 if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) { 986 fprintf(stderr, "An error :-)\n"); 987 exit(1); 988 } 989 } 990 991 rtnl_close(&rth); 992 993 return 0; 994} 995 996/* 997 * With an existing state of nlmsg, make new nlmsg for deleting the state 998 * and store it to buffer. 999 */ 1000static int xfrm_state_keep(const struct sockaddr_nl *who, 1001 struct nlmsghdr *n, 1002 void *arg) 1003{ 1004 struct xfrm_buffer *xb = (struct xfrm_buffer *)arg; 1005 struct rtnl_handle *rth = xb->rth; 1006 struct xfrm_usersa_info *xsinfo = NLMSG_DATA(n); 1007 int len = n->nlmsg_len; 1008 struct nlmsghdr *new_n; 1009 struct xfrm_usersa_id *xsid; 1010 1011 if (n->nlmsg_type != XFRM_MSG_NEWSA) { 1012 fprintf(stderr, "Not a state: %08x %08x %08x\n", 1013 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); 1014 return 0; 1015 } 1016 1017 len -= NLMSG_LENGTH(sizeof(*xsinfo)); 1018 if (len < 0) { 1019 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); 1020 return -1; 1021 } 1022 1023 if (!xfrm_state_filter_match(xsinfo)) 1024 return 0; 1025 1026 if (xb->offset > xb->size) { 1027 fprintf(stderr, "State buffer overflow\n"); 1028 return -1; 1029 } 1030 1031 new_n = (struct nlmsghdr *)(xb->buf + xb->offset); 1032 new_n->nlmsg_len = NLMSG_LENGTH(sizeof(*xsid)); 1033 new_n->nlmsg_flags = NLM_F_REQUEST; 1034 new_n->nlmsg_type = XFRM_MSG_DELSA; 1035 new_n->nlmsg_seq = ++rth->seq; 1036 1037 xsid = NLMSG_DATA(new_n); 1038 xsid->family = xsinfo->family; 1039 memcpy(&xsid->daddr, &xsinfo->id.daddr, sizeof(xsid->daddr)); 1040 xsid->spi = xsinfo->id.spi; 1041 xsid->proto = xsinfo->id.proto; 1042 1043 addattr_l(new_n, xb->size, XFRMA_SRCADDR, &xsinfo->saddr, 1044 sizeof(xsid->daddr)); 1045 1046 xb->offset += new_n->nlmsg_len; 1047 xb->nlmsg_count ++; 1048 1049 return 0; 1050} 1051 1052static int xfrm_state_list_or_deleteall(int argc, char **argv, int deleteall) 1053{ 1054 char *idp = NULL; 1055 struct rtnl_handle rth; 1056 1057 if(argc > 0) 1058 filter.use = 1; 1059 filter.xsinfo.family = preferred_family; 1060 1061 while (argc > 0) { 1062 if (strcmp(*argv, "mode") == 0) { 1063 NEXT_ARG(); 1064 xfrm_mode_parse(&filter.xsinfo.mode, &argc, &argv); 1065 1066 filter.mode_mask = XFRM_FILTER_MASK_FULL; 1067 1068 } else if (strcmp(*argv, "reqid") == 0) { 1069 NEXT_ARG(); 1070 xfrm_reqid_parse(&filter.xsinfo.reqid, &argc, &argv); 1071 1072 filter.reqid_mask = XFRM_FILTER_MASK_FULL; 1073 1074 } else if (strcmp(*argv, "flag") == 0) { 1075 NEXT_ARG(); 1076 xfrm_state_flag_parse(&filter.xsinfo.flags, &argc, &argv); 1077 1078 filter.state_flags_mask = XFRM_FILTER_MASK_FULL; 1079 1080 } else { 1081 if (idp) 1082 invarg("unknown", *argv); 1083 idp = *argv; 1084 1085 /* ID */ 1086 xfrm_id_parse(&filter.xsinfo.saddr, &filter.xsinfo.id, 1087 &filter.xsinfo.family, 1, &argc, &argv); 1088 if (preferred_family == AF_UNSPEC) 1089 preferred_family = filter.xsinfo.family; 1090 } 1091 argc--; argv++; 1092 } 1093 1094 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) 1095 exit(1); 1096 1097 if (deleteall) { 1098 struct xfrm_buffer xb; 1099 char buf[NLMSG_DELETEALL_BUF_SIZE]; 1100 int i; 1101 1102 xb.buf = buf; 1103 xb.size = sizeof(buf); 1104 xb.rth = &rth; 1105 1106 for (i = 0; ; i++) { 1107 xb.offset = 0; 1108 xb.nlmsg_count = 0; 1109 1110 if (show_stats > 1) 1111 fprintf(stderr, "Delete-all round = %d\n", i); 1112 1113 if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) { 1114 perror("Cannot send dump request"); 1115 exit(1); 1116 } 1117 1118 if (rtnl_dump_filter(&rth, xfrm_state_keep, &xb) < 0) { 1119 fprintf(stderr, "Delete-all terminated\n"); 1120 exit(1); 1121 } 1122 if (xb.nlmsg_count == 0) { 1123 if (show_stats > 1) 1124 fprintf(stderr, "Delete-all completed\n"); 1125 break; 1126 } 1127 1128 if (rtnl_send_check(&rth, xb.buf, xb.offset) < 0) { 1129 perror("Failed to send delete-all request\n"); 1130 exit(1); 1131 } 1132 if (show_stats > 1) 1133 fprintf(stderr, "Delete-all nlmsg count = %d\n", xb.nlmsg_count); 1134 1135 xb.offset = 0; 1136 xb.nlmsg_count = 0; 1137 } 1138 1139 } else { 1140 if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) { 1141 perror("Cannot send dump request"); 1142 exit(1); 1143 } 1144 1145 if (rtnl_dump_filter(&rth, xfrm_state_print, stdout) < 0) { 1146 fprintf(stderr, "Dump terminated\n"); 1147 exit(1); 1148 } 1149 } 1150 1151 rtnl_close(&rth); 1152 1153 exit(0); 1154} 1155 1156static int print_sadinfo(struct nlmsghdr *n, void *arg) 1157{ 1158 FILE *fp = (FILE*)arg; 1159 __u32 *f = NLMSG_DATA(n); 1160 struct rtattr *tb[XFRMA_SAD_MAX+1]; 1161 struct rtattr *rta; 1162 __u32 *cnt; 1163 1164 int len = n->nlmsg_len; 1165 1166 len -= NLMSG_LENGTH(sizeof(__u32)); 1167 if (len < 0) { 1168 fprintf(stderr, "SADinfo: Wrong len %d\n", len); 1169 return -1; 1170 } 1171 1172 rta = XFRMSAPD_RTA(f); 1173 parse_rtattr(tb, XFRMA_SAD_MAX, rta, len); 1174 1175 if (tb[XFRMA_SAD_CNT]) { 1176 fprintf(fp,"\t SAD"); 1177 cnt = (__u32 *)RTA_DATA(tb[XFRMA_SAD_CNT]); 1178 fprintf(fp," count %d", *cnt); 1179 } else { 1180 fprintf(fp,"BAD SAD info returned\n"); 1181 return -1; 1182 } 1183 1184 if (show_stats) { 1185 if (tb[XFRMA_SAD_HINFO]) { 1186 struct xfrmu_sadhinfo *si; 1187 1188 if (RTA_PAYLOAD(tb[XFRMA_SAD_HINFO]) < sizeof(*si)) { 1189 fprintf(fp,"BAD SAD length returned\n"); 1190 return -1; 1191 } 1192 1193 si = RTA_DATA(tb[XFRMA_SAD_HINFO]); 1194 fprintf(fp," (buckets "); 1195 fprintf(fp,"count %d", si->sadhcnt); 1196 fprintf(fp," Max %d", si->sadhmcnt); 1197 fprintf(fp,")"); 1198 } 1199 } 1200 fprintf(fp,"\n"); 1201 1202 return 0; 1203} 1204 1205static int xfrm_sad_getinfo(int argc, char **argv) 1206{ 1207 struct rtnl_handle rth; 1208 struct { 1209 struct nlmsghdr n; 1210 __u32 flags; 1211 char ans[64]; 1212 } req; 1213 1214 memset(&req, 0, sizeof(req)); 1215 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.flags)); 1216 req.n.nlmsg_flags = NLM_F_REQUEST; 1217 req.n.nlmsg_type = XFRM_MSG_GETSADINFO; 1218 req.flags = 0XFFFFFFFF; 1219 1220 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) 1221 exit(1); 1222 1223 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) 1224 exit(2); 1225 1226 print_sadinfo(&req.n, (void*)stdout); 1227 1228 rtnl_close(&rth); 1229 1230 return 0; 1231} 1232 1233static int xfrm_state_flush(int argc, char **argv) 1234{ 1235 struct rtnl_handle rth; 1236 struct { 1237 struct nlmsghdr n; 1238 struct xfrm_usersa_flush xsf; 1239 } req; 1240 char *protop = NULL; 1241 1242 memset(&req, 0, sizeof(req)); 1243 1244 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsf)); 1245 req.n.nlmsg_flags = NLM_F_REQUEST; 1246 req.n.nlmsg_type = XFRM_MSG_FLUSHSA; 1247 req.xsf.proto = 0; 1248 1249 while (argc > 0) { 1250 if (strcmp(*argv, "proto") == 0) { 1251 int ret; 1252 1253 if (protop) 1254 duparg("proto", *argv); 1255 protop = *argv; 1256 1257 NEXT_ARG(); 1258 1259 ret = xfrm_xfrmproto_getbyname(*argv); 1260 if (ret < 0) 1261 invarg("XFRM-PROTO value is invalid", *argv); 1262 1263 req.xsf.proto = (__u8)ret; 1264 } else 1265 invarg("unknown", *argv); 1266 1267 argc--; argv++; 1268 } 1269 1270 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) 1271 exit(1); 1272 1273 if (show_stats > 1) 1274 fprintf(stderr, "Flush state with XFRM-PROTO value \"%s\"\n", 1275 strxf_xfrmproto(req.xsf.proto)); 1276 1277 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) 1278 exit(2); 1279 1280 rtnl_close(&rth); 1281 1282 return 0; 1283} 1284 1285int do_xfrm_state(int argc, char **argv) 1286{ 1287 if (argc < 1) 1288 return xfrm_state_list_or_deleteall(0, NULL, 0); 1289 1290 if (matches(*argv, "add") == 0) 1291 return xfrm_state_modify(XFRM_MSG_NEWSA, 0, 1292 argc-1, argv+1); 1293 if (matches(*argv, "update") == 0) 1294 return xfrm_state_modify(XFRM_MSG_UPDSA, 0, 1295 argc-1, argv+1); 1296 if (matches(*argv, "allocspi") == 0) 1297 return xfrm_state_allocspi(argc-1, argv+1); 1298 if (matches(*argv, "delete") == 0) 1299 return xfrm_state_get_or_delete(argc-1, argv+1, 1); 1300 if (matches(*argv, "deleteall") == 0 || matches(*argv, "delall") == 0) 1301 return xfrm_state_list_or_deleteall(argc-1, argv+1, 1); 1302 if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0 1303 || matches(*argv, "lst") == 0) 1304 return xfrm_state_list_or_deleteall(argc-1, argv+1, 0); 1305 if (matches(*argv, "get") == 0) 1306 return xfrm_state_get_or_delete(argc-1, argv+1, 0); 1307 if (matches(*argv, "flush") == 0) 1308 return xfrm_state_flush(argc-1, argv+1); 1309 if (matches(*argv, "count") == 0) { 1310 return xfrm_sad_getinfo(argc, argv); 1311 } 1312 if (matches(*argv, "help") == 0) 1313 usage(); 1314 fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm state help\".\n", *argv); 1315 exit(-1); 1316} 1317