IP applet by Bastian Blank <waldi@debian.org>

This commit is contained in:
Glenn L McGrath 2002-11-10 01:33:55 +00:00
parent 021fa7db91
commit 9a2d27249c
27 changed files with 5016 additions and 3 deletions

View File

@ -22,8 +22,8 @@ include $(TOPDIR).config
include $(TOPDIR)Rules.mak
SUBDIRS:=applets archival archival/libunarchive console-tools \
editors fileutils findutils init miscutils modutils networking \
networking/udhcp procps loginutils shell shellutils sysklogd \
textutils util-linux libbb libpwdgrp
networking/libiproute networking/udhcp procps loginutils shell \
shellutils sysklogd textutils util-linux libbb libpwdgrp
all: do-it-all

View File

@ -251,6 +251,9 @@
#ifdef CONFIG_INSMOD
APPLET(insmod, insmod_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
#endif
#ifdef CONFIG_IP
APPLET(ip, ip_main, _BB_DIR_BIN, _BB_SUID_NEVER)
#endif
#ifdef CONFIG_KILL
APPLET(kill, kill_main, _BB_DIR_BIN, _BB_SUID_NEVER)
#endif

View File

@ -977,6 +977,11 @@
"\t-L\tLock to prevent simultaneous loads of a module\n" \
"\t-x\tdo not export externs"
#define ip_trivial_usage \
"not written yet"
#define ip_full_usage \
"not written yet"
#define kill_trivial_usage \
"[-signal] process-id [process-id ...]"
#define kill_full_usage \

View File

@ -26,7 +26,8 @@ NETWORKING-y:=
NETWORKING-$(CONFIG_HOSTNAME) += hostname.o
NETWORKING-$(CONFIG_IFCONFIG) += ifconfig.o
NETWORKING-$(CONFIG_IFUPDOWN) += ifupdown.o
NETWORKING-$(CONFIG_NC) += nc.o
NETWORKING-$(CONFIG_IP) += ip.o
NETWORKING-$(CONFIG_NC) += nc.o
NETWORKING-$(CONFIG_NETSTAT) += netstat.o
NETWORKING-$(CONFIG_NSLOOKUP) += nslookup.o
NETWORKING-$(CONFIG_PING) += ping.o

View File

@ -22,6 +22,13 @@ if [ "$CONFIG_IFUPDOWN" = "y" ]; then
bool ' Enable support for IPv6 (requires ip command)' CONFIG_FEATURE_IFUPDOWN_IPV6
bool ' Enable support for IPX (requires ipx_interface command)' CONFIG_FEATURE_IFUPDOWN_IPX
fi
bool 'ip' CONFIG_IP
if [ "$CONFIG_IP" = "y" ]; then
bool ' address' CONFIG_FEATURE_IP_ADDRESS
bool ' link' CONFIG_FEATURE_IP_LINK
bool ' route' CONFIG_FEATURE_IP_ROUTE
bool ' tunnel' CONFIG_FEATURE_IP_TUNNEL
fi
bool 'nc' CONFIG_NC
bool 'netstat' CONFIG_NETSTAT
bool 'nslookup' CONFIG_NSLOOKUP

104
networking/ip.c Normal file
View File

@ -0,0 +1,104 @@
/*
* ip.c "ip" utility frontend.
*
* 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>
*
*
* Changes:
*
* Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include "./libiproute/utils.h"
#include "./libiproute/ip_common.h"
#include "busybox.h"
int preferred_family = AF_UNSPEC;
int oneline = 0;
char * _SL_ = NULL;
int ip_main(int argc, char **argv)
{
char *basename;
basename = strrchr(argv[0], '/');
if (basename == NULL)
basename = argv[0];
else
basename++;
while (argc > 1) {
char *opt = argv[1];
if (strcmp(opt,"--") == 0) {
argc--; argv++;
break;
}
if (opt[0] != '-')
break;
if (opt[1] == '-')
opt++;
if (matches(opt, "-family") == 0) {
argc--;
argv++;
if (strcmp(argv[1], "inet") == 0)
preferred_family = AF_INET;
else if (strcmp(argv[1], "inet6") == 0)
preferred_family = AF_INET6;
else if (strcmp(argv[1], "link") == 0)
preferred_family = AF_PACKET;
else
invarg(argv[1], "invalid protocol family");
} else if (strcmp(opt, "-4") == 0) {
preferred_family = AF_INET;
} else if (strcmp(opt, "-6") == 0) {
preferred_family = AF_INET6;
} else if (strcmp(opt, "-0") == 0) {
preferred_family = AF_PACKET;
} else if (matches(opt, "-oneline") == 0) {
++oneline;
} else {
fprintf(stderr, "Option \"%s\" is unknown, try \"ip -help\".\n", opt);
exit(-1);
}
argc--; argv++;
}
_SL_ = oneline ? "\\" : "\n" ;
if (argc > 1) {
#ifdef CONFIG_FEATURE_IP_ADDRESS
if (matches(argv[1], "address") == 0)
return do_ipaddr(argc-2, argv+2);
#endif
#ifdef CONFIG_FEATURE_IP_ROUTE
if (matches(argv[1], "route") == 0)
return do_iproute(argc-2, argv+2);
#endif
#ifdef CONFIG_FEATURE_IP_LINK
if (matches(argv[1], "link") == 0)
return do_iplink(argc-2, argv+2);
#endif
#ifdef CONFIG_FEATURE_IP_TUNNEL
if (matches(argv[1], "tunnel") == 0 ||
strcmp(argv[1], "tunl") == 0)
return do_iptunnel(argc-2, argv+2);
#endif
fprintf(stderr, "Object \"%s\" is unknown, try \"ip help\".\n", argv[1]);
exit(-1);
}
}

View File

@ -0,0 +1,30 @@
# Makefile for busybox
#
# Copyright (C) 1999-2002 Erik Andersen <andersee@debian.org>
#
# 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
TOPDIR:= ../../
LIBIPROUTE_DIR:=./
include $(TOPDIR).config
include $(TOPDIR)Rules.mak
include Makefile.in
all: $(libraries-y)
-include $(TOPDIR).depend
clean:
rm -f *.o *.a $(AR_TARGET)

View File

@ -0,0 +1,43 @@
# Makefile for busybox
#
# Copyright (C) 1999-2002 by Erik Andersen <andersee@debian.org>
#
# 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
LIBIPROUTE_AR:=libiproute.a
ifndef $(LIBIPROUTE_DIR)
LIBIPROUTE_DIR:=$(TOPDIR)networking/libiproute/
endif
LIBIPROUTE-y:= \
ipaddress.o \
iplink.o \
iproute.o \
iptunnel.o \
libnetlink.o \
ll_addr.o \
ll_map.o \
ll_proto.o \
ll_types.o \
rt_names.o \
rtm_map.o \
utils.o
libraries-y+=$(LIBIPROUTE_DIR)$(LIBIPROUTE_AR)
$(LIBIPROUTE_DIR)$(LIBIPROUTE_AR): $(patsubst %,$(LIBIPROUTE_DIR)%, $(LIBIPROUTE-y))
$(AR) -ro $@ $(patsubst %,$(LIBIPROUTE_DIR)%, $(LIBIPROUTE-y))

View File

@ -0,0 +1,20 @@
extern int print_linkinfo(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
extern int print_addrinfo(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
extern int print_neigh(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
extern int ipaddr_list(int argc, char **argv);
extern int ipaddr_list_link(int argc, char **argv);
extern int iproute_monitor(int argc, char **argv);
extern void iplink_usage(void) __attribute__((noreturn));
extern void iproute_reset_filter(void);
extern void ipaddr_reset_filter(int);
extern void ipneigh_reset_filter(void);
extern int print_route(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
extern int do_ipaddr(int argc, char **argv);
extern int do_iproute(int argc, char **argv);
extern int do_iprule(int argc, char **argv);
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_ipmonitor(int argc, char **argv);
extern int do_multiaddr(int argc, char **argv);
extern int do_multiroute(int argc, char **argv);

View File

@ -0,0 +1,723 @@
/*
* ipaddress.c "ip address".
*
* 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>
*
* Changes:
* Laszlo Valko <valko@linux.karinthy.hu> 990223: address label must be zero terminated
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <fnmatch.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/sockios.h>
#include "rt_names.h"
#include "utils.h"
#include "ll_map.h"
#include "ip_common.h"
#include "busybox.h"
static struct
{
int ifindex;
int family;
int oneline;
int showqueue;
inet_prefix pfx;
int scope, scopemask;
int flags, flagmask;
int up;
char *label;
struct rtnl_handle *rth;
} filter;
static int do_link;
void print_link_flags(FILE *fp, unsigned flags, unsigned mdown)
{
fprintf(fp, "<");
flags &= ~IFF_RUNNING;
#define _PF(f) if (flags&IFF_##f) { \
flags &= ~IFF_##f ; \
fprintf(fp, #f "%s", flags ? "," : ""); }
_PF(LOOPBACK);
_PF(BROADCAST);
_PF(POINTOPOINT);
_PF(MULTICAST);
_PF(NOARP);
#if 0
_PF(ALLMULTI);
_PF(PROMISC);
_PF(MASTER);
_PF(SLAVE);
_PF(DEBUG);
_PF(DYNAMIC);
_PF(AUTOMEDIA);
_PF(PORTSEL);
_PF(NOTRAILERS);
#endif
_PF(UP);
#undef _PF
if (flags)
fprintf(fp, "%x", flags);
if (mdown)
fprintf(fp, ",M-DOWN");
fprintf(fp, "> ");
}
void print_queuelen(char *name)
{
struct ifreq ifr;
int s;
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0)
return;
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, name);
if (ioctl(s, SIOCGIFTXQLEN, &ifr) < 0) {
perror("SIOCGIFXQLEN");
close(s);
return;
}
close(s);
if (ifr.ifr_qlen)
printf("qlen %d", ifr.ifr_qlen);
}
int print_linkinfo(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
FILE *fp = (FILE*)arg;
struct ifinfomsg *ifi = NLMSG_DATA(n);
struct rtattr * tb[IFLA_MAX+1];
int len = n->nlmsg_len;
unsigned m_flag = 0;
if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK)
return 0;
len -= NLMSG_LENGTH(sizeof(*ifi));
if (len < 0)
return -1;
if (filter.ifindex && ifi->ifi_index != filter.ifindex)
return 0;
if (filter.up && !(ifi->ifi_flags&IFF_UP))
return 0;
memset(tb, 0, sizeof(tb));
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
if (tb[IFLA_IFNAME] == NULL) {
fprintf(stderr, "BUG: nil ifname\n");
return -1;
}
if (filter.label &&
(!filter.family || filter.family == AF_PACKET) &&
fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0))
return 0;
if (n->nlmsg_type == RTM_DELLINK)
fprintf(fp, "Deleted ");
fprintf(fp, "%d: %s", ifi->ifi_index,
tb[IFLA_IFNAME] ? (char*)RTA_DATA(tb[IFLA_IFNAME]) : "<nil>");
if (tb[IFLA_LINK]) {
SPRINT_BUF(b1);
int iflink = *(int*)RTA_DATA(tb[IFLA_LINK]);
if (iflink == 0)
fprintf(fp, "@NONE: ");
else {
fprintf(fp, "@%s: ", ll_idx_n2a(iflink, b1));
m_flag = ll_index_to_flags(iflink);
m_flag = !(m_flag & IFF_UP);
}
} else {
fprintf(fp, ": ");
}
print_link_flags(fp, ifi->ifi_flags, m_flag);
if (tb[IFLA_MTU])
fprintf(fp, "mtu %u ", *(int*)RTA_DATA(tb[IFLA_MTU]));
if (tb[IFLA_QDISC])
fprintf(fp, "qdisc %s ", (char*)RTA_DATA(tb[IFLA_QDISC]));
#ifdef IFLA_MASTER
if (tb[IFLA_MASTER]) {
SPRINT_BUF(b1);
fprintf(fp, "master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1));
}
#endif
if (filter.showqueue)
print_queuelen((char*)RTA_DATA(tb[IFLA_IFNAME]));
if (!filter.family || filter.family == AF_PACKET) {
SPRINT_BUF(b1);
fprintf(fp, "%s", _SL_);
fprintf(fp, " link/%s ", ll_type_n2a(ifi->ifi_type, b1, sizeof(b1)));
if (tb[IFLA_ADDRESS]) {
fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]),
RTA_PAYLOAD(tb[IFLA_ADDRESS]),
ifi->ifi_type,
b1, sizeof(b1)));
}
if (tb[IFLA_BROADCAST]) {
if (ifi->ifi_flags&IFF_POINTOPOINT)
fprintf(fp, " peer ");
else
fprintf(fp, " brd ");
fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]),
RTA_PAYLOAD(tb[IFLA_BROADCAST]),
ifi->ifi_type,
b1, sizeof(b1)));
}
}
fprintf(fp, "\n");
fflush(fp);
return 0;
}
int print_addrinfo(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
FILE *fp = (FILE*)arg;
struct ifaddrmsg *ifa = NLMSG_DATA(n);
int len = n->nlmsg_len;
struct rtattr * rta_tb[IFA_MAX+1];
char abuf[256];
SPRINT_BUF(b1);
if (n->nlmsg_type != RTM_NEWADDR && n->nlmsg_type != RTM_DELADDR)
return 0;
len -= NLMSG_LENGTH(sizeof(*ifa));
if (len < 0) {
fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
return -1;
}
memset(rta_tb, 0, sizeof(rta_tb));
parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
if (!rta_tb[IFA_LOCAL])
rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
if (!rta_tb[IFA_ADDRESS])
rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];
if (filter.ifindex && filter.ifindex != ifa->ifa_index)
return 0;
if ((filter.scope^ifa->ifa_scope)&filter.scopemask)
return 0;
if ((filter.flags^ifa->ifa_flags)&filter.flagmask)
return 0;
if (filter.label) {
SPRINT_BUF(b1);
const char *label;
if (rta_tb[IFA_LABEL])
label = RTA_DATA(rta_tb[IFA_LABEL]);
else
label = ll_idx_n2a(ifa->ifa_index, b1);
if (fnmatch(filter.label, label, 0) != 0)
return 0;
}
if (filter.pfx.family) {
if (rta_tb[IFA_LOCAL]) {
inet_prefix dst;
memset(&dst, 0, sizeof(dst));
dst.family = ifa->ifa_family;
memcpy(&dst.data, RTA_DATA(rta_tb[IFA_LOCAL]), RTA_PAYLOAD(rta_tb[IFA_LOCAL]));
if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen))
return 0;
}
}
if (n->nlmsg_type == RTM_DELADDR)
fprintf(fp, "Deleted ");
if (filter.oneline)
fprintf(fp, "%u: %s", ifa->ifa_index, ll_index_to_name(ifa->ifa_index));
if (ifa->ifa_family == AF_INET)
fprintf(fp, " inet ");
else if (ifa->ifa_family == AF_INET6)
fprintf(fp, " inet6 ");
else
fprintf(fp, " family %d ", ifa->ifa_family);
if (rta_tb[IFA_LOCAL]) {
fprintf(fp, "%s", rt_addr_n2a(ifa->ifa_family,
RTA_PAYLOAD(rta_tb[IFA_LOCAL]),
RTA_DATA(rta_tb[IFA_LOCAL]),
abuf, sizeof(abuf)));
if (rta_tb[IFA_ADDRESS] == NULL ||
memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), 4) == 0) {
fprintf(fp, "/%d ", ifa->ifa_prefixlen);
} else {
fprintf(fp, " peer %s/%d ",
rt_addr_n2a(ifa->ifa_family,
RTA_PAYLOAD(rta_tb[IFA_ADDRESS]),
RTA_DATA(rta_tb[IFA_ADDRESS]),
abuf, sizeof(abuf)),
ifa->ifa_prefixlen);
}
}
if (rta_tb[IFA_BROADCAST]) {
fprintf(fp, "brd %s ",
rt_addr_n2a(ifa->ifa_family,
RTA_PAYLOAD(rta_tb[IFA_BROADCAST]),
RTA_DATA(rta_tb[IFA_BROADCAST]),
abuf, sizeof(abuf)));
}
if (rta_tb[IFA_ANYCAST]) {
fprintf(fp, "any %s ",
rt_addr_n2a(ifa->ifa_family,
RTA_PAYLOAD(rta_tb[IFA_ANYCAST]),
RTA_DATA(rta_tb[IFA_ANYCAST]),
abuf, sizeof(abuf)));
}
fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1)));
if (ifa->ifa_flags&IFA_F_SECONDARY) {
ifa->ifa_flags &= ~IFA_F_SECONDARY;
fprintf(fp, "secondary ");
}
if (ifa->ifa_flags&IFA_F_TENTATIVE) {
ifa->ifa_flags &= ~IFA_F_TENTATIVE;
fprintf(fp, "tentative ");
}
if (ifa->ifa_flags&IFA_F_DEPRECATED) {
ifa->ifa_flags &= ~IFA_F_DEPRECATED;
fprintf(fp, "deprecated ");
}
if (!(ifa->ifa_flags&IFA_F_PERMANENT)) {
fprintf(fp, "dynamic ");
} else
ifa->ifa_flags &= ~IFA_F_PERMANENT;
if (ifa->ifa_flags)
fprintf(fp, "flags %02x ", ifa->ifa_flags);
if (rta_tb[IFA_LABEL])
fprintf(fp, "%s", (char*)RTA_DATA(rta_tb[IFA_LABEL]));
if (rta_tb[IFA_CACHEINFO]) {
struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]);
char buf[128];
fprintf(fp, "%s", _SL_);
if (ci->ifa_valid == 0xFFFFFFFFU)
sprintf(buf, "valid_lft forever");
else
sprintf(buf, "valid_lft %dsec", ci->ifa_valid);
if (ci->ifa_prefered == 0xFFFFFFFFU)
sprintf(buf+strlen(buf), " preferred_lft forever");
else
sprintf(buf+strlen(buf), " preferred_lft %dsec", ci->ifa_prefered);
fprintf(fp, " %s", buf);
}
fprintf(fp, "\n");
fflush(fp);
return 0;
}
struct nlmsg_list
{
struct nlmsg_list *next;
struct nlmsghdr h;
};
int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo, FILE *fp)
{
for ( ;ainfo ; ainfo = ainfo->next) {
struct nlmsghdr *n = &ainfo->h;
struct ifaddrmsg *ifa = NLMSG_DATA(n);
if (n->nlmsg_type != RTM_NEWADDR)
continue;
if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifa)))
return -1;
if (ifa->ifa_index != ifindex ||
(filter.family && filter.family != ifa->ifa_family))
continue;
print_addrinfo(NULL, n, fp);
}
return 0;
}
int store_nlmsg(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
struct nlmsg_list **linfo = (struct nlmsg_list**)arg;
struct nlmsg_list *h;
struct nlmsg_list **lp;
h = malloc(n->nlmsg_len+sizeof(void*));
if (h == NULL)
return -1;
memcpy(&h->h, n, n->nlmsg_len);
h->next = NULL;
for (lp = linfo; *lp; lp = &(*lp)->next) /* NOTHING */;
*lp = h;
ll_remember_index(who, n, NULL);
return 0;
}
int ipaddr_list(int argc, char **argv)
{
struct nlmsg_list *linfo = NULL;
struct nlmsg_list *ainfo = NULL;
struct nlmsg_list *l;
struct rtnl_handle rth;
char *filter_dev = NULL;
int no_link = 0;
ipaddr_reset_filter(oneline);
filter.showqueue = 1;
if (filter.family == AF_UNSPEC)
filter.family = preferred_family;
while (argc > 0) {
if (strcmp(*argv, "to") == 0) {
NEXT_ARG();
get_prefix(&filter.pfx, *argv, filter.family);
if (filter.family == AF_UNSPEC)
filter.family = filter.pfx.family;
} else if (strcmp(*argv, "scope") == 0) {
int scope = 0;
NEXT_ARG();
filter.scopemask = -1;
if (rtnl_rtscope_a2n(&scope, *argv)) {
if (strcmp(*argv, "all") != 0)
invarg("invalid \"scope\"\n", *argv);
scope = RT_SCOPE_NOWHERE;
filter.scopemask = 0;
}
filter.scope = scope;
} else if (strcmp(*argv, "up") == 0) {
filter.up = 1;
} else if (strcmp(*argv, "label") == 0) {
NEXT_ARG();
filter.label = *argv;
} else {
if (strcmp(*argv, "dev") == 0) {
NEXT_ARG();
}
if (filter_dev)
duparg2("dev", *argv);
filter_dev = *argv;
}
argv++; argc--;
}
if (rtnl_open(&rth, 0) < 0)
exit(1);
if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK) < 0) {
perror("Cannot send dump request");
exit(1);
}
if (rtnl_dump_filter(&rth, store_nlmsg, &linfo, NULL, NULL) < 0) {
fprintf(stderr, "Dump terminated\n");
exit(1);
}
if (filter_dev) {
filter.ifindex = ll_name_to_index(filter_dev);
if (filter.ifindex <= 0) {
fprintf(stderr, "Device \"%s\" does not exist.\n", filter_dev);
return -1;
}
}
if (filter.family != AF_PACKET) {
if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) {
perror("Cannot send dump request");
exit(1);
}
if (rtnl_dump_filter(&rth, store_nlmsg, &ainfo, NULL, NULL) < 0) {
fprintf(stderr, "Dump terminated\n");
exit(1);
}
}
if (filter.family && filter.family != AF_PACKET) {
struct nlmsg_list **lp;
lp=&linfo;
if (filter.oneline)
no_link = 1;
while ((l=*lp)!=NULL) {
int ok = 0;
struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
struct nlmsg_list *a;
for (a=ainfo; a; a=a->next) {
struct nlmsghdr *n = &a->h;
struct ifaddrmsg *ifa = NLMSG_DATA(n);
if (ifa->ifa_index != ifi->ifi_index ||
(filter.family && filter.family != ifa->ifa_family))
continue;
if ((filter.scope^ifa->ifa_scope)&filter.scopemask)
continue;
if ((filter.flags^ifa->ifa_flags)&filter.flagmask)
continue;
if (filter.pfx.family || filter.label) {
struct rtattr *tb[IFA_MAX+1];
memset(tb, 0, sizeof(tb));
parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n));
if (!tb[IFA_LOCAL])
tb[IFA_LOCAL] = tb[IFA_ADDRESS];
if (filter.pfx.family && tb[IFA_LOCAL]) {
inet_prefix dst;
memset(&dst, 0, sizeof(dst));
dst.family = ifa->ifa_family;
memcpy(&dst.data, RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_LOCAL]));
if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen))
continue;
}
if (filter.label) {
SPRINT_BUF(b1);
const char *label;
if (tb[IFA_LABEL])
label = RTA_DATA(tb[IFA_LABEL]);
else
label = ll_idx_n2a(ifa->ifa_index, b1);
if (fnmatch(filter.label, label, 0) != 0)
continue;
}
}
ok = 1;
break;
}
if (!ok)
*lp = l->next;
else
lp = &l->next;
}
}
for (l=linfo; l; l = l->next) {
if (no_link || print_linkinfo(NULL, &l->h, stdout) == 0) {
struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
if (filter.family != AF_PACKET)
print_selected_addrinfo(ifi->ifi_index, ainfo, stdout);
}
fflush(stdout);
}
exit(0);
}
int ipaddr_list_link(int argc, char **argv)
{
preferred_family = AF_PACKET;
do_link = 1;
return ipaddr_list(argc, argv);
}
void ipaddr_reset_filter(int oneline)
{
memset(&filter, 0, sizeof(filter));
filter.oneline = oneline;
}
int default_scope(inet_prefix *lcl)
{
if (lcl->family == AF_INET) {
if (lcl->bytelen >= 1 && *(__u8*)&lcl->data == 127)
return RT_SCOPE_HOST;
}
return 0;
}
int ipaddr_modify(int cmd, int argc, char **argv)
{
struct rtnl_handle rth;
struct {
struct nlmsghdr n;
struct ifaddrmsg ifa;
char buf[256];
} req;
char *d = NULL;
char *l = NULL;
inet_prefix lcl;
inet_prefix peer;
int local_len = 0;
int peer_len = 0;
int brd_len = 0;
int any_len = 0;
int scoped = 0;
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = cmd;
req.ifa.ifa_family = preferred_family;
while (argc > 0) {
if (strcmp(*argv, "peer") == 0 ||
strcmp(*argv, "remote") == 0) {
NEXT_ARG();
if (peer_len)
duparg("peer", *argv);
get_prefix(&peer, *argv, req.ifa.ifa_family);
peer_len = peer.bytelen;
if (req.ifa.ifa_family == AF_UNSPEC)
req.ifa.ifa_family = peer.family;
addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen);
req.ifa.ifa_prefixlen = peer.bitlen;
} else if (matches(*argv, "broadcast") == 0 ||
strcmp(*argv, "brd") == 0) {
inet_prefix addr;
NEXT_ARG();
if (brd_len)
duparg("broadcast", *argv);
if (strcmp(*argv, "+") == 0)
brd_len = -1;
else if (strcmp(*argv, "-") == 0)
brd_len = -2;
else {
get_addr(&addr, *argv, req.ifa.ifa_family);
if (req.ifa.ifa_family == AF_UNSPEC)
req.ifa.ifa_family = addr.family;
addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen);
brd_len = addr.bytelen;
}
} else if (strcmp(*argv, "anycast") == 0) {
inet_prefix addr;
NEXT_ARG();
if (any_len)
duparg("anycast", *argv);
get_addr(&addr, *argv, req.ifa.ifa_family);
if (req.ifa.ifa_family == AF_UNSPEC)
req.ifa.ifa_family = addr.family;
addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen);
any_len = addr.bytelen;
} else if (strcmp(*argv, "scope") == 0) {
int scope = 0;
NEXT_ARG();
if (rtnl_rtscope_a2n(&scope, *argv))
invarg(*argv, "invalid scope value.");
req.ifa.ifa_scope = scope;
scoped = 1;
} else if (strcmp(*argv, "dev") == 0) {
NEXT_ARG();
d = *argv;
} else if (strcmp(*argv, "label") == 0) {
NEXT_ARG();
l = *argv;
addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1);
} else {
if (strcmp(*argv, "local") == 0) {
NEXT_ARG();
}
if (local_len)
duparg2("local", *argv);
get_prefix(&lcl, *argv, req.ifa.ifa_family);
if (req.ifa.ifa_family == AF_UNSPEC)
req.ifa.ifa_family = lcl.family;
addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen);
local_len = lcl.bytelen;
}
argc--; argv++;
}
if (d == NULL) {
fprintf(stderr, "Not enough information: \"dev\" argument is required.\n");
return -1;
}
if (l && matches(d, l) != 0) {
fprintf(stderr, "\"dev\" (%s) must match \"label\" (%s).\n", d, l);
exit(1);
}
if (peer_len == 0 && local_len && cmd != RTM_DELADDR) {
peer = lcl;
addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &lcl.data, lcl.bytelen);
}
if (req.ifa.ifa_prefixlen == 0)
req.ifa.ifa_prefixlen = lcl.bitlen;
if (brd_len < 0 && cmd != RTM_DELADDR) {
inet_prefix brd;
int i;
if (req.ifa.ifa_family != AF_INET) {
fprintf(stderr, "Broadcast can be set only for IPv4 addresses\n");
return -1;
}
brd = peer;
if (brd.bitlen <= 30) {
for (i=31; i>=brd.bitlen; i--) {
if (brd_len == -1)
brd.data[0] |= htonl(1<<(31-i));
else
brd.data[0] &= ~htonl(1<<(31-i));
}
addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &brd.data, brd.bytelen);
brd_len = brd.bytelen;
}
}
if (!scoped && cmd != RTM_DELADDR)
req.ifa.ifa_scope = default_scope(&lcl);
if (rtnl_open(&rth, 0) < 0)
exit(1);
ll_init_map(&rth);
if ((req.ifa.ifa_index = ll_name_to_index(d)) == 0) {
fprintf(stderr, "Cannot find device \"%s\"\n", d);
return -1;
}
if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
exit(2);
exit(0);
}
int do_ipaddr(int argc, char **argv)
{
if (argc < 1)
return ipaddr_list(0, NULL);
if (matches(*argv, "add") == 0)
return ipaddr_modify(RTM_NEWADDR, argc-1, argv+1);
if (matches(*argv, "delete") == 0)
return ipaddr_modify(RTM_DELADDR, argc-1, argv+1);
if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
|| matches(*argv, "lst") == 0)
return ipaddr_list(argc-1, argv+1);
fprintf(stderr, "Command \"%s\" is unknown, try \"ip address help\".\n", *argv);
exit(-1);
}

