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