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 ] [ label ] [all-nsid] [dev DEVICE]\n");
     34 	fprintf(stderr, "LISTofOBJECTS := link | address | route | mroute | prefix |\n");
     35 	fprintf(stderr, "                 neigh | netconf | rule | nsid\n");
     36 	fprintf(stderr, "FILE := file FILENAME\n");
     37 	exit(-1);
     38 }
     39 
     40 static void print_headers(FILE *fp, char *label, struct rtnl_ctrl_data *ctrl)
     41 {
     42 	if (timestamp)
     43 		print_timestamp(fp);
     44 
     45 	if (listen_all_nsid) {
     46 		if (ctrl == NULL || ctrl->nsid < 0)
     47 			fprintf(fp, "[nsid current]");
     48 		else
     49 			fprintf(fp, "[nsid %d]", ctrl->nsid);
     50 	}
     51 
     52 	if (prefix_banner)
     53 		fprintf(fp, "%s", label);
     54 }
     55 
     56 static int accept_msg(const struct sockaddr_nl *who,
     57 		      struct rtnl_ctrl_data *ctrl,
     58 		      struct nlmsghdr *n, void *arg)
     59 {
     60 	FILE *fp = (FILE *)arg;
     61 
     62 	if (n->nlmsg_type == RTM_NEWROUTE || n->nlmsg_type == RTM_DELROUTE) {
     63 		struct rtmsg *r = NLMSG_DATA(n);
     64 		int len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*r));
     65 
     66 		if (len < 0) {
     67 			fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
     68 			return -1;
     69 		}
     70 
     71 		if (r->rtm_flags & RTM_F_CLONED)
     72 			return 0;
     73 
     74 		if (r->rtm_family == RTNL_FAMILY_IPMR ||
     75 		    r->rtm_family == RTNL_FAMILY_IP6MR) {
     76 			print_headers(fp, "[MROUTE]", ctrl);
     77 			print_mroute(who, n, arg);
     78 			return 0;
     79 		} else {
     80 			print_headers(fp, "[ROUTE]", ctrl);
     81 			print_route(who, n, arg);
     82 			return 0;
     83 		}
     84 	}
     85 
     86 	if (n->nlmsg_type == RTM_NEWLINK || n->nlmsg_type == RTM_DELLINK) {
     87 		ll_remember_index(who, n, NULL);
     88 		print_headers(fp, "[LINK]", ctrl);
     89 		print_linkinfo(who, n, arg);
     90 		return 0;
     91 	}
     92 	if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) {
     93 		print_headers(fp, "[ADDR]", ctrl);
     94 		print_addrinfo(who, n, arg);
     95 		return 0;
     96 	}
     97 	if (n->nlmsg_type == RTM_NEWADDRLABEL || n->nlmsg_type == RTM_DELADDRLABEL) {
     98 		print_headers(fp, "[ADDRLABEL]", ctrl);
     99 		print_addrlabel(who, n, arg);
    100 		return 0;
    101 	}
    102 	if (n->nlmsg_type == RTM_NEWNEIGH || n->nlmsg_type == RTM_DELNEIGH ||
    103 	    n->nlmsg_type == RTM_GETNEIGH) {
    104 		if (preferred_family) {
    105 			struct ndmsg *r = NLMSG_DATA(n);
    106 
    107 			if (r->ndm_family != preferred_family)
    108 				return 0;
    109 		}
    110 
    111 		print_headers(fp, "[NEIGH]", ctrl);
    112 		print_neigh(who, n, arg);
    113 		return 0;
    114 	}
    115 	if (n->nlmsg_type == RTM_NEWPREFIX) {
    116 		print_headers(fp, "[PREFIX]", ctrl);
    117 		print_prefix(who, n, arg);
    118 		return 0;
    119 	}
    120 	if (n->nlmsg_type == RTM_NEWRULE || n->nlmsg_type == RTM_DELRULE) {
    121 		print_headers(fp, "[RULE]", ctrl);
    122 		print_rule(who, n, arg);
    123 		return 0;
    124 	}
    125 	if (n->nlmsg_type == RTM_NEWNETCONF) {
    126 		print_headers(fp, "[NETCONF]", ctrl);
    127 		print_netconf(who, ctrl, n, arg);
    128 		return 0;
    129 	}
    130 	if (n->nlmsg_type == NLMSG_TSTAMP) {
    131 		print_nlmsg_timestamp(fp, n);
    132 		return 0;
    133 	}
    134 	if (n->nlmsg_type == RTM_NEWNSID || n->nlmsg_type == RTM_DELNSID) {
    135 		print_headers(fp, "[NSID]", ctrl);
    136 		print_nsid(who, n, arg);
    137 		return 0;
    138 	}
    139 	if (n->nlmsg_type != NLMSG_ERROR && n->nlmsg_type != NLMSG_NOOP &&
    140 	    n->nlmsg_type != NLMSG_DONE) {
    141 		fprintf(fp, "Unknown message: type=0x%08x(%d) flags=0x%08x(%d)len=0x%08x(%d)\n",
    142 			n->nlmsg_type, n->nlmsg_type,
    143 			n->nlmsg_flags, n->nlmsg_flags, n->nlmsg_len,
    144 			n->nlmsg_len);
    145 	}
    146 	return 0;
    147 }
    148 
    149 int do_ipmonitor(int argc, char **argv)
    150 {
    151 	char *file = NULL;
    152 	unsigned int groups = 0;
    153 	int llink = 0;
    154 	int laddr = 0;
    155 	int lroute = 0;
    156 	int lmroute = 0;
    157 	int lprefix = 0;
    158 	int lneigh = 0;
    159 	int lnetconf = 0;
    160 	int lrule = 0;
    161 	int lnsid = 0;
    162 	int ifindex = 0;
    163 
    164 	groups |= nl_mgrp(RTNLGRP_LINK);
    165 	groups |= nl_mgrp(RTNLGRP_IPV4_IFADDR);
    166 	groups |= nl_mgrp(RTNLGRP_IPV6_IFADDR);
    167 	groups |= nl_mgrp(RTNLGRP_IPV4_ROUTE);
    168 	groups |= nl_mgrp(RTNLGRP_IPV6_ROUTE);
    169 	groups |= nl_mgrp(RTNLGRP_MPLS_ROUTE);
    170 	groups |= nl_mgrp(RTNLGRP_IPV4_MROUTE);
    171 	groups |= nl_mgrp(RTNLGRP_IPV6_MROUTE);
    172 	groups |= nl_mgrp(RTNLGRP_IPV6_PREFIX);
    173 	groups |= nl_mgrp(RTNLGRP_NEIGH);
    174 	groups |= nl_mgrp(RTNLGRP_IPV4_NETCONF);
    175 	groups |= nl_mgrp(RTNLGRP_IPV6_NETCONF);
    176 	groups |= nl_mgrp(RTNLGRP_IPV4_RULE);
    177 	groups |= nl_mgrp(RTNLGRP_IPV6_RULE);
    178 	groups |= nl_mgrp(RTNLGRP_NSID);
    179 	groups |= nl_mgrp(RTNLGRP_MPLS_NETCONF);
    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, "link") == 0) {
    190 			llink = 1;
    191 			groups = 0;
    192 		} else if (matches(*argv, "address") == 0) {
    193 			laddr = 1;
    194 			groups = 0;
    195 		} else if (matches(*argv, "route") == 0) {
    196 			lroute = 1;
    197 			groups = 0;
    198 		} else if (matches(*argv, "mroute") == 0) {
    199 			lmroute = 1;
    200 			groups = 0;
    201 		} else if (matches(*argv, "prefix") == 0) {
    202 			lprefix = 1;
    203 			groups = 0;
    204 		} else if (matches(*argv, "neigh") == 0) {
    205 			lneigh = 1;
    206 			groups = 0;
    207 		} else if (matches(*argv, "netconf") == 0) {
    208 			lnetconf = 1;
    209 			groups = 0;
    210 		} else if (matches(*argv, "rule") == 0) {
    211 			lrule = 1;
    212 			groups = 0;
    213 		} else if (matches(*argv, "nsid") == 0) {
    214 			lnsid = 1;
    215 			groups = 0;
    216 		} else if (strcmp(*argv, "all") == 0) {
    217 			prefix_banner = 1;
    218 		} else if (matches(*argv, "all-nsid") == 0) {
    219 			listen_all_nsid = 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 		if (!preferred_family || preferred_family == AF_MPLS)
    276 			groups |= nl_mgrp(RTNLGRP_MPLS_NETCONF);
    277 	}
    278 	if (lrule) {
    279 		if (!preferred_family || preferred_family == AF_INET)
    280 			groups |= nl_mgrp(RTNLGRP_IPV4_RULE);
    281 		if (!preferred_family || preferred_family == AF_INET6)
    282 			groups |= nl_mgrp(RTNLGRP_IPV6_RULE);
    283 	}
    284 	if (lnsid) {
    285 		groups |= nl_mgrp(RTNLGRP_NSID);
    286 	}
    287 	if (file) {
    288 		FILE *fp;
    289 		int err;
    290 
    291 		fp = fopen(file, "r");
    292 		if (fp == NULL) {
    293 			perror("Cannot fopen");
    294 			exit(-1);
    295 		}
    296 		err = rtnl_from_file(fp, accept_msg, stdout);
    297 		fclose(fp);
    298 		return err;
    299 	}
    300 
    301 	if (rtnl_open(&rth, groups) < 0)
    302 		exit(1);
    303 	if (listen_all_nsid && rtnl_listen_all_nsid(&rth) < 0)
    304 		exit(1);
    305 
    306 	ll_init_map(&rth);
    307 	netns_nsid_socket_init();
    308 	netns_map_init();
    309 
    310 	if (rtnl_listen(&rth, accept_msg, stdout) < 0)
    311 		exit(2);
    312 
    313 	return 0;
    314 }
    315