Import mrouted version 3.9-beta3+IOS12 . This is a version of 3.9-beta3

with minor changes to work around a bug in Cisco's IOS version 12.0 .
3.9-beta3 is much improved over 3.8, and is only labelled "beta" because
of missing features, as opposed to instability or known bugs.
This commit is contained in:
Bill Fenner 1999-01-20 07:44:18 +00:00
parent ce595def07
commit 1f25327484
26 changed files with 4790 additions and 1884 deletions

View File

@ -1,21 +1,188 @@
$Id: README-3.8.mrouted,v 3.8 1995/11/29 22:23:02 fenner Rel $
README-3.9-beta3.mrouted,v 1.1.2.1 1998/03/01 03:00:20 fenner Exp
IP Multicast Extensions for BSD-Derived Unix Systems
Multicast Routing Daemon
Release 3.8
November 29, 1995
Release 3.9-beta3
February 28, 1998
available from parcftp.xerox.com,
file pub/net-research/ipmulti/mrouted3.8.tar.Z
binaries pub/net-research/ipmulti/mrouted3.8-sparc-sunos41x.tar.Z
pub/net-research/ipmulti/mrouted3.8-sparc-solaris2.tar.Z
pub/net-research/ipmulti/mrouted3.8-i386-bsd.tar.Z
pub/net-research/ipmulti/mrouted3.8-alpha-osf1.tar.Z
pub/net-research/ipmulti/mrouted3.8-sgi-irix.tar.Z
pub/net-research/ipmulti/mrouted3.8-hp-hpux.tar.Z
file pub/net-research/ipmulti/beta-test/mrouted3.9-beta3.tar.Z
binaries:
pub/net-research/ipmulti/beta-test/mrouted3.9-beta3-sparc-sunos41x.tar.Z
pub/net-research/ipmulti/beta-test/mrouted3.9-beta3-sparc-solaris2.tar.Z
pub/net-research/ipmulti/beta-test/mrouted3.9-beta3-i386-freebsd22.tar.Z
pub/net-research/ipmulti/beta-test/mrouted3.9-beta3-alpha-osf1.tar.Z
pub/net-research/ipmulti/beta-test/mrouted3.9-beta3-sgi-irix6.tar.Z
Note: The 3.8 release is mrouted-only, and will run on top of a 3.5 kernel.
It is a drop-in replacement for mrouted 3.5, 3.6 or 3.7 .
Note: The 3.9 release is mrouted-only, and will run on top of a 3.5 kernel.
It is a drop-in replacement for mrouted 3.5, 3.6, 3.7 or 3.8.
NOTE WELL: This is a beta-test release of mrouted. The basic
functionality has been extensively tested in CAIRN and other
testbeds, but it is expected to have bugs. Please report bugs to Bill
Fenner <fenner@parc.xerox.com>.
The 3.9-beta3 release fixes the following bugs:
o There was a bug handling routing updates which caused random black
holes.
o There was a race condition in the timer handlers causing free'd memory
to sometimes get touched.
o "allow_nonpruners" wasn't allowed in the configuration file (and almost
nobody noticed! - probably a good sign)
o When a prune times out and the source has been active "recently",
mrouted now waits for further traffic instead of triggering a new
prune.
o mrouted now ignores unreachable routes when making a routing decision
(previously it would blackhole, now it can find a less-specific)
The 3.9-beta3 release has the following new features:
o A "blaster" keyword for mrouted.conf, to turn on handling of routers
(mostly ciscos) which overwhelm the socket buffers by blasting the
whole routing table at once.
o A "notransit" keyword; routes learned on a "notransit" vif will not be
readvertised onto another "notransit" vif.
o The 500kbps default rate limit on tunnels has been removed.
o An ICMP listener which logs ICMP errors which appear to be in response to
tunnel packets that we sent.
o A tunnel traffic encapsulator, which encapsulates control traffic
inside the tunnel instead of unicasting it "beside" the tunnel.
This is turned off by default; use "beside off" to turn it on.
o A "force_leaf" flag to ignore any potential neighbors on a given interface.
=========
3.9-beta2
June 11, 1997
The 3.9-beta2 release fixes the following bugs:
o There was a bug in 3.9-beta1's raw socket buffer processing that
would cause an immediate lockup on startup on some systems.
o RSRR would not clear out the group membership information if
further notification of changes to this route entry was not possible.
There is no need to upgrade to 3.9-beta2 if you are not experiencing
one of the aforementioned bugs.
=========
3.9-beta1
June 6, 1997
The 3.9-beta1 release has the following known bugs:
o The startup message doesn't print properly if you have too many
interfaces.
The 3.9-beta1 release fixes the following bugs:
o mrouted did not properly keep track of subordinates, and would not
time out subordinateness. This caused 2 major problems:
1. pruning did not happen when there were equal-cost paths to
the same multi-access link
2. subordinateness which did not get cancelled by a non-poisoned
route (e.g. in the face of route filtering) did not time out,
causing traffic to continue to flow.
o mrouted's IGMPv2 processing when it is not the querier now
conforms to draft-ietf-idmr-igmp-v2-06.txt Thanks to Lorenzo
VICISANO <L.Vicisano@cs.ucl.ac.uk> for finding a problem.
o mrouted is much more careful about forgetting prunes; 3.8
would forget prunes whenever any route change ocurred.
The 3.9-beta1 release has the following new features:
o Longer prune lifetimes (2 hours) by default. Prune lifetimes may
be configured per-vif, with the "prune_lifetime N" mrouted.conf
configuration file entry (where N is in seconds). This helps to
work around the black holes caused on restart when you have a Cisco
upstream which does not handle genid's; if this is your situation
the recommended value is 300.
o mrouted's behavior of flooding new routes by default at startup
in order to speed healing of paths during startup can be turned off
per-vif or globally with the "noflood" configuration option.
Turning this option off means you are likely to experience
black holes for a minute or two when you restart a router. The
default is to flood for a minute or two until mrouted is able to
learn subordinate relationships.
o mrouted now retransmits prunes by default on point-to-point links.
prune retransmission can be turned on or off per vif via the
"rexmit_prunes [on|off]" mrouted.conf command. Prune retransmission
helps on lossy links, and also helps when a router has forgotten
about a prune (e.g. if it is out of memory and needs to shed state,
or due to a bug).
o The new "passive" mode causes mrouted to not actively send probes
looking for neighbors. This allows a dialup link to become quiescent
if there is no DVMRP neighbor on the other end. Configuring
"passive" on both ends of a link will cause it to never come up.
o mrouted defaults to not peering with DVMRP routers that do not
prune. Use the "allow_nonpruners" mrouted.conf option on a vif
on which you want to allow such peerings.
o mrouted now allows route filtering. mrouted.conf syntax:
accept 13/8
accepts all routes matching 13/8 (e.g. accepts
13.2.116/22). If you want to accept only exactly
13/8, use
accept 13/8 exact
deny 10/8 64/2 130/8 exact 172/8 exact
denies some common MBone martians
Only "accept" or "deny" is allowed, no combinations.
Add "bidir" to apply the filter to output too, otherwise
it's input only.
Expected usage:
- Providers filter routes that customers send them
- Martian removal
- Topology modification (e.g. don't let the existence of
private tunnel foo out into the world).
o mrouted now malloc's the buffer it uses for SIOCGIFCONF, to allow
for more interfaces. Thanks to Danny Mitzel
o mrouted now ignores multiple entries for a single interface
name (temporary hack until mrouted understands interface aliases)
o mrouted's "-d" flag has been modified to accept the names of the
systems which you would like to debug.
packet, prunes, routes, peers, cache, timeout, interface,
membership, traceroute, igmp
o mrouted now times neighbors out fater, and fully detects and
ignores routes from one-way peerings.
o mrouted's route processing has been sped up, especially at startup.
o mrouted uses the biggest SO_RCVBUF the operating system allows
(up to 256Kbytes)
o mrouted uses TOS 0xc0 ("Internet Control") for DVMRP messages.
===========
Release 3.8
November 29, 1995
The 3.8 release fixes the following bugs:

1
usr.sbin/mrouted/VERSION Normal file
View File

@ -0,0 +1 @@
3.9-beta3+IOS12

View File

