Move back from gnu/dist/mrouted, now that it's available under a BSD

license.
This commit is contained in:
wiz 2003-03-05 21:05:38 +00:00
parent 925de95670
commit c60d41a9de
24 changed files with 10510 additions and 0 deletions

48
usr.sbin/mrouted/LICENSE Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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

File diff suppressed because it is too large Load Diff

150
usr.sbin/mrouted/prune.h Normal file
View 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

File diff suppressed because it is too large Load Diff

50
usr.sbin/mrouted/route.h Normal file
View 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
View 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->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->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
View 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 */
};

View 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

File diff suppressed because it is too large Load Diff

9
usr.sbin/mrouted/snmp.h Normal file
View 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

File diff suppressed because it is too large Load Diff

77
usr.sbin/mrouted/vif.h Normal file
View 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 */