diff -urN iproute2-2.4.7-now-ss020116-try/ip/Makefile iproute2-iparp/ip/Makefile --- iproute2-2.4.7-now-ss020116-try/ip/Makefile Thu Jan 10 03:08:18 2002 +++ iproute2-iparp/ip/Makefile Sun Mar 10 15:08:13 2002 @@ -1,4 +1,4 @@ -IPOBJ=ip.o ipaddress.o iproute.o iprule.o \ +IPOBJ=ip.o ipaddress.o iproute.o iprule.o iparp.o \ rtm_map.o iptunnel.o ipneigh.o iplink.o ipmaddr.o \ ipmonitor.o ipmroute.o diff -urN iproute2-2.4.7-now-ss020116-try/ip/ip.c iproute2-iparp/ip/ip.c --- iproute2-2.4.7-now-ss020116-try/ip/ip.c Sun Apr 16 17:42:50 2000 +++ iproute2-iparp/ip/ip.c Sun Mar 31 13:44:30 2002 @@ -39,7 +39,7 @@ { fprintf(stderr, "Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }\n" -"where OBJECT := { link | addr | route | rule | neigh | tunnel |\n" +"where OBJECT := { link | addr | route | rule | neigh | arp | tunnel |\n" " maddr | mroute | monitor }\n" " OPTIONS := { -V[ersion] | -s[tatistics] | -r[esolve] |\n" " -f[amily] { inet | inet6 | ipx | dnet | link } | -o[neline] }\n"); @@ -132,6 +132,8 @@ return do_ipneigh(argc-1, argv+1); if (strcmp(basename, "iplink") == 0) return do_iplink(argc-1, argv+1); + if (strcmp(basename, "iparp") == 0) + return do_iparprule(argc-1, argv+1); if (strcmp(basename, "iptunnel") == 0) return do_iptunnel(argc-1, argv+1); if (strcmp(basename, "ipmonitor") == 0) @@ -153,6 +155,8 @@ return do_ipneigh(argc-2, argv+2); if (matches(argv[1], "link") == 0) return do_iplink(argc-2, argv+2); + if (matches(argv[1], "arp") == 0) + return do_iparprule(argc-2, argv+2); if (matches(argv[1], "tunnel") == 0 || strcmp(argv[1], "tunl") == 0) return do_iptunnel(argc-2, argv+2); diff -urN iproute2-2.4.7-now-ss020116-try/ip/ip_common.h iproute2-iparp/ip/ip_common.h --- iproute2-2.4.7-now-ss020116-try/ip/ip_common.h Sun Apr 16 17:42:50 2000 +++ iproute2-iparp/ip/ip_common.h Sun Mar 31 20:44:02 2002 @@ -15,6 +15,8 @@ extern int do_ipneigh(int argc, char **argv); extern int do_iptunnel(int argc, char **argv); extern int do_iplink(int argc, char **argv); +extern int do_iparprule(int argc, char **argv); +extern int print_arprule(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); extern int do_ipmonitor(int argc, char **argv); extern int do_multiaddr(int argc, char **argv); extern int do_multiroute(int argc, char **argv); diff -urN iproute2-2.4.7-now-ss020116-try/ip/iparp.c iproute2-iparp/ip/iparp.c --- iproute2-2.4.7-now-ss020116-try/ip/iparp.c Thu Jan 1 00:00:00 1970 +++ iproute2-iparp/ip/iparp.c Wed Apr 3 23:56:17 2002 @@ -0,0 +1,943 @@ +/* + * iparp.c "ip arp". + * + * Authors: Julian Anastasov , March 2002 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation; + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt_names.h" +#include "utils.h" + +static void usage(void) __attribute__((noreturn)); + +#define CMD_LIST 0x0001 /* list, lst, show */ +#define CMD_APPEND 0x0002 /* append */ +#define CMD_PREPEND 0x0004 /* prepend, insert */ +#define CMD_ADD 0x0008 /* add, create */ +#define CMD_DEL 0x0010 /* delete, remove */ +#define CMD_CHANGE 0x0020 /* change, chg, update */ +#define CMD_REPLACE 0x0040 /* replace, set */ +#define CMD_FLUSH 0x0080 /* flush */ +#define CMD_TEST 0x0100 /* test */ + +typedef struct { + char *name; + int code; +} strarr_t; + +static strarr_t cmds[] = { + { "list", CMD_LIST }, + { "lst", CMD_LIST }, + { "show", CMD_LIST }, + { "append", CMD_APPEND }, + { "prepend", CMD_PREPEND }, + { "insert", CMD_PREPEND }, + { "add", CMD_ADD }, + { "create", CMD_ADD }, + { "delete", CMD_DEL }, + { "remove", CMD_DEL }, + { "change", CMD_CHANGE }, + { "chg", CMD_CHANGE }, + { "update", CMD_CHANGE }, + { "replace", CMD_REPLACE }, + { "set", CMD_REPLACE }, + { "flush", CMD_FLUSH }, + { "test", CMD_TEST }, + + { NULL, 0 } +}; + +static strarr_t arp_tables[] = { + { "input", ARPA_TABLE_INPUT }, + { "output", ARPA_TABLE_OUTPUT }, + { "forward", ARPA_TABLE_FORWARD }, + + { NULL, 0 } +}; + +static strarr_t arp_actions[] = { + { "deny", 0 }, + { "allow", 1 }, + + { NULL, 0 } +}; + +static int cmd; + +static struct +{ + int tb; + int pref; + int action; + int flushed; + char *flushb; + int flushp; + int flushe; + struct rtnl_handle *rth; + inet_prefix rto; + inet_prefix mto; + inet_prefix rfrom; + inet_prefix mfrom; + inet_prefix rsrc; + __u8 llfrom[MAX_ADDR_LEN]; + __u8 llto[MAX_ADDR_LEN]; + __u8 llsrc[MAX_ADDR_LEN]; + __u8 lldst[MAX_ADDR_LEN]; + int llfrom_len; + int llto_len; + int llsrc_len; + int lldst_len; + int broadcasts; + int unicasts; + char *iif; + char *oif; + __u32 packets; +} f = { + tb: ARPA_TABLE_ALL, + action: -1, +}; + +static strarr_t *lookup_strarr(strarr_t *arr, char *name) +{ + strarr_t *p; + + for (p = arr; p->name; p++) { + if (matches(name, p->name) == 0) + return p; + } + return NULL; +} + +static strarr_t *lookup_strarr_code(strarr_t *arr, int code) +{ + strarr_t *p; + + for (p = arr; p->name; p++) { + if (p->code == code) + return p; + } + return NULL; +} + +static void usage(void) +{ + fprintf(stderr, "Usage: ip arp [ list | flush ] [ RULE ]\n"); + fprintf(stderr, " ip arp [ append | prepend | add | del | change | replace | test ] RULE\n"); + fprintf(stderr, "RULE := [ table TABLE_NAME ] [ pref NUMBER ] [ from PREFIX ] [ to PREFIX ]\n"); + fprintf(stderr, " [ iif STRING ] [ oif STRING ] [ llfrom PREFIX ] [ llto PREFIX ]\n"); + fprintf(stderr, " [ broadcasts ] [ unicasts ] [ ACTION ] [ ALTER ]\n"); + fprintf(stderr, "TABLE_NAME := [ input | forward | output ]\n"); + fprintf(stderr, "ACTION := [ deny | allow ]\n"); + fprintf(stderr, "ALTER := [ src IP ] [ llsrc LLADDR ] [ lldst LLADDR ]\n"); + exit(-1); +} + +static int flush_update(void) +{ + if (rtnl_send(f.rth, f.flushb, f.flushp) < 0) { + perror("Failed to send flush request\n"); + return -1; + } + f.flushp = 0; + return 0; +} + +int print_arprule(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) +{ + FILE *fp = (FILE*)arg; + struct arpmsg *r = NLMSG_DATA(n); + int len = n->nlmsg_len; + int host_len = 32, family = AF_INET; + struct rtattr * tb[RTATTR_MAX+1]; + inet_prefix vto, vfrom, vsrc; + __u32 packets = 0; + char abuf[256]; + SPRINT_BUF(b1); + + if (n->nlmsg_type != RTM_NEWARPRULE && n->nlmsg_type != RTM_DELARPRULE) + return 0; + + if (f.flushb && n->nlmsg_type != RTM_NEWARPRULE) + return 0; + + len -= NLMSG_LENGTH(sizeof(*r)); + if (len < 0) + return -1; + + if (f.tb >= 0 && f.tb != r->arpm_table) + return 0; + + if (f.pref > 0 && f.pref != r->arpm_pref) + return 0; + + if (f.action >= 0 && f.action != r->arpm_action) + return 0; + + if (f.rto.family && f.rto.bitlen > r->arpm_to_len) + return 0; + if (f.mto.family && f.mto.bitlen >= 0 && + f.mto.bitlen < r->arpm_to_len) + return 0; + + if (f.rfrom.family && f.rfrom.bitlen > r->arpm_from_len) + return 0; + if (f.mfrom.family && f.mfrom.bitlen >= 0 && + f.mfrom.bitlen < r->arpm_from_len) + return 0; + + if (f.broadcasts && !(r->arpm_flags & ARPM_F_BROADCAST)) + return 0; + + if (f.unicasts && !(r->arpm_flags & ARPM_F_UNICAST)) + return 0; + + memset(tb, 0, sizeof(tb)); + parse_rtattr(tb, ARPA_MAX, ARPA_RTA(r), len); + + memset(&vto, 0, sizeof(vto)); + if (tb[ARPA_TO]) + memcpy(&vto.data, RTA_DATA(tb[ARPA_TO]), (r->arpm_to_len+7)/8); + + memset(&vfrom, 0, sizeof(vfrom)); + if (tb[ARPA_FROM]) + memcpy(&vfrom.data, RTA_DATA(tb[ARPA_FROM]), + (r->arpm_from_len+7)/8); + + memset(&vsrc, 0, sizeof(vsrc)); + if (tb[ARPA_SRC]) + memcpy(&vsrc.data, RTA_DATA(tb[ARPA_SRC]), 4); + + if (f.rto.family && inet_addr_match(&vto, &f.rto, f.rto.bitlen)) + return 0; + if (f.mto.family && f.mto.bitlen >= 0 && + inet_addr_match(&vto, &f.mto, r->arpm_to_len)) + return 0; + + if (f.rfrom.family && inet_addr_match(&vfrom, &f.rfrom, f.rfrom.bitlen)) + return 0; + if (f.mfrom.family && f.mfrom.bitlen >= 0 && + inet_addr_match(&vfrom, &f.mfrom, r->arpm_from_len)) + return 0; + + if (f.rsrc.family && inet_addr_match(&vsrc, &f.rsrc, f.rsrc.bitlen)) + return 0; + + if (f.iif) { + char *dev, *cp; + int size; + + if (!tb[ARPA_IIF]) + return 0; + dev = (char*)RTA_DATA(tb[ARPA_IIF]); + size = strlen(dev); + if ((cp = strchr(f.iif, '+')) && size > cp - f.iif) + size = cp - f.iif; + if (strncmp(dev, f.iif, size) || + (0 != f.iif[size] && '+' != f.iif[size])) + return 0; + } + + if (f.oif) { + char *dev, *cp; + int size; + + if (!tb[ARPA_OIF]) + return 0; + dev = (char*)RTA_DATA(tb[ARPA_OIF]); + size = strlen(dev); + if ((cp = strchr(f.oif, '+')) && size > cp - f.oif) + size = cp - f.oif; + if (strncmp(dev, f.oif, size) || + (0 != f.oif[size] && '+' != f.oif[size])) + return 0; + } + + if (f.packets) { + if (tb[ARPA_PACKETS]) + memcpy(&packets, RTA_DATA(tb[ARPA_PACKETS]), 4); + if (packets < f.packets) + return 0; + } + + if (f.flushb) { + struct nlmsghdr *fn; + if (NLMSG_ALIGN(f.flushp) + n->nlmsg_len > f.flushe) { + if (flush_update()) + return -1; + } + fn = (struct nlmsghdr*)(f.flushb + NLMSG_ALIGN(f.flushp)); + memcpy(fn, n, n->nlmsg_len); + fn->nlmsg_type = RTM_DELARPRULE; + fn->nlmsg_flags = NLM_F_REQUEST; + fn->nlmsg_seq = ++f.rth->seq; + f.flushp = (((char*)fn) + n->nlmsg_len) - f.flushb; + f.flushed++; + if (show_stats < 2) + return 0; + } + + if (n->nlmsg_type == RTM_DELARPRULE) + fprintf(fp, "Deleted "); + + { + strarr_t *p = lookup_strarr_code(arp_tables, r->arpm_table); + fprintf(fp, "%s", p? p->name:"unknown"); + } + + fprintf(fp, " rule %-2u", r->arpm_pref); + + { + strarr_t *p = lookup_strarr_code(arp_actions, r->arpm_action); + fprintf(fp, " %-5s ", p? p->name:"unk"); + } + + if (tb[ARPA_FROM]) { + if (r->arpm_from_len != host_len) { + fprintf(fp, "from %s/%u", + rt_addr_n2a(family, + RTA_PAYLOAD(tb[ARPA_FROM]), + RTA_DATA(tb[ARPA_FROM]), + abuf, sizeof(abuf)), + r->arpm_from_len + ); + } else { + fprintf(fp, "from %s", + format_host(family, + RTA_PAYLOAD(tb[ARPA_FROM]), + RTA_DATA(tb[ARPA_FROM]), + abuf, sizeof(abuf)) + ); + } + } else if (r->arpm_from_len) { + fprintf(fp, "from 0/%d", r->arpm_from_len); + } else { + fprintf(fp, "from all"); + } + + if (tb[ARPA_TO]) { + if (r->arpm_to_len != host_len) { + fprintf(fp, " to %s/%u", + rt_addr_n2a(family, + RTA_PAYLOAD(tb[ARPA_TO]), + RTA_DATA(tb[ARPA_TO]), + abuf, sizeof(abuf)), + r->arpm_to_len + ); + } else { + fprintf(fp, " to %s", + format_host(family, + RTA_PAYLOAD(tb[ARPA_TO]), + RTA_DATA(tb[ARPA_TO]), + abuf, sizeof(abuf)) + ); + } + } else if (r->arpm_to_len) { + fprintf(fp, " to 0/%d", r->arpm_to_len); + } else { + fprintf(fp, " to all"); + } + + if (tb[ARPA_LLFROM]) { + fprintf(fp, " llfrom %s", + ll_addr_n2a(RTA_DATA(tb[ARPA_LLFROM]), + RTA_PAYLOAD(tb[ARPA_LLFROM]), + ARPHRD_VOID, + b1, sizeof(b1))); + } + + if (tb[ARPA_LLTO]) { + fprintf(fp, " llto %s", + ll_addr_n2a(RTA_DATA(tb[ARPA_LLTO]), + RTA_PAYLOAD(tb[ARPA_LLTO]), + ARPHRD_VOID, + b1, sizeof(b1))); + } + + if (tb[ARPA_IIF]) { + fprintf(fp, " iif %s%s", + (char*)RTA_DATA(tb[ARPA_IIF]), + (r->arpm_flags & ARPM_F_WILDIIF) ? "+" : "" + ); + } + + if (tb[ARPA_OIF]) { + fprintf(fp, " oif %s%s", + (char*)RTA_DATA(tb[ARPA_OIF]), + (r->arpm_flags & ARPM_F_WILDOIF) ? "+" : "" + ); + } + + if (r->arpm_flags & ARPM_F_BROADCAST) { + fprintf(fp, " broadcasts"); + } + + if (r->arpm_flags & ARPM_F_UNICAST) { + fprintf(fp, " unicasts"); + } + + if (tb[ARPA_LLSRC]) { + fprintf(fp, " llsrc %s", + ll_addr_n2a(RTA_DATA(tb[ARPA_LLSRC]), + RTA_PAYLOAD(tb[ARPA_LLSRC]), + ARPHRD_VOID, + b1, sizeof(b1))); + } + + if (tb[ARPA_LLDST]) { + fprintf(fp, " lldst %s", + ll_addr_n2a(RTA_DATA(tb[ARPA_LLDST]), + RTA_PAYLOAD(tb[ARPA_LLDST]), + ARPHRD_VOID, + b1, sizeof(b1))); + } + + if (tb[ARPA_SRC]) { + fprintf(fp, " src %s", + format_host(family, + RTA_PAYLOAD(tb[ARPA_SRC]), + RTA_DATA(tb[ARPA_SRC]), + abuf, sizeof(abuf)) + ); + } + + if (show_stats) { + fprintf(fp, "%s", _SL_); + + if (tb[ARPA_PACKETS]) + fprintf(fp, " packets %u", + *(unsigned*) RTA_DATA(tb[ARPA_PACKETS])); + } + + fprintf(fp, "\n"); + + fflush(fp); + return 0; +} + +int iparprule_do_cmd(int c, int argc, char **argv) +{ + struct rtnl_handle rth; + struct { + struct nlmsghdr n; + struct arpmsg r; + char buf[1024]; + } req; + int af = AF_INET; + int wild = c & (CMD_LIST | CMD_FLUSH); + char *dev = 0; + + f.tb = ARPA_TABLE_ALL; + f.action = -1; + + if (!wild) { + memset(&req, 0, sizeof(req)); + + if (c & CMD_DEL) + req.n.nlmsg_type = RTM_DELARPRULE; + else + req.n.nlmsg_type = RTM_NEWARPRULE; + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct arpmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.r.arpm_table = ARPA_TABLE_ALL; + + switch (c) { + case CMD_APPEND: + req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_APPEND; + break; + case CMD_PREPEND: + req.n.nlmsg_flags |= NLM_F_CREATE; + break; + case CMD_ADD: + req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL; + break; + case CMD_DEL: + req.n.nlmsg_flags |= 0; + break; + case CMD_CHANGE: + req.n.nlmsg_flags |= NLM_F_REPLACE; + break; + case CMD_REPLACE: + req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_REPLACE; + break; + case CMD_TEST: + req.n.nlmsg_flags |= NLM_F_EXCL; + break; + } + } + + for (; argc > 0; argc--, argv++) { + if (matches(*argv, "table") == 0 || + matches(*argv, "lookup") == 0) { + strarr_t *c; + + NEXT_ARG(); + if (f.tb != ARPA_TABLE_ALL) duparg("table", *argv); + c = lookup_strarr(arp_tables, *argv); + if (!c && strcmp(*argv, "all") != 0) + invarg("table value is invalid", *argv); + if (c) + f.tb = c->code; + continue; + } + + if (matches(*argv, "rule") == 0 || + matches(*argv, "preference") == 0 || + matches(*argv, "order") == 0 || + matches(*argv, "priority") == 0) { + NEXT_ARG(); + goto get_pref_; + } + + if (matches(*argv, "input") == 0) { + if (f.tb != ARPA_TABLE_ALL) duparg("input", *argv); + f.tb = ARPA_TABLE_INPUT; + continue; + } + + if (matches(*argv, "output") == 0) { + if (f.tb != ARPA_TABLE_ALL) duparg("output", *argv); + f.tb = ARPA_TABLE_OUTPUT; + continue; + } + + if (matches(*argv, "forward") == 0) { + if (f.tb != ARPA_TABLE_ALL) duparg("forward", *argv); + f.tb = ARPA_TABLE_FORWARD; + continue; + } + + if (matches(*argv, "allow") == 0) { + f.action = 1; + continue; + } + + if (matches(*argv, "deny") == 0 || + matches(*argv, "drop") == 0) { + f.action = 0; + continue; + } + + if (matches(*argv, "from") == 0) { + /* For any command */ + NEXT_ARG(); + if (wild && matches(*argv, "root") == 0) { + NEXT_ARG(); + get_prefix(&f.rfrom, *argv, af); + continue; + } + if (wild && matches(*argv, "match") == 0) { + NEXT_ARG(); + get_prefix(&f.mfrom, *argv, af); + continue; + } + if (matches(*argv, "exact") == 0) { + NEXT_ARG(); + } + if (f.mfrom.family) duparg("from", *argv); + get_prefix(&f.mfrom, *argv, af); + f.rfrom = f.mfrom; + if (!wild) { + req.r.arpm_from_len = f.mfrom.bitlen; + addattr_l(&req.n, sizeof(req), ARPA_FROM, + &f.mfrom.data, 4); + } + continue; + } + + if (matches(*argv, "to") == 0) { + /* For any command */ + NEXT_ARG(); + if (wild && matches(*argv, "root") == 0) { + NEXT_ARG(); + get_prefix(&f.rto, *argv, af); + continue; + } + if (wild && matches(*argv, "match") == 0) { + NEXT_ARG(); + get_prefix(&f.mto, *argv, af); + continue; + } + if (matches(*argv, "exact") == 0) { + NEXT_ARG(); + } + if (f.mto.family) duparg("to", *argv); + get_prefix(&f.mto, *argv, af); + f.rto = f.mto; + if (!wild) { + req.r.arpm_to_len = f.mto.bitlen; + addattr_l(&req.n, sizeof(req), ARPA_TO, + &f.mto.data, 4); + } + continue; + } + + if (matches(*argv, "src") == 0) { + NEXT_ARG(); + if (wild && matches(*argv, "root") == 0) { + NEXT_ARG(); + get_prefix(&f.rsrc, *argv, af); + continue; + } + if (matches(*argv, "exact") == 0) { + NEXT_ARG(); + } + if (f.rsrc.family) duparg("src", *argv); + get_prefix(&f.rsrc, *argv, af); + if (!f.rsrc.bitlen) { + f.rsrc.bitlen = 32; + f.rsrc.data[0] = 0; + } + if (f.rsrc.bitlen != 32) + invarg("src value is invalid", *argv); + if (!wild) + addattr_l(&req.n, sizeof(req), ARPA_SRC, + &f.rsrc.data, 4); + continue; + } + + if (matches(*argv, "llfrom") == 0) { + /* For any command */ + __u8 llabuf[MAX_ADDR_LEN]; + int l; + + NEXT_ARG(); + + if (f.llfrom_len) duparg("llfrom", *argv); + + l = ll_addr_a2n(llabuf, sizeof(llabuf), *argv); + if (l < 0) return 1; + if (l > sizeof(llabuf)) l = sizeof(llabuf); + f.llfrom_len = l; + memcpy(f.llfrom, llabuf, l); + if (!wild) + addattr_l(&req.n, sizeof(req), ARPA_LLFROM, + llabuf, l); + continue; + } + + if (matches(*argv, "llto") == 0) { + /* For any command */ + __u8 llabuf[MAX_ADDR_LEN]; + int l; + + NEXT_ARG(); + + if (f.llto_len) duparg("llto", *argv); + + l = ll_addr_a2n(llabuf, sizeof(llabuf), *argv); + if (l < 0) return 1; + if (l > sizeof(llabuf)) l = sizeof(llabuf); + f.llto_len = l; + memcpy(f.llto, llabuf, l); + if (!wild) + addattr_l(&req.n, sizeof(req), ARPA_LLTO, + llabuf, l); + continue; + } + + if (matches(*argv, "llsrc") == 0) { + /* For any command */ + __u8 llabuf[MAX_ADDR_LEN]; + int l; + + NEXT_ARG(); + + if (f.llsrc_len) duparg("llsrc", *argv); + + l = ll_addr_a2n(llabuf, sizeof(llabuf), *argv); + if (l < 0) return 1; + if (l > sizeof(llabuf)) l = sizeof(llabuf); + f.llsrc_len = l; + memcpy(f.llsrc, llabuf, l); + if (!wild) + addattr_l(&req.n, sizeof(req), ARPA_LLSRC, + llabuf, l); + continue; + } + + if (matches(*argv, "lldst") == 0) { + /* For any command */ + __u8 llabuf[MAX_ADDR_LEN]; + int l; + + NEXT_ARG(); + + if (f.lldst_len) duparg("lldst", *argv); + + l = ll_addr_a2n(llabuf, sizeof(llabuf), *argv); + if (l < 0) return 1; + if (l > sizeof(llabuf)) l = sizeof(llabuf); + f.lldst_len = l; + memcpy(f.lldst, llabuf, l); + if (!wild) + addattr_l(&req.n, sizeof(req), ARPA_LLDST, + llabuf, l); + continue; + } + + if (strcmp(*argv, "dev") == 0) { + NEXT_ARG(); + if (dev) duparg("dev", *argv); + dev = *argv; + continue; + } + + if (strcmp(*argv, "iif") == 0) { + NEXT_ARG(); + if (f.iif) duparg("iif", *argv); + f.iif = *argv; + continue; + } + + if (strcmp(*argv, "oif") == 0) { + NEXT_ARG(); + if (f.oif) duparg("oif", *argv); + f.oif = *argv; + continue; + } + + if (matches(*argv, "packets") == 0) { + NEXT_ARG(); + if (f.packets) duparg("packets", *argv); + if (get_u32(&f.packets, *argv, 0)) + invarg("packets value is invalid", *argv); + if (!wild) + addattr32(&req.n, sizeof(req), ARPA_PACKETS, + f.packets); + continue; + } + + if (matches(*argv, "broadcasts") == 0 || + strcmp(*argv, "brd") == 0) { + f.broadcasts = 1; + continue; + } + + if (matches(*argv, "unicasts") == 0) { + f.unicasts = 1; + continue; + } + + if (matches(*argv, "help") == 0) + usage(); + + get_pref_: + + { + int pref; + + if (f.pref) duparg("preference", *argv); + + if (get_u32(&pref, *argv, 0) || !pref) + invarg("preference value is invalid", *argv); + f.pref = pref; + } + } + + if (f.tb == ARPA_TABLE_ALL && !wild) { + f.tb = ARPA_TABLE_INPUT; + } + + if (dev) { + if (f.tb == ARPA_TABLE_INPUT && !f.iif) + f.iif = dev; + else + if (f.tb == ARPA_TABLE_OUTPUT && !f.oif) + f.oif = dev; + else + invarg("unexpected or duplicate value for dev", *argv); + } + + if (!wild) { + if (f.action < 0) { + /* Default action is allow */ + f.action = 1; + } + } + + /* Unexpected parameters for table input */ + if (!wild && f.tb == ARPA_TABLE_INPUT) { + if (f.rsrc.family) { + fprintf(stderr, "Unexpected argument for table input: src\n"); + return 1; + } + if (f.oif) { + fprintf(stderr, "Unexpected argument for table input: oif\n"); + return 1; + } + } + + /* Unexpected parameters for table output */ + if (!wild && f.tb == ARPA_TABLE_OUTPUT) { + if (f.iif) { + fprintf(stderr, "Unexpected argument for table output: iif\n"); + return 1; + } + if (f.broadcasts) { + fprintf(stderr, "Unexpected argument for table output: broadcasts\n"); + return 1; + } + if (f.unicasts) { + fprintf(stderr, "Unexpected argument for table output: unicasts\n"); + return 1; + } + } + + /* Unexpected parameters for table forward */ + if (!wild && f.tb == ARPA_TABLE_FORWARD) { + if (f.rsrc.family) { + fprintf(stderr, "Unexpected argument for table forward: src\n"); + return 1; + } + } + + if (!wild && f.broadcasts && f.unicasts) { + fprintf(stderr, "Incompatible arguments: broadcasts and unicasts\n"); + return 1; + } + + if (!wild) { + if (!(f.pref || f.mfrom.family || f.mto.family || + f.llto_len || f.llto_len || f.iif || f.oif || + f.broadcasts || f.unicasts)) { + fprintf(stderr, "No arguments for rule selection.\n"); + return 1; + } + } + + if (!wild) { + req.r.arpm_family = AF_INET; + req.r.arpm_table = f.tb; + req.r.arpm_pref = f.pref; + req.r.arpm_action = f.action; + + if (f.broadcasts) + req.r.arpm_flags |= ARPM_F_BROADCAST; + if (f.unicasts) + req.r.arpm_flags |= ARPM_F_UNICAST; + + if (f.iif) { + char *cp = strchr(f.iif, '+'); + + if (cp) { + *cp = 0; + req.r.arpm_flags |= ARPM_F_WILDIIF; + } + if (strlen(f.iif) > IFNAMSIZ-1) { + fprintf(stderr, "Value for iif is too long\n"); + return 1; + } + addattr_l(&req.n, sizeof(req), ARPA_IIF, + f.iif, strlen(f.iif)+1); + } + if (f.oif) { + char *cp = strchr(f.oif, '+'); + + if (cp) { + *cp = 0; + req.r.arpm_flags |= ARPM_F_WILDOIF; + } + if (strlen(f.oif) > IFNAMSIZ-1) { + fprintf(stderr, "Value for oif is too long\n"); + return 1; + } + addattr_l(&req.n, sizeof(req), ARPA_OIF, + f.oif, strlen(f.oif)+1); + } + } + + if (rtnl_open(&rth, 0) < 0) + return 1; + + if (c & CMD_FLUSH) { + int round = 0; + char flushb[4096-512]; + + f.flushb = flushb; + f.flushp = 0; + f.flushe = sizeof(flushb); + f.rth = &rth; + + for (;;) { + if (rtnl_wilddump_request(&rth, af, RTM_GETARPRULE) < 0) { + perror("Cannot send dump request"); + exit(1); + } + f.flushed = 0; + if (rtnl_dump_filter(&rth, print_arprule, stdout, NULL, NULL) < 0) { + fprintf(stderr, "Flush terminated\n"); + exit(1); + } + if (f.flushed == 0) { + if (round == 0) { + fprintf(stderr, "Nothing to flush.\n"); + } + else + if (show_stats) + printf("*** Flush is complete after %d round%s ***\n", round, round>1?"s":""); + fflush(stdout); + return 0; + } + round++; + if (flush_update() < 0) + exit(1); + if (show_stats) { + printf("\n*** Round %d, deleting %d entries ***\n", round, f.flushed); + fflush(stdout); + } + } + } + else + if (wild) { + if (rtnl_wilddump_request(&rth, af, RTM_GETARPRULE) < 0) { + perror("Cannot send dump request"); + return 1; + } + + if (rtnl_dump_filter(&rth, print_arprule, stdout, NULL, NULL) < 0) { + fprintf(stderr, "Dump terminated\n"); + return 1; + } + } else { + if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) + return 2; + } + + return 0; +} + +int do_iparprule(int argc, char **argv) +{ +strarr_t *c; + + if (argc < 1) + return iparprule_do_cmd(CMD_LIST, 0, NULL); + c = lookup_strarr(cmds, argv[0]); + if (c) { + cmd = c->code; + return iparprule_do_cmd(cmd, argc-1, argv+1); + } + if (matches(argv[0], "help") == 0) + usage(); + + fprintf(stderr, "Command \"%s\" is unknown, try \"ip arp help\".\n", *argv); + exit(-1); +} + diff -urN iproute2-2.4.7-now-ss020116-try/ip/ipmonitor.c iproute2-iparp/ip/ipmonitor.c --- iproute2-2.4.7-now-ss020116-try/ip/ipmonitor.c Thu Aug 2 03:23:25 2001 +++ iproute2-iparp/ip/ipmonitor.c Sun Mar 31 20:47:33 2002 @@ -54,6 +54,10 @@ print_neigh(who, n, arg); return 0; } + if (n->nlmsg_type == RTM_NEWARPRULE || n->nlmsg_type == RTM_DELARPRULE) { + print_arprule(who, n, arg); + return 0; + } if (n->nlmsg_type == 15) { char *tstr; time_t secs = ((__u32*)NLMSG_DATA(n))[0]; @@ -86,6 +90,7 @@ int llink=0; int laddr=0; int lroute=0; + int larprule=0; ipaddr_reset_filter(1); iproute_reset_filter(); @@ -104,6 +109,9 @@ } else if (matches(*argv, "route") == 0) { lroute=1; groups = 0; + } else if (matches(*argv, "arprules") == 0) { + larprule=1; + groups = 0; } else if (strcmp(*argv, "all") == 0) { groups = ~RTMGRP_TC; } else if (matches(*argv, "help") == 0) { @@ -129,6 +137,8 @@ if (!preferred_family || preferred_family == AF_INET6) groups |= RTMGRP_IPV6_ROUTE; } + if (larprule) + groups |= RTMGRP_ARP; if (file) { FILE *fp;