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