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 = 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, NULL, NULL) < 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