1 /* 2 * rtmon.c RTnetlink listener. 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 <sys/time.h> 20 #include <netinet/in.h> 21 #include <string.h> 22 23 #include "SNAPSHOT.h" 24 25 #include "utils.h" 26 #include "libnetlink.h" 27 28 int resolve_hosts = 0; 29 static int init_phase = 1; 30 31 static void write_stamp(FILE *fp) 32 { 33 char buf[128]; 34 struct nlmsghdr *n1 = (void*)buf; 35 struct timeval tv; 36 37 n1->nlmsg_type = 15; 38 n1->nlmsg_flags = 0; 39 n1->nlmsg_seq = 0; 40 n1->nlmsg_pid = 0; 41 n1->nlmsg_len = NLMSG_LENGTH(4*2); 42 gettimeofday(&tv, NULL); 43 ((__u32*)NLMSG_DATA(n1))[0] = tv.tv_sec; 44 ((__u32*)NLMSG_DATA(n1))[1] = tv.tv_usec; 45 fwrite((void*)n1, 1, NLMSG_ALIGN(n1->nlmsg_len), fp); 46 } 47 48 static int dump_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, 49 void *arg) 50 { 51 FILE *fp = (FILE*)arg; 52 if (!init_phase) 53 write_stamp(fp); 54 fwrite((void*)n, 1, NLMSG_ALIGN(n->nlmsg_len), fp); 55 fflush(fp); 56 return 0; 57 } 58 59 void usage(void) 60 { 61 fprintf(stderr, "Usage: rtmon file FILE [ all | LISTofOBJECTS]\n"); 62 fprintf(stderr, "LISTofOBJECTS := [ link ] [ address ] [ route ]\n"); 63 exit(-1); 64 } 65 66 int 67 main(int argc, char **argv) 68 { 69 FILE *fp; 70 struct rtnl_handle rth; 71 int family = AF_UNSPEC; 72 unsigned groups = ~0U; 73 int llink = 0; 74 int laddr = 0; 75 int lroute = 0; 76 char *file = NULL; 77 78 while (argc > 1) { 79 if (matches(argv[1], "-family") == 0) { 80 argc--; 81 argv++; 82 if (argc <= 1) 83 usage(); 84 if (strcmp(argv[1], "inet") == 0) 85 family = AF_INET; 86 else if (strcmp(argv[1], "inet6") == 0) 87 family = AF_INET6; 88 else if (strcmp(argv[1], "link") == 0) 89 family = AF_INET6; 90 else if (strcmp(argv[1], "help") == 0) 91 usage(); 92 else { 93 fprintf(stderr, "Protocol ID \"%s\" is unknown, try \"rtmon help\".\n", argv[1]); 94 exit(-1); 95 } 96 } else if (strcmp(argv[1], "-4") == 0) { 97 family = AF_INET; 98 } else if (strcmp(argv[1], "-6") == 0) { 99 family = AF_INET6; 100 } else if (strcmp(argv[1], "-0") == 0) { 101 family = AF_PACKET; 102 } else if (matches(argv[1], "-Version") == 0) { 103 printf("rtmon utility, iproute2-ss%s\n", SNAPSHOT); 104 exit(0); 105 } else if (matches(argv[1], "file") == 0) { 106 argc--; 107 argv++; 108 if (argc <= 1) 109 usage(); 110 file = argv[1]; 111 } else if (matches(argv[1], "link") == 0) { 112 llink=1; 113 groups = 0; 114 } else if (matches(argv[1], "address") == 0) { 115 laddr=1; 116 groups = 0; 117 } else if (matches(argv[1], "route") == 0) { 118 lroute=1; 119 groups = 0; 120 } else if (strcmp(argv[1], "all") == 0) { 121 groups = ~0U; 122 } else if (matches(argv[1], "help") == 0) { 123 usage(); 124 } else { 125 fprintf(stderr, "Argument \"%s\" is unknown, try \"rtmon help\".\n", argv[1]); 126 exit(-1); 127 } 128 argc--; argv++; 129 } 130 131 if (file == NULL) { 132 fprintf(stderr, "Not enough information: argument \"file\" is required\n"); 133 exit(-1); 134 } 135 if (llink) 136 groups |= nl_mgrp(RTNLGRP_LINK); 137 if (laddr) { 138 if (!family || family == AF_INET) 139 groups |= nl_mgrp(RTNLGRP_IPV4_IFADDR); 140 if (!family || family == AF_INET6) 141 groups |= nl_mgrp(RTNLGRP_IPV6_IFADDR); 142 } 143 if (lroute) { 144 if (!family || family == AF_INET) 145 groups |= nl_mgrp(RTNLGRP_IPV4_ROUTE); 146 if (!family || family == AF_INET6) 147 groups |= nl_mgrp(RTNLGRP_IPV6_ROUTE); 148 } 149 150 fp = fopen(file, "w"); 151 if (fp == NULL) { 152 perror("Cannot fopen"); 153 exit(-1); 154 } 155 156 if (rtnl_open(&rth, groups) < 0) 157 exit(1); 158 159 if (rtnl_wilddump_request(&rth, AF_UNSPEC, RTM_GETLINK) < 0) { 160 perror("Cannot send dump request"); 161 exit(1); 162 } 163 164 write_stamp(fp); 165 166 if (rtnl_dump_filter(&rth, dump_msg, fp) < 0) { 167 fprintf(stderr, "Dump terminated\n"); 168 return 1; 169 } 170 171 init_phase = 0; 172 173 if (rtnl_listen(&rth, dump_msg, (void*)fp) < 0) 174 exit(2); 175 176 exit(0); 177 } 178