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@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 
usage(void)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 
read_viftable(void)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 
read_mroute_list(FILE * ofp)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 
mroute_list(int argc,char ** argv)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 
do_multiroute(int argc,char ** argv)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