View File

@ -0,0 +1,349 @@
/*
* iplink.c "ip link".
*
* 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 <errno.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/sockios.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/sockios.h>
#include "rt_names.h"
#include "utils.h"
#include "ip_common.h"
#include "busybox.h"
static int on_off(char *msg)
{
fprintf(stderr, "Error: argument of \"%s\" must be \"on\" or \"off\"\n", msg);
return -1;
}
static int get_ctl_fd(void)
{
int s_errno;
int fd;
fd = socket(PF_INET, SOCK_DGRAM, 0);
if (fd >= 0)
return fd;
s_errno = errno;
fd = socket(PF_PACKET, SOCK_DGRAM, 0);
if (fd >= 0)
return fd;
fd = socket(PF_INET6, SOCK_DGRAM, 0);
if (fd >= 0)
return fd;
errno = s_errno;
perror("Cannot create control socket");
return -1;
}
static int do_chflags(char *dev, __u32 flags, __u32 mask)
{
struct ifreq ifr;
int fd;
int err;
strcpy(ifr.ifr_name, dev);
fd = get_ctl_fd();
if (fd < 0)
return -1;
err = ioctl(fd, SIOCGIFFLAGS, &ifr);
if (err) {
perror("SIOCGIFFLAGS");
close(fd);
return -1;
}
if ((ifr.ifr_flags^flags)&mask) {
ifr.ifr_flags &= ~mask;
ifr.ifr_flags |= mask&flags;
err = ioctl(fd, SIOCSIFFLAGS, &ifr);
if (err)
perror("SIOCSIFFLAGS");
}
close(fd);
return err;
}
static int do_changename(char *dev, char *newdev)
{
struct ifreq ifr;
int fd;
int err;
strcpy(ifr.ifr_name, dev);
strcpy(ifr.ifr_newname, newdev);
fd = get_ctl_fd();
if (fd < 0)
return -1;
err = ioctl(fd, SIOCSIFNAME, &ifr);
if (err) {
perror("SIOCSIFNAME");
close(fd);
return -1;
}
close(fd);
return err;
}
static int set_qlen(char *dev, int qlen)
{
struct ifreq ifr;
int s;
s = get_ctl_fd();
if (s < 0)
return -1;
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, dev);
ifr.ifr_qlen = qlen;
if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) {
perror("SIOCSIFXQLEN");
close(s);
return -1;
}
close(s);
return 0;
}
static int set_mtu(char *dev, int mtu)
{
struct ifreq ifr;
int s;
s = get_ctl_fd();
if (s < 0)
return -1;
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, dev);
ifr.ifr_mtu = mtu;
if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {
perror("SIOCSIFMTU");
close(s);
return -1;
}
close(s);
return 0;
}
static int get_address(char *dev, int *htype)
{
struct ifreq ifr;
struct sockaddr_ll me;
int alen;
int s;
s = socket(PF_PACKET, SOCK_DGRAM, 0);
if (s < 0) {
perror("socket(PF_PACKET)");
return -1;
}
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, dev);
if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
perror("SIOCGIFINDEX");
close(s);
return -1;
}
memset(&me, 0, sizeof(me));
me.sll_family = AF_PACKET;
me.sll_ifindex = ifr.ifr_ifindex;
me.sll_protocol = htons(ETH_P_LOOP);
if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) {
perror("bind");
close(s);
return -1;
}
alen = sizeof(me);
if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {
perror("getsockname");
close(s);
return -1;
}
close(s);
*htype = me.sll_hatype;
return me.sll_halen;
}
static int parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr)
{
int alen;
memset(ifr, 0, sizeof(*ifr));
strcpy(ifr->ifr_name, dev);
ifr->ifr_hwaddr.sa_family = hatype;
alen = ll_addr_a2n(ifr->ifr_hwaddr.sa_data, 14, lla);
if (alen < 0)
return -1;
if (alen != halen) {
fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n", lla, halen);
return -1;
}
return 0;
}
static int set_address(struct ifreq *ifr, int brd)
{
int s;
s = get_ctl_fd();
if (s < 0)
return -1;
if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) {
perror(brd?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR");
close(s);
return -1;
}
close(s);
return 0;
}
static int do_set(int argc, char **argv)
{
char *dev = NULL;
__u32 mask = 0;
__u32 flags = 0;
int qlen = -1;
int mtu = -1;
char *newaddr = NULL;
char *newbrd = NULL;
struct ifreq ifr0, ifr1;
char *newname = NULL;
int htype, halen;
while (argc > 0) {
if (strcmp(*argv, "up") == 0) {
mask |= IFF_UP;
flags |= IFF_UP;
} else if (strcmp(*argv, "down") == 0) {
mask |= IFF_UP;
flags &= ~IFF_UP;
} else if (strcmp(*argv, "name") == 0) {
NEXT_ARG();
newname = *argv;
} else if (strcmp(*argv, "mtu") == 0) {
NEXT_ARG();
if (mtu != -1)
duparg("mtu", *argv);
if (get_integer(&mtu, *argv, 0))
invarg("Invalid \"mtu\" value\n", *argv);
} else if (strcmp(*argv, "multicast") == 0) {
NEXT_ARG();
mask |= IFF_MULTICAST;
if (strcmp(*argv, "on") == 0) {
flags |= IFF_MULTICAST;
} else if (strcmp(*argv, "off") == 0) {
flags &= ~IFF_MULTICAST;
} else
return on_off("multicast");
} else if (strcmp(*argv, "arp") == 0) {
NEXT_ARG();
mask |= IFF_NOARP;
if (strcmp(*argv, "on") == 0) {
flags &= ~IFF_NOARP;
} else if (strcmp(*argv, "off") == 0) {
flags |= IFF_NOARP;
} else
return on_off("noarp");
} else {
if (strcmp(*argv, "dev") == 0) {
NEXT_ARG();
}
if (dev)
duparg2("dev", *argv);
dev = *argv;
}
argc--; argv++;
}
if (!dev) {
fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n");
exit(-1);
}
if (newaddr || newbrd) {
halen = get_address(dev, &htype);
if (halen < 0)
return -1;
if (newaddr) {
if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0)
return -1;
}
if (newbrd) {
if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0)
return -1;
}
}
if (newname && strcmp(dev, newname)) {
if (do_changename(dev, newname) < 0)
return -1;
dev = newname;
}
if (qlen != -1) {
if (set_qlen(dev, qlen) < 0)
return -1;
}
if (mtu != -1) {
if (set_mtu(dev, mtu) < 0)
return -1;
}
if (newaddr || newbrd) {
if (newbrd) {
if (set_address(&ifr1, 1) < 0)
return -1;
}
if (newaddr) {
if (set_address(&ifr0, 0) < 0)
return -1;
}
}
if (mask)
return do_chflags(dev, flags, mask);
return 0;
}
int do_iplink(int argc, char **argv)
{
if (argc > 0) {
if (matches(*argv, "set") == 0)
return do_set(argc-1, argv+1);
if (matches(*argv, "show") == 0 ||
matches(*argv, "lst") == 0 ||
matches(*argv, "list") == 0)
return ipaddr_list_link(argc-1, argv+1);
} else
return ipaddr_list_link(0, NULL);
fprintf(stderr, "Command \"%s\" is unknown, try \"ip link help\".\n", *argv);
exit(-1);
}

View File

@ -0,0 +1,674 @@
/*
* iproute.c "ip route".
*
* 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>
*
*
* Changes:
*
* Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
* Kunihiro Ishiguro <kunihiro@zebra.org> 001102: rtnh_ifindex was not initialized
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
#include <string.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <linux/in_route.h>
#include "rt_names.h"
#include "utils.h"
#include "ip_common.h"
#include "busybox.h"
#ifndef RTAX_RTTVAR
#define RTAX_RTTVAR RTAX_HOPS
#endif
static struct
{
int tb;
int flushp;
int flushe;
struct rtnl_handle *rth;
int protocol, protocolmask;
int scope, scopemask;
int type, typemask;
int tos, tosmask;
int iif, iifmask;
int oif, oifmask;
int realm, realmmask;
inet_prefix rprefsrc;
inet_prefix rvia;
inet_prefix rdst;
inet_prefix mdst;
inet_prefix rsrc;
inet_prefix msrc;
} filter;
int print_route(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
FILE *fp = (FILE*)arg;
struct rtmsg *r = NLMSG_DATA(n);
int len = n->nlmsg_len;
struct rtattr * tb[RTA_MAX+1];
char abuf[256];
int host_len = -1;
SPRINT_BUF(b1);
if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
fprintf(stderr, "Not a route: %08x %08x %08x\n",
n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
return 0;
}
len -= NLMSG_LENGTH(sizeof(*r));
if (len < 0) {
fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
return -1;
}
if (r->rtm_family == AF_INET6)
host_len = 128;
else if (r->rtm_family == AF_INET)
host_len = 32;
if (r->rtm_family == AF_INET6) {
if (filter.tb) {
if (filter.tb < 0) {
if (!(r->rtm_flags&RTM_F_CLONED))
return 0;
} else {
if (r->rtm_flags&RTM_F_CLONED)
return 0;
if (filter.tb == RT_TABLE_LOCAL) {
if (r->rtm_type != RTN_LOCAL)
return 0;
} else if (filter.tb == RT_TABLE_MAIN) {
if (r->rtm_type == RTN_LOCAL)
return 0;
} else {
return 0;
}
}
}
} else {
if (filter.tb > 0 && filter.tb != r->rtm_table)
return 0;
}
if (filter.rdst.family &&
(r->rtm_family != filter.rdst.family || filter.rdst.bitlen > r->rtm_dst_len))
return 0;
if (filter.mdst.family &&
(r->rtm_family != filter.mdst.family ||
(filter.mdst.bitlen >= 0 && filter.mdst.bitlen < r->rtm_dst_len)))
return 0;
if (filter.rsrc.family &&
(r->rtm_family != filter.rsrc.family || filter.rsrc.bitlen > r->rtm_src_len))
return 0;
if (filter.msrc.family &&
(r->rtm_family != filter.msrc.family ||
(filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len)))
return 0;
memset(tb, 0, sizeof(tb));
parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
if (n->nlmsg_type == RTM_DELROUTE)
fprintf(fp, "Deleted ");
if (r->rtm_type != RTN_UNICAST && !filter.type)
fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
if (tb[RTA_DST]) {
if (r->rtm_dst_len != host_len) {
fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family,
RTA_PAYLOAD(tb[RTA_DST]),
RTA_DATA(tb[RTA_DST]),
abuf, sizeof(abuf)),
r->rtm_dst_len
);
} else {
fprintf(fp, "%s ", format_host(r->rtm_family,
RTA_PAYLOAD(tb[RTA_DST]),
RTA_DATA(tb[RTA_DST]),
abuf, sizeof(abuf))
);
}
} else if (r->rtm_dst_len) {
fprintf(fp, "0/%d ", r->rtm_dst_len);
} else {
fprintf(fp, "default ");
}
if (tb[RTA_SRC]) {
if (r->rtm_src_len != host_len) {
fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family,
RTA_PAYLOAD(tb[RTA_SRC]),
RTA_DATA(tb[RTA_SRC]),
abuf, sizeof(abuf)),
r->rtm_src_len
);
} else {
fprintf(fp, "from %s ", format_host(r->rtm_family,
RTA_PAYLOAD(tb[RTA_SRC]),
RTA_DATA(tb[RTA_SRC]),
abuf, sizeof(abuf))
);
}
} else if (r->rtm_src_len) {
fprintf(fp, "from 0/%u ", r->rtm_src_len);
}
if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
fprintf(fp, "via %s ",
format_host(r->rtm_family,
RTA_PAYLOAD(tb[RTA_GATEWAY]),
RTA_DATA(tb[RTA_GATEWAY]),
abuf, sizeof(abuf)));
}
if (tb[RTA_OIF] && filter.oifmask != -1)
fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) {
/* Do not use format_host(). It is our local addr
and symbolic name will not be useful.
*/
fprintf(fp, " src %s ",
rt_addr_n2a(r->rtm_family,
RTA_PAYLOAD(tb[RTA_PREFSRC]),
RTA_DATA(tb[RTA_PREFSRC]),
abuf, sizeof(abuf)));
}
if (tb[RTA_PRIORITY])
fprintf(fp, " metric %d ", *(__u32*)RTA_DATA(tb[RTA_PRIORITY]));
if (r->rtm_family == AF_INET6) {
struct rta_cacheinfo *ci = NULL;
if (tb[RTA_CACHEINFO])
ci = RTA_DATA(tb[RTA_CACHEINFO]);
if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
static int hz;
if (!hz)
hz = get_hz();
if (r->rtm_flags & RTM_F_CLONED)
fprintf(fp, "%s cache ", _SL_);
if (ci->rta_expires)
fprintf(fp, " expires %dsec", ci->rta_expires/hz);
if (ci->rta_error != 0)
fprintf(fp, " error %d", ci->rta_error);
} else if (ci) {
if (ci->rta_error != 0)
fprintf(fp, " error %d", ci->rta_error);
}
}
if (tb[RTA_IIF] && filter.iifmask != -1) {
fprintf(fp, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF])));
}
fprintf(fp, "\n");
fflush(fp);
return 0;
}
int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
{
struct rtnl_handle rth;
struct {
struct nlmsghdr n;
struct rtmsg r;
char buf[1024];
} req;
char mxbuf[256];
struct rtattr * mxrta = (void*)mxbuf;
unsigned mxlock = 0;
char *d = NULL;
int gw_ok = 0;
int dst_ok = 0;
//int nhs_ok = 0;
//int scope_ok = 0;
//int table_ok = 0;
int proto_ok = 0;
int type_ok = 0;
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
req.n.nlmsg_flags = NLM_F_REQUEST|flags;
req.n.nlmsg_type = cmd;
req.r.rtm_family = preferred_family;
req.r.rtm_table = RT_TABLE_MAIN;
req.r.rtm_scope = RT_SCOPE_NOWHERE;
if (cmd != RTM_DELROUTE) {
req.r.rtm_protocol = RTPROT_BOOT;
req.r.rtm_scope = RT_SCOPE_UNIVERSE;
req.r.rtm_type = RTN_UNICAST;
}
mxrta->rta_type = RTA_METRICS;
mxrta->rta_len = RTA_LENGTH(0);
while (argc > 0) {
if (strcmp(*argv, "src") == 0) {
inet_prefix addr;
NEXT_ARG();
get_addr(&addr, *argv, req.r.rtm_family);
if (req.r.rtm_family == AF_UNSPEC)
req.r.rtm_family = addr.family;
addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen);
} else if (strcmp(*argv, "via") == 0) {
inet_prefix addr;
gw_ok = 1;
NEXT_ARG();
get_addr(&addr, *argv, req.r.rtm_family);
if (req.r.rtm_family == AF_UNSPEC)
req.r.rtm_family = addr.family;
addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen);
} else if (strcmp(*argv, "mtu") == 0) {
unsigned mtu;
NEXT_ARG();
if (strcmp(*argv, "lock") == 0) {
mxlock |= (1<<RTAX_MTU);
NEXT_ARG();
}
if (get_unsigned(&mtu, *argv, 0))
invarg("\"mtu\" value is invalid\n", *argv);
rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu);
} else if (matches(*argv, "protocol") == 0) {
int prot;
NEXT_ARG();
if (rtnl_rtprot_a2n(&prot, *argv))
invarg("\"protocol\" value is invalid\n", *argv);
req.r.rtm_protocol = prot;
proto_ok =1;
} else if (strcmp(*argv, "dev") == 0 ||
strcmp(*argv, "oif") == 0) {
NEXT_ARG();
d = *argv;
} else {
int type;
inet_prefix dst;
if (strcmp(*argv, "to") == 0) {
NEXT_ARG();
}
if ((**argv < '0' || **argv > '9') &&
rtnl_rtntype_a2n(&type, *argv) == 0) {
NEXT_ARG();
req.r.rtm_type = type;
type_ok = 1;
}
if (dst_ok)
duparg2("to", *argv);
get_prefix(&dst, *argv, req.r.rtm_family);
if (req.r.rtm_family == AF_UNSPEC)
req.r.rtm_family = dst.family;
req.r.rtm_dst_len = dst.bitlen;
dst_ok = 1;
if (dst.bytelen)
addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen);
}
argc--; argv++;
}
if (rtnl_open(&rth, 0) < 0)
exit(1);
if (mxrta->rta_len > RTA_LENGTH(0)) {
if (mxlock)
rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock);
addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
}
if (req.r.rtm_family == AF_UNSPEC)
req.r.rtm_family = AF_INET;
if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
exit(2);
return 0;
}
static int rtnl_rtcache_request(struct rtnl_handle *rth, int family)
{
struct {
struct nlmsghdr nlh;
struct rtmsg rtm;
} req;
struct sockaddr_nl nladdr;
memset(&nladdr, 0, sizeof(nladdr));
memset(&req, 0, sizeof(req));
nladdr.nl_family = AF_NETLINK;
req.nlh.nlmsg_len = sizeof(req);
req.nlh.nlmsg_type = RTM_GETROUTE;
req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_REQUEST;
req.nlh.nlmsg_pid = 0;
req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
req.rtm.rtm_family = family;
req.rtm.rtm_flags |= RTM_F_CLONED;
return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
}
static int iproute_list(int argc, char **argv)
{
int do_ipv6 = preferred_family;
struct rtnl_handle rth;
char *id = NULL;
char *od = NULL;
iproute_reset_filter();
filter.tb = RT_TABLE_MAIN;
while (argc > 0) {
if (matches(*argv, "protocol") == 0) {
int prot = 0;
NEXT_ARG();
filter.protocolmask = -1;
if (rtnl_rtprot_a2n(&prot, *argv)) {
if (strcmp(*argv, "all") != 0)
invarg("invalid \"protocol\"\n", *argv);
prot = 0;
filter.protocolmask = 0;
}
filter.protocol = prot;
} else if (strcmp(*argv, "dev") == 0 ||
strcmp(*argv, "oif") == 0) {
NEXT_ARG();
od = *argv;
} else if (strcmp(*argv, "iif") == 0) {
NEXT_ARG();
id = *argv;
} else if (matches(*argv, "from") == 0) {
NEXT_ARG();
if (matches(*argv, "root") == 0) {
NEXT_ARG();
get_prefix(&filter.rsrc, *argv, do_ipv6);
} else if (matches(*argv, "match") == 0) {
NEXT_ARG();
get_prefix(&filter.msrc, *argv, do_ipv6);
} else {
if (matches(*argv, "exact") == 0) {
NEXT_ARG();
}
get_prefix(&filter.msrc, *argv, do_ipv6);
filter.rsrc = filter.msrc;
}
} else {
if (matches(*argv, "to") == 0) {
NEXT_ARG();
}
if (matches(*argv, "root") == 0) {
NEXT_ARG();
get_prefix(&filter.rdst, *argv, do_ipv6);
} else if (matches(*argv, "match") == 0) {
NEXT_ARG();
get_prefix(&filter.mdst, *argv, do_ipv6);
} else {
if (matches(*argv, "exact") == 0) {
NEXT_ARG();
}
get_prefix(&filter.mdst, *argv, do_ipv6);
filter.rdst = filter.mdst;
}
}
argc--; argv++;
}
if (do_ipv6 == AF_UNSPEC && filter.tb)
do_ipv6 = AF_INET;
if (rtnl_open(&rth, 0) < 0)
exit(1);
ll_init_map(&rth);
if (id || od) {
int idx;
if (id) {
if ((idx = ll_name_to_index(id)) == 0) {
fprintf(stderr, "Cannot find device \"%s\"\n", id);
return -1;
}
filter.iif = idx;
filter.iifmask = -1;
}
if (od) {
if ((idx = ll_name_to_index(od)) == 0) {
fprintf(stderr, "Cannot find device \"%s\"\n", od);
return -1;
}
filter.oif = idx;
filter.oifmask = -1;
}
}
if (filter.tb != -1) {
if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
perror("Cannot send dump request");
exit(1);
}
} else {
if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
perror("Cannot send dump request");
exit(1);
}
}
if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) {
fprintf(stderr, "Dump terminated\n");
exit(1);
}
exit(0);
}
int iproute_get(int argc, char **argv)
{
struct rtnl_handle rth;
struct {
struct nlmsghdr n;
struct rtmsg r;
char buf[1024];
} req;
char *idev = NULL;
char *odev = NULL;
int connected = 0;
int from_ok = 0;
memset(&req, 0, sizeof(req));
iproute_reset_filter();
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = RTM_GETROUTE;
req.r.rtm_family = preferred_family;
req.r.rtm_table = 0;
req.r.rtm_protocol = 0;
req.r.rtm_scope = 0;
req.r.rtm_type = 0;
req.r.rtm_src_len = 0;
req.r.rtm_dst_len = 0;
req.r.rtm_tos = 0;
while (argc > 0) {
if (matches(*argv, "from") == 0) {
inet_prefix addr;
NEXT_ARG();
from_ok = 1;
get_prefix(&addr, *argv, req.r.rtm_family);
if (req.r.rtm_family == AF_UNSPEC)
req.r.rtm_family = addr.family;
if (addr.bytelen)
addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
req.r.rtm_src_len = addr.bitlen;
} else if (matches(*argv, "iif") == 0) {
NEXT_ARG();
idev = *argv;
} else if (matches(*argv, "oif") == 0 ||
strcmp(*argv, "dev") == 0) {
NEXT_ARG();
odev = *argv;
} else if (matches(*argv, "notify") == 0) {
req.r.rtm_flags |= RTM_F_NOTIFY;
} else if (matches(*argv, "connected") == 0) {
connected = 1;
} else {
inet_prefix addr;
if (strcmp(*argv, "to") == 0) {
NEXT_ARG();
}
get_prefix(&addr, *argv, req.r.rtm_family);
if (req.r.rtm_family == AF_UNSPEC)
req.r.rtm_family = addr.family;
if (addr.bytelen)
addattr_l(&req.n, sizeof(req), RTA_DST, &addr.data, addr.bytelen);
req.r.rtm_dst_len = addr.bitlen;
}
argc--; argv++;
}
if (req.r.rtm_dst_len == 0) {
fprintf(stderr, "need at least destination address\n");
exit(1);
}
if (rtnl_open(&rth, 0) < 0)
exit(1);
ll_init_map(&rth);
if (idev || odev) {
int idx;
if (idev) {
if ((idx = ll_name_to_index(idev)) == 0) {
fprintf(stderr, "Cannot find device \"%s\"\n", idev);
return -1;
}
addattr32(&req.n, sizeof(req), RTA_IIF, idx);
}
if (odev) {
if ((idx = ll_name_to_index(odev)) == 0) {
fprintf(stderr, "Cannot find device \"%s\"\n", odev);
return -1;
}
addattr32(&req.n, sizeof(req), RTA_OIF, idx);
}
}
if (req.r.rtm_family == AF_UNSPEC)
req.r.rtm_family = AF_INET;
if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0)
exit(2);
if (connected && !from_ok) {
struct rtmsg *r = NLMSG_DATA(&req.n);
int len = req.n.nlmsg_len;
struct rtattr * tb[RTA_MAX+1];
if (print_route(NULL, &req.n, (void*)stdout) < 0) {
fprintf(stderr, "An error :-)\n");
exit(1);
}
if (req.n.nlmsg_type != RTM_NEWROUTE) {
fprintf(stderr, "Not a route?\n");
return -1;
}
len -= NLMSG_LENGTH(sizeof(*r));
if (len < 0) {
fprintf(stderr, "Wrong len %d\n", len);
return -1;
}
memset(tb, 0, sizeof(tb));
parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
if (tb[RTA_PREFSRC]) {
tb[RTA_PREFSRC]->rta_type = RTA_SRC;
r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]);
} else if (!tb[RTA_SRC]) {
fprintf(stderr, "Failed to connect the route\n");
return -1;
}
if (!odev && tb[RTA_OIF])
tb[RTA_OIF]->rta_type = 0;
if (tb[RTA_GATEWAY])
tb[RTA_GATEWAY]->rta_type = 0;
if (!idev && tb[RTA_IIF])
tb[RTA_IIF]->rta_type = 0;
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = RTM_GETROUTE;
if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0)
exit(2);
}
if (print_route(NULL, &req.n, (void*)stdout) < 0) {
fprintf(stderr, "An error :-)\n");
exit(1);
}
exit(0);
}
void iproute_reset_filter()
{
memset(&filter, 0, sizeof(filter));
filter.mdst.bitlen = -1;
filter.msrc.bitlen = -1;
}
int do_iproute(int argc, char **argv)
{
if (argc < 1)
return iproute_list(0, NULL);
if (matches(*argv, "add") == 0)
return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_EXCL,
argc-1, argv+1);
if (matches(*argv, "change") == 0 || strcmp(*argv, "chg") == 0)
return iproute_modify(RTM_NEWROUTE, NLM_F_REPLACE,
argc-1, argv+1);
if (matches(*argv, "replace") == 0)
return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_REPLACE,
argc-1, argv+1);
if (matches(*argv, "prepend") == 0)
return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE,
argc-1, argv+1);
if (matches(*argv, "append") == 0)
return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_APPEND,
argc-1, argv+1);
if (matches(*argv, "test") == 0)
return iproute_modify(RTM_NEWROUTE, NLM_F_EXCL,
argc-1, argv+1);
if (matches(*argv, "delete") == 0)
return iproute_modify(RTM_DELROUTE, 0,
argc-1, argv+1);
if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
|| matches(*argv, "lst") == 0)
return iproute_list(argc-1, argv+1);
if (matches(*argv, "get") == 0)
return iproute_get(argc-1, argv+1);
fprintf(stderr, "Command \"%s\" is unknown, try \"ip route help\".\n", *argv);
exit(-1);
}

