Move back from gnu/dist/mrouted, now that it's available under a BSD
license.
This commit is contained in:
parent
925de95670
commit
c60d41a9de
48
usr.sbin/mrouted/LICENSE
Normal file
48
usr.sbin/mrouted/LICENSE
Normal file
@ -0,0 +1,48 @@
|
||||
|
||||
The mrouted program is covered by the following license. Use of the
|
||||
mrouted program represents acceptance of these terms and conditions.
|
||||
|
||||
1. STANFORD grants to LICENSEE a nonexclusive and nontransferable license
|
||||
to use, copy and modify the computer software ``mrouted'' (hereinafter
|
||||
called the ``Program''), upon the terms and conditions hereinafter set
|
||||
out and until Licensee discontinues use of the Licensed Program.
|
||||
|
||||
2. LICENSEE acknowledges that the Program is a research tool still in
|
||||
the development state, that it is being supplied ``as is,'' without any
|
||||
accompanying services from STANFORD, and that this license is entered
|
||||
into in order to encourage scientific collaboration aimed at further
|
||||
development and application of the Program.
|
||||
|
||||
3. LICENSEE may copy the Program and may sublicense others to use object
|
||||
code copies of the Program or any derivative version of the Program.
|
||||
All copies must contain all copyright and other proprietary notices found
|
||||
in the Program as provided by STANFORD. Title to copyright to the
|
||||
Program remains with STANFORD.
|
||||
|
||||
4. LICENSEE may create derivative versions of the Program. LICENSEE
|
||||
hereby grants STANFORD a royalty-free license to use, copy, modify,
|
||||
distribute and sublicense any such derivative works. At the time
|
||||
LICENSEE provides a copy of a derivative version of the Program to a
|
||||
third party, LICENSEE shall provide STANFORD with one copy of the source
|
||||
code of the derivative version at no charge to STANFORD.
|
||||
|
||||
5. STANFORD MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.
|
||||
By way of example, but not limitation, STANFORD MAKES NO REPRESENTATION
|
||||
OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
|
||||
THAT THE USE OF THE LICENSED PROGRAM WILL NOT INFRINGE ANY PATENTS,
|
||||
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. STANFORD shall not be held liable
|
||||
for any liability nor for any direct, indirect or consequential damages
|
||||
with respect to any claim by LICENSEE or any third party on account of or
|
||||
arising from this Agreement or use of the Program.
|
||||
|
||||
6. This agreement shall be construed, interpreted and applied in
|
||||
accordance with the State of California and any legal action arising
|
||||
out of this Agreement or use of the Program shall be filed in a court
|
||||
in the State of California.
|
||||
|
||||
7. Nothing in this Agreement shall be construed as conferring rights to
|
||||
use in advertising, publicity or otherwise any trademark or the name
|
||||
of ``Stanford''.
|
||||
|
||||
The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
|
||||
Leland Stanford Junior University.
|
14
usr.sbin/mrouted/Makefile
Normal file
14
usr.sbin/mrouted/Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
# $NetBSD: Makefile,v 1.12 2003/03/05 21:05:38 wiz Exp $
|
||||
# from: Id: Makefile,v 1.5 1993/06/24 05:11:16 deering Exp
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
PROG= mrouted
|
||||
SRCS= callout.c cfparse.y config.c igmp.c inet.c kern.c main.c prune.c \
|
||||
route.c vif.c
|
||||
MAN= mrouted.8
|
||||
|
||||
LDADD+= -lutil
|
||||
DPADD+= ${LIBUTIL}
|
||||
|
||||
.include <bsd.prog.mk>
|
227
usr.sbin/mrouted/callout.c
Normal file
227
usr.sbin/mrouted/callout.c
Normal file
@ -0,0 +1,227 @@
|
||||
/* $NetBSD: callout.c,v 1.7 2003/03/05 21:05:38 wiz Exp $ */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
/* 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 */
|
||||
int time; /* time offset to next event*/
|
||||
};
|
||||
|
||||
#ifdef IGMP_DEBUG
|
||||
static void print_Q(void);
|
||||
#else
|
||||
#define print_Q()
|
||||
#endif
|
||||
|
||||
int secs_remaining(int);
|
||||
|
||||
void
|
||||
callout_init(void)
|
||||
{
|
||||
Q = (struct timeout_q *) 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* signal handler for SIGALARM that is called once every second
|
||||
*/
|
||||
void
|
||||
age_callout_queue(void)
|
||||
{
|
||||
struct timeout_q *ptr;
|
||||
|
||||
if (in_callout)
|
||||
return;
|
||||
|
||||
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
|
||||
logit(LOG_DEBUG,0,"[callout, age_callout_queue] -- time (%d)", ptr->time);
|
||||
#endif /* IGMP_DEBUG */
|
||||
in_callout = 0; return;
|
||||
}
|
||||
}
|
||||
in_callout = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* sets the timer
|
||||
*
|
||||
* delay: number of units for timeout
|
||||
* action: function to be called on timeout
|
||||
* data: what to call the timeout function with
|
||||
*/
|
||||
int
|
||||
timer_setTimer(int delay, cfunc_t action, char *data)
|
||||
{
|
||||
struct timeout_q *ptr, *node, *prev;
|
||||
|
||||
if (in_callout)
|
||||
return -1;
|
||||
|
||||
in_callout = 1;
|
||||
|
||||
/* create a node */
|
||||
node = (struct timeout_q *)malloc(sizeof(struct timeout_q));
|
||||
if (node == 0) {
|
||||
logit(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n");
|
||||
in_callout = 0;
|
||||
return -1;
|
||||
}
|
||||
node->func = action;
|
||||
node->data = data;
|
||||
node->time = delay;
|
||||
node->next = 0;
|
||||
node->id = ++id;
|
||||
|
||||
prev = ptr = Q;
|
||||
|
||||
/* insert node in the queue */
|
||||
|
||||
/* if the queue is empty, insert the node and return */
|
||||
if (!Q)
|
||||
Q = node;
|
||||
else {
|
||||
/* chase the pointer looking for the right place */
|
||||
while (ptr) {
|
||||
|
||||
if (delay < ptr->time) {
|
||||
/* right place */
|
||||
|
||||
node->next = ptr;
|
||||
if (ptr == Q)
|
||||
Q = node;
|
||||
else
|
||||
prev->next = node;
|
||||
ptr->time -= node->time;
|
||||
print_Q();
|
||||
in_callout = 0;
|
||||
return node->id;
|
||||
} else {
|
||||
/* keep moving */
|
||||
|
||||
delay -= ptr->time; node->time = delay;
|
||||
prev = ptr;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
}
|
||||
prev->next = node;
|
||||
}
|
||||
print_Q();
|
||||
in_callout = 0;
|
||||
return node->id;
|
||||
}
|
||||
|
||||
|
||||
/* clears the associated timer */
|
||||
void
|
||||
timer_clearTimer(int timer_id)
|
||||
{
|
||||
struct timeout_q *ptr, *prev;
|
||||
|
||||
if (in_callout)
|
||||
return;
|
||||
if (!timer_id)
|
||||
return;
|
||||
|
||||
in_callout = 1;
|
||||
|
||||
prev = ptr = Q;
|
||||
|
||||
/*
|
||||
* find the right node, delete it. the subsequent node's time
|
||||
* gets bumped up
|
||||
*/
|
||||
|
||||
print_Q();
|
||||
while (ptr) {
|
||||
if (ptr->id == timer_id) {
|
||||
/* got the right node */
|
||||
|
||||
/* unlink it from the queue */
|
||||
if (ptr == Q)
|
||||
Q = Q->next;
|
||||
else
|
||||
prev->next = ptr->next;
|
||||
|
||||
/* increment next node if any */
|
||||
if (ptr->next != 0)
|
||||
(ptr->next)->time += ptr->time;
|
||||
|
||||
free(ptr->data);
|
||||
free(ptr);
|
||||
print_Q();
|
||||
in_callout = 0;
|
||||
return;
|
||||
}
|
||||
prev = ptr;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
print_Q();
|
||||
in_callout = 0;
|
||||
}
|
||||
|
||||
#ifdef IGMP_DEBUG
|
||||
/*
|
||||
* debugging utility
|
||||
*/
|
||||
static void
|
||||
print_Q(void)
|
||||
{
|
||||
struct timeout_q *ptr;
|
||||
|
||||
for(ptr = Q; ptr; ptr = ptr->next)
|
||||
logit(LOG_DEBUG,0,"(%d,%d) ", ptr->id, ptr->time);
|
||||
}
|
||||
#endif /* IGMP_DEBUG */
|
||||
|
||||
int
|
||||
secs_remaining(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;
|
||||
}
|
624
usr.sbin/mrouted/cfparse.y
Normal file
624
usr.sbin/mrouted/cfparse.y
Normal file
@ -0,0 +1,624 @@
|
||||
%{
|
||||
/* $NetBSD: cfparse.y,v 1.10 2003/03/05 21:05:38 wiz Exp $ */
|
||||
|
||||
/*
|
||||
* Configuration file parser for mrouted.
|
||||
*
|
||||
* Written by Bill Fenner, NRL, 1994
|
||||
* Copyright (c) 1994
|
||||
* Naval Research Laboratory (NRL/CCS)
|
||||
* and the
|
||||
* Defense Advanced Research Projects Agency (DARPA)
|
||||
*
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and its
|
||||
* documentation is hereby granted, provided that both the copyright notice and
|
||||
* this permission notice appear in all copies of the software, derivative
|
||||
* works or modified versions, and any portions thereof, and that both notices
|
||||
* appear in supporting documentation.
|
||||
*
|
||||
* NRL AND DARPA ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND
|
||||
* DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* THE USE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "defs.h"
|
||||
#include <netdb.h>
|
||||
|
||||
/*
|
||||
* Local function declarations
|
||||
*/
|
||||
static void fatal(char *fmt, ...)
|
||||
__attribute__((__format__(__printf__, 1, 2)));
|
||||
static void warn(char *fmt, ...)
|
||||
__attribute__((__format__(__printf__, 1, 2)));
|
||||
static void yyerror(char *s);
|
||||
static char * next_word(void);
|
||||
static int yylex(void);
|
||||
static u_int32_t valid_if(char *s);
|
||||
static struct ifreq * ifconfaddr(struct ifconf *ifcp, u_int32_t a);
|
||||
int yyparse(void);
|
||||
|
||||
static FILE *f __attribute__((__unused__)); /* XXX egcs */
|
||||
extern int udp_socket;
|
||||
char *configfilename = _PATH_MROUTED_CONF;
|
||||
|
||||
extern int cache_lifetime;
|
||||
extern int max_prune_lifetime;
|
||||
|
||||
static int lineno;
|
||||
static struct ifreq ifbuf[32];
|
||||
static struct ifconf ifc;
|
||||
|
||||
static struct uvif *v;
|
||||
|
||||
static int order;
|
||||
|
||||
struct addrmask {
|
||||
u_int32_t addr;
|
||||
int mask;
|
||||
};
|
||||
|
||||
struct boundnam {
|
||||
char *name;
|
||||
struct addrmask bound;
|
||||
};
|
||||
|
||||
#define MAXBOUNDS 20
|
||||
|
||||
struct boundnam boundlist[MAXBOUNDS]; /* Max. of 20 named boundaries */
|
||||
int numbounds = 0; /* Number of named boundaries */
|
||||
|
||||
%}
|
||||
|
||||
%union
|
||||
{
|
||||
int num;
|
||||
char *ptr;
|
||||
struct addrmask addrmask;
|
||||
u_int32_t addr;
|
||||
};
|
||||
|
||||
%token CACHE_LIFETIME PRUNING
|
||||
%token PHYINT TUNNEL NAME
|
||||
%token DISABLE IGMPV1 SRCRT
|
||||
%token METRIC THRESHOLD RATE_LIMIT BOUNDARY NETMASK ALTNET
|
||||
%token SYSNAM SYSCONTACT SYSVERSION SYSLOCATION
|
||||
%token <num> BOOLEAN
|
||||
%token <num> NUMBER
|
||||
%token <ptr> STRING
|
||||
%token <addrmask> ADDRMASK
|
||||
%token <addr> ADDR
|
||||
|
||||
%type <addr> interface addrname
|
||||
%type <addrmask> bound boundary addrmask
|
||||
|
||||
%start conf
|
||||
|
||||
%%
|
||||
|
||||
conf : stmts
|
||||
;
|
||||
|
||||
stmts : /* Empty */
|
||||
| stmts stmt
|
||||
;
|
||||
|
||||
stmt : error
|
||||
| PHYINT interface {
|
||||
|
||||
vifi_t vifi;
|
||||
|
||||
if (order)
|
||||
fatal("phyints must appear before tunnels");
|
||||
|
||||
for (vifi = 0, v = uvifs;
|
||||
vifi < numvifs;
|
||||
++vifi, ++v)
|
||||
if (!(v->uv_flags & VIFF_TUNNEL) &&
|
||||
$2 == v->uv_lcl_addr)
|
||||
break;
|
||||
|
||||
if (vifi == numvifs)
|
||||
fatal("%s is not a configured interface",
|
||||
inet_fmt($2,s1));
|
||||
|
||||
}
|
||||
ifmods
|
||||
| TUNNEL interface addrname {
|
||||
|
||||
struct ifreq *ifr;
|
||||
struct ifreq ffr;
|
||||
vifi_t vifi;
|
||||
|
||||
order++;
|
||||
|
||||
ifr = ifconfaddr(&ifc, $2);
|
||||
if (ifr == 0)
|
||||
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",
|
||||
inet_fmt($2, s1));
|
||||
|
||||
if (ifconfaddr(&ifc, $3) != 0)
|
||||
fatal("Tunnel remote address %s is one of mine",
|
||||
inet_fmt($3, s1));
|
||||
|
||||
for (vifi = 0, v = uvifs;
|
||||
vifi < numvifs;
|
||||
++vifi, ++v)
|
||||
if (v->uv_flags & VIFF_TUNNEL) {
|
||||
if ($3 == v->uv_rmt_addr)
|
||||
fatal("Duplicate tunnel to %s",
|
||||
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));
|
||||
}
|
||||
|
||||
if (numvifs == MAXVIFS)
|
||||
fatal("too many vifs");
|
||||
|
||||
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;
|
||||
v->uv_lcl_addr = $2;
|
||||
v->uv_rmt_addr = $3;
|
||||
v->uv_subnet = 0;
|
||||
v->uv_subnetmask= 0;
|
||||
v->uv_subnetbcast= 0;
|
||||
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;
|
||||
vifs_down = TRUE;
|
||||
}
|
||||
}
|
||||
tunnelmods
|
||||
{
|
||||
logit(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;
|
||||
}
|
||||
| NAME STRING boundary { if (numbounds >= MAXBOUNDS) {
|
||||
fatal("Too many named boundaries (max %d)", MAXBOUNDS);
|
||||
}
|
||||
|
||||
boundlist[numbounds].name = malloc(strlen($2) + 1);
|
||||
strcpy(boundlist[numbounds].name, $2);
|
||||
boundlist[numbounds++].bound = $3;
|
||||
}
|
||||
| SYSNAM STRING {
|
||||
#ifdef SNMP
|
||||
set_sysName($2);
|
||||
#endif /* SNMP */
|
||||
}
|
||||
| SYSCONTACT STRING {
|
||||
#ifdef SNMP
|
||||
set_sysContact($2);
|
||||
#endif /* SNMP */
|
||||
}
|
||||
| SYSVERSION STRING {
|
||||
#ifdef SNMP
|
||||
set_sysVersion($2);
|
||||
#endif /* SNMP */
|
||||
}
|
||||
| SYSLOCATION STRING {
|
||||
#ifdef SNMP
|
||||
set_sysLocation($2);
|
||||
#endif /* SNMP */
|
||||
}
|
||||
;
|
||||
|
||||
tunnelmods : /* empty */
|
||||
| tunnelmods tunnelmod
|
||||
;
|
||||
|
||||
tunnelmod : mod
|
||||
| SRCRT { fatal("Source-route tunnels not supported"); }
|
||||
;
|
||||
|
||||
ifmods : /* empty */
|
||||
| ifmods ifmod
|
||||
;
|
||||
|
||||
ifmod : mod
|
||||
| DISABLE { v->uv_flags |= VIFF_DISABLED; }
|
||||
| IGMPV1 { v->uv_flags |= VIFF_IGMPV1; }
|
||||
| NETMASK addrname {
|
||||
u_int32_t subnet, mask;
|
||||
|
||||
mask = $2;
|
||||
subnet = v->uv_lcl_addr & mask;
|
||||
if (!inet_valid_subnet(subnet, mask))
|
||||
fatal("Invalid netmask");
|
||||
v->uv_subnet = subnet;
|
||||
v->uv_subnetmask = mask;
|
||||
v->uv_subnetbcast = subnet | ~mask;
|
||||
}
|
||||
| NETMASK {
|
||||
|
||||
warn("Expected address after netmask keyword, ignored");
|
||||
|
||||
}
|
||||
| ALTNET addrmask {
|
||||
|
||||
struct phaddr *ph;
|
||||
|
||||
ph = (struct phaddr *)malloc(sizeof(struct phaddr));
|
||||
if (ph == NULL)
|
||||
fatal("out of memory");
|
||||
if ($2.mask) {
|
||||
VAL_TO_MASK(ph->pa_subnetmask, $2.mask);
|
||||
} else
|
||||
ph->pa_subnetmask = v->uv_subnetmask;
|
||||
ph->pa_subnet = $2.addr & ph->pa_subnetmask;
|
||||
ph->pa_subnetbcast = ph->pa_subnet | ~ph->pa_subnetmask;
|
||||
if ($2.addr & ~ph->pa_subnetmask)
|
||||
warn("Extra subnet %s/%d has host bits set",
|
||||
inet_fmt($2.addr,s1), $2.mask);
|
||||
ph->pa_next = v->uv_addrs;
|
||||
v->uv_addrs = ph;
|
||||
|
||||
}
|
||||
| ALTNET {
|
||||
|
||||
warn("Expected address after altnet keyword, ignored");
|
||||
|
||||
}
|
||||
;
|
||||
|
||||
mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255)
|
||||
fatal("Invalid threshold %d",$2);
|
||||
v->uv_threshold = $2;
|
||||
}
|
||||
| THRESHOLD {
|
||||
|
||||
warn("Expected number after threshold keyword, ignored");
|
||||
|
||||
}
|
||||
| METRIC NUMBER { if ($2 < 1 || $2 > UNREACHABLE)
|
||||
fatal("Invalid metric %d",$2);
|
||||
v->uv_metric = $2;
|
||||
}
|
||||
| METRIC {
|
||||
|
||||
warn("Expected number after metric keyword, ignored");
|
||||
|
||||
}
|
||||
| RATE_LIMIT NUMBER { if ($2 > MAX_RATE_LIMIT)
|
||||
fatal("Invalid rate_limit %d",$2);
|
||||
v->uv_rate_limit = $2;
|
||||
}
|
||||
| RATE_LIMIT {
|
||||
|
||||
warn("Expected number after rate_limit keyword, ignored");
|
||||
|
||||
}
|
||||
| BOUNDARY bound {
|
||||
|
||||
struct vif_acl *v_acl;
|
||||
|
||||
v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
|
||||
if (v_acl == NULL)
|
||||
fatal("out of memory");
|
||||
VAL_TO_MASK(v_acl->acl_mask, $2.mask);
|
||||
v_acl->acl_addr = $2.addr & v_acl->acl_mask;
|
||||
if ($2.addr & ~v_acl->acl_mask)
|
||||
warn("Boundary spec %s/%d has host bits set",
|
||||
inet_fmt($2.addr,s1),$2.mask);
|
||||
v_acl->acl_next = v->uv_acl;
|
||||
v->uv_acl = v_acl;
|
||||
|
||||
}
|
||||
| BOUNDARY {
|
||||
|
||||
warn("Expected boundary spec after boundary keyword, ignored");
|
||||
|
||||
}
|
||||
;
|
||||
|
||||
interface : ADDR { $$ = $1; }
|
||||
| STRING {
|
||||
$$ = valid_if($1);
|
||||
if ($$ == 0)
|
||||
fatal("Invalid interface name %s",$1);
|
||||
}
|
||||
;
|
||||
|
||||
addrname : ADDR { $$ = $1; }
|
||||
| STRING { struct hostent *hp;
|
||||
|
||||
if ((hp = gethostbyname($1)) == NULL)
|
||||
fatal("No such host %s", $1);
|
||||
|
||||
if (hp->h_addr_list[1])
|
||||
fatal("Hostname %s does not %s",
|
||||
$1, "map to a unique address");
|
||||
|
||||
bcopy(hp->h_addr_list[0], &$$,
|
||||
hp->h_length);
|
||||
}
|
||||
|
||||
bound : boundary { $$ = $1; }
|
||||
| STRING { int i;
|
||||
|
||||
for (i=0; i < numbounds; i++) {
|
||||
if (!strcmp(boundlist[i].name, $1)) {
|
||||
$$ = boundlist[i].bound;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == numbounds) {
|
||||
fatal("Invalid boundary name %s",$1);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
boundary : ADDRMASK {
|
||||
|
||||
if ((ntohl($1.addr) & 0xff000000) != 0xef000000) {
|
||||
fatal("Boundaries must be 239.x.x.x, not %s/%d",
|
||||
inet_fmt($1.addr, s1), $1.mask);
|
||||
}
|
||||
$$ = $1;
|
||||
|
||||
}
|
||||
;
|
||||
|
||||
addrmask : ADDRMASK { $$ = $1; }
|
||||
| ADDR { $$.addr = $1; $$.mask = 0; }
|
||||
;
|
||||
%%
|
||||
static void
|
||||
fatal(char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[200];
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsprintf(buf, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
logit(LOG_ERR,0,"%s: %s near line %d", configfilename, buf, lineno);
|
||||
}
|
||||
|
||||
static void
|
||||
warn(char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[200];
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsprintf(buf, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
logit(LOG_WARNING,0,"%s: %s near line %d", configfilename, buf, lineno);
|
||||
}
|
||||
|
||||
static void
|
||||
yyerror(s)
|
||||
char *s;
|
||||
{
|
||||
logit(LOG_ERR, 0, "%s: %s near line %d", configfilename, s, lineno);
|
||||
}
|
||||
|
||||
static char *
|
||||
next_word()
|
||||
{
|
||||
static char buf[1024];
|
||||
static char *p=NULL;
|
||||
extern FILE *f;
|
||||
char *q;
|
||||
|
||||
while (1) {
|
||||
if (!p || !*p) {
|
||||
lineno++;
|
||||
if (fgets(buf, sizeof(buf), f) == NULL)
|
||||
return NULL;
|
||||
p = buf;
|
||||
}
|
||||
while (*p && (*p == ' ' || *p == '\t')) /* skip whitespace */
|
||||
p++;
|
||||
if (*p == '#') {
|
||||
p = NULL; /* skip comments */
|
||||
continue;
|
||||
}
|
||||
q = p;
|
||||
#ifdef SNMP
|
||||
if (*p == '"') {
|
||||
p++;
|
||||
while (*p && *p != '"' && *p != '\n')
|
||||
p++; /* find next whitespace */
|
||||
if (*p == '"')
|
||||
p++;
|
||||
} else
|
||||
#endif
|
||||
while (*p && *p != ' ' && *p != '\t' && *p != '\n')
|
||||
p++; /* find next whitespace */
|
||||
*p++ = '\0'; /* null-terminate string */
|
||||
|
||||
if (!*q) {
|
||||
p = NULL;
|
||||
continue; /* if 0-length string, read another line */
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
yylex()
|
||||
{
|
||||
int n;
|
||||
u_int32_t addr;
|
||||
char *q;
|
||||
|
||||
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;
|
||||
if (!strcmp(q,"on") || !strcmp(q,"yes")) {
|
||||
yylval.num = 1;
|
||||
return BOOLEAN;
|
||||
}
|
||||
if (!strcmp(q,"off") || !strcmp(q,"no")) {
|
||||
yylval.num = 0;
|
||||
return BOOLEAN;
|
||||
}
|
||||
if (sscanf(q,"%[.0-9]/%d%c",s1,&n,s2) == 2) {
|
||||
if ((addr = inet_parse(s1)) != 0xffffffff) {
|
||||
yylval.addrmask.mask = n;
|
||||
yylval.addrmask.addr = addr;
|
||||
return ADDRMASK;
|
||||
}
|
||||
/* fall through to returning STRING */
|
||||
}
|
||||
if (sscanf(q,"%[.0-9]%c",s1,s2) == 1) {
|
||||
if ((addr = inet_parse(s1)) != 0xffffffff &&
|
||||
inet_valid_host(addr)) {
|
||||
yylval.addr = addr;
|
||||
return ADDR;
|
||||
}
|
||||
}
|
||||
if (sscanf(q,"0x%8x%c",&n,s1) == 1) {
|
||||
yylval.addr = n;
|
||||
return ADDR;
|
||||
}
|
||||
if (sscanf(q,"%d%c",&n,s1) == 1) {
|
||||
yylval.num = n;
|
||||
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 */
|
||||
yylval.ptr = q+1;
|
||||
return STRING;
|
||||
}
|
||||
#endif
|
||||
yylval.ptr = q;
|
||||
return STRING;
|
||||
}
|
||||
|
||||
void
|
||||
config_vifs_from_file()
|
||||
{
|
||||
extern FILE *f;
|
||||
|
||||
order = 0;
|
||||
numbounds = 0;
|
||||
lineno = 0;
|
||||
|
||||
if ((f = fopen(configfilename, "r")) == NULL) {
|
||||
if (errno != ENOENT)
|
||||
logit(LOG_ERR, errno, "can't open %s", configfilename);
|
||||
return;
|
||||
}
|
||||
|
||||
ifc.ifc_buf = (char *)ifbuf;
|
||||
ifc.ifc_len = sizeof(ifbuf);
|
||||
if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
|
||||
logit(LOG_ERR, errno, "ioctl SIOCGIFCONF");
|
||||
|
||||
yyparse();
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static u_int32_t
|
||||
valid_if(s)
|
||||
char *s;
|
||||
{
|
||||
vifi_t vifi;
|
||||
struct uvif *v;
|
||||
|
||||
for (vifi=0, v=uvifs; vifi<numvifs; vifi++, v++)
|
||||
if (!strcmp(v->uv_name, s))
|
||||
return v->uv_lcl_addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ifreq *
|
||||
ifconfaddr(ifcp, a)
|
||||
struct ifconf *ifcp;
|
||||
u_int32_t a;
|
||||
{
|
||||
int n;
|
||||
struct ifreq *ifrp = (struct ifreq *)ifcp->ifc_buf;
|
||||
struct ifreq *ifend = (struct ifreq *)((char *)ifrp + ifcp->ifc_len);
|
||||
|
||||
while (ifrp < ifend) {
|
||||
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))
|
||||
n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
|
||||
if (n < sizeof(*ifrp))
|
||||
++ifrp;
|
||||
else
|
||||
ifrp = (struct ifreq *)((char *)ifrp + n);
|
||||
#else
|
||||
++ifrp;
|
||||
#endif
|
||||
}
|
||||
return (0);
|
||||
}
|
121
usr.sbin/mrouted/config.c
Normal file
121
usr.sbin/mrouted/config.c
Normal file
@ -0,0 +1,121 @@
|
||||
/* $NetBSD: config.c,v 1.11 2003/03/05 21:05:38 wiz Exp $ */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include <net/if.h>
|
||||
#include <ifaddrs.h>
|
||||
|
||||
|
||||
/*
|
||||
* Query the kernel to find network interfaces that are multicast-capable
|
||||
* and install them in the uvifs array.
|
||||
*/
|
||||
void
|
||||
config_vifs_from_kernel(void)
|
||||
{
|
||||
struct ifaddrs *ifa, *ifap;
|
||||
struct uvif *v;
|
||||
vifi_t vifi;
|
||||
u_int32_t addr, mask, subnet;
|
||||
short flags;
|
||||
|
||||
if (getifaddrs(&ifap) < 0)
|
||||
logit(LOG_ERR, errno, "getifaddrs");
|
||||
|
||||
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
|
||||
/*
|
||||
* Ignore any interface for an address family other than IP.
|
||||
*/
|
||||
if (ifa->ifa_addr->sa_family != AF_INET)
|
||||
continue;
|
||||
|
||||
addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
|
||||
|
||||
/*
|
||||
* Ignore loopback interfaces and interfaces that do not support
|
||||
* multicast.
|
||||
*/
|
||||
flags = ifa->ifa_flags;
|
||||
if ((flags & (IFF_LOOPBACK|IFF_MULTICAST)) != IFF_MULTICAST)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Ignore any interface whose address and mask do not define a
|
||||
* valid subnet number, or whose address is of the form {subnet,0}
|
||||
* or {subnet,-1}.
|
||||
*/
|
||||
mask = ((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr.s_addr;
|
||||
subnet = addr & mask;
|
||||
if (!inet_valid_subnet(subnet, mask) ||
|
||||
addr == subnet ||
|
||||
addr == (subnet | ~mask)) {
|
||||
logit(LOG_WARNING, 0,
|
||||
"ignoring %s, has invalid address (%s) and/or mask (%s)",
|
||||
ifa->ifa_name, inet_fmt(addr, s1), inet_fmt(mask, s2));
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore any interface that is connected to the same subnet as
|
||||
* one already installed in the uvifs array.
|
||||
*/
|
||||
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
|
||||
if ((addr & v->uv_subnetmask) == v->uv_subnet ||
|
||||
(v->uv_subnet & mask) == subnet) {
|
||||
logit(LOG_WARNING, 0, "ignoring %s, same subnet as %s",
|
||||
ifa->ifa_name, v->uv_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (vifi != numvifs)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If there is room in the uvifs array, install this interface.
|
||||
*/
|
||||
if (numvifs == MAXVIFS) {
|
||||
logit(LOG_WARNING, 0, "too many vifs, ignoring %s", ifa->ifa_name);
|
||||
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;
|
||||
v->uv_lcl_addr = addr;
|
||||
v->uv_rmt_addr = 0;
|
||||
v->uv_subnet = subnet;
|
||||
v->uv_subnetmask = mask;
|
||||
v->uv_subnetbcast = subnet | ~mask;
|
||||
strlcpy(v->uv_name, ifa->ifa_name, sizeof(v->uv_name));
|
||||
v->uv_groups = NULL;
|
||||
v->uv_neighbors = NULL;
|
||||
v->uv_acl = NULL;
|
||||
v->uv_addrs = NULL;
|
||||
|
||||
logit(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),
|
||||
numvifs, v->uv_rate_limit);
|
||||
|
||||
++numvifs;
|
||||
|
||||
/*
|
||||
* If the interface is not yet up, set the vifs_down flag to
|
||||
* remind us to check again later.
|
||||
*/
|
||||
if (!(flags & IFF_UP)) {
|
||||
v->uv_flags |= VIFF_DOWN;
|
||||
vifs_down = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(ifap);
|
||||
}
|
304
usr.sbin/mrouted/defs.h
Normal file
304
usr.sbin/mrouted/defs.h
Normal file
@ -0,0 +1,304 @@
|
||||
/* $NetBSD: defs.h,v 1.11 2003/03/05 21:05:38 wiz Exp $ */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef SYSV
|
||||
#include <sys/sockio.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/igmp.h>
|
||||
#include <netinet/ip_mroute.h>
|
||||
#ifdef RSRR
|
||||
#include <sys/un.h>
|
||||
#endif /* RSRR */
|
||||
|
||||
typedef void (*cfunc_t)(void *);
|
||||
typedef void (*ihfunc_t)(int, fd_set *);
|
||||
|
||||
#include "dvmrp.h"
|
||||
#include "vif.h"
|
||||
#include "route.h"
|
||||
#include "prune.h"
|
||||
#include "pathnames.h"
|
||||
#ifdef RSRR
|
||||
#include "rsrr.h"
|
||||
#include "rsrr_var.h"
|
||||
#endif /* RSRR */
|
||||
|
||||
/*
|
||||
* Miscellaneous constants and macros.
|
||||
*/
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
#define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0)
|
||||
|
||||
#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 8 /* increment on local changes or bug fixes, */
|
||||
/* reset to 0 whever PROTOCOL_VERSION increments */
|
||||
|
||||
#define MROUTED_LEVEL ((MROUTED_VERSION << 8) | PROTOCOL_VERSION | \
|
||||
((NF_PRUNE | NF_GENID | NF_MTRACE) << 16) | \
|
||||
(VENDOR_CODE << 24))
|
||||
/* 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 */
|
||||
|
||||
/* obnoxious gcc gives an extraneous warning about this constant... */
|
||||
#define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */
|
||||
|
||||
#ifdef RSRR
|
||||
#define BIT_ZERO(X) ((X) = 0)
|
||||
#define BIT_SET(X,n) ((X) |= 1 << (n))
|
||||
#define BIT_CLR(X,n) ((X) &= ~(1 << (n)))
|
||||
#define BIT_TST(X,n) ((X) & 1 << (n))
|
||||
#endif /* RSRR */
|
||||
|
||||
#ifdef SYSV
|
||||
#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
|
||||
|
||||
/*
|
||||
* External declarations for global variables and functions.
|
||||
*/
|
||||
#define RECV_BUF_SIZE 8192
|
||||
extern char *recv_buf;
|
||||
extern char *send_buf;
|
||||
extern int igmp_socket;
|
||||
#ifdef RSRR
|
||||
extern int rsrr_socket;
|
||||
#endif /* RSRR */
|
||||
extern u_int32_t allhosts_group;
|
||||
extern u_int32_t allrtrs_group;
|
||||
extern u_int32_t dvmrp_group;
|
||||
extern u_int32_t dvmrp_genid;
|
||||
|
||||
#define DEFAULT_DEBUG 2 /* default if "-d" given without value */
|
||||
|
||||
extern int debug;
|
||||
extern u_char pruning;
|
||||
|
||||
extern int routes_changed;
|
||||
extern int delay_change_reports;
|
||||
extern unsigned nroutes;
|
||||
|
||||
extern struct uvif uvifs[MAXVIFS];
|
||||
extern vifi_t numvifs;
|
||||
extern int vifs_down;
|
||||
extern int udp_socket;
|
||||
extern int vifs_with_neighbors;
|
||||
|
||||
extern char s1[];
|
||||
extern char s2[];
|
||||
extern char s3[];
|
||||
extern char s4[];
|
||||
|
||||
#if !(defined(BSD) && (BSD >= 199103))
|
||||
extern int errno;
|
||||
extern int sys_nerr;
|
||||
extern char * sys_errlist[];
|
||||
#endif
|
||||
|
||||
#ifdef OLD_KERNEL
|
||||
#define MRT_INIT DVMRP_INIT
|
||||
#define MRT_DONE DVMRP_DONE
|
||||
#define MRT_ADD_VIF DVMRP_ADD_VIF
|
||||
#define MRT_DEL_VIF DVMRP_DEL_VIF
|
||||
#define MRT_ADD_MFC DVMRP_ADD_MFC
|
||||
#define MRT_DEL_MFC DVMRP_DEL_MFC
|
||||
|
||||
#define IGMP_PIM 0x14
|
||||
#endif
|
||||
|
||||
/* main.c */
|
||||
extern void logit(int, int, const char *, ...)
|
||||
__attribute__((__format__(__printf__, 3, 4)));
|
||||
extern int register_input_handler(int fd, ihfunc_t func);
|
||||
|
||||
/* igmp.c */
|
||||
extern void init_igmp(void);
|
||||
extern void accept_igmp(int recvlen);
|
||||
extern void send_igmp(u_int32_t src, u_int32_t dst, int type,
|
||||
int code, u_int32_t group, int datalen);
|
||||
|
||||
/* callout.c */
|
||||
extern void callout_init(void);
|
||||
extern void age_callout_queue(void);
|
||||
extern int timer_setTimer(int delay, cfunc_t action, char *data);
|
||||
extern void timer_clearTimer(int timer_id);
|
||||
|
||||
/* route.c */
|
||||
extern void init_routes(void);
|
||||
extern void start_route_updates(void);
|
||||
extern void update_route(u_int32_t origin, u_int32_t mask,
|
||||
u_int metric, u_int32_t src, vifi_t vifi);
|
||||
extern void age_routes(void);
|
||||
extern void expire_all_routes(void);
|
||||
extern void free_all_routes(void);
|
||||
extern void accept_probe(u_int32_t src, u_int32_t dst,
|
||||
char *p, int datalen, u_int32_t level);
|
||||
extern void accept_report(u_int32_t src, u_int32_t dst,
|
||||
char *p, int datalen, u_int32_t level);
|
||||
extern struct rtentry * determine_route(u_int32_t src);
|
||||
extern void report(int which_routes, vifi_t vifi, u_int32_t dst);
|
||||
extern void report_to_all_neighbors(int which_routes);
|
||||
extern int report_next_chunk(void);
|
||||
extern void add_vif_to_routes(vifi_t vifi);
|
||||
extern void delete_vif_from_routes(vifi_t vifi);
|
||||
extern void delete_neighbor_from_routes(u_int32_t addr,
|
||||
vifi_t vifi);
|
||||
extern void dump_routes(FILE *fp);
|
||||
extern void start_route_updates(void);
|
||||
|
||||
/* vif.c */
|
||||
extern void init_vifs(void);
|
||||
extern void check_vif_state(void);
|
||||
extern vifi_t find_vif(u_int32_t src, u_int32_t dst);
|
||||
extern void age_vifs(void);
|
||||
extern void dump_vifs(FILE *fp);
|
||||
extern void stop_all_vifs(void);
|
||||
extern struct listaddr *neighbor_info(vifi_t vifi, u_int32_t addr);
|
||||
extern void accept_group_report(u_int32_t src, u_int32_t dst,
|
||||
u_int32_t group, int r_type);
|
||||
extern void query_groups(void);
|
||||
extern void probe_for_neighbors(void);
|
||||
extern int update_neighbor(vifi_t vifi, u_int32_t addr,
|
||||
int msgtype, char *p, int datalen,
|
||||
u_int32_t level);
|
||||
extern void accept_neighbor_request(u_int32_t src, u_int32_t dst);
|
||||
extern void accept_neighbor_request2(u_int32_t src, u_int32_t dst);
|
||||
extern void accept_neighbors(u_int32_t src, u_int32_t dst,
|
||||
u_char *p, int datalen,
|
||||
u_int32_t level);
|
||||
extern void accept_neighbors2(u_int32_t src, u_int32_t dst,
|
||||
u_char *p, int datalen,
|
||||
u_int32_t level);
|
||||
extern void accept_leave_message(u_int32_t src, u_int32_t dst,
|
||||
u_int32_t group);
|
||||
extern void accept_membership_query(u_int32_t src, u_int32_t dst,
|
||||
u_int32_t group, int tmo);
|
||||
|
||||
/* config.c */
|
||||
extern void config_vifs_from_kernel(void);
|
||||
|
||||
/* cfparse.y */
|
||||
extern void config_vifs_from_file(void);
|
||||
|
||||
/* inet.c */
|
||||
extern int inet_valid_host(u_int32_t naddr);
|
||||
extern int inet_valid_mask(u_int32_t mask);
|
||||
extern int inet_valid_subnet(u_int32_t nsubnet, u_int32_t nmask);
|
||||
extern char * inet_fmt(u_int32_t addr, char *s);
|
||||
extern char * inet_fmts(u_int32_t addr, u_int32_t mask, char *s);
|
||||
extern u_int32_t inet_parse(char *s);
|
||||
extern int inet_cksum(u_short *addr, u_int len);
|
||||
|
||||
/* prune.c */
|
||||
extern unsigned kroutes;
|
||||
extern void add_table_entry(u_int32_t origin, u_int32_t mcastgrp);
|
||||
extern void del_table_entry(struct rtentry *r,
|
||||
u_int32_t mcastgrp, u_int del_flag);
|
||||
extern void update_table_entry(struct rtentry *r);
|
||||
extern void init_ktable(void);
|
||||
extern void accept_prune(u_int32_t src, u_int32_t dst, char *p,
|
||||
int datalen);
|
||||
extern void steal_sources(struct rtentry *rt);
|
||||
extern void reset_neighbor_state(vifi_t vifi, u_int32_t addr);
|
||||
extern int grplst_mem(vifi_t vifi, u_int32_t mcastgrp);
|
||||
extern int scoped_addr(vifi_t vifi, u_int32_t addr);
|
||||
extern void free_all_prunes(void);
|
||||
extern void age_table_entry(void);
|
||||
extern void dump_cache(FILE *fp2);
|
||||
extern void update_lclgrp(vifi_t vifi, u_int32_t mcastgrp);
|
||||
extern void delete_lclgrp(vifi_t vifi, u_int32_t mcastgrp);
|
||||
extern void chkgrp_graft(vifi_t vifi, u_int32_t mcastgrp);
|
||||
extern void accept_graft(u_int32_t src, u_int32_t dst, char *p,
|
||||
int datalen);
|
||||
extern void accept_g_ack(u_int32_t src, u_int32_t dst, char *p,
|
||||
int datalen);
|
||||
/* u_int is promoted u_char */
|
||||
extern void accept_mtrace(u_int32_t src, u_int32_t dst,
|
||||
u_int32_t group, char *data, u_int no,
|
||||
int datalen);
|
||||
extern int find_src_grp(u_int32_t, u_int32_t, u_int32_t);
|
||||
|
||||
/* kern.c */
|
||||
extern void k_set_rcvbuf(int bufsize);
|
||||
extern void k_hdr_include(int bool);
|
||||
extern void k_set_ttl(int t);
|
||||
extern void k_set_loop(int l);
|
||||
extern void k_set_if(u_int32_t ifa);
|
||||
extern void k_join(u_int32_t grp, u_int32_t ifa);
|
||||
extern void k_leave(u_int32_t grp, u_int32_t ifa);
|
||||
extern void k_init_dvmrp(void);
|
||||
extern void k_stop_dvmrp(void);
|
||||
extern void k_add_vif(vifi_t vifi, struct uvif *v);
|
||||
extern void k_del_vif(vifi_t vifi);
|
||||
extern void k_add_rg(u_int32_t origin, struct gtable *g);
|
||||
extern int k_del_rg(u_int32_t origin, struct gtable *g);
|
||||
extern int k_get_version(void);
|
||||
|
||||
#ifdef SNMP
|
||||
/* prune.c */
|
||||
extern struct rtentry * snmp_find_route();
|
||||
extern struct gtable * find_grp();
|
||||
extern struct stable * find_grp_src();
|
||||
#endif
|
||||
|
||||
#ifdef RSRR
|
||||
/* prune.c */
|
||||
extern struct gtable *kernel_table;
|
||||
extern struct gtable *gtp;
|
||||
extern int find_src_grp(u_int32_t src, u_int32_t mask,
|
||||
u_int32_t grp);
|
||||
|
||||
/* rsrr.c */
|
||||
extern void rsrr_init(void);
|
||||
extern void rsrr_read(int f, fd_set *rfd);
|
||||
extern void rsrr_clean(void);
|
||||
extern void rsrr_cache_send(struct gtable *gt, int notify);
|
||||
extern void rsrr_cache_clean(struct gtable *gt);
|
||||
#endif /* RSRR */
|
||||
|
||||
/* vif.c */
|
||||
extern void accept_info_reply(u_int32_t, u_int32_t, u_char *, int);
|
||||
extern void accept_info_request(u_int32_t, u_int32_t,
|
||||
u_char *, int);
|
||||
extern void init_installvifs(void);
|
173
usr.sbin/mrouted/dvmrp.h
Normal file
173
usr.sbin/mrouted/dvmrp.h
Normal file
@ -0,0 +1,173 @@
|
||||
/* $NetBSD: dvmrp.h,v 1.7 2003/03/05 21:05:39 wiz Exp $ */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* A DVMRP message consists of an IP header + an IGMP header + (for some types)
|
||||
* zero or more bytes of data.
|
||||
*
|
||||
* For REPORT messages, the data is route information; the route information
|
||||
* consists of one or more lists of the following form:
|
||||
*
|
||||
* (mask, (origin, metric), (origin, metric), ...)
|
||||
*
|
||||
* where:
|
||||
*
|
||||
* "mask" is the subnet mask for all the origins in the list.
|
||||
* It is always THREE bytes long, containing the low-order
|
||||
* three bytes of the mask (the high-order byte is always
|
||||
* 0xff and therefore need not be transmitted).
|
||||
*
|
||||
* "origin" is the number of a subnet from which multicast datagrams
|
||||
* may originate. It is from one to four bytes long,
|
||||
* depending on the value of "mask":
|
||||
* if all bytes of the mask are zero
|
||||
* the subnet number is one byte long
|
||||
* else if the low-order two bytes of the mask are zero
|
||||
* the subnet number is two bytes long
|
||||
* else if the lowest-order byte of the mask is zero
|
||||
* the subnet number is three bytes long,
|
||||
* else
|
||||
* the subnet number is four bytes long.
|
||||
*
|
||||
* "metric" is a one-byte value consisting of two subfields:
|
||||
* - the high-order bit is a flag which, when set, indicates
|
||||
* the last (origin, metric) pair of a list.
|
||||
* - the low-order seven bits contain the routing metric for
|
||||
* the corresponding origin, relative to the sender of the
|
||||
* DVMRP report. The metric may have the value of UNREACHABLE
|
||||
* added to it as a "split horizon" indication (so called
|
||||
* "poisoned reverse").
|
||||
*
|
||||
* Within a list, the origin subnet numbers must be in ascending order, and
|
||||
* the lists themselves are in order of increasing mask value. A message may
|
||||
* not exceed 576 bytes, the default maximum IP reassembly size, including
|
||||
* the IP and IGMP headers; the route information may be split across more
|
||||
* than one message if necessary, by terminating a list in one message and
|
||||
* starting a new list in the next message (repeating the same mask value,
|
||||
* if necessary).
|
||||
*
|
||||
* For NEIGHBORS messages, the data is neighboring-router information
|
||||
* consisting of one or more lists of the following form:
|
||||
*
|
||||
* (local-addr, metric, threshold, ncount, neighbor, neighbor, ...)
|
||||
*
|
||||
* where:
|
||||
*
|
||||
* "local-addr" is the sending router's address as seen by the neighbors
|
||||
* in this list; it is always four bytes long.
|
||||
* "metric" is a one-byte unsigned value, the TTL `cost' of forwarding
|
||||
* packets to any of the neighbors on this list.
|
||||
* "threshold" is a one-byte unsigned value, a lower bound on the TTL a
|
||||
* packet must have to be forwarded to any of the neighbors on
|
||||
* this list.
|
||||
* "ncount" is the number of neighbors in this list.
|
||||
* "neighbor" is the address of a neighboring router, four bytes long.
|
||||
*
|
||||
* As with REPORT messages, NEIGHBORS messages should not exceed 576 bytes,
|
||||
* including the IP and IGMP headers; split longer messages by terminating the
|
||||
* list in one and continuing in another, repeating the local-addr, etc., if
|
||||
* necessary.
|
||||
*
|
||||
* For NEIGHBORS2 messages, the data is identical to NEIGHBORS except
|
||||
* there is a flags byte before the neighbor count:
|
||||
*
|
||||
* (local-addr, metric, threshold, flags, ncount, neighbor, neighbor, ...)
|
||||
*/
|
||||
|
||||
/*
|
||||
* DVMRP message types (carried in the "code" field of an IGMP header)
|
||||
*/
|
||||
#define DVMRP_PROBE 1 /* for finding neighbors */
|
||||
#define DVMRP_REPORT 2 /* for reporting some or all routes */
|
||||
#define DVMRP_ASK_NEIGHBORS 3 /* sent by mapper, asking for a list */
|
||||
/* of this router's neighbors. */
|
||||
#define DVMRP_NEIGHBORS 4 /* response to such a request */
|
||||
#define DVMRP_ASK_NEIGHBORS2 5 /* as above, want new format reply */
|
||||
#define DVMRP_NEIGHBORS2 6
|
||||
#define DVMRP_PRUNE 7 /* prune message */
|
||||
#define DVMRP_GRAFT 8 /* graft message */
|
||||
#define DVMRP_GRAFT_ACK 9 /* graft acknowledgement */
|
||||
#define DVMRP_INFO_REQUEST 10 /* information request */
|
||||
#define DVMRP_INFO_REPLY 11 /* information reply */
|
||||
|
||||
/*
|
||||
* 'flags' byte values in DVMRP_NEIGHBORS2 reply.
|
||||
*/
|
||||
#define DVMRP_NF_TUNNEL 0x01 /* neighbors reached via tunnel */
|
||||
#define DVMRP_NF_SRCRT 0x02 /* tunnel uses IP source routing */
|
||||
#define DVMRP_NF_PIM 0x04 /* neighbor is a PIM neighbor */
|
||||
#define DVMRP_NF_DOWN 0x10 /* kernel state of interface */
|
||||
#define DVMRP_NF_DISABLED 0x20 /* administratively disabled */
|
||||
#define DVMRP_NF_QUERIER 0x40 /* I am the subnet's querier */
|
||||
#define DVMRP_NF_LEAF 0x80 /* Neighbor reports that it is a leaf */
|
||||
|
||||
/*
|
||||
* Request/reply types for info queries/replies
|
||||
*/
|
||||
#define DVMRP_INFO_VERSION 1 /* version string */
|
||||
#define DVMRP_INFO_NEIGHBORS 2 /* neighbors2 data */
|
||||
|
||||
/*
|
||||
* Limit on length of route data
|
||||
*/
|
||||
#define MAX_IP_PACKET_LEN 576
|
||||
#define MIN_IP_HEADER_LEN 20
|
||||
#define MAX_IP_HEADER_LEN 60
|
||||
#define MAX_DVMRP_DATA_LEN \
|
||||
( MAX_IP_PACKET_LEN - MAX_IP_HEADER_LEN - IGMP_MINLEN )
|
||||
|
||||
/*
|
||||
* Various protocol constants (all times in seconds)
|
||||
*/
|
||||
/* address for multicast DVMRP msgs */
|
||||
#define INADDR_DVMRP_GROUP (u_int32_t)0xe0000004 /* 224.0.0.4 */
|
||||
/*
|
||||
* The IGMPv2 <netinet/in.h> defines INADDR_ALLRTRS_GROUP, but earlier
|
||||
* ones don't, so we define it conditionally here.
|
||||
*/
|
||||
#ifndef INADDR_ALLRTRS_GROUP
|
||||
/* address for multicast mtrace msg */
|
||||
#define INADDR_ALLRTRS_GROUP (u_int32_t)0xe0000002 /* 224.0.0.2 */
|
||||
#endif
|
||||
|
||||
#define ROUTE_MAX_REPORT_DELAY 5 /* max delay for reporting changes */
|
||||
/* (This is the timer interrupt */
|
||||
/* interval; all times must be */
|
||||
/* multiples of this value.) */
|
||||
|
||||
#define ROUTE_REPORT_INTERVAL 60 /* periodic route report interval */
|
||||
#define ROUTE_SWITCH_TIME 140 /* time to switch to equivalent gw */
|
||||
#define ROUTE_EXPIRE_TIME 200 /* time to mark route invalid */
|
||||
#define ROUTE_DISCARD_TIME 340 /* time to garbage collect route */
|
||||
|
||||
#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 UNREACHABLE 32 /* "infinity" metric, must be <= 64 */
|
||||
#define DEFAULT_METRIC 1 /* default subnet/tunnel metric */
|
||||
#define DEFAULT_THRESHOLD 1 /* default subnet/tunnel threshold */
|
||||
|
||||
#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_CACHE_LIFETIME 300 /* kernel route entry discard time */
|
||||
#define GRAFT_TIMEOUT_VAL 5 /* retransmission time for grafts */
|
||||
|
||||
#define OLD_AGE_THRESHOLD 2
|
351
usr.sbin/mrouted/igmp.c
Normal file
351
usr.sbin/mrouted/igmp.c
Normal file
@ -0,0 +1,351 @@
|
||||
/* $NetBSD: igmp.c,v 1.10 2003/03/05 21:05:39 wiz Exp $ */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
|
||||
/*
|
||||
* Exported variables.
|
||||
*/
|
||||
char *recv_buf; /* input packet buffer */
|
||||
char *send_buf; /* output packet buffer */
|
||||
int igmp_socket; /* socket for all network I/O */
|
||||
u_int32_t allhosts_group; /* All hosts addr in net order */
|
||||
u_int32_t allrtrs_group; /* All-Routers " in net order */
|
||||
u_int32_t dvmrp_group; /* DVMRP grp addr in net order */
|
||||
u_int32_t dvmrp_genid; /* IGMP generation id */
|
||||
|
||||
/*
|
||||
* Local function definitions.
|
||||
*/
|
||||
/* u_char promoted to u_int */
|
||||
static char * packet_kind(u_int type, u_int code);
|
||||
static int igmp_log_level(u_int type, u_int code);
|
||||
|
||||
/*
|
||||
* Open and initialize the igmp socket, and fill in the non-changing
|
||||
* IP header fields in the output packet buffer.
|
||||
*/
|
||||
void
|
||||
init_igmp(void)
|
||||
{
|
||||
struct ip *ip;
|
||||
|
||||
recv_buf = malloc(RECV_BUF_SIZE);
|
||||
send_buf = malloc(RECV_BUF_SIZE);
|
||||
|
||||
if ((igmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0)
|
||||
logit(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_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;
|
||||
ip->ip_v = IPVERSION;
|
||||
ip->ip_tos = 0;
|
||||
ip->ip_off = 0;
|
||||
ip->ip_p = IPPROTO_IGMP;
|
||||
ip->ip_ttl = MAXTTL; /* applies to unicasts only */
|
||||
|
||||
allhosts_group = htonl(INADDR_ALLHOSTS_GROUP);
|
||||
dvmrp_group = htonl(INADDR_DVMRP_GROUP);
|
||||
allrtrs_group = htonl(INADDR_ALLRTRS_GROUP);
|
||||
}
|
||||
|
||||
#define PIM_QUERY 0
|
||||
#define PIM_REGISTER 1
|
||||
#define PIM_REGISTER_STOP 2
|
||||
#define PIM_JOIN_PRUNE 3
|
||||
#define PIM_RP_REACHABLE 4
|
||||
#define PIM_ASSERT 5
|
||||
#define PIM_GRAFT 6
|
||||
#define PIM_GRAFT_ACK 7
|
||||
|
||||
static char *
|
||||
packet_kind(u_int type, u_int code)
|
||||
{
|
||||
switch (type) {
|
||||
case IGMP_HOST_MEMBERSHIP_QUERY: return "membership query ";
|
||||
case IGMP_v1_HOST_MEMBERSHIP_REPORT: return "v1 member report ";
|
||||
case IGMP_v2_HOST_MEMBERSHIP_REPORT: return "v2 member report ";
|
||||
case IGMP_HOST_LEAVE_MESSAGE: 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_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 ";
|
||||
}
|
||||
case IGMP_PIM:
|
||||
switch (code) {
|
||||
case PIM_QUERY: return "PIM Router-Query ";
|
||||
case PIM_REGISTER: return "PIM Register ";
|
||||
case PIM_REGISTER_STOP: return "PIM Register-Stop ";
|
||||
case PIM_JOIN_PRUNE: return "PIM Join/Prune ";
|
||||
case PIM_RP_REACHABLE: return "PIM RP-Reachable ";
|
||||
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 ";
|
||||
}
|
||||
case IGMP_MTRACE_QUERY: return "IGMP trace query ";
|
||||
case IGMP_MTRACE_REPLY: return "IGMP trace reply ";
|
||||
default: return "unknown IGMP msg ";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a newly received IGMP packet that is sitting in the input
|
||||
* packet buffer.
|
||||
*/
|
||||
void
|
||||
accept_igmp(int recvlen)
|
||||
{
|
||||
u_int32_t src, dst, group;
|
||||
struct ip *ip;
|
||||
struct igmp *igmp;
|
||||
int ipdatalen, iphdrlen, igmpdatalen;
|
||||
|
||||
if (recvlen < sizeof(struct ip)) {
|
||||
logit(LOG_WARNING, 0,
|
||||
"received packet too short (%u bytes) for IP header", recvlen);
|
||||
return;
|
||||
}
|
||||
|
||||
ip = (struct ip *)recv_buf;
|
||||
src = ip->ip_src.s_addr;
|
||||
dst = ip->ip_dst.s_addr;
|
||||
|
||||
/*
|
||||
* this is most likely a message from the kernel indicating that
|
||||
* a new src grp pair message has arrived and so, it would be
|
||||
* necessary to install a route into the kernel for this.
|
||||
*/
|
||||
if (ip->ip_p == 0) {
|
||||
if (src == 0 || dst == 0)
|
||||
logit(LOG_WARNING, 0, "kernel request not accurate");
|
||||
else
|
||||
add_table_entry(src, dst);
|
||||
return;
|
||||
}
|
||||
|
||||
iphdrlen = ip->ip_hl << 2;
|
||||
ipdatalen = ip->ip_len;
|
||||
if (iphdrlen + ipdatalen != recvlen) {
|
||||
logit(LOG_WARNING, 0,
|
||||
"received packet from %s shorter (%u bytes) than hdr+data length (%u+%u)",
|
||||
inet_fmt(src, s1), recvlen, iphdrlen, ipdatalen);
|
||||
return;
|
||||
}
|
||||
|
||||
igmp = (struct igmp *)(recv_buf + iphdrlen);
|
||||
group = igmp->igmp_group.s_addr;
|
||||
igmpdatalen = ipdatalen - IGMP_MINLEN;
|
||||
if (igmpdatalen < 0) {
|
||||
logit(LOG_WARNING, 0,
|
||||
"received IP data field too short (%u bytes) for IGMP, from %s",
|
||||
ipdatalen, inet_fmt(src, s1));
|
||||
return;
|
||||
}
|
||||
|
||||
logit(LOG_DEBUG, 0, "RECV %s from %-15s to %s",
|
||||
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:
|
||||
accept_membership_query(src, dst, group, igmp->igmp_code);
|
||||
return;
|
||||
|
||||
case IGMP_v1_HOST_MEMBERSHIP_REPORT:
|
||||
case IGMP_v2_HOST_MEMBERSHIP_REPORT:
|
||||
accept_group_report(src, dst, group, igmp->igmp_type);
|
||||
return;
|
||||
|
||||
case IGMP_HOST_LEAVE_MESSAGE:
|
||||
accept_leave_message(src, dst, group);
|
||||
return;
|
||||
|
||||
case IGMP_DVMRP:
|
||||
group = ntohl(group);
|
||||
|
||||
switch (igmp->igmp_code) {
|
||||
case DVMRP_PROBE:
|
||||
accept_probe(src, dst,
|
||||
(char *)(igmp+1), igmpdatalen, group);
|
||||
return;
|
||||
|
||||
case DVMRP_REPORT:
|
||||
accept_report(src, dst,
|
||||
(char *)(igmp+1), igmpdatalen, group);
|
||||
return;
|
||||
|
||||
case DVMRP_ASK_NEIGHBORS:
|
||||
accept_neighbor_request(src, dst);
|
||||
return;
|
||||
|
||||
case DVMRP_ASK_NEIGHBORS2:
|
||||
accept_neighbor_request2(src, dst);
|
||||
return;
|
||||
|
||||
case DVMRP_NEIGHBORS:
|
||||
accept_neighbors(src, dst, (u_char *)(igmp+1), igmpdatalen,
|
||||
group);
|
||||
return;
|
||||
|
||||
case DVMRP_NEIGHBORS2:
|
||||
accept_neighbors2(src, dst, (u_char *)(igmp+1), igmpdatalen,
|
||||
group);
|
||||
return;
|
||||
|
||||
case DVMRP_PRUNE:
|
||||
accept_prune(src, dst, (char *)(igmp+1), igmpdatalen);
|
||||
return;
|
||||
|
||||
case DVMRP_GRAFT:
|
||||
accept_graft(src, dst, (char *)(igmp+1), igmpdatalen);
|
||||
return;
|
||||
|
||||
case DVMRP_GRAFT_ACK:
|
||||
accept_g_ack(src, dst, (char *)(igmp+1), igmpdatalen);
|
||||
return;
|
||||
|
||||
case DVMRP_INFO_REQUEST:
|
||||
accept_info_request(src, dst, (char *)(igmp+1),
|
||||
igmpdatalen);
|
||||
return;
|
||||
|
||||
case DVMRP_INFO_REPLY:
|
||||
accept_info_reply(src, dst, (char *)(igmp+1), igmpdatalen);
|
||||
return;
|
||||
|
||||
default:
|
||||
logit(LOG_INFO, 0,
|
||||
"ignoring unknown DVMRP message code %u from %s to %s",
|
||||
igmp->igmp_code, inet_fmt(src, s1),
|
||||
inet_fmt(dst, s2));
|
||||
return;
|
||||
}
|
||||
|
||||
case IGMP_PIM:
|
||||
return;
|
||||
|
||||
case IGMP_MTRACE_REPLY:
|
||||
return;
|
||||
|
||||
case IGMP_MTRACE_QUERY:
|
||||
accept_mtrace(src, dst, group, (char *)(igmp+1),
|
||||
igmp->igmp_code, igmpdatalen);
|
||||
return;
|
||||
|
||||
default:
|
||||
logit(LOG_INFO, 0,
|
||||
"ignoring unknown IGMP message type %x from %s to %s",
|
||||
igmp->igmp_type, inet_fmt(src, s1),
|
||||
inet_fmt(dst, s2));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Some IGMP messages are more important than others. This routine
|
||||
* determines the logging level at which to log a send error (often
|
||||
* "No route to host"). This is important when there is asymmetric
|
||||
* reachability and someone is trying to, i.e., mrinfo me periodically.
|
||||
*/
|
||||
static int
|
||||
igmp_log_level(u_int type, u_int code)
|
||||
{
|
||||
switch (type) {
|
||||
case IGMP_MTRACE_REPLY:
|
||||
return LOG_INFO;
|
||||
|
||||
case IGMP_DVMRP:
|
||||
switch (code) {
|
||||
case DVMRP_NEIGHBORS:
|
||||
case DVMRP_NEIGHBORS2:
|
||||
return LOG_INFO;
|
||||
}
|
||||
}
|
||||
return LOG_WARNING;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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'.
|
||||
*/
|
||||
void
|
||||
send_igmp(u_int32_t src, u_int32_t dst, int type, int code, u_int32_t group,
|
||||
int datalen)
|
||||
{
|
||||
struct sockaddr_in sdst;
|
||||
struct ip *ip;
|
||||
struct igmp *igmp;
|
||||
int setloop;
|
||||
|
||||
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_int16_t *)igmp,
|
||||
IGMP_MINLEN + datalen);
|
||||
|
||||
if (IN_MULTICAST(ntohl(dst))) {
|
||||
k_set_if(src);
|
||||
if (type != IGMP_DVMRP) {
|
||||
setloop = 1;
|
||||
k_set_loop(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
bzero(&sdst, sizeof(sdst));
|
||||
sdst.sin_family = AF_INET;
|
||||
#if (defined(BSD) && (BSD >= 199103))
|
||||
sdst.sin_len = sizeof(sdst);
|
||||
#endif
|
||||
sdst.sin_addr.s_addr = dst;
|
||||
if (sendto(igmp_socket, send_buf, ip->ip_len, 0,
|
||||
(struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
|
||||
if (errno == ENETDOWN)
|
||||
check_vif_state();
|
||||
else
|
||||
logit(igmp_log_level(type, code), errno,
|
||||
"sendto to %s on %s",
|
||||
inet_fmt(dst, s1), inet_fmt(src, s2));
|
||||
}
|
||||
|
||||
if (setloop)
|
||||
k_set_loop(FALSE);
|
||||
|
||||
logit(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
|
||||
packet_kind(type, code), inet_fmt(src, s1), inet_fmt(dst, s2));
|
||||
}
|
223
usr.sbin/mrouted/inet.c
Normal file
223
usr.sbin/mrouted/inet.c
Normal file
@ -0,0 +1,223 @@
|
||||
/* $NetBSD: inet.c,v 1.9 2003/03/05 21:05:39 wiz Exp $ */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
|
||||
/*
|
||||
* Exported variables.
|
||||
*/
|
||||
char s1[19]; /* buffers to hold the string representations */
|
||||
char s2[19]; /* of IP addresses, to be passed to inet_fmt() */
|
||||
char s3[19]; /* or inet_fmts(). */
|
||||
char s4[19];
|
||||
|
||||
|
||||
/*
|
||||
* Verify that a given IP address is credible as a host address.
|
||||
* (Without a mask, cannot detect addresses of the form {subnet,0} or
|
||||
* {subnet,-1}.)
|
||||
*/
|
||||
int
|
||||
inet_valid_host(u_int32_t naddr)
|
||||
{
|
||||
u_int32_t addr;
|
||||
|
||||
addr = ntohl(naddr);
|
||||
|
||||
return (!(IN_MULTICAST(addr) ||
|
||||
IN_BADCLASS (addr) ||
|
||||
(addr & 0xff000000) == 0));
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that a given netmask is plausible;
|
||||
* make sure that it is a series of 1's followed by
|
||||
* a series of 0's with no discontiguous 1's.
|
||||
*/
|
||||
int
|
||||
inet_valid_mask(u_int32_t mask)
|
||||
{
|
||||
if (~(((mask & -mask) - 1) | mask) != 0) {
|
||||
/* Mask is not contiguous */
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that a given subnet number and mask pair are credible.
|
||||
*
|
||||
* With CIDR, almost any subnet and mask are credible. mrouted still
|
||||
* can't handle aggregated class A's, so we still check that, but
|
||||
* otherwise the only requirements are that the subnet address is
|
||||
* within the [ABC] range and that the host bits of the subnet
|
||||
* are all 0.
|
||||
*/
|
||||
int
|
||||
inet_valid_subnet(u_int32_t nsubnet, u_int32_t nmask)
|
||||
{
|
||||
u_int32_t subnet, mask;
|
||||
|
||||
subnet = ntohl(nsubnet);
|
||||
mask = ntohl(nmask);
|
||||
|
||||
if ((subnet & mask) != subnet) return (FALSE);
|
||||
|
||||
if (subnet == 0)
|
||||
return (mask == 0);
|
||||
|
||||
if (IN_CLASSA(subnet)) {
|
||||
if (mask < 0xff000000 ||
|
||||
(subnet & 0xff000000) == 0x7f000000 ||
|
||||
(subnet & 0xff000000) == 0x00000000) return (FALSE);
|
||||
}
|
||||
else if (IN_CLASSD(subnet) || IN_BADCLASS(subnet)) {
|
||||
/* Above Class C address space */
|
||||
return (FALSE);
|
||||
}
|
||||
if (subnet & ~mask) {
|
||||
/* Host bits are set in the subnet */
|
||||
return (FALSE);
|
||||
}
|
||||
if (!inet_valid_mask(mask)) {
|
||||
/* Netmask is not contiguous */
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert an IP address in u_long (network) format into a printable string.
|
||||
*/
|
||||
char *
|
||||
inet_fmt(u_int32_t addr, char *s)
|
||||
{
|
||||
u_char *a;
|
||||
|
||||
a = (u_char *)&addr;
|
||||
sprintf(s, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]);
|
||||
return (s);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert an IP subnet number in u_long (network) format into a printable
|
||||
* string including the netmask as a number of bits.
|
||||
*/
|
||||
char *
|
||||
inet_fmts(u_int32_t addr, u_int32_t mask, char *s)
|
||||
{
|
||||
u_char *a, *m;
|
||||
int bits;
|
||||
|
||||
if ((addr == 0) && (mask == 0)) {
|
||||
sprintf(s, "default");
|
||||
return (s);
|
||||
}
|
||||
a = (u_char *)&addr;
|
||||
m = (u_char *)&mask;
|
||||
bits = 33 - ffs(ntohl(mask));
|
||||
|
||||
if (m[3] != 0) sprintf(s, "%u.%u.%u.%u/%d", a[0], a[1], a[2], a[3],
|
||||
bits);
|
||||
else if (m[2] != 0) sprintf(s, "%u.%u.%u/%d", a[0], a[1], a[2], bits);
|
||||
else if (m[1] != 0) sprintf(s, "%u.%u/%d", a[0], a[1], bits);
|
||||
else sprintf(s, "%u/%d", a[0], bits);
|
||||
|
||||
return (s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert the printable string representation of an IP address into the
|
||||
* u_long (network) format. Return 0xffffffff on error. (To detect the
|
||||
* legal address with that value, you must explicitly compare the string
|
||||
* with "255.255.255.255".)
|
||||
*/
|
||||
u_int32_t
|
||||
inet_parse(char *s)
|
||||
{
|
||||
u_int32_t a = 0;
|
||||
u_int a0, a1, a2, a3;
|
||||
char c;
|
||||
|
||||
if (sscanf(s, "%u.%u.%u.%u%c", &a0, &a1, &a2, &a3, &c) != 4 ||
|
||||
a0 > 255 || a1 > 255 || a2 > 255 || a3 > 255)
|
||||
return (0xffffffff);
|
||||
|
||||
((u_char *)&a)[0] = a0;
|
||||
((u_char *)&a)[1] = a1;
|
||||
((u_char *)&a)[2] = a2;
|
||||
((u_char *)&a)[3] = a3;
|
||||
|
||||
return (a);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* inet_cksum extracted from:
|
||||
* P I N G . C
|
||||
*
|
||||
* Author -
|
||||
* Mike Muuss
|
||||
* U. S. Army Ballistic Research Laboratory
|
||||
* December, 1983
|
||||
* Modified at Uc Berkeley
|
||||
*
|
||||
* (ping.c) Status -
|
||||
* Public Domain. Distribution Unlimited.
|
||||
*
|
||||
* I N _ C K S U M
|
||||
*
|
||||
* Checksum routine for Internet Protocol family headers (C Version)
|
||||
*
|
||||
*/
|
||||
int
|
||||
inet_cksum(u_int16_t *addr, u_int len)
|
||||
{
|
||||
int nleft = (int)len;
|
||||
u_int16_t *w = addr;
|
||||
int32_t sum = 0;
|
||||
union {
|
||||
u_int16_t w;
|
||||
u_int8_t b[2];
|
||||
} answer;
|
||||
|
||||
/*
|
||||
* Our algorithm is simple, using a 32 bit accumulator (sum),
|
||||
* we add sequential 16 bit words to it, and at the end, fold
|
||||
* back all the carry bits from the top 16 bits into the lower
|
||||
* 16 bits.
|
||||
*/
|
||||
while (nleft > 1) {
|
||||
sum += *w++;
|
||||
nleft -= 2;
|
||||
}
|
||||
|
||||
/* mop up an odd byte, if necessary */
|
||||
if (nleft == 1) {
|
||||
answer.w = 0;
|
||||
answer.b[0] = *(u_char *)w ;
|
||||
sum += answer.w;
|
||||
}
|
||||
|
||||
/*
|
||||
* add back carry outs from top 16 bits to low 16 bits
|
||||
*/
|
||||
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
|
||||
sum += (sum >> 16); /* add carry */
|
||||
answer.w = ~sum; /* truncate to 16 bits */
|
||||
return (answer.w);
|
||||
}
|
224
usr.sbin/mrouted/kern.c
Normal file
224
usr.sbin/mrouted/kern.c
Normal file
@ -0,0 +1,224 @@
|
||||
/* $NetBSD: kern.c,v 1.7 2003/03/05 21:05:39 wiz Exp $ */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
|
||||
void k_set_rcvbuf(int bufsize)
|
||||
{
|
||||
if (setsockopt(igmp_socket, SOL_SOCKET, SO_RCVBUF,
|
||||
(char *)&bufsize, sizeof(bufsize)) < 0)
|
||||
logit(LOG_ERR, errno, "setsockopt SO_RCVBUF %u", bufsize);
|
||||
}
|
||||
|
||||
|
||||
void k_hdr_include(int bool)
|
||||
{
|
||||
#ifdef IP_HDRINCL
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, IP_HDRINCL,
|
||||
(char *)&bool, sizeof(bool)) < 0)
|
||||
logit(LOG_ERR, errno, "setsockopt IP_HDRINCL %u", bool);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void k_set_ttl(int t)
|
||||
{
|
||||
u_char ttl;
|
||||
|
||||
ttl = t;
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_TTL,
|
||||
(char *)&ttl, sizeof(ttl)) < 0)
|
||||
logit(LOG_ERR, errno, "setsockopt IP_MULTICAST_TTL %u", ttl);
|
||||
}
|
||||
|
||||
|
||||
void k_set_loop(int l)
|
||||
{
|
||||
u_char loop;
|
||||
|
||||
loop = l;
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_LOOP,
|
||||
(char *)&loop, sizeof(loop)) < 0)
|
||||
logit(LOG_ERR, errno, "setsockopt IP_MULTICAST_LOOP %u", loop);
|
||||
}
|
||||
|
||||
|
||||
void k_set_if(u_int32_t ifa)
|
||||
{
|
||||
struct in_addr adr;
|
||||
|
||||
adr.s_addr = ifa;
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_IF,
|
||||
(char *)&adr, sizeof(adr)) < 0)
|
||||
logit(LOG_ERR, errno, "setsockopt IP_MULTICAST_IF %s",
|
||||
inet_fmt(ifa, s1));
|
||||
}
|
||||
|
||||
|
||||
void k_join(u_int32_t grp, u_int32_t ifa)
|
||||
{
|
||||
struct ip_mreq mreq;
|
||||
|
||||
mreq.imr_multiaddr.s_addr = grp;
|
||||
mreq.imr_interface.s_addr = ifa;
|
||||
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
||||
(char *)&mreq, sizeof(mreq)) < 0)
|
||||
logit(LOG_WARNING, errno, "can't join group %s on interface %s",
|
||||
inet_fmt(grp, s1), inet_fmt(ifa, s2));
|
||||
}
|
||||
|
||||
|
||||
void k_leave(u_int32_t grp, u_int32_t ifa)
|
||||
{
|
||||
struct ip_mreq mreq;
|
||||
|
||||
mreq.imr_multiaddr.s_addr = grp;
|
||||
mreq.imr_interface.s_addr = ifa;
|
||||
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, IP_DROP_MEMBERSHIP,
|
||||
(char *)&mreq, sizeof(mreq)) < 0)
|
||||
logit(LOG_WARNING, errno, "can't leave group %s on interface %s",
|
||||
inet_fmt(grp, s1), inet_fmt(ifa, s2));
|
||||
}
|
||||
|
||||
|
||||
void k_init_dvmrp(void)
|
||||
{
|
||||
#ifdef OLD_KERNEL
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, MRT_INIT,
|
||||
(char *)NULL, 0) < 0)
|
||||
#else
|
||||
int v=1;
|
||||
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, MRT_INIT,
|
||||
(char *)&v, sizeof(int)) < 0)
|
||||
#endif
|
||||
logit(LOG_ERR, errno, "can't enable Multicast routing in kernel");
|
||||
}
|
||||
|
||||
|
||||
void k_stop_dvmrp(void)
|
||||
{
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DONE,
|
||||
(char *)NULL, 0) < 0)
|
||||
logit(LOG_WARNING, errno, "can't disable Multicast routing in kernel");
|
||||
}
|
||||
|
||||
|
||||
void k_add_vif(vifi_t vifi, struct uvif *v)
|
||||
{
|
||||
struct vifctl vc;
|
||||
|
||||
vc.vifc_vifi = vifi;
|
||||
vc.vifc_flags = v->uv_flags & VIFF_KERNEL_FLAGS;
|
||||
vc.vifc_threshold = v->uv_threshold;
|
||||
vc.vifc_rate_limit = v->uv_rate_limit;
|
||||
vc.vifc_lcl_addr.s_addr = v->uv_lcl_addr;
|
||||
vc.vifc_rmt_addr.s_addr = v->uv_rmt_addr;
|
||||
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_VIF,
|
||||
(char *)&vc, sizeof(vc)) < 0)
|
||||
logit(LOG_ERR, errno, "setsockopt MRT_ADD_VIF");
|
||||
}
|
||||
|
||||
|
||||
void k_del_vif(vifi_t vifi)
|
||||
{
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_VIF,
|
||||
(char *)&vifi, sizeof(vifi)) < 0)
|
||||
logit(LOG_ERR, errno, "setsockopt MRT_DEL_VIF");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Adds a (source, mcastgrp) entry to the kernel
|
||||
*/
|
||||
void k_add_rg(u_int32_t origin, struct gtable *g)
|
||||
{
|
||||
struct mfcctl mc;
|
||||
vifi_t i;
|
||||
|
||||
#ifdef DEBUG_MFC
|
||||
md_log(MD_ADD, origin, g->gt_mcastgrp);
|
||||
#endif
|
||||
/* copy table values so that setsockopt can process it */
|
||||
mc.mfcc_origin.s_addr = origin;
|
||||
#ifdef OLD_KERNEL
|
||||
mc.mfcc_originmask.s_addr = 0xffffffff;
|
||||
#endif
|
||||
mc.mfcc_mcastgrp.s_addr = g->gt_mcastgrp;
|
||||
mc.mfcc_parent = g->gt_route ? g->gt_route->rt_parent : NO_VIF;
|
||||
for (i = 0; i < numvifs; i++)
|
||||
mc.mfcc_ttls[i] = g->gt_ttls[i];
|
||||
|
||||
/* write to kernel space */
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_MFC,
|
||||
(char *)&mc, sizeof(mc)) < 0) {
|
||||
#ifdef DEBUG_MFC
|
||||
md_log(MD_ADD_FAIL, origin, g->gt_mcastgrp);
|
||||
#endif
|
||||
logit(LOG_WARNING, errno, "setsockopt MRT_ADD_MFC");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Deletes a (source, mcastgrp) entry from the kernel
|
||||
*/
|
||||
int k_del_rg(u_int32_t origin, struct gtable *g)
|
||||
{
|
||||
struct mfcctl mc;
|
||||
int retval;
|
||||
|
||||
#ifdef DEBUG_MFC
|
||||
md_log(MD_DEL, origin, g->gt_mcastgrp);
|
||||
#endif
|
||||
/* copy table values so that setsockopt can process it */
|
||||
mc.mfcc_origin.s_addr = origin;
|
||||
#ifdef OLD_KERNEL
|
||||
mc.mfcc_originmask.s_addr = 0xffffffff;
|
||||
#endif
|
||||
mc.mfcc_mcastgrp.s_addr = g->gt_mcastgrp;
|
||||
|
||||
/* write to kernel space */
|
||||
if ((retval = setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_MFC,
|
||||
(char *)&mc, sizeof(mc))) < 0) {
|
||||
#ifdef DEBUG_MFC
|
||||
md_log(MD_DEL_FAIL, origin, g->gt_mcastgrp);
|
||||
#endif
|
||||
logit(LOG_WARNING, errno, "setsockopt MRT_DEL_MFC");
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the kernel's idea of what version of mrouted needs to run with it.
|
||||
*/
|
||||
int k_get_version(void)
|
||||
{
|
||||
#ifdef OLD_KERNEL
|
||||
return -1;
|
||||
#else
|
||||
int vers;
|
||||
int len = sizeof(vers);
|
||||
|
||||
if (getsockopt(igmp_socket, IPPROTO_IP, MRT_VERSION,
|
||||
(char *)&vers, &len) < 0)
|
||||
logit(LOG_ERR, errno,
|
||||
"getsockopt MRT_VERSION: perhaps your kernel is too old");
|
||||
|
||||
return vers;
|
||||
#endif
|
||||
}
|
701
usr.sbin/mrouted/main.c
Normal file
701
usr.sbin/mrouted/main.c
Normal file
@ -0,0 +1,701 @@
|
||||
/* $NetBSD: main.c,v 1.18 2003/03/05 21:05:39 wiz Exp $ */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Written by Steve Deering, Stanford University, February 1989.
|
||||
*
|
||||
* (An earlier version of DVMRP was implemented by David Waitzman of
|
||||
* BBN STC by extending Berkeley's routed program. Some of Waitzman's
|
||||
* extensions have been incorporated into mrouted, but none of the
|
||||
* original routed code has been adopted.)
|
||||
*/
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef SNMP
|
||||
#include "snmp.h"
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("@(#) $NetBSD: main.c,v 1.18 2003/03/05 21:05:39 wiz Exp $");
|
||||
#endif
|
||||
|
||||
#include <err.h>
|
||||
#include <util.h>
|
||||
|
||||
extern char *configfilename;
|
||||
char versionstring[100];
|
||||
|
||||
static char dumpfilename[] = _PATH_MROUTED_DUMP;
|
||||
static char cachefilename[] = _PATH_MROUTED_CACHE;
|
||||
static char genidfilename[] = _PATH_MROUTED_GENID;
|
||||
|
||||
int cache_lifetime = DEFAULT_CACHE_LIFETIME;
|
||||
int max_prune_lifetime = DEFAULT_CACHE_LIFETIME * 2;
|
||||
|
||||
int debug = 0;
|
||||
u_char pruning = 1; /* Enable pruning by default */
|
||||
|
||||
#ifdef SNMP
|
||||
#define NHANDLERS 34
|
||||
#else
|
||||
#define NHANDLERS 2
|
||||
#endif
|
||||
|
||||
static struct ihandler {
|
||||
int fd; /* File descriptor */
|
||||
ihfunc_t func; /* Function to call with &fd_set */
|
||||
} ihandlers[NHANDLERS];
|
||||
static int nhandlers = 0;
|
||||
|
||||
/*
|
||||
* Forward declarations.
|
||||
*/
|
||||
static void fasttimer(int);
|
||||
static void done(int);
|
||||
static void dump(int);
|
||||
static void fdump(int);
|
||||
static void cdump(int);
|
||||
static void restart(int);
|
||||
static void timer(void);
|
||||
static void cleanup(void);
|
||||
static void resetlogging(void *);
|
||||
|
||||
/* To shut up gcc -Wstrict-prototypes */
|
||||
int main(int argc, char *argv[]);
|
||||
void logit(int severity, int syserr, const char *format, ...)
|
||||
__attribute__((__format__(__printf__, 3, 4)));
|
||||
|
||||
int
|
||||
register_input_handler(int fd, ihfunc_t func)
|
||||
{
|
||||
if (nhandlers >= NHANDLERS)
|
||||
return -1;
|
||||
|
||||
ihandlers[nhandlers].fd = fd;
|
||||
ihandlers[nhandlers++].func = func;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int recvlen;
|
||||
int omask;
|
||||
int dummy;
|
||||
FILE *fp;
|
||||
struct timeval tv;
|
||||
u_int32_t prev_genid;
|
||||
int vers;
|
||||
fd_set rfds, readers;
|
||||
int nfds, n, i;
|
||||
#ifdef SNMP
|
||||
struct timeval timeout, *tvp = &timeout;
|
||||
struct timeval sched, *svp = &sched, now, *nvp = &now;
|
||||
int index, block;
|
||||
#endif
|
||||
|
||||
setlinebuf(stderr);
|
||||
|
||||
if (geteuid() != 0) {
|
||||
fprintf(stderr, "must be root\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
argv++, argc--;
|
||||
while (argc > 0 && *argv[0] == '-') {
|
||||
if (strcmp(*argv, "-d") == 0) {
|
||||
if (argc > 1 && isdigit(*(argv + 1)[0])) {
|
||||
argv++, argc--;
|
||||
debug = atoi(*argv);
|
||||
} else
|
||||
debug = DEFAULT_DEBUG;
|
||||
} else if (strcmp(*argv, "-c") == 0) {
|
||||
if (argc > 1) {
|
||||
argv++, argc--;
|
||||
configfilename = *argv;
|
||||
} else
|
||||
goto usage;
|
||||
} else if (strcmp(*argv, "-p") == 0) {
|
||||
pruning = 0;
|
||||
#ifdef SNMP
|
||||
} else if (strcmp(*argv, "-P") == 0) {
|
||||
if (argc > 1 && isdigit(*(argv + 1)[0])) {
|
||||
argv++, argc--;
|
||||
dest_port = atoi(*argv);
|
||||
} else
|
||||
dest_port = DEFAULT_PORT;
|
||||
#endif
|
||||
} else
|
||||
goto usage;
|
||||
argv++, argc--;
|
||||
}
|
||||
|
||||
if (argc > 0) {
|
||||
usage: fprintf(stderr,
|
||||
"usage: mrouted [-p] [-c configfile] [-d [debug_level]]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (debug == 0) {
|
||||
/*
|
||||
* Detach from the terminal
|
||||
*/
|
||||
if (daemon(0, 0))
|
||||
err(1, "can't fork");
|
||||
pidfile(NULL);
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "debug level %u\n", debug);
|
||||
|
||||
#ifdef LOG_DAEMON
|
||||
(void)openlog("mrouted", LOG_PID, LOG_DAEMON);
|
||||
(void)setlogmask(LOG_UPTO(LOG_NOTICE));
|
||||
#else
|
||||
(void)openlog("mrouted", LOG_PID);
|
||||
#endif
|
||||
sprintf(versionstring, "mrouted version %d.%d",
|
||||
PROTOCOL_VERSION, MROUTED_VERSION);
|
||||
|
||||
logit(LOG_NOTICE, 0, "%s", versionstring);
|
||||
|
||||
#ifdef SYSV
|
||||
srand48(time(NULL));
|
||||
#else
|
||||
srandom(gethostid());
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Get generation id
|
||||
*/
|
||||
gettimeofday(&tv, 0);
|
||||
dvmrp_genid = tv.tv_sec;
|
||||
|
||||
fp = fopen(genidfilename, "r");
|
||||
if (fp != NULL) {
|
||||
fscanf(fp, "%d", &prev_genid);
|
||||
if (prev_genid == dvmrp_genid)
|
||||
dvmrp_genid++;
|
||||
(void) fclose(fp);
|
||||
}
|
||||
|
||||
fp = fopen(genidfilename, "w");
|
||||
if (fp != NULL) {
|
||||
fprintf(fp, "%d", dvmrp_genid);
|
||||
(void) fclose(fp);
|
||||
}
|
||||
|
||||
callout_init();
|
||||
init_igmp();
|
||||
init_routes();
|
||||
init_ktable();
|
||||
k_init_dvmrp(); /* enable DVMRP routing in kernel */
|
||||
|
||||
#ifndef OLD_KERNEL
|
||||
vers = k_get_version();
|
||||
/*XXX
|
||||
* This function must change whenever the kernel version changes
|
||||
*/
|
||||
if ((((vers >> 8) & 0xff) != 3) ||
|
||||
((vers & 0xff) != 5))
|
||||
logit(LOG_ERR, 0, "kernel (v%d.%d)/mrouted (v%d.%d) version mismatch",
|
||||
(vers >> 8) & 0xff, vers & 0xff,
|
||||
PROTOCOL_VERSION, MROUTED_VERSION);
|
||||
#endif
|
||||
|
||||
#ifdef SNMP
|
||||
if (i = snmp_init())
|
||||
return i;
|
||||
|
||||
gettimeofday(nvp, 0);
|
||||
if (nvp->tv_usec < 500000L){
|
||||
svp->tv_usec = nvp->tv_usec + 500000L;
|
||||
svp->tv_sec = nvp->tv_sec;
|
||||
} else {
|
||||
svp->tv_usec = nvp->tv_usec - 500000L;
|
||||
svp->tv_sec = nvp->tv_sec + 1;
|
||||
}
|
||||
#endif /* SNMP */
|
||||
|
||||
init_vifs();
|
||||
|
||||
#ifdef RSRR
|
||||
rsrr_init();
|
||||
#endif /* RSRR */
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
if (debug)
|
||||
fprintf(stderr, "pruning %s\n", pruning ? "on" : "off");
|
||||
|
||||
(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);
|
||||
|
||||
FD_ZERO(&readers);
|
||||
if (igmp_socket >= FD_SETSIZE)
|
||||
logit(LOG_ERR, 0, "descriptor too big");
|
||||
FD_SET(igmp_socket, &readers);
|
||||
nfds = igmp_socket + 1;
|
||||
for (i = 0; i < nhandlers; i++) {
|
||||
if (ihandlers[i].fd >= FD_SETSIZE)
|
||||
logit(LOG_ERR, 0, "descriptor too big");
|
||||
FD_SET(ihandlers[i].fd, &readers);
|
||||
if (ihandlers[i].fd >= nfds)
|
||||
nfds = ihandlers[i].fd + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Install the vifs in the kernel as late as possible in the
|
||||
* initialization sequence.
|
||||
*/
|
||||
init_installvifs();
|
||||
|
||||
if (debug >= 2) dump(0);
|
||||
|
||||
/* Start up the log rate-limiter */
|
||||
resetlogging(NULL);
|
||||
|
||||
(void)alarm(1); /* schedule first timer interrupt */
|
||||
|
||||
/*
|
||||
* Main receive loop.
|
||||
*/
|
||||
dummy = 0;
|
||||
for(;;) {
|
||||
#ifdef SYSV
|
||||
sigset_t block, oblock;
|
||||
#endif
|
||||
bcopy((char *)&readers, (char *)&rfds, sizeof(rfds));
|
||||
#ifdef SNMP
|
||||
gettimeofday(nvp, 0);
|
||||
if (nvp->tv_sec > svp->tv_sec
|
||||
|| (nvp->tv_sec == svp->tv_sec && nvp->tv_usec > svp->tv_usec)){
|
||||
alarmTimer(nvp);
|
||||
eventTimer(nvp);
|
||||
if (nvp->tv_usec < 500000L){
|
||||
svp->tv_usec = nvp->tv_usec + 500000L;
|
||||
svp->tv_sec = nvp->tv_sec;
|
||||
} else {
|
||||
svp->tv_usec = nvp->tv_usec - 500000L;
|
||||
svp->tv_sec = nvp->tv_sec + 1;
|
||||
}
|
||||
}
|
||||
|
||||
tvp = &timeout;
|
||||
tvp->tv_sec = 0;
|
||||
tvp->tv_usec = 500000L;
|
||||
|
||||
block = 0;
|
||||
snmp_select_info(&nfds, &rfds, tvp, &block);
|
||||
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 */
|
||||
logit(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) logit(LOG_ERR, errno, "recvfrom");
|
||||
continue;
|
||||
}
|
||||
#ifdef SYSV
|
||||
(void)sigemptyset(&block);
|
||||
(void)sigaddset(&block, SIGALRM);
|
||||
if (sigprocmask(SIG_BLOCK, &block, &oblock) < 0)
|
||||
logit(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);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SNMP
|
||||
snmp_read(&rfds);
|
||||
snmp_timeout(); /* poll */
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* routine invoked every second. Its main goal is to cycle through
|
||||
* the routing table and send partial updates to all neighbors at a
|
||||
* rate that will cause the entire table to be sent in ROUTE_REPORT_INTERVAL
|
||||
* seconds. Also, every TIMER_INTERVAL seconds it calls timer() to
|
||||
* do all the other time-based processing.
|
||||
*/
|
||||
static void
|
||||
fasttimer(int i)
|
||||
{
|
||||
static unsigned int tlast;
|
||||
static unsigned int nsent;
|
||||
unsigned int t = tlast + 1;
|
||||
int n;
|
||||
|
||||
/*
|
||||
* if we're in the last second, send everything that's left.
|
||||
* otherwise send at least the fraction we should have sent by now.
|
||||
*/
|
||||
if (t >= ROUTE_REPORT_INTERVAL) {
|
||||
int nleft = nroutes - nsent;
|
||||
while (nleft > 0) {
|
||||
if ((n = report_next_chunk()) <= 0)
|
||||
break;
|
||||
nleft -= n;
|
||||
}
|
||||
tlast = 0;
|
||||
nsent = 0;
|
||||
} else {
|
||||
unsigned int ncum = nroutes * t / ROUTE_REPORT_INTERVAL;
|
||||
while (nsent < ncum) {
|
||||
if ((n = report_next_chunk()) <= 0)
|
||||
break;
|
||||
nsent += n;
|
||||
}
|
||||
tlast = t;
|
||||
}
|
||||
if ((t % TIMER_INTERVAL) == 0)
|
||||
timer();
|
||||
|
||||
age_callout_queue();/* Advance the timer for the callout queue
|
||||
for groups */
|
||||
alarm(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* The 'virtual_time' variable is initialized to a value that will cause the
|
||||
* first invocation of timer() to send a probe or route report to all vifs
|
||||
* and send group membership queries to all subnets for which this router is
|
||||
* querier. This first invocation occurs approximately TIMER_INTERVAL seconds
|
||||
* after the router starts up. Note that probes for neighbors and queries
|
||||
* for group memberships are also sent at start-up time, as part of initial-
|
||||
* ization. This repetition after a short interval is desirable for quickly
|
||||
* building up topology and membership information in the presence of possible
|
||||
* packet loss.
|
||||
*
|
||||
* 'virtual_time' advances at a rate that is only a crude approximation of
|
||||
* real time, because it does not take into account any time spent processing,
|
||||
* and because the timer intervals are sometimes shrunk by a random amount to
|
||||
* avoid unwanted synchronization with other routers.
|
||||
*/
|
||||
|
||||
static u_long virtual_time = 0;
|
||||
|
||||
|
||||
/*
|
||||
* Timer routine. Performs periodic neighbor probing, route reporting, and
|
||||
* group querying duties, and drives various timers in routing entries and
|
||||
* virtual interface data structures.
|
||||
*/
|
||||
static void
|
||||
timer(void)
|
||||
{
|
||||
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) {
|
||||
/*
|
||||
* Time to query the local group memberships on all subnets
|
||||
* for which this router is the elected querier.
|
||||
*/
|
||||
query_groups();
|
||||
}
|
||||
|
||||
if (virtual_time % NEIGHBOR_PROBE_INTERVAL == 0) {
|
||||
/*
|
||||
* Time to send a probe on all vifs from which no neighbors have
|
||||
* been heard. Also, check if any inoperative interfaces have now
|
||||
* come up. (If they have, they will also be probed as part of
|
||||
* their initialization.)
|
||||
*/
|
||||
probe_for_neighbors();
|
||||
|
||||
if (vifs_down)
|
||||
check_vif_state();
|
||||
}
|
||||
|
||||
delay_change_reports = FALSE;
|
||||
if (routes_changed) {
|
||||
/*
|
||||
* Some routes have changed since the last timer interrupt, but
|
||||
* have not been reported yet. Report the changed routes to all
|
||||
* neighbors.
|
||||
*/
|
||||
report_to_all_neighbors(CHANGED_ROUTES);
|
||||
}
|
||||
|
||||
#ifdef SNMP
|
||||
sync_timer();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Advance virtual time
|
||||
*/
|
||||
virtual_time += TIMER_INTERVAL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* On termination, let everyone know we're going away.
|
||||
*/
|
||||
static void
|
||||
done(int i)
|
||||
{
|
||||
logit(LOG_NOTICE, 0, "%s exiting", versionstring);
|
||||
cleanup();
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup(void)
|
||||
{
|
||||
static int in_cleanup = 0;
|
||||
|
||||
if (!in_cleanup) {
|
||||
in_cleanup++;
|
||||
#ifdef RSRR
|
||||
rsrr_clean();
|
||||
#endif /* RSRR */
|
||||
expire_all_routes();
|
||||
report_to_all_neighbors(ALL_ROUTES);
|
||||
k_stop_dvmrp();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Dump internal data structures to stderr.
|
||||
*/
|
||||
static void
|
||||
dump(int i)
|
||||
{
|
||||
dump_vifs(stderr);
|
||||
dump_routes(stderr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Dump internal data structures to a file.
|
||||
*/
|
||||
static void
|
||||
fdump(int i)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(dumpfilename, "w");
|
||||
if (fp != NULL) {
|
||||
dump_vifs(fp);
|
||||
dump_routes(fp);
|
||||
(void) fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Dump local cache contents to a file.
|
||||
*/
|
||||
static void
|
||||
cdump(int i)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(cachefilename, "w");
|
||||
if (fp != NULL) {
|
||||
dump_cache(fp);
|
||||
(void) fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Restart mrouted
|
||||
*/
|
||||
static void
|
||||
restart(int i)
|
||||
{
|
||||
int omask;
|
||||
#ifdef SYSV
|
||||
sigset_t block, oblock;
|
||||
#endif
|
||||
|
||||
logit(LOG_NOTICE, 0, "%s restart", versionstring);
|
||||
|
||||
/*
|
||||
* reset all the entries
|
||||
*/
|
||||
#ifdef SYSV
|
||||
(void)sigemptyset(&block);
|
||||
(void)sigaddset(&block, SIGALRM);
|
||||
if (sigprocmask(SIG_BLOCK, &block, &oblock) < 0)
|
||||
logit(LOG_ERR, errno, "sigprocmask");
|
||||
#else
|
||||
omask = sigblock(sigmask(SIGALRM));
|
||||
#endif
|
||||
free_all_prunes();
|
||||
free_all_routes();
|
||||
stop_all_vifs();
|
||||
k_stop_dvmrp();
|
||||
close(igmp_socket);
|
||||
close(udp_socket);
|
||||
|
||||
/*
|
||||
* 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();
|
||||
|
||||
#ifdef SYSV
|
||||
(void)sigprocmask(SIG_SETMASK, &oblock, (sigset_t *)NULL);
|
||||
#else
|
||||
(void)sigsetmask(omask);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define LOG_MAX_MSGS 20 /* if > 20/minute then shut up for a while */
|
||||
#define LOG_SHUT_UP 600 /* shut up for 10 minutes */
|
||||
static int log_nmsgs = 0;
|
||||
|
||||
static void
|
||||
resetlogging(void *arg)
|
||||
{
|
||||
int nxttime = 60;
|
||||
void *narg = NULL;
|
||||
|
||||
if (arg == NULL && log_nmsgs > LOG_MAX_MSGS) {
|
||||
nxttime = LOG_SHUT_UP;
|
||||
narg = (void *)&log_nmsgs; /* just need some valid void * */
|
||||
syslog(LOG_WARNING, "logging too fast, shutting up for %d minutes",
|
||||
LOG_SHUT_UP / 60);
|
||||
} else {
|
||||
log_nmsgs = 0;
|
||||
}
|
||||
|
||||
timer_setTimer(nxttime, resetlogging, narg);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* For errors of severity LOG_ERR or worse, terminate the program.
|
||||
*/
|
||||
void
|
||||
logit(int severity, int syserr, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
static char fmt[211] = "warning - ";
|
||||
char *msg;
|
||||
char tbuf[20];
|
||||
struct timeval now;
|
||||
struct tm *thyme;
|
||||
time_t t;
|
||||
|
||||
va_start(ap, format);
|
||||
vsprintf(&fmt[10], format, ap);
|
||||
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);
|
||||
t = now.tv_sec;
|
||||
thyme = localtime(&t);
|
||||
strftime(tbuf, sizeof(tbuf), "%X", thyme);
|
||||
fprintf(stderr, "%s.%03ld %s", tbuf, (long)now.tv_usec / 1000,
|
||||
msg);
|
||||
if (syserr == 0)
|
||||
fprintf(stderr, "\n");
|
||||
else
|
||||
fprintf(stderr, ": %s\n", strerror(syserr));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (severity <= LOG_ERR) exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MFC
|
||||
void
|
||||
md_log(int what, u_int32_t origin, u_int32_t mcastgrp)
|
||||
{
|
||||
static FILE *f = NULL;
|
||||
struct timeval tv;
|
||||
u_int32_t buf[4];
|
||||
|
||||
if (!f) {
|
||||
if ((f = fopen("/tmp/mrouted.clog", "w")) == NULL) {
|
||||
logit(LOG_ERR, errno, "open /tmp/mrouted.clog");
|
||||
}
|
||||
}
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
buf[0] = tv.tv_sec;
|
||||
buf[1] = what;
|
||||
buf[2] = origin;
|
||||
buf[3] = mcastgrp;
|
||||
|
||||
fwrite(buf, sizeof(u_int32_t), 4, f);
|
||||
}
|
||||
#endif
|
404
usr.sbin/mrouted/mrouted.8
Normal file
404
usr.sbin/mrouted/mrouted.8
Normal file
@ -0,0 +1,404 @@
|
||||
'\" $NetBSD: mrouted.8,v 1.13 2003/03/05 21:05:39 wiz Exp $
|
||||
'\"COPYRIGHT 1989 by The Board of Trustees of Leland Stanford Junior University.
|
||||
.TH MROUTED 8
|
||||
.UC 5
|
||||
.SH NAME
|
||||
mrouted \- IP multicast routing daemon
|
||||
.SH SYNOPSIS
|
||||
.B mrouted
|
||||
[
|
||||
.B \-p
|
||||
] [
|
||||
.B \-c
|
||||
.I config_file
|
||||
] [
|
||||
.B \-d
|
||||
[
|
||||
.I debug_level
|
||||
]]
|
||||
.SH DESCRIPTION
|
||||
.I Mrouted
|
||||
is an implementation of the Distance-Vector Multicast Routing
|
||||
Protocol (DVMRP), an earlier version of which is specified in RFC-1075.
|
||||
It maintains topological knowledge via a distance-vector routing protocol
|
||||
(like RIP, described in RFC-1058), upon which it implements a multicast
|
||||
datagram forwarding algorithm called Reverse Path Multicasting.
|
||||
.PP
|
||||
.I Mrouted
|
||||
forwards a multicast datagram along a shortest (reverse) path tree
|
||||
rooted at the subnet on which the datagram originates. The multicast
|
||||
delivery tree may be thought of as a broadcast delivery tree that has
|
||||
been pruned back so that it does not extend beyond those subnetworks
|
||||
that have members of the destination group. Hence, datagrams
|
||||
are not forwarded along those branches which have no listeners of the
|
||||
multicast group. The IP time-to-live of a multicast datagram can be
|
||||
used to limit the range of multicast datagrams.
|
||||
.PP
|
||||
In order to support multicasting among subnets that are separated by (unicast)
|
||||
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
|
||||
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
|
||||
(IP protocol number 4).
|
||||
Older versions of
|
||||
.I mrouted
|
||||
tunnel using IP source routing, which puts a heavy load on some
|
||||
types of routers.
|
||||
This version does not support IP source route tunnelling.
|
||||
.PP
|
||||
The tunnelling mechanism allows
|
||||
.I mrouted
|
||||
to establish a virtual internet, for
|
||||
the purpose of multicasting only, which is independent of the physical
|
||||
internet, and which may span multiple Autonomous Systems. This capability
|
||||
is intended for experimental support of internet multicasting only, pending
|
||||
widespread support for multicast routing by the regular (unicast) routers.
|
||||
.I Mrouted
|
||||
suffers from the well-known scaling problems of any distance-vector
|
||||
routing protocol, and does not (yet) support hierarchical multicast routing.
|
||||
.PP
|
||||
.I Mrouted
|
||||
handles multicast routing only; there may or may not be unicast routing
|
||||
software running on the same machine as
|
||||
.IR mrouted .
|
||||
With the use of tunnels, it
|
||||
is not necessary for
|
||||
.I mrouted
|
||||
to have access to more than one physical subnet
|
||||
in order to perform multicast forwarding.
|
||||
.br
|
||||
.ne 5
|
||||
.SH INVOCATION
|
||||
.PP
|
||||
If no "\-d" option is given, or if the debug level is specified as 0,
|
||||
.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,
|
||||
.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.
|
||||
.PP
|
||||
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
|
||||
via those interfaces. To override the default configuration, or to add
|
||||
tunnel links to other
|
||||
.IR mrouted s,
|
||||
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 \*[Lt]local-addr\*[Gt] [disable] [metric \*[Lt]m\*[Gt]]
|
||||
[threshold \*[Lt]t\*[Gt]] [rate_limit \*[Lt]b\*[Gt]]
|
||||
[boundary (\*[Lt]boundary-name\*[Gt]|\*[Lt]scoped-addr\*[Gt]/\*[Lt]mask-len\*[Gt])]
|
||||
[altnet \*[Lt]network\*[Gt]/\*[Lt]mask-len\*[Gt]]
|
||||
|
||||
tunnel \*[Lt]local-addr\*[Gt] \*[Lt]remote-addr\*[Gt] [metric \*[Lt]m\*[Gt]]
|
||||
[threshold \*[Lt]t\*[Gt]] [rate_limit \*[Lt]b\*[Gt]]
|
||||
[boundary (\*[Lt]boundary-name\*[Gt]|\*[Lt]scoped-addr\*[Gt]/\*[Lt]mask-len\*[Gt])]
|
||||
|
||||
cache_lifetime \*[Lt]ct\*[Gt]
|
||||
|
||||
pruning \*[Lt]off/on\*[Gt]
|
||||
|
||||
name \*[Lt]boundary-name\*[Gt] \*[Lt]scoped-addr\*[Gt]/\*[Lt]mask-len\*[Gt]
|
||||
|
||||
.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.
|
||||
.PP
|
||||
The phyint command can be used to disable multicast routing on the physical
|
||||
interface identified by local IP address \*[Lt]local-addr\*[Gt], or to associate a
|
||||
non-default metric or threshold with the specified physical interface.
|
||||
The local IP address \*[Lt]local-addr\*[Gt] may be replaced by the
|
||||
interface name (e.g le0).
|
||||
If a phyint is attached to multiple IP subnets, describe each additional subnet
|
||||
with the altnet keyword.
|
||||
Phyint commands must precede tunnel commands.
|
||||
.PP
|
||||
The tunnel command can be used to establish a tunnel link between local
|
||||
IP address \*[Lt]local-addr\*[Gt] and remote IP address \*[Lt]remote-addr\*[Gt], and to associate
|
||||
a non-default metric or threshold with that tunnel.
|
||||
The local IP address \*[Lt]local-addr\*[Gt] may be replaced by the
|
||||
interface name (e.g. le0). The remote IP address \*[Lt]remote-addr\*[Gt] 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.
|
||||
.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.
|
||||
.PP
|
||||
The pruning \*[Lt]off/on\*[Gt] 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
|
||||
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
|
||||
than 31.
|
||||
.LP
|
||||
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.
|
||||
.LP
|
||||
In general, all
|
||||
.IR mrouted s
|
||||
connected to a particular subnet or tunnel should
|
||||
use the same metric and threshold for that subnet or tunnel.
|
||||
.PP
|
||||
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
|
||||
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.
|
||||
.PP
|
||||
.I Mrouted
|
||||
will not initiate execution if it has fewer than two enabled vifs,
|
||||
where a vif (virtual interface) is either a physical multicast-capable
|
||||
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).
|
||||
.SH "EXAMPLE CONFIGURATION"
|
||||
.PP
|
||||
This is an example configuration for a mythical multicast router at a big
|
||||
school.
|
||||
.sp
|
||||
.nf
|
||||
#
|
||||
# mrouted.conf example
|
||||
#
|
||||
# Name our boundaries to make it easier
|
||||
name LOCAL 239.255.0.0/16
|
||||
name EE 239.254.0.0/16
|
||||
#
|
||||
# le1 is our gateway to compsci, don't forward our
|
||||
# local groups to them
|
||||
phyint le1 boundary EE
|
||||
#
|
||||
# le2 is our interface on the classroom net, it has four
|
||||
# different length subnets on it.
|
||||
# note that you can use either an ip address or an
|
||||
# interface name
|
||||
phyint 172.16.12.38 boundary EE altnet 172.16.15.0/26
|
||||
altnet 172.16.15.128/26 altnet 172.16.48.0/24
|
||||
#
|
||||
# atm0 is our ATM interface, which doesn't properly
|
||||
# support multicasting.
|
||||
phyint atm0 disable
|
||||
#
|
||||
# This is an internal tunnel to another EE subnet
|
||||
# Remove the default tunnel rate limit, since this
|
||||
# tunnel is over ethernets
|
||||
tunnel 192.168.5.4 192.168.55.101 metric 1 threshold 1
|
||||
rate_limit 0
|
||||
#
|
||||
# This is our tunnel to the outside world.
|
||||
# Careful with those boundaries, Eugene.
|
||||
tunnel 192.168.5.4 10.11.12.13 metric 1 threshold 32
|
||||
boundary LOCAL boundary EE
|
||||
.fi
|
||||
.SH SIGNALS
|
||||
.PP
|
||||
.I Mrouted
|
||||
responds to the following signals:
|
||||
.IP HUP
|
||||
restarts
|
||||
.I mrouted .
|
||||
The configuration file is reread every time this signal is evoked.
|
||||
.IP INT
|
||||
terminates execution gracefully (i.e., by sending
|
||||
good-bye messages to all neighboring routers).
|
||||
.IP TERM
|
||||
same as INT
|
||||
.IP USR1
|
||||
dumps the internal routing tables to /var/tmp/mrouted.dump.
|
||||
.IP USR2
|
||||
dumps the internal cache tables to /var/tmp/mrouted.cache.
|
||||
.IP QUIT
|
||||
dumps the internal routing tables to stderr (only if
|
||||
.I mrouted
|
||||
was invoked with a non-zero debug level).
|
||||
.PP
|
||||
For convenience in sending signals,
|
||||
.I mrouted
|
||||
writes its pid to /var/run/mrouted.pid upon startup.
|
||||
.bp
|
||||
.SH EXAMPLE
|
||||
.PP
|
||||
The routing tables look like this:
|
||||
.nf
|
||||
|
||||
Virtual Interface Table
|
||||
Vif Local-Address Metric Thresh Flags
|
||||
0 36.2.0.8 subnet: 36.2 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
|
||||
groups: 224.0.2.1
|
||||
224.0.1.0
|
||||
224.0.0.4
|
||||
pkts in: 345
|
||||
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
|
||||
pkts in: 34545433
|
||||
pkts out: 234342
|
||||
|
||||
3 36.2.0.8 tunnel: 36.6.8.23 3 16
|
||||
|
||||
Multicast Routing Table (1136 entries)
|
||||
Origin-Subnet From-Gateway Metric Tmr In-Vif Out-Vifs
|
||||
36.2 1 45 0 1* 2 3*
|
||||
36.8 36.8.0.77 4 15 2 0* 1* 3*
|
||||
36.11 1 20 1 0* 2 3*
|
||||
.
|
||||
.
|
||||
.
|
||||
|
||||
.fi
|
||||
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
|
||||
instance of
|
||||
.I mrouted
|
||||
is the one responsible for sending periodic group
|
||||
membership queries on the vif 0 and vif 1 subnets, as indicated by the
|
||||
"querier" flags. The list of boundaries indicate the scoped addresses on that
|
||||
interface. A count of the no. of incoming and outgoing packets is also
|
||||
shown at each interface.
|
||||
.PP
|
||||
Associated with each subnet from which a multicast datagram can originate
|
||||
is the address of the previous hop router (unless the subnet is directly-
|
||||
connected), the metric of the path back to the origin, the amount of time
|
||||
since we last received an update for this subnet, the incoming vif for
|
||||
multicasts from that origin, and a list of outgoing vifs. "*" means that
|
||||
the outgoing vif is connected to a leaf of the broadcast tree rooted at the
|
||||
origin, and a multicast datagram from that origin will be forwarded on that
|
||||
outgoing vif only if there are members of the destination group on that leaf.
|
||||
.bp
|
||||
.PP
|
||||
.I Mrouted
|
||||
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:
|
||||
.nf
|
||||
|
||||
Multicast Routing Cache Table (147 entries)
|
||||
Origin Mcast-group CTmr Age Ptmr IVif Forwvifs
|
||||
13.2.116/22 224.2.127.255 3m 2m - 0 1
|
||||
\*[Gt]13.2.116.19
|
||||
\*[Gt]13.2.116.196
|
||||
138.96.48/21 224.2.127.255 5m 2m - 0 1
|
||||
\*[Gt]138.96.48.108
|
||||
128.9.160/20 224.2.127.255 3m 2m - 0 1
|
||||
\*[Gt]128.9.160.45
|
||||
198.106.194/24 224.2.135.190 9m 28s 9m 0P
|
||||
\*[Gt]198.106.194.22
|
||||
|
||||
.fi
|
||||
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
|
||||
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.
|
||||
The 'Ptmr' field is simply a dash if no prune was sent upstream, or the
|
||||
amount of time until the upstream prune will time out.
|
||||
The 'Ivif' field indicates the
|
||||
incoming vif for multicast packets from that origin. Each router also
|
||||
maintains a record of the number of prunes received from neighboring
|
||||
routers for a particular source and group. If there are no members of
|
||||
a multicast group on any downward link of the multicast tree for a
|
||||
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
|
||||
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 "\*[Gt]" as the first character is printed for
|
||||
each source on the subnet. Note that there can be many sources in
|
||||
one subnet.
|
||||
.SH FILES
|
||||
/etc/mrouted.conf
|
||||
.br
|
||||
/var/run/mrouted.pid
|
||||
.br
|
||||
/var/tmp/mrouted.dump
|
||||
.br
|
||||
/var/tmp/mrouted.cache
|
||||
.SH SEE ALSO
|
||||
.BR mrinfo (8) ,
|
||||
.BR mtrace (8) ,
|
||||
.BR map-mbone (8)
|
||||
.sp
|
||||
DVMRP is described, along with other multicast routing algorithms, in the
|
||||
paper "Multicast Routing in Internetworks and Extended LANs" by S. Deering,
|
||||
in the Proceedings of the ACM SIGCOMM '88 Conference.
|
||||
.SH AUTHORS
|
||||
Steve Deering, Ajit Thyagarajan, Bill Fenner
|
22
usr.sbin/mrouted/pathnames.h
Normal file
22
usr.sbin/mrouted/pathnames.h
Normal file
@ -0,0 +1,22 @@
|
||||
/* $NetBSD: pathnames.h,v 1.7 2003/03/05 21:05:39 wiz Exp $ */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define _PATH_MROUTED_CONF "/etc/mrouted.conf"
|
||||
|
||||
#if (defined(BSD) && (BSD >= 199103))
|
||||
#define _PATH_MROUTED_GENID "/var/run/mrouted.genid"
|
||||
#define _PATH_MROUTED_DUMP "/var/tmp/mrouted.dump"
|
||||
#define _PATH_MROUTED_CACHE "/var/tmp/mrouted.cache"
|
||||
#else
|
||||
#define _PATH_MROUTED_GENID "/etc/mrouted.genid"
|
||||
#define _PATH_MROUTED_DUMP "/usr/tmp/mrouted.dump"
|
||||
#define _PATH_MROUTED_CACHE "/usr/tmp/mrouted.cache"
|
||||
#endif
|
2234
usr.sbin/mrouted/prune.c
Normal file
2234
usr.sbin/mrouted/prune.c
Normal file
File diff suppressed because it is too large
Load Diff
150
usr.sbin/mrouted/prune.h
Normal file
150
usr.sbin/mrouted/prune.h
Normal file
@ -0,0 +1,150 @@
|
||||
/* $NetBSD: prune.h,v 1.6 2003/03/05 21:05:40 wiz Exp $ */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Group table
|
||||
*
|
||||
* Each group entry is a member of two doubly-linked lists:
|
||||
*
|
||||
* a) A list hanging off of the routing table entry for this source (rt_groups)
|
||||
* sorted by group address under the routing entry (gt_next, gt_prev)
|
||||
* b) An independent list pointed to by kernel_table, which is a list of
|
||||
* active source,group's (gt_gnext, gt_gprev).
|
||||
*
|
||||
*/
|
||||
struct gtable {
|
||||
struct gtable *gt_next; /* pointer to the next entry */
|
||||
struct gtable *gt_prev; /* back pointer for linked list */
|
||||
struct gtable *gt_gnext; /* fwd pointer for group list */
|
||||
struct gtable *gt_gprev; /* rev pointer for group list */
|
||||
u_int32_t gt_mcastgrp; /* multicast group associated */
|
||||
vifbitmap_t gt_scope; /* scoped interfaces */
|
||||
u_char gt_ttls[MAXVIFS]; /* ttl vector for forwarding */
|
||||
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 */
|
||||
u_char gt_grftsnt; /* graft sent/retransmit timer */
|
||||
struct stable *gt_srctbl; /* source table */
|
||||
struct ptable *gt_pruntbl; /* prune table */
|
||||
struct rtentry *gt_route; /* parent route */
|
||||
#ifdef RSRR
|
||||
struct rsrr_cache *gt_rsrr_cache; /* RSRR cache */
|
||||
#endif /* RSRR */
|
||||
};
|
||||
|
||||
/*
|
||||
* Source table
|
||||
*
|
||||
* When source-based prunes exist, there will be a struct ptable here as well.
|
||||
*/
|
||||
struct stable
|
||||
{
|
||||
struct stable *st_next; /* pointer to the next entry */
|
||||
u_int32_t st_origin; /* host origin of multicasts */
|
||||
u_long st_pktcnt; /* packet count for src-grp entry */
|
||||
};
|
||||
|
||||
/*
|
||||
* structure to store incoming prunes. Can hang off of either group or source.
|
||||
*/
|
||||
struct ptable
|
||||
{
|
||||
struct ptable *pt_next; /* pointer to the next entry */
|
||||
u_int32_t pt_router; /* router that sent this prune */
|
||||
vifi_t pt_vifi; /* vif prune received on */
|
||||
int pt_timer; /* timer for prune */
|
||||
};
|
||||
|
||||
/*
|
||||
* The packet format for a traceroute request.
|
||||
*/
|
||||
struct tr_query {
|
||||
u_int32_t tr_src; /* traceroute source */
|
||||
u_int32_t tr_dst; /* traceroute destination */
|
||||
u_int32_t tr_raddr; /* traceroute response address */
|
||||
#if defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
struct {
|
||||
u_int qid : 24; /* traceroute query id */
|
||||
u_int ttl : 8; /* traceroute response ttl */
|
||||
} q;
|
||||
#else
|
||||
struct {
|
||||
u_int ttl : 8; /* traceroute response ttl */
|
||||
u_int qid : 24; /* traceroute query id */
|
||||
} q;
|
||||
#endif /* BYTE_ORDER */
|
||||
};
|
||||
|
||||
#define tr_rttl q.ttl
|
||||
#define tr_qid q.qid
|
||||
|
||||
/*
|
||||
* Traceroute response format. A traceroute response has a tr_query at the
|
||||
* beginning, followed by one tr_resp for each hop taken.
|
||||
*/
|
||||
struct tr_resp {
|
||||
u_int32_t tr_qarr; /* query arrival time */
|
||||
u_int32_t tr_inaddr; /* incoming interface address */
|
||||
u_int32_t tr_outaddr; /* outgoing interface address */
|
||||
u_int32_t tr_rmtaddr; /* parent address in source tree */
|
||||
u_int32_t tr_vifin; /* input packet count on interface */
|
||||
u_int32_t tr_vifout; /* output packet count on interface */
|
||||
u_int32_t tr_pktcnt; /* total incoming packets for src-grp */
|
||||
u_char tr_rproto; /* routing protocol deployed on router */
|
||||
u_char tr_fttl; /* ttl required to forward on outvif */
|
||||
u_char tr_smask; /* subnet mask for src addr */
|
||||
u_char tr_rflags; /* forwarding error codes */
|
||||
};
|
||||
|
||||
/* defs within mtrace */
|
||||
#define QUERY 1
|
||||
#define RESP 2
|
||||
#define QLEN sizeof(struct tr_query)
|
||||
#define RLEN sizeof(struct tr_resp)
|
||||
|
||||
/* fields for tr_rflags (forwarding error codes) */
|
||||
#define TR_NO_ERR 0
|
||||
#define TR_WRONG_IF 1
|
||||
#define TR_PRUNED 2
|
||||
#define TR_OPRUNED 3
|
||||
#define TR_SCOPED 4
|
||||
#define TR_NO_RTE 5
|
||||
#define TR_NO_FWD 7
|
||||
#define TR_RP_OR_CORE 8
|
||||
#define TR_RPF_INT 9
|
||||
#define TR_NO_MULTICAST 10
|
||||
#define TR_NO_SPACE 0x81
|
||||
#define TR_OLD_ROUTER 0x82
|
||||
#define TR_ADMIN_DENY 0x83
|
||||
|
||||
/* fields for tr_rproto (routing protocol) */
|
||||
#define PROTO_DVMRP 1
|
||||
#define PROTO_MOSPF 2
|
||||
#define PROTO_PIM 3
|
||||
#define PROTO_CBT 4
|
||||
#define PROTO_PIM_SPEC 5
|
||||
#define PROTO_PIM_STAT 6
|
||||
#define PROTO_DVMRP_STAT 7
|
||||
#define PROTO_PIM_MBGP 8
|
||||
|
||||
#define MASK_TO_VAL(x, i) { \
|
||||
u_int32_t _x = ntohl(x); \
|
||||
(i) = 1; \
|
||||
while ((_x) <<= 1) \
|
||||
(i)++; \
|
||||
};
|
||||
|
||||
#define VAL_TO_MASK(x, i) { \
|
||||
x = htonl(~((1 << (32 - (i))) - 1)); \
|
||||
};
|
||||
|
||||
#define NBR_VERS(n) (((n)->al_pv << 8) + (n)->al_mv)
|
1129
usr.sbin/mrouted/route.c
Normal file
1129
usr.sbin/mrouted/route.c
Normal file
File diff suppressed because it is too large
Load Diff
50
usr.sbin/mrouted/route.h
Normal file
50
usr.sbin/mrouted/route.h
Normal file
@ -0,0 +1,50 @@
|
||||
/* $NetBSD: route.h,v 1.6 2003/03/05 21:05:40 wiz Exp $ */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Routing Table Entry, one per subnet from which a multicast could originate.
|
||||
* (Note: all addresses, subnet numbers and masks are kept in NETWORK order.)
|
||||
*
|
||||
* The Routing Table is stored as a doubly-linked list of these structures,
|
||||
* ordered by decreasing value of rt_originmask and, secondarily, by
|
||||
* decreasing value of rt_origin within each rt_originmask value.
|
||||
* This data structure is efficient for generating route reports, whether
|
||||
* full or partial, for processing received full reports, for clearing the
|
||||
* CHANGED flags, and for periodically advancing the timers in all routes.
|
||||
* It is not so efficient for updating a small number of routes in response
|
||||
* to a partial report. In a stable topology, the latter are rare; if they
|
||||
* turn out to be costing a lot, we can add an auxiliary hash table for
|
||||
* faster access to arbitrary route entries.
|
||||
*/
|
||||
struct rtentry {
|
||||
struct rtentry *rt_next; /* link to next entry MUST BE FIRST */
|
||||
u_int32_t rt_origin; /* subnet origin of multicasts */
|
||||
u_int32_t rt_originmask; /* subnet mask for origin */
|
||||
short rt_originwidth; /* # bytes of origin subnet number */
|
||||
u_char rt_metric; /* cost of route back to origin */
|
||||
u_char rt_flags; /* RTF_ flags defined below */
|
||||
u_int32_t 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_t *rt_dominants; /* per vif dominant gateways */
|
||||
u_int32_t *rt_subordinates; /* per vif subordinate gateways */
|
||||
u_int *rt_leaf_timers; /* per vif leaf confirmation timers */
|
||||
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 ALL_ROUTES 0 /* possible arguments to report() */
|
||||
#define CHANGED_ROUTES 1 /* and report_to_all_neighbors() */
|
504
usr.sbin/mrouted/rsrr.c
Normal file
504
usr.sbin/mrouted/rsrr.c
Normal file
@ -0,0 +1,504 @@
|
||||
/* $NetBSD: rsrr.c,v 1.7 2003/03/05 21:05:40 wiz Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1993, 1998-2001.
|
||||
* The University of Southern California/Information Sciences Institute.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* RSRR code written by Daniel Zappala, USC Information Sciences Institute,
|
||||
* April 1995.
|
||||
*/
|
||||
|
||||
/* May 1995 -- Added support for Route Change Notification */
|
||||
|
||||
#ifdef RSRR
|
||||
|
||||
#include "defs.h"
|
||||
#include <sys/param.h>
|
||||
#if (defined(BSD) && (BSD >= 199103))
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
/* Taken from prune.c */
|
||||
/*
|
||||
* checks for scoped multicast addresses
|
||||
*/
|
||||
#define GET_SCOPE(gt) { \
|
||||
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); \
|
||||
}
|
||||
|
||||
/*
|
||||
* Exported variables.
|
||||
*/
|
||||
int rsrr_socket; /* interface to reservation protocol */
|
||||
|
||||
/*
|
||||
* Global RSRR variables.
|
||||
*/
|
||||
char rsrr_recv_buf[RSRR_MAX_LEN]; /* RSRR receive buffer */
|
||||
char rsrr_send_buf[RSRR_MAX_LEN]; /* RSRR send buffer */
|
||||
|
||||
struct sockaddr_un client_addr;
|
||||
int client_length = sizeof(client_addr);
|
||||
|
||||
|
||||
/*
|
||||
* Procedure definitions needed internally.
|
||||
*/
|
||||
static void rsrr_accept(int recvlen);
|
||||
static void rsrr_accept_iq(void);
|
||||
static int rsrr_accept_rq(struct rsrr_rq *route_query, int flags,
|
||||
struct gtable *gt_notify);
|
||||
static int rsrr_send(int sendlen);
|
||||
static void rsrr_cache(struct gtable *gt, struct rsrr_rq *route_query);
|
||||
|
||||
/* Initialize RSRR socket */
|
||||
void
|
||||
rsrr_init()
|
||||
{
|
||||
int servlen;
|
||||
struct sockaddr_un serv_addr;
|
||||
|
||||
if ((rsrr_socket = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0)
|
||||
logit(LOG_ERR, errno, "Can't create RSRR socket");
|
||||
|
||||
unlink(RSRR_SERV_PATH);
|
||||
bzero((char *) &serv_addr, sizeof(serv_addr));
|
||||
serv_addr.sun_family = AF_LOCAL;
|
||||
strcpy(serv_addr.sun_path, RSRR_SERV_PATH);
|
||||
#if (defined(BSD) && (BSD >= 199103))
|
||||
servlen = offsetof(struct sockaddr_un, sun_path) +
|
||||
strlen(serv_addr.sun_path);
|
||||
serv_addr.sun_len = servlen;
|
||||
#else
|
||||
servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
|
||||
#endif
|
||||
|
||||
if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0)
|
||||
logit(LOG_ERR, errno, "Can't bind RSRR socket");
|
||||
|
||||
if (register_input_handler(rsrr_socket,rsrr_read) < 0)
|
||||
logit(LOG_WARNING, 0, "Couldn't register RSRR as an input handler");
|
||||
}
|
||||
|
||||
/* Read a message from the RSRR socket */
|
||||
void
|
||||
rsrr_read(f, rfd)
|
||||
int f;
|
||||
fd_set *rfd;
|
||||
{
|
||||
int rsrr_recvlen;
|
||||
int omask;
|
||||
|
||||
bzero((char *) &client_addr, sizeof(client_addr));
|
||||
rsrr_recvlen = recvfrom(rsrr_socket, rsrr_recv_buf, sizeof(rsrr_recv_buf),
|
||||
0, (struct sockaddr *)&client_addr, &client_length);
|
||||
if (rsrr_recvlen < 0) {
|
||||
if (errno != EINTR)
|
||||
logit(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
|
||||
* appropriate action.
|
||||
*/
|
||||
static void
|
||||
rsrr_accept(recvlen)
|
||||
int recvlen;
|
||||
{
|
||||
struct rsrr_header *rsrr;
|
||||
struct rsrr_rq *route_query;
|
||||
|
||||
if (recvlen < RSRR_HEADER_LEN) {
|
||||
logit(LOG_WARNING, 0,
|
||||
"Received RSRR packet of %d bytes, which is less than min size",
|
||||
recvlen);
|
||||
return;
|
||||
}
|
||||
|
||||
rsrr = (struct rsrr_header *) rsrr_recv_buf;
|
||||
|
||||
if (rsrr->version > RSRR_MAX_VERSION) {
|
||||
logit(LOG_WARNING, 0,
|
||||
"Received RSRR packet version %d, which I don't understand",
|
||||
rsrr->version);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (rsrr->version) {
|
||||
case 1:
|
||||
switch (rsrr->type) {
|
||||
case RSRR_INITIAL_QUERY:
|
||||
/* Send Initial Reply to client */
|
||||
logit(LOG_INFO, 0, "Received Initial Query\n");
|
||||
rsrr_accept_iq();
|
||||
break;
|
||||
case RSRR_ROUTE_QUERY:
|
||||
/* Check size */
|
||||
if (recvlen < RSRR_RQ_LEN) {
|
||||
logit(LOG_WARNING, 0,
|
||||
"Received Route Query of %d bytes, which is too small",
|
||||
recvlen);
|
||||
break;
|
||||
}
|
||||
/* Get the query */
|
||||
route_query = (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN);
|
||||
logit(LOG_INFO, 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),
|
||||
BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT));
|
||||
/* Send Route Reply to client */
|
||||
rsrr_accept_rq(route_query,rsrr->flags,NULL);
|
||||
break;
|
||||
default:
|
||||
logit(LOG_WARNING, 0,
|
||||
"Received RSRR packet type %d, which I don't handle",
|
||||
rsrr->type);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
logit(LOG_WARNING, 0,
|
||||
"Received RSRR packet version %d, which I don't understand",
|
||||
rsrr->version);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Send an Initial Reply to the reservation protocol. */
|
||||
static void
|
||||
rsrr_accept_iq()
|
||||
{
|
||||
struct rsrr_header *rsrr;
|
||||
struct rsrr_vif *vif_list;
|
||||
struct uvif *v;
|
||||
int vifi, sendlen;
|
||||
|
||||
/* Check for space. There should be room for plenty of vifs,
|
||||
* but we should check anyway.
|
||||
*/
|
||||
if (numvifs > RSRR_MAX_VIFS) {
|
||||
logit(LOG_WARNING, 0,
|
||||
"Can't send RSRR Route Reply because %d is too many vifs %d",
|
||||
numvifs);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set up message */
|
||||
rsrr = (struct rsrr_header *) rsrr_send_buf;
|
||||
rsrr->version = 1;
|
||||
rsrr->type = RSRR_INITIAL_REPLY;
|
||||
rsrr->flags = 0;
|
||||
rsrr->num = numvifs;
|
||||
|
||||
vif_list = (struct rsrr_vif *) (rsrr_send_buf + RSRR_HEADER_LEN);
|
||||
|
||||
/* Include the vif list. */
|
||||
for (vifi=0, v = uvifs; vifi < numvifs; vifi++, v++) {
|
||||
vif_list[vifi].id = vifi;
|
||||
vif_list[vifi].status = 0;
|
||||
if (v->uv_flags & VIFF_DISABLED)
|
||||
BIT_SET(vif_list[vifi].status,RSRR_DISABLED_BIT);
|
||||
vif_list[vifi].threshold = v->uv_threshold;
|
||||
vif_list[vifi].local_addr.s_addr = v->uv_lcl_addr;
|
||||
}
|
||||
|
||||
/* Get the size. */
|
||||
sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN;
|
||||
|
||||
/* Send it. */
|
||||
logit(LOG_INFO, 0, "Send RSRR Initial Reply");
|
||||
rsrr_send(sendlen);
|
||||
}
|
||||
|
||||
/* Send a Route Reply to the reservation protocol. The Route Query
|
||||
* contains the query to which we are responding. The flags contain
|
||||
* the incoming flags from the query or, for route change
|
||||
* notification, the flags that should be set for the reply. The
|
||||
* kernel table entry contains the routing info to use for a route
|
||||
* change notification.
|
||||
*/
|
||||
static int
|
||||
rsrr_accept_rq(route_query,flags,gt_notify)
|
||||
struct rsrr_rq *route_query;
|
||||
int flags;
|
||||
struct gtable *gt_notify;
|
||||
{
|
||||
struct rsrr_header *rsrr;
|
||||
struct rsrr_rr *route_reply;
|
||||
struct gtable *gt,local_g;
|
||||
struct rtentry *r;
|
||||
int sendlen,i;
|
||||
u_long mcastgrp;
|
||||
|
||||
/* Set up message */
|
||||
rsrr = (struct rsrr_header *) rsrr_send_buf;
|
||||
rsrr->version = 1;
|
||||
rsrr->type = RSRR_ROUTE_REPLY;
|
||||
rsrr->flags = 0;
|
||||
rsrr->num = 0;
|
||||
|
||||
route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN);
|
||||
route_reply->dest_addr.s_addr = route_query->dest_addr.s_addr;
|
||||
route_reply->source_addr.s_addr = route_query->source_addr.s_addr;
|
||||
route_reply->query_id = route_query->query_id;
|
||||
|
||||
/* Blank routing entry for error. */
|
||||
route_reply->in_vif = 0;
|
||||
route_reply->reserved = 0;
|
||||
route_reply->out_vif_bm = 0;
|
||||
|
||||
/* Get the size. */
|
||||
sendlen = RSRR_RR_LEN;
|
||||
|
||||
/* If kernel table entry is defined, then we are sending a Route Reply
|
||||
* due to a Route Change Notification event. Use the kernel table entry
|
||||
* to supply the routing info.
|
||||
*/
|
||||
if (gt_notify) {
|
||||
/* Set flags */
|
||||
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;
|
||||
|
||||
} else if (find_src_grp(route_query->source_addr.s_addr, 0,
|
||||
route_query->dest_addr.s_addr)) {
|
||||
|
||||
/* Found kernel entry. Code taken from add_table_entry() */
|
||||
gt = gtp ? gtp->gt_gnext : kernel_table;
|
||||
|
||||
/* Include the routing entry. */
|
||||
route_reply->in_vif = gt->gt_route->rt_parent;
|
||||
route_reply->out_vif_bm = gt->gt_grpmems;
|
||||
|
||||
/* Cache reply if using route change notification. */
|
||||
if BIT_TST(flags,RSRR_NOTIFICATION_BIT) {
|
||||
rsrr_cache(gt,route_query);
|
||||
BIT_SET(rsrr->flags,RSRR_NOTIFICATION_BIT);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* No kernel entry; use routing table. */
|
||||
r = determine_route(route_query->source_addr.s_addr);
|
||||
|
||||
if (r != NULL) {
|
||||
/* We need to mimic what will happen if a data packet
|
||||
* is forwarded by multicast routing -- the kernel will
|
||||
* make an upcall and mrouted will install a route in the kernel.
|
||||
* Our outgoing vif bitmap should reflect what that table
|
||||
* will look like. Grab code from add_table_entry().
|
||||
* This is gross, but it's probably better to be accurate.
|
||||
*/
|
||||
|
||||
gt = &local_g;
|
||||
mcastgrp = route_query->dest_addr.s_addr;
|
||||
|
||||
gt->gt_mcastgrp = mcastgrp;
|
||||
gt->gt_grpmems = 0;
|
||||
gt->gt_scope = 0;
|
||||
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;
|
||||
|
||||
/* Include the routing entry. */
|
||||
route_reply->in_vif = gt->gt_route->rt_parent;
|
||||
route_reply->out_vif_bm = gt->gt_grpmems;
|
||||
|
||||
} else {
|
||||
/* Set error bit. */
|
||||
BIT_SET(rsrr->flags,RSRR_ERROR_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
if (gt_notify)
|
||||
logit(LOG_INFO, 0, "Route Change: Send RSRR Route Reply");
|
||||
|
||||
else
|
||||
logit(LOG_INFO, 0, "Send RSRR Route Reply");
|
||||
|
||||
logit(LOG_INFO, 0, "for src %s dst %s in vif %d out vif %d\n",
|
||||
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);
|
||||
|
||||
/* Send it. */
|
||||
return rsrr_send(sendlen);
|
||||
}
|
||||
|
||||
/* Send an RSRR message. */
|
||||
static int
|
||||
rsrr_send(sendlen)
|
||||
int sendlen;
|
||||
{
|
||||
int error;
|
||||
|
||||
/* Send it. */
|
||||
error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0,
|
||||
(struct sockaddr *)&client_addr, client_length);
|
||||
|
||||
/* Check for errors. */
|
||||
if (error < 0) {
|
||||
logit(LOG_WARNING, errno, "Failed send on RSRR socket");
|
||||
} else if (error != sendlen) {
|
||||
logit(LOG_WARNING, 0,
|
||||
"Sent only %d out of %d bytes on RSRR socket\n", error, sendlen);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Cache a message being sent to a client. Currently only used for
|
||||
* caching Route Reply messages for route change notification.
|
||||
*/
|
||||
static void
|
||||
rsrr_cache(gt,route_query)
|
||||
struct gtable *gt;
|
||||
struct rsrr_rq *route_query;
|
||||
{
|
||||
struct rsrr_cache *rc, **rcnp;
|
||||
struct rsrr_header *rsrr;
|
||||
|
||||
rsrr = (struct rsrr_header *) rsrr_send_buf;
|
||||
|
||||
rcnp = >->gt_rsrr_cache;
|
||||
while ((rc = *rcnp) != NULL) {
|
||||
if ((rc->route_query.source_addr.s_addr ==
|
||||
route_query->source_addr.s_addr) &&
|
||||
(rc->route_query.dest_addr.s_addr ==
|
||||
route_query->dest_addr.s_addr) &&
|
||||
(!strcmp(rc->client_addr.sun_path,client_addr.sun_path))) {
|
||||
/* Cache entry already exists.
|
||||
* Check if route notification bit has been cleared.
|
||||
*/
|
||||
if (!BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)) {
|
||||
/* Delete cache entry. */
|
||||
*rcnp = rc->next;
|
||||
free(rc);
|
||||
} else {
|
||||
/* Update */
|
||||
rc->route_query.query_id = route_query->query_id;
|
||||
logit(LOG_DEBUG, 0,
|
||||
"Update cached query id %ld from client %s\n",
|
||||
rc->route_query.query_id, rc->client_addr.sun_path);
|
||||
}
|
||||
return;
|
||||
}
|
||||
rcnp = &rc->next;
|
||||
}
|
||||
|
||||
/* Cache entry doesn't already exist. Create one and insert at
|
||||
* front of list.
|
||||
*/
|
||||
rc = (struct rsrr_cache *) malloc(sizeof(struct rsrr_cache));
|
||||
if (rc == NULL)
|
||||
logit(LOG_ERR, 0, "ran out of memory");
|
||||
rc->route_query.source_addr.s_addr = route_query->source_addr.s_addr;
|
||||
rc->route_query.dest_addr.s_addr = route_query->dest_addr.s_addr;
|
||||
rc->route_query.query_id = route_query->query_id;
|
||||
strcpy(rc->client_addr.sun_path, client_addr.sun_path);
|
||||
rc->client_length = client_length;
|
||||
rc->next = gt->gt_rsrr_cache;
|
||||
gt->gt_rsrr_cache = rc;
|
||||
logit(LOG_DEBUG, 0, "Cached query id %ld from client %s\n",
|
||||
rc->route_query.query_id,rc->client_addr.sun_path);
|
||||
}
|
||||
|
||||
/* Send all the messages in the cache. Currently this is used to send
|
||||
* all the cached Route Reply messages for route change notification.
|
||||
*/
|
||||
void
|
||||
rsrr_cache_send(gt,notify)
|
||||
struct gtable *gt;
|
||||
int notify;
|
||||
{
|
||||
struct rsrr_cache *rc, **rcnp;
|
||||
int flags = 0;
|
||||
|
||||
if (notify)
|
||||
BIT_SET(flags,RSRR_NOTIFICATION_BIT);
|
||||
|
||||
rcnp = >->gt_rsrr_cache;
|
||||
while ((rc = *rcnp) != NULL) {
|
||||
if (rsrr_accept_rq(&rc->route_query,flags,gt) < 0) {
|
||||
logit(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. */
|
||||
*rcnp = rc->next;
|
||||
free(rc);
|
||||
} else {
|
||||
rcnp = &rc->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Clean the cache by deleting all entries. */
|
||||
void
|
||||
rsrr_cache_clean(gt)
|
||||
struct gtable *gt;
|
||||
{
|
||||
struct rsrr_cache *rc,*rc_next;
|
||||
|
||||
printf("cleaning cache for group %s\n",inet_fmt(gt->gt_mcastgrp, s1));
|
||||
rc = gt->gt_rsrr_cache;
|
||||
while (rc) {
|
||||
rc_next = rc->next;
|
||||
free(rc);
|
||||
rc = rc_next;
|
||||
}
|
||||
gt->gt_rsrr_cache = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
rsrr_clean()
|
||||
{
|
||||
unlink(RSRR_SERV_PATH);
|
||||
}
|
||||
|
||||
#endif /* RSRR */
|
144
usr.sbin/mrouted/rsrr.h
Normal file
144
usr.sbin/mrouted/rsrr.h
Normal file
@ -0,0 +1,144 @@
|
||||
/* $NetBSD: rsrr.h,v 1.4 2003/03/05 21:05:40 wiz Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1993, 1998-2001.
|
||||
* The University of Southern California/Information Sciences Institute.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define RSRR_SERV_PATH "/tmp/.rsrr_svr"
|
||||
/* Note this needs to be 14 chars for 4.3 BSD compatibility */
|
||||
#define RSRR_CLI_PATH "/tmp/.rsrr_cli"
|
||||
|
||||
#define RSRR_MAX_LEN 2048
|
||||
#define RSRR_HEADER_LEN (sizeof(struct rsrr_header))
|
||||
#define RSRR_RQ_LEN (RSRR_HEADER_LEN + sizeof(struct rsrr_rq))
|
||||
#define RSRR_RR_LEN (RSRR_HEADER_LEN + sizeof(struct rsrr_rr))
|
||||
#define RSRR_VIF_LEN (sizeof(struct rsrr_vif))
|
||||
|
||||
/* Current maximum number of vifs. */
|
||||
#define RSRR_MAX_VIFS 32
|
||||
|
||||
/* Maximum acceptable version */
|
||||
#define RSRR_MAX_VERSION 1
|
||||
|
||||
/* RSRR message types */
|
||||
#define RSRR_ALL_TYPES 0
|
||||
#define RSRR_INITIAL_QUERY 1
|
||||
#define RSRR_INITIAL_REPLY 2
|
||||
#define RSRR_ROUTE_QUERY 3
|
||||
#define RSRR_ROUTE_REPLY 4
|
||||
|
||||
/* RSRR Initial Reply (Vif) Status bits
|
||||
* Each definition represents the position of the bit from right to left.
|
||||
*
|
||||
* Right-most bit is the disabled bit, set if the vif is administratively
|
||||
* disabled.
|
||||
*/
|
||||
#define RSRR_DISABLED_BIT 0
|
||||
/* All other bits are zeroes */
|
||||
|
||||
/* RSRR Route Query/Reply flag bits
|
||||
* Each definition represents the position of the bit from right to left.
|
||||
*
|
||||
* Right-most bit is the Route Change Notification bit, set if the
|
||||
* reservation protocol wishes to receive notification of
|
||||
* a route change for the source-destination pair listed in the query.
|
||||
* Notification is in the form of an unsolicitied Route Reply.
|
||||
*/
|
||||
#define RSRR_NOTIFICATION_BIT 0
|
||||
/* Next bit indicates an error returning the Route Reply. */
|
||||
#define RSRR_ERROR_BIT 1
|
||||
/* All other bits are zeroes */
|
||||
|
||||
/* Definition of an RSRR message header.
|
||||
* An Initial Query uses only the header, and an Initial Reply uses
|
||||
* the header and a list of vifs.
|
||||
*/
|
||||
struct rsrr_header {
|
||||
u_char version; /* RSRR Version, currently 1 */
|
||||
u_char type; /* type of message, as defined above */
|
||||
u_char flags; /* flags; defined by type */
|
||||
u_char num; /* number; defined by type */
|
||||
};
|
||||
|
||||
/* Definition of a vif as seen by the reservation protocol.
|
||||
*
|
||||
* Routing gives the reservation protocol a list of vifs in the
|
||||
* Initial Reply.
|
||||
*
|
||||
* We explicitly list the ID because we can't assume that all routing
|
||||
* protocols will use the same numbering scheme.
|
||||
*
|
||||
* The status is a bitmask of status flags, as defined above. It is the
|
||||
* responsibility of the reservation protocol to perform any status checks
|
||||
* if it uses the MULTICAST_VIF socket option.
|
||||
*
|
||||
* The threshold indicates the ttl an outgoing packet needs in order to
|
||||
* be forwarded. The reservation protocol must perform this check itself if
|
||||
* it uses the MULTICAST_VIF socket option.
|
||||
*
|
||||
* The local address is the address of the physical interface over which
|
||||
* packets are sent.
|
||||
*/
|
||||
struct rsrr_vif {
|
||||
u_char id; /* vif id */
|
||||
u_char threshold; /* vif threshold ttl */
|
||||
u_short status; /* vif status bitmask */
|
||||
struct in_addr local_addr; /* vif local address */
|
||||
};
|
||||
|
||||
/* Definition of an RSRR Route Query.
|
||||
*
|
||||
* The query asks routing for the forwarding entry for a particular
|
||||
* source and destination. The query ID uniquely identifies the query
|
||||
* for the reservation protocol. Thus, the combination of the client's
|
||||
* address and the query ID forms a unique identifier for routing.
|
||||
* Flags are defined above.
|
||||
*/
|
||||
struct rsrr_rq {
|
||||
struct in_addr dest_addr; /* destination */
|
||||
struct in_addr source_addr; /* source */
|
||||
u_long query_id; /* query ID */
|
||||
};
|
||||
|
||||
/* Definition of an RSRR Route Reply.
|
||||
*
|
||||
* Routing uses the reply to give the reservation protocol the
|
||||
* forwarding entry for a source-destination pair. Routing copies the
|
||||
* query ID from the query and fills in the incoming vif and a bitmask
|
||||
* of the outgoing vifs.
|
||||
* Flags are defined above.
|
||||
*/
|
||||
struct rsrr_rr {
|
||||
struct in_addr dest_addr; /* destination */
|
||||
struct in_addr source_addr; /* source */
|
||||
u_long query_id; /* query ID */
|
||||
u_short in_vif; /* incoming vif */
|
||||
u_short reserved; /* reserved */
|
||||
u_long out_vif_bm; /* outgoing vif bitmask */
|
||||
};
|
47
usr.sbin/mrouted/rsrr_var.h
Normal file
47
usr.sbin/mrouted/rsrr_var.h
Normal file
@ -0,0 +1,47 @@
|
||||
/* $NetBSD: rsrr_var.h,v 1.3 2003/03/05 21:05:40 wiz Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998-2001.
|
||||
* The University of Southern California/Information Sciences Institute.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* RSRR things that are only needed by mrouted. */
|
||||
|
||||
/* Cache of Route Query messages, distinguished by source,
|
||||
* destination, and client addresses. Cache is flushed by RSRR client
|
||||
* -- it sends notification when an unwanted Route Reply is received.
|
||||
* Since this only happens during route changes, it is more likely
|
||||
* that the cache will be flushed when the kernel table entry is
|
||||
* deleted. */
|
||||
struct rsrr_cache {
|
||||
struct rsrr_rq route_query; /* Cached Route Query */
|
||||
struct sockaddr_un client_addr; /* Client address */
|
||||
int client_length; /* Length of client */
|
||||
struct rsrr_cache *next; /* next cache item */
|
||||
};
|
||||
|
1288
usr.sbin/mrouted/snmp.c
Normal file
1288
usr.sbin/mrouted/snmp.c
Normal file
File diff suppressed because it is too large
Load Diff
9
usr.sbin/mrouted/snmp.h
Normal file
9
usr.sbin/mrouted/snmp.h
Normal file
@ -0,0 +1,9 @@
|
||||
/* $NetBSD: snmp.h,v 1.6 2003/03/05 21:05:40 wiz Exp $ */
|
||||
|
||||
extern int portlist[32], sdlen;
|
||||
extern in_port_t dest_port;
|
||||
extern int quantum;
|
||||
|
||||
extern int snmp_read_packet();
|
||||
|
||||
#define DEFAULT_PORT 161
|
1442
usr.sbin/mrouted/vif.c
Normal file
1442
usr.sbin/mrouted/vif.c
Normal file
File diff suppressed because it is too large
Load Diff
77
usr.sbin/mrouted/vif.h
Normal file
77
usr.sbin/mrouted/vif.h
Normal file
@ -0,0 +1,77 @@
|
||||
/* $NetBSD: vif.h,v 1.8 2003/03/05 21:05:41 wiz Exp $ */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* User level Virtual Interface structure
|
||||
*
|
||||
* A "virtual interface" is either a physical, multicast-capable interface
|
||||
* (called a "phyint") or a virtual point-to-point link (called a "tunnel").
|
||||
* (Note: all addresses, subnet numbers and masks are kept in NETWORK order.)
|
||||
*/
|
||||
struct uvif {
|
||||
u_short 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_threshold; /* min ttl required to forward on vif */
|
||||
u_int32_t uv_lcl_addr; /* local address of this vif */
|
||||
u_int32_t uv_rmt_addr; /* remote end-point addr (tunnels only) */
|
||||
u_int32_t uv_subnet; /* subnet number (phyints only) */
|
||||
u_int32_t uv_subnetmask; /* subnet mask (phyints only) */
|
||||
u_int32_t 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 */
|
||||
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 */
|
||||
};
|
||||
|
||||
#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 */
|
||||
|
||||
struct phaddr {
|
||||
struct phaddr *pa_next;
|
||||
u_int32_t pa_subnet; /* extra subnet */
|
||||
u_int32_t pa_subnetmask; /* netmask of extra subnet */
|
||||
u_int32_t pa_subnetbcast; /* broadcast of extra subnet */
|
||||
};
|
||||
|
||||
struct vif_acl {
|
||||
struct vif_acl *acl_next; /* next acl member */
|
||||
u_int32_t acl_addr; /* Group address */
|
||||
u_int32_t acl_mask; /* Group addr. mask */
|
||||
};
|
||||
|
||||
struct listaddr {
|
||||
struct listaddr *al_next; /* link to next addr, MUST BE FIRST */
|
||||
u_int32_t 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_t 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 */
|
||||
};
|
||||
|
||||
#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 NO_VIF ((vifi_t)MAXVIFS) /* An invalid vif index */
|
Loading…
Reference in New Issue
Block a user