summaryrefslogtreecommitdiff
path: root/usr.sbin/map-mbone/mapper.c
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
commitd6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch)
treeece253b876159b39c620e62b6c9b1174642e070e /usr.sbin/map-mbone/mapper.c
initial import of NetBSD tree
Diffstat (limited to 'usr.sbin/map-mbone/mapper.c')
-rw-r--r--usr.sbin/map-mbone/mapper.c960
1 files changed, 960 insertions, 0 deletions
diff --git a/usr.sbin/map-mbone/mapper.c b/usr.sbin/map-mbone/mapper.c
new file mode 100644
index 00000000000..e58b0fb3bad
--- /dev/null
+++ b/usr.sbin/map-mbone/mapper.c
@@ -0,0 +1,960 @@
+/* $NetBSD: mapper.c,v 1.2 1995/10/03 23:16:56 thorpej Exp $ */
+
+/* Mapper for connections between MRouteD multicast routers.
+ * Written by Pavel Curtis <Pavel@PARC.Xerox.Com>
+ */
+
+/*
+ * 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 <string.h>
+#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_int32_t 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_int32_t addr; /* IP address of the interface in NET order */
+ Neighbor *neighbors; /* List of neighbors' IP addresses */
+} Interface;
+
+typedef struct node {
+ u_int32_t addr; /* IP address of this entry in NET order */
+ u_int32_t 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_int32_t 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_int32_t 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_int32_t 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_int32_t 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_int32_t dst;
+{
+ send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS,
+ htonl(MROUTED_LEVEL), 0);
+}
+
+void ask2(dst)
+ u_int32_t 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_int32_t 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_int32_t 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_int32_t 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_int32_t 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_int32_t 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_int32_t 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_int32_t)*p++ << 24), a += ((u_int32_t)*p++ << 16),\
+ a += ((u_int32_t)*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_int32_t 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_int32_t 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_int32_t 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_int32_t 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_int32_t*)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_int32_t 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_int32_t*)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_int32_t addr;
+{
+ struct hostent *e;
+
+ e = gethostbyaddr((char *)&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_int32_t 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()
+{
+ time_t 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_int32_t 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;
+}
+
+
+int 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;
+#if (defined(BSD) && (BSD >= 199103))
+ addr.sin_len = sizeof addr;
+#endif
+ 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, RECV_BUF_SIZE,
+ 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 accept_leave_message()
+{
+}
+void accept_mtrace()
+{
+}
+void accept_membership_query()
+{
+}