View File

@ -0,0 +1,548 @@
/*
* iptunnel.c "ip tunnel"
*
* 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>
*
*
* Changes:
*
* Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
* Rani Assaf <rani@magic.metawire.com> 980930: do not allow key for ipip/sit
* Phil Karn <karn@ka9q.ampr.org> 990408: "pmtudisc" flag
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <linux/if.h>
#include <linux/if_arp.h>
#include <linux/if_tunnel.h>
#include "rt_names.h"
#include "utils.h"
#include "busybox.h"
static int do_ioctl_get_ifindex(char *dev)
{
struct ifreq ifr;
int fd;
int err;
strcpy(ifr.ifr_name, dev);
fd = socket(AF_INET, SOCK_DGRAM, 0);
err = ioctl(fd, SIOCGIFINDEX, &ifr);
if (err) {
perror("ioctl");
return 0;
}
close(fd);
return ifr.ifr_ifindex;
}
static int do_ioctl_get_iftype(char *dev)
{
struct ifreq ifr;
int fd;
int err;
strcpy(ifr.ifr_name, dev);
fd = socket(AF_INET, SOCK_DGRAM, 0);
err = ioctl(fd, SIOCGIFHWADDR, &ifr);
if (err) {
perror("ioctl");
return -1;
}
close(fd);
return ifr.ifr_addr.sa_family;
}
static char * do_ioctl_get_ifname(int idx)
{
static struct ifreq ifr;
int fd;
int err;
ifr.ifr_ifindex = idx;
fd = socket(AF_INET, SOCK_DGRAM, 0);
err = ioctl(fd, SIOCGIFNAME, &ifr);
if (err) {
perror("ioctl");
return NULL;
}
close(fd);
return ifr.ifr_name;
}
static int do_get_ioctl(char *basedev, struct ip_tunnel_parm *p)
{
struct ifreq ifr;
int fd;
int err;
strcpy(ifr.ifr_name, basedev);
ifr.ifr_ifru.ifru_data = (void*)p;
fd = socket(AF_INET, SOCK_DGRAM, 0);
err = ioctl(fd, SIOCGETTUNNEL, &ifr);
if (err)
perror("ioctl");
close(fd);
return err;
}
static int do_add_ioctl(int cmd, char *basedev, struct ip_tunnel_parm *p)
{
struct ifreq ifr;
int fd;
int err;
if (cmd == SIOCCHGTUNNEL && p->name[0])
strcpy(ifr.ifr_name, p->name);
else
strcpy(ifr.ifr_name, basedev);
ifr.ifr_ifru.ifru_data = (void*)p;
fd = socket(AF_INET, SOCK_DGRAM, 0);
err = ioctl(fd, cmd, &ifr);
if (err)
perror("ioctl");
close(fd);
return err;
}
static int do_del_ioctl(char *basedev, struct ip_tunnel_parm *p)
{
struct ifreq ifr;
int fd;
int err;
if (p->name[0])
strcpy(ifr.ifr_name, p->name);
else
strcpy(ifr.ifr_name, basedev);
ifr.ifr_ifru.ifru_data = (void*)p;
fd = socket(AF_INET, SOCK_DGRAM, 0);
err = ioctl(fd, SIOCDELTUNNEL, &ifr);
if (err)
perror("ioctl");
close(fd);
return err;
}
static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
{
int count = 0;
char medium[IFNAMSIZ];
memset(p, 0, sizeof(*p));
memset(&medium, 0, sizeof(medium));
p->iph.version = 4;
p->iph.ihl = 5;
#ifndef IP_DF
#define IP_DF 0x4000 /* Flag: "Don't Fragment" */
#endif
p->iph.frag_off = htons(IP_DF);
while (argc > 0) {
if (strcmp(*argv, "mode") == 0) {
NEXT_ARG();
if (strcmp(*argv, "ipip") == 0 ||
strcmp(*argv, "ip/ip") == 0) {
if (p->iph.protocol && p->iph.protocol != IPPROTO_IPIP) {
fprintf(stderr,"You managed to ask for more than one tunnel mode.\n");
exit(-1);
}
p->iph.protocol = IPPROTO_IPIP;
} else if (strcmp(*argv, "gre") == 0 ||
strcmp(*argv, "gre/ip") == 0) {
if (p->iph.protocol && p->iph.protocol != IPPROTO_GRE) {
fprintf(stderr,"You managed to ask for more than one tunnel mode.\n");
exit(-1);
}
p->iph.protocol = IPPROTO_GRE;
} else if (strcmp(*argv, "sit") == 0 ||
strcmp(*argv, "ipv6/ip") == 0) {
if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) {
fprintf(stderr,"You managed to ask for more than one tunnel mode.\n");
exit(-1);
}
p->iph.protocol = IPPROTO_IPV6;
} else {
fprintf(stderr,"Cannot guess tunnel mode.\n");
exit(-1);
}
} else if (strcmp(*argv, "key") == 0) {
unsigned uval;
NEXT_ARG();
p->i_flags |= GRE_KEY;
p->o_flags |= GRE_KEY;
if (strchr(*argv, '.'))
p->i_key = p->o_key = get_addr32(*argv);
else {
if (get_unsigned(&uval, *argv, 0)<0) {
fprintf(stderr, "invalid value of \"key\"\n");
exit(-1);
}
p->i_key = p->o_key = htonl(uval);
}
} else if (strcmp(*argv, "ikey") == 0) {
unsigned uval;
NEXT_ARG();
p->i_flags |= GRE_KEY;
if (strchr(*argv, '.'))
p->o_key = get_addr32(*argv);
else {
if (get_unsigned(&uval, *argv, 0)<0) {
fprintf(stderr, "invalid value of \"ikey\"\n");
exit(-1);
}
p->i_key = htonl(uval);
}
} else if (strcmp(*argv, "okey") == 0) {
unsigned uval;
NEXT_ARG();
p->o_flags |= GRE_KEY;
if (strchr(*argv, '.'))
p->o_key = get_addr32(*argv);
else {
if (get_unsigned(&uval, *argv, 0)<0) {
fprintf(stderr, "invalid value of \"okey\"\n");
exit(-1);
}
p->o_key = htonl(uval);
}
} else if (strcmp(*argv, "seq") == 0) {
p->i_flags |= GRE_SEQ;
p->o_flags |= GRE_SEQ;
} else if (strcmp(*argv, "iseq") == 0) {
p->i_flags |= GRE_SEQ;
} else if (strcmp(*argv, "oseq") == 0) {
p->o_flags |= GRE_SEQ;
} else if (strcmp(*argv, "csum") == 0) {
p->i_flags |= GRE_CSUM;
p->o_flags |= GRE_CSUM;
} else if (strcmp(*argv, "icsum") == 0) {
p->i_flags |= GRE_CSUM;
} else if (strcmp(*argv, "ocsum") == 0) {
p->o_flags |= GRE_CSUM;
} else if (strcmp(*argv, "nopmtudisc") == 0) {
p->iph.frag_off = 0;
} else if (strcmp(*argv, "pmtudisc") == 0) {
p->iph.frag_off = htons(IP_DF);
} else if (strcmp(*argv, "remote") == 0) {
NEXT_ARG();
if (strcmp(*argv, "any"))
p->iph.daddr = get_addr32(*argv);
} else if (strcmp(*argv, "local") == 0) {
NEXT_ARG();
if (strcmp(*argv, "any"))
p->iph.saddr = get_addr32(*argv);
} else if (strcmp(*argv, "dev") == 0) {
NEXT_ARG();
strncpy(medium, *argv, IFNAMSIZ-1);
} else if (strcmp(*argv, "ttl") == 0) {
unsigned uval;
NEXT_ARG();
if (strcmp(*argv, "inherit") != 0) {
if (get_unsigned(&uval, *argv, 0))
invarg("invalid TTL\n", *argv);
if (uval > 255)
invarg("TTL must be <=255\n", *argv);
p->iph.ttl = uval;
}
} else if (strcmp(*argv, "tos") == 0 ||
matches(*argv, "dsfield") == 0) {
__u32 uval;
NEXT_ARG();
if (strcmp(*argv, "inherit") != 0) {
if (rtnl_dsfield_a2n(&uval, *argv))
invarg("bad TOS value", *argv);
p->iph.tos = uval;
} else
p->iph.tos = 1;
} else {
if (strcmp(*argv, "name") == 0) {
NEXT_ARG();
}
if (p->name[0])
duparg2("name", *argv);
strncpy(p->name, *argv, IFNAMSIZ);
if (cmd == SIOCCHGTUNNEL && count == 0) {
struct ip_tunnel_parm old_p;
memset(&old_p, 0, sizeof(old_p));
if (do_get_ioctl(*argv, &old_p))
return -1;
*p = old_p;
}
}
count++;
argc--; argv++;
}
if (p->iph.protocol == 0) {
if (memcmp(p->name, "gre", 3) == 0)
p->iph.protocol = IPPROTO_GRE;
else if (memcmp(p->name, "ipip", 4) == 0)
p->iph.protocol = IPPROTO_IPIP;
else if (memcmp(p->name, "sit", 3) == 0)
p->iph.protocol = IPPROTO_IPV6;
}
if (p->iph.protocol == IPPROTO_IPIP || p->iph.protocol == IPPROTO_IPV6) {
if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) {
fprintf(stderr, "Keys are not allowed with ipip and sit.\n");
return -1;
}
}
if (medium[0]) {
p->link = do_ioctl_get_ifindex(medium);
if (p->link == 0)
return -1;
}
if (p->i_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) {
p->i_key = p->iph.daddr;
p->i_flags |= GRE_KEY;
}
if (p->o_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) {
p->o_key = p->iph.daddr;
p->o_flags |= GRE_KEY;
}
if (IN_MULTICAST(ntohl(p->iph.daddr)) && !p->iph.saddr) {
fprintf(stderr, "Broadcast tunnel requires a source address.\n");
return -1;
}
return 0;
}
static int do_add(int cmd, int argc, char **argv)
{
struct ip_tunnel_parm p;
if (parse_args(argc, argv, cmd, &p) < 0)
return -1;
if (p.iph.ttl && p.iph.frag_off == 0) {
fprintf(stderr, "ttl != 0 and noptmudisc are incompatible\n");
return -1;
}
switch (p.iph.protocol) {
case IPPROTO_IPIP:
return do_add_ioctl(cmd, "tunl0", &p);
case IPPROTO_GRE:
return do_add_ioctl(cmd, "gre0", &p);
case IPPROTO_IPV6:
return do_add_ioctl(cmd, "sit0", &p);
default:
fprintf(stderr, "cannot determine tunnel mode (ipip, gre or sit)\n");
return -1;
}
return -1;
}
int do_del(int argc, char **argv)
{
struct ip_tunnel_parm p;
if (parse_args(argc, argv, SIOCDELTUNNEL, &p) < 0)
return -1;
switch (p.iph.protocol) {
case IPPROTO_IPIP:
return do_del_ioctl("tunl0", &p);
case IPPROTO_GRE:
return do_del_ioctl("gre0", &p);
case IPPROTO_IPV6:
return do_del_ioctl("sit0", &p);
default:
return do_del_ioctl(p.name, &p);
}
return -1;
}
void print_tunnel(struct ip_tunnel_parm *p)
{
char s1[256];
char s2[256];
char s3[64];
char s4[64];
format_host(AF_INET, 4, &p->iph.daddr, s1, sizeof(s1));
format_host(AF_INET, 4, &p->iph.saddr, s2, sizeof(s2));
inet_ntop(AF_INET, &p->i_key, s3, sizeof(s3));
inet_ntop(AF_INET, &p->o_key, s4, sizeof(s4));
printf("%s: %s/ip remote %s local %s ",
p->name,
p->iph.protocol == IPPROTO_IPIP ? "ip" :
(p->iph.protocol == IPPROTO_GRE ? "gre" :
(p->iph.protocol == IPPROTO_IPV6 ? "ipv6" : "unknown")),
p->iph.daddr ? s1 : "any", p->iph.saddr ? s2 : "any");
if (p->link) {
char *n = do_ioctl_get_ifname(p->link);
if (n)
printf(" dev %s ", n);
}
if (p->iph.ttl)
printf(" ttl %d ", p->iph.ttl);
else
printf(" ttl inherit ");
if (p->iph.tos) {
SPRINT_BUF(b1);
printf(" tos");
if (p->iph.tos&1)
printf(" inherit");
if (p->iph.tos&~1)
printf("%c%s ", p->iph.tos&1 ? '/' : ' ',
rtnl_dsfield_n2a(p->iph.tos&~1, b1, sizeof(b1)));
}
if (!(p->iph.frag_off&htons(IP_DF)))
printf(" nopmtudisc");
if ((p->i_flags&GRE_KEY) && (p->o_flags&GRE_KEY) && p->o_key == p->i_key)
printf(" key %s", s3);
else if ((p->i_flags|p->o_flags)&GRE_KEY) {
if (p->i_flags&GRE_KEY)
printf(" ikey %s ", s3);
if (p->o_flags&GRE_KEY)
printf(" okey %s ", s4);
}
if (p->i_flags&GRE_SEQ)
printf("%s Drop packets out of sequence.\n", _SL_);
if (p->i_flags&GRE_CSUM)
printf("%s Checksum in received packet is required.", _SL_);
if (p->o_flags&GRE_SEQ)
printf("%s Sequence packets on output.", _SL_);
if (p->o_flags&GRE_CSUM)
printf("%s Checksum output packets.", _SL_);
}
static int do_tunnels_list(struct ip_tunnel_parm *p)
{
char name[IFNAMSIZ];
unsigned long rx_bytes, rx_packets, rx_errs, rx_drops,
rx_fifo, rx_frame,
tx_bytes, tx_packets, tx_errs, tx_drops,
tx_fifo, tx_colls, tx_carrier, rx_multi;
int type;
struct ip_tunnel_parm p1;
char buf[512];
FILE *fp = fopen("/proc/net/dev", "r");
if (fp == NULL) {
perror("fopen");
return -1;
}
fgets(buf, sizeof(buf), fp);
fgets(buf, sizeof(buf), fp);
while (fgets(buf, sizeof(buf), fp) != NULL) {
char *ptr;
buf[sizeof(buf) - 1] = 0;
if ((ptr = strchr(buf, ':')) == NULL ||
(*ptr++ = 0, sscanf(buf, "%s", name) != 1)) {
fprintf(stderr, "Wrong format of /proc/net/dev. Sorry.\n");
return -1;
}
if (sscanf(ptr, "%ld%ld%ld%ld%ld%ld%ld%*d%ld%ld%ld%ld%ld%ld%ld",
&rx_bytes, &rx_packets, &rx_errs, &rx_drops,
&rx_fifo, &rx_frame, &rx_multi,
&tx_bytes, &tx_packets, &tx_errs, &tx_drops,
&tx_fifo, &tx_colls, &tx_carrier) != 14)
continue;
if (p->name[0] && strcmp(p->name, name))
continue;
type = do_ioctl_get_iftype(name);
if (type == -1) {
fprintf(stderr, "Failed to get type of [%s]\n", name);
continue;
}
if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT)
continue;
memset(&p1, 0, sizeof(p1));
if (do_get_ioctl(name, &p1))
continue;
if ((p->link && p1.link != p->link) ||
(p->name[0] && strcmp(p1.name, p->name)) ||
(p->iph.daddr && p1.iph.daddr != p->iph.daddr) ||
(p->iph.saddr && p1.iph.saddr != p->iph.saddr) ||
(p->i_key && p1.i_key != p->i_key))
continue;
print_tunnel(&p1);
printf("\n");
}
return 0;
}
static int do_show(int argc, char **argv)
{
int err;
struct ip_tunnel_parm p;
if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0)
return -1;
switch (p.iph.protocol) {
case IPPROTO_IPIP:
err = do_get_ioctl(p.name[0] ? p.name : "tunl0", &p);
break;
case IPPROTO_GRE:
err = do_get_ioctl(p.name[0] ? p.name : "gre0", &p);
break;
case IPPROTO_IPV6:
err = do_get_ioctl(p.name[0] ? p.name : "sit0", &p);
break;
default:
do_tunnels_list(&p);
return 0;
}
if (err)
return -1;
print_tunnel(&p);
printf("\n");
return 0;
}
int do_iptunnel(int argc, char **argv)
{
if (argc > 0) {
if (matches(*argv, "add") == 0)
return do_add(SIOCADDTUNNEL, argc-1, argv+1);
if (matches(*argv, "change") == 0)
return do_add(SIOCCHGTUNNEL, argc-1, argv+1);
if (matches(*argv, "del") == 0)
return do_del(argc-1, argv+1);
if (matches(*argv, "show") == 0 ||
matches(*argv, "lst") == 0 ||
matches(*argv, "list") == 0)
return do_show(argc-1, argv+1);
} else
return do_show(0, NULL);
fprintf(stderr, "Command \"%s\" is unknown, try \"ip tunnel help\".\n", *argv);
exit(-1);
}

