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