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