View File

@ -0,0 +1,521 @@
/*
* libnetlink.c RTnetlink service routines.
*
* 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 <net/if_arp.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/uio.h>
#include "libnetlink.h"
void rtnl_close(struct rtnl_handle *rth)
{
close(rth->fd);
}
int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
{
int addr_len;
memset(rth, 0, sizeof(rth));
rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (rth->fd < 0) {
perror("Cannot open netlink socket");
return -1;
}
memset(&rth->local, 0, sizeof(rth->local));
rth->local.nl_family = AF_NETLINK;
rth->local.nl_groups = subscriptions;
if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
perror("Cannot bind netlink socket");
return -1;
}
addr_len = sizeof(rth->local);
if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) {
perror("Cannot getsockname");
return -1;
}
if (addr_len != sizeof(rth->local)) {
fprintf(stderr, "Wrong address length %d\n", addr_len);
return -1;
}
if (rth->local.nl_family != AF_NETLINK) {
fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
return -1;
}
rth->seq = time(NULL);
return 0;
}
int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
{
struct {
struct nlmsghdr nlh;
struct rtgenmsg g;
} req;
struct sockaddr_nl nladdr;
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
req.nlh.nlmsg_len = sizeof(req);
req.nlh.nlmsg_type = type;
req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
req.nlh.nlmsg_pid = 0;
req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
req.g.rtgen_family = family;
return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
}
int rtnl_send(struct rtnl_handle *rth, char *buf, int len)
{
struct sockaddr_nl nladdr;
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
return sendto(rth->fd, buf, len, 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
}
int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
{
struct nlmsghdr nlh;
struct sockaddr_nl nladdr;
struct iovec iov[2] = { { &nlh, sizeof(nlh) }, { req, len } };
struct msghdr msg = {
(void*)&nladdr, sizeof(nladdr),
iov, 2,
NULL, 0,
0
};
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
nlh.nlmsg_len = NLMSG_LENGTH(len);
nlh.nlmsg_type = type;
nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
nlh.nlmsg_pid = 0;
nlh.nlmsg_seq = rth->dump = ++rth->seq;
return sendmsg(rth->fd, &msg, 0);
}
int rtnl_dump_filter(struct rtnl_handle *rth,
int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
void *arg1,
int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
void *arg2)
{
char buf[8192];
struct sockaddr_nl nladdr;
struct iovec iov = { buf, sizeof(buf) };
while (1) {
int status;
struct nlmsghdr *h;
struct msghdr msg = {
(void*)&nladdr, sizeof(nladdr),
&iov, 1,
NULL, 0,
0
};
status = recvmsg(rth->fd, &msg, 0);
if (status < 0) {
if (errno == EINTR)
continue;
perror("OVERRUN");
continue;
}
if (status == 0) {
fprintf(stderr, "EOF on netlink\n");
return -1;
}
if (msg.msg_namelen != sizeof(nladdr)) {
fprintf(stderr, "sender address length == %d\n", msg.msg_namelen);
exit(1);
}
h = (struct nlmsghdr*)buf;
while (NLMSG_OK(h, status)) {
int err;
if (h->nlmsg_pid != rth->local.nl_pid ||
h->nlmsg_seq != rth->dump) {
if (junk) {
err = junk(&nladdr, h, arg2);
if (err < 0)
return err;
}
goto skip_it;
}
if (h->nlmsg_type == NLMSG_DONE)
return 0;
if (h->nlmsg_type == NLMSG_ERROR) {
struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
fprintf(stderr, "ERROR truncated\n");
} else {
errno = -err->error;
perror("RTNETLINK answers");
}
return -1;
}
err = filter(&nladdr, h, arg1);
if (err < 0)
return err;
skip_it:
h = NLMSG_NEXT(h, status);
}
if (msg.msg_flags & MSG_TRUNC) {
fprintf(stderr, "Message truncated\n");
continue;
}
if (status) {
fprintf(stderr, "!!!Remnant of size %d\n", status);
exit(1);
}
}
}
int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
unsigned groups, struct nlmsghdr *answer,
int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
void *jarg)
{
int status;
unsigned seq;
struct nlmsghdr *h;
struct sockaddr_nl nladdr;
struct iovec iov = { (void*)n, n->nlmsg_len };
char buf[8192];
struct msghdr msg = {
(void*)&nladdr, sizeof(nladdr),
&iov, 1,
NULL, 0,
0
};
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = peer;
nladdr.nl_groups = groups;
n->nlmsg_seq = seq = ++rtnl->seq;
if (answer == NULL)
n->nlmsg_flags |= NLM_F_ACK;
status = sendmsg(rtnl->fd, &msg, 0);
if (status < 0) {
perror("Cannot talk to rtnetlink");
return -1;
}
iov.iov_base = buf;
while (1) {
iov.iov_len = sizeof(buf);
status = recvmsg(rtnl->fd, &msg, 0);
if (status < 0) {
if (errno == EINTR)
continue;
perror("OVERRUN");
continue;
}
if (status == 0) {
fprintf(stderr, "EOF on netlink\n");
return -1;
}
if (msg.msg_namelen != sizeof(nladdr)) {
fprintf(stderr, "sender address length == %d\n", msg.msg_namelen);
exit(1);
}
for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
int err;
int len = h->nlmsg_len;
int l = len - sizeof(*h);
if (l<0 || len>status) {
if (msg.msg_flags & MSG_TRUNC) {
fprintf(stderr, "Truncated message\n");
return -1;
}
fprintf(stderr, "!!!malformed message: len=%d\n", len);
exit(1);
}
if (h->nlmsg_pid != rtnl->local.nl_pid ||
h->nlmsg_seq != seq) {
if (junk) {
err = junk(&nladdr, h, jarg);
if (err < 0)
return err;
}
continue;
}
if (h->nlmsg_type == NLMSG_ERROR) {
struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
if (l < sizeof(struct nlmsgerr)) {
fprintf(stderr, "ERROR truncated\n");
} else {
errno = -err->error;
if (errno == 0) {
if (answer)
memcpy(answer, h, h->nlmsg_len);
return 0;
}
perror("RTNETLINK answers");
}
return -1;
}
if (answer) {
memcpy(answer, h, h->nlmsg_len);
return 0;
}
fprintf(stderr, "Unexpected reply!!!\n");
status -= NLMSG_ALIGN(len);
h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
}
if (msg.msg_flags & MSG_TRUNC) {
fprintf(stderr, "Message truncated\n");
continue;
}
if (status) {
fprintf(stderr, "!!!Remnant of size %d\n", status);
exit(1);
}
}
}
int rtnl_listen(struct rtnl_handle *rtnl,
int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
void *jarg)
{
int status;
struct nlmsghdr *h;
struct sockaddr_nl nladdr;
struct iovec iov;
char buf[8192];
struct msghdr msg = {
(void*)&nladdr, sizeof(nladdr),
&iov, 1,
NULL, 0,
0
};
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = 0;
nladdr.nl_groups = 0;
iov.iov_base = buf;
while (1) {
iov.iov_len = sizeof(buf);
status = recvmsg(rtnl->fd, &msg, 0);
if (status < 0) {
if (errno == EINTR)
continue;
perror("OVERRUN");
continue;
}
if (status == 0) {
fprintf(stderr, "EOF on netlink\n");
return -1;
}
if (msg.msg_namelen != sizeof(nladdr)) {
fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen);
exit(1);
}
for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
int err;
int len = h->nlmsg_len;
int l = len - sizeof(*h);
if (l<0 || len>status) {
if (msg.msg_flags & MSG_TRUNC) {
fprintf(stderr, "Truncated message\n");
return -1;
}
fprintf(stderr, "!!!malformed message: len=%d\n", len);
exit(1);
}
err = handler(&nladdr, h, jarg);
if (err < 0)
return err;
status -= NLMSG_ALIGN(len);
h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
}
if (msg.msg_flags & MSG_TRUNC) {
fprintf(stderr, "Message truncated\n");
continue;
}
if (status) {
fprintf(stderr, "!!!Remnant of size %d\n", status);
exit(1);
}
}
}
int rtnl_from_file(FILE *rtnl,
int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
void *jarg)
{
int status;
struct sockaddr_nl nladdr;
char buf[8192];
struct nlmsghdr *h = (void*)buf;
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = 0;
nladdr.nl_groups = 0;
while (1) {
int err, len, type;
int l;
status = fread(&buf, 1, sizeof(*h), rtnl);
if (status < 0) {
if (errno == EINTR)
continue;
perror("rtnl_from_file: fread");
return -1;
}
if (status == 0)
return 0;
len = h->nlmsg_len;
type= h->nlmsg_type;
l = len - sizeof(*h);
if (l<0 || len>sizeof(buf)) {
fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
len, ftell(rtnl));
return -1;
}
status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
if (status < 0) {
perror("rtnl_from_file: fread");
return -1;
}
if (status < l) {
fprintf(stderr, "rtnl-from_file: truncated message\n");
return -1;
}
err = handler(&nladdr, h, jarg);
if (err < 0)
return err;
}
}
int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
{
int len = RTA_LENGTH(4);
struct rtattr *rta;
if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
return -1;
rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
rta->rta_type = type;
rta->rta_len = len;
memcpy(RTA_DATA(rta), &data, 4);
n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
return 0;
}
int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
{
int len = RTA_LENGTH(alen);
struct rtattr *rta;
if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
return -1;
rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
rta->rta_type = type;
rta->rta_len = len;
memcpy(RTA_DATA(rta), data, alen);
n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
return 0;
}
int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
{
int len = RTA_LENGTH(4);
struct rtattr *subrta;
if (RTA_ALIGN(rta->rta_len) + len > maxlen)
return -1;
subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
subrta->rta_type = type;
subrta->rta_len = len;
memcpy(RTA_DATA(subrta), &data, 4);
rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
return 0;
}
int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen)
{
struct rtattr *subrta;
int len = RTA_LENGTH(alen);
if (RTA_ALIGN(rta->rta_len) + len > maxlen)
return -1;
subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
subrta->rta_type = type;
subrta->rta_len = len;
memcpy(RTA_DATA(subrta), data, alen);
rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
return 0;
}
int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
{
while (RTA_OK(rta, len)) {
if (rta->rta_type <= max)
tb[rta->rta_type] = rta;
rta = RTA_NEXT(rta,len);
}
if (len)
fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
return 0;
}

View File

@ -0,0 +1,46 @@
#ifndef __LIBNETLINK_H__
#define __LIBNETLINK_H__ 1
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
struct rtnl_handle
{
int fd;
struct sockaddr_nl local;
struct sockaddr_nl peer;
__u32 seq;
__u32 dump;
};
extern int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions);
extern void rtnl_close(struct rtnl_handle *rth);
extern int rtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type);
extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len);
extern int rtnl_dump_filter(struct rtnl_handle *rth,
int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
void *arg1,
int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
void *arg2);
extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
unsigned groups, struct nlmsghdr *answer,
int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
void *jarg);
extern int rtnl_send(struct rtnl_handle *rth, char *buf, int);
extern int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data);
extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen);
extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data);
extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen);
extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len);
extern int rtnl_listen(struct rtnl_handle *, int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
void *jarg);
extern int rtnl_from_file(FILE *, int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
void *jarg);
#endif /* __LIBNETLINK_H__ */

