Home | History | Annotate | Download | only in ip
      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 = NLMSG_TSTAMP;
     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 rtnl_ctrl_data *ctrl,
     49 		    struct nlmsghdr *n, 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 static int dump_msg2(const struct sockaddr_nl *who,
     60 		     struct nlmsghdr *n, void *arg)
     61 {
     62 	return dump_msg(who, NULL, n, arg);
     63 }
     64 
     65 static void usage(void)
     66 {
     67 	fprintf(stderr, "Usage: rtmon file FILE [ all | LISTofOBJECTS]\n");
     68 	fprintf(stderr, "LISTofOBJECTS := [ link ] [ address ] [ route ]\n");
     69 	exit(-1);
     70 }
     71 
     72 int
     73 main(int argc, char **argv)
     74 {
     75 	FILE *fp;
     76 	struct rtnl_handle rth;
     77 	int family = AF_UNSPEC;
     78 	unsigned groups = ~0U;
     79 	int llink = 0;
     80 	int laddr = 0;
     81 	int lroute = 0;
     82 	char *file = NULL;
     83 
     84 	while (argc > 1) {
     85 		if (matches(argv[1], "-family") == 0) {
     86 			argc--;
     87 			argv++;
     88 			if (argc <= 1)
     89 				usage();
     90 			if (strcmp(argv[1], "inet") == 0)
     91 				family = AF_INET;
     92 			else if (strcmp(argv[1], "inet6") == 0)
     93 				family = AF_INET6;
     94 			else if (strcmp(argv[1], "link") == 0)
     95 				family = AF_INET6;
     96 			else if (strcmp(argv[1], "help") == 0)
     97 				usage();
     98 			else {
     99 				fprintf(stderr, "Protocol ID \"%s\" is unknown, try \"rtmon help\".\n", argv[1]);
    100 				exit(-1);
    101 			}
    102 		} else if (strcmp(argv[1], "-4") == 0) {
    103 			family = AF_INET;
    104 		} else if (strcmp(argv[1], "-6") == 0) {
    105 			family = AF_INET6;
    106 		} else if (strcmp(argv[1], "-0") == 0) {
    107 			family = AF_PACKET;
    108 		} else if (matches(argv[1], "-Version") == 0) {
    109 			printf("rtmon utility, iproute2-ss%s\n", SNAPSHOT);
    110 			exit(0);
    111 		} else if (matches(argv[1], "file") == 0) {
    112 			argc--;
    113 			argv++;
    114 			if (argc <= 1)
    115 				usage();
    116 			file = argv[1];
    117 		} else if (matches(argv[1], "link") == 0) {
    118 			llink=1;
    119 			groups = 0;
    120 		} else if (matches(argv[1], "address") == 0) {
    121 			laddr=1;
    122 			groups = 0;
    123 		} else if (matches(argv[1], "route") == 0) {
    124 			lroute=1;
    125 			groups = 0;
    126 		} else if (strcmp(argv[1], "all") == 0) {
    127 			groups = ~0U;
    128 		} else if (matches(argv[1], "help") == 0) {
    129 			usage();
    130 		} else {
    131 			fprintf(stderr, "Argument \"%s\" is unknown, try \"rtmon help\".\n", argv[1]);
    132 			exit(-1);
    133 		}
    134 		argc--;	argv++;
    135 	}
    136 
    137 	if (file == NULL) {
    138 		fprintf(stderr, "Not enough information: argument \"file\" is required\n");
    139 		exit(-1);
    140 	}
    141 	if (llink)
    142 		groups |= nl_mgrp(RTNLGRP_LINK);
    143 	if (laddr) {
    144 		if (!family || family == AF_INET)
    145 			groups |= nl_mgrp(RTNLGRP_IPV4_IFADDR);
    146 		if (!family || family == AF_INET6)
    147 			groups |= nl_mgrp(RTNLGRP_IPV6_IFADDR);
    148 	}
    149 	if (lroute) {
    150 		if (!family || family == AF_INET)
    151 			groups |= nl_mgrp(RTNLGRP_IPV4_ROUTE);
    152 		if (!family || family == AF_INET6)
    153 			groups |= nl_mgrp(RTNLGRP_IPV6_ROUTE);
    154 	}
    155 
    156 	fp = fopen(file, "w");
    157 	if (fp == NULL) {
    158 		perror("Cannot fopen");
    159 		exit(-1);
    160 	}
    161 
    162 	if (rtnl_open(&rth, groups) < 0)
    163 		exit(1);
    164 
    165 	if (rtnl_wilddump_request(&rth, AF_UNSPEC, RTM_GETLINK) < 0) {
    166 		perror("Cannot send dump request");
    167 		exit(1);
    168 	}
    169 
    170 	write_stamp(fp);
    171 
    172 	if (rtnl_dump_filter(&rth, dump_msg2, fp) < 0) {
    173 		fprintf(stderr, "Dump terminated\n");
    174 		return 1;
    175 	}
    176 
    177 	init_phase = 0;
    178 
    179 	if (rtnl_listen(&rth, dump_msg, (void*)fp) < 0)
    180 		exit(2);
    181 
    182 	exit(0);
    183 }
    184