mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-10 09:42:26 +00:00
mrouted from multicast 3.3 distribution
This commit is contained in:
commit
15fe6b8712
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/cvs2svn/branches/XEROX/; revision=2555 svn path=/cvs2svn/tags/MULTICAST_3_3/; revision=2557; tag=vendor/mrouted/3.3
48
usr.sbin/mrouted/LICENSE
Normal file
48
usr.sbin/mrouted/LICENSE
Normal file
@ -0,0 +1,48 @@
|
||||
|
||||
The mrouted program is covered by the following license. Use of the
|
||||
mrouted program represents acceptance of these terms and conditions.
|
||||
|
||||
1. STANFORD grants to LICENSEE a nonexclusive and nontransferable license
|
||||
to use, copy and modify the computer software ``mrouted'' (hereinafter
|
||||
called the ``Program''), upon the terms and conditions hereinafter set
|
||||
out and until Licensee discontinues use of the Licensed Program.
|
||||
|
||||
2. LICENSEE acknowledges that the Program is a research tool still in
|
||||
the development state, that it is being supplied ``as is,'' without any
|
||||
accompanying services from STANFORD, and that this license is entered
|
||||
into in order to encourage scientific collaboration aimed at further
|
||||
development and application of the Program.
|
||||
|
||||
3. LICENSEE may copy the Program and may sublicense others to use object
|
||||
code copies of the Program or any derivative version of the Program.
|
||||
All copies must contain all copyright and other proprietary notices found
|
||||
in the Program as provided by STANFORD. Title to copyright to the
|
||||
Program remains with STANFORD.
|
||||
|
||||
4. LICENSEE may create derivative versions of the Program. LICENSEE
|
||||
hereby grants STANFORD a royalty-free license to use, copy, modify,
|
||||
distribute and sublicense any such derivative works. At the time
|
||||
LICENSEE provides a copy of a derivative version of the Program to a
|
||||
third party, LICENSEE shall provide STANFORD with one copy of the source
|
||||
code of the derivative version at no charge to STANFORD.
|
||||
|
||||
5. STANFORD MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.
|
||||
By way of example, but not limitation, STANFORD MAKES NO REPRESENTATION
|
||||
OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
|
||||
THAT THE USE OF THE LICENSED PROGRAM WILL NOT INFRINGE ANY PATENTS,
|
||||
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. STANFORD shall not be held liable
|
||||
for any liability nor for any direct, indirect or consequential damages
|
||||
with respect to any claim by LICENSEE or any third party on account of or
|
||||
arising from this Agreement or use of the Program.
|
||||
|
||||
6. This agreement shall be construed, interpreted and applied in
|
||||
accordance with the State of California and any legal action arising
|
||||
out of this Agreement or use of the Program shall be filed in a court
|
||||
in the State of California.
|
||||
|
||||
7. Nothing in this Agreement shall be construed as conferring rights to
|
||||
use in advertising, publicity or otherwise any trademark or the name
|
||||
of ``Stanford''.
|
||||
|
||||
The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
|
||||
Leland Stanford Junior University.
|
201
usr.sbin/mrouted/callout.c
Normal file
201
usr.sbin/mrouted/callout.c
Normal file
@ -0,0 +1,201 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* $Id: callout.c,v 1.1 1994/08/24 23:52:49 thyagara Exp $
|
||||
*/
|
||||
|
||||
#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;
|
||||
|
||||
typedef void (* cfunc_t)();
|
||||
|
||||
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*/
|
||||
};
|
||||
|
||||
|
||||
callout_init()
|
||||
{
|
||||
Q = (struct timeout_q *) 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* signal handler for SIGALARM that is called once every second
|
||||
*/
|
||||
age_callout_queue()
|
||||
{
|
||||
struct timeout_q *ptr;
|
||||
|
||||
if (in_callout)
|
||||
return;
|
||||
|
||||
in_callout = 1;
|
||||
ptr = Q;
|
||||
|
||||
while (ptr){
|
||||
if (!ptr->time ) {
|
||||
/* timeout has happened */
|
||||
if(ptr->func)
|
||||
ptr->func(ptr->data);
|
||||
Q = Q->next;
|
||||
|
||||
free(ptr);
|
||||
ptr = Q;
|
||||
}
|
||||
else {
|
||||
ptr->time --;
|
||||
#ifdef IGMP_DEBUG
|
||||
log(LOG_DEBUG,0,"[callout, age_callout_queue] -- time (%d)", ptr->time);
|
||||
#endif IGMP_DEBUG
|
||||
in_callout = 0; return;
|
||||
}
|
||||
}
|
||||
in_callout = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* sets the timer
|
||||
*/
|
||||
int timer_setTimer(delay, action, data)
|
||||
int delay; /* number of units for timeout */
|
||||
cfunc_t action; /* function to be called on timeout */
|
||||
char *data; /* what to call the timeout function with */
|
||||
{
|
||||
struct timeout_q *ptr, *node, *prev;
|
||||
|
||||
if (in_callout)
|
||||
return;
|
||||
|
||||
in_callout = 1;
|
||||
|
||||
/* create a node */
|
||||
node = (struct timeout_q *)malloc(sizeof(struct timeout_q));
|
||||
if ((int) node <= 0) {
|
||||
log(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( id)
|
||||
int id;
|
||||
{
|
||||
struct timeout_q *ptr, *prev;
|
||||
|
||||
if (in_callout) return;
|
||||
in_callout = 1;
|
||||
|
||||
|
||||
if ( !id ) {in_callout = 0; return;}
|
||||
|
||||
prev = ptr = Q;
|
||||
|
||||
/*
|
||||
* find the right node, delete it. the subsequent node's time
|
||||
* gets bumped up
|
||||
*/
|
||||
|
||||
print_Q();
|
||||
while (ptr){
|
||||
if (ptr->id == 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* debugging utility
|
||||
*/
|
||||
print_Q()
|
||||
{
|
||||
struct timeout_q *ptr;
|
||||
|
||||
#ifdef IGMP_DEBUG
|
||||
for(ptr = Q; ptr; ptr = ptr->next)
|
||||
log(LOG_DEBUG,0,"(%d,%d) ", ptr->id, ptr->time);
|
||||
#endif IGMP_DEBUG
|
||||
}
|
||||
|
796
usr.sbin/mrouted/config.c
Normal file
796
usr.sbin/mrouted/config.c
Normal file
@ -0,0 +1,796 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* $Id: config.c,v 1.6 1994/08/24 23:52:54 thyagara Exp $
|
||||
*/
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
|
||||
char *configfilename = "/etc/mrouted.conf";
|
||||
|
||||
extern int cache_lifetime;
|
||||
extern int max_prune_lifetime;
|
||||
|
||||
/*
|
||||
* Forward declarations.
|
||||
*/
|
||||
static char *next_word();
|
||||
|
||||
|
||||
/*
|
||||
* Query the kernel to find network interfaces that are multicast-capable
|
||||
* and install them in the uvifs array.
|
||||
*/
|
||||
void config_vifs_from_kernel()
|
||||
{
|
||||
struct ifreq ifbuf[32];
|
||||
struct ifreq *ifrp, *ifend, *mp;
|
||||
struct ifconf ifc;
|
||||
register struct uvif *v;
|
||||
register vifi_t vifi;
|
||||
int i, n;
|
||||
u_long addr, mask, subnet;
|
||||
short flags;
|
||||
|
||||
ifc.ifc_buf = (char *)ifbuf;
|
||||
ifc.ifc_len = sizeof(ifbuf);
|
||||
if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
|
||||
log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
|
||||
|
||||
ifrp = (struct ifreq *)ifbuf;
|
||||
ifend = (struct ifreq *)((char *)ifbuf + ifc.ifc_len);
|
||||
/*
|
||||
* Loop through all of the interfaces.
|
||||
*/
|
||||
for (; ifrp < ifend; ifrp = (struct ifreq *)((char *)ifrp + n)) {
|
||||
struct ifreq ifr;
|
||||
#if BSD >= 199006
|
||||
n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
|
||||
if (n < sizeof(*ifrp))
|
||||
n = sizeof(*ifrp);
|
||||
#else
|
||||
n = sizeof(*ifrp);
|
||||
#endif
|
||||
/*
|
||||
* Ignore any interface for an address family other than IP.
|
||||
*/
|
||||
addr = ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr;
|
||||
if (ifrp->ifr_addr.sa_family != AF_INET)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Need a template to preserve address info that is
|
||||
* used below to locate the next entry. (Otherwise,
|
||||
* SIOCGIFFLAGS stomps over it because the requests
|
||||
* are returned in a union.)
|
||||
*/
|
||||
bcopy(ifrp->ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
|
||||
|
||||
/*
|
||||
* Ignore loopback interfaces and interfaces that do not support
|
||||
* multicast.
|
||||
*/
|
||||
if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
|
||||
log(LOG_ERR, errno, "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
|
||||
flags = ifr.ifr_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}.
|
||||
*/
|
||||
if (ioctl(udp_socket, SIOCGIFNETMASK, (char *)&ifr) < 0)
|
||||
log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s", ifr.ifr_name);
|
||||
mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
|
||||
subnet = addr & mask;
|
||||
if (!inet_valid_subnet(subnet, mask) ||
|
||||
addr == subnet ||
|
||||
addr == (subnet | ~mask)) {
|
||||
log(LOG_WARNING, 0,
|
||||
"ignoring %s, has invalid address (%s) and/or mask (%08x)",
|
||||
ifr.ifr_name, inet_fmt(addr, s1), ntohl(mask));
|
||||
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) {
|
||||
log(LOG_WARNING, 0, "ignoring %s, same subnet as %s",
|
||||
ifr.ifr_name, v->uv_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (vifi != numvifs) continue;
|
||||
|
||||
/*
|
||||
* If there is room in the uvifs array, install this interface.
|
||||
*/
|
||||
if (numvifs == MAXVIFS) {
|
||||
log(LOG_WARNING, 0, "too many vifs, ignoring %s", ifr.ifr_name);
|
||||
continue;
|
||||
}
|
||||
v = &uvifs[numvifs];
|
||||
v->uv_flags = 0;
|
||||
v->uv_metric = DEFAULT_METRIC;
|
||||
v->uv_rate_limit = DEFAULT_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;
|
||||
strncpy(v->uv_name, ifr.ifr_name, IFNAMSIZ);
|
||||
v->uv_groups = NULL;
|
||||
v->uv_neighbors = NULL;
|
||||
v->uv_acl = NULL;
|
||||
|
||||
log(LOG_INFO,0,"installing %s (%s on subnet %s) as vif #%u - rate=%d",
|
||||
v->uv_name, inet_fmt(addr, s1), inet_fmts(subnet, mask, s2),
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct ifreq *
|
||||
ifconfaddr(ifcp, a)
|
||||
struct ifconf *ifcp;
|
||||
u_long 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 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if the string constitutes a valid interface name
|
||||
*/
|
||||
static u_long valid_if(w)
|
||||
char *w;
|
||||
{
|
||||
register vifi_t vifi;
|
||||
register struct uvif *v;
|
||||
|
||||
for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++)
|
||||
if (EQUAL(v->uv_name, w))
|
||||
return v->uv_lcl_addr;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the config file to learn about tunnel vifs and
|
||||
* non-default phyint parameters.
|
||||
*/
|
||||
void config_vifs_from_file()
|
||||
{
|
||||
FILE *f;
|
||||
char linebuf[100];
|
||||
char *w, *s, c;
|
||||
u_long lcl_addr, rmt_addr;
|
||||
struct ifconf ifc;
|
||||
struct ifreq *ifr;
|
||||
struct ifreq ffr;
|
||||
int i;
|
||||
u_int n;
|
||||
struct ifreq ifbuf[32];
|
||||
vifi_t vifi;
|
||||
struct uvif *v;
|
||||
u_char order = 0;
|
||||
vifi_t prev_vif = NO_VIF;
|
||||
|
||||
f = fopen(configfilename, "r");
|
||||
if (f == NULL) {
|
||||
if (errno != ENOENT)
|
||||
log(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)
|
||||
log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
|
||||
|
||||
while (fgets(linebuf, sizeof(linebuf), f) != NULL) {
|
||||
|
||||
s = linebuf;
|
||||
if (EQUAL((w = next_word(&s)), "")) {
|
||||
/*
|
||||
* blank or comment line; ignore
|
||||
*/
|
||||
}
|
||||
|
||||
/* Set the cache_lifetime for kernel entries */
|
||||
else if (EQUAL(w, "cache_lifetime")) {
|
||||
if (EQUAL((w = next_word(&s)), "")) {
|
||||
log(LOG_ERR, 0,
|
||||
"missing cache_lifetime value in %s",
|
||||
configfilename);
|
||||
continue;
|
||||
}
|
||||
if(sscanf(w, "%u%c", &n, &c) != 1 ||
|
||||
n < 300 || n > 86400 ) {
|
||||
log(LOG_ERR, 0,
|
||||
"invalid cache_lifetime '%s' (300<n>86400) in %s",
|
||||
w, configfilename);
|
||||
break;
|
||||
}
|
||||
prev_vif = NO_VIF;
|
||||
cache_lifetime = n;
|
||||
max_prune_lifetime = cache_lifetime * 2;
|
||||
}
|
||||
|
||||
/* Check if pruning is to be turned off */
|
||||
else if (EQUAL(w, "pruning")) {
|
||||
if (!EQUAL((w = next_word(&s)), "off") &&
|
||||
!EQUAL(w, "on")) {
|
||||
log(LOG_ERR, 0,
|
||||
"invalid word '%s' in %s",
|
||||
w, configfilename);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(w, "off"))
|
||||
pruning = 0;
|
||||
|
||||
prev_vif = NO_VIF;
|
||||
}
|
||||
|
||||
/* Check for boundary statements (as continuation of a prev. line) */
|
||||
else if (EQUAL(w, "boundary") && prev_vif != NO_VIF) {
|
||||
register struct vif_acl *v_acl;
|
||||
register u_long baddr;
|
||||
|
||||
v = &uvifs[prev_vif];
|
||||
|
||||
if (EQUAL((w = next_word(&s)), "")) {
|
||||
log(LOG_ERR, 0,
|
||||
"missing group address for boundary %s in %s",
|
||||
inet_fmt(lcl_addr, s1), configfilename);
|
||||
w = "garbage";
|
||||
break;
|
||||
}
|
||||
|
||||
if ((sscanf(w, "%[0-9.]/%d", s1, &n) != 2) ||
|
||||
n < 0 || n> 32) {
|
||||
log(LOG_ERR, 0,
|
||||
"incorrect boundary format %s in %s",
|
||||
w, configfilename);
|
||||
w = "garbage";
|
||||
break;
|
||||
}
|
||||
|
||||
if ((baddr = inet_parse(s1)) == 0xffffffff ||
|
||||
(baddr & 0xff000000) != 0xef000000) {
|
||||
log(LOG_ERR, 0,
|
||||
"incorrect boundary address %s in %s",
|
||||
s1, configfilename);
|
||||
continue;
|
||||
}
|
||||
|
||||
v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
|
||||
if (v_acl == NULL)
|
||||
log(LOG_ERR, 0,
|
||||
"out of memory");
|
||||
VAL_TO_MASK(v_acl->acl_mask, n);
|
||||
v_acl->acl_addr = baddr & v_acl->acl_mask;
|
||||
|
||||
/*
|
||||
* link into data structure
|
||||
*/
|
||||
v_acl->acl_next = v->uv_acl;
|
||||
v->uv_acl = v_acl;
|
||||
}
|
||||
|
||||
else if (EQUAL(w, "phyint")) {
|
||||
/*
|
||||
* phyint <local-addr> [disable] [metric <m>] [threshold <t>]
|
||||
* [rate_limit <b>]
|
||||
*/
|
||||
|
||||
/*
|
||||
* Check if phyint was the first line - scream if not
|
||||
*/
|
||||
if (order) {
|
||||
log(LOG_ERR, 0,
|
||||
"phyint stmnts should occur before tunnel stmnts in %s",
|
||||
configfilename);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the local address.
|
||||
*/
|
||||
if (EQUAL((w = next_word(&s)), "")) {
|
||||
log(LOG_ERR, 0,
|
||||
"missing phyint address in %s",
|
||||
configfilename);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isalpha(*w) && !(lcl_addr = valid_if(w))) {
|
||||
log(LOG_ERR, 0,
|
||||
"invalid phyint name '%s' in %s",
|
||||
w, configfilename);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isdigit(*w)) {
|
||||
if ((lcl_addr = inet_parse(w)) == 0xffffffff ||
|
||||
!inet_valid_host(lcl_addr)) {
|
||||
log(LOG_ERR, 0,
|
||||
"invalid phyint address '%s' in %s",
|
||||
w, configfilename);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up the vif with the specified local address.
|
||||
*/
|
||||
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
|
||||
if (!(v->uv_flags & VIFF_TUNNEL) &&
|
||||
lcl_addr == v->uv_lcl_addr) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (vifi == numvifs) {
|
||||
log(LOG_ERR, 0,
|
||||
"phyint %s in %s is not a configured interface",
|
||||
inet_fmt(lcl_addr, s1), configfilename);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for "disable", "metric", "threshold", "rate_limit"
|
||||
* and "boundary" options.
|
||||
*/
|
||||
prev_vif = vifi;
|
||||
|
||||
while (!EQUAL((w = next_word(&s)), "")) {
|
||||
if (EQUAL(w, "disable")) {
|
||||
v->uv_flags |= VIFF_DISABLED;
|
||||
}
|
||||
else if (EQUAL(w, "metric")) {
|
||||
if(EQUAL((w = next_word(&s)), "")) {
|
||||
log(LOG_ERR, 0,
|
||||
"missing metric for phyint %s in %s",
|
||||
inet_fmt(lcl_addr, s1), configfilename);
|
||||
w = "garbage";
|
||||
break;
|
||||
}
|
||||
if(sscanf(w, "%u%c", &n, &c) != 1 ||
|
||||
n < 1 || n >= UNREACHABLE ) {
|
||||
log(LOG_ERR, 0,
|
||||
"invalid metric '%s' for phyint %s in %s",
|
||||
w, inet_fmt(lcl_addr, s1), configfilename);
|
||||
break;
|
||||
}
|
||||
v->uv_metric = n;
|
||||
}
|
||||
else if (EQUAL(w, "threshold")) {
|
||||
if(EQUAL((w = next_word(&s)), "")) {
|
||||
log(LOG_ERR, 0,
|
||||
"missing threshold for phyint %s in %s",
|
||||
inet_fmt(lcl_addr, s1), configfilename);
|
||||
w = "garbage";
|
||||
break;
|
||||
}
|
||||
if(sscanf(w, "%u%c", &n, &c) != 1 ||
|
||||
n < 1 || n > 255 ) {
|
||||
log(LOG_ERR, 0,
|
||||
"invalid threshold '%s' for phyint %s in %s",
|
||||
w, inet_fmt(lcl_addr, s1), configfilename);
|
||||
break;
|
||||
}
|
||||
v->uv_threshold = n;
|
||||
}
|
||||
else if (EQUAL(w, "rate_limit")) {
|
||||
if (EQUAL((w = next_word(&s)), "")) {
|
||||
log(LOG_ERR, 0,
|
||||
"missing rate_limit for phyint %s in %s",
|
||||
inet_fmt(rmt_addr, s1), configfilename);
|
||||
w = "garbage";
|
||||
break;
|
||||
}
|
||||
if(sscanf(w, "%u%c", &n, &c) != 1 ||
|
||||
n < 0 || n > MAX_RATE_LIMIT ) {
|
||||
log(LOG_ERR, 0,
|
||||
"invalid rate limit '%s' for phyint %s in %s",
|
||||
w, inet_fmt(lcl_addr, s1), configfilename);
|
||||
break;
|
||||
}
|
||||
v->uv_rate_limit = n;
|
||||
}
|
||||
else if (EQUAL(w, "boundary")) {
|
||||
register struct vif_acl *v_acl;
|
||||
register u_long baddr;
|
||||
|
||||
if (EQUAL((w = next_word(&s)), "")) {
|
||||
log(LOG_ERR, 0,
|
||||
"missing group address for boundary %s in %s",
|
||||
inet_fmt(lcl_addr, s1), configfilename);
|
||||
w = "garbage";
|
||||
break;
|
||||
}
|
||||
|
||||
if ((sscanf(w, "%[0-9.]/%d", s1, &n) != 2) ||
|
||||
n < 0 || n> 32) {
|
||||
log(LOG_ERR, 0,
|
||||
"incorrect boundary format %s in %s",
|
||||
w, configfilename);
|
||||
w = "garbage";
|
||||
break;
|
||||
}
|
||||
|
||||
if ((baddr = inet_parse(s1)) == 0xffffffff ||
|
||||
(baddr & 0xef000000) != 0xef000000) {
|
||||
log(LOG_ERR, 0,
|
||||
"incorrect boundary address %s in %s",
|
||||
s1, configfilename);
|
||||
continue;
|
||||
}
|
||||
|
||||
v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
|
||||
if (v_acl == NULL)
|
||||
log(LOG_ERR, 0,
|
||||
"out of memory");
|
||||
VAL_TO_MASK(v_acl->acl_mask, n);
|
||||
v_acl->acl_addr = baddr & v_acl->acl_mask;
|
||||
|
||||
/*
|
||||
* link into data structure
|
||||
*/
|
||||
v_acl->acl_next = v->uv_acl;
|
||||
v->uv_acl = v_acl;
|
||||
}
|
||||
else {
|
||||
log(LOG_ERR, 0,
|
||||
"invalid keyword (%s) in %s",
|
||||
w, configfilename);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!EQUAL(w, "")) continue;
|
||||
}
|
||||
|
||||
else if (EQUAL(w, "tunnel")) {
|
||||
/*
|
||||
* tunnel <local-addr> <remote-addr> [srcrt] [metric <m>]
|
||||
* [threshold <t>] [rate_limit <b>]
|
||||
*/
|
||||
|
||||
order++;
|
||||
|
||||
/*
|
||||
* Parse the local address.
|
||||
*/
|
||||
if (EQUAL((w = next_word(&s)), "")) {
|
||||
log(LOG_ERR, 0,
|
||||
"missing tunnel local address in %s",
|
||||
configfilename);
|
||||
continue;
|
||||
}
|
||||
if ((lcl_addr = inet_parse(w)) == 0xffffffff ||
|
||||
!inet_valid_host(lcl_addr)) {
|
||||
log(LOG_ERR, 0,
|
||||
"invalid tunnel local address '%s' in %s",
|
||||
w, configfilename);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure the local address is one of ours.
|
||||
*/
|
||||
ifr = ifconfaddr(&ifc, lcl_addr);
|
||||
if (ifr == 0) {
|
||||
log(LOG_ERR, 0,
|
||||
"tunnel local address %s in %s is not one of ours",
|
||||
inet_fmt(lcl_addr, s1), configfilename);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure the local address doesn't name a loopback interface..
|
||||
*/
|
||||
strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ);
|
||||
if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr) < 0) {
|
||||
log(LOG_ERR, errno,
|
||||
"ioctl SIOCGIFFLAGS for %s", ffr.ifr_name);
|
||||
}
|
||||
if (ffr.ifr_flags & IFF_LOOPBACK) {
|
||||
log(LOG_ERR, 0,
|
||||
"tunnel local address %s in %s is a loopback interface",
|
||||
inet_fmt(lcl_addr, s1), configfilename);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the remote address.
|
||||
*/
|
||||
if (EQUAL((w = next_word(&s)), "")) {
|
||||
log(LOG_ERR, 0,
|
||||
"missing tunnel remote address in %s",
|
||||
configfilename);
|
||||
continue;
|
||||
}
|
||||
if ((rmt_addr = inet_parse(w)) == 0xffffffff ||
|
||||
!inet_valid_host(rmt_addr)) {
|
||||
log(LOG_ERR, 0,
|
||||
"invalid tunnel remote address %s in %s",
|
||||
w, configfilename);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure the remote address is not one of ours.
|
||||
*/
|
||||
if (ifconfaddr(&ifc, rmt_addr) != 0) {
|
||||
log(LOG_ERR, 0,
|
||||
"tunnel remote address %s in %s is one of ours",
|
||||
inet_fmt(rmt_addr, s1), configfilename);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure the remote address has not been used for another
|
||||
* tunnel and does not belong to a subnet to which we have direct
|
||||
* access on an enabled phyint.
|
||||
*/
|
||||
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
|
||||
if (v->uv_flags & VIFF_TUNNEL) {
|
||||
if (rmt_addr == v->uv_rmt_addr) {
|
||||
log(LOG_ERR, 0,
|
||||
"duplicate tunnel remote address %s in %s",
|
||||
inet_fmt(rmt_addr, s1), configfilename);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!(v->uv_flags & VIFF_DISABLED)) {
|
||||
if ((rmt_addr & v->uv_subnetmask) == v->uv_subnet) {
|
||||
log(LOG_ERR, 0,
|
||||
"unnecessary tunnel remote address %s in %s",
|
||||
inet_fmt(rmt_addr, s1), configfilename);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (vifi != numvifs) continue;
|
||||
|
||||
/*
|
||||
* OK, let's initialize a uvif structure for the tunnel.
|
||||
*/
|
||||
if (numvifs == MAXVIFS) {
|
||||
log(LOG_ERR, 0, "too many vifs, ignoring tunnel to %s",
|
||||
inet_fmt(rmt_addr, s1));
|
||||
continue;
|
||||
}
|
||||
v = &uvifs[numvifs];
|
||||
v->uv_flags = VIFF_TUNNEL;
|
||||
v->uv_metric = DEFAULT_METRIC;
|
||||
v->uv_rate_limit = DEFAULT_RATE_LIMIT;
|
||||
v->uv_threshold = DEFAULT_THRESHOLD;
|
||||
v->uv_lcl_addr = lcl_addr;
|
||||
v->uv_rmt_addr = rmt_addr;
|
||||
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;
|
||||
|
||||
/*
|
||||
* set variable to define which interface
|
||||
*/
|
||||
prev_vif = numvifs;
|
||||
|
||||
/*
|
||||
* Look for "metric", "threshold", "srcrt", "rate_limit"
|
||||
* and "boundary" options.
|
||||
*/
|
||||
while (!EQUAL((w = next_word(&s)), "")) {
|
||||
if (EQUAL(w, "metric")) {
|
||||
if(EQUAL((w = next_word(&s)), "")) {
|
||||
log(LOG_ERR, 0,
|
||||
"missing metric for tunnel to %s in %s",
|
||||
inet_fmt(rmt_addr, s1), configfilename);
|
||||
w = "garbage";
|
||||
break;
|
||||
}
|
||||
if(sscanf(w, "%u%c", &n, &c) != 1 ||
|
||||
n < 1 || n >= UNREACHABLE ) {
|
||||
log(LOG_ERR, 0,
|
||||
"invalid metric '%s' for tunnel to %s in %s",
|
||||
w, inet_fmt(rmt_addr, s1), configfilename);
|
||||
break;
|
||||
}
|
||||
v->uv_metric = n;
|
||||
}
|
||||
else if (EQUAL(w, "threshold")) {
|
||||
if(EQUAL((w = next_word(&s)), "")) {
|
||||
log(LOG_ERR, 0,
|
||||
"missing threshold for tunnel to %s in %s",
|
||||
inet_fmt(rmt_addr, s1), configfilename);
|
||||
w = "garbage";
|
||||
break;
|
||||
}
|
||||
if(sscanf(w, "%u%c", &n, &c) != 1 ||
|
||||
n < 1 || n > 255 ) {
|
||||
log(LOG_ERR, 0,
|
||||
"invalid threshold '%s' for tunnel to %s in %s",
|
||||
w, inet_fmt(rmt_addr, s1), configfilename);
|
||||
break;
|
||||
}
|
||||
v->uv_threshold = n;
|
||||
}
|
||||
else if (EQUAL(w, "srcrt") || EQUAL(w, "sourceroute")) {
|
||||
v->uv_flags |= VIFF_SRCRT;
|
||||
}
|
||||
else if (EQUAL(w, "rate_limit")) {
|
||||
if (EQUAL((w = next_word(&s)), "")) {
|
||||
log(LOG_ERR, 0,
|
||||
"missing rate_limit for tunnel to %s in %s",
|
||||
inet_fmt(rmt_addr, s1), configfilename);
|
||||
w = "garbage";
|
||||
break;
|
||||
}
|
||||
if(sscanf(w, "%u%c", &n, &c) != 1 ||
|
||||
n < 0 || n > MAX_RATE_LIMIT ) {
|
||||
log(LOG_ERR, 0,
|
||||
"invalid rate_limit '%s' for tunnel to %s in %s",
|
||||
w, inet_fmt(rmt_addr, s1), configfilename);
|
||||
break;
|
||||
}
|
||||
v->uv_rate_limit = n;
|
||||
}
|
||||
else if (EQUAL(w, "boundary")) {
|
||||
register struct vif_acl *v_acl;
|
||||
register u_long baddr;
|
||||
|
||||
if (EQUAL((w = next_word(&s)), "")) {
|
||||
log(LOG_ERR, 0,
|
||||
"missing group address for tunnel to %s in %s",
|
||||
inet_fmt(rmt_addr, s1), configfilename);
|
||||
w = "garbage";
|
||||
break;
|
||||
}
|
||||
|
||||
if ((sscanf(w, "%[0-9.]/%d", s1, &n) != 2) ||
|
||||
n < 0 || n> 32) {
|
||||
log(LOG_ERR, 0,
|
||||
"incorrect format '%s' for tunnel to %s in %s",
|
||||
w, inet_fmt(rmt_addr, s1), configfilename);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((baddr = inet_parse(s1)) == 0xffffffff ||
|
||||
(baddr & 0xef000000) != 0xef000000) {
|
||||
log(LOG_ERR, 0,
|
||||
"incorrect address %s for tunnel to %s in %s",
|
||||
s1, inet_fmt(rmt_addr, s1), configfilename);
|
||||
continue;
|
||||
}
|
||||
|
||||
v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
|
||||
if (v_acl == NULL)
|
||||
log(LOG_ERR, 0,
|
||||
"out of memory");
|
||||
VAL_TO_MASK(v_acl->acl_mask, n);
|
||||
v_acl->acl_addr = baddr & v_acl->acl_mask;
|
||||
|
||||
/*
|
||||
* link into data structure
|
||||
*/
|
||||
v_acl->acl_next = v->uv_acl;
|
||||
v->uv_acl = v_acl;
|
||||
}
|
||||
else {
|
||||
log(LOG_ERR, 0,
|
||||
"invalid keyword (%s) in %s",
|
||||
w, configfilename);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!EQUAL(w, "")) continue;
|
||||
|
||||
log(LOG_INFO, 0,
|
||||
"installing %stunnel from %s to %s as vif #%u - rate=%d",
|
||||
v->uv_flags & VIFF_SRCRT? "srcrt " : "",
|
||||
inet_fmt(lcl_addr, s1), inet_fmt(rmt_addr, s2),
|
||||
numvifs, v->uv_rate_limit);
|
||||
|
||||
++numvifs;
|
||||
|
||||
if (!(ffr.ifr_flags & IFF_UP)) {
|
||||
v->uv_flags |= VIFF_DOWN;
|
||||
vifs_down = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
log(LOG_ERR, 0,
|
||||
"unknown command '%s' in %s", w, configfilename);
|
||||
}
|
||||
}
|
||||
|
||||
close(f);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return a pointer to the next "word" in the string to which '*s' points,
|
||||
* lower-cased and null terminated, and advance '*s' to point beyond the word.
|
||||
* Words are separated by blanks and/or tabs, and the input string is
|
||||
* considered to terminate at a newline, '#' (comment), or null character.
|
||||
* If no words remain, a pointer to a null string ("") is returned.
|
||||
* Warning: This function clobbers the input string.
|
||||
*/
|
||||
static char *next_word(s)
|
||||
char **s;
|
||||
{
|
||||
char *w;
|
||||
|
||||
w = *s;
|
||||
while (*w == ' ' || *w == '\t')
|
||||
++w;
|
||||
|
||||
*s = w;
|
||||
for(;;) {
|
||||
switch (**s) {
|
||||
|
||||
case ' ' :
|
||||
case '\t' : **s = '\0';
|
||||
++*s;
|
||||
return (w);
|
||||
|
||||
case '\n' :
|
||||
case '#' : **s = '\0';
|
||||
return (w);
|
||||
|
||||
case '\0' : return (w);
|
||||
|
||||
default : if (isascii(**s) && isupper(**s))
|
||||
**s = tolower(**s);
|
||||
++*s;
|
||||
}
|
||||
}
|
||||
}
|
170
usr.sbin/mrouted/defs.h
Normal file
170
usr.sbin/mrouted/defs.h
Normal file
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* $Id: defs.h,v 1.8 1994/08/24 23:53:23 thyagara Exp $
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
#include <signal.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#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>
|
||||
|
||||
#include "dvmrp.h"
|
||||
#include "vif.h"
|
||||
#include "route.h"
|
||||
#include "prune.h"
|
||||
|
||||
/*
|
||||
* 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 PROTOCOL_VERSION 3 /* increment when packet format/content changes */
|
||||
|
||||
#define MROUTED_VERSION 3 /* increment on local changes or bug fixes, */
|
||||
/* reset to 0 whever PROTOCOL_VERSION increments */
|
||||
|
||||
#define MROUTED_LEVEL ( (MROUTED_VERSION << 8) | PROTOCOL_VERSION )
|
||||
/* for IGMP 'group' field of DVMRP messages */
|
||||
|
||||
#define DEL_RTE_GROUP 0
|
||||
#define DEL_ALL_ROUTES 1
|
||||
/* for Deleting kernel table entries */
|
||||
|
||||
/*
|
||||
* External declarations for global variables and functions.
|
||||
*/
|
||||
extern char recv_buf[MAX_IP_PACKET_LEN];
|
||||
extern char send_buf[MAX_IP_PACKET_LEN];
|
||||
extern int igmp_socket;
|
||||
extern u_long allhosts_group;
|
||||
extern u_long dvmrp_group;
|
||||
extern u_long 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 char s1[];
|
||||
extern char s2[];
|
||||
extern char s3[];
|
||||
|
||||
extern int errno;
|
||||
extern int sys_nerr;
|
||||
extern char * sys_errlist[];
|
||||
|
||||
extern void log();
|
||||
|
||||
extern void init_igmp();
|
||||
extern void accept_igmp();
|
||||
extern void send_igmp();
|
||||
|
||||
extern void init_routes();
|
||||
extern void start_route_updates();
|
||||
extern void update_route();
|
||||
extern void age_routes();
|
||||
extern void expire_all_routes();
|
||||
extern void free_all_routes();
|
||||
|
||||
extern void accept_probe();
|
||||
extern void accept_report();
|
||||
extern void report();
|
||||
extern void report_to_all_neighbors();
|
||||
extern int report_next_chunk();
|
||||
extern void add_vif_to_routes();
|
||||
extern void delete_vif_from_routes();
|
||||
extern void delete_neighbor_from_routes();
|
||||
extern void dump_routes();
|
||||
|
||||
extern void init_vifs();
|
||||
extern void check_vif_state();
|
||||
extern vifi_t find_vif();
|
||||
extern void age_vifs();
|
||||
extern void dump_vifs();
|
||||
extern void stop_all_vifs();
|
||||
|
||||
extern void accept_group_report();
|
||||
extern void query_groups();
|
||||
extern void probe_for_neighbors();
|
||||
extern int update_neighbor();
|
||||
extern void accept_neighbor_request();
|
||||
|
||||
extern void config_vifs_from_kernel();
|
||||
extern void config_vifs_from_file();
|
||||
|
||||
extern int inet_valid_host();
|
||||
extern int inet_valid_subnet();
|
||||
extern char * inet_fmt();
|
||||
extern char * inet_fmts();
|
||||
extern u_long inet_parse();
|
||||
extern int inet_cksum();
|
||||
|
||||
extern struct rtentry * determine_route();
|
||||
|
||||
extern void init_ktable();
|
||||
extern int grplst_mem();
|
||||
extern void add_table_entry();
|
||||
extern void del_table_entry();
|
||||
extern void update_table_entry();
|
||||
extern void update_lclgrp();
|
||||
extern void delete_lclgrp();
|
||||
|
||||
extern unsigned kroutes;
|
||||
extern void send_prune();
|
||||
extern void accept_prune();
|
||||
extern int no_entry_exists();
|
||||
extern struct ktable * find_src_grp();
|
||||
extern int rtr_cnt();
|
||||
extern void free_all_prunes();
|
||||
extern void age_table_entry();
|
||||
extern void dump_cache();
|
||||
|
||||
extern void chkgrp_graft();
|
||||
extern void accept_graft();
|
||||
extern void send_graft_ack();
|
||||
extern void send_graft();
|
||||
extern void accept_g_ack();
|
||||
extern void mtrace();
|
||||
|
||||
extern char * malloc();
|
||||
extern char * fgets();
|
||||
extern FILE * fopen();
|
||||
|
||||
#ifndef htonl
|
||||
extern u_long htonl();
|
||||
extern u_long ntohl();
|
||||
#endif
|
152
usr.sbin/mrouted/dvmrp.h
Normal file
152
usr.sbin/mrouted/dvmrp.h
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* $Id: dvmrp.h,v 1.6 1994/08/24 23:53:30 thyagara Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
|
||||
/*
|
||||
* '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_DOWN 0x10 /* kernel state of interface */
|
||||
#define DVMRP_NF_DISABLED 0x20 /* administratively disabled */
|
||||
#define DVMRP_NF_QUERIER 0x40 /* I am the subnet's querier */
|
||||
|
||||
/*
|
||||
* 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_long)0xe0000004 /* 224.0.0.4 */
|
||||
|
||||
#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 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_RATE_LIMIT 0 /* default 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
|
289
usr.sbin/mrouted/igmp.c
Normal file
289
usr.sbin/mrouted/igmp.c
Normal file
@ -0,0 +1,289 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* $Id: igmp.c,v 1.8 1994/08/24 23:53:32 thyagara Exp $
|
||||
*/
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
|
||||
/*
|
||||
* Exported variables.
|
||||
*/
|
||||
char recv_buf[MAX_IP_PACKET_LEN]; /* input packet buffer */
|
||||
char send_buf[MAX_IP_PACKET_LEN]; /* output packet buffer */
|
||||
int igmp_socket; /* socket for all network I/O */
|
||||
u_long allhosts_group; /* allhosts addr in net order */
|
||||
u_long dvmrp_group; /* DVMRP grp addr in net order */
|
||||
u_long dvmrp_genid; /* IGMP generation id */
|
||||
|
||||
/*
|
||||
* Open and initialize the igmp socket, and fill in the non-changing
|
||||
* IP header fields in the output packet buffer.
|
||||
*/
|
||||
void init_igmp()
|
||||
{
|
||||
struct ip *ip;
|
||||
|
||||
if ((igmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0)
|
||||
log(LOG_ERR, errno, "IGMP socket");
|
||||
|
||||
k_hdr_include(TRUE); /* include IP header when sending */
|
||||
k_set_rcvbuf(48*1024); /* lots of input buffering */
|
||||
k_set_ttl(1); /* restrict multicasts to one hop */
|
||||
k_set_loop(FALSE); /* disable multicast loopback */
|
||||
|
||||
ip = (struct ip *)send_buf;
|
||||
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);
|
||||
}
|
||||
|
||||
/* %%% hack for PIM %%% */
|
||||
#define IGMP_PIM 0x14
|
||||
#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(type, code)
|
||||
u_char type, code;
|
||||
{
|
||||
switch (type) {
|
||||
case IGMP_HOST_MEMBERSHIP_QUERY: return "membership query ";
|
||||
case IGMP_HOST_MEMBERSHIP_REPORT: return "membership report ";
|
||||
case IGMP_HOST_NEW_MEMBERSHIP_REPORT: return "new membership 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 ";
|
||||
default: return "unknown DVMRP msg ";
|
||||
}
|
||||
case IGMP_PIM: /* %%% hack for 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: return "IGMP trace query ";
|
||||
case IGMP_MTRACE_RESP: 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(recvlen)
|
||||
int recvlen;
|
||||
{
|
||||
register vifi_t vifi;
|
||||
register u_long src, dst, group;
|
||||
struct ip *ip;
|
||||
struct igmp *igmp;
|
||||
int ipdatalen, iphdrlen, igmpdatalen;
|
||||
|
||||
if (recvlen < sizeof(struct ip)) {
|
||||
log(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 == NULL || dst == NULL)
|
||||
log(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) {
|
||||
log(LOG_WARNING, 0,
|
||||
"received packet shorter (%u bytes) than hdr+data length (%u+%u)",
|
||||
recvlen, iphdrlen, ipdatalen);
|
||||
return;
|
||||
}
|
||||
|
||||
igmp = (struct igmp *)(recv_buf + iphdrlen);
|
||||
group = igmp->igmp_group.s_addr;
|
||||
igmpdatalen = ipdatalen - IGMP_MINLEN;
|
||||
if (igmpdatalen < 0) {
|
||||
log(LOG_WARNING, 0,
|
||||
"received IP data field too short (%u bytes) for IGMP, from %s",
|
||||
ipdatalen, inet_fmt(src, s1));
|
||||
return;
|
||||
}
|
||||
|
||||
log(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:
|
||||
/* we have to do the determination of the querrier router here */
|
||||
return;
|
||||
|
||||
case IGMP_HOST_MEMBERSHIP_REPORT:
|
||||
case IGMP_HOST_NEW_MEMBERSHIP_REPORT:
|
||||
accept_group_report(src, dst, group,igmp->igmp_type);
|
||||
return;
|
||||
|
||||
case IGMP_HOST_LEAVE_MESSAGE:
|
||||
leave_group_message(src, dst, group);
|
||||
return;
|
||||
|
||||
case IGMP_DVMRP:
|
||||
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, (char *)(igmp+1), igmpdatalen,
|
||||
group);
|
||||
return;
|
||||
|
||||
case DVMRP_NEIGHBORS2:
|
||||
accept_neighbors2(src, dst, (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;
|
||||
|
||||
default:
|
||||
log(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: /* %%% hack for PIM %%% */
|
||||
return;
|
||||
|
||||
case IGMP_MTRACE:
|
||||
mtrace(src, dst, group, (char *)(igmp+1),
|
||||
igmp->igmp_code, igmpdatalen);
|
||||
return;
|
||||
|
||||
default:
|
||||
log(LOG_INFO, 0,
|
||||
"ignoring unknown IGMP message type %u from %s to %s",
|
||||
igmp->igmp_type, inet_fmt(src, s1),
|
||||
inet_fmt(dst, s2));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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(src, dst, type, code, group, datalen)
|
||||
u_long src, dst;
|
||||
int type, code;
|
||||
u_long group;
|
||||
int datalen;
|
||||
{
|
||||
static struct sockaddr_in sdst = {AF_INET};
|
||||
struct ip *ip;
|
||||
struct igmp *igmp;
|
||||
|
||||
ip = (struct ip *)send_buf;
|
||||
ip->ip_src.s_addr = src;
|
||||
ip->ip_dst.s_addr = dst;
|
||||
ip->ip_len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen;
|
||||
|
||||
igmp = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN);
|
||||
igmp->igmp_type = type;
|
||||
igmp->igmp_code = code;
|
||||
igmp->igmp_group.s_addr = group;
|
||||
igmp->igmp_cksum = 0;
|
||||
igmp->igmp_cksum = inet_cksum((u_short *)igmp,
|
||||
IGMP_MINLEN + datalen);
|
||||
|
||||
if (IN_MULTICAST(ntohl(dst))) k_set_if(src);
|
||||
if (dst == allhosts_group) k_set_loop(TRUE);
|
||||
|
||||
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 log(LOG_WARNING, errno, "sendto on %s", inet_fmt(src, s1));
|
||||
}
|
||||
|
||||
if (dst == allhosts_group) k_set_loop(FALSE);
|
||||
|
||||
log(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
|
||||
packet_kind(type, code), inet_fmt(src, s1), inet_fmt(dst, s2));
|
||||
}
|
187
usr.sbin/mrouted/inet.c
Normal file
187
usr.sbin/mrouted/inet.c
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* $Id: inet.c,v 1.4 1993/05/30 01:36:38 deering Exp $
|
||||
*/
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
|
||||
/*
|
||||
* Exported variables.
|
||||
*/
|
||||
char s1[16]; /* buffers to hold the string representations */
|
||||
char s2[16]; /* of IP addresses, to be passed to inet_fmt() */
|
||||
char s3[16]; /* or inet_fmts(). */
|
||||
|
||||
|
||||
/*
|
||||
* 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(naddr)
|
||||
u_long naddr;
|
||||
{
|
||||
register u_long addr;
|
||||
|
||||
addr = ntohl(naddr);
|
||||
|
||||
return (!(IN_MULTICAST(addr) ||
|
||||
IN_BADCLASS (addr) ||
|
||||
(addr & 0xff000000) == 0));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Verify that a given subnet number and mask pair are credible.
|
||||
*/
|
||||
int inet_valid_subnet(nsubnet, nmask)
|
||||
u_long nsubnet, nmask;
|
||||
{
|
||||
register u_long subnet, mask;
|
||||
|
||||
subnet = ntohl(nsubnet);
|
||||
mask = ntohl(nmask);
|
||||
|
||||
if ((subnet & mask) != subnet) return (FALSE);
|
||||
|
||||
if (IN_CLASSA(subnet)) {
|
||||
if (mask < 0xff000000 ||
|
||||
(subnet & 0xff000000) == 0 ||
|
||||
(subnet & 0xff000000) == 0x7f000000) return (FALSE);
|
||||
}
|
||||
else if (IN_CLASSB(subnet)) {
|
||||
if (mask < 0xffff0000) return (FALSE);
|
||||
}
|
||||
else if (IN_CLASSC(subnet)) {
|
||||
if (mask < 0xffffff00) return (FALSE);
|
||||
}
|
||||
else return (FALSE);
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert an IP address in u_long (network) format into a printable string.
|
||||
*/
|
||||
char *inet_fmt(addr, s)
|
||||
u_long addr;
|
||||
char *s;
|
||||
{
|
||||
register 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.
|
||||
*/
|
||||
char *inet_fmts(addr, mask, s)
|
||||
u_long addr, mask;
|
||||
char *s;
|
||||
{
|
||||
register u_char *a, *m;
|
||||
|
||||
a = (u_char *)&addr;
|
||||
m = (u_char *)&mask;
|
||||
|
||||
if (m[3] != 0) sprintf(s, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]);
|
||||
else if (m[2] != 0) sprintf(s, "%u.%u.%u", a[0], a[1], a[2]);
|
||||
else if (m[1] != 0) sprintf(s, "%u.%u", a[0], a[1]);
|
||||
else sprintf(s, "%u", a[0]);
|
||||
|
||||
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_long inet_parse(s)
|
||||
char *s;
|
||||
{
|
||||
u_long a;
|
||||
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(addr, len)
|
||||
u_short *addr;
|
||||
u_int len;
|
||||
{
|
||||
register int nleft = (int)len;
|
||||
register u_short *w = addr;
|
||||
u_short answer = 0;
|
||||
register int sum = 0;
|
||||
|
||||
/*
|
||||
* 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 ) {
|
||||
*(u_char *) (&answer) = *(u_char *)w ;
|
||||
sum += answer;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 = ~sum; /* truncate to 16 bits */
|
||||
return (answer);
|
||||
}
|
183
usr.sbin/mrouted/kern.c
Normal file
183
usr.sbin/mrouted/kern.c
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* $Id: kern.c,v 1.6 1994/08/24 23:53:37 thyagara Exp $
|
||||
*/
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
|
||||
void k_set_rcvbuf(bufsize)
|
||||
int bufsize;
|
||||
{
|
||||
if (setsockopt(igmp_socket, SOL_SOCKET, SO_RCVBUF,
|
||||
(char *)&bufsize, sizeof(bufsize)) < 0)
|
||||
log(LOG_ERR, errno, "setsockopt SO_RCVBUF %u", bufsize);
|
||||
}
|
||||
|
||||
|
||||
void k_hdr_include(bool)
|
||||
int bool;
|
||||
{
|
||||
#ifdef IP_HDRINCL
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, IP_HDRINCL,
|
||||
(char *)&bool, sizeof(bool)) < 0)
|
||||
log(LOG_ERR, errno, "setsockopt IP_HDRINCL %u", bool);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void k_set_ttl(t)
|
||||
int t;
|
||||
{
|
||||
u_char ttl;
|
||||
|
||||
ttl = t;
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_TTL,
|
||||
(char *)&ttl, sizeof(ttl)) < 0)
|
||||
log(LOG_ERR, errno, "setsockopt IP_MULTICAST_TTL %u", ttl);
|
||||
}
|
||||
|
||||
|
||||
void k_set_loop(l)
|
||||
int l;
|
||||
{
|
||||
u_char loop;
|
||||
|
||||
loop = l;
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_LOOP,
|
||||
(char *)&loop, sizeof(loop)) < 0)
|
||||
log(LOG_ERR, errno, "setsockopt IP_MULTICAST_LOOP %u", loop);
|
||||
}
|
||||
|
||||
|
||||
void k_set_if(ifa)
|
||||
u_long ifa;
|
||||
{
|
||||
struct in_addr adr;
|
||||
|
||||
adr.s_addr = ifa;
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_IF,
|
||||
(char *)&adr, sizeof(adr)) < 0)
|
||||
log(LOG_ERR, errno, "setsockopt IP_MULTICAST_IF %s",
|
||||
inet_fmt(ifa, s1));
|
||||
}
|
||||
|
||||
|
||||
void k_join(grp, ifa)
|
||||
u_long grp;
|
||||
u_long 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)
|
||||
log(LOG_WARNING, errno, "can't join group %s on interface %s",
|
||||
inet_fmt(grp, s1), inet_fmt(ifa, s2));
|
||||
}
|
||||
|
||||
|
||||
void k_leave(grp, ifa)
|
||||
u_long grp;
|
||||
u_long 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)
|
||||
log(LOG_WARNING, errno, "can't leave group %s on interface %s",
|
||||
inet_fmt(grp, s1), inet_fmt(ifa, s2));
|
||||
}
|
||||
|
||||
|
||||
void k_init_dvmrp()
|
||||
{
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_INIT,
|
||||
(char *)NULL, 0) < 0)
|
||||
log(LOG_ERR, errno, "can't enable DVMRP routing in kernel");
|
||||
}
|
||||
|
||||
|
||||
void k_stop_dvmrp()
|
||||
{
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DONE,
|
||||
(char *)NULL, 0) < 0)
|
||||
log(LOG_WARNING, errno, "can't disable DVMRP routing in kernel");
|
||||
}
|
||||
|
||||
|
||||
void k_add_vif(vifi, v)
|
||||
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, DVMRP_ADD_VIF,
|
||||
(char *)&vc, sizeof(vc)) < 0)
|
||||
log(LOG_ERR, errno, "setsockopt DVMRP_ADD_VIF");
|
||||
}
|
||||
|
||||
|
||||
void k_del_vif(vifi)
|
||||
vifi_t vifi;
|
||||
{
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DEL_VIF,
|
||||
(char *)&vifi, sizeof(vifi)) < 0)
|
||||
log(LOG_ERR, errno, "setsockopt DVMRP_DEL_VIF");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Adds a (source, mcastgrp) entry to the kernel
|
||||
*/
|
||||
void k_add_rg(kt)
|
||||
struct ktable *kt;
|
||||
{
|
||||
struct mfcctl mc;
|
||||
|
||||
/* copy table values so that setsockopt can process it */
|
||||
COPY_TABLES(kt, mc);
|
||||
|
||||
/* write to kernel space */
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_ADD_MFC,
|
||||
(char *)&mc, sizeof(mc)) < 0)
|
||||
log(LOG_WARNING, errno, "setsockopt DVMRP_ADD_MFC");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Deletes a (source, mcastgrp) entry from the kernel
|
||||
*/
|
||||
void k_del_rg(kt)
|
||||
struct ktable *kt;
|
||||
{
|
||||
struct mfcctl mc;
|
||||
|
||||
/* copy table values so that setsockopt can process it */
|
||||
COPY_TABLES(kt, mc);
|
||||
|
||||
/* write to kernel space */
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DEL_MFC,
|
||||
(char *)&mc, sizeof(mc)) < 0)
|
||||
log(LOG_WARNING, errno, "setsockopt DVMRP_DEL_MFC");
|
||||
}
|
439
usr.sbin/mrouted/main.c
Normal file
439
usr.sbin/mrouted/main.c
Normal file
@ -0,0 +1,439 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* $Id: main.c,v 1.8 1994/08/24 23:53:42 thyagara Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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"
|
||||
|
||||
extern char *configfilename;
|
||||
|
||||
static char pidfilename[] = "/etc/mrouted.pid";
|
||||
static char dumpfilename[] = "/usr/tmp/mrouted.dump";
|
||||
static char cachefilename[] = "/usr/tmp/mrouted.cache";
|
||||
static char genidfilename[] = "/usr/tmp/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 */
|
||||
|
||||
|
||||
/*
|
||||
* Forward declarations.
|
||||
*/
|
||||
static void fasttimer();
|
||||
static void timer();
|
||||
static void hup();
|
||||
static void dump();
|
||||
static void fdump();
|
||||
static void cdump();
|
||||
static void restart();
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
register int recvlen;
|
||||
register int omask;
|
||||
int dummy;
|
||||
FILE *fp;
|
||||
extern uid_t geteuid();
|
||||
struct timeval tv;
|
||||
struct timezone tzp;
|
||||
u_long prev_genid;
|
||||
|
||||
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;
|
||||
} 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
|
||||
*/
|
||||
int t;
|
||||
|
||||
if (fork()) exit(0);
|
||||
(void)close(0);
|
||||
(void)close(1);
|
||||
(void)close(2);
|
||||
(void)open("/", 0);
|
||||
(void)dup2(0, 1);
|
||||
(void)dup2(0, 2);
|
||||
t = open("/dev/tty", 2);
|
||||
if (t >= 0) {
|
||||
(void)ioctl(t, TIOCNOTTY, (char *)0);
|
||||
(void)close(t);
|
||||
}
|
||||
}
|
||||
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
|
||||
log(LOG_NOTICE, 0, "mrouted version %d.%d",
|
||||
PROTOCOL_VERSION, MROUTED_VERSION);
|
||||
|
||||
srandom(gethostid());
|
||||
|
||||
/*
|
||||
* Get generation id
|
||||
*/
|
||||
gettimeofday(&tv, &tzp);
|
||||
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();
|
||||
k_init_dvmrp(); /* enable DVMRP routing in kernel */
|
||||
init_routes();
|
||||
init_ktable();
|
||||
init_vifs();
|
||||
|
||||
if (debug)
|
||||
fprintf(stderr, "pruning %s\n", pruning ? "on" : "off");
|
||||
|
||||
fp = fopen(pidfilename, "w");
|
||||
if (fp != NULL) {
|
||||
fprintf(fp, "%d\n", getpid());
|
||||
(void) fclose(fp);
|
||||
}
|
||||
|
||||
if (debug >= 2) dump();
|
||||
|
||||
(void)signal(SIGALRM, fasttimer);
|
||||
|
||||
(void)signal(SIGHUP, restart);
|
||||
(void)signal(SIGTERM, hup);
|
||||
(void)signal(SIGINT, hup);
|
||||
(void)signal(SIGUSR1, fdump);
|
||||
(void)signal(SIGUSR2, cdump);
|
||||
if (debug != 0)
|
||||
(void)signal(SIGQUIT, dump);
|
||||
|
||||
(void)alarm(1); /* schedule first timer interrupt */
|
||||
|
||||
/*
|
||||
* Main receive loop.
|
||||
*/
|
||||
dummy = 0;
|
||||
for(;;) {
|
||||
recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
|
||||
0, NULL, &dummy);
|
||||
if (recvlen < 0) {
|
||||
if (errno != EINTR) log(LOG_ERR, errno, "recvfrom");
|
||||
continue;
|
||||
}
|
||||
omask = sigblock(sigmask(SIGALRM));
|
||||
accept_igmp(recvlen);
|
||||
(void)sigsetmask(omask);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* routine invoked every second. It's 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()
|
||||
{
|
||||
static unsigned int tlast;
|
||||
static unsigned int nsent;
|
||||
register unsigned int t = tlast + 1;
|
||||
register 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) {
|
||||
register int nleft = nroutes - nsent;
|
||||
while (nleft > 0) {
|
||||
if ((n = report_next_chunk()) <= 0)
|
||||
break;
|
||||
nleft -= n;
|
||||
}
|
||||
tlast = 0;
|
||||
nsent = 0;
|
||||
} else {
|
||||
register 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()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Advance virtual time
|
||||
*/
|
||||
virtual_time += TIMER_INTERVAL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* On hangup signal, let everyone know we're going away.
|
||||
*/
|
||||
static void hup()
|
||||
{
|
||||
log(LOG_INFO, 0, "hup");
|
||||
expire_all_routes();
|
||||
report_to_all_neighbors(ALL_ROUTES);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Dump internal data structures to stderr.
|
||||
*/
|
||||
static void dump()
|
||||
{
|
||||
dump_vifs(stderr);
|
||||
dump_routes(stderr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Dump internal data structures to a file.
|
||||
*/
|
||||
static void fdump()
|
||||
{
|
||||
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()
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(cachefilename, "w");
|
||||
if (fp != NULL) {
|
||||
dump_cache(fp);
|
||||
(void) fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Restart mrouted
|
||||
*/
|
||||
static void restart()
|
||||
{
|
||||
register int omask;
|
||||
|
||||
log(LOG_INFO, 0, "restart");
|
||||
|
||||
/*
|
||||
* reset all the entries
|
||||
*/
|
||||
omask = sigblock(sigmask(SIGALRM));
|
||||
free_all_prunes();
|
||||
free_all_routes();
|
||||
stop_all_vifs();
|
||||
k_stop_dvmrp();
|
||||
|
||||
/*
|
||||
* start processing again
|
||||
*/
|
||||
dvmrp_genid++;
|
||||
pruning = 1;
|
||||
|
||||
init_igmp();
|
||||
k_init_dvmrp(); /* enable DVMRP routing in kernel */
|
||||
init_routes();
|
||||
init_ktable();
|
||||
init_vifs();
|
||||
|
||||
(void)sigsetmask(omask);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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 log(severity, syserr, format, a, b, c, d, e)
|
||||
int severity, syserr;
|
||||
char *format;
|
||||
int a, b, c, d, e;
|
||||
{
|
||||
char fmt[100];
|
||||
|
||||
switch (debug) {
|
||||
case 0: break;
|
||||
case 1: if (severity > LOG_NOTICE) break;
|
||||
case 2: if (severity > LOG_INFO ) break;
|
||||
default:
|
||||
fmt[0] = '\0';
|
||||
if (severity == LOG_WARNING) strcat(fmt, "warning - ");
|
||||
strncat(fmt, format, 80);
|
||||
fprintf(stderr, fmt, a, b, c, d, e);
|
||||
if (syserr == 0)
|
||||
fprintf(stderr, "\n");
|
||||
else if(syserr < sys_nerr)
|
||||
fprintf(stderr, ": %s\n", sys_errlist[syserr]);
|
||||
else
|
||||
fprintf(stderr, ": errno %d\n", syserr);
|
||||
}
|
||||
|
||||
if (severity <= LOG_NOTICE) {
|
||||
fmt[0] = '\0';
|
||||
if (severity == LOG_WARNING) strcat(fmt, "warning - ");
|
||||
strncat(fmt, format, 80);
|
||||
if (syserr != 0) {
|
||||
strcat(fmt, ": %m");
|
||||
errno = syserr;
|
||||
}
|
||||
syslog(severity, fmt, a, b, c, d, e);
|
||||
|
||||
if (severity <= LOG_ERR) exit(-1);
|
||||
}
|
||||
}
|
953
usr.sbin/mrouted/mapper.c
Normal file
953
usr.sbin/mrouted/mapper.c
Normal file
@ -0,0 +1,953 @@
|
||||
/* Mapper for connections between MRouteD multicast routers.
|
||||
* Written by Pavel Curtis <Pavel@PARC.Xerox.Com>
|
||||
*
|
||||
* $Id: mapper.c,v 1.8 1994/08/24 23:53:54 thyagara Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) Xerox Corporation 1992. All rights reserved.
|
||||
*
|
||||
* License is granted to copy, to use, and to make and to use derivative
|
||||
* works for research and evaluation purposes, provided that Xerox is
|
||||
* acknowledged in all documentation pertaining to any such copy or derivative
|
||||
* work. Xerox grants no other licenses expressed or implied. The Xerox trade
|
||||
* name should not be used in any advertising without its written permission.
|
||||
*
|
||||
* XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
|
||||
* MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
|
||||
* FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without
|
||||
* express or implied warranty of any kind.
|
||||
*
|
||||
* These notices must be retained in any copies of any part of this software.
|
||||
*/
|
||||
|
||||
#include <netdb.h>
|
||||
#include <sys/time.h>
|
||||
#include "defs.h"
|
||||
|
||||
#define DEFAULT_TIMEOUT 2 /* How long to wait before retrying requests */
|
||||
#define DEFAULT_RETRIES 1 /* How many times to ask each router */
|
||||
|
||||
|
||||
/* All IP addresses are stored in the data structure in NET order. */
|
||||
|
||||
typedef struct neighbor {
|
||||
struct neighbor *next;
|
||||
u_long addr; /* IP address in NET order */
|
||||
u_char metric; /* TTL cost of forwarding */
|
||||
u_char threshold; /* TTL threshold to forward */
|
||||
u_short flags; /* flags on connection */
|
||||
#define NF_PRESENT 0x8000 /* True if flags are meaningful */
|
||||
} Neighbor;
|
||||
|
||||
typedef struct interface {
|
||||
struct interface *next;
|
||||
u_long addr; /* IP address of the interface in NET order */
|
||||
Neighbor *neighbors; /* List of neighbors' IP addresses */
|
||||
} Interface;
|
||||
|
||||
typedef struct node {
|
||||
u_long addr; /* IP address of this entry in NET order */
|
||||
u_long version; /* which mrouted version is running */
|
||||
int tries; /* How many requests sent? -1 for aliases */
|
||||
union {
|
||||
struct node *alias; /* If alias, to what? */
|
||||
struct interface *interfaces; /* Else, neighbor data */
|
||||
} u;
|
||||
struct node *left, *right;
|
||||
} Node;
|
||||
|
||||
|
||||
Node *routers = 0;
|
||||
u_long our_addr, target_addr = 0; /* in NET order */
|
||||
int debug = 0;
|
||||
int retries = DEFAULT_RETRIES;
|
||||
int timeout = DEFAULT_TIMEOUT;
|
||||
int show_names = TRUE;
|
||||
vifi_t numvifs; /* to keep loader happy */
|
||||
/* (see COPY_TABLES macro called in kern.c) */
|
||||
|
||||
|
||||
Node *find_node(addr, ptr)
|
||||
u_long addr;
|
||||
Node **ptr;
|
||||
{
|
||||
Node *n = *ptr;
|
||||
|
||||
if (!n) {
|
||||
*ptr = n = (Node *) malloc(sizeof(Node));
|
||||
n->addr = addr;
|
||||
n->version = 0;
|
||||
n->tries = 0;
|
||||
n->u.interfaces = 0;
|
||||
n->left = n->right = 0;
|
||||
return n;
|
||||
} else if (addr == n->addr)
|
||||
return n;
|
||||
else if (addr < n->addr)
|
||||
return find_node(addr, &(n->left));
|
||||
else
|
||||
return find_node(addr, &(n->right));
|
||||
}
|
||||
|
||||
|
||||
Interface *find_interface(addr, node)
|
||||
u_long addr;
|
||||
Node *node;
|
||||
{
|
||||
Interface *ifc;
|
||||
|
||||
for (ifc = node->u.interfaces; ifc; ifc = ifc->next)
|
||||
if (ifc->addr == addr)
|
||||
return ifc;
|
||||
|
||||
ifc = (Interface *) malloc(sizeof(Interface));
|
||||
ifc->addr = addr;
|
||||
ifc->next = node->u.interfaces;
|
||||
node->u.interfaces = ifc;
|
||||
ifc->neighbors = 0;
|
||||
|
||||
return ifc;
|
||||
}
|
||||
|
||||
|
||||
Neighbor *find_neighbor(addr, node)
|
||||
u_long addr;
|
||||
Node *node;
|
||||
{
|
||||
Interface *ifc;
|
||||
|
||||
for (ifc = node->u.interfaces; ifc; ifc = ifc->next) {
|
||||
Neighbor *nb;
|
||||
|
||||
for (nb = ifc->neighbors; nb; nb = nb->next)
|
||||
if (nb->addr == addr)
|
||||
return nb;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Log errors and other messages 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 log(severity, syserr, format, a, b, c, d, e)
|
||||
int severity, syserr;
|
||||
char *format;
|
||||
int a, b, c, d, e;
|
||||
{
|
||||
char fmt[100];
|
||||
|
||||
switch (debug) {
|
||||
case 0: if (severity > LOG_WARNING) return;
|
||||
case 1: if (severity > LOG_NOTICE ) return;
|
||||
case 2: if (severity > LOG_INFO ) return;
|
||||
default:
|
||||
fmt[0] = '\0';
|
||||
if (severity == LOG_WARNING)
|
||||
strcat(fmt, "warning - ");
|
||||
strncat(fmt, format, 80);
|
||||
fprintf(stderr, fmt, a, b, c, d, e);
|
||||
if (syserr == 0)
|
||||
fprintf(stderr, "\n");
|
||||
else if (syserr < sys_nerr)
|
||||
fprintf(stderr, ": %s\n", sys_errlist[syserr]);
|
||||
else
|
||||
fprintf(stderr, ": errno %d\n", syserr);
|
||||
}
|
||||
|
||||
if (severity <= LOG_ERR)
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Send a neighbors-list request.
|
||||
*/
|
||||
void ask(dst)
|
||||
u_long dst;
|
||||
{
|
||||
send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS,
|
||||
htonl(MROUTED_LEVEL), 0);
|
||||
}
|
||||
|
||||
void ask2(dst)
|
||||
u_long dst;
|
||||
{
|
||||
send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2,
|
||||
htonl(MROUTED_LEVEL), 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Process an incoming group membership report.
|
||||
*/
|
||||
void accept_group_report(src, dst, group)
|
||||
u_long src, dst, group;
|
||||
{
|
||||
log(LOG_INFO, 0, "ignoring IGMP group membership report from %s to %s",
|
||||
inet_fmt(src, s1), inet_fmt(dst, s2));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Process an incoming neighbor probe message.
|
||||
*/
|
||||
void accept_probe(src, dst)
|
||||
u_long src, dst;
|
||||
{
|
||||
log(LOG_INFO, 0, "ignoring DVMRP probe from %s to %s",
|
||||
inet_fmt(src, s1), inet_fmt(dst, s2));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Process an incoming route report message.
|
||||
*/
|
||||
void accept_report(src, dst, p, datalen)
|
||||
u_long src, dst;
|
||||
char *p;
|
||||
int datalen;
|
||||
{
|
||||
log(LOG_INFO, 0, "ignoring DVMRP routing report from %s to %s",
|
||||
inet_fmt(src, s1), inet_fmt(dst, s2));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Process an incoming neighbor-list request message.
|
||||
*/
|
||||
void accept_neighbor_request(src, dst)
|
||||
u_long src, dst;
|
||||
{
|
||||
if (src != our_addr)
|
||||
log(LOG_INFO, 0,
|
||||
"ignoring spurious DVMRP neighbor request from %s to %s",
|
||||
inet_fmt(src, s1), inet_fmt(dst, s2));
|
||||
}
|
||||
|
||||
void accept_neighbor_request2(src, dst)
|
||||
u_long src, dst;
|
||||
{
|
||||
if (src != our_addr)
|
||||
log(LOG_INFO, 0,
|
||||
"ignoring spurious DVMRP neighbor request2 from %s to %s",
|
||||
inet_fmt(src, s1), inet_fmt(dst, s2));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Process an incoming neighbor-list message.
|
||||
*/
|
||||
void accept_neighbors(src, dst, p, datalen, level)
|
||||
u_long src, dst, level;
|
||||
u_char *p;
|
||||
int datalen;
|
||||
{
|
||||
Node *node = find_node(src, &routers);
|
||||
|
||||
if (node->tries == 0) /* Never heard of 'em; must have hit them at */
|
||||
node->tries = 1; /* least once, though...*/
|
||||
else if (node->tries == -1) /* follow alias link */
|
||||
node = node->u.alias;
|
||||
|
||||
#define GET_ADDR(a) (a = ((u_long)*p++ << 24), a += ((u_long)*p++ << 16),\
|
||||
a += ((u_long)*p++ << 8), a += *p++)
|
||||
|
||||
/* if node is running a recent mrouted, ask for additional info */
|
||||
if (level != 0) {
|
||||
node->version = ntohl(level);
|
||||
node->tries = 0;
|
||||
ask2(src);
|
||||
return;
|
||||
}
|
||||
|
||||
if (debug > 3) {
|
||||
int i;
|
||||
|
||||
fprintf(stderr, " datalen = %d\n", datalen);
|
||||
for (i = 0; i < datalen; i++) {
|
||||
if ((i & 0xF) == 0)
|
||||
fprintf(stderr, " ");
|
||||
fprintf(stderr, " %02x", p[i]);
|
||||
if ((i & 0xF) == 0xF)
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
if ((datalen & 0xF) != 0xF)
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
while (datalen > 0) { /* loop through interfaces */
|
||||
u_long ifc_addr;
|
||||
u_char metric, threshold, ncount;
|
||||
Node *ifc_node;
|
||||
Interface *ifc;
|
||||
Neighbor *old_neighbors;
|
||||
|
||||
if (datalen < 4 + 3) {
|
||||
log(LOG_WARNING, 0, "received truncated interface record from %s",
|
||||
inet_fmt(src, s1));
|
||||
return;
|
||||
}
|
||||
|
||||
GET_ADDR(ifc_addr);
|
||||
ifc_addr = htonl(ifc_addr);
|
||||
metric = *p++;
|
||||
threshold = *p++;
|
||||
ncount = *p++;
|
||||
datalen -= 4 + 3;
|
||||
|
||||
/* Fix up any alias information */
|
||||
ifc_node = find_node(ifc_addr, &routers);
|
||||
if (ifc_node->tries == 0) { /* new node */
|
||||
ifc_node->tries = -1;
|
||||
ifc_node->u.alias = node;
|
||||
} else if (ifc_node != node
|
||||
&& (ifc_node->tries > 0 || ifc_node->u.alias != node)) {
|
||||
/* must merge two hosts' nodes */
|
||||
Interface *ifc_i, *next_ifc_i;
|
||||
|
||||
if (ifc_node->tries == -1) {
|
||||
Node *tmp = ifc_node->u.alias;
|
||||
|
||||
ifc_node->u.alias = node;
|
||||
ifc_node = tmp;
|
||||
}
|
||||
|
||||
/* Merge ifc_node (foo_i) into node (foo_n) */
|
||||
|
||||
if (ifc_node->tries > node->tries)
|
||||
node->tries = ifc_node->tries;
|
||||
|
||||
for (ifc_i = ifc_node->u.interfaces; ifc_i; ifc_i = next_ifc_i) {
|
||||
Neighbor *nb_i, *next_nb_i, *nb_n;
|
||||
Interface *ifc_n = find_interface(ifc_i->addr, node);
|
||||
|
||||
old_neighbors = ifc_n->neighbors;
|
||||
for (nb_i = ifc_i->neighbors; nb_i; nb_i = next_nb_i) {
|
||||
next_nb_i = nb_i->next;
|
||||
for (nb_n = old_neighbors; nb_n; nb_n = nb_n->next)
|
||||
if (nb_i->addr == nb_n->addr) {
|
||||
if (nb_i->metric != nb_n->metric
|
||||
|| nb_i->threshold != nb_i->threshold)
|
||||
log(LOG_WARNING, 0,
|
||||
"inconsistent %s for neighbor %s of %s",
|
||||
"metric/threshold",
|
||||
inet_fmt(nb_i->addr, s1),
|
||||
inet_fmt(node->addr, s2));
|
||||
free(nb_i);
|
||||
break;
|
||||
}
|
||||
if (!nb_n) { /* no match for this neighbor yet */
|
||||
nb_i->next = ifc_n->neighbors;
|
||||
ifc_n->neighbors = nb_i;
|
||||
}
|
||||
}
|
||||
|
||||
next_ifc_i = ifc_i->next;
|
||||
free(ifc_i);
|
||||
}
|
||||
|
||||
ifc_node->tries = -1;
|
||||
ifc_node->u.alias = node;
|
||||
}
|
||||
|
||||
ifc = find_interface(ifc_addr, node);
|
||||
old_neighbors = ifc->neighbors;
|
||||
|
||||
/* Add the neighbors for this interface */
|
||||
while (ncount--) {
|
||||
u_long neighbor;
|
||||
Neighbor *nb;
|
||||
Node *n_node;
|
||||
|
||||
if (datalen < 4) {
|
||||
log(LOG_WARNING, 0, "received truncated neighbor list from %s",
|
||||
inet_fmt(src, s1));
|
||||
return;
|
||||
}
|
||||
|
||||
GET_ADDR(neighbor);
|
||||
neighbor = htonl(neighbor);
|
||||
datalen -= 4;
|
||||
|
||||
for (nb = old_neighbors; nb; nb = nb->next)
|
||||
if (nb->addr == neighbor) {
|
||||
if (metric != nb->metric || threshold != nb->threshold)
|
||||
log(LOG_WARNING, 0,
|
||||
"inconsistent %s for neighbor %s of %s",
|
||||
"metric/threshold",
|
||||
inet_fmt(nb->addr, s1), inet_fmt(node->addr, s2));
|
||||
goto next_neighbor;
|
||||
}
|
||||
|
||||
nb = (Neighbor *) malloc(sizeof(Neighbor));
|
||||
nb->next = ifc->neighbors;
|
||||
ifc->neighbors = nb;
|
||||
nb->addr = neighbor;
|
||||
nb->metric = metric;
|
||||
nb->threshold = threshold;
|
||||
nb->flags = 0;
|
||||
|
||||
n_node = find_node(neighbor, &routers);
|
||||
if (n_node->tries == 0 && !target_addr) { /* it's a new router */
|
||||
ask(neighbor);
|
||||
n_node->tries = 1;
|
||||
}
|
||||
|
||||
next_neighbor: ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void accept_neighbors2(src, dst, p, datalen)
|
||||
u_long src, dst;
|
||||
u_char *p;
|
||||
int datalen;
|
||||
{
|
||||
Node *node = find_node(src, &routers);
|
||||
|
||||
if (node->tries == 0) /* Never heard of 'em; must have hit them at */
|
||||
node->tries = 1; /* least once, though...*/
|
||||
else if (node->tries == -1) /* follow alias link */
|
||||
node = node->u.alias;
|
||||
|
||||
while (datalen > 0) { /* loop through interfaces */
|
||||
u_long ifc_addr;
|
||||
u_char metric, threshold, ncount, flags;
|
||||
Node *ifc_node;
|
||||
Interface *ifc;
|
||||
Neighbor *old_neighbors;
|
||||
|
||||
if (datalen < 4 + 4) {
|
||||
log(LOG_WARNING, 0, "received truncated interface record from %s",
|
||||
inet_fmt(src, s1));
|
||||
return;
|
||||
}
|
||||
|
||||
ifc_addr = *(u_long*)p;
|
||||
p += 4;
|
||||
metric = *p++;
|
||||
threshold = *p++;
|
||||
flags = *p++;
|
||||
ncount = *p++;
|
||||
datalen -= 4 + 4;
|
||||
|
||||
/* Fix up any alias information */
|
||||
ifc_node = find_node(ifc_addr, &routers);
|
||||
if (ifc_node->tries == 0) { /* new node */
|
||||
ifc_node->tries = -1;
|
||||
ifc_node->u.alias = node;
|
||||
} else if (ifc_node != node
|
||||
&& (ifc_node->tries > 0 || ifc_node->u.alias != node)) {
|
||||
/* must merge two hosts' nodes */
|
||||
Interface *ifc_i, *next_ifc_i;
|
||||
|
||||
if (ifc_node->tries == -1) {
|
||||
Node *tmp = ifc_node->u.alias;
|
||||
|
||||
ifc_node->u.alias = node;
|
||||
ifc_node = tmp;
|
||||
}
|
||||
|
||||
/* Merge ifc_node (foo_i) into node (foo_n) */
|
||||
|
||||
if (ifc_node->tries > node->tries)
|
||||
node->tries = ifc_node->tries;
|
||||
|
||||
for (ifc_i = ifc_node->u.interfaces; ifc_i; ifc_i = next_ifc_i) {
|
||||
Neighbor *nb_i, *next_nb_i, *nb_n;
|
||||
Interface *ifc_n = find_interface(ifc_i->addr, node);
|
||||
|
||||
old_neighbors = ifc_n->neighbors;
|
||||
for (nb_i = ifc_i->neighbors; nb_i; nb_i = next_nb_i) {
|
||||
next_nb_i = nb_i->next;
|
||||
for (nb_n = old_neighbors; nb_n; nb_n = nb_n->next)
|
||||
if (nb_i->addr == nb_n->addr) {
|
||||
if (nb_i->metric != nb_n->metric
|
||||
|| nb_i->threshold != nb_i->threshold)
|
||||
log(LOG_WARNING, 0,
|
||||
"inconsistent %s for neighbor %s of %s",
|
||||
"metric/threshold",
|
||||
inet_fmt(nb_i->addr, s1),
|
||||
inet_fmt(node->addr, s2));
|
||||
free(nb_i);
|
||||
break;
|
||||
}
|
||||
if (!nb_n) { /* no match for this neighbor yet */
|
||||
nb_i->next = ifc_n->neighbors;
|
||||
ifc_n->neighbors = nb_i;
|
||||
}
|
||||
}
|
||||
|
||||
next_ifc_i = ifc_i->next;
|
||||
free(ifc_i);
|
||||
}
|
||||
|
||||
ifc_node->tries = -1;
|
||||
ifc_node->u.alias = node;
|
||||
}
|
||||
|
||||
ifc = find_interface(ifc_addr, node);
|
||||
old_neighbors = ifc->neighbors;
|
||||
|
||||
/* Add the neighbors for this interface */
|
||||
while (ncount--) {
|
||||
u_long neighbor;
|
||||
Neighbor *nb;
|
||||
Node *n_node;
|
||||
|
||||
if (datalen < 4) {
|
||||
log(LOG_WARNING, 0, "received truncated neighbor list from %s",
|
||||
inet_fmt(src, s1));
|
||||
return;
|
||||
}
|
||||
|
||||
neighbor = *(u_long*)p;
|
||||
p += 4;
|
||||
datalen -= 4;
|
||||
if (neighbor == 0)
|
||||
/* make leaf nets point to themselves */
|
||||
neighbor = ifc_addr;
|
||||
|
||||
for (nb = old_neighbors; nb; nb = nb->next)
|
||||
if (nb->addr == neighbor) {
|
||||
if (metric != nb->metric || threshold != nb->threshold)
|
||||
log(LOG_WARNING, 0,
|
||||
"inconsistent %s for neighbor %s of %s",
|
||||
"metric/threshold",
|
||||
inet_fmt(nb->addr, s1), inet_fmt(node->addr, s2));
|
||||
goto next_neighbor;
|
||||
}
|
||||
|
||||
nb = (Neighbor *) malloc(sizeof(Neighbor));
|
||||
nb->next = ifc->neighbors;
|
||||
ifc->neighbors = nb;
|
||||
nb->addr = neighbor;
|
||||
nb->metric = metric;
|
||||
nb->threshold = threshold;
|
||||
nb->flags = flags | NF_PRESENT;
|
||||
|
||||
n_node = find_node(neighbor, &routers);
|
||||
if (n_node->tries == 0 && !target_addr) { /* it's a new router */
|
||||
ask(neighbor);
|
||||
n_node->tries = 1;
|
||||
}
|
||||
|
||||
next_neighbor: ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void check_vif_state()
|
||||
{
|
||||
log(LOG_NOTICE, 0, "network marked down...");
|
||||
}
|
||||
|
||||
|
||||
int retry_requests(node)
|
||||
Node *node;
|
||||
{
|
||||
int result;
|
||||
|
||||
if (node) {
|
||||
result = retry_requests(node->left);
|
||||
if (node->tries > 0 && node->tries < retries) {
|
||||
if (node->version)
|
||||
ask2(node->addr);
|
||||
else
|
||||
ask(node->addr);
|
||||
node->tries++;
|
||||
result = 1;
|
||||
}
|
||||
return retry_requests(node->right) || result;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
char *inet_name(addr)
|
||||
u_long addr;
|
||||
{
|
||||
struct hostent *e;
|
||||
|
||||
e = gethostbyaddr(&addr, sizeof(addr), AF_INET);
|
||||
|
||||
return e ? e->h_name : 0;
|
||||
}
|
||||
|
||||
|
||||
void print_map(node)
|
||||
Node *node;
|
||||
{
|
||||
if (node) {
|
||||
char *name, *addr;
|
||||
|
||||
print_map(node->left);
|
||||
|
||||
addr = inet_fmt(node->addr, s1);
|
||||
if (!target_addr
|
||||
|| (node->tries >= 0 && node->u.interfaces)
|
||||
|| (node->tries == -1
|
||||
&& node->u.alias->tries >= 0
|
||||
&& node->u.alias->u.interfaces)) {
|
||||
if (show_names && (name = inet_name(node->addr)))
|
||||
printf("%s (%s):", addr, name);
|
||||
else
|
||||
printf("%s:", addr);
|
||||
if (node->tries < 0)
|
||||
printf(" alias for %s\n\n", inet_fmt(node->u.alias->addr, s1));
|
||||
else if (!node->u.interfaces)
|
||||
printf(" no response to query\n\n");
|
||||
else {
|
||||
Interface *ifc;
|
||||
|
||||
if (node->version)
|
||||
printf(" <v%d.%d>", node->version & 0xff,
|
||||
(node->version >> 8) & 0xff);
|
||||
printf("\n");
|
||||
for (ifc = node->u.interfaces; ifc; ifc = ifc->next) {
|
||||
Neighbor *nb;
|
||||
char *ifc_name = inet_fmt(ifc->addr, s1);
|
||||
int ifc_len = strlen(ifc_name);
|
||||
int count = 0;
|
||||
|
||||
printf(" %s:", ifc_name);
|
||||
for (nb = ifc->neighbors; nb; nb = nb->next) {
|
||||
if (count > 0)
|
||||
printf("%*s", ifc_len + 5, "");
|
||||
printf(" %s", inet_fmt(nb->addr, s1));
|
||||
if (show_names && (name = inet_name(nb->addr)))
|
||||
printf(" (%s)", name);
|
||||
printf(" [%d/%d", nb->metric, nb->threshold);
|
||||
if (nb->flags) {
|
||||
u_short flags = nb->flags;
|
||||
if (flags & DVMRP_NF_TUNNEL)
|
||||
printf("/tunnel");
|
||||
if (flags & DVMRP_NF_SRCRT)
|
||||
printf("/srcrt");
|
||||
if (flags & DVMRP_NF_QUERIER)
|
||||
printf("/querier");
|
||||
if (flags & DVMRP_NF_DISABLED)
|
||||
printf("/disabled");
|
||||
if (flags & DVMRP_NF_DOWN)
|
||||
printf("/down");
|
||||
}
|
||||
printf("]\n");
|
||||
count++;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
print_map(node->right);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char *graph_name(addr, buf)
|
||||
u_long addr;
|
||||
char *buf;
|
||||
{
|
||||
char *name;
|
||||
|
||||
if (show_names && (name = inet_name(addr)))
|
||||
strcpy(buf, name);
|
||||
else
|
||||
inet_fmt(addr, buf);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
void graph_edges(node)
|
||||
Node *node;
|
||||
{
|
||||
Interface *ifc;
|
||||
Neighbor *nb;
|
||||
char name[100];
|
||||
|
||||
if (node) {
|
||||
graph_edges(node->left);
|
||||
if (node->tries >= 0) {
|
||||
printf(" %d {$ NP %d0 %d0 $} \"%s%s\" \n",
|
||||
(int) node->addr,
|
||||
node->addr & 0xFF, (node->addr >> 8) & 0xFF,
|
||||
graph_name(node->addr, name),
|
||||
node->u.interfaces ? "" : "*");
|
||||
for (ifc = node->u.interfaces; ifc; ifc = ifc->next)
|
||||
for (nb = ifc->neighbors; nb; nb = nb->next) {
|
||||
Node *nb_node = find_node(nb->addr, &routers);
|
||||
Neighbor *nb2;
|
||||
|
||||
if (nb_node->tries < 0)
|
||||
nb_node = nb_node->u.alias;
|
||||
|
||||
if (node != nb_node &&
|
||||
(!(nb2 = find_neighbor(node->addr, nb_node))
|
||||
|| node->addr < nb_node->addr)) {
|
||||
printf(" %d \"%d/%d",
|
||||
nb_node->addr, nb->metric, nb->threshold);
|
||||
if (nb2 && (nb2->metric != nb->metric
|
||||
|| nb2->threshold != nb->threshold))
|
||||
printf(",%d/%d", nb2->metric, nb2->threshold);
|
||||
if (nb->flags & NF_PRESENT)
|
||||
printf("%s%s",
|
||||
nb->flags & DVMRP_NF_SRCRT ? "" :
|
||||
nb->flags & DVMRP_NF_TUNNEL ? "E" : "P",
|
||||
nb->flags & DVMRP_NF_DOWN ? "D" : "");
|
||||
printf("\"\n");
|
||||
}
|
||||
}
|
||||
printf(" ;\n");
|
||||
}
|
||||
graph_edges(node->right);
|
||||
}
|
||||
}
|
||||
|
||||
void elide_aliases(node)
|
||||
Node *node;
|
||||
{
|
||||
if (node) {
|
||||
elide_aliases(node->left);
|
||||
if (node->tries >= 0) {
|
||||
Interface *ifc;
|
||||
|
||||
for (ifc = node->u.interfaces; ifc; ifc = ifc->next) {
|
||||
Neighbor *nb;
|
||||
|
||||
for (nb = ifc->neighbors; nb; nb = nb->next) {
|
||||
Node *nb_node = find_node(nb->addr, &routers);
|
||||
|
||||
if (nb_node->tries < 0)
|
||||
nb->addr = nb_node->u.alias->addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
elide_aliases(node->right);
|
||||
}
|
||||
}
|
||||
|
||||
void graph_map()
|
||||
{
|
||||
u_long now = time(0);
|
||||
char *nowstr = ctime(&now);
|
||||
|
||||
nowstr[24] = '\0'; /* Kill the newline at the end */
|
||||
elide_aliases(routers);
|
||||
printf("GRAPH \"Multicast Router Connectivity: %s\" = UNDIRECTED\n",
|
||||
nowstr);
|
||||
graph_edges(routers);
|
||||
printf("END\n");
|
||||
}
|
||||
|
||||
|
||||
int get_number(var, deflt, pargv, pargc)
|
||||
int *var, *pargc, deflt;
|
||||
char ***pargv;
|
||||
{
|
||||
if ((*pargv)[0][2] == '\0') { /* Get the value from the next argument */
|
||||
if (*pargc > 1 && isdigit((*pargv)[1][0])) {
|
||||
(*pargv)++, (*pargc)--;
|
||||
*var = atoi((*pargv)[0]);
|
||||
return 1;
|
||||
} else if (deflt >= 0) {
|
||||
*var = deflt;
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
} else { /* Get value from the rest of this argument */
|
||||
if (isdigit((*pargv)[0][2])) {
|
||||
*var = atoi((*pargv)[0] + 2);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
u_long host_addr(name)
|
||||
char *name;
|
||||
{
|
||||
struct hostent *e = gethostbyname(name);
|
||||
int addr;
|
||||
|
||||
if (e)
|
||||
memcpy(&addr, e->h_addr_list[0], e->h_length);
|
||||
else {
|
||||
addr = inet_addr(name);
|
||||
if (addr == -1)
|
||||
addr = 0;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int flood = FALSE, graph = FALSE;
|
||||
|
||||
#ifdef SYSV
|
||||
setvbuf(stderr, NULL, _IOLBF, 0);
|
||||
#else
|
||||
setlinebuf(stderr);
|
||||
#endif
|
||||
|
||||
if (geteuid() != 0) {
|
||||
fprintf(stderr, "must be root\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
argv++, argc--;
|
||||
while (argc > 0 && argv[0][0] == '-') {
|
||||
switch (argv[0][1]) {
|
||||
case 'd':
|
||||
if (!get_number(&debug, DEFAULT_DEBUG, &argv, &argc))
|
||||
goto usage;
|
||||
break;
|
||||
case 'f':
|
||||
flood = TRUE;
|
||||
break;
|
||||
case 'g':
|
||||
graph = TRUE;
|
||||
break;
|
||||
case 'n':
|
||||
show_names = FALSE;
|
||||
break;
|
||||
case 'r':
|
||||
if (!get_number(&retries, -1, &argv, &argc))
|
||||
goto usage;
|
||||
break;
|
||||
case 't':
|
||||
if (!get_number(&timeout, -1, &argv, &argc))
|
||||
goto usage;
|
||||
break;
|
||||
default:
|
||||
goto usage;
|
||||
}
|
||||
argv++, argc--;
|
||||
}
|
||||
|
||||
if (argc > 1) {
|
||||
usage:
|
||||
fprintf(stderr,
|
||||
"Usage: map-mbone [-f] [-g] [-n] [-t timeout] %s\n\n",
|
||||
"[-r retries] [-d [debug-level]] [router]");
|
||||
fprintf(stderr, "\t-f Flood the routing graph with queries\n");
|
||||
fprintf(stderr, "\t (True by default unless `router' is given)\n");
|
||||
fprintf(stderr, "\t-g Generate output in GraphEd format\n");
|
||||
fprintf(stderr, "\t-n Don't look up DNS names for routers\n");
|
||||
exit(1);
|
||||
} else if (argc == 1 && !(target_addr = host_addr(argv[0]))) {
|
||||
fprintf(stderr, "Unknown host: %s\n", argv[0]);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
if (debug)
|
||||
fprintf(stderr, "Debug level %u\n", debug);
|
||||
|
||||
init_igmp();
|
||||
|
||||
{ /* Find a good local address for us. */
|
||||
int udp;
|
||||
struct sockaddr_in addr;
|
||||
int addrlen = sizeof(addr);
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = dvmrp_group;
|
||||
addr.sin_port = htons(2000); /* any port over 1024 will do... */
|
||||
if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
|
||||
|| connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0
|
||||
|| getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) {
|
||||
perror("Determining local address");
|
||||
exit(-1);
|
||||
}
|
||||
close(udp);
|
||||
our_addr = addr.sin_addr.s_addr;
|
||||
}
|
||||
|
||||
/* Send initial seed message to all local routers */
|
||||
ask(target_addr ? target_addr : allhosts_group);
|
||||
|
||||
if (target_addr) {
|
||||
Node *n = find_node(target_addr, &routers);
|
||||
|
||||
n->tries = 1;
|
||||
|
||||
if (flood)
|
||||
target_addr = 0;
|
||||
}
|
||||
|
||||
/* Main receive loop */
|
||||
for(;;) {
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
int count, recvlen, dummy = 0;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(igmp_socket, &fds);
|
||||
|
||||
tv.tv_sec = timeout;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
count = select(igmp_socket + 1, &fds, 0, 0, &tv);
|
||||
|
||||
if (count < 0) {
|
||||
if (errno != EINTR)
|
||||
perror("select");
|
||||
continue;
|
||||
} else if (count == 0) {
|
||||
log(LOG_DEBUG, 0, "Timed out receiving neighbor lists");
|
||||
if (retry_requests(routers))
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
|
||||
0, NULL, &dummy);
|
||||
if (recvlen >= 0)
|
||||
accept_igmp(recvlen);
|
||||
else if (errno != EINTR)
|
||||
perror("recvfrom");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
if (graph)
|
||||
graph_map();
|
||||
else {
|
||||
if (!target_addr)
|
||||
printf("Multicast Router Connectivity:\n\n");
|
||||
print_map(routers);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void accept_prune()
|
||||
{
|
||||
}
|
||||
void accept_graft()
|
||||
{
|
||||
}
|
||||
void accept_g_ack()
|
||||
{
|
||||
}
|
||||
void add_table_entry()
|
||||
{
|
||||
}
|
||||
void leave_group_message()
|
||||
{
|
||||
}
|
||||
void mtrace()
|
||||
{
|
||||
}
|
480
usr.sbin/mrouted/mrinfo.c
Normal file
480
usr.sbin/mrouted/mrinfo.c
Normal file
@ -0,0 +1,480 @@
|
||||
/*
|
||||
* This tool requests configuration info from a multicast router
|
||||
* and prints the reply (if any). Invoke it as:
|
||||
*
|
||||
* mrinfo router-name-or-address
|
||||
*
|
||||
* Written Wed Mar 24 1993 by Van Jacobson (adapted from the
|
||||
* multicast mapper written by Pavel Curtis).
|
||||
*
|
||||
* The lawyers insist we include the following UC copyright notice.
|
||||
* The mapper from which this is derived contained a Xerox copyright
|
||||
* notice which follows the UC one. Try not to get depressed noting
|
||||
* that the legal gibberish is larger than the program.
|
||||
*
|
||||
* Copyright (c) 1993 Regents of the University of California.
|
||||
* 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. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the Computer Systems
|
||||
* Engineering Group at Lawrence Berkeley Laboratory.
|
||||
* 4. Neither the name of the University nor of the Laboratory may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
|
||||
* ---------------------------------
|
||||
* Copyright (c) Xerox Corporation 1992. All rights reserved.
|
||||
*
|
||||
* License is granted to copy, to use, and to make and to use derivative works
|
||||
* for research and evaluation purposes, provided that Xerox is acknowledged
|
||||
* in all documentation pertaining to any such copy or derivative work. Xerox
|
||||
* grants no other licenses expressed or implied. The Xerox trade name should
|
||||
* not be used in any advertising without its written permission.
|
||||
*
|
||||
* XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
|
||||
* MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE FOR
|
||||
* ANY PARTICULAR PURPOSE. The software is provided "as is" without express
|
||||
* or implied warranty of any kind.
|
||||
*
|
||||
* These notices must be retained in any copies of any part of this software.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char rcsid[] =
|
||||
"@(#) $Id: mrinfo.c,v 1.7 1994/08/24 23:54:04 thyagara Exp $";
|
||||
/* original rcsid:
|
||||
"@(#) Header: mrinfo.c,v 1.6 93/04/08 15:14:16 van Exp (LBL)";
|
||||
*/
|
||||
#endif
|
||||
|
||||
#include <netdb.h>
|
||||
#include <sys/time.h>
|
||||
#include "defs.h"
|
||||
|
||||
#define DEFAULT_TIMEOUT 4 /* How long to wait before retrying requests */
|
||||
#define DEFAULT_RETRIES 3 /* How many times to ask each router */
|
||||
|
||||
u_long our_addr, target_addr = 0; /* in NET order */
|
||||
int debug = 0;
|
||||
int retries = DEFAULT_RETRIES;
|
||||
int timeout = DEFAULT_TIMEOUT;
|
||||
int target_level;
|
||||
vifi_t numvifs; /* to keep loader happy */
|
||||
/* (see COPY_TABLES macro called in kern.c) */
|
||||
|
||||
char *
|
||||
inet_name(addr)
|
||||
u_long addr;
|
||||
{
|
||||
struct hostent *e;
|
||||
|
||||
e = gethostbyaddr(&addr, sizeof(addr), AF_INET);
|
||||
|
||||
return e ? e->h_name : "?";
|
||||
}
|
||||
|
||||
/*
|
||||
* Log errors and other messages 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
|
||||
log(severity, syserr, format, a, b, c, d, e)
|
||||
int severity, syserr;
|
||||
char *format;
|
||||
int a, b, c, d, e;
|
||||
{
|
||||
char fmt[100];
|
||||
|
||||
switch (debug) {
|
||||
case 0:
|
||||
if (severity > LOG_WARNING)
|
||||
return;
|
||||
case 1:
|
||||
if (severity > LOG_NOTICE)
|
||||
return;
|
||||
case 2:
|
||||
if (severity > LOG_INFO)
|
||||
return;
|
||||
default:
|
||||
fmt[0] = '\0';
|
||||
if (severity == LOG_WARNING)
|
||||
strcat(fmt, "warning - ");
|
||||
strncat(fmt, format, 80);
|
||||
fprintf(stderr, fmt, a, b, c, d, e);
|
||||
if (syserr == 0)
|
||||
fprintf(stderr, "\n");
|
||||
else if (syserr < sys_nerr)
|
||||
fprintf(stderr, ": %s\n", sys_errlist[syserr]);
|
||||
else
|
||||
fprintf(stderr, ": errno %d\n", syserr);
|
||||
}
|
||||
|
||||
if (severity <= LOG_ERR)
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a neighbors-list request.
|
||||
*/
|
||||
void
|
||||
ask(dst)
|
||||
u_long dst;
|
||||
{
|
||||
send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS,
|
||||
htonl(MROUTED_LEVEL), 0);
|
||||
}
|
||||
|
||||
void
|
||||
ask2(dst)
|
||||
u_long dst;
|
||||
{
|
||||
send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2,
|
||||
htonl(MROUTED_LEVEL), 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process an incoming neighbor-list message.
|
||||
*/
|
||||
void
|
||||
accept_neighbors(src, dst, p, datalen)
|
||||
u_long src, dst;
|
||||
u_char *p;
|
||||
int datalen;
|
||||
{
|
||||
u_char *ep = p + datalen;
|
||||
#define GET_ADDR(a) (a = ((u_long)*p++ << 24), a += ((u_long)*p++ << 16),\
|
||||
a += ((u_long)*p++ << 8), a += *p++)
|
||||
|
||||
printf("%s (%s):\n", inet_fmt(src, s1), inet_name(src));
|
||||
while (p < ep) {
|
||||
register u_long laddr;
|
||||
register u_char metric;
|
||||
register u_char thresh;
|
||||
register int ncount;
|
||||
|
||||
GET_ADDR(laddr);
|
||||
laddr = htonl(laddr);
|
||||
metric = *p++;
|
||||
thresh = *p++;
|
||||
ncount = *p++;
|
||||
while (--ncount >= 0) {
|
||||
register u_long neighbor;
|
||||
GET_ADDR(neighbor);
|
||||
neighbor = htonl(neighbor);
|
||||
printf(" %s -> ", inet_fmt(laddr, s1));
|
||||
printf("%s (%s) [%d/%d]\n", inet_fmt(neighbor, s1),
|
||||
inet_name(neighbor), metric, thresh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
accept_neighbors2(src, dst, p, datalen)
|
||||
u_long src, dst;
|
||||
u_char *p;
|
||||
int datalen;
|
||||
{
|
||||
u_char *ep = p + datalen;
|
||||
|
||||
printf("%s (%s) [version %d.%d]:\n", inet_fmt(src, s1), inet_name(src),
|
||||
target_level & 0xff, (target_level >> 8) & 0xff);
|
||||
while (p < ep) {
|
||||
register u_char metric;
|
||||
register u_char thresh;
|
||||
register u_char flags;
|
||||
register int ncount;
|
||||
register u_long laddr = *(u_long*)p;
|
||||
|
||||
p += 4;
|
||||
metric = *p++;
|
||||
thresh = *p++;
|
||||
flags = *p++;
|
||||
ncount = *p++;
|
||||
while (--ncount >= 0) {
|
||||
register u_long neighbor = *(u_long*)p;
|
||||
p += 4;
|
||||
printf(" %s -> ", inet_fmt(laddr, s1));
|
||||
printf("%s (%s) [%d/%d", inet_fmt(neighbor, s1),
|
||||
inet_name(neighbor), metric, thresh);
|
||||
if (flags & DVMRP_NF_TUNNEL)
|
||||
printf("/tunnel");
|
||||
if (flags & DVMRP_NF_SRCRT)
|
||||
printf("/srcrt");
|
||||
if (flags & DVMRP_NF_QUERIER)
|
||||
printf("/querier");
|
||||
if (flags & DVMRP_NF_DISABLED)
|
||||
printf("/disabled");
|
||||
if (flags & DVMRP_NF_DOWN)
|
||||
printf("/down");
|
||||
printf("]\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
get_number(var, deflt, pargv, pargc)
|
||||
int *var, *pargc, deflt;
|
||||
char ***pargv;
|
||||
{
|
||||
if ((*pargv)[0][2] == '\0') { /* Get the value from the next
|
||||
* argument */
|
||||
if (*pargc > 1 && isdigit((*pargv)[1][0])) {
|
||||
(*pargv)++, (*pargc)--;
|
||||
*var = atoi((*pargv)[0]);
|
||||
return 1;
|
||||
} else if (deflt >= 0) {
|
||||
*var = deflt;
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
} else { /* Get value from the rest of this argument */
|
||||
if (isdigit((*pargv)[0][2])) {
|
||||
*var = atoi((*pargv)[0] + 2);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u_long
|
||||
host_addr(name)
|
||||
char *name;
|
||||
{
|
||||
struct hostent *e = gethostbyname(name);
|
||||
int addr;
|
||||
|
||||
if (e)
|
||||
memcpy(&addr, e->h_addr_list[0], e->h_length);
|
||||
else {
|
||||
addr = inet_addr(name);
|
||||
if (addr == -1)
|
||||
addr = 0;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
setlinebuf(stderr);
|
||||
|
||||
if (geteuid() != 0) {
|
||||
fprintf(stderr, "must be root\n");
|
||||
exit(1);
|
||||
}
|
||||
argv++, argc--;
|
||||
while (argc > 0 && argv[0][0] == '-') {
|
||||
switch (argv[0][1]) {
|
||||
case 'd':
|
||||
if (!get_number(&debug, DEFAULT_DEBUG, &argv, &argc))
|
||||
goto usage;
|
||||
break;
|
||||
case 'r':
|
||||
if (!get_number(&retries, -1, &argv, &argc))
|
||||
goto usage;
|
||||
break;
|
||||
case 't':
|
||||
if (!get_number(&timeout, -1, &argv, &argc))
|
||||
goto usage;
|
||||
break;
|
||||
default:
|
||||
goto usage;
|
||||
}
|
||||
argv++, argc--;
|
||||
}
|
||||
|
||||
if (argc > 1 || (argc == 1 && !(target_addr = host_addr(argv[0])))) {
|
||||
usage: fprintf(stderr,
|
||||
"Usage: mrinfo [-t timeout] [-r retries] router\n");
|
||||
exit(1);
|
||||
}
|
||||
if (target_addr == 0)
|
||||
goto usage;
|
||||
if (debug)
|
||||
fprintf(stderr, "Debug level %u\n", debug);
|
||||
|
||||
init_igmp();
|
||||
|
||||
{ /* Find a good local address for us. */
|
||||
int udp;
|
||||
struct sockaddr_in addr;
|
||||
int addrlen = sizeof(addr);
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = target_addr;
|
||||
addr.sin_port = htons(2000); /* any port over 1024 will
|
||||
* do... */
|
||||
if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
|
||||
|| connect(udp, (struct sockaddr *) & addr, sizeof(addr)) < 0
|
||||
|| getsockname(udp, (struct sockaddr *) & addr, &addrlen) < 0) {
|
||||
perror("Determining local address");
|
||||
exit(-1);
|
||||
}
|
||||
close(udp);
|
||||
our_addr = addr.sin_addr.s_addr;
|
||||
}
|
||||
|
||||
ask(target_addr);
|
||||
|
||||
/* Main receive loop */
|
||||
for (;;) {
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
int count, recvlen, dummy = 0;
|
||||
register u_long src, dst, group;
|
||||
struct ip *ip;
|
||||
struct igmp *igmp;
|
||||
int ipdatalen, iphdrlen, igmpdatalen;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(igmp_socket, &fds);
|
||||
|
||||
tv.tv_sec = timeout;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
count = select(igmp_socket + 1, &fds, 0, 0, &tv);
|
||||
|
||||
if (count < 0) {
|
||||
if (errno != EINTR)
|
||||
perror("select");
|
||||
continue;
|
||||
} else if (count == 0) {
|
||||
log(LOG_DEBUG, 0, "Timed out receiving neighbor lists");
|
||||
if (--retries < 0)
|
||||
exit(1);
|
||||
if (target_level == 0)
|
||||
ask(target_addr);
|
||||
else
|
||||
ask2(target_addr);
|
||||
continue;
|
||||
}
|
||||
recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
|
||||
0, NULL, &dummy);
|
||||
if (recvlen <= 0) {
|
||||
if (recvlen && errno != EINTR)
|
||||
perror("recvfrom");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (recvlen < sizeof(struct ip)) {
|
||||
log(LOG_WARNING, 0,
|
||||
"packet too short (%u bytes) for IP header",
|
||||
recvlen);
|
||||
continue;
|
||||
}
|
||||
ip = (struct ip *) recv_buf;
|
||||
src = ip->ip_src.s_addr;
|
||||
if (src != target_addr) {
|
||||
fprintf(stderr, "mrinfo: got reply from %s",
|
||||
inet_fmt(src, s1));
|
||||
fprintf(stderr, " instead of %s\n",
|
||||
inet_fmt(target_addr, s1));
|
||||
continue;
|
||||
}
|
||||
dst = ip->ip_dst.s_addr;
|
||||
iphdrlen = ip->ip_hl << 2;
|
||||
ipdatalen = ip->ip_len;
|
||||
if (iphdrlen + ipdatalen != recvlen) {
|
||||
log(LOG_WARNING, 0,
|
||||
"packet shorter (%u bytes) than hdr+data length (%u+%u)",
|
||||
recvlen, iphdrlen, ipdatalen);
|
||||
continue;
|
||||
}
|
||||
igmp = (struct igmp *) (recv_buf + iphdrlen);
|
||||
group = igmp->igmp_group.s_addr;
|
||||
igmpdatalen = ipdatalen - IGMP_MINLEN;
|
||||
if (igmpdatalen < 0) {
|
||||
log(LOG_WARNING, 0,
|
||||
"IP data field too short (%u bytes) for IGMP, from %s",
|
||||
ipdatalen, inet_fmt(src, s1));
|
||||
continue;
|
||||
}
|
||||
if (igmp->igmp_type != IGMP_DVMRP)
|
||||
continue;
|
||||
|
||||
switch (igmp->igmp_code) {
|
||||
|
||||
case DVMRP_NEIGHBORS:
|
||||
if (group) {
|
||||
/* knows about DVMRP_NEIGHBORS2 msg */
|
||||
if (target_level == 0) {
|
||||
target_level = ntohl(group);
|
||||
ask2(target_addr);
|
||||
}
|
||||
} else {
|
||||
accept_neighbors(src, dst, (char *)(igmp + 1),
|
||||
igmpdatalen);
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
|
||||
case DVMRP_NEIGHBORS2:
|
||||
accept_neighbors2(src, dst, (char *)(igmp + 1),
|
||||
igmpdatalen);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* dummies */
|
||||
void accept_probe()
|
||||
{
|
||||
}
|
||||
void accept_group_report()
|
||||
{
|
||||
}
|
||||
void accept_neighbor_request2()
|
||||
{
|
||||
}
|
||||
void accept_report()
|
||||
{
|
||||
}
|
||||
void accept_neighbor_request()
|
||||
{
|
||||
}
|
||||
void accept_prune()
|
||||
{
|
||||
}
|
||||
void accept_graft()
|
||||
{
|
||||
}
|
||||
void accept_g_ack()
|
||||
{
|
||||
}
|
||||
void add_table_entry()
|
||||
{
|
||||
}
|
||||
void check_vif_state()
|
||||
{
|
||||
}
|
||||
void leave_group_message()
|
||||
{
|
||||
}
|
||||
void mtrace()
|
||||
{
|
||||
}
|
319
usr.sbin/mrouted/mrouted.8
Normal file
319
usr.sbin/mrouted/mrouted.8
Normal file
@ -0,0 +1,319 @@
|
||||
'\"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 /etc/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 supports IP source route tunnelling only for backwards
|
||||
compatibility.
|
||||
.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.
|
||||
.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 <local-addr> [disable] [metric <m>]
|
||||
[threshold <t>] [rate_limit <b>]
|
||||
[boundary <scoped-addr>/<mask-len>]
|
||||
|
||||
tunnel <local-addr> <remote-addr> [metric <m>]
|
||||
[threshold <t>] [srcrt] [rate_limit <b>]
|
||||
[boundary <scoped-addr>/<mask-len>]
|
||||
|
||||
cache_lifetime <ct>
|
||||
|
||||
pruning <off/on>
|
||||
|
||||
.fi
|
||||
.PP
|
||||
One note about the configuration commands - all the phyint and tunnel
|
||||
command options must be on a single line except for the boundary option
|
||||
which may begin on a separate line. A single phyint or tunnel command may
|
||||
have multiple boundary options.
|
||||
.PP
|
||||
The phyint command can be used to disable multicast routing on the physical
|
||||
interface identified by local IP address <local-addr>, or to associate a
|
||||
non-default metric or threshold with the specified physical interface.
|
||||
The local IP address <local-addr> may be alternatively replaced by the
|
||||
interface name (e.g le0) for the phyint command only.
|
||||
Phyint commands must precede tunnel commands.
|
||||
.PP
|
||||
The tunnel command can be used to establish a tunnel link between local
|
||||
IP address <local-addr> and remote IP address <remote-addr>, and to associate
|
||||
a non-default metric or threshold with that tunnel. The 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 <off/on> option is provided for
|
||||
.IR mrouted
|
||||
to act as a non-pruning router. It is also possible to start
|
||||
.Ir mrouted
|
||||
in a non-pruning mode using the "-p" option on the command line. It is
|
||||
expected that a router would be configured in this manner for test
|
||||
purposes only. The default mode is pruning enabled.
|
||||
.PP
|
||||
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.
|
||||
.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.
|
||||
.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 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 /usr/tmp/mrouted.dump.
|
||||
.IP USR2
|
||||
dumps the internal cache tables to /usr/tmp/mrouted.cache.
|
||||
.IP QUIT
|
||||
dumps the internal routing tables to stderr (only if
|
||||
.I mrouted
|
||||
was invoked with a non-zero debug level).
|
||||
.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 In-Vif Out-Vifs
|
||||
36.2 1 0 1* 2 3*
|
||||
36.8 36.8.0.77 4 2 0* 1* 3*
|
||||
36.11 1 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 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 (325 entries)
|
||||
Origin-Subnet Mcast-group CTmr IVif Prcv# Psnt Forwvifs
|
||||
134.207.7 224.2.140.239 300 1 0 0 2
|
||||
138.15.103 224.2.203.214 295 1 2 P 0p 2p
|
||||
128.237.0 224.2.253.119 290 1 1 0 2p
|
||||
129.215.200 224.2.207.48 40 1 1 0p 2
|
||||
36.77.14 239.0.1.234 345 2b
|
||||
|
||||
.fi
|
||||
Each entry is characterized by the origin subnet number and the
|
||||
destination multicast group. The 'CTmr' field indicates the lifetime
|
||||
(in seconds) of the entry. The entry is deleted from the cache table
|
||||
when the timer decrements to zero. 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 neighbouring
|
||||
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" in the Psnt field. 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.
|
||||
|
||||
|
||||
.SH FILES
|
||||
/etc/mrouted.conf
|
||||
.SH SEE ALSO
|
||||
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
|
26
usr.sbin/mrouted/mrouted.conf
Normal file
26
usr.sbin/mrouted/mrouted.conf
Normal file
@ -0,0 +1,26 @@
|
||||
# $Id: mrouted.conf,v 1.5 1994/08/24 23:54:21 thyagara Exp $
|
||||
#
|
||||
# This is the configuration file for "mrouted", an IP multicast router.
|
||||
# mrouted looks for it in "/etc/mrouted.conf".
|
||||
#
|
||||
# Command formats:
|
||||
#
|
||||
# cache_lifetime 3600
|
||||
# pruning on
|
||||
#
|
||||
# phyint <local-addr> [disable] [metric <m>] [threshold <t>] [rate_limit <b>]
|
||||
# [boundary <scoped-addr>/<mask-len>]
|
||||
# tunnel <local-addr> <remote-addr> [srcrt] [metric <m>]
|
||||
# [threshold <t>] [rate_limit <b>]
|
||||
# [boundary <scoped-addr>/<mask-len>]
|
||||
#
|
||||
# NOTE: any phyint commands MUST precede any tunnel commands
|
||||
# NOTE: boundary commands may appear on a separate line
|
||||
# (OTHER keywords must be on the same line as phyint or tunnel)
|
||||
# NOTE: the mask-len is the no. of leading 1's in the mask
|
||||
#
|
||||
|
||||
phyint 128.4.2.2 metric 1 threshold 16 boundary 239.2.0.0/16
|
||||
boundary 239.5.8.0/24
|
||||
tunnel 128.4.0.77 128.4.0.8 metric 3 rate_limit 500 # <-- EXAMPLE
|
||||
boundary 239.2.3.3/16 # 239.2.x.x is scoped
|
459
usr.sbin/mrouted/mtrace.c
Normal file
459
usr.sbin/mrouted/mtrace.c
Normal file
@ -0,0 +1,459 @@
|
||||
#include <netdb.h>
|
||||
#include <sys/time.h>
|
||||
#include "defs.h"
|
||||
|
||||
#define DEFAULT_TIMEOUT 10 /* How long to wait before retrying requests */
|
||||
|
||||
int timeout = DEFAULT_TIMEOUT;
|
||||
|
||||
vifi_t numvifs; /* to keep loader happy */
|
||||
/* (see COPY_TABLES macro called in kern.c) */
|
||||
|
||||
|
||||
char *
|
||||
inet_name(addr)
|
||||
u_long addr;
|
||||
{
|
||||
struct hostent *e;
|
||||
|
||||
e = gethostbyaddr(&addr, sizeof(addr), AF_INET);
|
||||
|
||||
return e ? e->h_name : "?";
|
||||
}
|
||||
|
||||
u_long
|
||||
host_addr(name)
|
||||
char *name;
|
||||
{
|
||||
struct hostent *e = gethostbyname(name);
|
||||
int addr;
|
||||
|
||||
if (e)
|
||||
memcpy(&addr, e->h_addr_list[0], e->h_length);
|
||||
else {
|
||||
addr = inet_addr(name);
|
||||
if (addr == -1)
|
||||
addr = 0;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
char *
|
||||
proto_type(type)
|
||||
u_char type;
|
||||
{
|
||||
switch (type) {
|
||||
case PROTO_DVMRP:
|
||||
return ("PROTO_DVMRP");
|
||||
case PROTO_MOSPF:
|
||||
return ("PROTO_MOSPF");
|
||||
case PROTO_PIM:
|
||||
return ("PROTO_PIM");
|
||||
case PROTO_CBT:
|
||||
return ("PROTO_CBT");
|
||||
default:
|
||||
return ("PROTO_UNKNOWN");
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
flag_type(type)
|
||||
u_char type;
|
||||
{
|
||||
switch (type) {
|
||||
case TR_NO_ERR:
|
||||
return ("NO_ERR");
|
||||
case TR_WRONG_IF:
|
||||
return ("WRONG_IF");
|
||||
case TR_PRUNED:
|
||||
return ("PRUNED");
|
||||
case TR_SCOPED:
|
||||
return ("SCOPED");
|
||||
case TR_NO_RTE:
|
||||
return ("NO_RTE");
|
||||
default:
|
||||
return ("INVALID ERR");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
t_diff(a_sec, a_usec, b_sec, b_usec)
|
||||
u_long a_sec, a_usec, b_sec, b_usec;
|
||||
{
|
||||
int d = a_sec - b_sec;
|
||||
int ms = a_usec - b_usec;
|
||||
|
||||
if ((d < 0) ||
|
||||
((d == 0) && (ms < 0))) {
|
||||
d = b_sec - a_sec;
|
||||
ms = b_usec - a_usec;
|
||||
}
|
||||
|
||||
switch (d) {
|
||||
case 0:
|
||||
break;
|
||||
case 2:
|
||||
ms += 1000000;
|
||||
case 1:
|
||||
ms += 1000000;
|
||||
break;
|
||||
default:
|
||||
ms += (1000000) * d;
|
||||
}
|
||||
return (ms/1000);
|
||||
}
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
struct timeval tq;
|
||||
struct timezone tzp;
|
||||
u_long resptime;
|
||||
|
||||
int udp;
|
||||
struct sockaddr_in addr;
|
||||
int addrlen = sizeof(addr);
|
||||
u_long lcl_addr = 0; /* in NET order */
|
||||
|
||||
u_long qid = ((u_long)random() >> 8);
|
||||
u_long qsrc = NULL;
|
||||
u_long qgrp = NULL;
|
||||
u_long qdst = NULL;
|
||||
u_char qno = 0;
|
||||
u_long raddr = NULL;
|
||||
u_char qttl = 1;
|
||||
u_char rttl = 1;
|
||||
u_long dst = NULL;
|
||||
|
||||
struct tr_query *query;
|
||||
|
||||
struct tr_rlist *tr_rlist = NULL;
|
||||
|
||||
char *p;
|
||||
int datalen = 0;
|
||||
|
||||
int i;
|
||||
int done = 0;
|
||||
|
||||
argv++, argc--;
|
||||
|
||||
while (argc > 0 && *argv[0] == '-') {
|
||||
switch (argv[0][1]) {
|
||||
case 's':
|
||||
if (argc > 1 && isdigit(*(argv + 1)[0])) {
|
||||
argv++, argc--;
|
||||
qsrc = host_addr(argv[0]);
|
||||
break;
|
||||
} else
|
||||
goto usage;
|
||||
case 'g':
|
||||
if (argc > 1 && isdigit(*(argv + 1)[0])) {
|
||||
argv++, argc--;
|
||||
qgrp = host_addr(argv[0]);
|
||||
break;
|
||||
} else
|
||||
goto usage;
|
||||
case 'd':
|
||||
if (argc > 1 && isdigit(*(argv + 1)[0])) {
|
||||
argv++, argc--;
|
||||
qdst = host_addr(argv[0]);
|
||||
break;
|
||||
} else
|
||||
goto usage;
|
||||
case 'x':
|
||||
if (argc > 1 && isdigit(*(argv + 1)[0])) {
|
||||
argv++, argc--;
|
||||
dst = host_addr(argv[0]);
|
||||
break;
|
||||
} else
|
||||
goto usage;
|
||||
case 't':
|
||||
if (argc > 1 && isdigit(*(argv + 1)[0])) {
|
||||
argv++, argc--;
|
||||
qttl = atoi(argv[0]);
|
||||
if (qttl < 1)
|
||||
qttl = 1;
|
||||
break;
|
||||
} else
|
||||
goto usage;
|
||||
case 'n':
|
||||
if (argc > 1 && isdigit(*(argv + 1)[0])) {
|
||||
argv++, argc--;
|
||||
qno = atoi(argv[0]);
|
||||
break;
|
||||
} else
|
||||
goto usage;
|
||||
case 'l':
|
||||
if (argc > 1 && isdigit(*(argv + 1)[0])) {
|
||||
argv++, argc--;
|
||||
rttl = atoi(argv[0]);
|
||||
break;
|
||||
} else
|
||||
goto usage;
|
||||
case 'r':
|
||||
if (argc > 1 && isdigit(*(argv + 1)[0])) {
|
||||
argv++, argc--;
|
||||
raddr = host_addr(argv[0]);
|
||||
break;
|
||||
} else
|
||||
goto usage;
|
||||
default:
|
||||
goto usage;
|
||||
}
|
||||
argv++, argc--;
|
||||
}
|
||||
|
||||
if (argc > 0) {
|
||||
usage: printf("usage: mtrace -s <src> -g <grp> -d <dst> -n <# reports> \n");
|
||||
printf(" -t <ttl> [-x <qdst>] [-r <rdst>] [-l <rttl>]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Mtrace src %s grp %s dst %s #%d\n", inet_fmt(qsrc, s1),
|
||||
inet_fmt(qgrp, s2), inet_fmt(qdst, s3), qno);
|
||||
printf(" resp ttl %d resp addr %s\n", rttl, inet_fmt(raddr, s1));
|
||||
|
||||
init_igmp();
|
||||
|
||||
/* Obtain the local address from which to send out packets */
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = qgrp;
|
||||
addr.sin_port = htons(2000);
|
||||
|
||||
if (((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0) ||
|
||||
(connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0) ||
|
||||
getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) {
|
||||
perror("Determining local address");
|
||||
exit(-1);
|
||||
}
|
||||
close(udp);
|
||||
lcl_addr = addr.sin_addr.s_addr;
|
||||
|
||||
/* Got the local address now */
|
||||
/* Now, make up the IGMP packet to send */
|
||||
|
||||
query = (struct tr_query *)(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
|
||||
|
||||
query->tr_src = qsrc;
|
||||
query->tr_dst = qdst;
|
||||
query->tr_qid = qid;
|
||||
if (raddr)
|
||||
query->tr_raddr = raddr;
|
||||
else
|
||||
query->tr_raddr = lcl_addr;
|
||||
query->tr_rttl = rttl;
|
||||
|
||||
datalen += sizeof(struct tr_query);
|
||||
|
||||
if (IN_MULTICAST(ntohl(qgrp)))
|
||||
k_set_ttl(qttl);
|
||||
else
|
||||
k_set_ttl(1);
|
||||
|
||||
if (dst == NULL)
|
||||
dst = qgrp;
|
||||
|
||||
/*
|
||||
* set timer to calculate delays & send query
|
||||
*/
|
||||
gettimeofday(&tq, &tzp);
|
||||
|
||||
send_igmp(lcl_addr, dst, IGMP_MTRACE, qno,
|
||||
qgrp, datalen);
|
||||
|
||||
/*
|
||||
* If the response is to be a multicast address, make sure we
|
||||
* are listening on that multicast address.
|
||||
*/
|
||||
if (IN_MULTICAST(ntohl(raddr)))
|
||||
k_join(raddr, lcl_addr);
|
||||
|
||||
/* Wait for our reply now */
|
||||
while (!done) {
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
struct timezone tzp;
|
||||
|
||||
int count, recvlen, dummy = 0;
|
||||
register u_long src, dst, group, smask;
|
||||
struct ip *ip;
|
||||
struct igmp *igmp;
|
||||
struct tr_resp *resp;
|
||||
int ipdatalen, iphdrlen, igmpdatalen;
|
||||
int rno;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(igmp_socket, &fds);
|
||||
|
||||
/* need to input timeout as optional argument */
|
||||
tv.tv_sec = timeout;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
count = select(igmp_socket + 1, &fds, 0, 0, &tv);
|
||||
|
||||
if (count < 0) {
|
||||
if (errno != EINTR)
|
||||
perror("select");
|
||||
continue;
|
||||
} else if (count == 0) {
|
||||
printf("Timed out receiving responses\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
|
||||
0, NULL, &dummy);
|
||||
|
||||
if (recvlen <= 0) {
|
||||
if (recvlen && errno != EINTR)
|
||||
perror("recvfrom");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (recvlen < sizeof(struct ip)) {
|
||||
log(LOG_WARNING, 0,
|
||||
"packet too short (%u bytes) for IP header",
|
||||
recvlen);
|
||||
continue;
|
||||
}
|
||||
ip = (struct ip *) recv_buf;
|
||||
|
||||
iphdrlen = ip->ip_hl << 2;
|
||||
ipdatalen = ip->ip_len;
|
||||
if (iphdrlen + ipdatalen != recvlen) {
|
||||
printf("packet shorter (%u bytes) than hdr+data length (%u+%u)\n",
|
||||
recvlen, iphdrlen, ipdatalen);
|
||||
continue;
|
||||
}
|
||||
|
||||
igmp = (struct igmp *) (recv_buf + iphdrlen);
|
||||
group = igmp->igmp_group.s_addr;
|
||||
igmpdatalen = ipdatalen - IGMP_MINLEN;
|
||||
if (igmpdatalen < 0) {
|
||||
printf("IP data field too short (%u bytes) for IGMP, from %s\n",
|
||||
ipdatalen, inet_fmt(src, s1));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (igmp->igmp_type != IGMP_MTRACE &&
|
||||
igmp->igmp_type != IGMP_MTRACE_RESP)
|
||||
continue;
|
||||
|
||||
if (igmpdatalen == QLEN)
|
||||
continue;
|
||||
|
||||
if ((igmpdatalen - QLEN)%RLEN) {
|
||||
printf("packet with incorrect datalen\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
query = (struct tr_query *)(igmp + 1);
|
||||
|
||||
/* If this is query with a different id, ignore! */
|
||||
if (query->tr_qid != qid)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Most of the sanity checking done at this point.
|
||||
* This is the packet we have been waiting for all this time
|
||||
*/
|
||||
resp = (struct tr_resp *)(query + 1);
|
||||
|
||||
rno = (igmpdatalen - QLEN)/RLEN;
|
||||
|
||||
/*
|
||||
* print the responses out in reverse order (from src to dst)
|
||||
*/
|
||||
printf("src: <%s> grp: <%s> dst: <%s>\n\n", inet_fmt(qsrc, s1),
|
||||
inet_fmt(qgrp, s2), inet_fmt(qdst, s3));
|
||||
|
||||
VAL_TO_MASK(smask, (resp+rno-1)->tr_smask);
|
||||
|
||||
if (((resp+rno-1)->tr_inaddr & smask) == (qsrc & smask))
|
||||
printf(" %-15s \n", inet_fmt(qsrc, s1));
|
||||
else
|
||||
printf(" * * *\n");
|
||||
|
||||
resptime = 0;
|
||||
while (rno--) {
|
||||
struct tr_resp *r = resp + rno;
|
||||
|
||||
printf(" | \n");
|
||||
printf(" %-15s ", inet_fmt(r->tr_inaddr, s1));
|
||||
printf("ttl %d ", r->tr_fttl);
|
||||
printf("cum: %d ms ",
|
||||
t_diff(r->tr_qarr >> 16, (r->tr_qarr & 0xffff) << 4,
|
||||
tq.tv_sec & 0xffff, tq.tv_usec));
|
||||
printf("hop: %d ms ",
|
||||
t_diff(resptime >> 16, (resptime & 0xffff) << 4,
|
||||
r->tr_qarr >> 16, (r->tr_qarr & 0xffff) << 4));
|
||||
printf("%s ", proto_type(r->tr_rproto));
|
||||
printf("%s\n", flag_type(r->tr_rflags));
|
||||
|
||||
printf(" %-15s ", inet_fmt(r->tr_outaddr, s1));
|
||||
printf("v_in: %ld ", r->tr_vifin);
|
||||
printf("v_out: %ld ", r->tr_vifout);
|
||||
printf("pkts: %ld\n", r->tr_pktcnt);
|
||||
|
||||
resptime = r->tr_qarr;
|
||||
}
|
||||
printf(" | \n");
|
||||
printf(" %-15s \n", inet_fmt(qdst, s1));
|
||||
|
||||
/*
|
||||
* if the response was multicast back, leave the group
|
||||
*/
|
||||
if (IN_MULTICAST(ntohl(raddr)))
|
||||
k_leave(raddr, lcl_addr);
|
||||
|
||||
/* If I don't expect any more replies, exit here */
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
/* dummies */
|
||||
void log()
|
||||
{
|
||||
}
|
||||
void accept_probe()
|
||||
{
|
||||
}
|
||||
void accept_group_report()
|
||||
{
|
||||
}
|
||||
void accept_neighbors()
|
||||
{
|
||||
}
|
||||
void accept_neighbors2()
|
||||
{
|
||||
}
|
||||
void accept_neighbor_request2()
|
||||
{
|
||||
}
|
||||
void accept_report()
|
||||
{
|
||||
}
|
||||
void accept_neighbor_request()
|
||||
{
|
||||
}
|
||||
void accept_prune()
|
||||
{
|
||||
}
|
||||
void accept_graft()
|
||||
{
|
||||
}
|
||||
void accept_g_ack()
|
||||
{
|
||||
}
|
||||
void add_table_entry()
|
||||
{
|
||||
}
|
||||
void check_vif_state()
|
||||
{
|
||||
}
|
||||
void mtrace()
|
||||
{
|
||||
}
|
||||
void leave_group_message()
|
||||
{
|
||||
}
|
1370
usr.sbin/mrouted/prune.c
Normal file
1370
usr.sbin/mrouted/prune.c
Normal file
File diff suppressed because it is too large
Load Diff
123
usr.sbin/mrouted/prune.h
Normal file
123
usr.sbin/mrouted/prune.h
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* $Id: prune.h,v 1.3 1994/08/24 23:54:40 thyagara Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* Macro for copying the user-level cache table to the kernel
|
||||
* level table variable passed on by the setsock option
|
||||
*/
|
||||
|
||||
#define COPY_TABLES(from, to) { \
|
||||
register u_int _i; \
|
||||
(to).mfcc_origin.s_addr = (from)->kt_origin; \
|
||||
(to).mfcc_mcastgrp.s_addr = (from)->kt_mcastgrp; \
|
||||
(to).mfcc_originmask.s_addr = (from)->kt_originmask; \
|
||||
(to).mfcc_parent = (from)->kt_parent; \
|
||||
for (_i = 0; _i < numvifs; _i++) \
|
||||
(to).mfcc_ttls[_i] = (from)->kt_ttls[_i]; \
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* User level Kernel Cache Table structure
|
||||
*
|
||||
* A copy of the kernel table is kept at the user level. Modifications are
|
||||
* made to this table and then passed on to the kernel. A timeout value is
|
||||
* an extra field in the user level table.
|
||||
*
|
||||
*/
|
||||
struct ktable
|
||||
{
|
||||
struct ktable *kt_next; /* pointer to the next entry */
|
||||
u_long kt_origin; /* subnet origin of multicasts */
|
||||
u_long kt_mcastgrp; /* multicast group associated */
|
||||
u_long kt_originmask; /* subnet mask for origin */
|
||||
vifi_t kt_parent; /* incoming vif */
|
||||
u_long kt_gateway; /* upstream router */
|
||||
vifbitmap_t kt_children; /* outgoing children vifs */
|
||||
vifbitmap_t kt_leaves; /* subset of outgoing children vifs */
|
||||
vifbitmap_t kt_scope; /* scoped interfaces */
|
||||
u_char kt_ttls[MAXVIFS]; /* ttl vector for forwarding */
|
||||
vifbitmap_t kt_grpmems; /* forw. vifs for src, grp */
|
||||
int kt_timer; /* for timing out entry in cache */
|
||||
struct prunlst *kt_rlist; /* router list nghboring this rter */
|
||||
u_short kt_prun_count; /* count of total no. of prunes */
|
||||
int kt_prsent_timer; /* prune lifetime timer */
|
||||
u_int kt_grftsnt; /* graft sent upstream */
|
||||
};
|
||||
|
||||
/*
|
||||
* structure to store incoming prunes
|
||||
*/
|
||||
struct prunlst
|
||||
{
|
||||
struct prunlst *rl_next;
|
||||
u_long rl_router;
|
||||
u_long rl_router_subnet;
|
||||
vifi_t rl_vifi;
|
||||
int rl_timer;
|
||||
};
|
||||
|
||||
struct tr_query {
|
||||
u_long tr_src; /* traceroute source */
|
||||
u_long tr_dst; /* traceroute destination */
|
||||
u_long tr_raddr; /* traceroute response address */
|
||||
struct {
|
||||
u_int ttl : 8; /* traceroute response ttl */
|
||||
u_int qid : 24; /* traceroute query id */
|
||||
} q;
|
||||
} tr_query;
|
||||
|
||||
#define tr_rttl q.ttl
|
||||
#define tr_qid q.qid
|
||||
|
||||
struct tr_resp {
|
||||
u_long tr_qarr; /* query arrival time */
|
||||
u_long tr_inaddr; /* incoming interface address */
|
||||
u_long tr_outaddr; /* outgoing interface address */
|
||||
u_long tr_rmtaddr; /* parent address in source tree */
|
||||
u_long tr_vifin; /* input packet count on interface */
|
||||
u_long tr_vifout; /* output packet count on interface */
|
||||
u_long 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 */
|
||||
} tr_resp;
|
||||
|
||||
/* 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 0x0
|
||||
#define TR_WRONG_IF 0x1
|
||||
#define TR_PRUNED 0x2
|
||||
#define TR_SCOPED 0x4
|
||||
#define TR_NO_RTE 0x5
|
||||
|
||||
/* fields for tr_rproto (routing protocol) */
|
||||
#define PROTO_DVMRP 0x1
|
||||
#define PROTO_MOSPF 0x2
|
||||
#define PROTO_PIM 0x3
|
||||
#define PROTO_CBT 0x4
|
||||
|
||||
#define MASK_TO_VAL(x, i) { \
|
||||
(i) = 0; \
|
||||
while ((x) << (i)) \
|
||||
(i)++; \
|
||||
}
|
||||
|
||||
#define VAL_TO_MASK(x, i) { \
|
||||
x = ~((1 << (32 - (i))) - 1); \
|
||||
}
|
1076
usr.sbin/mrouted/route.c
Normal file
1076
usr.sbin/mrouted/route.c
Normal file
File diff suppressed because it is too large
Load Diff
50
usr.sbin/mrouted/route.h
Normal file
50
usr.sbin/mrouted/route.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* $Id: route.h,v 1.3 1993/05/30 01:36:38 deering Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 singly-linked list of these structures,
|
||||
* ordered by increasing value of rt_originmask and, secondarily, by
|
||||
* increasing 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_long rt_origin; /* subnet origin of multicasts */
|
||||
u_long 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_long 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_long *rt_dominants; /* per vif dominant gateways */
|
||||
u_long *rt_subordinates; /* per vif subordinate gateways */
|
||||
u_long *rt_leaf_timers; /* per vif leaf confirmation timers */
|
||||
u_long rt_timer; /* for timing out the route entry */
|
||||
};
|
||||
|
||||
#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() */
|
1136
usr.sbin/mrouted/vif.c
Normal file
1136
usr.sbin/mrouted/vif.c
Normal file
File diff suppressed because it is too large
Load Diff
62
usr.sbin/mrouted/vif.h
Normal file
62
usr.sbin/mrouted/vif.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* $Id: vif.h,v 1.6 1994/08/24 23:54:47 thyagara Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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_long uv_lcl_addr; /* local address of this vif */
|
||||
u_long uv_rmt_addr; /* remote end-point addr (tunnels only) */
|
||||
u_long uv_subnet; /* subnet number (phyints only) */
|
||||
u_long uv_subnetmask; /* subnet mask (phyints only) */
|
||||
u_long 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 */
|
||||
};
|
||||
|
||||
#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 */
|
||||
|
||||
struct vif_acl {
|
||||
struct vif_acl *acl_next; /* next acl member */
|
||||
u_long acl_addr; /* Group address */
|
||||
u_long acl_mask; /* Group addr. mask */
|
||||
};
|
||||
|
||||
struct listaddr {
|
||||
struct listaddr *al_next; /* link to next addr, MUST BE FIRST */
|
||||
u_long al_addr; /* local group or neighbor address */
|
||||
u_long al_timer; /* for timing out group or neighbor */
|
||||
u_long 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; /* if old memberships are present */
|
||||
u_short al_last; /* # of query's since last old rep */
|
||||
};
|
||||
|
||||
|
||||
#define NO_VIF ((vifi_t)MAXVIFS) /* An invalid vif index */
|
Loading…
Reference in New Issue
Block a user