View File

@ -0,0 +1,413 @@
#ifndef __LINUX_PKT_SCHED_H
#define __LINUX_PKT_SCHED_H
/* Logical priority bands not depending on specific packet scheduler.
Every scheduler will map them to real traffic classes, if it has
no more precise mechanism to classify packets.
These numbers have no special meaning, though their coincidence
with obsolete IPv6 values is not occasional :-). New IPv6 drafts
preferred full anarchy inspired by diffserv group.
Note: TC_PRIO_BESTEFFORT does not mean that it is the most unhappy
class, actually, as rule it will be handled with more care than
filler or even bulk.
*/
#include <asm/types.h>
#define TC_PRIO_BESTEFFORT 0
#define TC_PRIO_FILLER 1
#define TC_PRIO_BULK 2
#define TC_PRIO_INTERACTIVE_BULK 4
#define TC_PRIO_INTERACTIVE 6
#define TC_PRIO_CONTROL 7
#define TC_PRIO_MAX 15
/* Generic queue statistics, available for all the elements.
Particular schedulers may have also their private records.
*/
struct tc_stats
{
__u64 bytes; /* NUmber of enqueues bytes */
__u32 packets; /* Number of enqueued packets */
__u32 drops; /* Packets dropped because of lack of resources */
__u32 overlimits; /* Number of throttle events when this
* flow goes out of allocated bandwidth */
__u32 bps; /* Current flow byte rate */
__u32 pps; /* Current flow packet rate */
__u32 qlen;
__u32 backlog;
#ifdef __KERNEL__
spinlock_t *lock;
#endif
};
struct tc_estimator
{
char interval;
unsigned char ewma_log;
};
/* "Handles"
---------
All the traffic control objects have 32bit identifiers, or "handles".
They can be considered as opaque numbers from user API viewpoint,
but actually they always consist of two fields: major and
minor numbers, which are interpreted by kernel specially,
that may be used by applications, though not recommended.
F.e. qdisc handles always have minor number equal to zero,
classes (or flows) have major equal to parent qdisc major, and
minor uniquely identifying class inside qdisc.
Macros to manipulate handles:
*/
#define TC_H_MAJ_MASK (0xFFFF0000U)
#define TC_H_MIN_MASK (0x0000FFFFU)
#define TC_H_MAJ(h) ((h)&TC_H_MAJ_MASK)
#define TC_H_MIN(h) ((h)&TC_H_MIN_MASK)
#define TC_H_MAKE(maj,min) (((maj)&TC_H_MAJ_MASK)|((min)&TC_H_MIN_MASK))
#define TC_H_UNSPEC (0U)
#define TC_H_ROOT (0xFFFFFFFFU)
#define TC_H_INGRESS (0xFFFFFFF1U)
struct tc_ratespec
{
unsigned char cell_log;
unsigned char __reserved;
unsigned short feature;
short addend;
unsigned short mpu;
__u32 rate;
};
/* FIFO section */
struct tc_fifo_qopt
{
__u32 limit; /* Queue length: bytes for bfifo, packets for pfifo */
};
/* PRIO section */
#define TCQ_PRIO_BANDS 16
struct tc_prio_qopt
{
int bands; /* Number of bands */
__u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */
};
/* CSZ section */
struct tc_csz_qopt
{
int flows; /* Maximal number of guaranteed flows */
unsigned char R_log; /* Fixed point position for round number */
unsigned char delta_log; /* Log of maximal managed time interval */
__u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> CSZ band */
};
struct tc_csz_copt
{
struct tc_ratespec slice;
struct tc_ratespec rate;
struct tc_ratespec peakrate;
__u32 limit;
__u32 buffer;
__u32 mtu;
};
enum
{
TCA_CSZ_UNSPEC,
TCA_CSZ_PARMS,
TCA_CSZ_RTAB,
TCA_CSZ_PTAB,
};
/* TBF section */
struct tc_tbf_qopt
{
struct tc_ratespec rate;
struct tc_ratespec peakrate;
__u32 limit;
__u32 buffer;
__u32 mtu;
};
enum
{
TCA_TBF_UNSPEC,
TCA_TBF_PARMS,
TCA_TBF_RTAB,
TCA_TBF_PTAB,
};
/* TEQL section */
/* TEQL does not require any parameters */
/* SFQ section */
struct tc_sfq_qopt
{
unsigned quantum; /* Bytes per round allocated to flow */
int perturb_period; /* Period of hash perturbation */
__u32 limit; /* Maximal packets in queue */
unsigned divisor; /* Hash divisor */
unsigned flows; /* Maximal number of flows */
};
/*
* NOTE: limit, divisor and flows are hardwired to code at the moment.
*
* limit=flows=128, divisor=1024;
*
* The only reason for this is efficiency, it is possible
* to change these parameters in compile time.
*/
/* RED section */
enum
{
TCA_RED_UNSPEC,
TCA_RED_PARMS,
TCA_RED_STAB,
};
struct tc_red_qopt
{
__u32 limit; /* HARD maximal queue length (bytes) */
__u32 qth_min; /* Min average length threshold (bytes) */
__u32 qth_max; /* Max average length threshold (bytes) */
unsigned char Wlog; /* log(W) */
unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */
unsigned char Scell_log; /* cell size for idle damping */
unsigned char flags;
#define TC_RED_ECN 1
};
struct tc_red_xstats
{
__u32 early; /* Early drops */
__u32 pdrop; /* Drops due to queue limits */
__u32 other; /* Drops due to drop() calls */
__u32 marked; /* Marked packets */
};
/* GRED section */
#define MAX_DPs 16
enum
{
TCA_GRED_UNSPEC,
TCA_GRED_PARMS,
TCA_GRED_STAB,
TCA_GRED_DPS,
};
#define TCA_SET_OFF TCA_GRED_PARMS
struct tc_gred_qopt
{
__u32 limit; /* HARD maximal queue length (bytes)
*/
__u32 qth_min; /* Min average length threshold (bytes)
*/
__u32 qth_max; /* Max average length threshold (bytes)
*/
__u32 DP; /* upto 2^32 DPs */
__u32 backlog;
__u32 qave;
__u32 forced;
__u32 early;
__u32 other;
__u32 pdrop;
unsigned char Wlog; /* log(W) */
unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */
unsigned char Scell_log; /* cell size for idle damping */
__u8 prio; /* prio of this VQ */
__u32 packets;
__u32 bytesin;
};
/* gred setup */
struct tc_gred_sopt
{
__u32 DPs;
__u32 def_DP;
__u8 grio;
};
/* HTB section */
#define TC_HTB_NUMPRIO 4
#define TC_HTB_MAXDEPTH 4
struct tc_htb_opt
{
struct tc_ratespec rate;
struct tc_ratespec ceil;
__u32 buffer;
__u32 cbuffer;
__u32 quantum; /* out only */
__u32 level; /* out only */
__u8 prio;
__u8 injectd; /* inject class distance */
__u8 pad[2];
};
struct tc_htb_glob
{
__u32 rate2quantum; /* bps->quantum divisor */
__u32 defcls; /* default class number */
__u32 use_dcache; /* use dequeue cache ? */
__u32 debug; /* debug flags */
/* stats */
__u32 deq_rate; /* dequeue rate */
__u32 utilz; /* dequeue utilization */
__u32 trials; /* deq_prio trials per dequeue */
__u32 dcache_hits;
__u32 direct_pkts; /* count of non shapped packets */
};
enum
{
TCA_HTB_UNSPEC,
TCA_HTB_PARMS,
TCA_HTB_INIT,
TCA_HTB_CTAB,
TCA_HTB_RTAB,
};
struct tc_htb_xstats
{
__u32 lends;
__u32 borrows;
__u32 giants; /* too big packets (rate will not be accurate) */
__u32 injects; /* how many times leaf used injected bw */
__u32 tokens;
__u32 ctokens;
};
/* CBQ section */
#define TC_CBQ_MAXPRIO 8
#define TC_CBQ_MAXLEVEL 8
#define TC_CBQ_DEF_EWMA 5
struct tc_cbq_lssopt
{
unsigned char change;
unsigned char flags;
#define TCF_CBQ_LSS_BOUNDED 1
#define TCF_CBQ_LSS_ISOLATED 2
unsigned char ewma_log;
unsigned char level;
#define TCF_CBQ_LSS_FLAGS 1
#define TCF_CBQ_LSS_EWMA 2
#define TCF_CBQ_LSS_MAXIDLE 4
#define TCF_CBQ_LSS_MINIDLE 8
#define TCF_CBQ_LSS_OFFTIME 0x10
#define TCF_CBQ_LSS_AVPKT 0x20
__u32 maxidle;
__u32 minidle;
__u32 offtime;
__u32 avpkt;
};
struct tc_cbq_wrropt
{
unsigned char flags;
unsigned char priority;
unsigned char cpriority;
unsigned char __reserved;
__u32 allot;
__u32 weight;
};
struct tc_cbq_ovl
{
unsigned char strategy;
#define TC_CBQ_OVL_CLASSIC 0
#define TC_CBQ_OVL_DELAY 1
#define TC_CBQ_OVL_LOWPRIO 2
#define TC_CBQ_OVL_DROP 3
#define TC_CBQ_OVL_RCLASSIC 4
unsigned char priority2;
__u32 penalty;
};
struct tc_cbq_police
{
unsigned char police;
unsigned char __res1;
unsigned short __res2;
};
struct tc_cbq_fopt
{
__u32 split;
__u32 defmap;
__u32 defchange;
};
struct tc_cbq_xstats
{
__u32 borrows;
__u32 overactions;
__s32 avgidle;
__s32 undertime;
};
enum
{
TCA_CBQ_UNSPEC,
TCA_CBQ_LSSOPT,
TCA_CBQ_WRROPT,
TCA_CBQ_FOPT,
TCA_CBQ_OVL_STRATEGY,
TCA_CBQ_RATE,
TCA_CBQ_RTAB,
TCA_CBQ_POLICE,
};
#define TCA_CBQ_MAX TCA_CBQ_POLICE
/* dsmark section */
enum {
TCA_DSMARK_UNSPEC,
TCA_DSMARK_INDICES,
TCA_DSMARK_DEFAULT_INDEX,
TCA_DSMARK_SET_TC_INDEX,
TCA_DSMARK_MASK,
TCA_DSMARK_VALUE
};
#define TCA_DSMARK_MAX TCA_DSMARK_VALUE
/* ATM section */
enum {
TCA_ATM_UNSPEC,
TCA_ATM_FD, /* file/socket descriptor */
TCA_ATM_PTR, /* pointer to descriptor - later */
TCA_ATM_HDR, /* LL header */
TCA_ATM_EXCESS, /* excess traffic class (0 for CLP) */
TCA_ATM_ADDR, /* PVC address (for output only) */
TCA_ATM_STATE /* VC state (ATM_VS_*; for output only) */
};
#define TCA_ATM_MAX TCA_ATM_STATE
#endif

