Home | History | Annotate | Download | only in ip
      1 /*
      2  * ipmonitor.c		"ip monitor".
      3  *
      4  *		This program is free software; you can redistribute it and/or
      5  *		modify it under the terms of the GNU General Public License
      6  *		as published by the Free Software Foundation; either version
      7  *		2 of the License, or (at your option) any later version.
      8  *
      9  * Authors:	Alexey Kuznetsov, <kuznet (at) ms2.inr.ac.ru>
     10  *
     11  */
     12 
     13 #include <stdio.h>
     14 #include <stdlib.h>
     15 #include <unistd.h>
     16 #include <syslog.h>
     17 #include <fcntl.h>
     18 #include <sys/socket.h>
     19 #include <netinet/in.h>
     20 #include <arpa/inet.h>
     21 #include <string.h>
     22 #include <time.h>
     23 
     24 #include "utils.h"
     25 #include "ip_common.h"
     26 
     27 static void usage(void) __attribute__((noreturn));
     28 int prefix_banner;
     29 int listen_all_nsid;
     30 
     31 static void usage(void)
     32 {
     33 	fprintf(stderr, "Usage: ip monitor [ all | LISTofOBJECTS ] [ FILE ] "
     34 			"[ label ] [all-nsid] [dev DEVICE]\n");
     35 	fprintf(stderr, "LISTofOBJECTS := link | address | route | mroute | prefix |\n");
     36 	fprintf(stderr, "                 neigh | netconf | rule | nsid\n");
     37 	fprintf(stderr, "FILE := file FILENAME\n");
     38 	exit(-1);
     39 }
     40 
     41 static void print_headers(FILE *fp, char *label, struct rtnl_ctrl_data *ctrl)
     42 {
     43 	if (timestamp)
     44 		print_timestamp(fp);
     45 
     46 	if (listen_all_nsid) {
     47 		if (ctrl == NULL || ctrl->nsid < 0)
     48 			fprintf(fp, "[nsid current]");
     49 		else
     50 			fprintf(fp, "[nsid %d]", ctrl->nsid);
     51 	}
     52 
     53 	if (prefix_banner)
     54 		fprintf(fp, "%s", label);
     55 }
     56 
     57 static int accept_msg(const struct sockaddr_nl *who,
     58 		      struct rtnl_ctrl_data *ctrl,
     59 		      struct nlmsghdr *n, void *arg)
     60 {
     61 	FILE *fp = (FILE*)arg;
     62 
     63 	if (n->nlmsg_type == RTM_NEWROUTE || n->nlmsg_type == RTM_DELROUTE) {
     64 		struct rtmsg *r = NLMSG_DATA(n);
     65 		int len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*r));
     66 
     67 		if (len < 0) {
     68 			fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
     69 			return -1;
     70 		}
     71 
     72 		if (r->rtm_flags & RTM_F_CLONED)
     73 			return 0;
     74 
     75 		if (r->rtm_family == RTNL_FAMILY_IPMR ||
     76 		    r->rtm_family == RTNL_FAMILY_IP6MR) {
     77 			print_headers(fp, "[MROUTE]", ctrl);
     78 			print_mroute(who, n, arg);
     79 			return 0;
     80 		} else {
     81 			print_headers(fp, "[ROUTE]", ctrl);
     82 			print_route(who, n, arg);
     83 			return 0;
     84 		}
     85 	}
     86 
     87 	if (n->nlmsg_type == RTM_NEWLINK || n->nlmsg_type == RTM_DELLINK) {
     88 		ll_remember_index(who, n, NULL);
     89 		print_headers(fp, "[LINK]", ctrl);
     90 		print_linkinfo(who, n, arg);
     91 		return 0;
     92 	}
     93 	if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) {
     94 		print_headers(fp, "[ADDR]", ctrl);
     95 		print_addrinfo(who, n, arg);
     96 		return 0;
     97 	}
     98 	if (n->nlmsg_type == RTM_NEWADDRLABEL || n->nlmsg_type == RTM_DELADDRLABEL) {
     99 		print_headers(fp, "[ADDRLABEL]", ctrl);
    100 		print_addrlabel(who, n, arg);
    101 		return 0;
    102 	}
    103 	if (n->nlmsg_type == RTM_NEWNEIGH || n->nlmsg_type == RTM_DELNEIGH ||
    104 	    n->nlmsg_type == RTM_GETNEIGH) {
    105 		if (preferred_family) {
    106 			struct ndmsg *r = NLMSG_DATA(n);
    107 
    108 			if (r->ndm_family != preferred_family)
    109 				return 0;
    110 		}
    111 
    112 		print_headers(fp, "[NEIGH]", ctrl);
    113 		print_neigh(who, n, arg);
    114 		return 0;
    115 	}
    116 	if (n->nlmsg_type == RTM_NEWPREFIX) {
    117 		print_headers(fp, "[PREFIX]", ctrl);
    118 		print_prefix(who, n, arg);
    119 		return 0;
    120 	}
    121 	if (n->nlmsg_type == RTM_NEWRULE || n->nlmsg_type == RTM_DELRULE) {
    122 		print_headers(fp, "[RULE]", ctrl);
    123 		print_rule(who, n, arg);
    124 		return 0;
    125 	}
    126 	if (n->nlmsg_type == RTM_NEWNETCONF) {
    127 		print_headers(fp, "[NETCONF]", ctrl);
    128 		print_netconf(who, ctrl, n, arg);
    129 		return 0;
    130 	}
    131 	if (n->nlmsg_type == NLMSG_TSTAMP) {
    132 		print_nlmsg_timestamp(fp, n);
    133 		return 0;
    134 	}
    135 	if (n->nlmsg_type == RTM_NEWNSID || n->nlmsg_type == RTM_DELNSID) {
    136 		print_headers(fp, "[NSID]", ctrl);
    137 		print_nsid(who, n, arg);
    138 		return 0;
    139 	}
    140 	if (n->nlmsg_type != NLMSG_ERROR && n->nlmsg_type != NLMSG_NOOP &&
    141 	    n->nlmsg_type != NLMSG_DONE) {
    142 		fprintf(fp, "Unknown message: type=0x%08x(%d) flags=0x%08x(%d)"
    143 			"len=0x%08x(%d)\n", n->nlmsg_type, n->nlmsg_type,
    144 			n->nlmsg_flags, n->nlmsg_flags, n->nlmsg_len,
    145 			n->nlmsg_len);
    146 	}
    147 	return 0;
    148 }
    149 
    150 int do_ipmonitor(int argc, char **argv)
    151 {
    152 	char *file = NULL;
    153 	unsigned groups = 0;
    154 	int llink=0;
    155 	int laddr=0;
    156 	int lroute=0;
    157 	int lmroute=0;
    158 	int lprefix=0;
    159 	int lneigh=0;
    160 	int lnetconf=0;
    161 	int lrule=0;
    162 	int lnsid=0;
    163 	int ifindex=0;
    164 
    165 	groups |= nl_mgrp(RTNLGRP_LINK);
    166 	groups |= nl_mgrp(RTNLGRP_IPV4_IFADDR);
    167 	groups |= nl_mgrp(RTNLGRP_IPV6_IFADDR);
    168 	groups |= nl_mgrp(RTNLGRP_IPV4_ROUTE);
    169 	groups |= nl_mgrp(RTNLGRP_IPV6_ROUTE);
    170 	groups |= nl_mgrp(RTNLGRP_MPLS_ROUTE);
    171 	groups |= nl_mgrp(RTNLGRP_IPV4_MROUTE);
    172 	groups |= nl_mgrp(RTNLGRP_IPV6_MROUTE);
    173 	groups |= nl_mgrp(RTNLGRP_IPV6_PREFIX);
    174 	groups |= nl_mgrp(RTNLGRP_NEIGH);
    175 	groups |= nl_mgrp(RTNLGRP_IPV4_NETCONF);
    176 	groups |= nl_mgrp(RTNLGRP_IPV6_NETCONF);
    177 	groups |= nl_mgrp(RTNLGRP_IPV4_RULE);
    178 	groups |= nl_mgrp(RTNLGRP_IPV6_RULE);
    179 	groups |= nl_mgrp(RTNLGRP_NSID);
    180 
    181 	rtnl_close(&rth);
    182 
    183 	while (argc > 0) {
    184 		if (matches(*argv, "file") == 0) {
    185 			NEXT_ARG();
    186 			file = *argv;
    187 		} else if (matches(*argv, "label") == 0) {
    188 			prefix_banner = 1;
    189 		} else if (matches(*argv, "all-nsid") == 0) {
    190 			listen_all_nsid = 1;
    191 		} else if (matches(*argv, "link") == 0) {
    192 			llink=1;
    193 			groups = 0;
    194 		} else if (matches(*argv, "address") == 0) {
    195 			laddr=1;
    196 			groups = 0;
    197 		} else if (matches(*argv, "route") == 0) {
    198 			lroute=1;
    199 			groups = 0;
    200 		} else if (matches(*argv, "mroute") == 0) {
    201 			lmroute=1;
    202 			groups = 0;
    203 		} else if (matches(*argv, "prefix") == 0) {
    204 			lprefix=1;
    205 			groups = 0;
    206 		} else if (matches(*argv, "neigh") == 0) {
    207 			lneigh = 1;
    208 			groups = 0;
    209 		} else if (matches(*argv, "netconf") == 0) {
    210 			lnetconf = 1;
    211 			groups = 0;
    212 		} else if (matches(*argv, "rule") == 0) {
    213 			lrule = 1;
    214 			groups = 0;
    215 		} else if (matches(*argv, "nsid") == 0) {
    216 			lnsid = 1;
    217 			groups = 0;
    218 		} else if (strcmp(*argv, "all") == 0) {
    219 			prefix_banner=1;
    220 		} else if (matches(*argv, "help") == 0) {
    221 			usage();
    222 		} else if (strcmp(*argv, "dev") == 0) {
    223 			NEXT_ARG();
    224 
    225 			ifindex = ll_name_to_index(*argv);
    226 			if (!ifindex)
    227 				invarg("Device does not exist\n", *argv);
    228 		} else {
    229 			fprintf(stderr, "Argument \"%s\" is unknown, try \"ip monitor help\".\n", *argv);
    230 			exit(-1);
    231 		}
    232 		argc--;	argv++;
    233 	}
    234 
    235 	ipaddr_reset_filter(1, ifindex);
    236 	iproute_reset_filter(ifindex);
    237 	ipmroute_reset_filter(ifindex);
    238 	ipneigh_reset_filter(ifindex);
    239 	ipnetconf_reset_filter(ifindex);
    240 
    241 	if (llink)
    242 		groups |= nl_mgrp(RTNLGRP_LINK);
    243 	if (laddr) {
    244 		if (!preferred_family || preferred_family == AF_INET)
    245 			groups |= nl_mgrp(RTNLGRP_IPV4_IFADDR);
    246 		if (!preferred_family || preferred_family == AF_INET6)
    247 			groups |= nl_mgrp(RTNLGRP_IPV6_IFADDR);
    248 	}
    249 	if (lroute) {
    250 		if (!preferred_family || preferred_family == AF_INET)
    251 			groups |= nl_mgrp(RTNLGRP_IPV4_ROUTE);
    252 		if (!preferred_family || preferred_family == AF_INET6)
    253 			groups |= nl_mgrp(RTNLGRP_IPV6_ROUTE);
    254 		if (!preferred_family || preferred_family == AF_MPLS)
    255 			groups |= nl_mgrp(RTNLGRP_MPLS_ROUTE);
    256 	}
    257 	if (lmroute) {
    258 		if (!preferred_family || preferred_family == AF_INET)
    259 			groups |= nl_mgrp(RTNLGRP_IPV4_MROUTE);
    260 		if (!preferred_family || preferred_family == AF_INET6)
    261 			groups |= nl_mgrp(RTNLGRP_IPV6_MROUTE);
    262 	}
    263 	if (lprefix) {
    264 		if (!preferred_family || preferred_family == AF_INET6)
    265 			groups |= nl_mgrp(RTNLGRP_IPV6_PREFIX);
    266 	}
    267 	if (lneigh) {
    268 		groups |= nl_mgrp(RTNLGRP_NEIGH);
    269 	}
    270 	if (lnetconf) {
    271 		if (!preferred_family || preferred_family == AF_INET)
    272 			groups |= nl_mgrp(RTNLGRP_IPV4_NETCONF);
    273 		if (!preferred_family || preferred_family == AF_INET6)
    274 			groups |= nl_mgrp(RTNLGRP_IPV6_NETCONF);
    275 	}
    276 	if (lrule) {
    277 		if (!preferred_family || preferred_family == AF_INET)
    278 			groups |= nl_mgrp(RTNLGRP_IPV4_RULE);
    279 		if (!preferred_family || preferred_family == AF_INET6)
    280 			groups |= nl_mgrp(RTNLGRP_IPV6_RULE);
    281 	}
    282 	if (lnsid) {
    283 		groups |= nl_mgrp(RTNLGRP_NSID);
    284 	}
    285 	if (file) {
    286 		FILE *fp;
    287 		int err;
    288 
    289 		fp = fopen(file, "r");
    290 		if (fp == NULL) {
    291 			perror("Cannot fopen");
    292 			exit(-1);
    293 		}
    294 		err = rtnl_from_file(fp, accept_msg, stdout);
    295 		fclose(fp);
    296 		return err;
    297 	}
    298 
    299 	if (rtnl_open(&rth, groups) < 0)
    300 		exit(1);
    301 	if (listen_all_nsid && rtnl_listen_all_nsid(&rth) < 0)
    302 		exit(1);
    303 
    304 	ll_init_map(&rth);
    305 	netns_map_init();
    306 
    307 	if (rtnl_listen(&rth, accept_msg, stdout) < 0)
    308 		exit(2);
    309 
    310 	return 0;
    311 }
    312