lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame^] | 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 | |
| 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 | }; |
| 52 | static struct rtfilter filter; |
| 53 | |
| 54 | static 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 | |
| 81 | static 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 | |
| 168 | static 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 | |
| 193 | int 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 | } |