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/netlink.h> 33 #include <linux/xfrm.h> 34 #include <linux/in.h> 35 #include <linux/in6.h> 36 #include "utils.h" 37 #include "xfrm.h" 38 #include "ip_common.h" 39 40 //#define NLMSG_DELETEALL_BUF_SIZE (4096-512) 41 #define NLMSG_DELETEALL_BUF_SIZE 8192 42 43 /* 44 * Receiving buffer defines: 45 * nlmsg 46 * data = struct xfrm_userpolicy_info 47 * rtattr 48 * data = struct xfrm_user_tmpl[] 49 */ 50 #define NLMSG_BUF_SIZE 4096 51 #define RTA_BUF_SIZE 2048 52 #define XFRM_TMPLS_BUF_SIZE 1024 53 54 static void usage(void) __attribute__((noreturn)); 55 56 static void usage(void) 57 { 58 fprintf(stderr, "Usage: ip xfrm policy { add | update } dir DIR SELECTOR [ index INDEX ] [ ptype PTYPE ]\n"); 59 fprintf(stderr, " [ action ACTION ] [ priority PRIORITY ] [ flag FLAG-LIST ] [ LIMIT-LIST ] [ TMPL-LIST ] [mark MARK [mask MASK]]\n"); 60 fprintf(stderr, "Usage: ip xfrm policy { delete | get } dir DIR [ SELECTOR | index INDEX ] [ ptype PTYPE ] [mark MARK [mask MASK]]\n"); 61 fprintf(stderr, "Usage: ip xfrm policy { deleteall | list } [ dir DIR ] [ SELECTOR ]\n"); 62 fprintf(stderr, " [ index INDEX ] [ action ACTION ] [ priority PRIORITY ] [ flag FLAG-LIST ]\n"); 63 fprintf(stderr, "Usage: ip xfrm policy flush [ ptype PTYPE ]\n"); 64 fprintf(stderr, "Usage: ip xfrm count\n"); 65 fprintf(stderr, "PTYPE := [ main | sub ](default=main)\n"); 66 fprintf(stderr, "DIR := [ in | out | fwd ]\n"); 67 68 fprintf(stderr, "SELECTOR := src ADDR[/PLEN] dst ADDR[/PLEN] [ UPSPEC ] [ dev DEV ]\n"); 69 70 fprintf(stderr, "UPSPEC := proto PROTO [ [ sport PORT ] [ dport PORT ] |\n"); 71 fprintf(stderr, " [ type NUMBER ] [ code NUMBER ] ]\n"); 72 73 //fprintf(stderr, "DEV - device name(default=none)\n"); 74 75 fprintf(stderr, "ACTION := [ allow | block ](default=allow)\n"); 76 77 //fprintf(stderr, "PRIORITY - priority value(default=0)\n"); 78 79 fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n"); 80 fprintf(stderr, "FLAG := [ localok ]\n"); 81 82 fprintf(stderr, "LIMIT-LIST := [ LIMIT-LIST ] | [ limit LIMIT ]\n"); 83 fprintf(stderr, "LIMIT := [ [time-soft|time-hard|time-use-soft|time-use-hard] SECONDS ] |\n"); 84 fprintf(stderr, " [ [byte-soft|byte-hard] SIZE ] | [ [packet-soft|packet-hard] NUMBER ]\n"); 85 86 fprintf(stderr, "TMPL-LIST := [ TMPL-LIST ] | [ tmpl TMPL ]\n"); 87 fprintf(stderr, "TMPL := ID [ mode MODE ] [ reqid REQID ] [ level LEVEL ]\n"); 88 fprintf(stderr, "ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM_PROTO ] [ spi SPI ]\n"); 89 90 fprintf(stderr, "XFRM_PROTO := [ "); 91 fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ESP)); 92 fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_AH)); 93 fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_COMP)); 94 fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ROUTING)); 95 fprintf(stderr, "%s ", strxf_xfrmproto(IPPROTO_DSTOPTS)); 96 fprintf(stderr, "]\n"); 97 98 fprintf(stderr, "MODE := [ transport | tunnel | beet ](default=transport)\n"); 99 //fprintf(stderr, "REQID - number(default=0)\n"); 100 fprintf(stderr, "LEVEL := [ required | use ](default=required)\n"); 101 102 exit(-1); 103 } 104 105 static int xfrm_policy_dir_parse(__u8 *dir, int *argcp, char ***argvp) 106 { 107 int argc = *argcp; 108 char **argv = *argvp; 109 110 if (strcmp(*argv, "in") == 0) 111 *dir = XFRM_POLICY_IN; 112 else if (strcmp(*argv, "out") == 0) 113 *dir = XFRM_POLICY_OUT; 114 else if (strcmp(*argv, "fwd") == 0) 115 *dir = XFRM_POLICY_FWD; 116 else 117 invarg("\"DIR\" is invalid", *argv); 118 119 *argcp = argc; 120 *argvp = argv; 121 122 return 0; 123 } 124 125 static int xfrm_policy_ptype_parse(__u8 *ptype, int *argcp, char ***argvp) 126 { 127 int argc = *argcp; 128 char **argv = *argvp; 129 130 if (strcmp(*argv, "main") == 0) 131 *ptype = XFRM_POLICY_TYPE_MAIN; 132 else if (strcmp(*argv, "sub") == 0) 133 *ptype = XFRM_POLICY_TYPE_SUB; 134 else 135 invarg("\"PTYPE\" is invalid", *argv); 136 137 *argcp = argc; 138 *argvp = argv; 139 140 return 0; 141 } 142 143 static int xfrm_policy_flag_parse(__u8 *flags, int *argcp, char ***argvp) 144 { 145 int argc = *argcp; 146 char **argv = *argvp; 147 int len = strlen(*argv); 148 149 if (len > 2 && strncmp(*argv, "0x", 2) == 0) { 150 __u8 val = 0; 151 152 if (get_u8(&val, *argv, 16)) 153 invarg("\"FLAG\" is invalid", *argv); 154 *flags = val; 155 } else { 156 while (1) { 157 if (strcmp(*argv, "localok") == 0) 158 *flags |= XFRM_POLICY_LOCALOK; 159 else { 160 PREV_ARG(); /* back track */ 161 break; 162 } 163 164 if (!NEXT_ARG_OK()) 165 break; 166 NEXT_ARG(); 167 } 168 } 169 170 *argcp = argc; 171 *argvp = argv; 172 173 return 0; 174 } 175 176 static int xfrm_tmpl_parse(struct xfrm_user_tmpl *tmpl, 177 int *argcp, char ***argvp) 178 { 179 int argc = *argcp; 180 char **argv = *argvp; 181 char *idp = NULL; 182 183 while (1) { 184 if (strcmp(*argv, "mode") == 0) { 185 NEXT_ARG(); 186 xfrm_mode_parse(&tmpl->mode, &argc, &argv); 187 } else if (strcmp(*argv, "reqid") == 0) { 188 NEXT_ARG(); 189 xfrm_reqid_parse(&tmpl->reqid, &argc, &argv); 190 } else if (strcmp(*argv, "level") == 0) { 191 NEXT_ARG(); 192 193 if (strcmp(*argv, "required") == 0) 194 tmpl->optional = 0; 195 else if (strcmp(*argv, "use") == 0) 196 tmpl->optional = 1; 197 else 198 invarg("\"LEVEL\" is invalid\n", *argv); 199 200 } else { 201 if (idp) { 202 PREV_ARG(); /* back track */ 203 break; 204 } 205 idp = *argv; 206 preferred_family = AF_UNSPEC; 207 xfrm_id_parse(&tmpl->saddr, &tmpl->id, &tmpl->family, 208 0, &argc, &argv); 209 preferred_family = tmpl->family; 210 } 211 212 if (!NEXT_ARG_OK()) 213 break; 214 215 NEXT_ARG(); 216 } 217 if (argc == *argcp) 218 missarg("TMPL"); 219 220 *argcp = argc; 221 *argvp = argv; 222 223 return 0; 224 } 225 226 static int xfrm_policy_modify(int cmd, unsigned flags, int argc, char **argv) 227 { 228 struct rtnl_handle rth; 229 struct { 230 struct nlmsghdr n; 231 struct xfrm_userpolicy_info xpinfo; 232 char buf[RTA_BUF_SIZE]; 233 } req; 234 char *dirp = NULL; 235 char *selp = NULL; 236 char *ptypep = NULL; 237 struct xfrm_userpolicy_type upt; 238 char tmpls_buf[XFRM_TMPLS_BUF_SIZE]; 239 int tmpls_len = 0; 240 struct xfrm_mark mark = {0, 0}; 241 242 memset(&req, 0, sizeof(req)); 243 memset(&upt, 0, sizeof(upt)); 244 memset(&tmpls_buf, 0, sizeof(tmpls_buf)); 245 246 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpinfo)); 247 req.n.nlmsg_flags = NLM_F_REQUEST|flags; 248 req.n.nlmsg_type = cmd; 249 req.xpinfo.sel.family = preferred_family; 250 251 req.xpinfo.lft.soft_byte_limit = XFRM_INF; 252 req.xpinfo.lft.hard_byte_limit = XFRM_INF; 253 req.xpinfo.lft.soft_packet_limit = XFRM_INF; 254 req.xpinfo.lft.hard_packet_limit = XFRM_INF; 255 256 while (argc > 0) { 257 if (strcmp(*argv, "dir") == 0) { 258 if (dirp) 259 duparg("dir", *argv); 260 dirp = *argv; 261 262 NEXT_ARG(); 263 xfrm_policy_dir_parse(&req.xpinfo.dir, &argc, &argv); 264 } else if (strcmp(*argv, "mark") == 0) { 265 xfrm_parse_mark(&mark, &argc, &argv); 266 } else if (strcmp(*argv, "index") == 0) { 267 NEXT_ARG(); 268 if (get_u32(&req.xpinfo.index, *argv, 0)) 269 invarg("\"INDEX\" is invalid", *argv); 270 } else if (strcmp(*argv, "ptype") == 0) { 271 if (ptypep) 272 duparg("ptype", *argv); 273 ptypep = *argv; 274 275 NEXT_ARG(); 276 xfrm_policy_ptype_parse(&upt.type, &argc, &argv); 277 } else if (strcmp(*argv, "action") == 0) { 278 NEXT_ARG(); 279 if (strcmp(*argv, "allow") == 0) 280 req.xpinfo.action = XFRM_POLICY_ALLOW; 281 else if (strcmp(*argv, "block") == 0) 282 req.xpinfo.action = XFRM_POLICY_BLOCK; 283 else 284 invarg("\"action\" value is invalid\n", *argv); 285 } else if (strcmp(*argv, "priority") == 0) { 286 NEXT_ARG(); 287 if (get_u32(&req.xpinfo.priority, *argv, 0)) 288 invarg("\"PRIORITY\" is invalid", *argv); 289 } else if (strcmp(*argv, "flag") == 0) { 290 NEXT_ARG(); 291 xfrm_policy_flag_parse(&req.xpinfo.flags, &argc, 292 &argv); 293 } else if (strcmp(*argv, "limit") == 0) { 294 NEXT_ARG(); 295 xfrm_lifetime_cfg_parse(&req.xpinfo.lft, &argc, &argv); 296 } else if (strcmp(*argv, "tmpl") == 0) { 297 struct xfrm_user_tmpl *tmpl; 298 299 if (tmpls_len + sizeof(*tmpl) > sizeof(tmpls_buf)) { 300 fprintf(stderr, "Too many tmpls: buffer overflow\n"); 301 exit(1); 302 } 303 tmpl = (struct xfrm_user_tmpl *)((char *)tmpls_buf + tmpls_len); 304 305 tmpl->family = preferred_family; 306 tmpl->aalgos = (~(__u32)0); 307 tmpl->ealgos = (~(__u32)0); 308 tmpl->calgos = (~(__u32)0); 309 310 NEXT_ARG(); 311 xfrm_tmpl_parse(tmpl, &argc, &argv); 312 313 tmpls_len += sizeof(*tmpl); 314 } else { 315 if (selp) 316 duparg("unknown", *argv); 317 selp = *argv; 318 319 xfrm_selector_parse(&req.xpinfo.sel, &argc, &argv); 320 if (preferred_family == AF_UNSPEC) 321 preferred_family = req.xpinfo.sel.family; 322 } 323 324 argc--; argv++; 325 } 326 327 if (!dirp) { 328 fprintf(stderr, "Not enough information: \"DIR\" is required.\n"); 329 exit(1); 330 } 331 332 if (ptypep) { 333 addattr_l(&req.n, sizeof(req), XFRMA_POLICY_TYPE, 334 (void *)&upt, sizeof(upt)); 335 } 336 337 if (tmpls_len > 0) { 338 addattr_l(&req.n, sizeof(req), XFRMA_TMPL, 339 (void *)tmpls_buf, tmpls_len); 340 } 341 342 if (mark.m & mark.v) { 343 int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK, 344 (void *)&mark, sizeof(mark)); 345 if (r < 0) { 346 fprintf(stderr, "%s: XFRMA_MARK failed\n",__func__); 347 exit(1); 348 } 349 } 350 351 352 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) 353 exit(1); 354 355 if (req.xpinfo.sel.family == AF_UNSPEC) 356 req.xpinfo.sel.family = AF_INET; 357 358 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) 359 exit(2); 360 361 rtnl_close(&rth); 362 363 return 0; 364 } 365 366 static int xfrm_policy_filter_match(struct xfrm_userpolicy_info *xpinfo, 367 __u8 ptype) 368 { 369 if (!filter.use) 370 return 1; 371 372 if ((xpinfo->dir^filter.xpinfo.dir)&filter.dir_mask) 373 return 0; 374 375 if ((ptype^filter.ptype)&filter.ptype_mask) 376 return 0; 377 378 if (filter.sel_src_mask) { 379 if (xfrm_addr_match(&xpinfo->sel.saddr, &filter.xpinfo.sel.saddr, 380 filter.sel_src_mask)) 381 return 0; 382 } 383 384 if (filter.sel_dst_mask) { 385 if (xfrm_addr_match(&xpinfo->sel.daddr, &filter.xpinfo.sel.daddr, 386 filter.sel_dst_mask)) 387 return 0; 388 } 389 390 if ((xpinfo->sel.ifindex^filter.xpinfo.sel.ifindex)&filter.sel_dev_mask) 391 return 0; 392 393 if ((xpinfo->sel.proto^filter.xpinfo.sel.proto)&filter.upspec_proto_mask) 394 return 0; 395 396 if (filter.upspec_sport_mask) { 397 if ((xpinfo->sel.sport^filter.xpinfo.sel.sport)&filter.upspec_sport_mask) 398 return 0; 399 } 400 401 if (filter.upspec_dport_mask) { 402 if ((xpinfo->sel.dport^filter.xpinfo.sel.dport)&filter.upspec_dport_mask) 403 return 0; 404 } 405 406 if ((xpinfo->index^filter.xpinfo.index)&filter.index_mask) 407 return 0; 408 409 if ((xpinfo->action^filter.xpinfo.action)&filter.action_mask) 410 return 0; 411 412 if ((xpinfo->priority^filter.xpinfo.priority)&filter.priority_mask) 413 return 0; 414 415 if (filter.policy_flags_mask) 416 if ((xpinfo->flags & filter.xpinfo.flags) == 0) 417 return 0; 418 419 return 1; 420 } 421 422 int xfrm_policy_print(const struct sockaddr_nl *who, struct nlmsghdr *n, 423 void *arg) 424 { 425 struct rtattr * tb[XFRMA_MAX+1]; 426 struct rtattr * rta; 427 struct xfrm_userpolicy_info *xpinfo = NULL; 428 struct xfrm_user_polexpire *xpexp = NULL; 429 struct xfrm_userpolicy_id *xpid = NULL; 430 __u8 ptype = XFRM_POLICY_TYPE_MAIN; 431 FILE *fp = (FILE*)arg; 432 int len = n->nlmsg_len; 433 434 if (n->nlmsg_type != XFRM_MSG_NEWPOLICY && 435 n->nlmsg_type != XFRM_MSG_DELPOLICY && 436 n->nlmsg_type != XFRM_MSG_UPDPOLICY && 437 n->nlmsg_type != XFRM_MSG_POLEXPIRE) { 438 fprintf(stderr, "Not a policy: %08x %08x %08x\n", 439 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); 440 return 0; 441 } 442 443 if (n->nlmsg_type == XFRM_MSG_DELPOLICY) { 444 xpid = NLMSG_DATA(n); 445 len -= NLMSG_SPACE(sizeof(*xpid)); 446 } else if (n->nlmsg_type == XFRM_MSG_POLEXPIRE) { 447 xpexp = NLMSG_DATA(n); 448 xpinfo = &xpexp->pol; 449 len -= NLMSG_SPACE(sizeof(*xpexp)); 450 } else { 451 xpexp = NULL; 452 xpinfo = NLMSG_DATA(n); 453 len -= NLMSG_SPACE(sizeof(*xpinfo)); 454 } 455 456 if (len < 0) { 457 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); 458 return -1; 459 } 460 461 if (n->nlmsg_type == XFRM_MSG_DELPOLICY) 462 rta = XFRMPID_RTA(xpid); 463 else if (n->nlmsg_type == XFRM_MSG_POLEXPIRE) 464 rta = XFRMPEXP_RTA(xpexp); 465 else 466 rta = XFRMP_RTA(xpinfo); 467 468 parse_rtattr(tb, XFRMA_MAX, rta, len); 469 470 if (tb[XFRMA_POLICY_TYPE]) { 471 struct xfrm_userpolicy_type *upt; 472 473 if (RTA_PAYLOAD(tb[XFRMA_POLICY_TYPE]) < sizeof(*upt)) { 474 fprintf(stderr, "too short XFRMA_POLICY_TYPE len\n"); 475 return -1; 476 } 477 upt = (struct xfrm_userpolicy_type *)RTA_DATA(tb[XFRMA_POLICY_TYPE]); 478 ptype = upt->type; 479 } 480 481 if (xpinfo && !xfrm_policy_filter_match(xpinfo, ptype)) 482 return 0; 483 484 if (n->nlmsg_type == XFRM_MSG_DELPOLICY) 485 fprintf(fp, "Deleted "); 486 else if (n->nlmsg_type == XFRM_MSG_UPDPOLICY) 487 fprintf(fp, "Updated "); 488 else if (n->nlmsg_type == XFRM_MSG_POLEXPIRE) 489 fprintf(fp, "Expired "); 490 491 if (n->nlmsg_type == XFRM_MSG_DELPOLICY) { 492 //xfrm_policy_id_print(); 493 if (!tb[XFRMA_POLICY]) { 494 fprintf(stderr, "Buggy XFRM_MSG_DELPOLICY: no XFRMA_POLICY\n"); 495 return -1; 496 } 497 if (RTA_PAYLOAD(tb[XFRMA_POLICY]) < sizeof(*xpinfo)) { 498 fprintf(stderr, "Buggy XFRM_MSG_DELPOLICY: too short XFRMA_POLICY len\n"); 499 return -1; 500 } 501 xpinfo = (struct xfrm_userpolicy_info *)RTA_DATA(tb[XFRMA_POLICY]); 502 } 503 504 xfrm_policy_info_print(xpinfo, tb, fp, NULL, NULL); 505 506 if (n->nlmsg_type == XFRM_MSG_POLEXPIRE) { 507 fprintf(fp, "\t"); 508 fprintf(fp, "hard %u", xpexp->hard); 509 fprintf(fp, "%s", _SL_); 510 } 511 512 if (oneline) 513 fprintf(fp, "\n"); 514 fflush(fp); 515 516 return 0; 517 } 518 519 static int xfrm_policy_get_or_delete(int argc, char **argv, int delete, 520 void *res_nlbuf) 521 { 522 struct rtnl_handle rth; 523 struct { 524 struct nlmsghdr n; 525 struct xfrm_userpolicy_id xpid; 526 char buf[RTA_BUF_SIZE]; 527 } req; 528 char *dirp = NULL; 529 char *selp = NULL; 530 char *indexp = NULL; 531 char *ptypep = NULL; 532 struct xfrm_userpolicy_type upt; 533 struct xfrm_mark mark = {0, 0}; 534 535 memset(&req, 0, sizeof(req)); 536 memset(&upt, 0, sizeof(upt)); 537 538 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpid)); 539 req.n.nlmsg_flags = NLM_F_REQUEST; 540 req.n.nlmsg_type = delete ? XFRM_MSG_DELPOLICY : XFRM_MSG_GETPOLICY; 541 542 while (argc > 0) { 543 if (strcmp(*argv, "dir") == 0) { 544 if (dirp) 545 duparg("dir", *argv); 546 dirp = *argv; 547 548 NEXT_ARG(); 549 xfrm_policy_dir_parse(&req.xpid.dir, &argc, &argv); 550 551 } else if (strcmp(*argv, "mark") == 0) { 552 xfrm_parse_mark(&mark, &argc, &argv); 553 } else if (strcmp(*argv, "index") == 0) { 554 if (indexp) 555 duparg("index", *argv); 556 indexp = *argv; 557 558 NEXT_ARG(); 559 if (get_u32(&req.xpid.index, *argv, 0)) 560 invarg("\"INDEX\" is invalid", *argv); 561 562 } else if (strcmp(*argv, "ptype") == 0) { 563 if (ptypep) 564 duparg("ptype", *argv); 565 ptypep = *argv; 566 567 NEXT_ARG(); 568 xfrm_policy_ptype_parse(&upt.type, &argc, &argv); 569 570 } else { 571 if (selp) 572 invarg("unknown", *argv); 573 selp = *argv; 574 575 xfrm_selector_parse(&req.xpid.sel, &argc, &argv); 576 if (preferred_family == AF_UNSPEC) 577 preferred_family = req.xpid.sel.family; 578 579 } 580 581 argc--; argv++; 582 } 583 584 if (!dirp) { 585 fprintf(stderr, "Not enough information: \"DIR\" is required.\n"); 586 exit(1); 587 } 588 if (ptypep) { 589 addattr_l(&req.n, sizeof(req), XFRMA_POLICY_TYPE, 590 (void *)&upt, sizeof(upt)); 591 } 592 if (!selp && !indexp) { 593 fprintf(stderr, "Not enough information: either \"SELECTOR\" or \"INDEX\" is required.\n"); 594 exit(1); 595 } 596 if (selp && indexp) 597 duparg2("SELECTOR", "INDEX"); 598 599 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) 600 exit(1); 601 602 if (req.xpid.sel.family == AF_UNSPEC) 603 req.xpid.sel.family = AF_INET; 604 605 if (mark.m & mark.v) { 606 int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK, 607 (void *)&mark, sizeof(mark)); 608 if (r < 0) { 609 fprintf(stderr, "%s: XFRMA_MARK failed\n",__func__); 610 exit(1); 611 } 612 } 613 614 if (rtnl_talk(&rth, &req.n, 0, 0, res_nlbuf, NULL, NULL) < 0) 615 exit(2); 616 617 rtnl_close(&rth); 618 619 return 0; 620 } 621 622 static int xfrm_policy_delete(int argc, char **argv) 623 { 624 return xfrm_policy_get_or_delete(argc, argv, 1, NULL); 625 } 626 627 static int xfrm_policy_get(int argc, char **argv) 628 { 629 char buf[NLMSG_BUF_SIZE]; 630 struct nlmsghdr *n = (struct nlmsghdr *)buf; 631 632 memset(buf, 0, sizeof(buf)); 633 634 xfrm_policy_get_or_delete(argc, argv, 0, n); 635 636 if (xfrm_policy_print(NULL, n, (void*)stdout) < 0) { 637 fprintf(stderr, "An error :-)\n"); 638 exit(1); 639 } 640 641 return 0; 642 } 643 644 /* 645 * With an existing policy of nlmsg, make new nlmsg for deleting the policy 646 * and store it to buffer. 647 */ 648 static int xfrm_policy_keep(const struct sockaddr_nl *who, 649 struct nlmsghdr *n, 650 void *arg) 651 { 652 struct xfrm_buffer *xb = (struct xfrm_buffer *)arg; 653 struct rtnl_handle *rth = xb->rth; 654 struct xfrm_userpolicy_info *xpinfo = NLMSG_DATA(n); 655 int len = n->nlmsg_len; 656 struct rtattr *tb[XFRMA_MAX+1]; 657 __u8 ptype = XFRM_POLICY_TYPE_MAIN; 658 struct nlmsghdr *new_n; 659 struct xfrm_userpolicy_id *xpid; 660 661 if (n->nlmsg_type != XFRM_MSG_NEWPOLICY) { 662 fprintf(stderr, "Not a policy: %08x %08x %08x\n", 663 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); 664 return 0; 665 } 666 667 len -= NLMSG_LENGTH(sizeof(*xpinfo)); 668 if (len < 0) { 669 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); 670 return -1; 671 } 672 673 parse_rtattr(tb, XFRMA_MAX, XFRMP_RTA(xpinfo), len); 674 675 if (tb[XFRMA_POLICY_TYPE]) { 676 struct xfrm_userpolicy_type *upt; 677 678 if (RTA_PAYLOAD(tb[XFRMA_POLICY_TYPE]) < sizeof(*upt)) { 679 fprintf(stderr, "too short XFRMA_POLICY_TYPE len\n"); 680 return -1; 681 } 682 upt = (struct xfrm_userpolicy_type *)RTA_DATA(tb[XFRMA_POLICY_TYPE]); 683 ptype = upt->type; 684 } 685 686 if (!xfrm_policy_filter_match(xpinfo, ptype)) 687 return 0; 688 689 if (xb->offset > xb->size) { 690 fprintf(stderr, "Policy buffer overflow\n"); 691 return -1; 692 } 693 694 new_n = (struct nlmsghdr *)(xb->buf + xb->offset); 695 new_n->nlmsg_len = NLMSG_LENGTH(sizeof(*xpid)); 696 new_n->nlmsg_flags = NLM_F_REQUEST; 697 new_n->nlmsg_type = XFRM_MSG_DELPOLICY; 698 new_n->nlmsg_seq = ++rth->seq; 699 700 xpid = NLMSG_DATA(new_n); 701 memcpy(&xpid->sel, &xpinfo->sel, sizeof(xpid->sel)); 702 xpid->dir = xpinfo->dir; 703 xpid->index = xpinfo->index; 704 705 xb->offset += new_n->nlmsg_len; 706 xb->nlmsg_count ++; 707 708 return 0; 709 } 710 711 static int xfrm_policy_list_or_deleteall(int argc, char **argv, int deleteall) 712 { 713 char *selp = NULL; 714 struct rtnl_handle rth; 715 716 if (argc > 0) 717 filter.use = 1; 718 filter.xpinfo.sel.family = preferred_family; 719 720 while (argc > 0) { 721 if (strcmp(*argv, "dir") == 0) { 722 NEXT_ARG(); 723 xfrm_policy_dir_parse(&filter.xpinfo.dir, &argc, &argv); 724 725 filter.dir_mask = XFRM_FILTER_MASK_FULL; 726 727 } else if (strcmp(*argv, "index") == 0) { 728 NEXT_ARG(); 729 if (get_u32(&filter.xpinfo.index, *argv, 0)) 730 invarg("\"INDEX\" is invalid", *argv); 731 732 filter.index_mask = XFRM_FILTER_MASK_FULL; 733 734 } else if (strcmp(*argv, "ptype") == 0) { 735 NEXT_ARG(); 736 xfrm_policy_ptype_parse(&filter.ptype, &argc, &argv); 737 738 filter.ptype_mask = XFRM_FILTER_MASK_FULL; 739 740 } else if (strcmp(*argv, "action") == 0) { 741 NEXT_ARG(); 742 if (strcmp(*argv, "allow") == 0) 743 filter.xpinfo.action = XFRM_POLICY_ALLOW; 744 else if (strcmp(*argv, "block") == 0) 745 filter.xpinfo.action = XFRM_POLICY_BLOCK; 746 else 747 invarg("\"ACTION\" is invalid\n", *argv); 748 749 filter.action_mask = XFRM_FILTER_MASK_FULL; 750 751 } else if (strcmp(*argv, "priority") == 0) { 752 NEXT_ARG(); 753 if (get_u32(&filter.xpinfo.priority, *argv, 0)) 754 invarg("\"PRIORITY\" is invalid", *argv); 755 756 filter.priority_mask = XFRM_FILTER_MASK_FULL; 757 758 } else if (strcmp(*argv, "flag") == 0) { 759 NEXT_ARG(); 760 xfrm_policy_flag_parse(&filter.xpinfo.flags, &argc, 761 &argv); 762 763 filter.policy_flags_mask = XFRM_FILTER_MASK_FULL; 764 765 } else { 766 if (selp) 767 invarg("unknown", *argv); 768 selp = *argv; 769 770 xfrm_selector_parse(&filter.xpinfo.sel, &argc, &argv); 771 if (preferred_family == AF_UNSPEC) 772 preferred_family = filter.xpinfo.sel.family; 773 774 } 775 776 argc--; argv++; 777 } 778 779 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) 780 exit(1); 781 782 if (deleteall) { 783 struct xfrm_buffer xb; 784 char buf[NLMSG_DELETEALL_BUF_SIZE]; 785 int i; 786 787 xb.buf = buf; 788 xb.size = sizeof(buf); 789 xb.rth = &rth; 790 791 for (i = 0; ; i++) { 792 xb.offset = 0; 793 xb.nlmsg_count = 0; 794 795 if (show_stats > 1) 796 fprintf(stderr, "Delete-all round = %d\n", i); 797 798 if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETPOLICY) < 0) { 799 perror("Cannot send dump request"); 800 exit(1); 801 } 802 803 if (rtnl_dump_filter(&rth, xfrm_policy_keep, &xb, NULL, NULL) < 0) { 804 fprintf(stderr, "Delete-all terminated\n"); 805 exit(1); 806 } 807 if (xb.nlmsg_count == 0) { 808 if (show_stats > 1) 809 fprintf(stderr, "Delete-all completed\n"); 810 break; 811 } 812 813 if (rtnl_send_check(&rth, xb.buf, xb.offset) < 0) { 814 perror("Failed to send delete-all request"); 815 exit(1); 816 } 817 if (show_stats > 1) 818 fprintf(stderr, "Delete-all nlmsg count = %d\n", xb.nlmsg_count); 819 820 xb.offset = 0; 821 xb.nlmsg_count = 0; 822 } 823 } else { 824 if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETPOLICY) < 0) { 825 perror("Cannot send dump request"); 826 exit(1); 827 } 828 829 if (rtnl_dump_filter(&rth, xfrm_policy_print, stdout, NULL, NULL) < 0) { 830 fprintf(stderr, "Dump terminated\n"); 831 exit(1); 832 } 833 } 834 835 rtnl_close(&rth); 836 837 exit(0); 838 } 839 840 int print_spdinfo( struct nlmsghdr *n, void *arg) 841 { 842 FILE *fp = (FILE*)arg; 843 __u32 *f = NLMSG_DATA(n); 844 struct rtattr * tb[XFRMA_SPD_MAX+1]; 845 struct rtattr * rta; 846 847 int len = n->nlmsg_len; 848 849 len -= NLMSG_LENGTH(sizeof(__u32)); 850 if (len < 0) { 851 fprintf(stderr, "SPDinfo: Wrong len %d\n", len); 852 return -1; 853 } 854 855 rta = XFRMSAPD_RTA(f); 856 parse_rtattr(tb, XFRMA_SPD_MAX, rta, len); 857 858 fprintf(fp,"\t SPD"); 859 if (tb[XFRMA_SPD_INFO]) { 860 struct xfrmu_spdinfo *si; 861 862 if (RTA_PAYLOAD(tb[XFRMA_SPD_INFO]) < sizeof(*si)) { 863 fprintf(stderr, "SPDinfo: Wrong len %d\n", len); 864 return -1; 865 } 866 si = RTA_DATA(tb[XFRMA_SPD_INFO]); 867 fprintf(fp," IN %d", si->incnt); 868 fprintf(fp," OUT %d", si->outcnt); 869 fprintf(fp," FWD %d", si->fwdcnt); 870 871 if (show_stats) { 872 fprintf(fp," (Sock:"); 873 fprintf(fp," IN %d", si->inscnt); 874 fprintf(fp," OUT %d", si->outscnt); 875 fprintf(fp," FWD %d", si->fwdscnt); 876 fprintf(fp,")"); 877 } 878 879 fprintf(fp,"\n"); 880 } 881 if (show_stats > 1) { 882 struct xfrmu_spdhinfo *sh; 883 884 if (tb[XFRMA_SPD_HINFO]) { 885 if (RTA_PAYLOAD(tb[XFRMA_SPD_HINFO]) < sizeof(*sh)) { 886 fprintf(stderr, "SPDinfo: Wrong len %d\n", len); 887 return -1; 888 } 889 sh = RTA_DATA(tb[XFRMA_SPD_HINFO]); 890 fprintf(fp,"\t SPD buckets:"); 891 fprintf(fp," count %d", sh->spdhcnt); 892 fprintf(fp," Max %d", sh->spdhmcnt); 893 } 894 } 895 fprintf(fp,"\n"); 896 897 return 0; 898 } 899 900 static int xfrm_spd_getinfo(int argc, char **argv) 901 { 902 struct rtnl_handle rth; 903 struct { 904 struct nlmsghdr n; 905 __u32 flags; 906 char ans[128]; 907 } req; 908 909 memset(&req, 0, sizeof(req)); 910 911 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(__u32)); 912 req.n.nlmsg_flags = NLM_F_REQUEST; 913 req.n.nlmsg_type = XFRM_MSG_GETSPDINFO; 914 req.flags = 0XFFFFFFFF; 915 916 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) 917 exit(1); 918 919 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) 920 exit(2); 921 922 print_spdinfo(&req.n, (void*)stdout); 923 924 rtnl_close(&rth); 925 926 return 0; 927 } 928 929 static int xfrm_policy_flush(int argc, char **argv) 930 { 931 struct rtnl_handle rth; 932 struct { 933 struct nlmsghdr n; 934 char buf[RTA_BUF_SIZE]; 935 } req; 936 char *ptypep = NULL; 937 struct xfrm_userpolicy_type upt; 938 939 memset(&req, 0, sizeof(req)); 940 memset(&upt, 0, sizeof(upt)); 941 942 req.n.nlmsg_len = NLMSG_LENGTH(0); /* nlmsg data is nothing */ 943 req.n.nlmsg_flags = NLM_F_REQUEST; 944 req.n.nlmsg_type = XFRM_MSG_FLUSHPOLICY; 945 946 while (argc > 0) { 947 if (strcmp(*argv, "ptype") == 0) { 948 if (ptypep) 949 duparg("ptype", *argv); 950 ptypep = *argv; 951 952 NEXT_ARG(); 953 xfrm_policy_ptype_parse(&upt.type, &argc, &argv); 954 } else 955 invarg("unknown", *argv); 956 957 argc--; argv++; 958 } 959 960 if (ptypep) { 961 addattr_l(&req.n, sizeof(req), XFRMA_POLICY_TYPE, 962 (void *)&upt, sizeof(upt)); 963 } 964 965 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) 966 exit(1); 967 968 if (show_stats > 1) 969 fprintf(stderr, "Flush policy\n"); 970 971 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) 972 exit(2); 973 974 rtnl_close(&rth); 975 976 return 0; 977 } 978 979 int do_xfrm_policy(int argc, char **argv) 980 { 981 if (argc < 1) 982 return xfrm_policy_list_or_deleteall(0, NULL, 0); 983 984 if (matches(*argv, "add") == 0) 985 return xfrm_policy_modify(XFRM_MSG_NEWPOLICY, 0, 986 argc-1, argv+1); 987 if (matches(*argv, "update") == 0) 988 return xfrm_policy_modify(XFRM_MSG_UPDPOLICY, 0, 989 argc-1, argv+1); 990 if (matches(*argv, "delete") == 0) 991 return xfrm_policy_delete(argc-1, argv+1); 992 if (matches(*argv, "deleteall") == 0 || matches(*argv, "delall") == 0) 993 return xfrm_policy_list_or_deleteall(argc-1, argv+1, 1); 994 if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0 995 || matches(*argv, "lst") == 0) 996 return xfrm_policy_list_or_deleteall(argc-1, argv+1, 0); 997 if (matches(*argv, "get") == 0) 998 return xfrm_policy_get(argc-1, argv+1); 999 if (matches(*argv, "flush") == 0) 1000 return xfrm_policy_flush(argc-1, argv+1); 1001 if (matches(*argv, "count") == 0) 1002 return xfrm_spd_getinfo(argc, argv); 1003 if (matches(*argv, "help") == 0) 1004 usage(); 1005 fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm policy help\".\n", *argv); 1006 exit(-1); 1007 } 1008