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