View File

@ -0,0 +1,92 @@
/*
* ll_addr.c
*
* 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 <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/sockios.h>
#include "utils.h"
const char *ll_addr_n2a(unsigned char *addr, int alen, int type, char *buf, int blen)
{
int i;
int l;
if (alen == 4 &&
(type == ARPHRD_TUNNEL || type == ARPHRD_SIT || type == ARPHRD_IPGRE)) {
return inet_ntop(AF_INET, addr, buf, blen);
}
l = 0;
for (i=0; i<alen; i++) {
if (i==0) {
snprintf(buf+l, blen, "%02x", addr[i]);
blen -= 2;
l += 2;
} else {
snprintf(buf+l, blen, ":%02x", addr[i]);
blen -= 3;
l += 3;
}
}
return buf;
}
int ll_addr_a2n(unsigned char *lladdr, int len, char *arg)
{
if (strchr(arg, '.')) {
inet_prefix pfx;
if (get_addr_1(&pfx, arg, AF_INET)) {
fprintf(stderr, "\"%s\" is invalid lladdr.\n", arg);
return -1;
}
if (len < 4)
return -1;
memcpy(lladdr, pfx.data, 4);
return 4;
} else {
int i;
for (i=0; i<len; i++) {
int temp;
char *cp = strchr(arg, ':');
if (cp) {
*cp = 0;
cp++;
}
if (sscanf(arg, "%x", &temp) != 1) {
fprintf(stderr, "\"%s\" is invalid lladdr.\n", arg);
return -1;
}
if (temp < 0 || temp > 255) {
fprintf(stderr, "\"%s\" is invalid lladdr.\n", arg);
return -1;
}
lladdr[i] = temp;
if (!cp)
break;
arg = cp;
}
return i+1;
}
}

View File

@ -0,0 +1,169 @@
/*
* ll_map.c
*
* 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/socket.h>
#include <netinet/in.h>
#include <string.h>
#include "libnetlink.h"
#include "ll_map.h"
struct idxmap
{
struct idxmap * next;
int index;
int type;
int alen;
unsigned flags;
unsigned char addr[8];
char name[16];
};
static struct idxmap *idxmap[16];
int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
int h;
struct ifinfomsg *ifi = NLMSG_DATA(n);
struct idxmap *im, **imp;
struct rtattr *tb[IFLA_MAX+1];
if (n->nlmsg_type != RTM_NEWLINK)
return 0;
if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi)))
return -1;
memset(tb, 0, sizeof(tb));
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
if (tb[IFLA_IFNAME] == NULL)
return 0;
h = ifi->ifi_index&0xF;
for (imp=&idxmap[h]; (im=*imp)!=NULL; imp = &im->next)
if (im->index == ifi->ifi_index)
break;
if (im == NULL) {
im = malloc(sizeof(*im));
if (im == NULL)
return 0;
im->next = *imp;
im->index = ifi->ifi_index;
*imp = im;
}
im->type = ifi->ifi_type;
im->flags = ifi->ifi_flags;
if (tb[IFLA_ADDRESS]) {
int alen;
im->alen = alen = RTA_PAYLOAD(tb[IFLA_ADDRESS]);
if (alen > sizeof(im->addr))
alen = sizeof(im->addr);
memcpy(im->addr, RTA_DATA(tb[IFLA_ADDRESS]), alen);
} else {
im->alen = 0;
memset(im->addr, 0, sizeof(im->addr));
}
strcpy(im->name, RTA_DATA(tb[IFLA_IFNAME]));
return 0;
}
const char *ll_idx_n2a(int idx, char *buf)
{
struct idxmap *im;
if (idx == 0)
return "*";
for (im = idxmap[idx&0xF]; im; im = im->next)
if (im->index == idx)
return im->name;
snprintf(buf, 16, "if%d", idx);
return buf;
}
const char *ll_index_to_name(int idx)
{
static char nbuf[16];
return ll_idx_n2a(idx, nbuf);
}
int ll_index_to_type(int idx)
{
struct idxmap *im;
if (idx == 0)
return -1;
for (im = idxmap[idx&0xF]; im; im = im->next)
if (im->index == idx)
return im->type;
return -1;
}
unsigned ll_index_to_flags(int idx)
{
struct idxmap *im;
if (idx == 0)
return 0;
for (im = idxmap[idx&0xF]; im; im = im->next)
if (im->index == idx)
return im->flags;
return 0;
}
int ll_name_to_index(char *name)
{
static char ncache[16];
static int icache;
struct idxmap *im;
int i;
if (name == NULL)
return 0;
if (icache && strcmp(name, ncache) == 0)
return icache;
for (i=0; i<16; i++) {
for (im = idxmap[i]; im; im = im->next) {
if (strcmp(im->name, name) == 0) {
icache = im->index;
strcpy(ncache, name);
return im->index;
}
}
}
return 0;
}
int ll_init_map(struct rtnl_handle *rth)
{
if (rtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK) < 0) {
perror("Cannot send dump request");
exit(1);
}
if (rtnl_dump_filter(rth, ll_remember_index, &idxmap, NULL, NULL) < 0) {
fprintf(stderr, "Dump terminated\n");
exit(1);
}
return 0;
}

View File

@ -0,0 +1,12 @@
#ifndef __LL_MAP_H__
#define __LL_MAP_H__ 1
extern int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
extern int ll_init_map(struct rtnl_handle *rth);
extern int ll_name_to_index(char *name);
extern const char *ll_index_to_name(int idx);
extern const char *ll_idx_n2a(int idx, char *buf);
extern int ll_index_to_type(int idx);
extern unsigned ll_index_to_flags(int idx);
#endif /* __LL_MAP_H__ */

