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