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 "utils.h" 35#include "xfrm.h" 36#include "ip_common.h" 37 38//#define NLMSG_DELETEALL_BUF_SIZE (4096-512) 39#define NLMSG_DELETEALL_BUF_SIZE 8192 40 41/* 42 * Receiving buffer defines: 43 * nlmsg 44 * data = struct xfrm_userpolicy_info 45 * rtattr 46 * data = struct xfrm_user_tmpl[] 47 */ 48#define NLMSG_BUF_SIZE 4096 49#define RTA_BUF_SIZE 2048 50#define XFRM_TMPLS_BUF_SIZE 1024 51 52static void usage(void) __attribute__((noreturn)); 53 54static void usage(void) 55{ 56 fprintf(stderr, "Usage: ip xfrm policy { add | update } dir DIR SELECTOR [ index INDEX ] \n"); 57 fprintf(stderr, " [ action ACTION ] [ priority PRIORITY ] [ LIMIT-LIST ] [ TMPL-LIST ]\n"); 58 fprintf(stderr, "Usage: ip xfrm policy { delete | get } dir DIR [ SELECTOR | index INDEX ]\n"); 59 fprintf(stderr, "Usage: ip xfrm policy { deleteall | list } [ dir DIR ] [ SELECTOR ]\n"); 60 fprintf(stderr, " [ index INDEX ] [ action ACTION ] [ priority PRIORITY ]\n"); 61 fprintf(stderr, "Usage: ip xfrm policy flush\n"); 62 fprintf(stderr, "DIR := [ in | out | fwd ]\n"); 63 64 fprintf(stderr, "SELECTOR := src ADDR[/PLEN] dst ADDR[/PLEN] [ UPSPEC ] [ dev DEV ]\n"); 65 66 fprintf(stderr, "UPSPEC := proto PROTO [ [ sport PORT ] [ dport PORT ] |\n"); 67 fprintf(stderr, " [ type NUMBER ] [ code NUMBER ] ]\n"); 68 69 //fprintf(stderr, "DEV - device name(default=none)\n"); 70 71 fprintf(stderr, "ACTION := [ allow | block ](default=allow)\n"); 72 73 //fprintf(stderr, "PRIORITY - priority value(default=0)\n"); 74 75 fprintf(stderr, "LIMIT-LIST := [ LIMIT-LIST ] | [ limit LIMIT ]\n"); 76 fprintf(stderr, "LIMIT := [ [time-soft|time-hard|time-use-soft|time-use-hard] SECONDS ] |\n"); 77 fprintf(stderr, " [ [byte-soft|byte-hard] SIZE ] | [ [packet-soft|packet-hard] NUMBER ]\n"); 78 79 fprintf(stderr, "TMPL-LIST := [ TMPL-LIST ] | [ tmpl TMPL ]\n"); 80 fprintf(stderr, "TMPL := ID [ mode MODE ] [ reqid REQID ] [ level LEVEL ]\n"); 81 fprintf(stderr, "ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM_PROTO ] [ spi SPI ]\n"); 82 83 //fprintf(stderr, "XFRM_PROTO := [ esp | ah | comp ]\n"); 84 fprintf(stderr, "XFRM_PROTO := [ "); 85 fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ESP)); 86 fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_AH)); 87 fprintf(stderr, "%s", strxf_xfrmproto(IPPROTO_COMP)); 88 fprintf(stderr, " ]\n"); 89 90 fprintf(stderr, "MODE := [ transport | tunnel ](default=transport)\n"); 91 //fprintf(stderr, "REQID - number(default=0)\n"); 92 fprintf(stderr, "LEVEL := [ required | use ](default=required)\n"); 93 94 exit(-1); 95} 96 97static int xfrm_policy_dir_parse(__u8 *dir, int *argcp, char ***argvp) 98{ 99 int argc = *argcp; 100 char **argv = *argvp; 101 102 if (strcmp(*argv, "in") == 0) 103 *dir = XFRM_POLICY_IN; 104 else if (strcmp(*argv, "out") == 0) 105 *dir = XFRM_POLICY_OUT; 106 else if (strcmp(*argv, "fwd") == 0) 107 *dir = XFRM_POLICY_FWD; 108 else 109 invarg("\"DIR\" is invalid", *argv); 110 111 *argcp = argc; 112 *argvp = argv; 113 114 return 0; 115} 116 117static int xfrm_tmpl_parse(struct xfrm_user_tmpl *tmpl, 118 int *argcp, char ***argvp) 119{ 120 int argc = *argcp; 121 char **argv = *argvp; 122 char *idp = NULL; 123 124 while (1) { 125 if (strcmp(*argv, "mode") == 0) { 126 NEXT_ARG(); 127 xfrm_mode_parse(&tmpl->mode, &argc, &argv); 128 } else if (strcmp(*argv, "reqid") == 0) { 129 NEXT_ARG(); 130 xfrm_reqid_parse(&tmpl->reqid, &argc, &argv); 131 } else if (strcmp(*argv, "level") == 0) { 132 NEXT_ARG(); 133 134 if (strcmp(*argv, "required") == 0) 135 tmpl->optional = 0; 136 else if (strcmp(*argv, "use") == 0) 137 tmpl->optional = 1; 138 else 139 invarg("\"LEVEL\" is invalid\n", *argv); 140 141 } else { 142 if (idp) { 143 PREV_ARG(); /* back track */ 144 break; 145 } 146 idp = *argv; 147 xfrm_id_parse(&tmpl->saddr, &tmpl->id, &tmpl->family, 148 0, &argc, &argv); 149 if (preferred_family == AF_UNSPEC) 150 preferred_family = tmpl->family; 151 } 152 153 if (!NEXT_ARG_OK()) 154 break; 155 156 NEXT_ARG(); 157 } 158 if (argc == *argcp) 159 missarg("TMPL"); 160 161 *argcp = argc; 162 *argvp = argv; 163 164 return 0; 165} 166 167static int xfrm_policy_modify(int cmd, unsigned flags, int argc, char **argv) 168{ 169 struct rtnl_handle rth; 170 struct { 171 struct nlmsghdr n; 172 struct xfrm_userpolicy_info xpinfo; 173 char buf[RTA_BUF_SIZE]; 174 } req; 175 char *dirp = NULL; 176 char *selp = NULL; 177 char tmpls_buf[XFRM_TMPLS_BUF_SIZE]; 178 int tmpls_len = 0; 179 180 memset(&req, 0, sizeof(req)); 181 memset(&tmpls_buf, 0, sizeof(tmpls_buf)); 182 183 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpinfo)); 184 req.n.nlmsg_flags = NLM_F_REQUEST|flags; 185 req.n.nlmsg_type = cmd; 186 req.xpinfo.sel.family = preferred_family; 187 188 req.xpinfo.lft.soft_byte_limit = XFRM_INF; 189 req.xpinfo.lft.hard_byte_limit = XFRM_INF; 190 req.xpinfo.lft.soft_packet_limit = XFRM_INF; 191 req.xpinfo.lft.hard_packet_limit = XFRM_INF; 192 193 while (argc > 0) { 194 if (strcmp(*argv, "dir") == 0) { 195 if (dirp) 196 duparg("dir", *argv); 197 dirp = *argv; 198 199 NEXT_ARG(); 200 xfrm_policy_dir_parse(&req.xpinfo.dir, &argc, &argv); 201 202 filter.dir_mask = XFRM_FILTER_MASK_FULL; 203 204 } else if (strcmp(*argv, "index") == 0) { 205 NEXT_ARG(); 206 if (get_u32(&req.xpinfo.index, *argv, 0)) 207 invarg("\"INDEX\" is invalid", *argv); 208 209 filter.index_mask = XFRM_FILTER_MASK_FULL; 210 211 } else if (strcmp(*argv, "action") == 0) { 212 NEXT_ARG(); 213 if (strcmp(*argv, "allow") == 0) 214 req.xpinfo.action = XFRM_POLICY_ALLOW; 215 else if (strcmp(*argv, "block") == 0) 216 req.xpinfo.action = XFRM_POLICY_BLOCK; 217 else 218 invarg("\"action\" value is invalid\n", *argv); 219 220 filter.action_mask = XFRM_FILTER_MASK_FULL; 221 222 } else if (strcmp(*argv, "priority") == 0) { 223 NEXT_ARG(); 224 if (get_u32(&req.xpinfo.priority, *argv, 0)) 225 invarg("\"PRIORITY\" is invalid", *argv); 226 227 filter.priority_mask = XFRM_FILTER_MASK_FULL; 228 229 } else if (strcmp(*argv, "limit") == 0) { 230 NEXT_ARG(); 231 xfrm_lifetime_cfg_parse(&req.xpinfo.lft, &argc, &argv); 232 } else if (strcmp(*argv, "tmpl") == 0) { 233 struct xfrm_user_tmpl *tmpl; 234 235 if (tmpls_len + sizeof(*tmpl) > sizeof(tmpls_buf)) { 236 fprintf(stderr, "Too many tmpls: buffer overflow\n"); 237 exit(1); 238 } 239 tmpl = (struct xfrm_user_tmpl *)((char *)tmpls_buf + tmpls_len); 240 241 tmpl->family = preferred_family; 242 tmpl->aalgos = (~(__u32)0); 243 tmpl->ealgos = (~(__u32)0); 244 tmpl->calgos = (~(__u32)0); 245 246 NEXT_ARG(); 247 xfrm_tmpl_parse(tmpl, &argc, &argv); 248 249 tmpls_len += sizeof(*tmpl); 250 } else { 251 if (selp) 252 duparg("unknown", *argv); 253 selp = *argv; 254 255 xfrm_selector_parse(&req.xpinfo.sel, &argc, &argv); 256 if (preferred_family == AF_UNSPEC) 257 preferred_family = req.xpinfo.sel.family; 258 } 259 260 argc--; argv++; 261 } 262 263 if (!dirp) { 264 fprintf(stderr, "Not enough information: \"DIR\" is required.\n"); 265 exit(1); 266 } 267 268 if (tmpls_len > 0) { 269 addattr_l(&req.n, sizeof(req), XFRMA_TMPL, 270 (void *)tmpls_buf, tmpls_len); 271 } 272 273 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) 274 exit(1); 275 276 if (req.xpinfo.sel.family == AF_UNSPEC) 277 req.xpinfo.sel.family = AF_INET; 278 279 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) 280 exit(2); 281 282 rtnl_close(&rth); 283 284 return 0; 285} 286 287static int xfrm_policy_filter_match(struct xfrm_userpolicy_info *xpinfo) 288{ 289 if (!filter.use) 290 return 1; 291 292 if ((xpinfo->dir^filter.xpinfo.dir)&filter.dir_mask) 293 return 0; 294 295 if (filter.sel_src_mask) { 296 if (xfrm_addr_match(&xpinfo->sel.saddr, &filter.xpinfo.sel.saddr, 297 filter.sel_src_mask)) 298 return 0; 299 } 300 301 if (filter.sel_dst_mask) { 302 if (xfrm_addr_match(&xpinfo->sel.daddr, &filter.xpinfo.sel.daddr, 303 filter.sel_dst_mask)) 304 return 0; 305 } 306 307 if ((xpinfo->sel.ifindex^filter.xpinfo.sel.ifindex)&filter.sel_dev_mask) 308 return 0; 309 310 if ((xpinfo->sel.proto^filter.xpinfo.sel.proto)&filter.upspec_proto_mask) 311 return 0; 312 313 if (filter.upspec_sport_mask) { 314 if ((xpinfo->sel.sport^filter.xpinfo.sel.sport)&filter.upspec_sport_mask) 315 return 0; 316 } 317 318 if (filter.upspec_dport_mask) { 319 if ((xpinfo->sel.dport^filter.xpinfo.sel.dport)&filter.upspec_dport_mask) 320 return 0; 321 } 322 323 if ((xpinfo->index^filter.xpinfo.index)&filter.index_mask) 324 return 0; 325 326 if ((xpinfo->action^filter.xpinfo.action)&filter.action_mask) 327 return 0; 328 329 if ((xpinfo->priority^filter.xpinfo.priority)&filter.priority_mask) 330 return 0; 331 332 return 1; 333} 334 335int xfrm_policy_print(const struct sockaddr_nl *who, struct nlmsghdr *n, 336 void *arg) 337{ 338 struct rtattr * tb[XFRMA_MAX+1]; 339 struct rtattr * rta; 340 struct xfrm_userpolicy_info *xpinfo = NULL; 341 struct xfrm_user_polexpire *xpexp = NULL; 342 struct xfrm_userpolicy_id *xpid = NULL; 343 FILE *fp = (FILE*)arg; 344 int len = n->nlmsg_len; 345 346 if (n->nlmsg_type != XFRM_MSG_NEWPOLICY && 347 n->nlmsg_type != XFRM_MSG_DELPOLICY && 348 n->nlmsg_type != XFRM_MSG_UPDPOLICY && 349 n->nlmsg_type != XFRM_MSG_POLEXPIRE) { 350 fprintf(stderr, "Not a policy: %08x %08x %08x\n", 351 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); 352 return 0; 353 } 354 355 if (n->nlmsg_type == XFRM_MSG_DELPOLICY) { 356 xpid = NLMSG_DATA(n); 357 len -= NLMSG_LENGTH(sizeof(*xpid)); 358 } else if (n->nlmsg_type == XFRM_MSG_POLEXPIRE) { 359 xpexp = NLMSG_DATA(n); 360 xpinfo = &xpexp->pol; 361 len -= NLMSG_LENGTH(sizeof(*xpexp)); 362 } else { 363 xpexp = NULL; 364 xpinfo = NLMSG_DATA(n); 365 len -= NLMSG_LENGTH(sizeof(*xpinfo)); 366 } 367 368 if (len < 0) { 369 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); 370 return -1; 371 } 372 373 if (xpinfo && !xfrm_policy_filter_match(xpinfo)) 374 return 0; 375 376 if (n->nlmsg_type == XFRM_MSG_DELPOLICY) 377 fprintf(fp, "Deleted "); 378 else if (n->nlmsg_type == XFRM_MSG_UPDPOLICY) 379 fprintf(fp, "Updated "); 380 else if (n->nlmsg_type == XFRM_MSG_POLEXPIRE) 381 fprintf(fp, "Expired "); 382 383 if (n->nlmsg_type == XFRM_MSG_DELPOLICY) 384 rta = XFRMPID_RTA(xpid); 385 else if (n->nlmsg_type == XFRM_MSG_POLEXPIRE) 386 rta = XFRMPEXP_RTA(xpexp); 387 else 388 rta = XFRMP_RTA(xpinfo); 389 390 parse_rtattr(tb, XFRMA_MAX, rta, len); 391 392 if (n->nlmsg_type == XFRM_MSG_DELPOLICY) { 393 //xfrm_policy_id_print(); 394 if (!tb[XFRMA_POLICY]) { 395 fprintf(stderr, "Buggy XFRM_MSG_DELPOLICY: no XFRMA_POLICY\n"); 396 return -1; 397 } 398 if (RTA_PAYLOAD(tb[XFRMA_POLICY]) < sizeof(*xpinfo)) { 399 fprintf(stderr, "Buggy XFRM_MSG_DELPOLICY: too short XFRMA_POLICY len\n"); 400 return -1; 401 } 402 xpinfo = (struct xfrm_userpolicy_info *)RTA_DATA(tb[XFRMA_POLICY]); 403 } 404 405 xfrm_policy_info_print(xpinfo, tb, fp, NULL, NULL); 406 407 if (n->nlmsg_type == XFRM_MSG_POLEXPIRE) { 408 fprintf(fp, "\t"); 409 fprintf(fp, "hard %u", xpexp->hard); 410 fprintf(fp, "%s", _SL_); 411 } 412 413 if (oneline) 414 fprintf(fp, "\n"); 415 fflush(fp); 416 417 return 0; 418} 419 420static int xfrm_policy_get_or_delete(int argc, char **argv, int delete, 421 void *res_nlbuf) 422{ 423 struct rtnl_handle rth; 424 struct { 425 struct nlmsghdr n; 426 struct xfrm_userpolicy_id xpid; 427 } req; 428 char *dirp = NULL; 429 char *selp = NULL; 430 char *indexp = NULL; 431 432 memset(&req, 0, sizeof(req)); 433 434 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpid)); 435 req.n.nlmsg_flags = NLM_F_REQUEST; 436 req.n.nlmsg_type = delete ? XFRM_MSG_DELPOLICY : XFRM_MSG_GETPOLICY; 437 438 while (argc > 0) { 439 if (strcmp(*argv, "dir") == 0) { 440 if (dirp) 441 duparg("dir", *argv); 442 dirp = *argv; 443 444 NEXT_ARG(); 445 xfrm_policy_dir_parse(&req.xpid.dir, &argc, &argv); 446 447 } else if (strcmp(*argv, "index") == 0) { 448 if (indexp) 449 duparg("index", *argv); 450 indexp = *argv; 451 452 NEXT_ARG(); 453 if (get_u32(&req.xpid.index, *argv, 0)) 454 invarg("\"INDEX\" is invalid", *argv); 455 456 } else { 457 if (selp) 458 invarg("unknown", *argv); 459 selp = *argv; 460 461 xfrm_selector_parse(&req.xpid.sel, &argc, &argv); 462 if (preferred_family == AF_UNSPEC) 463 preferred_family = req.xpid.sel.family; 464 465 } 466 467 argc--; argv++; 468 } 469 470 if (!dirp) { 471 fprintf(stderr, "Not enough information: \"DIR\" is required.\n"); 472 exit(1); 473 } 474 if (!selp && !indexp) { 475 fprintf(stderr, "Not enough information: either \"SELECTOR\" or \"INDEX\" is required.\n"); 476 exit(1); 477 } 478 if (selp && indexp) 479 duparg2("SELECTOR", "INDEX"); 480 481 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) 482 exit(1); 483 484 if (req.xpid.sel.family == AF_UNSPEC) 485 req.xpid.sel.family = AF_INET; 486 487 if (rtnl_talk(&rth, &req.n, 0, 0, res_nlbuf, NULL, NULL) < 0) 488 exit(2); 489 490 rtnl_close(&rth); 491 492 return 0; 493} 494 495static int xfrm_policy_delete(int argc, char **argv) 496{ 497 return xfrm_policy_get_or_delete(argc, argv, 1, NULL); 498} 499 500static int xfrm_policy_get(int argc, char **argv) 501{ 502 char buf[NLMSG_BUF_SIZE]; 503 struct nlmsghdr *n = (struct nlmsghdr *)buf; 504 505 memset(buf, 0, sizeof(buf)); 506 507 xfrm_policy_get_or_delete(argc, argv, 0, n); 508 509 if (xfrm_policy_print(NULL, n, (void*)stdout) < 0) { 510 fprintf(stderr, "An error :-)\n"); 511 exit(1); 512 } 513 514 return 0; 515} 516 517/* 518 * With an existing policy of nlmsg, make new nlmsg for deleting the policy 519 * and store it to buffer. 520 */ 521static int xfrm_policy_keep(const struct sockaddr_nl *who, 522 struct nlmsghdr *n, 523 void *arg) 524{ 525 struct xfrm_buffer *xb = (struct xfrm_buffer *)arg; 526 struct rtnl_handle *rth = xb->rth; 527 struct xfrm_userpolicy_info *xpinfo = NLMSG_DATA(n); 528 int len = n->nlmsg_len; 529 struct nlmsghdr *new_n; 530 struct xfrm_userpolicy_id *xpid; 531 532 if (n->nlmsg_type != XFRM_MSG_NEWPOLICY) { 533 fprintf(stderr, "Not a policy: %08x %08x %08x\n", 534 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); 535 return 0; 536 } 537 538 len -= NLMSG_LENGTH(sizeof(*xpinfo)); 539 if (len < 0) { 540 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); 541 return -1; 542 } 543 544 if (!xfrm_policy_filter_match(xpinfo)) 545 return 0; 546 547 if (xb->offset > xb->size) { 548 fprintf(stderr, "Policy buffer overflow\n"); 549 return -1; 550 } 551 552 new_n = (struct nlmsghdr *)(xb->buf + xb->offset); 553 new_n->nlmsg_len = NLMSG_LENGTH(sizeof(*xpid)); 554 new_n->nlmsg_flags = NLM_F_REQUEST; 555 new_n->nlmsg_type = XFRM_MSG_DELPOLICY; 556 new_n->nlmsg_seq = ++rth->seq; 557 558 xpid = NLMSG_DATA(new_n); 559 memcpy(&xpid->sel, &xpinfo->sel, sizeof(xpid->sel)); 560 xpid->dir = xpinfo->dir; 561 xpid->index = xpinfo->index; 562 563 xb->offset += new_n->nlmsg_len; 564 xb->nlmsg_count ++; 565 566 return 0; 567} 568 569static int xfrm_policy_list_or_deleteall(int argc, char **argv, int deleteall) 570{ 571 char *selp = NULL; 572 struct rtnl_handle rth; 573 574 if (argc > 0) 575 filter.use = 1; 576 filter.xpinfo.sel.family = preferred_family; 577 578 while (argc > 0) { 579 if (strcmp(*argv, "dir") == 0) { 580 NEXT_ARG(); 581 xfrm_policy_dir_parse(&filter.xpinfo.dir, &argc, &argv); 582 583 filter.dir_mask = XFRM_FILTER_MASK_FULL; 584 585 } else if (strcmp(*argv, "index") == 0) { 586 NEXT_ARG(); 587 if (get_u32(&filter.xpinfo.index, *argv, 0)) 588 invarg("\"INDEX\" is invalid", *argv); 589 590 filter.index_mask = XFRM_FILTER_MASK_FULL; 591 592 } else if (strcmp(*argv, "action") == 0) { 593 NEXT_ARG(); 594 if (strcmp(*argv, "allow") == 0) 595 filter.xpinfo.action = XFRM_POLICY_ALLOW; 596 else if (strcmp(*argv, "block") == 0) 597 filter.xpinfo.action = XFRM_POLICY_BLOCK; 598 else 599 invarg("\"ACTION\" is invalid\n", *argv); 600 601 filter.action_mask = XFRM_FILTER_MASK_FULL; 602 603 } else if (strcmp(*argv, "priority") == 0) { 604 NEXT_ARG(); 605 if (get_u32(&filter.xpinfo.priority, *argv, 0)) 606 invarg("\"PRIORITY\" is invalid", *argv); 607 608 filter.priority_mask = XFRM_FILTER_MASK_FULL; 609 610 } else { 611 if (selp) 612 invarg("unknown", *argv); 613 selp = *argv; 614 615 xfrm_selector_parse(&filter.xpinfo.sel, &argc, &argv); 616 if (preferred_family == AF_UNSPEC) 617 preferred_family = filter.xpinfo.sel.family; 618 619 } 620 621 argc--; argv++; 622 } 623 624 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) 625 exit(1); 626 627 if (deleteall) { 628 struct xfrm_buffer xb; 629 char buf[NLMSG_DELETEALL_BUF_SIZE]; 630 int i; 631 632 xb.buf = buf; 633 xb.size = sizeof(buf); 634 xb.rth = &rth; 635 636 for (i = 0; ; i++) { 637 xb.offset = 0; 638 xb.nlmsg_count = 0; 639 640 if (show_stats > 1) 641 fprintf(stderr, "Delete-all round = %d\n", i); 642 643 if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETPOLICY) < 0) { 644 perror("Cannot send dump request"); 645 exit(1); 646 } 647 648 if (rtnl_dump_filter(&rth, xfrm_policy_keep, &xb, NULL, NULL) < 0) { 649 fprintf(stderr, "Delete-all terminated\n"); 650 exit(1); 651 } 652 if (xb.nlmsg_count == 0) { 653 if (show_stats > 1) 654 fprintf(stderr, "Delete-all completed\n"); 655 break; 656 } 657 658 if (rtnl_send(&rth, xb.buf, xb.offset) < 0) { 659 perror("Failed to send delete-all request\n"); 660 exit(1); 661 } 662 if (show_stats > 1) 663 fprintf(stderr, "Delete-all nlmsg count = %d\n", xb.nlmsg_count); 664 665 xb.offset = 0; 666 xb.nlmsg_count = 0; 667 } 668 } else { 669 if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETPOLICY) < 0) { 670 perror("Cannot send dump request"); 671 exit(1); 672 } 673 674 if (rtnl_dump_filter(&rth, xfrm_policy_print, stdout, NULL, NULL) < 0) { 675 fprintf(stderr, "Dump terminated\n"); 676 exit(1); 677 } 678 } 679 680 rtnl_close(&rth); 681 682 exit(0); 683} 684 685static int xfrm_policy_flush(void) 686{ 687 struct rtnl_handle rth; 688 struct { 689 struct nlmsghdr n; 690 } req; 691 692 memset(&req, 0, sizeof(req)); 693 694 req.n.nlmsg_len = NLMSG_LENGTH(0); /* nlmsg data is nothing */ 695 req.n.nlmsg_flags = NLM_F_REQUEST; 696 req.n.nlmsg_type = XFRM_MSG_FLUSHPOLICY; 697 698 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) 699 exit(1); 700 701 if (show_stats > 1) 702 fprintf(stderr, "Flush policy\n"); 703 704 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) 705 exit(2); 706 707 rtnl_close(&rth); 708 709 return 0; 710} 711 712int do_xfrm_policy(int argc, char **argv) 713{ 714 if (argc < 1) 715 return xfrm_policy_list_or_deleteall(0, NULL, 0); 716 717 if (matches(*argv, "add") == 0) 718 return xfrm_policy_modify(XFRM_MSG_NEWPOLICY, 0, 719 argc-1, argv+1); 720 if (matches(*argv, "update") == 0) 721 return xfrm_policy_modify(XFRM_MSG_UPDPOLICY, 0, 722 argc-1, argv+1); 723 if (matches(*argv, "delete") == 0) 724 return xfrm_policy_delete(argc-1, argv+1); 725 if (matches(*argv, "deleteall") == 0 || matches(*argv, "delall") == 0) 726 return xfrm_policy_list_or_deleteall(argc-1, argv+1, 1); 727 if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0 728 || matches(*argv, "lst") == 0) 729 return xfrm_policy_list_or_deleteall(argc-1, argv+1, 0); 730 if (matches(*argv, "get") == 0) 731 return xfrm_policy_get(argc-1, argv+1); 732 if (matches(*argv, "flush") == 0) 733 return xfrm_policy_flush(); 734 if (matches(*argv, "help") == 0) 735 usage(); 736 fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm policy help\".\n", *argv); 737 exit(-1); 738} 739