/* * rtmon.c RTnetlink listener. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <syslog.h> #include <fcntl.h> #include <sys/socket.h> #include <sys/time.h> #include <netinet/in.h> #include <string.h> #include "SNAPSHOT.h" #include "utils.h" #include "libnetlink.h" static int init_phase = 1; static void write_stamp(FILE *fp) { char buf[128]; struct nlmsghdr *n1 = (void *)buf; struct timeval tv; n1->nlmsg_type = NLMSG_TSTAMP; n1->nlmsg_flags = 0; n1->nlmsg_seq = 0; n1->nlmsg_pid = 0; n1->nlmsg_len = NLMSG_LENGTH(4*2); gettimeofday(&tv, NULL); ((__u32 *)NLMSG_DATA(n1))[0] = tv.tv_sec; ((__u32 *)NLMSG_DATA(n1))[1] = tv.tv_usec; fwrite((void *)n1, 1, NLMSG_ALIGN(n1->nlmsg_len), fp); } static int dump_msg(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE *)arg; if (!init_phase) write_stamp(fp); fwrite((void *)n, 1, NLMSG_ALIGN(n->nlmsg_len), fp); fflush(fp); return 0; } static int dump_msg2(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { return dump_msg(who, NULL, n, arg); } static void usage(void) { fprintf(stderr, "Usage: rtmon file FILE [ all | LISTofOBJECTS]\n"); fprintf(stderr, "LISTofOBJECTS := [ link ] [ address ] [ route ]\n"); exit(-1); } int main(int argc, char **argv) { FILE *fp; struct rtnl_handle rth; int family = AF_UNSPEC; unsigned int groups = ~0U; int llink = 0; int laddr = 0; int lroute = 0; char *file = NULL; while (argc > 1) { if (matches(argv[1], "-family") == 0) { argc--; argv++; if (argc <= 1) usage(); if (strcmp(argv[1], "inet") == 0) family = AF_INET; else if (strcmp(argv[1], "inet6") == 0) family = AF_INET6; else if (strcmp(argv[1], "link") == 0) family = AF_INET6; else if (strcmp(argv[1], "help") == 0) usage(); else { fprintf(stderr, "Protocol ID \"%s\" is unknown, try \"rtmon help\".\n", argv[1]); exit(-1); } } else if (strcmp(argv[1], "-4") == 0) { family = AF_INET; } else if (strcmp(argv[1], "-6") == 0) { family = AF_INET6; } else if (strcmp(argv[1], "-0") == 0) { family = AF_PACKET; } else if (matches(argv[1], "-Version") == 0) { printf("rtmon utility, iproute2-ss%s\n", SNAPSHOT); exit(0); } else if (matches(argv[1], "file") == 0) { argc--; argv++; if (argc <= 1) usage(); file = argv[1]; } else if (matches(argv[1], "link") == 0) { llink = 1; groups = 0; } else if (matches(argv[1], "address") == 0) { laddr = 1; groups = 0; } else if (matches(argv[1], "route") == 0) { lroute = 1; groups = 0; } else if (strcmp(argv[1], "all") == 0) { groups = ~0U; } else if (matches(argv[1], "help") == 0) { usage(); } else { fprintf(stderr, "Argument \"%s\" is unknown, try \"rtmon help\".\n", argv[1]); exit(-1); } argc--; argv++; } if (file == NULL) { fprintf(stderr, "Not enough information: argument \"file\" is required\n"); exit(-1); } if (llink) groups |= nl_mgrp(RTNLGRP_LINK); if (laddr) { if (!family || family == AF_INET) groups |= nl_mgrp(RTNLGRP_IPV4_IFADDR); if (!family || family == AF_INET6) groups |= nl_mgrp(RTNLGRP_IPV6_IFADDR); } if (lroute) { if (!family || family == AF_INET) groups |= nl_mgrp(RTNLGRP_IPV4_ROUTE); if (!family || family == AF_INET6) groups |= nl_mgrp(RTNLGRP_IPV6_ROUTE); } fp = fopen(file, "w"); if (fp == NULL) { perror("Cannot fopen"); exit(-1); } if (rtnl_open(&rth, groups) < 0) exit(1); if (rtnl_wilddump_request(&rth, AF_UNSPEC, RTM_GETLINK) < 0) { perror("Cannot send dump request"); exit(1); } write_stamp(fp); if (rtnl_dump_filter(&rth, dump_msg2, fp) < 0) { fprintf(stderr, "Dump terminated\n"); return 1; } init_phase = 0; if (rtnl_listen(&rth, dump_msg, (void *)fp) < 0) exit(2); exit(0); }