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