1 /* $USAGI: $ */ 2 3 /* 4 * Copyright (C)2005 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 ipmonitor.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 <endian.h> 32 #include <linux/xfrm.h> 33 #include "utils.h" 34 #include "xfrm.h" 35 #include "ip_common.h" 36 37 static void usage(void) __attribute__((noreturn)); 38 39 static void usage(void) 40 { 41 fprintf(stderr, "Usage: ip xfrm monitor [ all | LISTofXFRM-OBJECTS ]\n"); 42 exit(-1); 43 } 44 45 static int xfrm_acquire_print(const struct sockaddr_nl *who, 46 struct nlmsghdr *n, void *arg) 47 { 48 FILE *fp = (FILE*)arg; 49 struct xfrm_user_acquire *xacq = NLMSG_DATA(n); 50 int len = n->nlmsg_len; 51 struct rtattr * tb[XFRMA_MAX+1]; 52 __u16 family; 53 54 len -= NLMSG_LENGTH(sizeof(*xacq)); 55 if (len < 0) { 56 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); 57 return -1; 58 } 59 60 parse_rtattr(tb, XFRMA_MAX, XFRMACQ_RTA(xacq), len); 61 62 family = xacq->sel.family; 63 if (family == AF_UNSPEC) 64 family = xacq->policy.sel.family; 65 if (family == AF_UNSPEC) 66 family = preferred_family; 67 68 fprintf(fp, "acquire "); 69 70 fprintf(fp, "proto %s ", strxf_xfrmproto(xacq->id.proto)); 71 if (show_stats > 0 || xacq->id.spi) { 72 __u32 spi = ntohl(xacq->id.spi); 73 fprintf(fp, "spi 0x%08x", spi); 74 if (show_stats > 0) 75 fprintf(fp, "(%u)", spi); 76 fprintf(fp, " "); 77 } 78 fprintf(fp, "%s", _SL_); 79 80 xfrm_selector_print(&xacq->sel, family, fp, " sel "); 81 82 xfrm_policy_info_print(&xacq->policy, tb, fp, " ", " policy "); 83 84 if (show_stats > 0) 85 fprintf(fp, " seq 0x%08u ", xacq->seq); 86 if (show_stats > 0) { 87 fprintf(fp, "%s-mask %s ", 88 strxf_algotype(XFRMA_ALG_CRYPT), 89 strxf_mask32(xacq->ealgos)); 90 fprintf(fp, "%s-mask %s ", 91 strxf_algotype(XFRMA_ALG_AUTH), 92 strxf_mask32(xacq->aalgos)); 93 fprintf(fp, "%s-mask %s", 94 strxf_algotype(XFRMA_ALG_COMP), 95 strxf_mask32(xacq->calgos)); 96 } 97 fprintf(fp, "%s", _SL_); 98 99 if (oneline) 100 fprintf(fp, "\n"); 101 fflush(fp); 102 103 return 0; 104 } 105 106 static int xfrm_state_flush_print(const struct sockaddr_nl *who, 107 struct nlmsghdr *n, void *arg) 108 { 109 FILE *fp = (FILE*)arg; 110 struct xfrm_usersa_flush *xsf = NLMSG_DATA(n); 111 int len = n->nlmsg_len; 112 const char *str; 113 114 len -= NLMSG_SPACE(sizeof(*xsf)); 115 if (len < 0) { 116 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); 117 return -1; 118 } 119 120 fprintf(fp, "Flushed state "); 121 122 str = strxf_xfrmproto(xsf->proto); 123 if (str) 124 fprintf(fp, "proto %s", str); 125 else 126 fprintf(fp, "proto %u", xsf->proto); 127 fprintf(fp, "%s", _SL_); 128 129 if (oneline) 130 fprintf(fp, "\n"); 131 fflush(fp); 132 133 return 0; 134 } 135 136 static int xfrm_policy_flush_print(const struct sockaddr_nl *who, 137 struct nlmsghdr *n, void *arg) 138 { 139 struct rtattr * tb[XFRMA_MAX+1]; 140 FILE *fp = (FILE*)arg; 141 int len = n->nlmsg_len; 142 143 len -= NLMSG_SPACE(0); 144 if (len < 0) { 145 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); 146 return -1; 147 } 148 149 fprintf(fp, "Flushed policy "); 150 151 parse_rtattr(tb, XFRMA_MAX, NLMSG_DATA(n), len); 152 153 if (tb[XFRMA_POLICY_TYPE]) { 154 struct xfrm_userpolicy_type *upt; 155 156 fprintf(fp, "ptype "); 157 158 if (RTA_PAYLOAD(tb[XFRMA_POLICY_TYPE]) < sizeof(*upt)) 159 fprintf(fp, "(ERROR truncated)"); 160 161 upt = (struct xfrm_userpolicy_type *)RTA_DATA(tb[XFRMA_POLICY_TYPE]); 162 fprintf(fp, "%s ", strxf_ptype(upt->type)); 163 } 164 165 fprintf(fp, "%s", _SL_); 166 167 if (oneline) 168 fprintf(fp, "\n"); 169 fflush(fp); 170 171 return 0; 172 } 173 174 static int xfrm_report_print(const struct sockaddr_nl *who, 175 struct nlmsghdr *n, void *arg) 176 { 177 FILE *fp = (FILE*)arg; 178 struct xfrm_user_report *xrep = NLMSG_DATA(n); 179 int len = n->nlmsg_len; 180 struct rtattr * tb[XFRMA_MAX+1]; 181 __u16 family; 182 183 len -= NLMSG_LENGTH(sizeof(*xrep)); 184 if (len < 0) { 185 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); 186 return -1; 187 } 188 189 family = xrep->sel.family; 190 if (family == AF_UNSPEC) 191 family = preferred_family; 192 193 fprintf(fp, "report "); 194 195 fprintf(fp, "proto %s ", strxf_xfrmproto(xrep->proto)); 196 fprintf(fp, "%s", _SL_); 197 198 xfrm_selector_print(&xrep->sel, family, fp, " sel "); 199 200 parse_rtattr(tb, XFRMA_MAX, XFRMREP_RTA(xrep), len); 201 202 xfrm_xfrma_print(tb, family, fp, " "); 203 204 if (oneline) 205 fprintf(fp, "\n"); 206 207 return 0; 208 } 209 210 void xfrm_ae_flags_print(__u32 flags, void *arg) 211 { 212 FILE *fp = (FILE*)arg; 213 fprintf(fp, " (0x%x) ", flags); 214 if (!flags) 215 return; 216 if (flags & XFRM_AE_CR) 217 fprintf(fp, " replay update "); 218 if (flags & XFRM_AE_CE) 219 fprintf(fp, " timer expired "); 220 if (flags & XFRM_AE_CU) 221 fprintf(fp, " policy updated "); 222 223 } 224 225 static void xfrm_usersa_print(const struct xfrm_usersa_id *sa_id, __u32 reqid, FILE *fp) 226 { 227 char buf[256]; 228 229 buf[0] = 0; 230 fprintf(fp, "dst %s ", rt_addr_n2a(sa_id->family, 231 sizeof(sa_id->daddr), &sa_id->daddr, buf, sizeof(buf))); 232 233 fprintf(fp, " reqid 0x%x", reqid); 234 235 fprintf(fp, " protocol %s ", strxf_proto(sa_id->proto)); 236 fprintf(fp, " SPI 0x%x", ntohl(sa_id->spi)); 237 } 238 239 static int xfrm_ae_print(const struct sockaddr_nl *who, 240 struct nlmsghdr *n, void *arg) 241 { 242 FILE *fp = (FILE*)arg; 243 struct xfrm_aevent_id *id = NLMSG_DATA(n); 244 char abuf[256]; 245 246 fprintf(fp, "Async event "); 247 xfrm_ae_flags_print(id->flags, arg); 248 fprintf(fp,"\n\t"); 249 memset(abuf, '\0', sizeof(abuf)); 250 fprintf(fp, "src %s ", rt_addr_n2a(id->sa_id.family, 251 sizeof(id->saddr), &id->saddr, 252 abuf, sizeof(abuf))); 253 254 xfrm_usersa_print(&id->sa_id, id->reqid, fp); 255 256 fprintf(fp, "\n"); 257 fflush(fp); 258 259 return 0; 260 } 261 262 static void xfrm_print_addr(FILE *fp, int family, xfrm_address_t *a, size_t s) 263 { 264 char buf[256]; 265 266 buf[0] = 0; 267 fprintf(fp, "%s", rt_addr_n2a(family, s, a, buf, sizeof(buf))); 268 } 269 270 static int xfrm_mapping_print(const struct sockaddr_nl *who, 271 struct nlmsghdr *n, void *arg) 272 { 273 FILE *fp = (FILE*)arg; 274 struct xfrm_user_mapping *map = NLMSG_DATA(n); 275 276 fprintf(fp, "Mapping change "); 277 xfrm_print_addr(fp, map->id.family, &map->old_saddr, 278 sizeof(map->old_saddr)); 279 280 fprintf(fp, ":%d -> ", ntohs(map->old_sport)); 281 xfrm_print_addr(fp, map->id.family, &map->new_saddr, 282 sizeof(map->new_saddr)); 283 fprintf(fp, ":%d\n\t", ntohs(map->new_sport)); 284 285 xfrm_usersa_print(&map->id, map->reqid, fp); 286 287 fprintf(fp, "\n"); 288 fflush(fp); 289 return 0; 290 } 291 292 static int xfrm_accept_msg(const struct sockaddr_nl *who, 293 struct nlmsghdr *n, void *arg) 294 { 295 FILE *fp = (FILE*)arg; 296 297 if (timestamp) 298 print_timestamp(fp); 299 300 switch (n->nlmsg_type) { 301 case XFRM_MSG_NEWSA: 302 case XFRM_MSG_DELSA: 303 case XFRM_MSG_UPDSA: 304 case XFRM_MSG_EXPIRE: 305 xfrm_state_print(who, n, arg); 306 return 0; 307 case XFRM_MSG_NEWPOLICY: 308 case XFRM_MSG_DELPOLICY: 309 case XFRM_MSG_UPDPOLICY: 310 case XFRM_MSG_POLEXPIRE: 311 xfrm_policy_print(who, n, arg); 312 return 0; 313 case XFRM_MSG_ACQUIRE: 314 xfrm_acquire_print(who, n, arg); 315 return 0; 316 case XFRM_MSG_FLUSHSA: 317 xfrm_state_flush_print(who, n, arg); 318 return 0; 319 case XFRM_MSG_FLUSHPOLICY: 320 xfrm_policy_flush_print(who, n, arg); 321 return 0; 322 case XFRM_MSG_REPORT: 323 xfrm_report_print(who, n, arg); 324 return 0; 325 case XFRM_MSG_NEWAE: 326 xfrm_ae_print(who, n, arg); 327 return 0; 328 case XFRM_MSG_MAPPING: 329 xfrm_mapping_print(who, n, arg); 330 return 0; 331 default: 332 break; 333 } 334 335 if (n->nlmsg_type != NLMSG_ERROR && n->nlmsg_type != NLMSG_NOOP && 336 n->nlmsg_type != NLMSG_DONE) { 337 fprintf(fp, "Unknown message: %08d 0x%08x 0x%08x\n", 338 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); 339 } 340 return 0; 341 } 342 343 extern struct rtnl_handle rth; 344 345 int do_xfrm_monitor(int argc, char **argv) 346 { 347 char *file = NULL; 348 unsigned groups = ~((unsigned)0); /* XXX */ 349 int lacquire=0; 350 int lexpire=0; 351 int laevent=0; 352 int lpolicy=0; 353 int lsa=0; 354 int lreport=0; 355 356 rtnl_close(&rth); 357 358 while (argc > 0) { 359 if (matches(*argv, "file") == 0) { 360 NEXT_ARG(); 361 file = *argv; 362 } else if (matches(*argv, "acquire") == 0) { 363 lacquire=1; 364 groups = 0; 365 } else if (matches(*argv, "expire") == 0) { 366 lexpire=1; 367 groups = 0; 368 } else if (matches(*argv, "SA") == 0) { 369 lsa=1; 370 groups = 0; 371 } else if (matches(*argv, "aevent") == 0) { 372 laevent=1; 373 groups = 0; 374 } else if (matches(*argv, "policy") == 0) { 375 lpolicy=1; 376 groups = 0; 377 } else if (matches(*argv, "report") == 0) { 378 lreport=1; 379 groups = 0; 380 } else if (matches(*argv, "help") == 0) { 381 usage(); 382 } else { 383 fprintf(stderr, "Argument \"%s\" is unknown, try \"ip xfrm monitor help\".\n", *argv); 384 exit(-1); 385 } 386 argc--; argv++; 387 } 388 389 if (lacquire) 390 groups |= nl_mgrp(XFRMNLGRP_ACQUIRE); 391 if (lexpire) 392 groups |= nl_mgrp(XFRMNLGRP_EXPIRE); 393 if (lsa) 394 groups |= nl_mgrp(XFRMNLGRP_SA); 395 if (lpolicy) 396 groups |= nl_mgrp(XFRMNLGRP_POLICY); 397 if (laevent) 398 groups |= nl_mgrp(XFRMNLGRP_AEVENTS); 399 if (lreport) 400 groups |= nl_mgrp(XFRMNLGRP_REPORT); 401 402 if (file) { 403 FILE *fp; 404 fp = fopen(file, "r"); 405 if (fp == NULL) { 406 perror("Cannot fopen"); 407 exit(-1); 408 } 409 return rtnl_from_file(fp, xfrm_accept_msg, (void*)stdout); 410 } 411 412 //ll_init_map(&rth); 413 414 if (rtnl_open_byproto(&rth, groups, NETLINK_XFRM) < 0) 415 exit(1); 416 417 if (rtnl_listen(&rth, xfrm_accept_msg, (void*)stdout) < 0) 418 exit(2); 419 420 return 0; 421 } 422