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@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
28int resolve_hosts = 0;
29static int init_phase = 1;
30
31static 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
48static 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
59static 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
65static 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
72int
73main(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