| /* |
| * ipmroute.c "ip mroute". |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * as published by the Free Software Foundation; either version |
| * 2 of the License, or (at your option) any later version. |
| * |
| * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> |
| * |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <syslog.h> |
| #include <fcntl.h> |
| #include <sys/ioctl.h> |
| #include <sys/socket.h> |
| #include <netinet/in.h> |
| #include <arpa/inet.h> |
| #include <string.h> |
| |
| #include <linux/netdevice.h> |
| #include <linux/if.h> |
| #include <linux/if_arp.h> |
| #include <linux/sockios.h> |
| |
| #include "utils.h" |
| |
| char filter_dev[16]; |
| int filter_family; |
| |
| static void usage(void) __attribute__((noreturn)); |
| |
| static void usage(void) |
| { |
| fprintf(stderr, "Usage: ip mroute show [ PREFIX ] [ from PREFIX ] [ iif DEVICE ]\n"); |
| #if 0 |
| fprintf(stderr, "Usage: ip mroute [ add | del ] DESTINATION from SOURCE [ iif DEVICE ] [ oif DEVICE ]\n"); |
| #endif |
| exit(-1); |
| } |
| |
| static char *viftable[32]; |
| |
| struct rtfilter |
| { |
| inet_prefix mdst; |
| inet_prefix msrc; |
| } filter; |
| |
| static void read_viftable(void) |
| { |
| char buf[256]; |
| FILE *fp = fopen("/proc/net/ip_mr_vif", "r"); |
| |
| if (!fp) |
| return; |
| |
| if (!fgets(buf, sizeof(buf), fp)) { |
| fclose(fp); |
| return; |
| } |
| while (fgets(buf, sizeof(buf), fp)) { |
| int vifi; |
| char dev[256]; |
| |
| if (sscanf(buf, "%d%s", &vifi, dev) < 2) |
| continue; |
| |
| if (vifi<0 || vifi>31) |
| continue; |
| |
| viftable[vifi] = strdup(dev); |
| } |
| fclose(fp); |
| } |
| |
| static void read_mroute_list(FILE *ofp) |
| { |
| char buf[256]; |
| FILE *fp = fopen("/proc/net/ip_mr_cache", "r"); |
| |
| if (!fp) |
| return; |
| |
| if (!fgets(buf, sizeof(buf), fp)) { |
| fclose(fp); |
| return; |
| } |
| |
| while (fgets(buf, sizeof(buf), fp)) { |
| inet_prefix maddr, msrc; |
| unsigned pkts, b, w; |
| int vifi; |
| char oiflist[256]; |
| char sbuf[256]; |
| char mbuf[256]; |
| char obuf[256]; |
| |
| oiflist[0] = 0; |
| if (sscanf(buf, "%x%x%d%u%u%u %[^\n]", |
| maddr.data, msrc.data, &vifi, |
| &pkts, &b, &w, oiflist) < 6) |
| continue; |
| |
| if (vifi!=-1 && (vifi < 0 || vifi>31)) |
| continue; |
| |
| if (filter_dev[0] && (vifi<0 || strcmp(filter_dev, viftable[vifi]))) |
| continue; |
| if (filter.mdst.family && inet_addr_match(&maddr, &filter.mdst, filter.mdst.bitlen)) |
| continue; |
| if (filter.msrc.family && inet_addr_match(&msrc, &filter.msrc, filter.msrc.bitlen)) |
| continue; |
| |
| snprintf(obuf, sizeof(obuf), "(%s, %s)", |
| format_host(AF_INET, 4, &msrc.data[0], sbuf, sizeof(sbuf)), |
| format_host(AF_INET, 4, &maddr.data[0], mbuf, sizeof(mbuf))); |
| |
| fprintf(ofp, "%-32s Iif: ", obuf); |
| |
| if (vifi == -1) |
| fprintf(ofp, "unresolved "); |
| else |
| fprintf(ofp, "%-10s ", viftable[vifi]); |
| |
| if (oiflist[0]) { |
| char *next = NULL; |
| char *p = oiflist; |
| int ovifi, ottl; |
| |
| fprintf(ofp, "Oifs: "); |
| |
| while (p) { |
| next = strchr(p, ' '); |
| if (next) { |
| *next = 0; |
| next++; |
| } |
| if (sscanf(p, "%d:%d", &ovifi, &ottl)<2) { |
| p = next; |
| continue; |
| } |
| p = next; |
| |
| fprintf(ofp, "%s", viftable[ovifi]); |
| if (ottl>1) |
| fprintf(ofp, "(ttl %d) ", ovifi); |
| else |
| fprintf(ofp, " "); |
| } |
| } |
| |
| if (show_stats && b) { |
| fprintf(ofp, "%s %u packets, %u bytes", _SL_, pkts, b); |
| if (w) |
| fprintf(ofp, ", %u arrived on wrong iif.", w); |
| } |
| fprintf(ofp, "\n"); |
| } |
| fclose(fp); |
| } |
| |
| |
| static int mroute_list(int argc, char **argv) |
| { |
| while (argc > 0) { |
| if (strcmp(*argv, "iif") == 0) { |
| NEXT_ARG(); |
| strncpy(filter_dev, *argv, sizeof(filter_dev)-1); |
| } else if (matches(*argv, "from") == 0) { |
| NEXT_ARG(); |
| get_prefix(&filter.msrc, *argv, AF_INET); |
| } else { |
| if (strcmp(*argv, "to") == 0) { |
| NEXT_ARG(); |
| } |
| if (matches(*argv, "help") == 0) |
| usage(); |
| get_prefix(&filter.mdst, *argv, AF_INET); |
| } |
| argv++; argc--; |
| } |
| |
| read_viftable(); |
| read_mroute_list(stdout); |
| return 0; |
| } |
| |
| int do_multiroute(int argc, char **argv) |
| { |
| if (argc < 1) |
| return mroute_list(0, NULL); |
| #if 0 |
| if (matches(*argv, "add") == 0) |
| return mroute_modify(RTM_NEWADDR, argc-1, argv+1); |
| if (matches(*argv, "delete") == 0) |
| return mroute_modify(RTM_DELADDR, argc-1, argv+1); |
| if (matches(*argv, "get") == 0) |
| return mroute_get(argc-1, argv+1); |
| #endif |
| if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0 |
| || matches(*argv, "lst") == 0) |
| return mroute_list(argc-1, argv+1); |
| if (matches(*argv, "help") == 0) |
| usage(); |
| fprintf(stderr, "Command \"%s\" is unknown, try \"ip mroute help\".\n", *argv); |
| exit(-1); |
| } |