@ -7,22 +7,25 @@
* Leland Stanford Junior University.
*
*
* $Id: callout.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
* callout.c,v 3.8.4.8 1998/01/06 01:58:45 fenner Exp
*/
#include "defs.h"
#ifndef lint
static char rcsid[] = "@(#) $Id: \
callout.c,v 3.8.4.8 1998/01/06 01:58:45 fenner Exp $";
#endif
/* the code below implements a callout queue */
static int id = 0;
static struct timeout_q *Q = 0; /* pointer to the beginning of timeout queue */
static int in_callout = 0;
struct timeout_q {
struct timeout_q *next; /* next event */
int id;
cfunc_t func; /* function to call */
char *data; /* func's data */
void *data; /* func's data */
int time; /* time offset to next event*/
};
@ -38,47 +41,64 @@ callout_init()
Q = (struct timeout_q *) 0;
}
/*
* signal handler for SIGALARM that is called once every second
*/
void
age_callout_queue()
free_all_callouts()
{
struct timeout_q *ptr;
if (in_callout)
return;
struct timeout_q *p;
in_callout = 1;
ptr = Q;
while (ptr) {
if (!ptr->time) {
/* timeout has happened */
Q = Q->next;
in_callout = 0;
if (ptr->func)
ptr->func(ptr->data);
in_callout = 1;
free(ptr);
ptr = Q;
}
else {
ptr->time --;
#ifdef IGMP_DEBUG
log(LOG_DEBUG,0,"[callout, age_callout_queue] -- time (%d)", ptr->time);
#endif /* IGMP_DEBUG */
in_callout = 0; return;
}
while (Q) {
p = Q;
Q = Q->next;
free(p);
}
in_callout = 0;
return;
}
/*
* elapsed_time seconds have passed; perform all the events that should
* happen.
*/
void
age_callout_queue(elapsed_time)
int elapsed_time;
{
struct timeout_q *ptr;
int i = 0;
for (ptr = Q; ptr; ptr = Q, i++) {
if (ptr->time > elapsed_time) {
ptr->time -= elapsed_time;
return;
} else {
elapsed_time -= ptr->time;
Q = Q->next;
IF_DEBUG(DEBUG_TIMEOUT)
log(LOG_DEBUG, 0, "about to call timeout %d (#%d)", ptr->id, i);
if (ptr->func)
ptr->func(ptr->data);
free(ptr);
}
}
}
/*
* Return in how many seconds age_callout_queue() would like to be called.
* Return -1 if there are no events pending.
*/
int
timer_nextTimer()
{
if (Q) {
if (Q->time < 0) {
log(LOG_WARNING, 0, "timer_nextTimer top of queue says %d",
Q->time);
return 0;
}
return Q->time;
}
return -1;
}
/*
* sets the timer
*/
@ -86,20 +106,15 @@ int
timer_setTimer(delay, action, data)
int delay; /* number of units for timeout */
cfunc_t action; /* function to be called on timeout */
char *data; /* what to call the timeout function with */
void *data; /* what to call the timeout function with */
{
struct timeout_q *ptr, *node, *prev;
if (in_callout)
return -1;
in_callout = 1;
int i = 0;
/* create a node */
node = (struct timeout_q *)malloc(sizeof(struct timeout_q));
if (node == 0) {
log(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n");
in_callout = 0;
return -1;
}
node->func = action;
@ -129,7 +144,8 @@ timer_setTimer(delay, action, data)
prev->next = node;
ptr->time -= node->time;
print_Q();
in_callout = 0;
IF_DEBUG(DEBUG_TIMEOUT)
log(LOG_DEBUG, 0, "created timeout %d (#%d)", node->id, i);
return node->id;
} else {
/* keep moving */
@ -138,29 +154,46 @@ timer_setTimer(delay, action, data)
prev = ptr;
ptr = ptr->next;
}
i++;
}
prev->next = node;
}
print_Q();
in_callout = 0;
IF_DEBUG(DEBUG_TIMEOUT)
log(LOG_DEBUG, 0, "created timeout %d (#%d)", node->id, i);
return node->id;
}
/* returns the time until the timer is scheduled */
int
timer_leftTimer(timer_id)
int timer_id;
{
struct timeout_q *ptr;
int left = 0;
/* clears the associated timer */
void
if (!timer_id)
return -1;
for (ptr = Q; ptr; ptr = ptr->next) {
left += ptr->time;
if (ptr->id == timer_id)
return left;
}
return -1;
}
/* clears the associated timer. Returns 1 if succeeded. */
int
timer_clearTimer(timer_id)
int timer_id;
{
struct timeout_q *ptr, *prev;
int i = 0;
if (in_callout)
return;
if (!timer_id)
return;
return 0;
in_callout = 1;
prev = ptr = Q;
/*
@ -183,17 +216,22 @@ timer_clearTimer(timer_id)
if (ptr->next != 0)
(ptr->next)->time += ptr->time;
free(ptr->data);
if (ptr->data)
free(ptr->data);
IF_DEBUG(DEBUG_TIMEOUT)
log(LOG_DEBUG, 0, "deleted timer %d (#%d)", ptr->id, i);
free(ptr);
print_Q();
in_callout = 0;
return;
return 1;
}
prev = ptr;
ptr = ptr->next;
i++;
}
IF_DEBUG(DEBUG_TIMEOUT)
log(LOG_DEBUG, 0, "failed to delete timer %d (#%d)", timer_id, i);
print_Q();
in_callout = 0;
return 0;
}
#ifdef IGMP_DEBUG
@ -205,22 +243,8 @@ print_Q()
{
struct timeout_q *ptr;
for(ptr = Q; ptr; ptr = ptr->next)
log(LOG_DEBUG,0,"(%d,%d) ", ptr->id, ptr->time);
IF_DEBUG(DEBUG_TIMEOUT)
for (ptr = Q; ptr; ptr = ptr->next)
log(LOG_DEBUG, 0, "(%d,%d) ", ptr->id, ptr->time);
}
#endif /* IGMP_DEBUG */
int
secs_remaining( timer_id)
int timer_id;
{
struct timeout_q *ptr;
int left=0;
for (ptr = Q; ptr && ptr->id != timer_id; ptr = ptr->next)
left += ptr->time;
if (!ptr) /* not found */
return 0;
return left + ptr->time;
}

View File

@ -4,7 +4,7 @@
*
* Written by Bill Fenner, NRL, 1994
*
* $Id: cfparse.y,v 3.8 1995/11/29 22:36:57 fenner Rel $
* cfparse.y,v 3.8.4.30 1998/03/01 01:48:58 fenner Exp
*/
#include <stdio.h>
#ifdef __STDC__
@ -29,19 +29,23 @@ int yyparse __P((void));
static FILE *f;
extern int udp_socket;
char *configfilename = _PATH_MROUTED_CONF;
extern int cache_lifetime;
extern int max_prune_lifetime;
extern int prune_lifetime;
/* imported from config.c, with slight memory leak */
extern struct ifconf ifc;
int allow_black_holes = 0;
static int lineno;
static struct ifreq ifbuf[32];
static struct ifconf ifc;
static struct uvif *v;
static int order;
static int order, state;
static int noflood = 0;
static int rexmit = VIFF_REXMIT_PRUNES;
struct addrmask {
u_int32 addr;
@ -66,12 +70,17 @@ int numbounds = 0; /* Number of named boundaries */
char *ptr;
struct addrmask addrmask;
u_int32 addr;
struct vf_element *filterelem;
};
%token CACHE_LIFETIME PRUNING
%token CACHE_LIFETIME PRUNE_LIFETIME PRUNING BLACK_HOLE NOFLOOD
%token PHYINT TUNNEL NAME
%token DISABLE IGMPV1 SRCRT
%token METRIC THRESHOLD RATE_LIMIT BOUNDARY NETMASK ALTNET
%token DISABLE IGMPV1 SRCRT BESIDE
%token METRIC THRESHOLD RATE_LIMIT BOUNDARY NETMASK ALTNET ADVERT_METRIC
%token FILTER ACCEPT DENY EXACT BIDIR REXMIT_PRUNES REXMIT_PRUNES2
%token PASSIVE ALLOW_NONPRUNERS
%token NOTRANSIT BLASTER FORCE_LEAF
%token PRUNE_LIFETIME2 NOFLOOD2
%token SYSNAM SYSCONTACT SYSVERSION SYSLOCATION
%token <num> BOOLEAN
%token <num> NUMBER
@ -81,6 +90,7 @@ int numbounds = 0; /* Number of named boundaries */
%type <addr> interface addrname
%type <addrmask> bound boundary addrmask
%type <filterelem> filter filtlist filtelement filtelem
%start conf
@ -98,6 +108,8 @@ stmt : error
vifi_t vifi;
state++;
if (order)
fatal("phyints must appear before tunnels");
@ -127,11 +139,9 @@ stmt : error
fatal("Tunnel local address %s is not mine",
inet_fmt($2, s1));
strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ);
if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr)<0)
fatal("ioctl SIOCGIFFLAGS on %s",ffr.ifr_name);
if (ffr.ifr_flags & IFF_LOOPBACK)
fatal("Tunnel local address %s is a loopback interface",
if (((ntohl($2) & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) ==
IN_LOOPBACKNET)
fatal("Tunnel local address %s is a loopback address",
inet_fmt($2, s1));
if (ifconfaddr(&ifc, $3) != 0)
@ -147,28 +157,25 @@ stmt : error
inet_fmt($3, s1));
} else if (!(v->uv_flags & VIFF_DISABLED)) {
if (($3 & v->uv_subnetmask) == v->uv_subnet)
fatal("Unnecessary tunnel to %s",
inet_fmt($3,s1));
fatal("Unnecessary tunnel to %s, same subnet as vif %d (%s)",
inet_fmt($3,s1), vifi, v->uv_name);
}
if (numvifs == MAXVIFS)
fatal("too many vifs");
strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ);
if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr)<0)
fatal("ioctl SIOCGIFFLAGS on %s", ffr.ifr_name);
v = &uvifs[numvifs];
v->uv_flags = VIFF_TUNNEL;
v->uv_metric = DEFAULT_METRIC;
v->uv_rate_limit= DEFAULT_TUN_RATE_LIMIT;
v->uv_threshold = DEFAULT_THRESHOLD;
zero_vif(v, 1);
v->uv_flags = VIFF_TUNNEL | rexmit | noflood;
v->uv_flags |= VIFF_OTUNNEL; /*XXX*/
v->uv_lcl_addr = $2;
v->uv_rmt_addr = $3;
v->uv_subnet = 0;
v->uv_subnetmask= 0;
v->uv_subnetbcast= 0;
v->uv_dst_addr = $3;
strncpy(v->uv_name, ffr.ifr_name, IFNAMSIZ);
v->uv_groups = NULL;
v->uv_neighbors = NULL;
v->uv_acl = NULL;
v->uv_addrs = NULL;
if (!(ffr.ifr_flags & IFF_UP)) {
v->uv_flags |= VIFF_DOWN;
@ -177,17 +184,101 @@ stmt : error
}
tunnelmods
{
log(LOG_INFO, 0,
"installing tunnel from %s to %s as vif #%u - rate=%d",
inet_fmt($2, s1), inet_fmt($3, s2),
numvifs, v->uv_rate_limit);
++numvifs;
if (!(v->uv_flags & VIFF_OTUNNEL)) {
init_ipip_on_vif(v);
}
log(LOG_INFO, 0,
"installing tunnel from %s to %s as vif #%u - rate=%d",
inet_fmt($2, s1), inet_fmt($3, s2),
numvifs, v->uv_rate_limit);
++numvifs;
}
| PRUNING BOOLEAN { pruning = $2; }
| CACHE_LIFETIME NUMBER { cache_lifetime = $2;
max_prune_lifetime = cache_lifetime * 2;
| CACHE_LIFETIME NUMBER {
if ($2 < MIN_CACHE_LIFETIME) {
warn("cache_lifetime %d must be at least %d",
$2, MIN_CACHE_LIFETIME);
} else {
cache_lifetime = $2;
}
}
| PRUNE_LIFETIME NUMBER {
if ($2 < MIN_PRUNE_LIFETIME) {
warn("prune_lifetime %d must be at least %d",
$2, MIN_PRUNE_LIFETIME);
} else {
prune_lifetime = $2;
}
}
| PRUNING BOOLEAN {
if ($2 != 1) {
warn("Disabling pruning is no longer supported");
}
}
| BLACK_HOLE {
#ifdef ALLOW_BLACK_HOLES
allow_black_holes = 1;
#endif
}
/*
* Turn off initial flooding (until subordinateness is learned
* via route exchange) on all phyints and set the default for
* all further tunnels.
*/
| NOFLOOD {
vifi_t vifi;
noflood = VIFF_NOFLOOD;
for (vifi = 0, v = uvifs;
vifi < numvifs;
++vifi, ++v)
v->uv_flags |= VIFF_NOFLOOD;
}
/*
* Turn on prune retransmission on all interfaces.
* Tunnels default to retransmitting, so this just
* needs to turn on phyints.
*/
| REXMIT_PRUNES {
vifi_t vifi;
for (vifi = 0, v = uvifs;
vifi < numvifs;
++vifi, ++v)
v->uv_flags |= VIFF_REXMIT_PRUNES;
}
/*
* If true, do as above. If false, no need to turn
* it off for phyints since they default to not
* rexmit; need to set flag to not rexmit on tunnels.
*/
| REXMIT_PRUNES BOOLEAN {
if ($2) {
vifi_t vifi;
for (vifi = 0, v = uvifs;
vifi < numvifs;
++vifi, ++v)
v->uv_flags |= VIFF_REXMIT_PRUNES;
} else {
rexmit = 0;
}
}
| NAME STRING boundary { if (numbounds >= MAXBOUNDS) {
fatal("Too many named boundaries (max %d)", MAXBOUNDS);
}
@ -223,6 +314,16 @@ tunnelmods : /* empty */
;
tunnelmod : mod
| BESIDE { v->uv_flags |= VIFF_OTUNNEL; }
| BESIDE BOOLEAN {
if ($2) {
v->uv_flags |= VIFF_OTUNNEL;
} else {
v->uv_flags &= ~VIFF_OTUNNEL;
}
}
| SRCRT { fatal("Source-route tunnels not supported"); }
;
@ -273,6 +374,20 @@ ifmod : mod
warn("Expected address after altnet keyword, ignored");
}
| FORCE_LEAF {
v->uv_flags |= VIFF_FORCE_LEAF;
}
| FORCE_LEAF BOOLEAN {
if ($2) {
v->uv_flags |= VIFF_FORCE_LEAF;
} else {
v->uv_flags &= ~VIFF_FORCE_LEAF;
}
}
;
@ -293,6 +408,15 @@ mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255)
warn("Expected number after metric keyword, ignored");
}
| ADVERT_METRIC NUMBER { if ($2 < 0 || $2 > UNREACHABLE - 1)
fatal("Invalid advert_metric %d", $2);
v->uv_admetric = $2;
}
| ADVERT_METRIC {
warn("Expected number after advert_metric keyword, ignored");
}
| RATE_LIMIT NUMBER { if ($2 > MAX_RATE_LIMIT)
fatal("Invalid rate_limit %d",$2);
@ -323,6 +447,122 @@ mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255)
warn("Expected boundary spec after boundary keyword, ignored");
}
| REXMIT_PRUNES2 {
v->uv_flags |= VIFF_REXMIT_PRUNES;
}
| REXMIT_PRUNES2 BOOLEAN {
if ($2) {
v->uv_flags |= VIFF_REXMIT_PRUNES;
} else {
v->uv_flags &= ~VIFF_REXMIT_PRUNES;
}
}
| PASSIVE {
v->uv_flags |= VIFF_PASSIVE;
}
| NOFLOOD2 {
v->uv_flags |= VIFF_NOFLOOD;
}
| NOTRANSIT {
v->uv_flags |= VIFF_NOTRANSIT;
}
| BLASTER {
v->uv_flags |= VIFF_BLASTER;
blaster_alloc(v - uvifs);
}
| ALLOW_NONPRUNERS {
v->uv_flags |= VIFF_ALLOW_NONPRUNERS;
}
| PRUNE_LIFETIME2 NUMBER {
if ($2 < MIN_PRUNE_LIFETIME) {
warn("prune_lifetime %d must be at least %d",
$2, MIN_PRUNE_LIFETIME);
} else {
v->uv_prune_lifetime = $2;
}
}
| ACCEPT filter {
if (v->uv_filter == NULL) {
struct vif_filter *v_filter;
v_filter = (struct vif_filter *)malloc(sizeof(struct vif_filter));
if (v_filter == NULL)
fatal("out of memory");
v_filter->vf_flags = 0;
v_filter->vf_type = VFT_ACCEPT;
v_filter->vf_filter = $2;
v->uv_filter = v_filter;
} else if (v->uv_filter->vf_type != VFT_ACCEPT) {
fatal("can't accept and deny");
} else {
struct vf_element *p;
p = v->uv_filter->vf_filter;
while (p->vfe_next)
p = p->vfe_next;
p->vfe_next = $2;
}
}
| ACCEPT {
warn("Expected filter spec after accept keyword, ignored");
}
| DENY filter {
if (v->uv_filter == NULL) {
struct vif_filter *v_filter;
v_filter = (struct vif_filter *)malloc(sizeof(struct vif_filter));
if (v_filter == NULL)
fatal("out of memory");
v_filter->vf_flags = 0;
v_filter->vf_type = VFT_DENY;
v_filter->vf_filter = $2;
v->uv_filter = v_filter;
} else if (v->uv_filter->vf_type != VFT_DENY) {
fatal("can't accept and deny");
} else {
struct vf_element *p;
p = v->uv_filter->vf_filter;
while (p->vfe_next)
p = p->vfe_next;
p->vfe_next = $2;
}
}
| DENY {
warn("Expected filter spec after deny keyword, ignored");
}
| BIDIR {
if (v->uv_filter == NULL) {
fatal("bidir goes after filters");
}
v->uv_filter->vf_flags |= VFF_BIDIR;
}
;
@ -365,6 +605,9 @@ bound : boundary { $$ = $1; }
boundary : ADDRMASK {
#ifdef ALLOW_BLACK_HOLES
if (!allow_black_holes)
#endif
if ((ntohl($1.addr) & 0xff000000) != 0xef000000) {
fatal("Boundaries must be 239.x.x.x, not %s/%d",
inet_fmt($1.addr, s1), $1.mask);
@ -377,6 +620,35 @@ boundary : ADDRMASK {
addrmask : ADDRMASK { $$ = $1; }
| ADDR { $$.addr = $1; $$.mask = 0; }
;
filter : filtlist { $$ = $1; }
| STRING { fatal("named filters no implemented yet"); }
;
filtlist : filtelement { $$ = $1; }
| filtelement filtlist { $1->vfe_next = $2; $$ = $1; }
;
filtelement : filtelem { $$ = $1; }
| filtelem EXACT { $1->vfe_flags |= VFEF_EXACT; $$ = $1; }
;
filtelem : ADDRMASK {
struct vf_element *vfe;
vfe = (struct vf_element *)malloc(sizeof(struct vf_element));
if (vfe == NULL)
fatal("out of memory");
vfe->vfe_addr = $1.addr;
VAL_TO_MASK(vfe->vfe_mask, $1.mask);
vfe->vfe_flags = 0;
vfe->vfe_next = NULL;
$$ = vfe;
}
%%
#ifdef __STDC__
static void
@ -442,7 +714,6 @@ next_word()
{
static char buf[1024];
static char *p=NULL;
extern FILE *f;
char *q;
while (1) {
@ -481,45 +752,75 @@ next_word()
}
}
/*
* List of keywords. Must have an empty record at the end to terminate
* list. If a second value is specified, the first is used at the beginning
* of the file and the second is used while parsing interfaces (e.g. after
* the first "phyint" or "tunnel" keyword).
*/
static struct keyword {
char *word;
int val1;
int val2;
} words[] = {
{ "cache_lifetime", CACHE_LIFETIME },
{ "prune_lifetime", PRUNE_LIFETIME, PRUNE_LIFETIME2 },
{ "pruning", PRUNING },
{ "phyint", PHYINT },
{ "tunnel", TUNNEL },
{ "disable", DISABLE },
{ "metric", METRIC },
{ "advert_metric", ADVERT_METRIC },
{ "threshold", THRESHOLD },
{ "rate_limit", RATE_LIMIT },
{ "force_leaf", FORCE_LEAF },
{ "srcrt", SRCRT },
{ "sourceroute", SRCRT },
{ "boundary", BOUNDARY },
{ "netmask", NETMASK },
{ "igmpv1", IGMPV1 },
{ "altnet", ALTNET },
{ "name", NAME },
{ "accept", ACCEPT },
{ "deny", DENY },
{ "exact", EXACT },
{ "bidir", BIDIR },
{ "allow_nonpruners", ALLOW_NONPRUNERS },
#ifdef ALLOW_BLACK_HOLES
{ "allow_black_holes", BLACK_HOLE },
#endif
{ "noflood", NOFLOOD, NOFLOOD2},
{ "notransit", NOTRANSIT },
{ "blaster", BLASTER },
{ "rexmit_prunes", REXMIT_PRUNES, REXMIT_PRUNES2 },
{ "passive", PASSIVE },
{ "beside", BESIDE },
#ifdef SNMP
{ "sysName", SYSNAM },
{ "sysContact", SYSCONTACT },
{ "sysVersion", SYSVERSION },
{ "sysLocation", SYSLOCATION },
#endif
{ NULL, 0 }
};
static int
yylex()
{
int n;
u_int32 addr;
char *q;
struct keyword *w;
if ((q = next_word()) == NULL) {
return 0;
}
if (!strcmp(q,"cache_lifetime"))
return CACHE_LIFETIME;
if (!strcmp(q,"pruning"))
return PRUNING;
if (!strcmp(q,"phyint"))
return PHYINT;
if (!strcmp(q,"tunnel"))
return TUNNEL;
if (!strcmp(q,"disable"))
return DISABLE;
if (!strcmp(q,"metric"))
return METRIC;
if (!strcmp(q,"threshold"))
return THRESHOLD;
if (!strcmp(q,"rate_limit"))
return RATE_LIMIT;
if (!strcmp(q,"srcrt") || !strcmp(q,"sourceroute"))
return SRCRT;
if (!strcmp(q,"boundary"))
return BOUNDARY;
if (!strcmp(q,"netmask"))
return NETMASK;
if (!strcmp(q,"igmpv1"))
return IGMPV1;
if (!strcmp(q,"altnet"))
return ALTNET;
if (!strcmp(q,"name"))
return NAME;
for (w = words; w->word; w++)
if (!strcmp(q, w->word))
return (state && w->val2) ? w->val2 : w->val1;
if (!strcmp(q,"on") || !strcmp(q,"yes")) {
yylval.num = 1;
return BOOLEAN;
@ -528,8 +829,13 @@ yylex()
yylval.num = 0;
return BOOLEAN;
}
if (!strcmp(q,"default")) {
yylval.addrmask.mask = 0;
yylval.addrmask.addr = 0;
return ADDRMASK;
}
if (sscanf(q,"%[.0-9]/%d%c",s1,&n,s2) == 2) {
if ((addr = inet_parse(s1)) != 0xffffffff) {
if ((addr = inet_parse(s1,1)) != 0xffffffff) {
yylval.addrmask.mask = n;
yylval.addrmask.addr = addr;
return ADDRMASK;
@ -537,7 +843,7 @@ yylex()
/* fall through to returning STRING */
}
if (sscanf(q,"%[.0-9]%c",s1,s2) == 1) {
if ((addr = inet_parse(s1)) != 0xffffffff &&
if ((addr = inet_parse(s1,4)) != 0xffffffff &&
inet_valid_host(addr)) {
yylval.addr = addr;
return ADDR;
@ -552,14 +858,6 @@ yylex()
return NUMBER;
}
#ifdef SNMP
if (!strcmp(q,"sysName"))
return SYSNAM;
if (!strcmp(q,"sysContact"))
return SYSCONTACT;
if (!strcmp(q,"sysVersion"))
return SYSVERSION;
if (!strcmp(q,"sysLocation"))
return SYSLOCATION;
if (*q=='"') {
if (q[ strlen(q)-1 ]=='"')
q[ strlen(q)-1 ]='\0'; /* trash trailing quote */
@ -574,9 +872,8 @@ yylex()
void
config_vifs_from_file()
{
extern FILE *f;
order = 0;
state = 0;
numbounds = 0;
lineno = 0;
@ -586,11 +883,6 @@ config_vifs_from_file()
return;
}
ifc.ifc_buf = (char *)ifbuf;
ifc.ifc_len = sizeof(ifbuf);
if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
yyparse();
fclose(f);
@ -623,7 +915,7 @@ ifconfaddr(ifcp, a)
if (ifrp->ifr_addr.sa_family == AF_INET &&
((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr == a)
return (ifrp);
#if (defined(BSD) && (BSD >= 199006))
#ifdef HAVE_SA_LEN
n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
if (n < sizeof(*ifrp))
++ifrp;

View File

@ -7,12 +7,18 @@
* Leland Stanford Junior University.
*
*
* $Id: config.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
* config.c,v 3.8.4.10 1998/01/06 01:57:41 fenner Exp
*/
#include "defs.h"
#ifndef lint
static char rcsid[] = "@(#) $Id: \
config.c,v 3.8.4.10 1998/01/06 01:57:41 fenner Exp $";
#endif
struct ifconf ifc;
/*
* Query the kernel to find network interfaces that are multicast-capable
@ -21,28 +27,48 @@
void
config_vifs_from_kernel()
{
struct ifreq ifbuf[32];
struct ifreq *ifrp, *ifend;
struct ifconf ifc;
register struct uvif *v;
register vifi_t vifi;
int n;
u_int32 addr, mask, subnet;
short flags;
int num_ifreq = 32;
ifc.ifc_buf = (char *)ifbuf;
ifc.ifc_len = sizeof(ifbuf);
if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
ifc.ifc_len = num_ifreq * sizeof(struct ifreq);
ifc.ifc_buf = malloc(ifc.ifc_len);
while (ifc.ifc_buf) {
if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
ifrp = (struct ifreq *)ifbuf;
ifend = (struct ifreq *)((char *)ifbuf + ifc.ifc_len);
/*
* If the buffer was large enough to hold all the addresses
* then break out, otherwise increase the buffer size and
* try again.
*
* The only way to know that we definitely had enough space
* is to know that there was enough space for at least one
* more struct ifreq. ???
*/
if ((num_ifreq * sizeof(struct ifreq)) >=
ifc.ifc_len + sizeof(struct ifreq))
break;
num_ifreq *= 2;
ifc.ifc_len = num_ifreq * sizeof(struct ifreq);
ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len);
}
if (ifc.ifc_buf == NULL)
log(LOG_ERR, 0, "config_vifs_from_kernel: ran out of memory");
ifrp = (struct ifreq *)ifc.ifc_buf;
ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len);
/*
* Loop through all of the interfaces.
*/
for (; ifrp < ifend; ifrp = (struct ifreq *)((char *)ifrp + n)) {
struct ifreq ifr;
#if BSD >= 199006
#ifdef HAVE_SA_LEN
n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
if (n < sizeof(*ifrp))
n = sizeof(*ifrp);
@ -97,6 +123,12 @@ config_vifs_from_kernel()
* one already installed in the uvifs array.
*/
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
if (strcmp(v->uv_name, ifr.ifr_name) == 0) {
log(LOG_DEBUG, 0, "skipping %s (%s on subnet %s) (alias for vif#%u?)",
v->uv_name, inet_fmt(addr, s1),
inet_fmts(subnet, mask, s2), vifi);
break;
}
if ((addr & v->uv_subnetmask) == v->uv_subnet ||
(v->uv_subnet & mask) == subnet) {
log(LOG_WARNING, 0, "ignoring %s, same subnet as %s",
@ -114,20 +146,15 @@ config_vifs_from_kernel()
continue;
}
v = &uvifs[numvifs];
v->uv_flags = 0;
v->uv_metric = DEFAULT_METRIC;
v->uv_rate_limit = DEFAULT_PHY_RATE_LIMIT;
v->uv_threshold = DEFAULT_THRESHOLD;
zero_vif(v, 0);
v->uv_lcl_addr = addr;
v->uv_rmt_addr = 0;
v->uv_subnet = subnet;
v->uv_subnetmask = mask;
v->uv_subnetbcast = subnet | ~mask;
strncpy(v->uv_name, ifr.ifr_name, IFNAMSIZ);
v->uv_groups = NULL;
v->uv_neighbors = NULL;
v->uv_acl = NULL;
v->uv_addrs = NULL;
if (flags & IFF_POINTOPOINT)
v->uv_flags |= VIFF_REXMIT_PRUNES;
log(LOG_INFO,0,"installing %s (%s on subnet %s) as vif #%u - rate=%d",
v->uv_name, inet_fmt(addr, s1), inet_fmts(subnet, mask, s2),

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: defs.h,v 3.8 1995/11/29 22:36:34 fenner Rel $
* defs.h,v 3.8.4.15 1998/03/01 02:51:42 fenner Exp
*/
@ -26,12 +26,25 @@
#ifdef SYSV
#include <sys/sockio.h>
#endif
#ifdef _AIX
#include <time.h>
#endif
#include <sys/time.h>
#include <sys/uio.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/igmp.h>
#ifdef __FreeBSD__ /* sigh */
#include <osreldate.h>
#if __FreeBSD_version >= 220000
#define rtentry kernel_rtentry
#include <net/route.h>
#undef rtentry
#endif
#endif
#include <netinet/ip_mroute.h>
#ifdef RSRR
#include <sys/un.h>
@ -52,6 +65,7 @@ typedef void (*cfunc_t) __P((void *));
typedef void (*ihfunc_t) __P((int, fd_set *));
#include "dvmrp.h"
#include "igmpv2.h"
#include "vif.h"
#include "route.h"
#include "prune.h"
@ -71,21 +85,17 @@ typedef void (*ihfunc_t) __P((int, fd_set *));
#define TIMER_INTERVAL ROUTE_MAX_REPORT_DELAY
#define VENDOR_CODE 1 /* Get a new vendor code if you make significant
* changes to mrouted. */
#define PROTOCOL_VERSION 3 /* increment when packet format/content changes */
#define MROUTED_VERSION 9 /* not in DVMRP packets at all */
#define MROUTED_VERSION 8 /* increment on local changes or bug fixes, */
/* reset to 0 whever PROTOCOL_VERSION increments */
#define DVMRP_CONSTANT 0x000eff00 /* constant portion of 'group' field */
#define MROUTED_LEVEL ((MROUTED_VERSION << 8) | PROTOCOL_VERSION | \
((NF_PRUNE | NF_GENID | NF_MTRACE) << 16) | \
(VENDOR_CODE << 24))
#define MROUTED_LEVEL (DVMRP_CONSTANT | PROTOCOL_VERSION)
/* for IGMP 'group' field of DVMRP messages */
#define LEAF_FLAGS (( vifs_with_neighbors == 1 ) ? 0x010000 : 0)
/* more for IGMP 'group' field of DVMRP messages */
#define DEL_RTE_GROUP 0
#define DEL_ALL_ROUTES 1
/* for Deleting kernel table entries */
@ -109,7 +119,10 @@ typedef void (*ihfunc_t) __P((int, fd_set *));
#define bcopy(a, b, c) memcpy(b, a, c)
#define bzero(s, n) memset((s), 0, (n))
#define setlinebuf(s) setvbuf(s, NULL, _IOLBF, 0)
#define signal(s,f) sigset(s,f)
#endif
#if defined(_AIX) || (defined(BSD) && (BSD >= 199103))
#define HAVE_SA_LEN
#endif
/*
@ -127,10 +140,27 @@ extern u_int32 allrtrs_group;
extern u_int32 dvmrp_group;
extern u_int32 dvmrp_genid;
#define DEFAULT_DEBUG 2 /* default if "-d" given without value */
#define IF_DEBUG(l) if (debug && debug & (l))
#define DEBUG_PKT 0x0001
#define DEBUG_PRUNE 0x0002
#define DEBUG_ROUTE 0x0004
#define DEBUG_PEER 0x0008
#define DEBUG_CACHE 0x0010
#define DEBUG_TIMEOUT 0x0020
#define DEBUG_IF 0x0040
#define DEBUG_MEMBER 0x0080
#define DEBUG_TRACE 0x0100
#define DEBUG_IGMP 0x0200
#define DEBUG_RTDETAIL 0x0400
#define DEBUG_KERN 0x0800
#define DEBUG_RSRR 0x1000
#define DEBUG_ICMP 0x2000
#define DEFAULT_DEBUG 0x02de /* default if "-d" given without value */
extern int debug;
extern u_char pruning;
extern int did_final_init;
extern int routes_changed;
extern int delay_change_reports;
@ -160,81 +190,134 @@ extern char * sys_errlist[];
#define MRT_DEL_VIF DVMRP_DEL_VIF
#define MRT_ADD_MFC DVMRP_ADD_MFC
#define MRT_DEL_MFC DVMRP_DEL_MFC
#endif
#ifndef IGMP_PIM
#define IGMP_PIM 0x14
#endif
#ifndef IPPROTO_IPIP
#define IPPROTO_IPIP 4
#endif
/*
* The original multicast releases defined
* IGMP_HOST_{MEMBERSHIP_QUERY,MEMBERSHIP_REPORT,NEW_MEMBERSHIP_REPORT
* ,LEAVE_MESSAGE}. Later releases removed the HOST and inserted
* the IGMP version number. NetBSD inserted the version number in
* a different way. mrouted uses the new names, so we #define them
* to the old ones if needed.
*/
#if !defined(IGMP_MEMBERSHIP_QUERY) && defined(IGMP_HOST_MEMBERSHIP_QUERY)
#define IGMP_MEMBERSHIP_QUERY IGMP_HOST_MEMBERSHIP_QUERY
#define IGMP_V2_LEAVE_GROUP IGMP_HOST_LEAVE_MESSAGE
#endif
#ifndef IGMP_V1_MEMBERSHIP_REPORT
#ifdef IGMP_HOST_MEMBERSHIP_REPORT
#define IGMP_V1_MEMBERSHIP_REPORT IGMP_HOST_MEMBERSHIP_REPORT
#define IGMP_V2_MEMBERSHIP_REPORT IGMP_HOST_NEW_MEMBERSHIP_REPORT
#endif
#ifdef IGMP_v1_HOST_MEMBERSHIP_REPORT
#define IGMP_V1_MEMBERSHIP_REPORT IGMP_v1_HOST_MEMBERSHIP_REPORT
#define IGMP_V2_MEMBERSHIP_REPORT IGMP_v2_HOST_MEMBERSHIP_REPORT
#endif
#endif
/*
* NetBSD also renamed the mtrace types.
*/
#if !defined(IGMP_MTRACE_RESP) && defined(IGMP_MTRACE_REPLY)
#define IGMP_MTRACE_RESP IGMP_MTRACE_REPLY
#define IGMP_MTRACE IGMP_MTRACE_QUERY
#endif
/* main.c */
extern char * scaletime __P((u_long));
extern void log __P((int, int, char *, ...));
extern int register_input_handler __P((int fd, ihfunc_t func));
extern int register_input_handler __P((int, ihfunc_t));
/* igmp.c */
extern void init_igmp __P((void));
extern void accept_igmp __P((int recvlen));
extern void send_igmp __P((u_int32 src, u_int32 dst, int type,
int code, u_int32 group,
int datalen));
extern void accept_igmp __P((int));
extern void build_igmp __P((u_int32, u_int32, int, int, u_int32,
int));
extern void send_igmp __P((u_int32, u_int32, int, int, u_int32,
int));
extern char * igmp_packet_kind __P((u_int, u_int));
extern int igmp_debug_kind __P((u_int, u_int));
/* icmp.c */
extern void init_icmp __P((void));
/* ipip.c */
extern void init_ipip __P((void));
extern void init_ipip_on_vif __P((struct uvif *));
extern void send_ipip __P((u_int32, u_int32, int, int, u_int32,
int, struct uvif *));
/* callout.c */
extern void callout_init __P((void));
extern void age_callout_queue __P((void));
extern int timer_setTimer __P((int delay, cfunc_t action,
char *data));
extern void timer_clearTimer __P((int timer_id));
extern void free_all_callouts __P((void));
extern void age_callout_queue __P((int));
extern int timer_nextTimer __P((void));
extern int timer_setTimer __P((int, cfunc_t, void *));
extern int timer_clearTimer __P((int));
extern int timer_leftTimer __P((int));
/* route.c */
extern void init_routes __P((void));
extern void start_route_updates __P((void));
extern void update_route __P((u_int32 origin, u_int32 mask,
u_int metric, u_int32 src,
vifi_t vifi));
extern void update_route __P((u_int32, u_int32, u_int, u_int32,
vifi_t, struct listaddr *));
extern void age_routes __P((void));
extern void expire_all_routes __P((void));
extern void free_all_routes __P((void));
extern void accept_probe __P((u_int32 src, u_int32 dst,
char *p, int datalen,
u_int32 level));
extern void accept_report __P((u_int32 src, u_int32 dst,
char *p, int datalen,
u_int32 level));
extern void accept_probe __P((u_int32, u_int32, char *, int,
u_int32));
extern void accept_report __P((u_int32, u_int32, char *, int,
u_int32));
extern struct rtentry * determine_route __P((u_int32 src));
extern void report __P((int which_routes, vifi_t vifi,
u_int32 dst));
extern void report_to_all_neighbors __P((int which_routes));
extern void report __P((int, vifi_t, u_int32));
extern void report_to_all_neighbors __P((int));
extern int report_next_chunk __P((void));
extern void add_vif_to_routes __P((vifi_t vifi));
extern void delete_vif_from_routes __P((vifi_t vifi));
extern void delete_neighbor_from_routes __P((u_int32 addr,
vifi_t vifi));
extern void blaster_alloc __P((vifi_t));
extern void add_vif_to_routes __P((vifi_t));
extern void delete_vif_from_routes __P((vifi_t));
extern void add_neighbor_to_routes __P((vifi_t, int));
extern void delete_neighbor_from_routes __P((u_int32,
vifi_t, int));
extern void dump_routes __P((FILE *fp));
extern void start_route_updates __P((void));
/* vif.c */
extern void init_vifs __P((void));
extern void zero_vif __P((struct uvif *, int));
extern void init_installvifs __P((void));
extern void check_vif_state __P((void));
extern vifi_t find_vif __P((u_int32 src, u_int32 dst));
extern void send_on_vif __P((struct uvif *, u_int32, int, int));
extern vifi_t find_vif __P((u_int32, u_int32));
extern void age_vifs __P((void));
extern void dump_vifs __P((FILE *fp));
extern void dump_vifs __P((FILE *));
extern void stop_all_vifs __P((void));
extern struct listaddr *neighbor_info __P((vifi_t vifi, u_int32 addr));
extern void accept_group_report __P((u_int32 src, u_int32 dst,
u_int32 group, int r_type));
extern struct listaddr *neighbor_info __P((vifi_t, u_int32));
extern void accept_group_report __P((u_int32, u_int32,
u_int32, int));
extern void query_groups __P((void));
extern void probe_for_neighbors __P((void));
extern int update_neighbor __P((vifi_t vifi, u_int32 addr,
int msgtype, char *p, int datalen,
u_int32 level));
extern void accept_neighbor_request __P((u_int32 src, u_int32 dst));
extern void accept_neighbor_request2 __P((u_int32 src,
u_int32 dst));
extern void accept_neighbors __P((u_int32 src, u_int32 dst,
u_char *p, int datalen, u_int32 level));
extern void accept_neighbors2 __P((u_int32 src, u_int32 dst,
u_char *p, int datalen, u_int32 level));
extern void accept_leave_message __P((u_int32 src, u_int32 dst,
u_int32 group));
extern void accept_membership_query __P((u_int32 src, u_int32 dst,
u_int32 group, int tmo));
extern struct listaddr *update_neighbor __P((vifi_t, u_int32, int, char *, int,
u_int32));
extern void accept_neighbor_request __P((u_int32, u_int32));
extern void accept_neighbor_request2 __P((u_int32, u_int32));
extern void accept_info_request __P((u_int32, u_int32,
u_char *, int));
extern void accept_info_reply __P((u_int32, u_int32,
u_char *, int));
extern void accept_neighbors __P((u_int32, u_int32,
u_char *, int, u_int32));
extern void accept_neighbors2 __P((u_int32, u_int32,
u_char *, int, u_int32));
extern void accept_leave_message __P((u_int32, u_int32,
u_int32));
extern void accept_membership_query __P((u_int32, u_int32,
u_int32, int));
/* config.c */
extern void config_vifs_from_kernel __P((void));
@ -243,75 +326,84 @@ extern void config_vifs_from_kernel __P((void));
extern void config_vifs_from_file __P((void));
/* inet.c */
extern int inet_valid_host __P((u_int32 naddr));
extern int inet_valid_subnet __P((u_int32 nsubnet, u_int32 nmask));
extern char * inet_fmt __P((u_int32 addr, char *s));
extern char * inet_fmts __P((u_int32 addr, u_int32 mask, char *s));
extern u_int32 inet_parse __P((char *s));
extern int inet_cksum __P((u_short *addr, u_int len));
extern int inet_valid_host __P((u_int32));
extern int inet_valid_mask __P((u_int32));
extern int inet_valid_subnet __P((u_int32, u_int32));
extern char * inet_fmt __P((u_int32, char *));
extern char * inet_fmts __P((u_int32, u_int32, char *));
extern u_int32 inet_parse __P((char *, int));
extern int inet_cksum __P((u_short *, u_int));
/* prune.c */
extern unsigned kroutes;
extern void add_table_entry __P((u_int32 origin, u_int32 mcastgrp));
extern void del_table_entry __P((struct rtentry *r,
u_int32 mcastgrp, u_int del_flag));
extern void update_table_entry __P((struct rtentry *r));
extern void determine_forwvifs __P((struct gtable *));
extern void send_prune_or_graft __P((struct gtable *));
extern void add_table_entry __P((u_int32, u_int32));
extern void del_table_entry __P((struct rtentry *,
u_int32, u_int));
extern void update_table_entry __P((struct rtentry *, u_int32));
extern int find_src_grp __P((u_int32, u_int32, u_int32));
extern void init_ktable __P((void));
extern void accept_prune __P((u_int32 src, u_int32 dst, char *p,
int datalen));
extern void steal_sources __P((struct rtentry *rt));
extern void reset_neighbor_state __P((vifi_t vifi, u_int32 addr));
extern int grplst_mem __P((vifi_t vifi, u_int32 mcastgrp));
extern int scoped_addr __P((vifi_t vifi, u_int32 addr));
extern void steal_sources __P((struct rtentry *));
extern void reset_neighbor_state __P((vifi_t, u_int32));
extern int grplst_mem __P((vifi_t, u_int32));
extern void free_all_prunes __P((void));
extern void age_table_entry __P((void));
extern void dump_cache __P((FILE *fp2));
extern void update_lclgrp __P((vifi_t vifi, u_int32 mcastgrp));
extern void delete_lclgrp __P((vifi_t vifi, u_int32 mcastgrp));
extern void chkgrp_graft __P((vifi_t vifi, u_int32 mcastgrp));
extern void accept_graft __P((u_int32 src, u_int32 dst, char *p,
int datalen));
extern void accept_g_ack __P((u_int32 src, u_int32 dst, char *p,
int datalen));
extern void dump_cache __P((FILE *));
extern void update_lclgrp __P((vifi_t, u_int32));
extern void delete_lclgrp __P((vifi_t, u_int32));
extern void chkgrp_graft __P((vifi_t, u_int32));
extern void accept_prune __P((u_int32, u_int32, char *, int));
extern void accept_graft __P((u_int32, u_int32, char *, int));
extern void accept_g_ack __P((u_int32, u_int32, char *, int));
/* u_int is promoted u_char */
extern void accept_mtrace __P((u_int32 src, u_int32 dst,
u_int32 group, char *data, u_int no,
int datalen));
extern void accept_mtrace __P((u_int32, u_int32,
u_int32, char *, u_int, int));
/* kern.c */
extern void k_set_rcvbuf __P((int bufsize));
extern void k_hdr_include __P((int bool));
extern void k_set_ttl __P((int t));
extern void k_set_loop __P((int l));
extern void k_set_if __P((u_int32 ifa));
extern void k_join __P((u_int32 grp, u_int32 ifa));
extern void k_leave __P((u_int32 grp, u_int32 ifa));
extern void k_set_rcvbuf __P((int, int));
extern void k_hdr_include __P((int));
extern void k_set_ttl __P((int));
extern void k_set_loop __P((int));
extern void k_set_if __P((u_int32));
extern void k_join __P((u_int32, u_int32));
extern void k_leave __P((u_int32, u_int32));
extern void k_init_dvmrp __P((void));
extern void k_stop_dvmrp __P((void));
extern void k_add_vif __P((vifi_t vifi, struct uvif *v));
extern void k_del_vif __P((vifi_t vifi));
extern void k_add_rg __P((u_int32 origin, struct gtable *g));
extern int k_del_rg __P((u_int32 origin, struct gtable *g));
extern void k_add_vif __P((vifi_t, struct uvif *));
extern void k_del_vif __P((vifi_t));
extern void k_add_rg __P((u_int32, struct gtable *));
extern int k_del_rg __P((u_int32, struct gtable *));
extern int k_get_version __P((void));
#ifdef SNMP
/* prune.c */
extern struct rtentry * snmp_find_route __P(());
extern struct gtable * find_grp __P(());
extern struct stable * find_grp_src __P(());
extern struct gtable * find_grp __P((u_int32));
extern struct stable * find_grp_src __P((struct gtable *, u_int32));
extern int next_grp_src_mask __P((struct gtable **,
struct stable **, u_int32,
u_int32, u_int32));
extern void refresh_sg __P((struct sioc_sg_req *, struct gtable *,
struct stable *));
extern int next_child __P((struct gtable **, struct stable **,
u_int32, u_int32, u_int32,
vifi_t *));
/* route.c */
extern struct rtentry * snmp_find_route __P((u_int32, u_int32));
extern int next_route __P((struct rtentry **, u_int32, u_int32));
extern int next_route_child __P((struct rtentry **,
u_int32, u_int32, vifi_t *));
#endif
#ifdef RSRR
/* prune.c */
extern struct gtable *kernel_table;
extern struct gtable *gtp;
extern int find_src_grp __P((u_int32 src, u_int32 mask,
u_int32 grp));
/* rsrr.c */
extern void rsrr_init __P((void));
extern void rsrr_read __P((int f, fd_set *rfd));
extern void rsrr_clean __P((void));
extern void rsrr_cache_send __P((struct gtable *gt, int notify));
extern void rsrr_cache_clean __P((struct gtable *gt));
extern void rsrr_cache_send __P((struct gtable *, int));
extern void rsrr_cache_clean __P((struct gtable *));
#endif /* RSRR */

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: dvmrp.h,v 3.8 1995/11/29 22:36:57 fenner Rel $
* dvmrp.h,v 3.8.4.5 1997/11/18 23:25:57 fenner Exp
*/
/*
@ -152,13 +152,8 @@
#define LEAF_CONFIRMATION_TIME 200 /* time to consider subnet a leaf */
#define NEIGHBOR_PROBE_INTERVAL 10 /* periodic neighbor probe interval */
#define NEIGHBOR_EXPIRE_TIME 140 /* time to consider neighbor gone */
#define GROUP_QUERY_INTERVAL 125 /* periodic group query interval */
#define GROUP_EXPIRE_TIME 270 /* time to consider group gone */
#define LEAVE_EXPIRE_TIME 3 /* " " after receiving a leave */
/* Note: LEAVE_EXPIRE_TIME should ideally be shorter, but the resolution of
* the timer in mrouted doesn't allow us to make it any shorter. */
#define NEIGHBOR_EXPIRE_TIME 30 /* time to consider neighbor gone */
#define OLD_NEIGHBOR_EXPIRE_TIME 140 /* time to consider neighbor gone */
#define UNREACHABLE 32 /* "infinity" metric, must be <= 64 */
#define DEFAULT_METRIC 1 /* default subnet/tunnel metric */
@ -166,9 +161,11 @@
#define MAX_RATE_LIMIT 100000 /* max rate limit */
#define DEFAULT_PHY_RATE_LIMIT 0 /* default phyint rate limit */
#define DEFAULT_TUN_RATE_LIMIT 500 /* default tunnel rate limit */
#define DEFAULT_TUN_RATE_LIMIT 0 /* default tunnel rate limit */
#define DEFAULT_CACHE_LIFETIME 300 /* kernel route entry discard time */
#define MIN_CACHE_LIFETIME 60 /* minimum allowed cache lifetime */
#define AVERAGE_PRUNE_LIFETIME 7200 /* average lifetime of prunes sent */
#define MIN_PRUNE_LIFETIME 120 /* minimum allowed prune lifetime */
#define GRAFT_TIMEOUT_VAL 5 /* retransmission time for grafts */
#define OLD_AGE_THRESHOLD 2
#define PRUNE_REXMIT_VAL 3 /* initial time for prune rexmission*/

225
usr.sbin/mrouted/icmp.c Normal file
View File

@ -0,0 +1,225 @@
/*
* The mrouted program is covered by the license in the accompanying file
* named "LICENSE". Use of the mrouted program represents acceptance of
* the terms and conditions listed in that file.
*
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
* Leland Stanford Junior University.
*
*
* icmp.c,v 3.8.4.2 1998/01/06 01:57:42 fenner Exp
*/
#include "defs.h"
#ifndef lint
static char rcsid[] = "@(#) $Id: \
icmp.c,v 3.8.4.2 1998/01/06 01:57:42 fenner Exp $";
#endif
static int icmp_socket;
static void icmp_handler __P((int, fd_set *));
static char * icmp_name __P((struct icmp *));
void
init_icmp()
{
if ((icmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
log(LOG_ERR, errno, "ICMP socket");
register_input_handler(icmp_socket, icmp_handler);
IF_DEBUG(DEBUG_ICMP)
log(LOG_DEBUG, 0, "registering icmp socket fd %d\n", icmp_socket);
}
static void
icmp_handler(fd, rfds)
int fd;
fd_set *rfds;
{
u_char icmp_buf[RECV_BUF_SIZE];
struct sockaddr_in from;
int fromlen, recvlen, iphdrlen, ipdatalen;
struct icmp *icmp;
struct ip *ip;
vifi_t i;
struct uvif *v;
u_int32 src;
fromlen = sizeof(from);
recvlen = recvfrom(icmp_socket, icmp_buf, RECV_BUF_SIZE, 0,
(struct sockaddr *)&from, &fromlen);
if (recvlen < 0) {
if (errno != EINTR)
log(LOG_WARNING, errno, "icmp_socket recvfrom");
return;
}
ip = (struct ip *)icmp_buf;
iphdrlen = ip->ip_hl << 2;
#ifdef RAW_INPUT_IS_RAW
ipdatalen = ntohs(ip->ip_len) - iphdrlen;
#else
ipdatalen = ip->ip_len;
#endif
if (iphdrlen + ipdatalen != recvlen) {
IF_DEBUG(DEBUG_ICMP)
log(LOG_DEBUG, 0, "hdr %d data %d != rcv %d", iphdrlen, ipdatalen, recvlen);
/* Malformed ICMP, just return. */
return;
}
if (ipdatalen < ICMP_MINLEN + sizeof(struct ip)) {
/* Not enough data for us to be interested in it. */
return;
}
src = ip->ip_src.s_addr;
icmp = (struct icmp *)(icmp_buf + iphdrlen);
IF_DEBUG(DEBUG_ICMP)
log(LOG_DEBUG, 0, "got ICMP type %d from %s",
icmp->icmp_type, inet_fmt(src, s1));
/*
* Eventually:
* have registry of ICMP listeners, by type, code and ICMP_ID
* (and maybe fields of the original packet too -- maybe need a
* generalized packet filter!) to allow ping and traceroute
* from the monitoring tool.
*/
switch (icmp->icmp_type) {
case ICMP_UNREACH:
case ICMP_TIMXCEED:
/* Look at returned packet to see if it's us sending on a tunnel */
ip = &icmp->icmp_ip;
if (ip->ip_p != IPPROTO_IGMP && ip->ip_p != IPPROTO_IPIP)
return;
for (v = uvifs, i = 0; i < numvifs; v++, i++) {
if (ip->ip_src.s_addr == v->uv_lcl_addr &&
ip->ip_dst.s_addr == v->uv_dst_addr) {
char *p;
int n;
/*
* I sent this packet on this vif.
*/
n = ++v->uv_icmp_warn;
while (n && !(n & 1))
n >>= 1;
if (n == 1 && ((p = icmp_name(icmp)) != NULL))
log(LOG_WARNING, 0, "Received ICMP %s from %s %s %s on vif %d",
p, inet_fmt(src, s1), "for traffic sent to",
inet_fmt(ip->ip_dst.s_addr, s2),
i);
break;
}
}
break;
}
}
/*
* Return NULL for ICMP informational messages.
* Return string describing the error for ICMP errors.
*/
static char *
icmp_name(icmp)
struct icmp *icmp;
{
static char retval[30];
switch (icmp->icmp_type) {
case ICMP_UNREACH:
switch (icmp->icmp_code) {
case ICMP_UNREACH_NET:
return "network unreachable";
case ICMP_UNREACH_HOST:
return "host unreachable";
case ICMP_UNREACH_PROTOCOL:
return "protocol unreachable";
case ICMP_UNREACH_PORT:
return "port unreachable";
case ICMP_UNREACH_NEEDFRAG:
return "needs fragmentation";
case ICMP_UNREACH_SRCFAIL:
return "source route failed";
#ifndef ICMP_UNREACH_NET_UNKNOWN
#define ICMP_UNREACH_NET_UNKNOWN 6
#endif
case ICMP_UNREACH_NET_UNKNOWN:
return "network unknown";
#ifndef ICMP_UNREACH_HOST_UNKNOWN
#define ICMP_UNREACH_HOST_UNKNOWN 7
#endif
case ICMP_UNREACH_HOST_UNKNOWN:
return "host unknown";
#ifndef ICMP_UNREACH_ISOLATED
#define ICMP_UNREACH_ISOLATED 8
#endif
case ICMP_UNREACH_ISOLATED:
return "source host isolated";
#ifndef ICMP_UNREACH_NET_PROHIB
#define ICMP_UNREACH_NET_PROHIB 9
#endif
case ICMP_UNREACH_NET_PROHIB:
return "network access prohibited";
#ifndef ICMP_UNREACH_HOST_PROHIB
#define ICMP_UNREACH_HOST_PROHIB 10
#endif
case ICMP_UNREACH_HOST_PROHIB:
return "host access prohibited";
#ifndef ICMP_UNREACH_TOSNET
#define ICMP_UNREACH_TOSNET 11
#endif
case ICMP_UNREACH_TOSNET:
return "bad TOS for net";
#ifndef ICMP_UNREACH_TOSHOST
#define ICMP_UNREACH_TOSHOST 12
#endif
case ICMP_UNREACH_TOSHOST:
return "bad TOS for host";
#ifndef ICMP_UNREACH_FILTER_PROHIB
#define ICMP_UNREACH_FILTER_PROHIB 13
#endif
case ICMP_UNREACH_FILTER_PROHIB:
return "prohibited by filter";
#ifndef ICMP_UNREACH_HOST_PRECEDENCE
#define ICMP_UNREACH_HOST_PRECEDENCE 14
#endif
case ICMP_UNREACH_HOST_PRECEDENCE:
return "host precedence violation";
#ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF
#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15
#endif
case ICMP_UNREACH_PRECEDENCE_CUTOFF:
return "precedence cutoff";
default:
sprintf(retval, "unreachable code %d", icmp->icmp_code);
return retval;
}
case ICMP_SOURCEQUENCH:
return "source quench";
case ICMP_REDIRECT:
return NULL; /* XXX */
case ICMP_TIMXCEED:
switch (icmp->icmp_code) {
case ICMP_TIMXCEED_INTRANS:
return "time exceeded in transit";
case ICMP_TIMXCEED_REASS:
return "time exceeded in reassembly";
default:
sprintf(retval, "time exceeded code %d", icmp->icmp_code);
return retval;
}
case ICMP_PARAMPROB:
switch (icmp->icmp_code) {
#ifndef ICMP_PARAMPROB_OPTABSENT
#define ICMP_PARAMPROB_OPTABSENT 1
#endif
case ICMP_PARAMPROB_OPTABSENT:
return "required option absent";
default:
sprintf(retval, "parameter problem code %d", icmp->icmp_code);
return retval;
}
}
return NULL;
}

View File

@ -7,12 +7,16 @@
* Leland Stanford Junior University.
*
*
* $Id: igmp.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
* igmp.c,v 3.8.4.19 1998/01/06 01:57:43 fenner Exp
*/
#include "defs.h"
#ifndef lint
static char rcsid[] = "@(#) $Id: \
igmp.c,v 3.8.4.19 1998/01/06 01:57:43 fenner Exp $";
#endif
/*
* Exported variables.
@ -29,7 +33,6 @@ u_int32 dvmrp_genid; /* IGMP generation id */
* Local function definitions.
*/
/* u_char promoted to u_int */
static char * packet_kind __P((u_int type, u_int code));
static int igmp_log_level __P((u_int type, u_int code));
/*
@ -48,17 +51,23 @@ init_igmp()
log(LOG_ERR, errno, "IGMP socket");
k_hdr_include(TRUE); /* include IP header when sending */
k_set_rcvbuf(48*1024); /* lots of input buffering */
k_set_rcvbuf(256*1024,48*1024); /* lots of input buffering */
k_set_ttl(1); /* restrict multicasts to one hop */
k_set_loop(FALSE); /* disable multicast loopback */
ip = (struct ip *)send_buf;
ip->ip_hl = sizeof(struct ip) >> 2;
bzero(ip, sizeof(struct ip));
/*
* Fields zeroed that aren't filled in later:
* - IP ID (let the kernel fill it in)
* - Offset (we don't send fragments)
* - Checksum (let the kernel fill it in)
*/
ip->ip_v = IPVERSION;
ip->ip_tos = 0;
ip->ip_off = 0;
ip->ip_p = IPPROTO_IGMP;
ip->ip_hl = sizeof(struct ip) >> 2;
ip->ip_tos = 0xc0; /* Internet Control */
ip->ip_ttl = MAXTTL; /* applies to unicasts only */
ip->ip_p = IPPROTO_IGMP;
allhosts_group = htonl(INADDR_ALLHOSTS_GROUP);
dvmrp_group = htonl(INADDR_DVMRP_GROUP);
@ -74,29 +83,33 @@ init_igmp()
#define PIM_GRAFT 6
#define PIM_GRAFT_ACK 7
static char *
packet_kind(type, code)
char *
igmp_packet_kind(type, code)
u_int type, code;
{
static char unknown[20];
switch (type) {
case IGMP_HOST_MEMBERSHIP_QUERY: return "membership query ";
case IGMP_HOST_MEMBERSHIP_REPORT: return "membership report ";
case IGMP_HOST_NEW_MEMBERSHIP_REPORT: return "new member report ";
case IGMP_HOST_LEAVE_MESSAGE: return "leave message ";
case IGMP_MEMBERSHIP_QUERY: return "membership query ";
case IGMP_V1_MEMBERSHIP_REPORT: return "V1 member report ";
case IGMP_V2_MEMBERSHIP_REPORT: return "V2 member report ";
case IGMP_V2_LEAVE_GROUP: return "leave message ";
case IGMP_DVMRP:
switch (code) {
case DVMRP_PROBE: return "neighbor probe ";
case DVMRP_REPORT: return "route report ";
case DVMRP_ASK_NEIGHBORS: return "neighbor request ";
case DVMRP_NEIGHBORS: return "neighbor list ";
case DVMRP_ASK_NEIGHBORS2: return "neighbor request 2";
case DVMRP_NEIGHBORS2: return "neighbor list 2 ";
case DVMRP_PROBE: return "neighbor probe ";
case DVMRP_REPORT: return "route report ";
case DVMRP_ASK_NEIGHBORS: return "neighbor request ";
case DVMRP_NEIGHBORS: return "neighbor list ";
case DVMRP_ASK_NEIGHBORS2: return "neighbor request 2";
case DVMRP_NEIGHBORS2: return "neighbor list 2 ";
case DVMRP_PRUNE: return "prune message ";
case DVMRP_GRAFT: return "graft message ";
case DVMRP_GRAFT_ACK: return "graft message ack ";
case DVMRP_INFO_REQUEST: return "info request ";
case DVMRP_INFO_REPLY: return "info reply ";
default: return "unknown DVMRP msg ";
default:
sprintf(unknown, "unknown DVMRP %3d ", code);
return unknown;
}
case IGMP_PIM:
switch (code) {
@ -108,11 +121,57 @@ packet_kind(type, code)
case PIM_ASSERT: return "PIM Assert ";
case PIM_GRAFT: return "PIM Graft ";
case PIM_GRAFT_ACK: return "PIM Graft-Ack ";
default: return "unknown PIM msg ";
default:
sprintf(unknown, "unknown PIM msg%3d", code);
return unknown;
}
case IGMP_MTRACE: return "IGMP trace query ";
case IGMP_MTRACE_RESP: return "IGMP trace reply ";
default: return "unknown IGMP msg ";
default:
sprintf(unknown, "unk: 0x%02x/0x%02x ", type, code);
return unknown;
}
}
int
igmp_debug_kind(type, code)
u_int type, code;
{
switch (type) {
case IGMP_MEMBERSHIP_QUERY: return DEBUG_IGMP;
case IGMP_V1_MEMBERSHIP_REPORT: return DEBUG_IGMP;
case IGMP_V2_MEMBERSHIP_REPORT: return DEBUG_IGMP;
case IGMP_V2_LEAVE_GROUP: return DEBUG_IGMP;
case IGMP_DVMRP:
switch (code) {
case DVMRP_PROBE: return DEBUG_PEER;
case DVMRP_REPORT: return DEBUG_ROUTE;
case DVMRP_ASK_NEIGHBORS: return 0;
case DVMRP_NEIGHBORS: return 0;
case DVMRP_ASK_NEIGHBORS2: return 0;
case DVMRP_NEIGHBORS2: return 0;
case DVMRP_PRUNE: return DEBUG_PRUNE;
case DVMRP_GRAFT: return DEBUG_PRUNE;
case DVMRP_GRAFT_ACK: return DEBUG_PRUNE;
case DVMRP_INFO_REQUEST: return 0;
case DVMRP_INFO_REPLY: return 0;
default: return 0;
}
case IGMP_PIM:
switch (code) {
case PIM_QUERY: return 0;
case PIM_REGISTER: return 0;
case PIM_REGISTER_STOP: return 0;
case PIM_JOIN_PRUNE: return 0;
case PIM_RP_REACHABLE: return 0;
case PIM_ASSERT: return 0;
case PIM_GRAFT: return 0;
case PIM_GRAFT_ACK: return 0;
default: return 0;
}
case IGMP_MTRACE: return DEBUG_TRACE;
case IGMP_MTRACE_RESP: return DEBUG_TRACE;
default: return DEBUG_IGMP;
}
}
@ -153,7 +212,11 @@ accept_igmp(recvlen)
}
iphdrlen = ip->ip_hl << 2;
#ifdef RAW_INPUT_IS_RAW
ipdatalen = ntohs(ip->ip_len) - iphdrlen;
#else
ipdatalen = ip->ip_len;
#endif
if (iphdrlen + ipdatalen != recvlen) {
log(LOG_WARNING, 0,
"received packet from %s shorter (%u bytes) than hdr+data length (%u+%u)",
@ -171,22 +234,23 @@ accept_igmp(recvlen)
return;
}
IF_DEBUG(DEBUG_PKT|igmp_debug_kind(igmp->igmp_type, igmp->igmp_code))
log(LOG_DEBUG, 0, "RECV %s from %-15s to %s",
packet_kind(igmp->igmp_type, igmp->igmp_code),
igmp_packet_kind(igmp->igmp_type, igmp->igmp_code),
inet_fmt(src, s1), inet_fmt(dst, s2));
switch (igmp->igmp_type) {
case IGMP_HOST_MEMBERSHIP_QUERY:
case IGMP_MEMBERSHIP_QUERY:
accept_membership_query(src, dst, group, igmp->igmp_code);
return;
case IGMP_HOST_MEMBERSHIP_REPORT:
case IGMP_HOST_NEW_MEMBERSHIP_REPORT:
case IGMP_V1_MEMBERSHIP_REPORT:
case IGMP_V2_MEMBERSHIP_REPORT:
accept_group_report(src, dst, group, igmp->igmp_type);
return;
case IGMP_HOST_LEAVE_MESSAGE:
case IGMP_V2_LEAVE_GROUP:
accept_leave_message(src, dst, group);
return;
@ -297,8 +361,45 @@ igmp_log_level(type, code)
/*
* Construct an IGMP message in the output packet buffer. The caller may
* have already placed data in that buffer, of length 'datalen'. Then send
* the message from the interface with IP address 'src' to destination 'dst'.
* have already placed data in that buffer, of length 'datalen'.
*/
void
build_igmp(src, dst, type, code, group, datalen)
u_int32 src, dst;
int type, code;
u_int32 group;
int datalen;
{
struct ip *ip;
struct igmp *igmp;
extern int curttl;
ip = (struct ip *)send_buf;
ip->ip_src.s_addr = src;
ip->ip_dst.s_addr = dst;
ip->ip_len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen;
#ifdef RAW_OUTPUT_IS_RAW
ip->ip_len = htons(ip->ip_len);
#endif
if (IN_MULTICAST(ntohl(dst))) {
ip->ip_ttl = curttl;
} else {
ip->ip_ttl = MAXTTL;
}
igmp = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN);
igmp->igmp_type = type;
igmp->igmp_code = code;
igmp->igmp_group.s_addr = group;
igmp->igmp_cksum = 0;
igmp->igmp_cksum = inet_cksum((u_short *)igmp,
IGMP_MINLEN + datalen);
}
/*
* Call build_igmp() to build an IGMP message in the output packet buffer.
* Then send the message from the interface with IP address 'src' to
* destination 'dst'.
*/
void
send_igmp(src, dst, type, code, group, datalen)
@ -308,26 +409,13 @@ send_igmp(src, dst, type, code, group, datalen)
int datalen;
{
struct sockaddr_in sdst;
struct ip *ip;
struct igmp *igmp;
int setloop;
int setloop = 0;
ip = (struct ip *)send_buf;
ip->ip_src.s_addr = src;
ip->ip_dst.s_addr = dst;
ip->ip_len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen;
igmp = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN);
igmp->igmp_type = type;
igmp->igmp_code = code;
igmp->igmp_group.s_addr = group;
igmp->igmp_cksum = 0;
igmp->igmp_cksum = inet_cksum((u_short *)igmp,
IGMP_MINLEN + datalen);
build_igmp(src, dst, type, code, group, datalen);
if (IN_MULTICAST(ntohl(dst))) {
k_set_if(src);
if (type != IGMP_DVMRP) {
if (type != IGMP_DVMRP || dst == allhosts_group) {
setloop = 1;
k_set_loop(TRUE);
}
@ -335,11 +423,12 @@ send_igmp(src, dst, type, code, group, datalen)
bzero(&sdst, sizeof(sdst));
sdst.sin_family = AF_INET;
#if (defined(BSD) && (BSD >= 199103))
#ifdef HAVE_SA_LEN
sdst.sin_len = sizeof(sdst);
#endif
sdst.sin_addr.s_addr = dst;
if (sendto(igmp_socket, send_buf, ip->ip_len, 0,
if (sendto(igmp_socket, send_buf,
MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen, 0,
(struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
if (errno == ENETDOWN)
check_vif_state();
@ -352,6 +441,8 @@ send_igmp(src, dst, type, code, group, datalen)
if (setloop)
k_set_loop(FALSE);
IF_DEBUG(DEBUG_PKT|igmp_debug_kind(type, code))
log(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
packet_kind(type, code), inet_fmt(src, s1), inet_fmt(dst, s2));
igmp_packet_kind(type, code), src == INADDR_ANY ? "INADDR_ANY" :
inet_fmt(src, s1), inet_fmt(dst, s2));
}

42
usr.sbin/mrouted/igmpv2.h Normal file
View File

@ -0,0 +1,42 @@
/*
* The mrouted program is covered by the license in the accompanying file
* named "LICENSE". Use of the mrouted program represents acceptance of
* the terms and conditions listed in that file.
*
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
* Leland Stanford Junior University.
*
*
* igmpv2.h,v 3.8.4.1 1997/11/18 23:25:58 fenner Exp
*/
/*
* Constants for IGMP Version 2. Several of these, especially the
* robustness variable, should be variables and not constants.
*/
#define IGMP_ROBUSTNESS_VARIABLE 2
#define IGMP_QUERY_INTERVAL 125
#define IGMP_QUERY_RESPONSE_INTERVAL 10
#define IGMP_GROUP_MEMBERSHIP_INTERVAL (IGMP_ROBUSTNESS_VARIABLE * \
IGMP_QUERY_INTERVAL + \
IGMP_QUERY_RESPONSE_INTERVAL)
#define IGMP_OTHER_QUERIER_PRESENT_INTERVAL (IGMP_ROBUSTNESS_VARIABLE * \
IGMP_QUERY_INTERVAL + \
IGMP_QUERY_RESPONSE_INTERVAL / 2)
/* Round to the nearest TIMER_INTERVAL */
#define IGMP_STARTUP_QUERY_INTERVAL (((IGMP_QUERY_INTERVAL / 4) \
/ TIMER_INTERVAL) * TIMER_INTERVAL)
#define IGMP_STARTUP_QUERY_COUNT IGMP_ROBUSTNESS_VARIABLE
#define IGMP_LAST_MEMBER_QUERY_INTERVAL 1
#define IGMP_LAST_MEMBER_QUERY_COUNT IGMP_ROBUSTNESS_VARIABLE
/*
* OLD_AGE_THRESHOLD is the number of IGMP_QUERY_INTERVAL's to remember the
* presence of an IGMPv1 group member. According to the IGMPv2 specification,
* routers remember this presence for [Robustness Variable] * [Query Interval] +
* [Query Response Interval]. However, OLD_AGE_THRESHOLD is in units of
* [Query Interval], so doesn't have sufficient resolution to represent
* [Query Response Interval]. When the timer mechanism gets an efficient
* method of refreshing timers, this should get fixed.
*/
#define OLD_AGE_THRESHOLD IGMP_ROBUSTNESS_VARIABLE

View File

@ -7,12 +7,16 @@
* Leland Stanford Junior University.
*
*
* $Id: inet.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
* inet.c,v 3.8.4.2 1998/01/06 01:57:44 fenner Exp
*/
#include "defs.h"
#ifndef lint
static char rcsid[] = "@(#) $Id: \
inet.c,v 3.8.4.2 1998/01/06 01:57:44 fenner Exp $";
#endif
/*
* Exported variables.
@ -155,15 +159,17 @@ inet_fmts(addr, mask, s)
* with "255.255.255.255".)
*/
u_int32
inet_parse(s)
inet_parse(s,n)
char *s;
int n;
{
u_int32 a = 0;
u_int a0, a1, a2, a3;
u_int a0 = 0, a1 = 0, a2 = 0, a3 = 0;
int i;
char c;
if (sscanf(s, "%u.%u.%u.%u%c", &a0, &a1, &a2, &a3, &c) != 4 ||
a0 > 255 || a1 > 255 || a2 > 255 || a3 > 255)
i = sscanf(s, "%u.%u.%u.%u%c", &a0, &a1, &a2, &a3, &c);
if (i < n || i > 4 || a0 > 255 || a1 > 255 || a2 > 255 || a3 > 255)
return (0xffffffff);
((u_char *)&a)[0] = a0;

145
usr.sbin/mrouted/ipip.c Normal file
View File

@ -0,0 +1,145 @@
/*
* The mrouted program is covered by the license in the accompanying file
* named "LICENSE". Use of the mrouted program represents acceptance of
* the terms and conditions listed in that file.
*
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
* Leland Stanford Junior University.
*
*
* ipip.c,v 3.8.4.6 1998/01/06 01:57:45 fenner Exp
*/
#include "defs.h"
#ifndef lint
static char rcsid[] = "@(#) $Id: \
ipip.c,v 3.8.4.6 1998/01/06 01:57:45 fenner Exp $";
#endif
/*
* Exported variables.
*/
#ifdef notyet
int raw_socket; /* socket for raw network I/O */
#endif
/*
*XXX For now, we just use the IGMP socket to send packets.
* This is legal in BSD, because the protocol # is not checked
* on raw sockets. The k_* interfaces need to gain a socket
* argument so that we can call them on the raw_socket also.
*/
#define raw_socket igmp_socket
/*
* Private variables.
*/
static int rawid = 0;
/*
* Open and initialize the raw socket.
*/
void
init_ipip()
{
#ifdef notyet
if ((raw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
log(LOG_ERR, errno, "Raw IP socket");
#endif
}
/*
* Allocate and fill in static IP header for encapsulating on a tunnel.
*/
void
init_ipip_on_vif(v)
struct uvif *v;
{
struct ip *ip;
ip = v->uv_encap_hdr = (struct ip *)malloc(sizeof(struct ip));
if (ip == NULL)
log(LOG_ERR, 0, "out of memory");
bzero(ip, sizeof(struct ip));
/*
* Fields zeroed that aren't filled in later:
* - IP ID (let the kernel fill it in)
* - Offset (we don't send fragments)
* - Checksum (let the kernel fill it in)
*/
ip->ip_v = IPVERSION;
ip->ip_hl = sizeof(struct ip) >> 2;
ip->ip_tos = 0xc0; /* Internet Control */
ip->ip_ttl = MAXTTL; /* applies to unicasts only */
ip->ip_p = IPPROTO_IPIP;
ip->ip_src.s_addr = v->uv_lcl_addr;
ip->ip_dst.s_addr = v->uv_rmt_addr;
}
/*
* Call build_igmp() to build an IGMP message in the output packet buffer.
* Then fill in the fields of the IP packet that build_igmp() left for the
* kernel to fill in, and encapsulate the original packet with the
* pre-created ip header for this vif.
*/
void
send_ipip(src, dst, type, code, group, datalen, v)
u_int32 src, dst;
int type, code;
u_int32 group;
int datalen;
struct uvif *v;
{
struct msghdr msg;
struct iovec iov[2];
struct sockaddr_in sdst;
struct ip *ip;
build_igmp(src, dst, type, code, group, datalen);
ip = (struct ip *)send_buf;
#ifndef RAW_OUTPUT_IS_RAW
ip->ip_len = htons(ip->ip_len);
#endif
ip->ip_id = htons(rawid++);
ip->ip_sum = 0;
ip->ip_sum = inet_cksum((u_short *)ip, ip->ip_hl << 2);
ip = v->uv_encap_hdr;
ip->ip_len = 2 * MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen;
#ifdef RAW_OUTPUT_IS_RAW
ip->ip_len = htons(ip->ip_len);
#endif
bzero(&sdst, sizeof(sdst));
sdst.sin_family = AF_INET;
#ifdef HAVE_SA_LEN
sdst.sin_len = sizeof(sdst);
#endif
sdst.sin_addr = ip->ip_dst;
iov[0].iov_base = (caddr_t)v->uv_encap_hdr;
iov[0].iov_len = sizeof(struct ip);
iov[1].iov_base = (caddr_t)send_buf;
iov[1].iov_len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen;
bzero(&msg, sizeof(msg));
msg.msg_name = (caddr_t)&sdst;
msg.msg_namelen = sizeof(sdst);
msg.msg_iov = iov;
msg.msg_iovlen = 2;
if (sendmsg(raw_socket, &msg, 0) < 0) {
if (errno == ENETDOWN)
check_vif_state();
else
log(LOG_WARNING, errno,
"sendmsg to %s on %s",
inet_fmt(sdst.sin_addr.s_addr, s1), inet_fmt(src, s2));
}
IF_DEBUG(DEBUG_PKT|igmp_debug_kind(type, code))
log(LOG_DEBUG, 0, "SENT %s from %-15s to %s encaped to %s",
igmp_packet_kind(type, code), src == INADDR_ANY ? "INADDR_ANY" :
inet_fmt(src, s1), inet_fmt(dst, s2),
inet_fmt(sdst.sin_addr.s_addr, s3));
}

View File

@ -7,19 +7,58 @@
* Leland Stanford Junior University.
*
*
* $Id: kern.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
* kern.c,v 3.8.4.10 1998/01/06 02:00:51 fenner Exp
*/
#include "defs.h"
#ifndef lint
static char rcsid[] = "@(#) $Id: \
kern.c,v 3.8.4.10 1998/01/06 02:00:51 fenner Exp $";
#endif
void k_set_rcvbuf(bufsize)
int curttl = 0;
void k_set_rcvbuf(bufsize, minsize)
int bufsize;
int minsize;
{
int delta = bufsize / 2;
int iter = 0;
/*
* Set the socket buffer. If we can't set it as large as we
* want, search around to try to find the highest acceptable
* value. The highest acceptable value being smaller than
* minsize is a fatal error.
*/
if (setsockopt(igmp_socket, SOL_SOCKET, SO_RCVBUF,
(char *)&bufsize, sizeof(bufsize)) < 0)
log(LOG_ERR, errno, "setsockopt SO_RCVBUF %u", bufsize);
(char *)&bufsize, sizeof(bufsize)) < 0) {
bufsize -= delta;
while (1) {
iter++;
if (delta > 1)
delta /= 2;
if (setsockopt(igmp_socket, SOL_SOCKET, SO_RCVBUF,
(char *)&bufsize, sizeof(bufsize)) < 0) {
bufsize -= delta;
} else {
if (delta < 1024)
break;
bufsize += delta;
}
}
if (bufsize < minsize) {
log(LOG_ERR, 0, "OS-allowed buffer size %u < app min %u",
bufsize, minsize);
/*NOTREACHED*/
}
}
IF_DEBUG(DEBUG_KERN)
log(LOG_DEBUG, 0, "Got %d byte buffer size in %d iterations",
bufsize, iter);
}
@ -37,12 +76,15 @@ void k_hdr_include(bool)
void k_set_ttl(t)
int t;
{
#ifndef RAW_OUTPUT_IS_RAW
u_char ttl;
ttl = t;
if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_TTL,
(char *)&ttl, sizeof(ttl)) < 0)
log(LOG_ERR, errno, "setsockopt IP_MULTICAST_TTL %u", ttl);
#endif
curttl = t;
}
@ -141,7 +183,7 @@ void k_add_vif(vifi, v)
if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_VIF,
(char *)&vc, sizeof(vc)) < 0)
log(LOG_ERR, errno, "setsockopt MRT_ADD_VIF");
log(LOG_ERR, errno, "setsockopt MRT_ADD_VIF on vif %d", vifi);
}
@ -150,7 +192,7 @@ void k_del_vif(vifi)
{
if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_VIF,
(char *)&vifi, sizeof(vifi)) < 0)
log(LOG_ERR, errno, "setsockopt MRT_DEL_VIF");
log(LOG_ERR, errno, "setsockopt MRT_DEL_VIF on vif %d", vifi);
}
@ -183,7 +225,8 @@ void k_add_rg(origin, g)
#ifdef DEBUG_MFC
md_log(MD_ADD_FAIL, origin, g->gt_mcastgrp);
#endif
log(LOG_WARNING, errno, "setsockopt MRT_ADD_MFC");
log(LOG_WARNING, errno, "setsockopt MRT_ADD_MFC",
inet_fmt(origin, s1), inet_fmt(g->gt_mcastgrp, s2));
}
}
@ -214,7 +257,8 @@ int k_del_rg(origin, g)
#ifdef DEBUG_MFC
md_log(MD_DEL_FAIL, origin, g->gt_mcastgrp);
#endif
log(LOG_WARNING, errno, "setsockopt MRT_DEL_MFC");
log(LOG_WARNING, errno, "setsockopt MRT_DEL_MFC of (%s %s)",
inet_fmt(origin, s1), inet_fmt(g->gt_mcastgrp, s2));
}
return retval;
@ -239,3 +283,63 @@ int k_get_version()
return vers;
#endif
}
#if 0
/*
* Get packet counters
*/
int
k_get_vif_count(vifi, icount, ocount, ibytes, obytes)
vifi_t vifi;
int *icount, *ocount, *ibytes, *obytes;
{
struct sioc_vif_req vreq;
int retval = 0;
vreq.vifi = vifi;
if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&vreq) < 0) {
log(LOG_WARNING, errno, "SIOCGETVIFCNT on vif %d", vifi);
vreq.icount = vreq.ocount = vreq.ibytes =
vreq.obytes = 0xffffffff;
retval = 1;
}
if (icount)
*icount = vreq.icount;
if (ocount)
*ocount = vreq.ocount;
if (ibytes)
*ibytes = vreq.ibytes;
if (obytes)
*obytes = vreq.obytes;
return retval;
}
/*
* Get counters for a desired source and group.
*/
int
k_get_sg_count(src, grp, pktcnt, bytecnt, wrong_if)
u_int32 src;
u_int32 grp;
struct sg_count *retval;
{
struct sioc_sg_req sgreq;
int retval = 0;
sgreq.src.s_addr = src;
sgreq.grp.s_addr = grp;
if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sgreq) < 0) {
log(LOG_WARNING, errno, "SIOCGETSGCNT on (%s %s)",
inet_fmt(src, s1), inet_fmt(grp, s2));
sgreq.pktcnt = sgreq.bytecnt = sgreq.wrong_if = 0xffffffff;
return 1;
}
if (pktcnt)
*pktcnt = sgreq.pktcnt;
if (bytecnt)
*bytecnt = sgreq.bytecnt;
if (wrong_if)
*wrong_if = sgreq.wrong_if;
return retval;
}
#endif

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: main.c,v 3.8 1995/11/29 22:36:34 fenner Rel $
* main.c,v 3.8.4.29 1998/03/01 01:49:00 fenner Exp
*/
/*
@ -33,8 +33,8 @@
#endif
#ifndef lint
static char rcsid[] =
"@(#) $Id: main.c,v 3.8 1995/11/29 22:36:34 fenner Rel $";
static char rcsid[] = "@(#) $Id: \
main.c,v 3.8.4.29 1998/03/01 01:49:00 fenner Exp $";
#endif
extern char *configfilename;
@ -45,11 +45,21 @@ static char dumpfilename[] = _PATH_MROUTED_DUMP;
static char cachefilename[] = _PATH_MROUTED_CACHE;
static char genidfilename[] = _PATH_MROUTED_GENID;
static int haveterminal = 1;
int did_final_init = 0;
static int sighandled = 0;
#define GOT_SIGINT 0x01
#define GOT_SIGHUP 0x02
#define GOT_SIGUSR1 0x04
#define GOT_SIGUSR2 0x08
int cache_lifetime = DEFAULT_CACHE_LIFETIME;
int max_prune_lifetime = DEFAULT_CACHE_LIFETIME * 2;
int prune_lifetime = AVERAGE_PRUNE_LIFETIME;
int debug = 0;
u_char pruning = 1; /* Enable pruning by default */
char *progname;
time_t mrouted_init_time;
#ifdef SNMP
#define NHANDLERS 34
@ -63,16 +73,48 @@ static struct ihandler {
} ihandlers[NHANDLERS];
static int nhandlers = 0;
static struct debugname {
char *name;
int level;
int nchars;
} debugnames[] = {
{ "packet", DEBUG_PKT, 2 },
{ "pkt", DEBUG_PKT, 3 },
{ "pruning", DEBUG_PRUNE, 1 },
{ "prunes", DEBUG_PRUNE, 1 },
{ "routing", DEBUG_ROUTE, 1 },
{ "routes", DEBUG_ROUTE, 1 },
{ "route_detail", DEBUG_RTDETAIL, 6 },
{ "rtdetail", DEBUG_RTDETAIL, 2 },
{ "peers", DEBUG_PEER, 2 },
{ "neighbors", DEBUG_PEER, 1 },
{ "cache", DEBUG_CACHE, 1 },
{ "timeout", DEBUG_TIMEOUT, 1 },
{ "callout", DEBUG_TIMEOUT, 2 },
{ "interface", DEBUG_IF, 2 },
{ "vif", DEBUG_IF, 1 },
{ "membership", DEBUG_MEMBER, 1 },
{ "groups", DEBUG_MEMBER, 1 },
{ "traceroute", DEBUG_TRACE, 2 },
{ "mtrace", DEBUG_TRACE, 2 },
{ "igmp", DEBUG_IGMP, 1 },
{ "icmp", DEBUG_ICMP, 2 },
{ "rsrr", DEBUG_RSRR, 2 },
{ "3", 0xffffffff, 1 } /* compat. */
};
/*
* Forward declarations.
*/
static void fasttimer __P((int));
static void done __P((int));
static void dump __P((int));
static void fdump __P((int));
static void cdump __P((int));
static void restart __P((int));
static void timer __P((void));
static void final_init __P((void *));
static void fasttimer __P((void *));
static void timer __P((void *));
static void dump __P((void));
static void dump_version __P((FILE *));
static void fdump __P((void));
static void cdump __P((void));
static void restart __P((void));
static void handler __P((int));
static void cleanup __P((void));
static void resetlogging __P((void *));
@ -99,14 +141,15 @@ main(argc, argv)
char *argv[];
{
register int recvlen;
register int omask;
int dummy;
FILE *fp;
struct timeval tv;
struct timeval tv, difftime, curtime, lasttime, *timeout;
u_int32 prev_genid;
int vers;
fd_set rfds, readers;
int nfds, n, i;
int nfds, n, i, secs;
extern char todaysversion[];
struct sigaction sa;
#ifdef SNMP
struct timeval timeout, *tvp = &timeout;
struct timeval sched, *svp = &sched, now, *nvp = &now;
@ -116,16 +159,57 @@ main(argc, argv)
setlinebuf(stderr);
if (geteuid() != 0) {
fprintf(stderr, "must be root\n");
fprintf(stderr, "mrouted: must be root\n");
exit(1);
}
progname = strrchr(argv[0], '/');
if (progname)
progname++;
else
progname = argv[0];
argv++, argc--;
while (argc > 0 && *argv[0] == '-') {
if (strcmp(*argv, "-d") == 0) {
if (argc > 1 && isdigit(*(argv + 1)[0])) {
if (argc > 1 && *(argv + 1)[0] != '-') {
char *p,*q;
int i, len;
struct debugname *d;
argv++, argc--;
debug = atoi(*argv);
debug = 0;
p = *argv; q = NULL;
while (p) {
q = strchr(p, ',');
if (q)
*q++ = '\0';
len = strlen(p);
for (i = 0, d = debugnames;
i < sizeof(debugnames) / sizeof(debugnames[0]);
i++, d++)
if (len >= d->nchars && strncmp(d->name, p, len) == 0)
break;
if (i == sizeof(debugnames) / sizeof(debugnames[0])) {
int j = 0xffffffff;
int k = 0;
fprintf(stderr, "Valid debug levels: ");
for (i = 0, d = debugnames;
i < sizeof(debugnames) / sizeof(debugnames[0]);
i++, d++) {
if ((j & d->level) == d->level) {
if (k++)
putc(',', stderr);
fputs(d->name, stderr);
j &= ~d->level;
}
}
putc('\n', stderr);
goto usage;
}
debug |= d->level;
p = q;
}
} else
debug = DEFAULT_DEBUG;
} else if (strcmp(*argv, "-c") == 0) {
@ -135,7 +219,7 @@ main(argc, argv)
} else
goto usage;
} else if (strcmp(*argv, "-p") == 0) {
pruning = 0;
log(LOG_WARNING, 0, "disabling pruning is no longer supported");
#ifdef SNMP
} else if (strcmp(*argv, "-P") == 0) {
if (argc > 1 && isdigit(*(argv + 1)[0])) {
@ -151,40 +235,27 @@ main(argc, argv)
if (argc > 0) {
usage: fprintf(stderr,
"usage: mrouted [-p] [-c configfile] [-d [debug_level]]\n");
"usage: mrouted [-p] [-c configfile] [-d [debug_level][,debug_level...]]\n");
exit(1);
}
if (debug == 0) {
/*
* Detach from the terminal
*/
int t;
if (debug != 0) {
struct debugname *d;
char c;
int tmpd = debug;
if (fork()) exit(0);
(void)close(0);
(void)close(1);
(void)close(2);
(void)open("/", 0);
(void)dup2(0, 1);
(void)dup2(0, 2);
#ifdef SYSV
(void)setpgrp();
#else
#ifdef TIOCNOTTY
t = open("/dev/tty", 2);
if (t >= 0) {
(void)ioctl(t, TIOCNOTTY, (char *)0);
(void)close(t);
fprintf(stderr, "debug level 0x%x ", debug);
c = '(';
for (d = debugnames; d < debugnames +
sizeof(debugnames) / sizeof(debugnames[0]); d++) {
if ((tmpd & d->level) == d->level) {
tmpd &= ~d->level;
fprintf(stderr, "%c%s", c, d->name);
c = ',';
}
}
#else
if (setsid() < 0)
perror("setsid");
#endif
#endif
fprintf(stderr, ")\n");
}
else
fprintf(stderr, "debug level %u\n", debug);
#ifdef LOG_DAEMON
(void)openlog("mrouted", LOG_PID, LOG_DAEMON);
@ -192,10 +263,9 @@ usage: fprintf(stderr,
#else
(void)openlog("mrouted", LOG_PID);
#endif
sprintf(versionstring, "mrouted version %d.%d",
PROTOCOL_VERSION, MROUTED_VERSION);
sprintf(versionstring, "mrouted version %s", todaysversion);
log(LOG_NOTICE, 0, "%s", versionstring);
log(LOG_DEBUG, 0, "%s starting", versionstring);
#ifdef SYSV
srand48(time(NULL));
@ -223,14 +293,27 @@ usage: fprintf(stderr,
(void) fclose(fp);
}
/* Start up the log rate-limiter */
resetlogging(NULL);
callout_init();
init_igmp();
init_icmp();
init_ipip();
init_routes();
init_ktable();
k_init_dvmrp(); /* enable DVMRP routing in kernel */
#ifndef OLD_KERNEL
/*
* Unfortunately, you can't k_get_version() unless you've
* k_init_dvmrp()'d. Now that we want to move the
* k_init_dvmrp() to later in the initialization sequence,
* we have to do the disgusting hack of initializing,
* getting the version, then stopping the kernel multicast
* forwarding.
*/
k_init_dvmrp();
vers = k_get_version();
k_stop_dvmrp();
/*XXX
* This function must change whenever the kernel version changes
*/
@ -261,33 +344,14 @@ usage: fprintf(stderr,
rsrr_init();
#endif /* RSRR */
#if defined(__STDC__) || defined(__GNUC__)
/*
* Allow cleanup if unexpected exit. Apparently some architectures
* have a kernel bug where closing the socket doesn't do an
* ip_mrouter_done(), so we attempt to do it on exit.
*/
atexit(cleanup);
#endif
if (debug)
fprintf(stderr, "pruning %s\n", pruning ? "on" : "off");
fp = fopen(pidfilename, "w");
if (fp != NULL) {
fprintf(fp, "%d\n", (int)getpid());
(void) fclose(fp);
}
(void)signal(SIGALRM, fasttimer);
(void)signal(SIGHUP, restart);
(void)signal(SIGTERM, done);
(void)signal(SIGINT, done);
(void)signal(SIGUSR1, fdump);
(void)signal(SIGUSR2, cdump);
if (debug != 0)
(void)signal(SIGQUIT, dump);
sa.sa_handler = handler;
sa.sa_flags = 0; /* Interrupt system calls */
sigemptyset(&sa.sa_mask);
sigaction(SIGHUP, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGUSR1, &sa, NULL);
sigaction(SIGUSR2, &sa, NULL);
FD_ZERO(&readers);
FD_SET(igmp_socket, &readers);
@ -298,30 +362,82 @@ usage: fprintf(stderr,
nfds = ihandlers[i].fd + 1;
}
/*
* Install the vifs in the kernel as late as possible in the
* initialization sequence.
IF_DEBUG(DEBUG_IF)
dump_vifs(stderr);
IF_DEBUG(DEBUG_ROUTE)
dump_routes(stderr);
/* schedule first timer interrupt */
timer_setTimer(1, fasttimer, NULL);
timer_setTimer(TIMER_INTERVAL, timer, NULL);
if (debug == 0) {
/*
* Detach from the terminal
*/
int t;
haveterminal = 0;
if (fork()) exit(0);
(void)close(0);
(void)close(1);
(void)close(2);
(void)open("/", 0);
(void)dup2(0, 1);
(void)dup2(0, 2);
#if defined(SYSV) || defined(linux)
(void)setpgrp();
#else
#ifdef TIOCNOTTY
t = open("/dev/tty", 2);
if (t >= 0) {
(void)ioctl(t, TIOCNOTTY, (char *)0);
(void)close(t);
}
#else
if (setsid() < 0)
perror("setsid");
#endif
#endif
}
fp = fopen(pidfilename, "w");
if (fp != NULL) {
fprintf(fp, "%d\n", (int)getpid());
(void) fclose(fp);
}
/* XXX HACK
* This will cause black holes for the first few seconds after startup,
* since we are exchanging routes but not actually forwarding.
* However, it eliminates much of the startup transient.
*
* It's possible that we can set a flag which says not to report any
* routes (just accept reports) until this timer fires, and then
* do a report_to_all_neighbors(ALL_ROUTES) immediately before
* turning on DVMRP.
*/
init_installvifs();
if (debug >= 2) dump(0);
/* Start up the log rate-limiter */
resetlogging(NULL);
(void)alarm(1); /* schedule first timer interrupt */
timer_setTimer(10, final_init, NULL);
/*
* Main receive loop.
*/
dummy = 0;
difftime.tv_usec = 0;
gettimeofday(&curtime, NULL);
lasttime = curtime;
for(;;) {
#ifdef SYSV
sigset_t block, oblock;
#endif
bcopy((char *)&readers, (char *)&rfds, sizeof(rfds));
secs = timer_nextTimer();
if (secs == -1)
timeout = NULL;
else {
timeout = &tv;
timeout->tv_sec = secs;
timeout->tv_usec = 0;
}
#ifdef SNMP
gettimeofday(nvp, 0);
THIS IS BROKEN
if (nvp->tv_sec > svp->tv_sec
|| (nvp->tv_sec == svp->tv_sec && nvp->tv_usec > svp->tv_usec)){
alarmTimer(nvp);
@ -344,51 +460,121 @@ usage: fprintf(stderr,
if (block == 1)
tvp = NULL; /* block without timeout */
if ((n = select(nfds, &rfds, NULL, NULL, tvp)) < 0)
#else
if ((n = select(nfds, &rfds, NULL, NULL, NULL)) < 0)
#endif
{
if (errno != EINTR) /* SIGALRM is expected */
if (sighandled) {
if (sighandled & GOT_SIGINT) {
sighandled &= ~GOT_SIGINT;
break;
}
if (sighandled & GOT_SIGHUP) {
sighandled &= ~GOT_SIGHUP;
restart();
}
if (sighandled & GOT_SIGUSR1) {
sighandled &= ~GOT_SIGUSR1;
fdump();
}
if (sighandled & GOT_SIGUSR2) {
sighandled &= ~GOT_SIGUSR2;
cdump();
}
}
if ((n = select(nfds, &rfds, NULL, NULL, timeout)) < 0) {
if (errno != EINTR)
log(LOG_WARNING, errno, "select failed");
continue;
}
if (FD_ISSET(igmp_socket, &rfds)) {
recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
0, NULL, &dummy);
if (recvlen < 0) {
if (errno != EINTR) log(LOG_ERR, errno, "recvfrom");
continue;
if (n > 0) {
if (FD_ISSET(igmp_socket, &rfds)) {
recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
0, NULL, &dummy);
if (recvlen < 0) {
if (errno != EINTR) log(LOG_ERR, errno, "recvfrom");
continue;
}
accept_igmp(recvlen);
}
#ifdef SYSV
(void)sigemptyset(&block);
(void)sigaddset(&block, SIGALRM);
if (sigprocmask(SIG_BLOCK, &block, &oblock) < 0)
log(LOG_ERR, errno, "sigprocmask");
#else
omask = sigblock(sigmask(SIGALRM));
#endif
accept_igmp(recvlen);
#ifdef SYSV
(void)sigprocmask(SIG_SETMASK, &oblock, (sigset_t *)NULL);
#else
(void)sigsetmask(omask);
#endif
}
for (i = 0; i < nhandlers; i++) {
if (FD_ISSET(ihandlers[i].fd, &rfds)) {
(*ihandlers[i].func)(ihandlers[i].fd, &rfds);
for (i = 0; i < nhandlers; i++) {
if (FD_ISSET(ihandlers[i].fd, &rfds)) {
(*ihandlers[i].func)(ihandlers[i].fd, &rfds);
}
}
}
#ifdef SNMP
THIS IS BROKEN
snmp_read(&rfds);
snmp_timeout(); /* poll */
#endif
/*
* Handle timeout queue.
*
* If select + packet processing took more than 1 second,
* or if there is a timeout pending, age the timeout queue.
*
* If not, collect usec in difftime to make sure that the
* time doesn't drift too badly.
*
* If the timeout handlers took more than 1 second,
* age the timeout queue again. XXX This introduces the
* potential for infinite loops!
*/
do {
/*
* If the select timed out, then there's no other
* activity to account for and we don't need to
* call gettimeofday.
*/
if (n == 0) {
curtime.tv_sec = lasttime.tv_sec + secs;
curtime.tv_usec = lasttime.tv_usec;
n = -1; /* don't do this next time through the loop */
} else
gettimeofday(&curtime, NULL);
difftime.tv_sec = curtime.tv_sec - lasttime.tv_sec;
difftime.tv_usec += curtime.tv_usec - lasttime.tv_usec;
while (difftime.tv_usec > 1000000) {
difftime.tv_sec++;
difftime.tv_usec -= 1000000;
}
if (difftime.tv_usec < 0) {
difftime.tv_sec--;
difftime.tv_usec += 1000000;
}
lasttime = curtime;
if (secs == 0 || difftime.tv_sec > 0)
age_callout_queue(difftime.tv_sec);
secs = -1;
} while (difftime.tv_sec > 0);
}
log(LOG_NOTICE, 0, "%s exiting", versionstring);
cleanup();
exit(0);
}
static void
final_init(i)
void *i;
{
char *s = (char *)i;
log(LOG_NOTICE, 0, "%s%s", versionstring, s ? s : "");
if (s)
free(s);
k_init_dvmrp(); /* enable DVMRP routing in kernel */
/*
* Install the vifs in the kernel as late as possible in the
* initialization sequence.
*/
init_installvifs();
time(&mrouted_init_time);
did_final_init = 1;
}
/*
* routine invoked every second. Its main goal is to cycle through
@ -399,7 +585,7 @@ usage: fprintf(stderr,
*/
static void
fasttimer(i)
int i;
void *i;
{
static unsigned int tlast;
static unsigned int nsent;
@ -428,12 +614,8 @@ fasttimer(i)
}
tlast = t;
}
if ((t % TIMER_INTERVAL) == 0)
timer();
age_callout_queue();/* Advance the timer for the callout queue
for groups */
alarm(1);
timer_setTimer(1, fasttimer, NULL);
}
/*
@ -453,7 +635,7 @@ fasttimer(i)
* avoid unwanted synchronization with other routers.
*/
static u_long virtual_time = 0;
u_long virtual_time = 0;
/*
@ -462,13 +644,14 @@ static u_long virtual_time = 0;
* virtual interface data structures.
*/
static void
timer()
timer(i)
void *i;
{
age_routes(); /* Advance the timers in the route entries */
age_vifs(); /* Advance the timers for neighbors */
age_table_entry(); /* Advance the timers for the cache entries */
if (virtual_time % GROUP_QUERY_INTERVAL == 0) {
if (virtual_time % IGMP_QUERY_INTERVAL == 0) {
/*
* Time to query the local group memberships on all subnets
* for which this router is the elected querier.
@ -507,21 +690,10 @@ timer()
* Advance virtual time
*/
virtual_time += TIMER_INTERVAL;
timer_setTimer(TIMER_INTERVAL, timer, NULL);
}
/*
* On termination, let everyone know we're going away.
*/
static void
done(i)
int i;
{
log(LOG_NOTICE, 0, "%s exiting", versionstring);
cleanup();
_exit(1);
}
static void
cleanup()
{
@ -534,7 +706,36 @@ cleanup()
#endif /* RSRR */
expire_all_routes();
report_to_all_neighbors(ALL_ROUTES);
k_stop_dvmrp();
if (did_final_init)
k_stop_dvmrp();
}
}
/*
* Signal handler. Take note of the fact that the signal arrived
* so that the main loop can take care of it.
*/
static void
handler(sig)
int sig;
{
switch (sig) {
case SIGINT:
case SIGTERM:
sighandled |= GOT_SIGINT;
break;
case SIGHUP:
sighandled |= GOT_SIGHUP;
break;
case SIGUSR1:
sighandled |= GOT_SIGUSR1;
break;
case SIGUSR2:
sighandled |= GOT_SIGUSR2;
break;
}
}
@ -543,25 +744,39 @@ cleanup()
* Dump internal data structures to stderr.
*/
static void
dump(i)
int i;
dump()
{
dump_vifs(stderr);
dump_routes(stderr);
}
static void
dump_version(fp)
FILE *fp;
{
time_t t;
time(&t);
fprintf(fp, "%s ", versionstring);
if (did_final_init)
fprintf(fp, "up %s",
scaletime(t - mrouted_init_time));
else
fprintf(fp, "(not yet initialized)");
fprintf(fp, " %s\n", ctime(&t));
}
/*
* Dump internal data structures to a file.
*/
static void
fdump(i)
int i;
fdump()
{
FILE *fp;
fp = fopen(dumpfilename, "w");
if (fp != NULL) {
dump_version(fp);
dump_vifs(fp);
dump_routes(fp);
(void) fclose(fp);
@ -573,13 +788,13 @@ fdump(i)
* Dump local cache contents to a file.
*/
static void
cdump(i)
int i;
cdump()
{
FILE *fp;
fp = fopen(cachefilename, "w");
if (fp != NULL) {
dump_version(fp);
dump_cache(fp);
(void) fclose(fp);
}
@ -590,52 +805,42 @@ cdump(i)
* Restart mrouted
*/
static void
restart(i)
int i;
restart()
{
register int omask;
#ifdef SYSV
sigset_t block, oblock;
#endif
char *s;
log(LOG_NOTICE, 0, "%s restart", versionstring);
s = (char *)malloc(sizeof(" restart"));
if (s == NULL)
log(LOG_ERR, 0, "out of memory");
strcpy(s, " restart");
/*
* reset all the entries
*/
#ifdef SYSV
(void)sigemptyset(&block);
(void)sigaddset(&block, SIGALRM);
if (sigprocmask(SIG_BLOCK, &block, &oblock) < 0)
log(LOG_ERR, errno, "sigprocmask");
#else
omask = sigblock(sigmask(SIGALRM));
#endif
free_all_prunes();
free_all_routes();
free_all_callouts();
stop_all_vifs();
k_stop_dvmrp();
close(igmp_socket);
close(udp_socket);
did_final_init = 0;
/*
* start processing again
*/
dvmrp_genid++;
pruning = 1;
init_igmp();
init_routes();
init_ktable();
init_vifs();
k_init_dvmrp(); /* enable DVMRP routing in kernel */
init_installvifs();
/*XXX Schedule final_init() as main does? */
final_init(s);
#ifdef SYSV
(void)sigprocmask(SIG_SETMASK, &oblock, (sigset_t *)NULL);
#else
(void)sigsetmask(omask);
#endif
/* schedule timer interrupts */
timer_setTimer(1, fasttimer, NULL);
timer_setTimer(TIMER_INTERVAL, timer, NULL);
}
#define LOG_MAX_MSGS 20 /* if > 20/minute then shut up for a while */
@ -661,6 +866,61 @@ resetlogging(arg)
timer_setTimer(nxttime, resetlogging, narg);
}
char *
scaletime(t)
u_long t;
{
#define SCALETIMEBUFLEN 20
static char buf1[20];
static char buf2[20];
static char *buf = buf1;
char *p;
p = buf;
if (buf == buf1)
buf = buf2;
else
buf = buf1;
/* XXX snprintf */
sprintf(p, "%2ld:%02ld:%02ld", t / 3600, (t % 3600) / 60, t % 60);
p[SCALETIMEBUFLEN - 1] = '\0';
return p;
}
#ifdef RINGBUFFER
#define NLOGMSGS 10000
#define LOGMSGSIZE 200
char *logmsg[NLOGMSGS];
static int logmsgno = 0;
void
printringbuf()
{
FILE *f;
int i;
f = fopen("/var/tmp/mrouted.log", "a");
if (f == NULL) {
log(LOG_ERR, errno, "can't open /var/tmp/mrouted.log");
/*NOTREACHED*/
}
fprintf(f, "--------------------------------------------\n");
i = (logmsgno + 1) % NLOGMSGS;
while (i != logmsgno) {
if (*logmsg[i]) {
fprintf(f, "%s\n", logmsg[i]);
*logmsg[i] = '\0';
}
i = (i + 1) % NLOGMSGS;
}
fclose(f);
}
#endif
/*
* Log errors and other messages to the system log daemon and to stderr,
* according to the severity of the message and the current debug level.
@ -673,9 +933,11 @@ log(int severity, int syserr, char *format, ...)
va_list ap;
static char fmt[211] = "warning - ";
char *msg;
char tbuf[20];
struct timeval now;
struct tm *thyme;
#ifdef RINGBUFFER
static int ringbufinit = 0;
#endif
va_start(ap, format);
#else
@ -687,11 +949,14 @@ log(severity, syserr, format, va_alist)
va_dcl
{
va_list ap;
static char fmt[211] = "warning - ";
static char fmt[311] = "warning - ";
char *msg;
char tbuf[20];
struct timeval now;
struct tm *thyme;
#ifdef RINGBUFFER
static int ringbufinit = 0;
#endif
va_start(ap);
#endif
@ -699,35 +964,66 @@ log(severity, syserr, format, va_alist)
va_end(ap);
msg = (severity == LOG_WARNING) ? fmt : &fmt[10];
switch (debug) {
case 0: break;
case 1: if (severity > LOG_NOTICE) break;
case 2: if (severity > LOG_INFO ) break;
default:
gettimeofday(&now,NULL);
thyme = localtime(&now.tv_sec);
strftime(tbuf, sizeof(tbuf), "%X.%%03d ", thyme);
fprintf(stderr, tbuf, now.tv_usec / 1000);
fprintf(stderr, "%s", msg);
if (syserr == 0)
fprintf(stderr, "\n");
else if (syserr < sys_nerr)
fprintf(stderr, ": %s\n", sys_errlist[syserr]);
else
fprintf(stderr, ": errno %d\n", syserr);
}
#ifdef RINGBUFFER
if (!ringbufinit) {
int i;
if (severity <= LOG_NOTICE) {
if (log_nmsgs++ < LOG_MAX_MSGS) {
if (syserr != 0) {
errno = syserr;
syslog(severity, "%s: %m", msg);
} else
syslog(severity, "%s", msg);
for (i = 0; i < NLOGMSGS; i++) {
logmsg[i] = malloc(LOGMSGSIZE);
if (logmsg[i] == 0) {
syslog(LOG_ERR, "out of memory");
exit(-1);
}
*logmsg[i] = 0;
}
if (severity <= LOG_ERR) exit(-1);
ringbufinit = 1;
}
gettimeofday(&now,NULL);
thyme = localtime(&now.tv_sec);
sprintf(logmsg[logmsgno++], "%02d:%02d:%02d.%03ld %s err %d",
thyme->tm_hour, thyme->tm_min, thyme->tm_sec,
now.tv_usec / 1000, msg, syserr);
logmsgno %= NLOGMSGS;
if (severity <= LOG_NOTICE)
#endif
/*
* Log to stderr if we haven't forked yet and it's a warning or worse,
* or if we're debugging.
*/
if (haveterminal && (debug || severity <= LOG_WARNING)) {
gettimeofday(&now,NULL);
thyme = localtime(&now.tv_sec);
if (!debug)
fprintf(stderr, "%s: ", progname);
fprintf(stderr, "%02d:%02d:%02d.%03ld %s", thyme->tm_hour,
thyme->tm_min, thyme->tm_sec, now.tv_usec / 1000, msg);
if (syserr == 0)
fprintf(stderr, "\n");
else if (syserr < sys_nerr)
fprintf(stderr, ": %s\n", sys_errlist[syserr]);
else
fprintf(stderr, ": errno %d\n", syserr);
}
/*
* Always log things that are worse than warnings, no matter what
* the log_nmsgs rate limiter says.
* Only count things worse than debugging in the rate limiter
* (since if you put daemon.debug in syslog.conf you probably
* actually want to log the debugging messages so they shouldn't
* be rate-limited)
*/
if ((severity < LOG_WARNING) || (log_nmsgs < LOG_MAX_MSGS)) {
if (severity < LOG_DEBUG)
log_nmsgs++;
if (syserr != 0) {
errno = syserr;
syslog(severity, "%s: %m", msg);
} else
syslog(severity, "%s", msg);
}
if (severity <= LOG_ERR) exit(-1);
}
#ifdef DEBUG_MFC

View File

@ -1,7 +1,7 @@
/* Mapper for connections between MRouteD multicast routers.
* Written by Pavel Curtis <Pavel@PARC.Xerox.Com>
*
* $Id: mapper.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
* mapper.c,v 3.8.4.3 1998/01/06 01:57:47 fenner Exp
*/
/*
@ -32,6 +32,11 @@
#include <varargs.h>
#endif
#ifndef lint
static char rcsid[] = "@(#) $Id: \
mapper.c,v 3.8.4.3 1998/01/06 01:57:47 fenner Exp $";
#endif
#define DEFAULT_TIMEOUT 2 /* How long to wait before retrying requests */
#define DEFAULT_RETRIES 1 /* How many times to ask each router */
@ -844,13 +849,16 @@ int main(argc, argv)
{
int flood = FALSE, graph = FALSE;
setlinebuf(stderr);
if (geteuid() != 0) {
fprintf(stderr, "must be root\n");
fprintf(stderr, "map-mbone: must be root\n");
exit(1);
}
init_igmp();
setuid(getuid());
setlinebuf(stderr);
argv++, argc--;
while (argc > 0 && argv[0][0] == '-') {
switch (argv[0][1]) {
@ -899,15 +907,13 @@ int main(argc, argv)
if (debug)
fprintf(stderr, "Debug level %u\n", debug);
init_igmp();
{ /* Find a good local address for us. */
int udp;
struct sockaddr_in addr;
int addrlen = sizeof(addr);
addr.sin_family = AF_INET;
#if (defined(BSD) && (BSD >= 199103))
#ifdef HAVE_SA_LEN
addr.sin_len = sizeof addr;
#endif
addr.sin_addr.s_addr = dvmrp_group;

View File

@ -60,11 +60,8 @@
*/
#ifndef lint
static char rcsid[] =
"@(#) $Id: mrinfo.c,v 3.8 1995/11/29 22:36:34 fenner Rel $";
/* original rcsid:
"@(#) Header: mrinfo.c,v 1.6 93/04/08 15:14:16 van Exp (LBL)";
*/
static char rcsid[] = "@(#) $Id: \
mrinfo.c,v 3.8.4.7 1998/03/01 03:05:20 fenner Exp $";
#endif
#include <netdb.h>
@ -236,13 +233,14 @@ accept_neighbors2(src, dst, p, datalen, level)
u_char *ep = p + datalen;
u_int broken_cisco = ((level & 0xffff) == 0x020a); /* 10.2 */
/* well, only possibly_broken_cisco, but that's too long to type. */
u_int majvers = level & 0xff;
u_int minvers = (level >> 8) & 0xff;
printf("%s (%s) [version %d.%d", inet_fmt(src, s1), inet_name(src),
level & 0xff, (level >> 8) & 0xff);
if ((level >> 16) & NF_LEAF) { printf (",leaf"); }
if ((level >> 16) & NF_PRUNE) { printf (",prune"); }
if ((level >> 16) & NF_GENID) { printf (",genid"); }
if ((level >> 16) & NF_MTRACE) { printf (",mtrace"); }
printf("%s (%s) [", inet_fmt(src, s1), inet_name(src));
if (majvers == 3 && minvers == 0xff)
printf("DVMRPv3 compliant");
else
printf("version %d.%d", majvers, minvers);
printf ("]:\n");
while (p < ep) {
@ -333,12 +331,16 @@ main(argc, argv)
char *host;
int curaddr;
setlinebuf(stderr);
if (geteuid() != 0) {
fprintf(stderr, "mrinfo: must be root\n");
exit(1);
}
init_igmp();
setuid(getuid());
setlinebuf(stderr);
argv++, argc--;
while (argc > 0 && argv[0][0] == '-') {
switch (argv[0][1]) {
@ -386,8 +388,6 @@ main(argc, argv)
if (debug)
fprintf(stderr, "Debug level %u\n", debug);
init_igmp();
/* Check all addresses; mrouters often have unreachable interfaces */
for (curaddr = 0; hp->h_addr_list[curaddr] != NULL; curaddr++) {
memcpy(&target_addr, hp->h_addr_list[curaddr], hp->h_length);
@ -397,7 +397,7 @@ main(argc, argv)
int addrlen = sizeof(addr);
addr.sin_family = AF_INET;
#if (defined(BSD) && (BSD >= 199103))
#ifdef HAVE_SA_LEN
addr.sin_len = sizeof addr;
#endif
addr.sin_addr.s_addr = target_addr;
@ -492,7 +492,11 @@ main(argc, argv)
src = ip->ip_src.s_addr;
dst = ip->ip_dst.s_addr;
iphdrlen = ip->ip_hl << 2;
#ifdef RAW_INPUT_IS_RAW
ipdatalen = ntohs(ip->ip_len) - iphdrlen;
#else
ipdatalen = ip->ip_len;
#endif
if (iphdrlen + ipdatalen != recvlen) {
log(LOG_WARNING, 0,
"packet shorter (%u bytes) than hdr+data length (%u+%u)",

View File

@ -1,14 +1,12 @@
'\"COPYRIGHT 1989 by The Board of Trustees of Leland Stanford Junior University.
'\"$Id: mrouted.8,v 3.8 1995/11/29 22:37:21 fenner Rel $
'\"mrouted.8,v 3.8.4.5 1998/03/01 01:50:28 fenner Exp
.TH MROUTED 8
.UC 5
.SH NAME
mrouted \- IP multicast routing daemon
.SH SYNOPSIS
.B /etc/mrouted
.B /usr/sbin/mrouted
[
.B \-p
] [
.B \-c
.I config_file
] [
@ -39,17 +37,17 @@ routers that do not support IP multicasting,
.I mrouted
includes support for
"tunnels", which are virtual point-to-point links between pairs of
.IR mrouted s
multicast routers
located anywhere in an internet. IP multicast packets are encapsulated for
transmission through tunnels, so that they look like normal unicast datagrams
to intervening routers and subnets. The encapsulation
is added on entry to a tunnel, and stripped off
on exit from a tunnel.
By default, the packets are encapsulated using the IP-in-IP protocol
The packets are encapsulated using the IP-in-IP protocol
(IP protocol number 4).
Older versions of
.I mrouted
tunnel using IP source routing, which puts a heavy load on some
tunneled using IP source routing, which puts a heavy load on some
types of routers.
This version does not support IP source route tunnelling.
.PP
@ -75,136 +73,323 @@ to have access to more than one physical subnet
in order to perform multicast forwarding.
.br
.ne 5
.SH OPTIONS
.TP 10
.BI \-c " config_file"
Specifies an alternate configuration file to read (normally /etc/mrouted.conf)
.TP
.BI \-d " debug_level"
Turn on debugging;
.I debug_level
is a comma-seperated list of subsections to debug.
.SH INVOCATION
.PP
If no "\-d" option is given, or if the debug level is specified as 0,
If no "\-d" option is given,
.I mrouted
detaches from the invoking terminal. Otherwise, it remains attached to the
invoking terminal and responsive to signals from that terminal. If "\-d" is
given with no argument, the debug level defaults to 2. Regardless of the
debug level,
invoking terminal and responsive to signals from that terminal.
Regardless of the debug level,
.I mrouted
always writes warning and error messages to the system
log demon. Non-zero debug levels have the following effects:
.IP "level 1"
all syslog'ed messages are also printed to stderr.
.IP "level 2"
all level 1 messages plus notifications of "significant"
events are printed to stderr.
.IP "level 3"
all level 2 messages plus notifications of all packet
arrivals and departures are printed to stderr.
log demon. The
.I debug-level
argument is a comma-seperated list of any of the following:
.TP 13
packet
Display the type, source and destination of all packets sent or received.
.TP
pruning
Display more information about prunes sent or received.
.TP
routing
Display more information about routing update packets sent or received.
.TP
route_detail
Display routing updates in excruciating detail. This is generally way too
much information.
.TP
neighbors
Display information about neighbor discovery.
.TP
cache
Display insertions, deletions and refreshes of entries in
the kernel forwarding cache.
.TP
timeout
Debug timeouts and periodic processes.
.TP
interface
Display information about interfaces and their configuration.
.TP
membership
Display information about group memberships on physical interfaces.
.TP
traceroute
Display information about multicast traceroute requests
passing through this router.
.TP
igmp
Display IGMP operation including group membership and querier election.
.TP
icmp
Monitor ICMP handling.
.TP
rsrr
Monitor RSRR operation.
.PP
Upon startup, mrouted writes its pid to the file /etc/mrouted.pid .
Upon startup, mrouted writes its pid to the file /var/run/mrouted.pid .
.SH CONFIGURATION
.PP
.I Mrouted
automatically configures itself to forward on all multicast-capable
interfaces, i.e., interfaces that have the IFF_MULTICAST flag set (excluding
the loopback "interface"), and it finds other
.IR mrouted s
directly reachable
the loopback "interface"), and it finds other DVMRP routers directly reachable
via those interfaces. To override the default configuration, or to add
tunnel links to other
.IR mrouted s,
tunnel links to other multicast routers,
configuration commands may be placed in
/etc/mrouted.conf (or an alternative file, specified by the "\-c" option).
There are four types of configuration commands:
.nf
phyint <local-addr> [disable] [metric <m>]
[threshold <t>] [rate_limit <b>]
[boundary (<boundary-name>|<scoped-addr>/<mask-len>)]
[altnet <network>/<mask-len>]
tunnel <local-addr> <remote-addr> [metric <m>]
[threshold <t>] [rate_limit <b>]
[boundary (<boundary-name>|<scoped-addr>/<mask-len>)]
cache_lifetime <ct>
pruning <off/on>
name <boundary-name> <scoped-addr>/<mask-len>
.fi
.PP
The file format is free-form; whitespace (including newlines) is not
significant.
The
.I boundary
and
.I altnet
options may be specified as many times as necessary.
The file begins with commands that apply to
.IR mrouted 's
overall operation or set defaults.
.TP 15
.BI cache_lifetime " secs"
Specifies, in seconds, the lifetime of a multicast forwarding cache
entry in the kernel. Multicast forwarding cache entries in the kernel
are checked every
.I secs
seconds, and are refreshed if the source is still
active or deleted if not. Care should be taken when setting this value,
as a low value can keep the kernel cache small at the cost of "thrashing"
the cache for periodic senders, but high values can cause the kernel
cache to grow unacceptably large. The default is 300 seconds (5 minutes).
.TP
.BI prune_lifetime " secs"
Sepcifies, in seconds, the average lifetime of prunes that are sent towards
parents. The actual lifetimes will be randomized in the range
[.5\fIsecs\fP,1.5\fIsecs\fP]. The default is 7200 (2 hours). Smaller values
cause less state to be kept both at this router and the parent, at the
cost of more frequent broadcasts. However, some routers (e.g. mrouted <3.3
and all currently known versions of cisco's IOS) do not use the
DVMRP generation ID to determine that a neighbor has rebooted. Prunes
sent towards these neighbors should be kept short, in order to shorten
the time to recover from a reboot. For use in this situation, the
prune_lifetime keyword may be specified on an interface as described
below.
.TP
.B noflood
.I Mrouted
uses a DVMRP optimization to prevent having to keep individual routing tables
for each neighbor; part of this optimization is that
.I mrouted
assumes that it is the forwarder for each of its attached subnets on
startup. This can cause duplicates for a short period (approximately
one full route report interval), since both the router that just
started up and the proper forwarder will be forwarding traffic. This
behavior can be turned off with the noflood keyword;
.I mrouted
will not assume that it is the forwarder on startup.
Turning on noflood can cause black holes on restart, which will generally
last approximately one full route report interval.
The noflood keyword can also be specified on individual interfaces.
.TP
.BI rexmit_prunes " [on|off]"
.IR Mrouted 's
default is to retransmit prunes on all point-to-point interfaces
(including tunnels) but no multi-access interfaces. This option
may be used to make the default on (or off) for all interfaces.
The rexmit_prunes keyword can also be specified on individual interfaces.
.TP
.BI name " boundary-name scoped-addr/mask-len"
Associates
.I boundary-name
with the boundary described by
.IR scoped-addr/mask-len ,
to help make interface configurations
more readable and reduce repetition in the configuration file.
.PP
The phyint command can be used to disable multicast routing on the physical
interface identified by local IP address <local-addr>, or to associate a
non-default metric or threshold with the specified physical interface.
The local IP address <local-addr> may be replaced by the
interface name (e.g le0).
The second section of the configuration file, which may optionally
be empty, describes options that apply to physical interfaces.
.TP 15
.BI phyint " local-addr|ifname"
The phyint command does nothing by itself; it is simply a place holder
which interface-specific commands may follow. An interface address or
name may be specified.
.TP
.B disable
Disables multicast forwarding on this interface. By default,
.I mrouted
discovers all locally attached multicast capable interfaces and forwards
on all of them.
.TP
.BI netmask " netmask"
If the kernel's netmask does not accurately reflect
the subnet (e.g. you're using proxy-ARP in lieu of IP subnetting), use the
netmask command to describe the real netmask.
.TP
.BI altnet " network/mask-len"
If a phyint is attached to multiple IP subnets, describe each additional subnet
with the altnet keyword.
Phyint commands must precede tunnel commands.
with the altnet keyword. This command may be specified multiple times
to describe multiple subnets.
.TP
.B igmpv1
If there are any IGMPv1 routers on the phyint, use the \fBigmpv1\fP
keyword to force \fImrouted\fP into IGMPv1 mode. All routers on the phyint
must use the same version of IGMP.
.TP
.B force_leaf
Force \fImrouted\fP to ignore other routers on this interface.
mrouted will never send or accept neighbor probes or
route reports on this interface.
.PP
The tunnel command can be used to establish a tunnel link between local
IP address <local-addr> and remote IP address <remote-addr>, and to associate
a non-default metric or threshold with that tunnel.
The local IP address <local-addr> may be replaced by the
interface name (e.g. le0). The remote IP address <remote-addr> may
be replaced by a host name, if and only if the host name has a single
IP address associated with it.
The tunnel must be set
up in the mrouted.conf files of both routers before it can be used.
'\"For backwards compatibility with older
'\".IR mrouted s,
'\"the srcrt keyword specifies
'\"encapsulation using IP source routing.
In addition, the common vif commands described later may all be used on
a phyint.
.PP
The cache_lifetime is a value that determines the amount of time that a
cached multicast route stays in kernel before timing out. The value of this
entry should lie between 300 (5 min) and 86400 (1 day). It defaults to 300.
The third section of the configuration file, also optional, describes
the configuration of any DVMRP tunnels this router might have.
.TP 15
.BI tunnel " local-addr|ifname remote-addr|remote-hostname"
This command establishes a DVMRP tunnel between this host (on the interface
described by
.I local-addr
or
.IR ifname )
and a remote host (identified by
.I remote-addr
or
.IR remote-hostname ).
A remote hostname may only be used if
it maps to a single IP address.
A tunnel must be configured on both routers before it can be used.
Be careful that the unicast route to the remote address goes out the
interface specified by the
.I local-addr|ifname
argument. Some UNIX
kernels rewrite the source address of
.IR mrouted 's
packets on their way out to contain the address of the transmission
interface. This is best assured via a static host route.
.PP
The pruning <off/on> option is provided for
.IR mrouted
to act as a non-pruning router. It is also possible to start
.IR mrouted
in a non-pruning mode using the "-p" option on the command line. It is
expected that a router would be configured in this manner for test
purposes only. The default mode is pruning enabled.
.PP
You may assign names to boundaries to make configuration easier with
the name keyword. The boundary option on phyint or tunnel commands
can accept either a name or a boundary.
.PP
The metric is the "cost" associated with sending a datagram on the given
The common vif commands described below
may all be used on tunnels or phyints.
.TP 15
.BI metric " m"
The metric is the "cost" associated with receiving a datagram on the given
interface or tunnel; it may be used to influence the choice of routes.
The metric defaults to 1. Metrics should be kept as small as possible,
because
.I mrouted
cannot route along paths with a sum of metrics greater
because DVMRP cannot route along paths with a sum of metrics greater
than 31.
.LP
.TP
.BI advert_metric " m"
The advert_metric is the "cost" associated with sending a datagram
on the given interface or tunnel; it may be used to influence the choice
of routes. The advert_metric defaults to 0. Note that the effective
metric of a link is one end's metric plus the other end's advert_metric.
.TP
.BI threshold " t"
The threshold is the minimum IP time-to-live required for a multicast datagram
to be forwarded to the given interface or tunnel. It is used to control the
scope of multicast datagrams. (The TTL of forwarded packets is only compared
to the threshold, it is not decremented by the threshold. Every multicast
router decrements the TTL by 1.) The default threshold is 1.
router decrements the TTL by exactly 1.) The default threshold is 1.
.LP
In general, all
.IR mrouted s
In general, all multicast routers
connected to a particular subnet or tunnel should
use the same metric and threshold for that subnet or tunnel.
.PP
.TP 15
.BI rate_limit " r"
The rate_limit option allows the network administrator to specify a
certain bandwidth in Kbits/second which would be allocated to multicast
traffic. It defaults to 500Kbps on tunnels, and 0 (unlimited) on physical
interfaces.
.PP
traffic. It defaults 0 (unlimited).
.TP
.BI boundary " boundary-name|scoped-addr/mask-len"
The boundary option allows an interface
to be configured as an administrative boundary for the specified
scoped address. Packets belonging to this address will not
be forwarded on a scoped interface. The boundary option accepts either
a name or a boundary spec.
a name or a boundary spec. This command may be specified several times
on an interface in order to describe multiple boundaries.
.TP
.B passive
No packets will be sent on this link or tunnel until we hear from the other
end. This is useful for the "server" end of a tunnel that goes over
a dial-on-demand link; configure the "server" end as passive and
it will not send its periodic probes until it hears one from the other
side, so will not keep the link up. If this option is specified on both
ends of a tunnel, the tunnel will never come up.
.TP
.B noflood
As described above, but only applicable to this interface/tunnel.
.TP
.BI prune_lifetime " secs"
As described above, but only applicable to this interface/tunnel.
.TP
.BI rexmit_prunes " [on|off]"
As described above, but only applicable to this interface/tunnel.
Recall that prune retransmission
defaults to on on point-to-point links and tunnels, and off on
multi-access links.
.TP
.B allow_nonpruners
By default, \fImrouted\fP refuses to peer with DVMRP neighbors that
do not claim to support pruning. This option allows such peerings
on this interface.
.TP
.B notransit
A specialized case of route filtering; no route learned from an interface
marked "notransit" will be advertised on another interface marked
"notransit". Marking only a single interface "notransit" has no meaning.
.TP
.BI accept|deny " (route/mask-len [exact])+ [bidir]"
The
.B accept
and
.B deny
commands allow rudimentary route filtering. The
.B accept
command causes
.I mrouted
to accept only the listed routes on the configured interface; the
.B deny
command causes
.I mrouted
to accept all but the listed routes.
Only one of
.B accept
or
.B deny
commands may be used on a given interface.
The list of routes follows the
.B accept
or
.B deny
keyword. If the keyword
.I exact
follows a route, then only that route is matched; otherwise, that route
and any more specific route is matched. For example,
.B deny 0/0
denys all routes, while
.B deny 0/0 exact
denys only the default route. The default route may also be specified
with the
.B default
keyword.
The
.B bidir
keyword enables bidirectional route filtering; the filter will be applied
to routes on both output and input. Without the
.B bidir
keyword,
.B accept
and
.B deny
filters are only applied on input. Poison reverse routes are never
filtered out.
.PP
.I Mrouted
will not initiate execution if it has fewer than two enabled vifs,
@ -213,7 +398,7 @@ interface or a tunnel. It will log a warning if all of its vifs are
tunnels; such an
.I mrouted
configuration would be better replaced by more
direct tunnels (i.e., eliminate the middle man).
direct tunnels (i.e. eliminate the middle man).
.SH "EXAMPLE CONFIGURATION"
.PP
This is an example configuration for a mythical multicast router at a big
@ -267,9 +452,9 @@ good-bye messages to all neighboring routers).
.IP TERM
same as INT
.IP USR1
dumps the internal routing tables to /usr/tmp/mrouted.dump.
dumps the internal routing tables to /var/tmp/mrouted.dump.
.IP USR2
dumps the internal cache tables to /usr/tmp/mrouted.cache.
dumps the internal cache tables to /var/tmp/mrouted.cache.
.IP QUIT
dumps the internal routing tables to stderr (only if
.I mrouted
@ -277,22 +462,23 @@ was invoked with a non-zero debug level).
.PP
For convenience in sending signals,
.I mrouted
writes its pid to /etc/mrouted.pid upon startup.
writes its pid to /var/run/mrouted.pid upon startup.
.bp
.SH EXAMPLE
.PP
The routing tables look like this:
The routing tables dumped in /var/tmp/mrouted.dump look like this:
.nf
.ft C
Virtual Interface Table
Vif Local-Address Metric Thresh Flags
0 36.2.0.8 subnet: 36.2 1 1 querier
0 36.2.0.8 subnet: 36.2/16 1 1 querier
groups: 224.0.2.1
224.0.0.4
pkts in: 3456
pkts out: 2322323
1 36.11.0.1 subnet: 36.11 1 1 querier
1 36.11.0.1 subnet: 36.11/16 1 1 querier
groups: 224.0.2.1
224.0.1.0
224.0.0.4
@ -300,9 +486,9 @@ Virtual Interface Table
pkts out: 3456
2 36.2.0.8 tunnel: 36.8.0.77 3 1
peers: 36.8.0.77 (2.2)
boundaries: 239.0.1
: 239.1.2
peers: 36.8.0.77 (3.255)
boundaries: 239.0.1/24
: 239.1.2/24
pkts in: 34545433
pkts out: 234342
@ -318,6 +504,7 @@ Multicast Routing Table (1136 entries)
.
.fi
.LP
In this example, there are four vifs connecting to two subnets and two
tunnels. The vif 3 tunnel is not in use (no peer address). The vif 0 and
vif 1 subnets have some groups present; tunnels never have any groups. This
@ -344,8 +531,9 @@ also maintains a copy of the kernel forwarding cache table. Entries
are created and deleted by
.I mrouted.
.PP
The cache tables look like this:
The cache tables dumped in /var/tmp/mrouted.cache look like this:
.nf
.ft C
Multicast Routing Cache Table (147 entries)
Origin Mcast-group CTmr Age Ptmr IVif Forwvifs
@ -360,9 +548,11 @@ Multicast Routing Cache Table (147 entries)
>198.106.194.22
.fi
.LP
Each entry is characterized by the origin subnet number and mask and the
destination multicast group. The 'CTmr' field indicates the lifetime
of the entry. The entry is deleted from the cache table
(or refreshed, if traffic is flowing)
when the timer decrements to zero. The 'Age' field is the time since
this cache entry was originally created. Since cache entries get refreshed
if traffic is flowing, routing entries can grow very old.
@ -377,21 +567,55 @@ subnet, a prune message is sent to the upstream router. They are
indicated by a "P" after the vif number. The Forwvifs field shows the
interfaces along which datagrams belonging to the source-group are
forwarded. A "p" indicates that no datagrams are being forwarded along
that interface. An unlisted interface is a leaf subnet with are no
that interface. An unlisted interface is a leaf subnet with no
members of the particular group on that subnet. A "b" on an interface
indicates that it is a boundary interface, i.e. traffic will not be
forwarded on the scoped address on that interface.
An additional line with a ">" as the first character is printed for
each source on the subnet. Note that there can be many sources in
one subnet.
An additional line with a "<" as the first character is printed
describing any prunes received from downstream dependent neighbors
for this subnet and group.
.SH FILES
/etc/mrouted.conf
.br
/etc/mrouted.pid
.br
/usr/tmp/mrouted.dump
.br
/usr/tmp/mrouted.cache
.TP 25
.B /etc/mrouted.conf
.IR mrouted 's
configuration file.
.TP
.B /var/run/mrouted.pid
.IR mrouted 's
PID file.
.TP
.B /var/tmp/mrouted.dump
Where
.I mrouted
dumps its routing table when sent a SIGUSR1.
.TP
.B /var/tmp/mrouted.cache
Where
.I mrouted
dumps its forwarding cache when sent a SIGUSR2.
.PP
Note that these files are located in the following places on pre-4.4BSD systems:
.TP 25
.B /etc/mrouted.conf
.IR mrouted 's
configuration file.
.TP
.B /etc/mrouted.pid
.IR mrouted 's
PID file.
.TP
.B /usr/tmp/mrouted.dump
Where
.I mrouted
dumps its routing table when sent a SIGUSR1.
.TP
.B /usr/tmp/mrouted.cache
Where
.I mrouted
dumps its forwarding cache when sent a SIGUSR2.
.SH SEE ALSO
.BR mrinfo (8) ,
.BR mtrace (8) ,

View File

@ -1,4 +1,4 @@
# $Id: mrouted.conf,v 3.8 1995/11/29 22:40:47 fenner Rel $
# mrouted.conf,v 3.8 1995/11/29 22:40:47 fenner Rel
#
# This is the configuration file for "mrouted", an IP multicast router.
# mrouted looks for it in "/etc/mrouted.conf".

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: pathnames.h,v 3.8 1995/11/29 22:36:57 fenner Rel $
* pathnames.h,v 3.8 1995/11/29 22:36:57 fenner Rel
*/
#define _PATH_MROUTED_CONF "/etc/mrouted.conf"

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: prune.h,v 3.8 1995/11/29 22:36:57 fenner Rel $
* prune.h,v 3.8.4.5 1998/02/27 22:45:43 fenner Exp
*/
/*
@ -32,11 +32,14 @@ struct gtable {
vifbitmap_t gt_grpmems; /* forw. vifs for src, grp */
int gt_prsent_timer; /* prune timer for this group */
int gt_timer; /* timer for this group entry */
time_t gt_ctime; /* time of entry creation */
time_t gt_ctime; /* time of entry creation */
u_char gt_grftsnt; /* graft sent/retransmit timer */
nbrbitmap_t gt_prunes; /* bitmap of neighbors who pruned */
struct stable *gt_srctbl; /* source table */
struct ptable *gt_pruntbl; /* prune table */
struct rtentry *gt_route; /* parent route */
int gt_rexmit_timer; /* timer for prune retransmission */
int gt_prune_rexmit; /* time til prune retransmission */
#ifdef RSRR
struct rsrr_cache *gt_rsrr_cache; /* RSRR cache */
#endif /* RSRR */
@ -52,6 +55,8 @@ struct stable
struct stable *st_next; /* pointer to the next entry */
u_int32 st_origin; /* host origin of multicasts */
u_long st_pktcnt; /* packet count for src-grp entry */
u_long st_savpkt; /* saved pkt cnt when no krnl entry */
time_t st_ctime; /* kernel entry creation time */
};
/*
@ -62,9 +67,12 @@ struct ptable
struct ptable *pt_next; /* pointer to the next entry */
u_int32 pt_router; /* router that sent this prune */
vifi_t pt_vifi; /* vif prune received on */
int pt_index; /* neighbor index of router */
int pt_timer; /* timer for prune */
};
#define MIN_PRUNE_LIFE TIMER_INTERVAL /* min prune lifetime to bother with */
/*
* The packet format for a traceroute request.
*/
@ -137,7 +145,7 @@ struct tr_resp {
};
#define VAL_TO_MASK(x, i) { \
x = htonl(~((1 << (32 - (i))) - 1)); \
x = i ? htonl(~((1 << (32 - (i))) - 1)) : 0; \
};
#define NBR_VERS(n) (((n)->al_pv << 8) + (n)->al_mv)

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: route.h,v 3.8 1995/11/29 22:36:57 fenner Rel $
* route.h,v 3.8.4.6 1997/07/01 23:02:35 fenner Exp
*/
/*
@ -35,17 +35,18 @@ struct rtentry {
u_int32 rt_gateway; /* first-hop gateway back to origin */
vifi_t rt_parent; /* incoming vif (ie towards origin) */
vifbitmap_t rt_children; /* outgoing children vifs */
vifbitmap_t rt_leaves; /* subset of outgoing children vifs */
u_int32 *rt_dominants; /* per vif dominant gateways */
u_int32 *rt_subordinates; /* per vif subordinate gateways */
u_int *rt_leaf_timers; /* per vif leaf confirmation timers */
nbrbitmap_t rt_subordinates; /* bitmap of subordinate gateways */
nbrbitmap_t rt_subordadv; /* recently advertised subordinates */
u_int rt_timer; /* for timing out the route entry */
struct rtentry *rt_prev; /* link to previous entry */
struct gtable *rt_groups; /* link to active groups */
};
#define RTF_CHANGED 0x01 /* route changed but not reported */
#define RTF_LEAF_TIMING 0x02 /* some leaf timers are running */
#define RTF_HOLDDOWN 0x04 /* this route is in holddown */
#define ALL_ROUTES 0 /* possible arguments to report() */
#define CHANGED_ROUTES 1 /* and report_to_all_neighbors() */
#define RT_FMT(r, s) inet_fmts((r)->rt_origin, (r)->rt_originmask, s)

View File

@ -34,21 +34,14 @@
#include "defs.h"
#include <sys/param.h>
#if (defined(BSD) && (BSD >= 199103))
#include <stddef.h>
#ifdef HAVE_SA_LEN
#include <stddef.h> /* for offsetof */
#endif
/* Taken from prune.c */
/*
* checks for scoped multicast addresses
*/
#define GET_SCOPE(gt) { \
register int _i; \
if (((gt)->gt_mcastgrp & 0xff000000) == 0xef000000) \
for (_i = 0; _i < numvifs; _i++) \
if (scoped_addr(_i, (gt)->gt_mcastgrp)) \
VIFM_SET(_i, (gt)->gt_scope); \
}
#ifndef lint
static char rcsid[] = "@(#) $Id: \
rsrr.c,v 3.8.4.8 1998/01/06 01:57:58 fenner Exp $";
#endif
/*
* Exported variables.
@ -72,6 +65,7 @@ static void rsrr_accept __P((int recvlen));
static void rsrr_accept_iq __P((void));
static int rsrr_accept_rq __P((struct rsrr_rq *route_query, int flags,
struct gtable *gt_notify));
static void rsrr_read __P((int, fd_set *));
static int rsrr_send __P((int sendlen));
static void rsrr_cache __P((struct gtable *gt,
struct rsrr_rq *route_query));
@ -90,7 +84,7 @@ rsrr_init()
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sun_family = AF_UNIX;
strcpy(serv_addr.sun_path, RSRR_SERV_PATH);
#if (defined(BSD) && (BSD >= 199103))
#ifdef HAVE_SA_LEN
servlen = offsetof(struct sockaddr_un, sun_path) +
strlen(serv_addr.sun_path);
serv_addr.sun_len = servlen;
@ -101,18 +95,17 @@ rsrr_init()
if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0)
log(LOG_ERR, errno, "Can't bind RSRR socket");
if (register_input_handler(rsrr_socket,rsrr_read) < 0)
if (register_input_handler(rsrr_socket, rsrr_read) < 0)
log(LOG_WARNING, 0, "Couldn't register RSRR as an input handler");
}
/* Read a message from the RSRR socket */
void
static void
rsrr_read(f, rfd)
int f;
fd_set *rfd;
{
register int rsrr_recvlen;
register int omask;
bzero((char *) &client_addr, sizeof(client_addr));
rsrr_recvlen = recvfrom(rsrr_socket, rsrr_recv_buf, sizeof(rsrr_recv_buf),
@ -122,10 +115,7 @@ rsrr_read(f, rfd)
log(LOG_ERR, errno, "RSRR recvfrom");
return;
}
/* Use of omask taken from main() */
omask = sigblock(sigmask(SIGALRM));
rsrr_accept(rsrr_recvlen);
(void)sigsetmask(omask);
}
/* Accept a message from the reservation protocol and take
@ -159,7 +149,8 @@ rsrr_accept(recvlen)
switch (rsrr->type) {
case RSRR_INITIAL_QUERY:
/* Send Initial Reply to client */
log(LOG_INFO, 0, "Received Initial Query\n");
IF_DEBUG(DEBUG_RSRR)
log(LOG_DEBUG, 0, "Received Initial Query\n");
rsrr_accept_iq();
break;
case RSRR_ROUTE_QUERY:
@ -172,7 +163,8 @@ rsrr_accept(recvlen)
}
/* Get the query */
route_query = (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN);
log(LOG_INFO, 0,
IF_DEBUG(DEBUG_RSRR)
log(LOG_DEBUG, 0,
"Received Route Query for src %s grp %s notification %d",
inet_fmt(route_query->source_addr.s_addr, s1),
inet_fmt(route_query->dest_addr.s_addr,s2),
@ -238,7 +230,8 @@ rsrr_accept_iq()
sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN;
/* Send it. */
log(LOG_INFO, 0, "Send RSRR Initial Reply");
IF_DEBUG(DEBUG_RSRR)
log(LOG_DEBUG, 0, "Send RSRR Initial Reply");
rsrr_send(sendlen);
}
@ -259,7 +252,7 @@ rsrr_accept_rq(route_query,flags,gt_notify)
struct rsrr_rr *route_reply;
struct gtable *gt,local_g;
struct rtentry *r;
int sendlen,i;
int sendlen;
u_long mcastgrp;
/* Set up message */
@ -291,8 +284,10 @@ rsrr_accept_rq(route_query,flags,gt_notify)
rsrr->flags = flags;
/* Include the routing entry. */
route_reply->in_vif = gt_notify->gt_route->rt_parent;
route_reply->out_vif_bm = gt_notify->gt_grpmems;
if (BIT_TST(flags,RSRR_NOTIFICATION_BIT))
route_reply->out_vif_bm = gt_notify->gt_grpmems;
else
route_reply->out_vif_bm = 0;
} else if (find_src_grp(route_query->source_addr.s_addr, 0,
route_query->dest_addr.s_addr)) {
@ -331,17 +326,7 @@ rsrr_accept_rq(route_query,flags,gt_notify)
gt->gt_route = r;
/* obtain the multicast group membership list */
for (i = 0; i < numvifs; i++) {
if (VIFM_ISSET(i, r->rt_children) &&
!(VIFM_ISSET(i, r->rt_leaves)))
VIFM_SET(i, gt->gt_grpmems);
if (VIFM_ISSET(i, r->rt_leaves) && grplst_mem(i, mcastgrp))
VIFM_SET(i, gt->gt_grpmems);
}
GET_SCOPE(gt);
gt->gt_grpmems &= ~gt->gt_scope;
determine_forwvifs(gt);
/* Include the routing entry. */
route_reply->in_vif = gt->gt_route->rt_parent;
@ -353,13 +338,9 @@ rsrr_accept_rq(route_query,flags,gt_notify)
}
}
if (gt_notify)
log(LOG_INFO, 0, "Route Change: Send RSRR Route Reply");
else
log(LOG_INFO, 0, "Send RSRR Route Reply");
log(LOG_INFO, 0, "for src %s dst %s in vif %d out vif %d\n",
IF_DEBUG(DEBUG_RSRR)
log(LOG_DEBUG, 0, "%sSend RSRR Route Reply for src %s dst %s in vif %d out vif %d\n",
gt_notify ? "Route Change: " : "",
inet_fmt(route_reply->source_addr.s_addr,s1),
inet_fmt(route_reply->dest_addr.s_addr,s2),
route_reply->in_vif,route_reply->out_vif_bm);
@ -419,6 +400,7 @@ rsrr_cache(gt,route_query)
} else {
/* Update */
rc->route_query.query_id = route_query->query_id;
IF_DEBUG(DEBUG_RSRR)
log(LOG_DEBUG, 0,
"Update cached query id %ld from client %s\n",
rc->route_query.query_id, rc->client_addr.sun_path);
@ -441,6 +423,7 @@ rsrr_cache(gt,route_query)
rc->client_length = client_length;
rc->next = gt->gt_rsrr_cache;
gt->gt_rsrr_cache = rc;
IF_DEBUG(DEBUG_RSRR)
log(LOG_DEBUG, 0, "Cached query id %ld from client %s\n",
rc->route_query.query_id,rc->client_addr.sun_path);
}
@ -462,6 +445,7 @@ rsrr_cache_send(gt,notify)
rcnp = &gt->gt_rsrr_cache;
while ((rc = *rcnp) != NULL) {
if (rsrr_accept_rq(&rc->route_query,flags,gt) < 0) {
IF_DEBUG(DEBUG_RSRR)
log(LOG_DEBUG, 0, "Deleting cached query id %ld from client %s\n",
rc->route_query.query_id,rc->client_addr.sun_path);
/* Delete cache entry. */
@ -480,7 +464,9 @@ rsrr_cache_clean(gt)
{
struct rsrr_cache *rc,*rc_next;
printf("cleaning cache for group %s\n",inet_fmt(gt->gt_mcastgrp, s1));
IF_DEBUG(DEBUG_RSRR)
log(LOG_DEBUG, 0, "cleaning cache for group %s\n",
inet_fmt(gt->gt_mcastgrp, s1));
rc = gt->gt_rsrr_cache;
while (rc) {
rc_next = rc->next;

File diff suppressed because it is too large Load Diff

View File

@ -7,9 +7,91 @@
* Leland Stanford Junior University.
*
*
* $Id: vif.h,v 3.8 1995/11/29 22:36:57 fenner Rel $
* vif.h,v 3.8.4.26 1998/01/14 21:21:19 fenner Exp
*/
/*
* Bitmap handling functions.
* These should be fast but generic. bytes can be slow to zero and compare,
* words are hard to make generic. Thus two sets of macros (yuk).
*/
/*
* The VIFM_ functions should migrate out of <netinet/ip_mroute.h>, since
* the kernel no longer uses vifbitmaps.
*/
#ifndef VIFM_SET
typedef u_long vifbitmap_t;
#define VIFM_SET(n, m) ((m) |= (1 << (n)))
#define VIFM_CLR(n, m) ((m) &= ~(1 << (n)))
#define VIFM_ISSET(n, m) ((m) & (1 << (n)))
#define VIFM_CLRALL(m) ((m) = 0x00000000)
#define VIFM_COPY(mfrom, mto) ((mto) = (mfrom))
#define VIFM_SAME(m1, m2) ((m1) == (m2))
#endif
/*
* And <netinet/ip_mroute.h> was missing some required functions anyway
*/
#ifndef VIFM_SETALL
#define VIFM_SETALL(m) ((m) = ~0)
#endif
#define VIFM_ISSET_ONLY(n, m) ((m) == (1 << (n)))
#define VIFM_ISEMPTY(m) ((m) == 0)
#define VIFM_CLR_MASK(m, mask) ((m) &= ~(mask))
#define VIFM_SET_MASK(m, mask) ((m) |= (mask))
/*
* Neighbor bitmaps are, for efficiency, implemented as a struct
* containing two variables of a native machine type. If you
* have a native type that's bigger than a long, define it below.
*/
#define NBRTYPE u_long
#define NBRBITS sizeof(NBRTYPE) * 8
typedef struct {
NBRTYPE hi;
NBRTYPE lo;
} nbrbitmap_t;
#define MAXNBRS 2 * NBRBITS
#define NO_NBR MAXNBRS
#define NBRM_SET(n, m) (((n) < NBRBITS) ? ((m).lo |= (1 << (n))) : \
((m).hi |= (1 << (n - NBRBITS))))
#define NBRM_CLR(n, m) (((n) < NBRBITS) ? ((m).lo &= ~(1 << (n))) : \
((m).hi &= ~(1 << (n - NBRBITS))))
#define NBRM_ISSET(n, m) (((n) < NBRBITS) ? ((m).lo & (1 << (n))) : \
((m).hi & (1 << ((n) - NBRBITS))))
#define NBRM_CLRALL(m) ((m).lo = (m).hi = 0)
#define NBRM_COPY(mfrom, mto) ((mto).lo = (mfrom).lo, (mto).hi = (mfrom).hi)
#define NBRM_SAME(m1, m2) (((m1).lo == (m2).lo) && ((m1).hi == (m2).hi))
#define NBRM_ISEMPTY(m) (((m).lo == 0) && ((m).hi == 0))
#define NBRM_SETMASK(m, mask) (((m).lo |= (mask).lo),((m).hi |= (mask).hi))
#define NBRM_CLRMASK(m, mask) (((m).lo &= ~(mask).lo),((m).hi &= ~(mask).hi))
#define NBRM_MASK(m, mask) (((m).lo &= (mask).lo),((m).hi &= (mask).hi))
#define NBRM_ISSETMASK(m, mask) (((m).lo & (mask).lo) || ((m).hi & (mask).hi))
#define NBRM_ISSETALLMASK(m, mask)\
((((m).lo & (mask).lo) == (mask).lo) && \
(((m).hi & (mask).hi) == (mask).hi))
/*
* This macro is TRUE if all the subordinates have been pruned, or if
* there are no subordinates on this vif.
* The arguments is the map of subordinates, the map of neighbors on the
* vif, and the map of received prunes.
*/
#define SUBS_ARE_PRUNED(sub, vifmask, prunes) \
(((sub).lo & (vifmask).lo) == ((prunes).lo & (vifmask).lo & (sub).lo) && \
((sub).hi & (vifmask).hi) == ((prunes).hi & (vifmask).hi & (sub).hi))
struct blastinfo {
char * bi_buf; /* Pointer to malloced storage */
char * bi_cur; /* The update to process next */
char * bi_end; /* The place to put the next update */
int bi_len; /* Size of malloced storage */
int bi_timer; /* Timer to run process_blaster_report */
};
/*
* User level Virtual Interface structure
*
@ -18,30 +100,62 @@
* (Note: all addresses, subnet numbers and masks are kept in NETWORK order.)
*/
struct uvif {
u_short uv_flags; /* VIFF_ flags defined below */
u_int uv_flags; /* VIFF_ flags defined below */
u_char uv_metric; /* cost of this vif */
u_int uv_rate_limit; /* rate limit on this vif */
u_char uv_admetric; /* advertised cost of this vif */
u_char uv_threshold; /* min ttl required to forward on vif */
u_int uv_rate_limit; /* rate limit on this vif */
u_int32 uv_lcl_addr; /* local address of this vif */
u_int32 uv_rmt_addr; /* remote end-point addr (tunnels only) */
u_int32 uv_dst_addr; /* destination for DVMRP messages */
u_int32 uv_subnet; /* subnet number (phyints only) */
u_int32 uv_subnetmask; /* subnet mask (phyints only) */
u_int32 uv_subnetbcast;/* subnet broadcast addr (phyints only) */
char uv_name[IFNAMSIZ]; /* interface name */
struct listaddr *uv_groups; /* list of local groups (phyints only) */
struct listaddr *uv_neighbors; /* list of neighboring routers */
nbrbitmap_t uv_nbrmap; /* bitmap of active neighboring routers */
struct listaddr *uv_querier; /* IGMP querier on vif */
int uv_igmpv1_warn;/* To rate-limit IGMPv1 warnings */
int uv_prune_lifetime; /* Prune lifetime or 0 for default */
struct vif_acl *uv_acl; /* access control list of groups */
int uv_leaf_timer; /* time until this vif is considrd leaf */
struct phaddr *uv_addrs; /* Additional subnets on this vif */
struct vif_filter *uv_filter; /* Route filters on this vif */
struct blastinfo uv_blaster; /* Info about route blasters */
int uv_nbrup; /* Counter for neighbor up events */
int uv_icmp_warn; /* To rate-limit ICMP warnings */
u_int uv_nroutes; /* # of routes with this vif as parent */
struct ip *uv_encap_hdr; /* Pre-formed header to encapsulate msgs*/
};
#define uv_blasterbuf uv_blaster.bi_buf
#define uv_blastercur uv_blaster.bi_cur
#define uv_blasterend uv_blaster.bi_end
#define uv_blasterlen uv_blaster.bi_len
#define uv_blastertimer uv_blaster.bi_timer
#define VIFF_KERNEL_FLAGS (VIFF_TUNNEL|VIFF_SRCRT)
#define VIFF_DOWN 0x0100 /* kernel state of interface */
#define VIFF_DISABLED 0x0200 /* administratively disabled */
#define VIFF_QUERIER 0x0400 /* I am the subnet's querier */
#define VIFF_ONEWAY 0x0800 /* Maybe one way interface */
#define VIFF_LEAF 0x1000 /* all neighbors are leaves */
#define VIFF_IGMPV1 0x2000 /* Act as an IGMPv1 Router */
#define VIFF_DOWN 0x000100 /* kernel state of interface */
#define VIFF_DISABLED 0x000200 /* administratively disabled */
#define VIFF_QUERIER 0x000400 /* I am the subnet's querier */
#define VIFF_ONEWAY 0x000800 /* Maybe one way interface */
#define VIFF_LEAF 0x001000 /* all neighbors are leaves */
#define VIFF_IGMPV1 0x002000 /* Act as an IGMPv1 Router */
#define VIFF_REXMIT_PRUNES 0x004000 /* retransmit prunes */
#define VIFF_PASSIVE 0x008000 /* passive tunnel */
#define VIFF_ALLOW_NONPRUNERS 0x010000 /* ok to peer with nonprunrs */
#define VIFF_NOFLOOD 0x020000 /* don't flood on this vif */
#define VIFF_NOTRANSIT 0x040000 /* don't transit these vifs */
#define VIFF_BLASTER 0x080000 /* nbr on vif blasts routes */
#define VIFF_FORCE_LEAF 0x100000 /* ignore nbrs on this vif */
#define VIFF_OTUNNEL 0x200000 /* DVMRP msgs "beside" tunnel*/
#define AVOID_TRANSIT(v, r) \
(((r)->rt_parent != NO_VIF) && \
((r)->rt_gateway != 0) && \
(uvifs[(v)].uv_flags & VIFF_NOTRANSIT) && \
(uvifs[(r)->rt_parent].uv_flags & VIFF_NOTRANSIT))
struct phaddr {
struct phaddr *pa_next;
@ -56,23 +170,67 @@ struct vif_acl {
u_int32 acl_mask; /* Group addr. mask */
};
struct vif_filter {
int vf_type;
#define VFT_ACCEPT 1
#define VFT_DENY 2
int vf_flags;
#define VFF_BIDIR 1
struct vf_element *vf_filter;
};
struct vf_element {
struct vf_element *vfe_next;
u_int32 vfe_addr;
u_int32 vfe_mask;
int vfe_flags;
#define VFEF_EXACT 0x0001
};
struct listaddr {
struct listaddr *al_next; /* link to next addr, MUST BE FIRST */
u_int32 al_addr; /* local group or neighbor address */
u_long al_timer; /* for timing out group or neighbor */
time_t al_ctime; /* neighbor creation time */
u_int32 al_genid; /* generation id for neighbor */
u_char al_pv; /* router protocol version */
u_char al_mv; /* router mrouted version */
u_long al_timerid; /* returned by set timer */
u_long al_query; /* second query in case of leave */
u_short al_old; /* time since heard old report */
u_char al_flags; /* flags related to this neighbor */
time_t al_ctime; /* entry creation time */
union {
struct {
u_int32 alur_genid; /* generation id for neighbor */
u_int alur_nroutes; /* # of routes w/ nbr as parent */
u_char alur_pv; /* router protocol version */
u_char alur_mv; /* router mrouted version */
u_char alur_index; /* neighbor index */
} alu_router;
struct {
u_int32 alug_reporter; /* a host which reported membership */
u_long alug_timerid; /* timer for group membership */
u_long alug_query; /* timer for repeated leave query */
u_char alug_old; /* time since heard old report */
} alu_group;
} al_alu;
u_short al_flags; /* flags related to this neighbor */
};
#define al_genid al_alu.alu_router.alur_genid
#define al_nroutes al_alu.alu_router.alur_nroutes
#define al_pv al_alu.alu_router.alur_pv
#define al_mv al_alu.alu_router.alur_mv
#define al_index al_alu.alu_router.alur_index
#define al_reporter al_alu.alu_group.alug_reporter
#define al_old al_alu.alu_group.alug_old
#define al_timerid al_alu.alu_group.alug_timerid
#define al_query al_alu.alu_group.alug_query
#define NF_LEAF 0x01 /* This neighbor is a leaf */
#define NF_PRUNE 0x02 /* This neighbor understands prunes */
#define NF_GENID 0x04 /* I supply genid & rtrlist in probe*/
#define NF_MTRACE 0x08 /* I can understand mtrace requests */
#define NBRF_LEAF 0x0001 /* This neighbor is a leaf */
#define NBRF_GENID 0x0100 /* I know this neighbor's genid */
#define NBRF_WAITING 0x0200 /* Waiting for peering to come up */
#define NBRF_ONEWAY 0x0400 /* One-way peering */
#define NBRF_TOOOLD 0x0800 /* Too old (policy decision) */
#define NBRF_TOOMANYROUTES 0x1000 /* Neighbor is spouting routes */
#define NBRF_NOTPRUNING 0x2000 /* Neighbor doesn't appear to prune */
/*
* Don't peer with neighbors with any of these flags set
*/
#define NBRF_DONTPEER (NBRF_WAITING|NBRF_ONEWAY|NBRF_TOOOLD| \
NBRF_TOOMANYROUTES|NBRF_NOTPRUNING)
#define NO_VIF ((vifi_t)MAXVIFS) /* An invalid vif index */