aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcvs2svn <cvs2svn@FreeBSD.org>1995-06-13 18:05:18 +0000
committercvs2svn <cvs2svn@FreeBSD.org>1995-06-13 18:05:18 +0000
commited30da51aa6c648930983a5e2dc31760eda8e16a (patch)
tree989d74468ea768bfc8cc4b6fc42fcd3d9053c6f7
parent15fe6b871201106b32216eee33c871d4d5684e1c (diff)
downloadsrc-ed30da51aa6c648930983a5e2dc31760eda8e16a.tar.gz
src-ed30da51aa6c648930983a5e2dc31760eda8e16a.zip
This commit was manufactured by cvs2svn to create branch 'XEROX'.
Notes
Notes: svn path=/cvs2svn/branches/XEROX/; revision=9212
-rw-r--r--usr.sbin/mrouted/cfparse.y511
-rw-r--r--usr.sbin/mrouted/map-mbone.897
-rw-r--r--usr.sbin/mrouted/mrinfo.892
-rw-r--r--usr.sbin/mrouted/mtrace.8499
-rw-r--r--usr.sbin/mrouted/pathnames.h25
-rw-r--r--usr.sbin/mrouted/rsrr.c498
-rw-r--r--usr.sbin/mrouted/rsrr.h138
-rw-r--r--usr.sbin/mrouted/rsrr_var.h41
8 files changed, 1901 insertions, 0 deletions
diff --git a/usr.sbin/mrouted/cfparse.y b/usr.sbin/mrouted/cfparse.y
new file mode 100644
index 000000000000..5c1402f41bdc
--- /dev/null
+++ b/usr.sbin/mrouted/cfparse.y
@@ -0,0 +1,511 @@
+%{
+/*
+ * Configuration file parser for mrouted.
+ *
+ * Written by Bill Fenner, NRL, 1994
+ *
+ * $Id: cfparse.y,v 3.5 1995/05/09 01:00:39 fenner Exp $
+ */
+#include <stdio.h>
+#include <varargs.h>
+#include "defs.h"
+
+static FILE *f;
+
+extern int udp_socket;
+char *configfilename = _PATH_MROUTED_CONF;
+
+extern int cache_lifetime;
+extern int max_prune_lifetime;
+
+static int lineno;
+static struct ifreq ifbuf[32];
+static struct ifconf ifc;
+
+static struct uvif *v;
+
+static int order;
+
+struct addrmask {
+ u_int32 addr;
+ int mask;
+};
+
+struct boundnam {
+ char *name;
+ struct addrmask bound;
+};
+
+#define MAXBOUNDS 20
+
+struct boundnam boundlist[MAXBOUNDS]; /* Max. of 20 named boundaries */
+int numbounds = 0; /* Number of named boundaries */
+
+%}
+
+%union
+{
+ int num;
+ char *ptr;
+ struct addrmask addrmask;
+ u_int32 addr;
+};
+
+%token CACHE_LIFETIME PRUNING
+%token PHYINT TUNNEL NAME
+%token DISABLE METRIC THRESHOLD RATE_LIMIT SRCRT BOUNDARY NETMASK ALTNET
+%token <num> BOOLEAN
+%token <num> NUMBER
+%token <ptr> STRING
+%token <addrmask> ADDRMASK
+%token <addr> ADDR
+
+%type <addr> interface
+%type <addrmask> bound boundary addrmask
+
+%start conf
+
+%%
+
+conf : stmts
+ ;
+
+stmts : /* Empty */
+ | stmts stmt
+ ;
+
+stmt : error
+ | PHYINT interface {
+
+ vifi_t vifi;
+
+ if (order)
+ fatal("phyints must appear before tunnels");
+
+ for (vifi = 0, v = uvifs;
+ vifi < numvifs;
+ ++vifi, ++v)
+ if (!(v->uv_flags & VIFF_TUNNEL) &&
+ $2 == v->uv_lcl_addr)
+ break;
+
+ if (vifi == numvifs)
+ fatal("%s is not a configured interface",
+ inet_fmt($2,s1));
+
+ /*log(LOG_INFO, 0, "phyint: %x\n", v);*/
+ }
+ ifmods
+ | TUNNEL interface ADDR {
+
+ struct ifreq *ifr;
+ struct ifreq ffr;
+ vifi_t vifi;
+
+ order++;
+
+ ifr = ifconfaddr(&ifc, $2);
+ if (ifr == 0)
+ fatal("Tunnel local address %s is not mine",
+ inet_fmt($2, s1));
+
+ strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ);
+ if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr)<0)
+ fatal("ioctl SIOCGIFFLAGS on %s",ffr.ifr_name);
+ if (ffr.ifr_flags & IFF_LOOPBACK)
+ fatal("Tunnel local address %s is a loopback interface",
+ inet_fmt($2, s1));
+
+ if (ifconfaddr(&ifc, $3) != 0)
+ fatal("Tunnel remote address %s is one of mine",
+ inet_fmt($3, s1));
+
+ for (vifi = 0, v = uvifs;
+ vifi < numvifs;
+ ++vifi, ++v)
+ if (v->uv_flags & VIFF_TUNNEL) {
+ if ($3 == v->uv_rmt_addr)
+ fatal("Duplicate tunnel to %s",
+ inet_fmt($3, s1));
+ } else if (!(v->uv_flags & VIFF_DISABLED)) {
+ if (($3 & v->uv_subnetmask) == v->uv_subnet)
+ fatal("Unnecessary tunnel to %s",
+ inet_fmt($3,s1));
+ }
+
+ if (numvifs == MAXVIFS)
+ fatal("too many vifs");
+
+ v = &uvifs[numvifs];
+ v->uv_flags = VIFF_TUNNEL;
+ v->uv_metric = DEFAULT_METRIC;
+ v->uv_rate_limit= DEFAULT_TUN_RATE_LIMIT;
+ v->uv_threshold = DEFAULT_THRESHOLD;
+ v->uv_lcl_addr = $2;
+ v->uv_rmt_addr = $3;
+ v->uv_subnet = 0;
+ v->uv_subnetmask= 0;
+ v->uv_subnetbcast= 0;
+ strncpy(v->uv_name, ffr.ifr_name, IFNAMSIZ);
+ v->uv_groups = NULL;
+ v->uv_neighbors = NULL;
+ v->uv_acl = NULL;
+ v->uv_addrs = NULL;
+
+ if (!(ffr.ifr_flags & IFF_UP)) {
+ v->uv_flags |= VIFF_DOWN;
+ vifs_down = TRUE;
+ }
+ /*log(LOG_INFO, 0, "tunnel: %x\n", v);*/
+ }
+ tunnelmods
+ {
+ log(LOG_INFO, 0,
+ "installing tunnel from %s to %s as vif #%u - rate=%d",
+ inet_fmt($2, s1), inet_fmt($3, s2),
+ numvifs, v->uv_rate_limit);
+
+ ++numvifs;
+ }
+ | PRUNING BOOLEAN { pruning = $2; }
+ | CACHE_LIFETIME NUMBER { cache_lifetime = $2;
+ max_prune_lifetime = cache_lifetime * 2;
+ }
+ | NAME STRING boundary { if (numbounds >= MAXBOUNDS) {
+ fatal("Too many named boundaries (max %d)", MAXBOUNDS);
+ }
+
+ boundlist[numbounds].name = malloc(strlen($2) + 1);
+ strcpy(boundlist[numbounds].name, $2);
+ boundlist[numbounds++].bound = $3;
+ }
+ ;
+
+tunnelmods : /* empty */
+ | tunnelmods /*{ log(LOG_INFO, 0, "tunnelmod: %x", v); }*/ tunnelmod
+ ;
+
+tunnelmod : mod
+ | SRCRT { fatal("Source-route tunnels not supported"); }
+ ;
+
+ifmods : /* empty */
+ | ifmods /*{ log(LOG_INFO, 0, "ifmod: %x", v); }*/ ifmod
+ ;
+
+ifmod : mod
+ | DISABLE { v->uv_flags |= VIFF_DISABLED; }
+ | NETMASK ADDR { v->uv_subnetmask = $2; }
+ | ALTNET addrmask {
+
+ struct phaddr *ph;
+
+ ph = (struct phaddr *)malloc(sizeof(struct phaddr));
+ if (ph == NULL)
+ fatal("out of memory");
+ if ($2.mask) {
+ VAL_TO_MASK(ph->pa_mask, $2.mask);
+ } else
+ ph->pa_mask = v->uv_subnetmask;
+ ph->pa_addr = $2.addr & ph->pa_mask;
+ if ($2.addr & ~ph->pa_mask)
+ warn("Extra addr %s/%d has host bits set",
+ inet_fmt($2.addr,s1), $2.mask);
+ ph->pa_next = v->uv_addrs;
+ v->uv_addrs = ph;
+
+ }
+ ;
+
+mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255)
+ fatal("Invalid threshold %d",$2);
+ v->uv_threshold = $2;
+ }
+ | THRESHOLD {
+
+ warn("Expected number after threshold keyword");
+
+ }
+ | METRIC NUMBER { if ($2 < 1 || $2 > UNREACHABLE)
+ fatal("Invalid metric %d",$2);
+ v->uv_metric = $2;
+ }
+ | METRIC {
+
+ warn("Expected number after metric keyword");
+
+ }
+ | RATE_LIMIT NUMBER { if ($2 > MAX_RATE_LIMIT)
+ fatal("Invalid rate_limit %d",$2);
+ v->uv_rate_limit = $2;
+ }
+ | RATE_LIMIT {
+
+ warn("Expected number after rate_limit keyword");
+
+ }
+ | BOUNDARY bound {
+
+ struct vif_acl *v_acl;
+
+ v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
+ if (v_acl == NULL)
+ fatal("out of memory");
+ VAL_TO_MASK(v_acl->acl_mask, $2.mask);
+ v_acl->acl_addr = $2.addr & v_acl->acl_mask;
+ if ($2.addr & ~v_acl->acl_mask)
+ warn("Boundary spec %s/%d has host bits set",
+ inet_fmt($2.addr,s1),$2.mask);
+ v_acl->acl_next = v->uv_acl;
+ v->uv_acl = v_acl;
+
+ }
+ | BOUNDARY {
+
+ warn("Expected boundary spec after boundary keyword");
+
+ }
+ ;
+
+interface : ADDR { $$ = $1; }
+ | STRING {
+ $$ = valid_if($1);
+ if ($$ == 0)
+ fatal("Invalid interface name %s",$1);
+ }
+ ;
+
+bound : boundary { $$ = $1; }
+ | STRING { int i;
+
+ for (i=0; i < numbounds; i++) {
+ if (!strcmp(boundlist[i].name, $1)) {
+ $$ = boundlist[i].bound;
+ break;
+ }
+ }
+ if (i == numbounds) {
+ fatal("Invalid boundary name %s",$1);
+ }
+ }
+ ;
+
+boundary : ADDRMASK {
+
+ if ((ntohl($1.addr) & 0xff000000) != 0xef000000) {
+ fatal("Boundaries must be 239.x.x.x, not %s/%d",
+ inet_fmt($1.addr, s1), $1.mask);
+ }
+ $$ = $1;
+
+ }
+ ;
+
+addrmask : ADDRMASK { $$ = $1; }
+ | ADDR { $$.addr = $1; $$.mask = 0; }
+ ;
+%%
+/*VARARGS1*/
+static void fatal(fmt, va_alist)
+char *fmt;
+va_dcl
+{
+ va_list ap;
+ char buf[200];
+
+ va_start(ap);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ log(LOG_ERR,0,"%s: %s near line %d", configfilename, buf, lineno);
+}
+
+/*VARARGS1*/
+static void warn(fmt, va_alist)
+char *fmt;
+va_dcl
+{
+ va_list ap;
+ char buf[200];
+
+ va_start(ap);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ log(LOG_WARNING,0,"%s: %s near line %d", configfilename, buf, lineno);
+}
+
+void yyerror(s)
+char *s;
+{
+ log(LOG_ERR, 0, "%s: %s near line %d", configfilename, s, lineno);
+}
+
+char *next_word()
+{
+ static char buf[1024];
+ static char *p=NULL;
+ extern FILE *f;
+ char *q;
+
+ while (1) {
+ if (!p || !*p) {
+ lineno++;
+ if (fgets(buf, sizeof(buf), f) == NULL)
+ return NULL;
+ p = buf;
+ }
+ while (*p && (*p == ' ' || *p == '\t')) /* skip whitespace */
+ p++;
+ if (*p == '#') {
+ p = NULL; /* skip comments */
+ continue;
+ }
+ q = p;
+ while (*p && *p != ' ' && *p != '\t' && *p != '\n')
+ p++; /* find next whitespace */
+ *p++ = '\0'; /* null-terminate string */
+
+ if (!*q) {
+ p = NULL;
+ continue; /* if 0-length string, read another line */
+ }
+
+ return q;
+ }
+}
+
+int yylex()
+{
+ int n;
+ u_int32 addr;
+ char *q;
+
+ if ((q = next_word()) == NULL) {
+ return 0;
+ }
+
+ if (!strcmp(q,"cache_lifetime"))
+ return CACHE_LIFETIME;
+ if (!strcmp(q,"pruning"))
+ return PRUNING;
+ if (!strcmp(q,"phyint"))
+ return PHYINT;
+ if (!strcmp(q,"tunnel"))
+ return TUNNEL;
+ if (!strcmp(q,"disable"))
+ return DISABLE;
+ if (!strcmp(q,"metric"))
+ return METRIC;
+ if (!strcmp(q,"threshold"))
+ return THRESHOLD;
+ if (!strcmp(q,"rate_limit"))
+ return RATE_LIMIT;
+ if (!strcmp(q,"srcrt") || !strcmp(q,"sourceroute"))
+ return SRCRT;
+ if (!strcmp(q,"boundary"))
+ return BOUNDARY;
+ if (!strcmp(q,"netmask"))
+ return NETMASK;
+ if (!strcmp(q,"name"))
+ return NAME;
+ if (!strcmp(q,"altnet"))
+ return ALTNET;
+ if (!strcmp(q,"on") || !strcmp(q,"yes")) {
+ yylval.num = 1;
+ return BOOLEAN;
+ }
+ if (!strcmp(q,"off") || !strcmp(q,"no")) {
+ yylval.num = 0;
+ return BOOLEAN;
+ }
+ if (sscanf(q,"%[.0-9]/%d%c",s1,&n,s2) == 2) {
+ if ((addr = inet_parse(s1)) != 0xffffffff) {
+ yylval.addrmask.mask = n;
+ yylval.addrmask.addr = addr;
+ return ADDRMASK;
+ }
+ /* fall through to returning STRING */
+ }
+ if (sscanf(q,"%[.0-9]%c",s1,s2) == 1) {
+ if ((addr = inet_parse(s1)) != 0xffffffff &&
+ inet_valid_host(addr)) {
+ yylval.addr = addr;
+ return ADDR;
+ }
+ }
+ if (sscanf(q,"0x%8x%c",&n,s1) == 1) {
+ yylval.addr = n;
+ return ADDR;
+ }
+ if (sscanf(q,"%d%c",&n,s1) == 1) {
+ yylval.num = n;
+ return NUMBER;
+ }
+ yylval.ptr = q;
+ return STRING;
+}
+
+void config_vifs_from_file()
+{
+ extern FILE *f;
+
+ order = 0;
+ numbounds = 0;
+ lineno = 0;
+
+ if ((f = fopen(configfilename, "r")) == NULL) {
+ if (errno != ENOENT)
+ 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");
+
+ yyparse();
+
+ close(f);
+}
+
+static u_int32
+valid_if(s)
+char *s;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+
+ for (vifi=0, v=uvifs; vifi<numvifs; vifi++, v++)
+ if (!strcmp(v->uv_name, s))
+ return v->uv_lcl_addr;
+
+ return 0;
+}
+
+static struct ifreq *
+ifconfaddr(ifcp, a)
+ struct ifconf *ifcp;
+ u_int32 a;
+{
+ int n;
+ struct ifreq *ifrp = (struct ifreq *)ifcp->ifc_buf;
+ struct ifreq *ifend = (struct ifreq *)((char *)ifrp + ifcp->ifc_len);
+
+ while (ifrp < ifend) {
+ if (ifrp->ifr_addr.sa_family == AF_INET &&
+ ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr == a)
+ return (ifrp);
+#if (defined(BSD) && (BSD >= 199006))
+ n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
+ if (n < sizeof(*ifrp))
+ ++ifrp;
+ else
+ ifrp = (struct ifreq *)((char *)ifrp + n);
+#else
+ ++ifrp;
+#endif
+ }
+ return (0);
+}
diff --git a/usr.sbin/mrouted/map-mbone.8 b/usr.sbin/mrouted/map-mbone.8
new file mode 100644
index 000000000000..41eb8088206c
--- /dev/null
+++ b/usr.sbin/mrouted/map-mbone.8
@@ -0,0 +1,97 @@
+.Dd March 31, 1995
+.Dt MAP-MBONE 8
+.Os FreeBSD 2.0
+.Sh NAME
+.Nm map-mbone
+.Nd multicast connection mapper
+.Sh SYNOPSIS
+.Nm map-mbone
+.Op Fl d Ar debuglevel
+.Op Fl f
+.Op Fl g
+.Op Fl n
+.Op Fl r Ar retries
+.Op Fl t Ar timeout
+.Op Ar router
+.Sh DESCRIPTION
+.Nm map-mbone
+attempts to display all multicast routers that are reachable from the multicast
+router
+.Ar router .
+If not specified on the command line, the default
+.Ar router
+is the local host.
+.Nm
+traverses neighboring multicast routers by sending the
+.Dv ASK_NEIGHBORS
+.Tn IGMP
+message to each router. If this multicast router responds, the version
+number and a list of their neighboring multicast router addresses is
+part of that response. If the responding router has recent multicast
+version number, then
+.Nm
+requests additional information such as metrics, thresholds, and flags from the
+multicast router. For each new occurrence of neighboring multicast router in
+the reply and provided the flooding option has been selected, then
+.Nm
+asks each of this multicast router for a list of neighbors. This search
+for unique routers will continue until no new neighboring multicast routers
+are reported.
+.Pp
+The options supported by
+.Nm
+are as follows:
+.Bl -tag -width XXXdebuglevel
+.It Fl d Ar debuglevel
+This sets the debug level to
+.Ar debuglevel .
+When the debug level is greater than the default value of 0,
+additional debugging messages are printed. Regardless of the debug
+level, an error condition, will always write an error message and will
+cause
+.I map-mbone
+to terminate.
+Non-zero debug levels have the following effects:
+.Bl -tag -width "level 3"
+.It level 1
+packet warnings are printed to stderr.
+.It level 2
+all level 1 messages plus notifications down networks are printed to stderr.
+.It level 3
+all level 2 messages plus notifications of all packet
+timeouts are printed to stderr.
+.El
+.It Fl f
+This option enables flooding. Flooding allows
+.Nm
+to perform recursive search
+of neighboring multicast routers and is enabled by default when an
+initial
+.Ar router
+is not specified.
+.It Fl g
+This option enables graphing in GraphEd format.
+.It Fl n
+This option disables the DNS lookup for the multicast routers' names.
+.It Fl r Ar retries
+This options sets the neighbor query retry limit to
+.Ar retries .
+The default is one retry.
+.It Fl t Ar timeout
+This option sets the number of seconds to wait for a neighbor query
+reply before retrying. The default timeout is two seconds.
+.Sh RESTRICTIONS
+.Nm
+must be run as `root'.
+.Sh SEE ALSO
+.Xr mrinfo 8 ,
+.Xr mrouted 8 ,
+.Xr mtrace 8
+.Sh AUTHOR
+Pavel Curtis
+.Sh HISTORY
+A
+.Nm
+command first appeared in
+.Tn FreeBSD
+2.0.
diff --git a/usr.sbin/mrouted/mrinfo.8 b/usr.sbin/mrouted/mrinfo.8
new file mode 100644
index 000000000000..b1e7880bf8ae
--- /dev/null
+++ b/usr.sbin/mrouted/mrinfo.8
@@ -0,0 +1,92 @@
+.Dd March 31, 1995
+.Dt MRINFO 8
+.Sh NAME
+.Nm mrinfo
+.Nd displays configuration info from a multicast router
+.Sh SYNOPSIS
+.Nm mrinfo
+.Op Fl d Ar debuglevel
+.Op Fl r Ar retries
+.Op Fl t Ar timeout
+.Ar router
+.Sh DESCRIPTION
+The
+.Nm mrinfo
+program attempts to display the configuration information from the
+multicast router
+.Ar router .
+.Pp
+.Nm
+uses the
+.Dv ASK_NEIGHBORS
+.Tn IGMP
+message to the specified multicast router. If this multicast router
+responds, the version number and a list of their neighboring multicast
+router addresses is part of that response. If the responding router
+has a recent multicast version number, then
+.Nm mrinfo
+requests additional information such as metrics, thresholds, and flags
+from the multicast router. Once the specified multicast router
+responds, the configuration is displayed to the standard output.
+.Pp
+The
+.Nm
+program accepts the following options:
+.Bl -tag -width XXXdebuglevel
+.It Fl d Ar debuglevel
+This option sets the debug level to
+.Ar debuglevel .
+When the debug level is greater than the default value of 0, addition
+debugging messages are printed. Regardless of the debug level, an
+error condition, will always write an error message and will cause
+.Nm
+to terminate.
+Non-zero debug levels have the following effects:
+.Bl -tag -width "level 3"
+.It level 1
+packet warnings are printed to stderr.
+.It level 2
+all level 1 messages plus notifications down networks are printed to stderr.
+.It level 3
+all level 2 messages plus notifications of all packet
+timeouts are printed to stderr.
+.El
+.It Fl r Ar retries
+This option sets the neighbor query retry limit to
+.Ar retries .
+The default is three retries.
+.It Fl t Ar timeout
+This sets the number of seconds to wait for a neighbor query
+reply. The default timeout is four seconds.
+.El
+.Sh SAMPLE OUTPUT
+.Bd -literal
+# mrinfo mbone.phony.dom.net
+127.148.176.10 (mbone.phony.dom.net) [version 3.3]:
+ 127.148.176.10 -> 0.0.0.0 (?) [1/1/querier]
+ 127.148.176.10 -> 127.0.8.4 (mbone2.phony.dom.net) [1/45/tunnel]
+ 127.148.176.10 -> 105.1.41.9 (momoney.com) [1/32/tunnel/down]
+ 127.148.176.10 -> 143.192.152.119 (mbone.dipu.edu) [1/32/tunnel]
+.Ed
+.Pp
+For each neighbor of the queried multicast router, the IP of the
+queried router is displayed, followed by the IP and name of the
+neighbor. In square brackets the metric (cost of connection) and the
+threshold (minimum TTL to forward) are displayed. If the queried multicast
+router has a newer version number, the type (tunnel, srcrt) and status
+(disabled, down) of the connection are also displayed.
+.Sh RESTRICTIONS
+.Nm
+must be run as `root'.
+.Sh SEE ALSO
+.Xr map-mbone 8 ,
+.Xr mrouted 8 ,
+.Xr mtrace 8
+.Sh AUTHOR
+Pavel Curtis
+.Sh HISTORY
+An
+.Nm
+command first appeared in
+.Tn FreeBSD
+2.0.
diff --git a/usr.sbin/mrouted/mtrace.8 b/usr.sbin/mrouted/mtrace.8
new file mode 100644
index 000000000000..bfc6dd54135c
--- /dev/null
+++ b/usr.sbin/mrouted/mtrace.8
@@ -0,0 +1,499 @@
+.\" Copyright (c) 1995 by the University of Southern California
+.\" All rights reserved.
+.\"
+.\" Permission to use, copy, modify, and distribute this software and its
+.\" documentation in source and binary forms for non-commercial purposes
+.\" and without fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both the copyright notice and
+.\" this permission notice appear in supporting documentation, and that
+.\" any documentation, advertising materials, and other materials related
+.\" to such distribution and use acknowledge that the software was
+.\" developed by the University of Southern California, Information
+.\" Sciences Institute. The name of the University may not be used to
+.\" endorse or promote products derived from this software without
+.\" specific prior written permission.
+.\"
+.\" THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about
+.\" the suitability of this software for any purpose. THIS SOFTWARE IS
+.\" PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
+.\" INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" Other copyrights might apply to parts of this software and are so
+.\" noted when applicable.
+.\"
+.\" This manual page (but not the software) was derived from the
+.\" manual page for the traceroute program which bears the following
+.\" copyright notice:
+.\"
+.\" Copyright (c) 1988 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" $Id: mtrace.8,v 3.5 1995/05/09 01:23:58 fenner Exp $
+.\"
+.TH MTRACE 8 "May 8, 1995"
+.UC 6
+.SH NAME
+mtrace \- print multicast path from a source to a receiver
+.SH SYNOPSIS
+.B mtrace
+[
+.B \-g
+.I gateway
+] [
+.B \-i
+.I if_addr
+] [
+.B \-l
+] [
+.B \-M
+] [
+.B \-m
+.I max_hops
+] [
+.B \-n
+] [
+.B \-p
+] [
+.B \-q
+.I nqueries
+] [
+.B \-r
+.I resp_dest
+] [
+.B \-s
+.I src_addr
+] [
+.B \-t
+.I ttl
+] [
+.B \-w
+.I waittime
+]
+.I source
+[
+.I receiver
+] [
+.I group
+]
+.SH DESCRIPTION
+Assessing problems in the distribution of IP multicast traffic
+can be difficult.
+.B mtrace
+utilizes a tracing feature implemented in multicast routers
+.RB ( mrouted
+version 3.3 and later) that is
+accessed via an extension to the IGMP protocol. A trace query is
+passed hop-by-hop along the reverse path from the
+.I receiver
+to the
+.IR source ,
+collecting hop addresses, packet counts, and routing error conditions
+along the path, and then the response is returned to the requestor.
+.PP
+The only required parameter is the
+.I source
+host name or address. The default
+.I receiver
+is the host running mtrace, and the default
+.I group
+is "MBone Audio" (224.2.0.1), which is sufficient if packet loss
+statistics for a particular multicast group are not needed. These two
+optional parameters may be specified to test the path to some other
+receiver in a particular group, subject to some constraints as
+detailed below. The two parameters can be distinguished because the
+.I receiver
+is a unicast address and the
+.I group
+is a multicast address.
+.SH OPTIONS
+.TP 8 8
+.BI \-g\ gwy
+Send the trace query via unicast directly to the multicast router
+.I gwy
+rather than multicasting the query.
+This must be the last-hop router on the path from the intended
+.I source
+to the
+.IR receiver .
+.RS 8
+.TP 12 12
+.I CAUTION!!
+Version 3.3 of
+.B mrouted
+will crash if a trace query is received via a
+unicast packet and
+.B mrouted
+has no route for the
+.I source
+address. Therefore, do not use the
+.B \-g
+option unless the target
+.B mrouted
+has been verified to be newer than 3.3.
+.RE
+.TP 8 8
+.BI \-i\ addr
+Use
+.I addr
+as the local interface address (on a multi-homed host) for sending the
+trace query and as the default for the
+.I receiver
+and the response destination.
+.TP 8 8
+.B \-l
+Loop indefinitely printing packet rate and loss statistics for the
+multicast path every 10 seconds.
+.TP 8 8
+.B \-M
+Always send the response using multicast rather than attempting
+unicast first.
+.TP 8 8
+.BI \-m\ n
+Set to
+.I n
+the maximum number of hops that will be traced from the
+.I receiver
+back toward the
+.IR source .
+The default is 32 hops (infinity for the DVMRP routing protocol).
+.TP 8 8
+.B \-n
+Print hop addresses numerically rather than symbolically and numerically
+(saves a nameserver address-to-name lookup for each router found on the
+path).
+.TP 8 8
+.BI \-q\ n
+Set the maximum number of query attempts for any hop to
+.IR n .
+The default is 3.
+.TP 8 8
+.B \-p
+Listen passively for multicast responses from traces initiated by
+others (not implemented yet).
+.TP 8 8
+.BI \-r\ host
+Send the trace response to
+.I host
+rather than to the host on which
+.B mtrace
+is being run, or to a multicast address other than the one registered
+for this purpose (224.0.1.32).
+.TP 8 8
+.B \-s
+Print a short form output including only the multicast path and not
+the packet rate and loss statistics.
+.TP 8 8
+.BI \-t\ ttl
+Set the
+.I ttl
+(time-to-live, or number of hops) for multicast trace queries and
+responses. The default is 64, except for local queries to the "all
+routers" multicast group which use ttl 1.
+.TP 8 8
+.BI \-w\ n
+Set the time to wait for a trace response to
+.I n
+seconds (default 3 seconds).
+.SH USAGE
+.SS How It Works
+The technique used by the
+.B traceroute
+tool to trace unicast network paths will not work for IP multicast
+because ICMP responses are specifically forbidden for multicast traffic.
+Instead, a tracing feature has been built into the multicast routers.
+This technique has the advantage that additional information about
+packet rates and losses can be accumulated while the number of packets
+sent is minimized.
+.PP
+Since multicast uses
+reverse path forwarding, the trace is run backwards from the
+.I receiver
+to the
+.IR source .
+A trace query packet is sent to the last
+hop multicast router (the leaf router for the desired
+.I receiver
+address). The last hop router builds a trace response packet, fills in
+a report for its hop, and forwards the trace packet using unicast to
+the router it believes is the previous hop for packets originating
+from the specified
+.IR source .
+Each router along the path adds its report and forwards the packet.
+When the trace response packet reaches the first hop router (the router
+that is directly connected to the source's net), that router sends the
+completed response to the response destination address specified in
+the trace query.
+.PP
+If some multicast router along the path does not implement the
+multicast traceroute feature or if there is some outage, then no
+response will be returned. To solve this problem, the trace query
+includes a maximum hop count field to limit the number of hops traced
+before the response is returned. That allows a partial path to be
+traced.
+.PP
+The reports inserted by each router contain not only the address of
+the hop, but also the ttl required to forward and some flags to indicate
+routing errors, plus counts of the total number of packets on the
+incoming and outgoing interfaces and those forwarded for the specified
+.IR group .
+Taking differences in these counts for two traces separated in time
+and comparing the output packet counts from one hop with the input
+packet counts of the next hop allows the calculation of packet rate
+and packet loss statistics for each hop to isolate congestion
+problems.
+.SS Finding the Last-Hop Router
+The trace query must be sent to the multicast router which is the
+last hop on the path from the
+.I source
+to the
+.IR receiver .
+If the receiver is on the local subnet (as determined using the subnet
+mask), then the default method is to multicast the trace query to
+all-routers.mcast.net (224.0.0.2) with a ttl of 1. Otherwise, the
+trace query is multicast to the
+.I group
+address since the last hop router will be a member of that group if
+the receiver is. Therefore it is necessary to specify a group that
+the intended receiver has joined. This multicast is sent with a
+default ttl of 64, which may not be sufficient for all cases (changed
+with the
+.B \-t
+option).
+If the last hop router is known, it may also be addressed directly
+using the
+.B \-g
+option). Alternatively, if it is desired to trace a group that the
+receiver has not joined, but it is known that the last-hop router is a
+member of another group, the
+.B \-g
+option may also be used to specify a different multicast address for the
+trace query.
+.PP
+When tracing from a multihomed host or router, the default receiver
+address may not be the desired interface for the path from the source.
+In that case, the desired interface should be specified explicitly as
+the
+.IR receiver .
+.SS Directing the Response
+By default,
+.B mtrace
+first attempts to trace the full reverse path, unless the number of
+hops to trace is explicitly set with the
+.B \-m
+option. If there is no response within a 3 second timeout interval
+(changed with the
+.B \-w
+option), a "*" is printed and the probing switches to hop-by-hop mode.
+Trace queries are issued starting with a maximum hop count of one and
+increasing by one until the full path is traced or no response is
+received. At each hop, multiple probes are sent (default is three,
+changed with
+.B \-q
+option). The first half of the attempts (default is one) are made with
+the unicast address of the host running
+.B mtrace
+as the destination for the response. Since the unicast route may be
+blocked, the remainder of attempts request that the response be
+multicast to mtrace.mcast.net (224.0.1.32) with the ttl set to 32 more
+than what's needed to pass the thresholds seen so far along the path
+to the receiver. For the last quarter of the attempts (default is
+one), the ttl is increased by another 32 each time up to a maximum of
+192. Alternatively, the ttl may be set explicity with the
+.B \-t
+option and/or the initial unicast attempts can be forced to use
+multicast instead with the
+.B \-M
+option. For each attempt, if no response is received within the
+timeout, a "*" is printed. After the specified number of attempts
+have failed,
+.B mtrace
+will try to query the next hop router with a DVMRP_ASK_NEIGHBORS2
+request (as used by the
+.B mrinfo
+program) to see what kind of router it is.
+.SH EXAMPLES
+The output of
+.B mtrace
+is in two sections. The first section is a short listing of the hops
+in the order they are queried, that is, in the reverse of the order
+from the
+.I source
+to the
+.IR receiver .
+For each hop, a line is printed showing the hop number (counted
+negatively to indicate that this is the reverse path); the multicast
+routing protocol (DVMRP, MOSPF, PIM, etc.); the threshold required to
+forward data (to the previous hop in the listing as indicated by the
+up-arrow character); and the cumulative delay for the query to reach
+that hop (valid only if the clocks are synchronized). This first
+section ends with a line showing the round-trip time which measures
+the interval from when the query is issued until the response is
+received, both derived from the local system clock. A sample use and
+output might be:
+.PP
+.nf
+.ft C
+oak.isi.edu 80# mtrace -l caraway.lcs.mit.edu 224.2.0.3
+Mtrace from 18.26.0.170 to 128.9.160.100 via group 224.2.0.3
+Querying full reverse path...
+ 0 oak.isi.edu (128.9.160.100)
+ -1 cub.isi.edu (128.9.160.153) DVMRP thresh^ 1 3 ms
+ -2 la.dart.net (140.173.128.1) DVMRP thresh^ 1 14 ms
+ -3 dc.dart.net (140.173.64.1) DVMRP thresh^ 1 50 ms
+ -4 bbn.dart.net (140.173.32.1) DVMRP thresh^ 1 63 ms
+ -5 mit.dart.net (140.173.48.2) DVMRP thresh^ 1 71 ms
+ -6 caraway.lcs.mit.edu (18.26.0.170)
+Round trip time 124 ms
+.fi
+.PP
+The second section provides a pictorial view of the path in the
+forward direction with data flow indicated by arrows pointing downward
+and the query path indicated by arrows pointing upward. For each hop,
+both the entry and exit addresses of the router are shown if
+different, along with the initial ttl required on the packet in order
+to be forwarded at this hop and the propagation delay across the hop
+assuming that the routers at both ends have synchronized clocks. The
+right half of this section is composed of several columns of
+statistics in two groups. Within each group, the columns are the
+number of packets lost, the number of packets sent, the percentage
+lost, and the average packet rate at each hop. These statistics are
+calculated from differences between traces and from hop to hop as
+explained above. The first group shows the statistics for all traffic
+flowing out the interface at one hop and in the interface at the next
+hop. The second group shows the statistics only for traffic forwarded
+from the specified
+.I source
+to the specified
+.IR group .
+.PP
+These statistics are shown on one or two lines for each hop. Without
+any options, this second section of the output is printed only once,
+approximately 10 seconds after the initial trace. One line is shown
+for each hop showing the statistics over that 10-second period. If
+the
+.B \-l
+option is given, the second section is repeated every 10 seconds and
+two lines are shown for each hop. The first line shows the statistics
+for the last 10 seconds, and the second line shows the cumulative
+statistics over the period since the initial trace, which is 101
+seconds in the example below. The second section of the output is
+omitted if the
+.B \-s
+option is set.
+.ie t \{\
+.ft C
+. ie \w'i'<>\w'm' \{\" looks like this is not proper Courier font
+(If this example is not properly columned with a fixed-width font, get
+.B groff
+and try again.)
+. \}
+.\}
+.PP
+.ft C
+.nf
+Waiting to accumulate statistics... Results after 101 seconds:
+
+ Source Response Dest Packet Statistics For Only For Traffic
+18.26.0.170 128.9.160.100 All Multicast Traffic From 18.26.0.170
+ | __/ rtt 125 ms Lost/Sent = Pct Rate To 224.2.0.3
+ v / hop 65 ms --------------------- ------------------
+18.26.0.144
+140.173.48.2 mit.dart.net
+ | ^ ttl 1 0/6 = --% 0 pps 0/2 = --% 0 pps
+ v | hop 8 ms 1/52 = 2% 0 pps 0/18 = 0% 0 pps
+140.173.48.1
+140.173.32.1 bbn.dart.net
+ | ^ ttl 2 0/6 = --% 0 pps 0/2 = --% 0 pps
+ v | hop 12 ms 1/52 = 2% 0 pps 0/18 = 0% 0 pps
+140.173.32.2
+140.173.64.1 dc.dart.net
+ | ^ ttl 3 0/271 = 0% 27 pps 0/2 = --% 0 pps
+ v | hop 34 ms -1/2652 = 0% 26 pps 0/18 = 0% 0 pps
+140.173.64.2
+140.173.128.1 la.dart.net
+ | ^ ttl 4 -2/831 = 0% 83 pps 0/2 = --% 0 pps
+ v | hop 11 ms -3/8072 = 0% 79 pps 0/18 = 0% 0 pps
+140.173.128.2
+128.9.160.153 cub.isi.edu
+ | \\__ ttl 5 833 83 pps 2 0 pps
+ v \\ hop -8 ms 8075 79 pps 18 0 pps
+128.9.160.100 128.9.160.100
+ Receiver Query Source
+.fi
+.PP
+Because the packet counts may be changing as the trace query is
+propagating, there may be small errors (off by 1 or 2) in these
+statistics. However, those errors should not accumulate, so the
+cumulative statistics line should increase in accuracy as a new trace
+is run every 10 seconds. There are two sources of larger errors, both
+of which show up as negative losses:
+.LP
+.RS
+.PD 0
+.TP 3
+\(bu
+If the input to a node is from a multi-access network with more than
+one other node attached, then the input count will be (close to) the
+sum of the output counts from all the attached nodes, but the output
+count from the previous hop on the traced path will be only part of
+that. Hence the output count minus the input count will be negative.
+.TP 3
+\(bu
+In release 3.3 of the DVMRP multicast forwarding software for SunOS
+and other systems, a multicast packet generated on a router will be
+counted as having come in an interface even though it did not. This
+creates the negative loss that can be seen in the example above.
+.PD
+.RE
+.LP
+Note that these negative losses may mask positive losses.
+.PP
+In the example, there is also one negative hop time. This simply
+indicates a lack of synchronization between the system clocks across
+that hop. This example also illustrates how the percentage loss is
+shown as two dashes when the number of packets sent is less than 10
+because the percentage would not be statistically valid.
+.PP
+A second example shows a trace to a receiver that is not local; the
+query is sent to the last-hop router with the
+.B \-g
+option. In this example, the trace of the full reverse path resulted
+in no response because there was a node running an old version of
+.B mrouted
+that did not implement the multicast traceroute function, so
+.B mtrace
+switched to hop-by-hop mode. The \*(lqRoute pruned\*(rq error code
+indicates that traffic for group 224.2.143.24 would not be forwarded.
+.PP
+.nf
+.ft C
+oak.isi.edu 108# mtrace -g 140.173.48.2 204.62.246.73 \\
+ butter.lcs.mit.edu 224.2.143.24
+Mtrace from 204.62.246.73 to 18.26.0.151 via group 224.2.143.24
+Querying full reverse path... * switching to hop-by-hop:
+ 0 butter.lcs.mit.edu (18.26.0.151)
+ -1 jam.lcs.mit.edu (18.26.0.144) DVMRP thresh^ 1 33 ms Route pruned
+ -2 bbn.dart.net (140.173.48.1) DVMRP thresh^ 1 36 ms
+ -3 dc.dart.net (140.173.32.2) DVMRP thresh^ 1 44 ms
+ -4 darpa.dart.net (140.173.240.2) DVMRP thresh^ 16 47 ms
+ -5 * * * noc.hpc.org (192.187.8.2) [mrouted 2.2] didn't respond
+Round trip time 95 ms
+.fi
+.SH AUTHOR
+Implemented by Steve Casner based on an initial prototype written by
+Ajit Thyagarajan. The multicast traceroute mechanism was designed by
+Van Jacobson with help from Steve Casner, Steve Deering, Dino
+Farinacci, and Deb Agrawal; it was implemented in
+.B mrouted
+by Ajit Thyagarajan and Bill Fenner. The option syntax and the output
+format of
+.B mtrace
+are modeled after the unicast
+.B traceroute
+program written by Van Jacobson.
+.SH SEE ALSO
+.BR mrouted (8) ,
+.BR mrinfo (8) ,
+.BR map-mbone (8) ,
+.BR traceroute (8)
diff --git a/usr.sbin/mrouted/pathnames.h b/usr.sbin/mrouted/pathnames.h
new file mode 100644
index 000000000000..20223144c779
--- /dev/null
+++ b/usr.sbin/mrouted/pathnames.h
@@ -0,0 +1,25 @@
+/*
+ * 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: pathnames.h,v 3.5 1995/05/09 01:00:39 fenner Exp $
+ */
+
+#define _PATH_MROUTED_CONF "/etc/mrouted.conf"
+
+#if (defined(BSD) && (BSD >= 199103))
+#define _PATH_MROUTED_PID "/var/run/mrouted.pid"
+#define _PATH_MROUTED_GENID "/var/run/mrouted.genid"
+#define _PATH_MROUTED_DUMP "/var/tmp/mrouted.dump"
+#define _PATH_MROUTED_CACHE "/var/tmp/mrouted.cache"
+#else
+#define _PATH_MROUTED_PID "/etc/mrouted.pid"
+#define _PATH_MROUTED_GENID "/etc/mrouted.genid"
+#define _PATH_MROUTED_DUMP "/usr/tmp/mrouted.dump"
+#define _PATH_MROUTED_CACHE "/usr/tmp/mrouted.cache"
+#endif
diff --git a/usr.sbin/mrouted/rsrr.c b/usr.sbin/mrouted/rsrr.c
new file mode 100644
index 000000000000..34eedabbe8aa
--- /dev/null
+++ b/usr.sbin/mrouted/rsrr.c
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 1993 by the University of Southern California
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation in source and binary forms for non-commercial purposes
+ * and without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both the copyright notice and
+ * this permission notice appear in supporting documentation. and that
+ * any documentation, advertising materials, and other materials related
+ * to such distribution and use acknowledge that the software was
+ * developed by the University of Southern California, Information
+ * Sciences Institute. The name of the University may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about
+ * the suitability of this software for any purpose. THIS SOFTWARE IS
+ * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Other copyrights might apply to parts of this software and are so
+ * noted when applicable.
+ */
+
+/* RSRR code written by Daniel Zappala, USC Information Sciences Institute,
+ * April 1995.
+ */
+
+/* May 1995 -- Added support for Route Change Notification */
+
+#ifdef RSRR
+
+#include "defs.h"
+
+/* Taken from prune.c */
+/*
+ * checks for scoped multicast addresses
+ */
+#define GET_SCOPE(gt) { \
+ register int _i; \
+ if (((gt)->gt_mcastgrp & 0xff000000) == 0xef000000) \
+ for (_i = 0; _i < numvifs; _i++) \
+ if (scoped_addr(_i, (gt)->gt_mcastgrp)) \
+ VIFM_SET(_i, (gt)->gt_scope); \
+ }
+
+/*
+ * Exported variables.
+ */
+int rsrr_socket; /* interface to reservation protocol */
+
+/*
+ * Global RSRR variables.
+ */
+char rsrr_recv_buf[RSRR_MAX_LEN]; /* RSRR receive buffer */
+char rsrr_send_buf[RSRR_MAX_LEN]; /* RSRR send buffer */
+
+struct sockaddr_un client_addr;
+int client_length = sizeof(client_addr);
+
+
+/*
+ * Procedure definitions needed internally.
+ */
+void rsrr_accept();
+void rsrr_accept_iq();
+int rsrr_accept_rq();
+int rsrr_send();
+void rsrr_cache();
+
+/* Initialize RSRR socket */
+void
+rsrr_init()
+{
+ int servlen;
+ struct sockaddr_un serv_addr;
+
+ if ((rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
+ log(LOG_ERR, errno, "Can't create RSRR socket");
+
+ unlink(RSRR_SERV_PATH);
+ bzero((char *) &serv_addr, sizeof(serv_addr));
+ serv_addr.sun_family = AF_UNIX;
+ strcpy(serv_addr.sun_path, RSRR_SERV_PATH);
+ servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
+
+ if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0)
+ log(LOG_ERR, errno, "Can't bind RSRR socket");
+
+ if (register_input_handler(rsrr_socket,rsrr_read) < 0)
+ log(LOG_WARNING, 0, "Couldn't register RSRR as an input handler");
+}
+
+/* Read a message from the RSRR socket */
+void
+rsrr_read()
+{
+ register int rsrr_recvlen;
+ register int omask;
+
+ bzero((char *) &client_addr, sizeof(client_addr));
+ rsrr_recvlen = recvfrom(rsrr_socket, rsrr_recv_buf, sizeof(rsrr_recv_buf),
+ 0, (struct sockaddr *)&client_addr,&client_length);
+ if (rsrr_recvlen < 0) {
+ if (errno != EINTR)
+ log(LOG_ERR, errno, "RSRR recvfrom");
+ return;
+ }
+ /* Use of omask taken from main() */
+ omask = sigblock(sigmask(SIGALRM));
+ rsrr_accept(rsrr_recvlen);
+ (void)sigsetmask(omask);
+}
+
+/* Accept a message from the reservation protocol and take
+ * appropriate action.
+ */
+void
+rsrr_accept(recvlen)
+ int recvlen;
+{
+ struct rsrr_header *rsrr;
+ struct rsrr_rq *route_query;
+
+ if (recvlen < RSRR_HEADER_LEN) {
+ log(LOG_WARNING, 0,
+ "Received RSRR packet of %d bytes, which is less than min size",
+ recvlen);
+ return;
+ }
+
+ rsrr = (struct rsrr_header *) rsrr_recv_buf;
+
+ if (rsrr->version > RSRR_MAX_VERSION) {
+ log(LOG_WARNING, 0,
+ "Received RSRR packet version %d, which I don't understand",
+ rsrr->version);
+ return;
+ }
+
+ switch (rsrr->version) {
+ case 1:
+ switch (rsrr->type) {
+ case RSRR_INITIAL_QUERY:
+ /* Send Initial Reply to client */
+ log(LOG_INFO, 0, "Received Initial Query\n");
+ rsrr_accept_iq();
+ break;
+ case RSRR_ROUTE_QUERY:
+ /* Check size */
+ if (recvlen < RSRR_RQ_LEN) {
+ log(LOG_WARNING, 0,
+ "Received Route Query of %d bytes, which is too small",
+ recvlen);
+ break;
+ }
+ /* Get the query */
+ route_query = (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN);
+ log(LOG_INFO, 0,
+ "Received Route Query for src %s grp %s notification %d",
+ inet_fmt(route_query->source_addr.s_addr, s1),
+ inet_fmt(route_query->dest_addr.s_addr,s2),
+ BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT));
+ /* Send Route Reply to client */
+ rsrr_accept_rq(route_query,rsrr->flags,NULL);
+ break;
+ default:
+ log(LOG_WARNING, 0,
+ "Received RSRR packet type %d, which I don't handle",
+ rsrr->type);
+ break;
+ }
+ break;
+
+ default:
+ log(LOG_WARNING, 0,
+ "Received RSRR packet version %d, which I don't understand",
+ rsrr->version);
+ break;
+ }
+}
+
+/* Send an Initial Reply to the reservation protocol. */
+void
+rsrr_accept_iq()
+{
+ struct rsrr_header *rsrr;
+ struct rsrr_vif *vif_list;
+ struct uvif *v;
+ int vifi, sendlen;
+
+ /* Check for space. There should be room for plenty of vifs,
+ * but we should check anyway.
+ */
+ if (numvifs > RSRR_MAX_VIFS) {
+ log(LOG_WARNING, 0,
+ "Can't send RSRR Route Reply because %d is too many vifs %d",
+ numvifs);
+ return;
+ }
+
+ /* Set up message */
+ rsrr = (struct rsrr_header *) rsrr_send_buf;
+ rsrr->version = 1;
+ rsrr->type = RSRR_INITIAL_REPLY;
+ rsrr->flags = 0;
+ rsrr->num = numvifs;
+
+ vif_list = (struct rsrr_vif *) (rsrr_send_buf + RSRR_HEADER_LEN);
+
+ /* Include the vif list. */
+ for (vifi=0, v = uvifs; vifi < numvifs; vifi++, v++) {
+ vif_list[vifi].id = vifi;
+ vif_list[vifi].status = 0;
+ if (v->uv_flags & VIFF_DISABLED)
+ BIT_SET(vif_list[vifi].status,RSRR_DISABLED_BIT);
+ vif_list[vifi].threshold = v->uv_threshold;
+ vif_list[vifi].local_addr.s_addr = v->uv_lcl_addr;
+ }
+
+ /* Get the size. */
+ sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN;
+
+ /* Send it. */
+ log(LOG_INFO, 0, "Send RSRR Initial Reply");
+ rsrr_send(sendlen);
+}
+
+/* Send a Route Reply to the reservation protocol. The Route Query
+ * contains the query to which we are responding. The flags contain
+ * the incoming flags from the query or, for route change
+ * notification, the flags that should be set for the reply. The
+ * kernel table entry contains the routing info to use for a route
+ * change notification.
+ */
+int
+rsrr_accept_rq(route_query,flags,gt_notify)
+ struct rsrr_rq *route_query;
+ int flags;
+ struct gtable *gt_notify;
+{
+ struct rsrr_header *rsrr;
+ struct rsrr_rr *route_reply;
+ struct gtable *gt,local_g;
+ struct rtentry *r;
+ int sendlen,i;
+ u_long mcastgrp;
+
+ /* Set up message */
+ rsrr = (struct rsrr_header *) rsrr_send_buf;
+ rsrr->version = 1;
+ rsrr->type = RSRR_ROUTE_REPLY;
+ rsrr->flags = 0;
+ rsrr->num = 0;
+
+ route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN);
+ route_reply->dest_addr.s_addr = route_query->dest_addr.s_addr;
+ route_reply->source_addr.s_addr = route_query->source_addr.s_addr;
+ route_reply->query_id = route_query->query_id;
+
+ /* Blank routing entry for error. */
+ route_reply->in_vif = 0;
+ route_reply->reserved = 0;
+ route_reply->out_vif_bm = 0;
+
+ /* Get the size. */
+ sendlen = RSRR_RR_LEN;
+
+ /* If kernel table entry is defined, then we are sending a Route Reply
+ * due to a Route Change Notification event. Use the kernel table entry
+ * to supply the routing info.
+ */
+ if (gt_notify) {
+ /* Set flags */
+ rsrr->flags = flags;
+ /* Include the routing entry. */
+ route_reply->in_vif = gt_notify->gt_route->rt_parent;
+ route_reply->out_vif_bm = gt_notify->gt_grpmems;
+
+ } else if (find_src_grp(route_query->source_addr.s_addr, 0,
+ route_query->dest_addr.s_addr)) {
+
+ /* Found kernel entry. Code taken from add_table_entry() */
+ gt = gtp ? gtp->gt_gnext : kernel_table;
+
+ /* Include the routing entry. */
+ route_reply->in_vif = gt->gt_route->rt_parent;
+ route_reply->out_vif_bm = gt->gt_grpmems;
+
+ /* Cache reply if using route change notification. */
+ if BIT_TST(flags,RSRR_NOTIFICATION_BIT) {
+ rsrr_cache(gt,route_query);
+ BIT_SET(rsrr->flags,RSRR_NOTIFICATION_BIT);
+ }
+
+ } else {
+ /* No kernel entry; use routing table. */
+ r = determine_route(route_query->source_addr.s_addr);
+
+ if (r != NULL) {
+ /* We need to mimic what will happen if a data packet
+ * is forwarded by multicast routing -- the kernel will
+ * make an upcall and mrouted will install a route in the kernel.
+ * Our outgoing vif bitmap should reflect what that table
+ * will look like. Grab code from add_table_entry().
+ * This is gross, but it's probably better to be accurate.
+ */
+
+ gt = &local_g;
+ mcastgrp = route_query->dest_addr.s_addr;
+
+ gt->gt_mcastgrp = mcastgrp;
+ gt->gt_grpmems = 0;
+ gt->gt_scope = 0;
+ gt->gt_route = r;
+
+ /* obtain the multicast group membership list */
+ for (i = 0; i < numvifs; i++) {
+ if (VIFM_ISSET(i, r->rt_children) &&
+ !(VIFM_ISSET(i, r->rt_leaves)))
+ VIFM_SET(i, gt->gt_grpmems);
+
+ if (VIFM_ISSET(i, r->rt_leaves) && grplst_mem(i, mcastgrp))
+ VIFM_SET(i, gt->gt_grpmems);
+ }
+
+ GET_SCOPE(gt);
+ gt->gt_grpmems &= ~gt->gt_scope;
+
+ /* Include the routing entry. */
+ route_reply->in_vif = gt->gt_route->rt_parent;
+ route_reply->out_vif_bm = gt->gt_grpmems;
+
+ } else {
+ /* Set error bit. */
+ BIT_SET(rsrr->flags,RSRR_ERROR_BIT);
+ }
+ }
+
+ if (gt_notify)
+ log(LOG_INFO, 0, "Route Change: Send RSRR Route Reply");
+
+ else
+ log(LOG_INFO, 0, "Send RSRR Route Reply");
+
+ log(LOG_INFO, 0, "for src %s dst %s in vif %d out vif %d\n",
+ inet_fmt(route_reply->source_addr.s_addr,s1),
+ inet_fmt(route_reply->dest_addr.s_addr,s2),
+ route_reply->in_vif,route_reply->out_vif_bm);
+
+ /* Send it. */
+ return rsrr_send(sendlen);
+}
+
+/* Send an RSRR message. */
+int
+rsrr_send(sendlen)
+ int sendlen;
+{
+ int error;
+
+ /* Send it. */
+ error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0,
+ (struct sockaddr *)&client_addr, client_length);
+
+ /* Check for errors. */
+ if (error < 0) {
+ log(LOG_WARNING, errno, "Failed send on RSRR socket");
+ return error;
+ }
+ if (error != sendlen) {
+ log(LOG_WARNING, 0,
+ "Sent only %d out of %d bytes on RSRR socket\n", error, sendlen);
+ return error;
+ }
+}
+
+/* Cache a message being sent to a client. Currently only used for
+ * caching Route Reply messages for route change notification.
+ */
+void
+rsrr_cache(gt,route_query)
+ struct gtable *gt;
+ struct rsrr_rq *route_query;
+{
+ struct rsrr_cache *rc,*rc_prev;
+ struct rsrr_header *rsrr;
+
+ rsrr = (struct rsrr_header *) rsrr_send_buf;
+
+ rc = gt->gt_rsrr_cache;
+ while (rc) {
+ if ((rc->route_query.source_addr.s_addr ==
+ route_query->source_addr.s_addr) &&
+ (rc->route_query.dest_addr.s_addr ==
+ route_query->dest_addr.s_addr) &&
+ (!strcmp(rc->client_addr.sun_path,client_addr.sun_path))) {
+ /* Cache entry already exists.
+ * Check if route notification bit has been cleared.
+ */
+ if (!BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)) {
+ /* Delete cache entry. */
+ if (rc == gt->gt_rsrr_cache)
+ /* Deleting first entry. */
+ gt->gt_rsrr_cache = rc->next;
+ else
+ rc_prev->next = rc->next;
+ free(rc);
+ } else {
+ /* Update */
+ rc->route_query.query_id = route_query->query_id;
+ printf("Update cached query id %d from client %s\n",
+ rc->route_query.query_id,rc->client_addr.sun_path);
+ }
+ return;
+ }
+ rc_prev = rc;
+ rc = rc->next;
+ }
+
+ /* Cache entry doesn't already exist. Create one and insert at
+ * front of list.
+ */
+ rc = (struct rsrr_cache *) malloc(sizeof(struct rsrr_cache));
+ if (rc == NULL)
+ log(LOG_ERR, 0, "ran out of memory");
+ rc->route_query.source_addr.s_addr = route_query->source_addr.s_addr;
+ rc->route_query.dest_addr.s_addr = route_query->dest_addr.s_addr;
+ rc->route_query.query_id = route_query->query_id;
+ strcpy(rc->client_addr.sun_path, client_addr.sun_path);
+ rc->client_length = client_length;
+ rc->next = gt->gt_rsrr_cache;
+ gt->gt_rsrr_cache = rc;
+ printf("Cached query id %d from client %s\n",
+ rc->route_query.query_id,rc->client_addr.sun_path);
+}
+
+/* Send all the messages in the cache. Currently this is used to send
+ * all the cached Route Reply messages for route change notification.
+ */
+void
+rsrr_cache_send(gt,notify)
+ struct gtable *gt;
+ int notify;
+{
+ struct rsrr_cache *rc,*rc_next,*rc_prev;
+ int flags = 0;
+
+ rc = gt->gt_rsrr_cache;
+ while (rc) {
+ rc_next = rc->next;
+
+ if (notify)
+ BIT_SET(flags,RSRR_NOTIFICATION_BIT);
+
+ if (rsrr_accept_rq(&rc->route_query,flags,gt) < 0) {
+ printf("Deleting cached query id %d from client %s\n",
+ rc->route_query.query_id,rc->client_addr.sun_path);
+ /* Delete cache entry. */
+ if (rc == gt->gt_rsrr_cache)
+ /* Deleting first entry. */
+ gt->gt_rsrr_cache = rc_next;
+ else
+ rc_prev->next = rc_next;
+ free(rc);
+ } else {
+ rc_prev = rc;
+ }
+ rc = rc_next;
+ }
+}
+
+/* Clean the cache by deleting all entries. */
+void
+rsrr_cache_clean(gt)
+ struct gtable *gt;
+{
+ struct rsrr_cache *rc,*rc_next;
+
+ printf("cleaning cache for group %s\n",inet_fmt(gt->gt_mcastgrp, s1));
+ rc = gt->gt_rsrr_cache;
+ while (rc) {
+ rc_next = rc->next;
+ free(rc);
+ rc = rc_next;
+ }
+ gt->gt_rsrr_cache = NULL;
+}
+
+void
+rsrr_clean()
+{
+ unlink(RSRR_SERV_PATH);
+}
+
+#endif /* RSRR */
diff --git a/usr.sbin/mrouted/rsrr.h b/usr.sbin/mrouted/rsrr.h
new file mode 100644
index 000000000000..4099dcd8e438
--- /dev/null
+++ b/usr.sbin/mrouted/rsrr.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 1993 by the University of Southern California
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation in source and binary forms for non-commercial purposes
+ * and without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both the copyright notice and
+ * this permission notice appear in supporting documentation. and that
+ * any documentation, advertising materials, and other materials related
+ * to such distribution and use acknowledge that the software was
+ * developed by the University of Southern California, Information
+ * Sciences Institute. The name of the University may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about
+ * the suitability of this software for any purpose. THIS SOFTWARE IS
+ * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Other copyrights might apply to parts of this software and are so
+ * noted when applicable.
+ */
+
+#define RSRR_SERV_PATH "/tmp/.rsrr_svr"
+/* Note this needs to be 14 chars for 4.3 BSD compatibility */
+#define RSRR_CLI_PATH "/tmp/.rsrr_cli"
+
+#define RSRR_MAX_LEN 2048
+#define RSRR_HEADER_LEN (sizeof(struct rsrr_header))
+#define RSRR_RQ_LEN (RSRR_HEADER_LEN + sizeof(struct rsrr_rq))
+#define RSRR_RR_LEN (RSRR_HEADER_LEN + sizeof(struct rsrr_rr))
+#define RSRR_VIF_LEN (sizeof(struct rsrr_vif))
+
+/* Current maximum number of vifs. */
+#define RSRR_MAX_VIFS 32
+
+/* Maximum acceptable version */
+#define RSRR_MAX_VERSION 1
+
+/* RSRR message types */
+#define RSRR_ALL_TYPES 0
+#define RSRR_INITIAL_QUERY 1
+#define RSRR_INITIAL_REPLY 2
+#define RSRR_ROUTE_QUERY 3
+#define RSRR_ROUTE_REPLY 4
+
+/* RSRR Initial Reply (Vif) Status bits.
+ * Each definition represents the position of the bit from right to left.
+ *
+ * Right-most bit is the disabled bit, set if the vif is administratively
+ * disabled.
+ */
+#define RSRR_DISABLED_BIT 0
+/* All other bits are zeroes */
+
+/* RSRR Route Query/Reply flag bits.
+ * Each definition represents the position of the bit from right to left.
+ *
+ * Right-most bit is the Route Change Notification bit, set if the
+ * reservation protocol wishes to receive notification of
+ * a route change for the source-destination pair listed in the query.
+ * Notification is in the form of an unsolicitied Route Reply.
+ */
+#define RSRR_NOTIFICATION_BIT 0
+/* Next bit indicates an error returning the Route Reply. */
+#define RSRR_ERROR_BIT 1
+/* All other bits are zeroes */
+
+/* Definition of an RSRR message header.
+ * An Initial Query uses only the header, and an Initial Reply uses
+ * the header and a list of vifs.
+ */
+struct rsrr_header {
+ u_char version; /* RSRR Version, currently 1 */
+ u_char type; /* type of message, as defined above */
+ u_char flags; /* flags; defined by type */
+ u_char num; /* number; defined by type */
+};
+
+/* Definition of a vif as seen by the reservation protocol.
+ *
+ * Routing gives the reservation protocol a list of vifs in the
+ * Initial Reply.
+ *
+ * We explicitly list the ID because we can't assume that all routing
+ * protocols will use the same numbering scheme.
+ *
+ * The status is a bitmask of status flags, as defined above. It is the
+ * responsibility of the reservation protocol to perform any status checks
+ * if it uses the MULTICAST_VIF socket option.
+ *
+ * The threshold indicates the ttl an outgoing packet needs in order to
+ * be forwarded. The reservation protocol must perform this check itself if
+ * it uses the MULTICAST_VIF socket option.
+ *
+ * The local address is the address of the physical interface over which
+ * packets are sent.
+ */
+struct rsrr_vif {
+ u_char id; /* vif id */
+ u_char threshold; /* vif threshold ttl */
+ u_short status; /* vif status bitmask */
+ struct in_addr local_addr; /* vif local address */
+};
+
+/* Definition of an RSRR Route Query.
+ *
+ * The query asks routing for the forwarding entry for a particular
+ * source and destination. The query ID uniquely identifies the query
+ * for the reservation protocol. Thus, the combination of the client's
+ * address and the query ID forms a unique identifier for routing.
+ * Flags are defined above.
+ */
+struct rsrr_rq {
+ struct in_addr dest_addr; /* destination */
+ struct in_addr source_addr; /* source */
+ u_long query_id; /* query ID */
+};
+
+/* Definition of an RSRR Route Reply.
+ *
+ * Routing uses the reply to give the reservation protocol the
+ * forwarding entry for a source-destination pair. Routing copies the
+ * query ID from the query and fills in the incoming vif and a bitmask
+ * of the outgoing vifs.
+ * Flags are defined above.
+ */
+struct rsrr_rr {
+ struct in_addr dest_addr; /* destination */
+ struct in_addr source_addr; /* source */
+ u_long query_id; /* query ID */
+ u_short in_vif; /* incoming vif */
+ u_short reserved; /* reserved */
+ u_long out_vif_bm; /* outgoing vif bitmask */
+};
diff --git a/usr.sbin/mrouted/rsrr_var.h b/usr.sbin/mrouted/rsrr_var.h
new file mode 100644
index 000000000000..9b1c09c1396e
--- /dev/null
+++ b/usr.sbin/mrouted/rsrr_var.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 1993 by the University of Southern California
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation in source and binary forms for non-commercial purposes
+ * and without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both the copyright notice and
+ * this permission notice appear in supporting documentation. and that
+ * any documentation, advertising materials, and other materials related
+ * to such distribution and use acknowledge that the software was
+ * developed by the University of Southern California, Information
+ * Sciences Institute. The name of the University may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about
+ * the suitability of this software for any purpose. THIS SOFTWARE IS
+ * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Other copyrights might apply to parts of this software and are so
+ * noted when applicable.
+ */
+
+/* RSRR things that are only needed by mrouted. */
+
+/* Cache of Route Query messages, distinguished by source,
+ * destination, and client addresses. Cache is flushed by RSRR client
+ * -- it sends notification when an unwanted Route Reply is received.
+ * Since this only happens during route changes, it is more likely
+ * that the cache will be flushed when the kernel table entry is
+ * deleted. */
+struct rsrr_cache {
+ struct rsrr_rq route_query; /* Cached Route Query */
+ struct sockaddr_un client_addr; /* Client address */
+ int client_length; /* Length of client */
+ struct rsrr_cache *next; /* next cache item */
+};
+