View File

@ -0,0 +1,118 @@
/*
* ll_proto.c
*
* 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 <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/sockios.h>
#include "utils.h"
#define __PF(f,n) { ETH_P_##f, #n },
static struct {
int id;
char *name;
} llproto_names[] = {
__PF(LOOP,loop)
__PF(PUP,pup)
#ifdef ETH_P_PUPAT
__PF(PUPAT,pupat)
#endif
__PF(IP,ip)
__PF(X25,x25)
__PF(ARP,arp)
__PF(BPQ,bpq)
#ifdef ETH_P_IEEEPUP
__PF(IEEEPUP,ieeepup)
#endif
#ifdef ETH_P_IEEEPUPAT
__PF(IEEEPUPAT,ieeepupat)
#endif
__PF(DEC,dec)
__PF(DNA_DL,dna_dl)
__PF(DNA_RC,dna_rc)
__PF(DNA_RT,dna_rt)
__PF(LAT,lat)
__PF(DIAG,diag)
__PF(CUST,cust)
__PF(SCA,sca)
__PF(RARP,rarp)
__PF(ATALK,atalk)
__PF(AARP,aarp)
__PF(IPX,ipx)
__PF(IPV6,ipv6)
__PF(PPP_DISC,ppp_disc)
__PF(PPP_SES,ppp_ses)
__PF(ATMMPOA,atmmpoa)
__PF(ATMFATE,atmfate)
__PF(802_3,802_3)
__PF(AX25,ax25)
__PF(ALL,all)
__PF(802_2,802_2)
__PF(SNAP,snap)
__PF(DDCMP,ddcmp)
__PF(WAN_PPP,wan_ppp)
__PF(PPP_MP,ppp_mp)
__PF(LOCALTALK,localtalk)
__PF(PPPTALK,ppptalk)
__PF(TR_802_2,tr_802_2)
__PF(MOBITEX,mobitex)
__PF(CONTROL,control)
__PF(IRDA,irda)
__PF(ECONET,econet)
{ 0x8100, "802.1Q" },
{ ETH_P_IP, "ipv4" },
};
#undef __PF
char * ll_proto_n2a(unsigned short id, char *buf, int len)
{
int i;
id = ntohs(id);
for (i=0; i<sizeof(llproto_names)/sizeof(llproto_names[0]); i++) {
if (llproto_names[i].id == id)
return llproto_names[i].name;
}
snprintf(buf, len, "[%d]", id);
return buf;
}
int ll_proto_a2n(unsigned short *id, char *buf)
{
int i;
for (i=0; i<sizeof(llproto_names)/sizeof(llproto_names[0]); i++) {
if (strcasecmp(llproto_names[i].name, buf) == 0) {
*id = htons(llproto_names[i].id);
return 0;
}
}
if (get_u16(id, buf, 0))
return -1;
*id = htons(*id);
return 0;
}

View File

@ -0,0 +1,121 @@
/*
* ll_types.c
*
* 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 <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/sockios.h>
char * ll_type_n2a(int type, char *buf, int len)
{
#define __PF(f,n) { ARPHRD_##f, #n },
static struct {
int type;
char *name;
} arphrd_names[] = {
{ 0, "generic" },
__PF(ETHER,ether)
__PF(EETHER,eether)
__PF(AX25,ax25)
__PF(PRONET,pronet)
__PF(CHAOS,chaos)
#ifdef ARPHRD_IEEE802_TR
__PF(IEEE802,ieee802)
#else
__PF(IEEE802,tr)
#endif
__PF(ARCNET,arcnet)
__PF(APPLETLK,atalk)
__PF(DLCI,dlci)
__PF(ATM,atm)
__PF(METRICOM,metricom)
#ifdef ARPHRD_IEEE1394
__PF(IEEE1394,ieee1394)
#endif
__PF(SLIP,slip)
__PF(CSLIP,cslip)
__PF(SLIP6,slip6)
__PF(CSLIP6,cslip6)
__PF(RSRVD,rsrvd)
__PF(ADAPT,adapt)
__PF(ROSE,rose)
__PF(X25,x25)
__PF(HWX25,hwx25)
__PF(PPP,ppp)
__PF(HDLC,hdlc)
__PF(LAPB,lapb)
__PF(DDCMP,ddcmp)
__PF(RAWHDLC,rawhdlc)
__PF(TUNNEL,ipip)
__PF(TUNNEL6,tunnel6)
__PF(FRAD,frad)
__PF(SKIP,skip)
__PF(LOOPBACK,loopback)
__PF(LOCALTLK,ltalk)
__PF(FDDI,fddi)
__PF(BIF,bif)
__PF(SIT,sit)
__PF(IPDDP,ip/ddp)
__PF(IPGRE,gre)
__PF(PIMREG,pimreg)
__PF(HIPPI,hippi)
__PF(ASH,ash)
__PF(ECONET,econet)
__PF(IRDA,irda)
__PF(FCPP,fcpp)
__PF(FCAL,fcal)
__PF(FCPL,fcpl)
__PF(FCFABRIC,fcfb0)
__PF(FCFABRIC+1,fcfb1)
__PF(FCFABRIC+2,fcfb2)
__PF(FCFABRIC+3,fcfb3)
__PF(FCFABRIC+4,fcfb4)
__PF(FCFABRIC+5,fcfb5)
__PF(FCFABRIC+6,fcfb6)
__PF(FCFABRIC+7,fcfb7)
__PF(FCFABRIC+8,fcfb8)
__PF(FCFABRIC+9,fcfb9)
__PF(FCFABRIC+10,fcfb10)
__PF(FCFABRIC+11,fcfb11)
__PF(FCFABRIC+12,fcfb12)
#ifdef ARPHRD_IEEE802_TR
__PF(IEEE802_TR,tr)
#endif
#ifdef ARPHRD_IEEE80211
__PF(IEEE80211,ieee802.11)
#endif
#ifdef ARPHRD_VOID
__PF(VOID,void)
#endif
};
#undef __PF
int i;
for (i=0; i<sizeof(arphrd_names)/sizeof(arphrd_names[0]); i++) {
if (arphrd_names[i].type == type)
return arphrd_names[i].name;
}
snprintf(buf, len, "[%d]", type);
return buf;
}

View File

@ -0,0 +1,389 @@
/*
* rt_names.c rtnetlink names DB.
*
* 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 <string.h>
#include <sys/time.h>
#include <stdint.h>
static void rtnl_tab_initialize(char *file, char **tab, int size)
{
char buf[512];
FILE *fp;
fp = fopen(file, "r");
if (!fp)
return;
while (fgets(buf, sizeof(buf), fp)) {
char *p = buf;
int id;
char namebuf[512];
while (*p == ' ' || *p == '\t')
p++;
if (*p == '#' || *p == '\n' || *p == 0)
continue;
if (sscanf(p, "0x%x %s\n", &id, namebuf) != 2 &&
sscanf(p, "0x%x %s #", &id, namebuf) != 2 &&
sscanf(p, "%d %s\n", &id, namebuf) != 2 &&
sscanf(p, "%d %s #", &id, namebuf) != 2) {
fprintf(stderr, "Database %s is corrupted at %s\n",
file, p);
return;
}
if (id<0 || id>size)
continue;
tab[id] = strdup(namebuf);
}
fclose(fp);
}
static char * rtnl_rtprot_tab[256] = {
"none",
"redirect",
"kernel",
"boot",
"static",
NULL,
NULL,
NULL,
"gated",
"ra",
"mrt",
"zebra",
"bird",
};
static int rtnl_rtprot_init;
static void rtnl_rtprot_initialize(void)
{
rtnl_rtprot_init = 1;
rtnl_tab_initialize("/etc/iproute2/rt_protos",
rtnl_rtprot_tab, 256);
}
char * rtnl_rtprot_n2a(int id, char *buf, int len)
{
if (id<0 || id>=256) {
snprintf(buf, len, "%d", id);
return buf;
}
if (!rtnl_rtprot_tab[id]) {
if (!rtnl_rtprot_init)
rtnl_rtprot_initialize();
}
if (rtnl_rtprot_tab[id])
return rtnl_rtprot_tab[id];
snprintf(buf, len, "%d", id);
return buf;
}
int rtnl_rtprot_a2n(uint32_t *id, char *arg)
{
static char *cache = NULL;
static unsigned long res;
char *end;
int i;
if (cache && strcmp(cache, arg) == 0) {
*id = res;
return 0;
}
if (!rtnl_rtprot_init)
rtnl_rtprot_initialize();
for (i=0; i<256; i++) {
if (rtnl_rtprot_tab[i] &&
strcmp(rtnl_rtprot_tab[i], arg) == 0) {
cache = rtnl_rtprot_tab[i];
res = i;
*id = res;
return 0;
}
}
res = strtoul(arg, &end, 0);
if (!end || end == arg || *end || res > 255)
return -1;
*id = res;
return 0;
}
static char * rtnl_rtscope_tab[256] = {
"global",
};
static int rtnl_rtscope_init;
static void rtnl_rtscope_initialize(void)
{
rtnl_rtscope_init = 1;
rtnl_rtscope_tab[255] = "nowhere";
rtnl_rtscope_tab[254] = "host";
rtnl_rtscope_tab[253] = "link";
rtnl_rtscope_tab[200] = "site";
rtnl_tab_initialize("/etc/iproute2/rt_scopes",
rtnl_rtscope_tab, 256);
}
char * rtnl_rtscope_n2a(int id, char *buf, int len)
{
if (id<0 || id>=256) {
snprintf(buf, len, "%d", id);
return buf;
}
if (!rtnl_rtscope_tab[id]) {
if (!rtnl_rtscope_init)
rtnl_rtscope_initialize();
}
if (rtnl_rtscope_tab[id])
return rtnl_rtscope_tab[id];
snprintf(buf, len, "%d", id);
return buf;
}
int rtnl_rtscope_a2n(uint32_t *id, char *arg)
{
static char *cache = NULL;
static unsigned long res;
char *end;
int i;
if (cache && strcmp(cache, arg) == 0) {
*id = res;
return 0;
}
if (!rtnl_rtscope_init)
rtnl_rtscope_initialize();
for (i=0; i<256; i++) {
if (rtnl_rtscope_tab[i] &&
strcmp(rtnl_rtscope_tab[i], arg) == 0) {
cache = rtnl_rtscope_tab[i];
res = i;
*id = res;
return 0;
}
}
res = strtoul(arg, &end, 0);
if (!end || end == arg || *end || res > 255)
return -1;
*id = res;
return 0;
}
static char * rtnl_rtrealm_tab[256] = {
"unknown",
};
static int rtnl_rtrealm_init;
static void rtnl_rtrealm_initialize(void)
{
rtnl_rtrealm_init = 1;
rtnl_tab_initialize("/etc/iproute2/rt_realms",
rtnl_rtrealm_tab, 256);
}
char * rtnl_rtrealm_n2a(int id, char *buf, int len)
{
if (id<0 || id>=256) {
snprintf(buf, len, "%d", id);
return buf;
}
if (!rtnl_rtrealm_tab[id]) {
if (!rtnl_rtrealm_init)
rtnl_rtrealm_initialize();
}
if (rtnl_rtrealm_tab[id])
return rtnl_rtrealm_tab[id];
snprintf(buf, len, "%d", id);
return buf;
}
int rtnl_rtrealm_a2n(uint32_t *id, char *arg)
{
static char *cache = NULL;
static unsigned long res;
char *end;
int i;
if (cache && strcmp(cache, arg) == 0) {
*id = res;
return 0;
}
if (!rtnl_rtrealm_init)
rtnl_rtrealm_initialize();
for (i=0; i<256; i++) {
if (rtnl_rtrealm_tab[i] &&
strcmp(rtnl_rtrealm_tab[i], arg) == 0) {
cache = rtnl_rtrealm_tab[i];
res = i;
*id = res;
return 0;
}
}
res = strtoul(arg, &end, 0);
if (!end || end == arg || *end || res > 255)
return -1;
*id = res;
return 0;
}
static char * rtnl_rttable_tab[256] = {
"unspec",
};
static int rtnl_rttable_init;
static void rtnl_rttable_initialize(void)
{
rtnl_rttable_init = 1;
rtnl_rttable_tab[255] = "local";
rtnl_rttable_tab[254] = "main";
rtnl_tab_initialize("/etc/iproute2/rt_tables",
rtnl_rttable_tab, 256);
}
char * rtnl_rttable_n2a(int id, char *buf, int len)
{
if (id<0 || id>=256) {
snprintf(buf, len, "%d", id);
return buf;
}
if (!rtnl_rttable_tab[id]) {
if (!rtnl_rttable_init)
rtnl_rttable_initialize();
}
if (rtnl_rttable_tab[id])
return rtnl_rttable_tab[id];
snprintf(buf, len, "%d", id);
return buf;
}
int rtnl_rttable_a2n(uint32_t *id, char *arg)
{
static char *cache = NULL;
static unsigned long res;
char *end;
int i;
if (cache && strcmp(cache, arg) == 0) {
*id = res;
return 0;
}
if (!rtnl_rttable_init)
rtnl_rttable_initialize();
for (i=0; i<256; i++) {
if (rtnl_rttable_tab[i] &&
strcmp(rtnl_rttable_tab[i], arg) == 0) {
cache = rtnl_rttable_tab[i];
res = i;
*id = res;
return 0;
}
}
i = strtoul(arg, &end, 0);
if (!end || end == arg || *end || i > 255)
return -1;
*id = i;
return 0;
}
static char * rtnl_rtdsfield_tab[256] = {
"0",
};
static int rtnl_rtdsfield_init;
static void rtnl_rtdsfield_initialize(void)
{
rtnl_rtdsfield_init = 1;
rtnl_tab_initialize("/etc/iproute2/rt_dsfield",
rtnl_rtdsfield_tab, 256);
}
char * rtnl_dsfield_n2a(int id, char *buf, int len)
{
if (id<0 || id>=256) {
snprintf(buf, len, "%d", id);
return buf;
}
if (!rtnl_rtdsfield_tab[id]) {
if (!rtnl_rtdsfield_init)
rtnl_rtdsfield_initialize();
}
if (rtnl_rtdsfield_tab[id])
return rtnl_rtdsfield_tab[id];
snprintf(buf, len, "0x%02x", id);
return buf;
}
int rtnl_dsfield_a2n(uint32_t *id, char *arg)
{
static char *cache = NULL;
static unsigned long res;
char *end;
int i;
if (cache && strcmp(cache, arg) == 0) {
*id = res;
return 0;
}
if (!rtnl_rtdsfield_init)
rtnl_rtdsfield_initialize();
for (i=0; i<256; i++) {
if (rtnl_rtdsfield_tab[i] &&
strcmp(rtnl_rtdsfield_tab[i], arg) == 0) {
cache = rtnl_rtdsfield_tab[i];
res = i;
*id = res;
return 0;
}
}
res = strtoul(arg, &end, 16);
if (!end || end == arg || *end || res > 255)
return -1;
*id = res;
return 0;
}

View File

@ -0,0 +1,30 @@
#ifndef RT_NAMES_H_
#define RT_NAMES_H_ 1
#include <stdint.h>
const char* rtnl_rtprot_n2a(int id, char *buf, int len);
const char* rtnl_rtscope_n2a(int id, char *buf, int len);
const char* rtnl_rttable_n2a(int id, char *buf, int len);
const char* rtnl_rtrealm_n2a(int id, char *buf, int len);
const char* rtnl_dsfield_n2a(int id, char *buf, int len);
int rtnl_rtprot_a2n(int *id, char *arg);
int rtnl_rtscope_a2n(int *id, char *arg);
int rtnl_rttable_a2n(int *id, char *arg);
int rtnl_rtrealm_a2n(uint32_t *id, char *arg);
int rtnl_dsfield_a2n(uint32_t *id, char *arg);
const char *inet_proto_n2a(int proto, char *buf, int len);
int inet_proto_a2n(char *buf);
const char * ll_type_n2a(int type, char *buf, int len);
const char *ll_addr_n2a(unsigned char *addr, int alen, int type, char *buf, int blen);
int ll_addr_a2n(unsigned char *lladdr, int len, char *arg);
const char * ll_proto_n2a(unsigned short id, char *buf, int len);
int ll_proto_a2n(unsigned short *id, char *buf);
#endif

View File

@ -0,0 +1,116 @@
/*
* rtm_map.c
*
* 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 <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "rt_names.h"
#include "utils.h"
char *rtnl_rtntype_n2a(int id, char *buf, int len)
{
switch (id) {
case RTN_UNSPEC:
return "none";
case RTN_UNICAST:
return "unicast";
case RTN_LOCAL:
return "local";
case RTN_BROADCAST:
return "broadcast";
case RTN_ANYCAST:
return "anycast";
case RTN_MULTICAST:
return "multicast";
case RTN_BLACKHOLE:
return "blackhole";
case RTN_UNREACHABLE:
return "unreachable";
case RTN_PROHIBIT:
return "prohibit";
case RTN_THROW:
return "throw";
case RTN_NAT:
return "nat";
case RTN_XRESOLVE:
return "xresolve";
default:
snprintf(buf, len, "%d", id);
return buf;
}
}
int rtnl_rtntype_a2n(int *id, char *arg)
{
char *end;
unsigned long res;
if (strcmp(arg, "local") == 0)
res = RTN_LOCAL;
else if (strcmp(arg, "nat") == 0)
res = RTN_NAT;
else if (matches(arg, "broadcast") == 0 ||
strcmp(arg, "brd") == 0)
res = RTN_BROADCAST;
else if (matches(arg, "anycast") == 0)
res = RTN_ANYCAST;
else if (matches(arg, "multicast") == 0)
res = RTN_MULTICAST;
else if (matches(arg, "prohibit") == 0)
res = RTN_PROHIBIT;
else if (matches(arg, "unreachable") == 0)
res = RTN_UNREACHABLE;
else if (matches(arg, "blackhole") == 0)
res = RTN_BLACKHOLE;
else if (matches(arg, "xresolve") == 0)
res = RTN_XRESOLVE;
else if (matches(arg, "unicast") == 0)
res = RTN_UNICAST;
else if (strcmp(arg, "throw") == 0)
res = RTN_THROW;
else {
res = strtoul(arg, &end, 0);
if (!end || end == arg || *end || res > 255)
return -1;
}
*id = res;
return 0;
}
int get_rt_realms(__u32 *realms, char *arg)
{
__u32 realm = 0;
char *p = strchr(arg, '/');
*realms = 0;
if (p) {
*p = 0;
if (rtnl_rtrealm_a2n(realms, arg)) {
*p = '/';
return -1;
}
*realms <<= 16;
*p = '/';
arg = p+1;
}
if (*arg && rtnl_rtrealm_a2n(&realm, arg))
return -1;
*realms |= realm;
return 0;
}

View File

@ -0,0 +1,10 @@
#ifndef __RTM_MAP_H__
#define __RTM_MAP_H__ 1
char *rtnl_rtntype_n2a(int id, char *buf, int len);
int rtnl_rtntype_a2n(int *id, char *arg);
int get_rt_realms(__u32 *realms, char *arg);
#endif /* __RTM_MAP_H__ */

