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 	if (!fgets(buf, sizeof(buf), fp)) {
     62 		fclose(fp);
     63 		return;
     64 	}
     65 	while (fgets(buf, sizeof(buf), fp)) {
     66 		int vifi;
     67 		char dev[256];
     68 
     69 		if (sscanf(buf, "%d%s", &vifi, dev) < 2)
     70 			continue;
     71 
     72 		if (vifi<0 || vifi>31)
     73 			continue;
     74 
     75 		viftable[vifi] = strdup(dev);
     76 	}
     77 	fclose(fp);
     78 }
     79 
     80 static void read_mroute_list(FILE *ofp)
     81 {
     82 	char buf[256];
     83 	FILE *fp = fopen("/proc/net/ip_mr_cache", "r");
     84 
     85 	if (!fp)
     86 		return;
     87 
     88 	if (!fgets(buf, sizeof(buf), fp)) {
     89 		fclose(fp);
     90 		return;
     91 	}
     92 
     93 	while (fgets(buf, sizeof(buf), fp)) {
     94 		inet_prefix maddr, msrc;
     95 		unsigned pkts, b, w;
     96 		int vifi;
     97 		char oiflist[256];
     98 		char sbuf[256];
     99 		char mbuf[256];
    100 		char obuf[256];
    101 
    102 		oiflist[0] = 0;
    103 		if (sscanf(buf, "%x%x%d%u%u%u %[^\n]",
    104 			   maddr.data, msrc.data, &vifi,
    105 			   &pkts, &b, &w, oiflist) < 6)
    106 			continue;
    107 
    108 		if (vifi!=-1 && (vifi < 0 || vifi>31))
    109 			continue;
    110 
    111 		if (filter_dev[0] && (vifi<0 || strcmp(filter_dev, viftable[vifi])))
    112 			continue;
    113 		if (filter.mdst.family && inet_addr_match(&maddr, &filter.mdst, filter.mdst.bitlen))
    114 			continue;
    115 		if (filter.msrc.family && inet_addr_match(&msrc, &filter.msrc, filter.msrc.bitlen))
    116 			continue;
    117 
    118 		snprintf(obuf, sizeof(obuf), "(%s, %s)",
    119 			 format_host(AF_INET, 4, &msrc.data[0], sbuf, sizeof(sbuf)),
    120 			 format_host(AF_INET, 4, &maddr.data[0], mbuf, sizeof(mbuf)));
    121 
    122 		fprintf(ofp, "%-32s Iif: ", obuf);
    123 
    124 		if (vifi == -1)
    125 			fprintf(ofp, "unresolved ");
    126 		else
    127 			fprintf(ofp, "%-10s ", viftable[vifi]);
    128 
    129 		if (oiflist[0]) {
    130 			char *next = NULL;
    131 			char *p = oiflist;
    132 			int ovifi, ottl;
    133 
    134 			fprintf(ofp, "Oifs: ");
    135 
    136 			while (p) {
    137 				next = strchr(p, ' ');
    138 				if (next) {
    139 					*next = 0;
    140 					next++;
    141 				}
    142 				if (sscanf(p, "%d:%d", &ovifi, &ottl)<2) {
    143 					p = next;
    144 					continue;
    145 				}
    146 				p = next;
    147 
    148 				fprintf(ofp, "%s", viftable[ovifi]);
    149 				if (ottl>1)
    150 					fprintf(ofp, "(ttl %d) ", ovifi);
    151 				else
    152 					fprintf(ofp, " ");
    153 			}
    154 		}
    155 
    156 		if (show_stats && b) {
    157 			fprintf(ofp, "%s  %u packets, %u bytes", _SL_, pkts, b);
    158 			if (w)
    159 				fprintf(ofp, ", %u arrived on wrong iif.", w);
    160 		}
    161 		fprintf(ofp, "\n");
    162 	}
    163 	fclose(fp);
    164 }
    165 
    166 
    167 static int mroute_list(int argc, char **argv)
    168 {
    169 	while (argc > 0) {
    170 		if (strcmp(*argv, "iif") == 0) {
    171 			NEXT_ARG();
    172 			strncpy(filter_dev, *argv, sizeof(filter_dev)-1);
    173 		} else if (matches(*argv, "from") == 0) {
    174 			NEXT_ARG();
    175 			get_prefix(&filter.msrc, *argv, AF_INET);
    176 		} else {
    177 			if (strcmp(*argv, "to") == 0) {
    178 				NEXT_ARG();
    179 			}
    180 			if (matches(*argv, "help") == 0)
    181 				usage();
    182 			get_prefix(&filter.mdst, *argv, AF_INET);
    183 		}
    184 		argv++; argc--;
    185 	}
    186 
    187 	read_viftable();
    188 	read_mroute_list(stdout);
    189 	return 0;
    190 }
    191 
    192 int do_multiroute(int argc, char **argv)
    193 {
    194 	if (argc < 1)
    195 		return mroute_list(0, NULL);
    196 #if 0
    197 	if (matches(*argv, "add") == 0)
    198 		return mroute_modify(RTM_NEWADDR, argc-1, argv+1);
    199 	if (matches(*argv, "delete") == 0)
    200 		return mroute_modify(RTM_DELADDR, argc-1, argv+1);
    201 	if (matches(*argv, "get") == 0)
    202 		return mroute_get(argc-1, argv+1);
    203 #endif
    204 	if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
    205 	    || matches(*argv, "lst") == 0)
    206 		return mroute_list(argc-1, argv+1);
    207 	if (matches(*argv, "help") == 0)
    208 		usage();
    209 	fprintf(stderr, "Command \"%s\" is unknown, try \"ip mroute help\".\n", *argv);
    210 	exit(-1);
    211 }
    212