Home | History | Annotate | Download | only in ip
      1 /*
      2  * ipmroute.c		"ip mroute".
      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/ioctl.h>
     19 #include <sys/socket.h>
     20 #include <netinet/in.h>
     21 #include <arpa/inet.h>
     22 #include <string.h>
     23 
     24 #include <linux/netdevice.h>
     25 #include <linux/if.h>
     26 #include <linux/if_arp.h>
     27 #include <linux/sockios.h>
     28 
     29 #include "utils.h"
     30 
     31 char filter_dev[16];
     32 int  filter_family;
     33 
     34 static void usage(void) __attribute__((noreturn));
     35 
     36 static void usage(void)
     37 {
     38 	fprintf(stderr, "Usage: ip mroute show [ PREFIX ] [ from PREFIX ] [ iif DEVICE ]\n");
     39 #if 0
     40 	fprintf(stderr, "Usage: ip mroute [ add | del ] DESTINATION from SOURCE [ iif DEVICE ] [ oif DEVICE ]\n");
     41 #endif
     42 	exit(-1);
     43 }
     44 
     45 static char *viftable[32];
     46 
     47 struct rtfilter
     48 {
     49 	inet_prefix mdst;
     50 	inet_prefix msrc;
     51 } filter;
     52 
     53 static void read_viftable(void)
     54 {
     55 	char buf[256];
     56 	FILE *fp = fopen("/proc/net/ip_mr_vif", "r");
     57 
     58 	if (!fp)
     59 		return;
     60 
     61 	fgets(buf, sizeof(buf), fp);
     62 
     63 	while (fgets(buf, sizeof(buf), fp)) {
     64 		int vifi;
     65 		char dev[256];
     66 
     67 		if (sscanf(buf, "%d%s", &vifi, dev) < 2)
     68 			continue;
     69 
     70 		if (vifi<0 || vifi>31)
     71 			continue;
     72 
     73 		viftable[vifi] = strdup(dev);
     74 	}
     75 	fclose(fp);
     76 }
     77 
     78 static void read_mroute_list(FILE *ofp)
     79 {
     80 	char buf[256];
     81 	FILE *fp = fopen("/proc/net/ip_mr_cache", "r");
     82 
     83 	if (!fp)
     84 		return;
     85 
     86 	fgets(buf, sizeof(buf), fp);
     87 
     88 	while (fgets(buf, sizeof(buf), fp)) {
     89 		inet_prefix maddr, msrc;
     90 		unsigned pkts, b, w;
     91 		int vifi;
     92 		char oiflist[256];
     93 		char sbuf[256];
     94 		char mbuf[256];
     95 		char obuf[256];
     96 
     97 		oiflist[0] = 0;
     98 		if (sscanf(buf, "%x%x%d%u%u%u %[^\n]",
     99 			   maddr.data, msrc.data, &vifi,
    100 			   &pkts, &b, &w, oiflist) < 6)
    101 			continue;
    102 
    103 		if (vifi!=-1 && (vifi < 0 || vifi>31))
    104 			continue;
    105 
    106 		if (filter_dev[0] && (vifi<0 || strcmp(filter_dev, viftable[vifi])))
    107 			continue;
    108 		if (filter.mdst.family && inet_addr_match(&maddr, &filter.mdst, filter.mdst.bitlen))
    109 			continue;
    110 		if (filter.msrc.family && inet_addr_match(&msrc, &filter.msrc, filter.msrc.bitlen))
    111 			continue;
    112 
    113 		snprintf(obuf, sizeof(obuf), "(%s, %s)",
    114 			 format_host(AF_INET, 4, &msrc.data[0], sbuf, sizeof(sbuf)),
    115 			 format_host(AF_INET, 4, &maddr.data[0], mbuf, sizeof(mbuf)));
    116 
    117 		fprintf(ofp, "%-32s Iif: ", obuf);
    118 
    119 		if (vifi == -1)
    120 			fprintf(ofp, "unresolved ");
    121 		else
    122 			fprintf(ofp, "%-10s ", viftable[vifi]);
    123 
    124 		if (oiflist[0]) {
    125 			char *next = NULL;
    126 			char *p = oiflist;
    127 			int ovifi, ottl;
    128 
    129 			fprintf(ofp, "Oifs: ");
    130 
    131 			while (p) {
    132 				next = strchr(p, ' ');
    133 				if (next) {
    134 					*next = 0;
    135 					next++;
    136 				}
    137 				if (sscanf(p, "%d:%d", &ovifi, &ottl)<2) {
    138 					p = next;
    139 					continue;
    140 				}
    141 				p = next;
    142 
    143 				fprintf(ofp, "%s", viftable[ovifi]);
    144 				if (ottl>1)
    145 					fprintf(ofp, "(ttl %d) ", ovifi);
    146 				else
    147 					fprintf(ofp, " ");
    148 			}
    149 		}
    150 
    151 		if (show_stats && b) {
    152 			fprintf(ofp, "%s  %u packets, %u bytes", _SL_, pkts, b);
    153 			if (w)
    154 				fprintf(ofp, ", %u arrived on wrong iif.", w);
    155 		}
    156 		fprintf(ofp, "\n");
    157 	}
    158 	fclose(fp);
    159 }
    160 
    161 
    162 static int mroute_list(int argc, char **argv)
    163 {
    164 	while (argc > 0) {
    165 		if (strcmp(*argv, "iif") == 0) {
    166 			NEXT_ARG();
    167 			strncpy(filter_dev, *argv, sizeof(filter_dev)-1);
    168 		} else if (matches(*argv, "from") == 0) {
    169 			NEXT_ARG();
    170 			get_prefix(&filter.msrc, *argv, AF_INET);
    171 		} else {
    172 			if (strcmp(*argv, "to") == 0) {
    173 				NEXT_ARG();
    174 			}
    175 			if (matches(*argv, "help") == 0)
    176 				usage();
    177 			get_prefix(&filter.mdst, *argv, AF_INET);
    178 		}
    179 		argv++; argc--;
    180 	}
    181 
    182 	read_viftable();
    183 	read_mroute_list(stdout);
    184 	return 0;
    185 }
    186 
    187 int do_multiroute(int argc, char **argv)
    188 {
    189 	if (argc < 1)
    190 		return mroute_list(0, NULL);
    191 #if 0
    192 	if (matches(*argv, "add") == 0)
    193 		return mroute_modify(RTM_NEWADDR, argc-1, argv+1);
    194 	if (matches(*argv, "delete") == 0)
    195 		return mroute_modify(RTM_DELADDR, argc-1, argv+1);
    196 	if (matches(*argv, "get") == 0)
    197 		return mroute_get(argc-1, argv+1);
    198 #endif
    199 	if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
    200 	    || matches(*argv, "lst") == 0)
    201 		return mroute_list(argc-1, argv+1);
    202 	if (matches(*argv, "help") == 0)
    203 		usage();
    204 	fprintf(stderr, "Command \"%s\" is unknown, try \"ip mroute help\".\n", *argv);
    205 	exit(-1);
    206 }
    207