View File

@ -0,0 +1,368 @@
/*
* utils.c
*
* 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>
*
*
* Changes:
*
* Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <resolv.h>
#include "./linux/pkt_sched.h"
#include "utils.h"
int get_integer(int *val, char *arg, int base)
{
long res;
char *ptr;
if (!arg || !*arg)
return -1;
res = strtol(arg, &ptr, base);
if (!ptr || ptr == arg || *ptr || res > INT_MAX || res < INT_MIN)
return -1;
*val = res;
return 0;
}
int get_unsigned(unsigned *val, char *arg, int base)
{
unsigned long res;
char *ptr;
if (!arg || !*arg)
return -1;
res = strtoul(arg, &ptr, base);
if (!ptr || ptr == arg || *ptr || res > UINT_MAX)
return -1;
*val = res;
return 0;
}
int get_u32(__u32 *val, char *arg, int base)
{
unsigned long res;
char *ptr;
if (!arg || !*arg)
return -1;
res = strtoul(arg, &ptr, base);
if (!ptr || ptr == arg || *ptr || res > 0xFFFFFFFFUL)
return -1;
*val = res;
return 0;
}
int get_u16(__u16 *val, char *arg, int base)
{
unsigned long res;
char *ptr;
if (!arg || !*arg)
return -1;
res = strtoul(arg, &ptr, base);
if (!ptr || ptr == arg || *ptr || res > 0xFFFF)
return -1;
*val = res;
return 0;
}
int get_u8(__u8 *val, char *arg, int base)
{
unsigned long res;
char *ptr;
if (!arg || !*arg)
return -1;
res = strtoul(arg, &ptr, base);
if (!ptr || ptr == arg || *ptr || res > 0xFF)
return -1;
*val = res;
return 0;
}
int get_s16(__s16 *val, char *arg, int base)
{
long res;
char *ptr;
if (!arg || !*arg)
return -1;
res = strtol(arg, &ptr, base);
if (!ptr || ptr == arg || *ptr || res > 0x7FFF || res < -0x8000)
return -1;
*val = res;
return 0;
}
int get_s8(__s8 *val, char *arg, int base)
{
long res;
char *ptr;
if (!arg || !*arg)
return -1;
res = strtol(arg, &ptr, base);
if (!ptr || ptr == arg || *ptr || res > 0x7F || res < -0x80)
return -1;
*val = res;
return 0;
}
int get_addr_1(inet_prefix *addr, char *name, int family)
{
char *cp;
unsigned char *ap = (unsigned char*)addr->data;
int i;
memset(addr, 0, sizeof(*addr));
if (strcmp(name, "default") == 0 ||
strcmp(name, "all") == 0 ||
strcmp(name, "any") == 0) {
addr->family = family;
addr->bytelen = (family == AF_INET6 ? 16 : 4);
addr->bitlen = -1;
return 0;
}
if (strchr(name, ':')) {
addr->family = AF_INET6;
if (family != AF_UNSPEC && family != AF_INET6)
return -1;
if (inet_pton(AF_INET6, name, addr->data) <= 0)
return -1;
addr->bytelen = 16;
addr->bitlen = -1;
return 0;
}
addr->family = AF_INET;
if (family != AF_UNSPEC && family != AF_INET)
return -1;
addr->bytelen = 4;
addr->bitlen = -1;
for (cp=name, i=0; *cp; cp++) {
if (*cp <= '9' && *cp >= '0') {
ap[i] = 10*ap[i] + (*cp-'0');
continue;
}
if (*cp == '.' && ++i <= 3)
continue;
return -1;
}
return 0;
}
int get_prefix_1(inet_prefix *dst, char *arg, int family)
{
int err;
unsigned plen;
char *slash;
memset(dst, 0, sizeof(*dst));
if (strcmp(arg, "default") == 0 || strcmp(arg, "any") == 0) {
dst->family = family;
dst->bytelen = 0;
dst->bitlen = 0;
return 0;
}
slash = strchr(arg, '/');
if (slash)
*slash = 0;
err = get_addr_1(dst, arg, family);
if (err == 0) {
switch(dst->family) {
case AF_INET6:
dst->bitlen = 128;
break;
default:
case AF_INET:
dst->bitlen = 32;
}
if (slash) {
if (get_integer(&plen, slash+1, 0) || plen > dst->bitlen) {
err = -1;
goto done;
}
dst->bitlen = plen;
}
}
done:
if (slash)
*slash = '/';
return err;
}
int get_addr(inet_prefix *dst, char *arg, int family)
{
if (family == AF_PACKET) {
fprintf(stderr, "Error: \"%s\" may be inet address, but it is not allowed in this context.\n", arg);
exit(1);
}
if (get_addr_1(dst, arg, family)) {
fprintf(stderr, "Error: an inet address is expected rather than \"%s\".\n", arg);
exit(1);
}
return 0;
}
int get_prefix(inet_prefix *dst, char *arg, int family)
{
if (family == AF_PACKET) {
fprintf(stderr, "Error: \"%s\" may be inet prefix, but it is not allowed in this context.\n", arg);
exit(1);
}
if (get_prefix_1(dst, arg, family)) {
fprintf(stderr, "Error: an inet prefix is expected rather than \"%s\".\n", arg);
exit(1);
}
return 0;
}
__u32 get_addr32(char *name)
{
inet_prefix addr;
if (get_addr_1(&addr, name, AF_INET)) {
fprintf(stderr, "Error: an IP address is expected rather than \"%s\"\n", name);
exit(1);
}
return addr.data[0];
}
void incomplete_command()
{
fprintf(stderr, "Command line is not complete. Try option \"help\"\n");
exit(-1);
}
void invarg(char *msg, char *arg)
{
fprintf(stderr, "Error: argument \"%s\" is wrong: %s\n", arg, msg);
exit(-1);
}
void duparg(char *key, char *arg)
{
fprintf(stderr, "Error: duplicate \"%s\": \"%s\" is the second value.\n", key, arg);
exit(-1);
}
void duparg2(char *key, char *arg)
{
fprintf(stderr, "Error: either \"%s\" is duplicate, or \"%s\" is a garbage.\n", key, arg);
exit(-1);
}
int matches(char *cmd, char *pattern)
{
int len = strlen(cmd);
if (len > strlen(pattern))
return -1;
return memcmp(pattern, cmd, len);
}
int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits)
{
__u32 *a1 = a->data;
__u32 *a2 = b->data;
int words = bits >> 0x05;
bits &= 0x1f;
if (words)
if (memcmp(a1, a2, words << 2))
return -1;
if (bits) {
__u32 w1, w2;
__u32 mask;
w1 = a1[words];
w2 = a2[words];
mask = htonl((0xffffffff) << (0x20 - bits));
if ((w1 ^ w2) & mask)
return 1;
}
return 0;
}
int __iproute2_hz_internal;
int __get_hz(void)
{
int hz = 0;
FILE *fp = fopen("/proc/net/psched", "r");
if (fp) {
unsigned nom, denom;
if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2)
if (nom == 1000000)
hz = denom;
fclose(fp);
}
if (hz)
return hz;
return HZ;
}
const char *rt_addr_n2a(int af, int len, void *addr, char *buf, int buflen)
{
switch (af) {
case AF_INET:
case AF_INET6:
return inet_ntop(af, addr, buf, buflen);
default:
return "???";
}
}
const char *format_host(int af, int len, void *addr, char *buf, int buflen)
{
#ifdef RESOLVE_HOSTNAMES
if (resolve_hosts) {
struct hostent *h_ent;
if (len <= 0) {
switch (af) {
case AF_INET:
len = 4;
break;
case AF_INET6:
len = 16;
break;
default: ;
}
}
if (len > 0 &&
(h_ent = gethostbyaddr(addr, len, af)) != NULL) {
snprintf(buf, buflen-1, "%s", h_ent->h_name);
return buf;
}
}
#endif
return rt_addr_n2a(af, len, addr, buf, buflen);
}

View File

@ -0,0 +1,101 @@
#ifndef __UTILS_H__
#define __UTILS_H__ 1
#include <asm/types.h>
#include <resolv.h>
#include "libnetlink.h"
#include "ll_map.h"
#include "rtm_map.h"
extern int preferred_family;
extern int show_stats;
extern int show_details;
extern int show_raw;
extern int resolve_hosts;
extern int oneline;
extern char * _SL_;
#ifndef IPPROTO_ESP
#define IPPROTO_ESP 50
#endif
#ifndef IPPROTO_AH
#define IPPROTO_AH 51
#endif
#define SPRINT_BSIZE 64
#define SPRINT_BUF(x) char x[SPRINT_BSIZE]
extern void incomplete_command(void) __attribute__((noreturn));
#define NEXT_ARG() do { argv++; if (--argc <= 0) incomplete_command(); } while(0)
typedef struct
{
__u8 family;
__u8 bytelen;
__s16 bitlen;
__u32 data[4];
} inet_prefix;
#define DN_MAXADDL 20
#ifndef AF_DECnet
#define AF_DECnet 12
#endif
struct dn_naddr
{
unsigned short a_len;
unsigned char a_addr[DN_MAXADDL];
};
#define IPX_NODE_LEN 6
struct ipx_addr {
u_int32_t ipx_net;
u_int8_t ipx_node[IPX_NODE_LEN];
};
extern __u32 get_addr32(char *name);
extern int get_addr_1(inet_prefix *dst, char *arg, int family);
extern int get_prefix_1(inet_prefix *dst, char *arg, int family);
extern int get_addr(inet_prefix *dst, char *arg, int family);
extern int get_prefix(inet_prefix *dst, char *arg, int family);
extern int get_integer(int *val, char *arg, int base);
extern int get_unsigned(unsigned *val, char *arg, int base);
#define get_byte get_u8
#define get_ushort get_u16
#define get_short get_s16
extern int get_u32(__u32 *val, char *arg, int base);
extern int get_u16(__u16 *val, char *arg, int base);
extern int get_s16(__s16 *val, char *arg, int base);
extern int get_u8(__u8 *val, char *arg, int base);
extern int get_s8(__s8 *val, char *arg, int base);
extern const char *format_host(int af, int len, void *addr, char *buf, int buflen);
extern const char *rt_addr_n2a(int af, int len, void *addr, char *buf, int buflen);
void invarg(char *, char *) __attribute__((noreturn));
void duparg(char *, char *) __attribute__((noreturn));
void duparg2(char *, char *) __attribute__((noreturn));
int matches(char *arg, char *pattern);
extern int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits);
const char *dnet_ntop(int af, const void *addr, char *str, size_t len);
int dnet_pton(int af, const char *src, void *addr);
const char *ipx_ntop(int af, const void *addr, char *str, size_t len);
int ipx_pton(int af, const char *src, void *addr);
extern int __iproute2_hz_internal;
extern int __get_hz(void);
static __inline__ int get_hz(void)
{
if (__iproute2_hz_internal == 0)
__iproute2_hz_internal = __get_hz();
return __iproute2_hz_internal;
}
#endif /* __UTILS_H__ */