IP applet by Bastian Blank <waldi@debian.org>
This commit is contained in:
parent
021fa7db91
commit
9a2d27249c
4
Makefile
4
Makefile
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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
104
networking/ip.c
Normal 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);
|
||||
}
|
||||
}
|
30
networking/libiproute/Makefile
Normal file
30
networking/libiproute/Makefile
Normal 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)
|
||||
|
43
networking/libiproute/Makefile.in
Normal file
43
networking/libiproute/Makefile.in
Normal 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))
|
||||
|
20
networking/libiproute/ip_common.h
Normal file
20
networking/libiproute/ip_common.h
Normal 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);
|
723
networking/libiproute/ipaddress.c
Normal file
723
networking/libiproute/ipaddress.c
Normal 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);
|
||||
}
|
349
networking/libiproute/iplink.c
Normal file
349
networking/libiproute/iplink.c
Normal 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);
|
||||
}
|
674
networking/libiproute/iproute.c
Normal file
674
networking/libiproute/iproute.c
Normal 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);
|
||||
}
|
||||
|
548
networking/libiproute/iptunnel.c
Normal file
548
networking/libiproute/iptunnel.c
Normal 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);
|
||||
}
|
521
networking/libiproute/libnetlink.c
Normal file
521
networking/libiproute/libnetlink.c
Normal 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;
|
||||
}
|
46
networking/libiproute/libnetlink.h
Normal file
46
networking/libiproute/libnetlink.h
Normal 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__ */
|
||||
|
413
networking/libiproute/linux/pkt_sched.h
Normal file
413
networking/libiproute/linux/pkt_sched.h
Normal 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
|
92
networking/libiproute/ll_addr.c
Normal file
92
networking/libiproute/ll_addr.c
Normal 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;
|
||||
}
|
||||
}
|
169
networking/libiproute/ll_map.c
Normal file
169
networking/libiproute/ll_map.c
Normal 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;
|
||||
}
|
12
networking/libiproute/ll_map.h
Normal file
12
networking/libiproute/ll_map.h
Normal 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__ */
|
118
networking/libiproute/ll_proto.c
Normal file
118
networking/libiproute/ll_proto.c
Normal 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;
|
||||
}
|
121
networking/libiproute/ll_types.c
Normal file
121
networking/libiproute/ll_types.c
Normal 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;
|
||||
}
|
389
networking/libiproute/rt_names.c
Normal file
389
networking/libiproute/rt_names.c
Normal 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;
|
||||
}
|
||||
|
30
networking/libiproute/rt_names.h
Normal file
30
networking/libiproute/rt_names.h
Normal 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
|
116
networking/libiproute/rtm_map.c
Normal file
116
networking/libiproute/rtm_map.c
Normal 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;
|
||||
}
|
10
networking/libiproute/rtm_map.h
Normal file
10
networking/libiproute/rtm_map.h
Normal 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__ */
|
368
networking/libiproute/utils.c
Normal file
368
networking/libiproute/utils.c
Normal 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);
|
||||
}
|
101
networking/libiproute/utils.h
Normal file
101
networking/libiproute/utils.h
Normal 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__ */
|
Loading…
Reference in New Issue
Block a user