/* Mapper for connections between MRouteD multicast routers.
* Written by Pavel Curtis <Pavel@PARC.Xerox.Com>
* $Id: mapper.c,v 1.4 1993/06/24 05:11:16 deering 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.
#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
{
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 */
typedef struct interface
{
u_long addr
; /* IP address of the interface in NET order */
Neighbor
*neighbors
; /* List of neighbors' IP addresses */
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 */
struct node
*alias
; /* If alias, to what? */
struct interface
*interfaces
; /* Else, neighbor data */
struct node
*left
, *right
;
u_long our_addr
, target_addr
= 0; /* in NET order */
int retries
= DEFAULT_RETRIES
;
int timeout
= DEFAULT_TIMEOUT
;
Node
*find_node(addr
, ptr
)
*ptr
= n
= (Node
*) malloc(sizeof(Node
));
} else if (addr
== n
->addr
)
return find_node(addr
, &(n
->left
));
return find_node(addr
, &(n
->right
));
Interface
*find_interface(addr
, node
)
for (ifc
= node
->u
.interfaces
; ifc
; ifc
= ifc
->next
)
ifc
= (Interface
*) malloc(sizeof(Interface
));
ifc
->next
= node
->u
.interfaces
;
node
->u
.interfaces
= ifc
;
Neighbor
*find_neighbor(addr
, node
)
for (ifc
= node
->u
.interfaces
; ifc
; ifc
= ifc
->next
) {
for (nb
= ifc
->neighbors
; nb
; nb
= nb
->next
)
* 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
)
case 0: if (severity
> LOG_WARNING
) return;
case 1: if (severity
> LOG_NOTICE
) return;
case 2: if (severity
> LOG_INFO
) return;
if (severity
== LOG_WARNING
)
strcat(fmt
, "warning - ");
strncat(fmt
, format
, 80);
fprintf(stderr
, fmt
, a
, b
, c
, d
, e
);
else if (syserr
< sys_nerr
)
fprintf(stderr
, ": %s\n", sys_errlist
[syserr
]);
fprintf(stderr
, ": errno %d\n", syserr
);
* Send a neighbors-list request.
send_igmp(our_addr
, dst
, IGMP_DVMRP
, DVMRP_ASK_NEIGHBORS
,
htonl(MROUTED_LEVEL
), 0);
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
)
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
)
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
)
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
)
"ignoring spurious DVMRP neighbor request from %s to %s",
inet_fmt(src
, s1
), inet_fmt(dst
, s2
));
void accept_neighbor_request2(src
, dst
)
"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
)
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 */
#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 */
node
->version
= ntohl(level
);
fprintf(stderr
, " datalen = %d\n", datalen
);
for (i
= 0; i
< datalen
; i
++) {
fprintf(stderr
, " %02x", p
[i
]);
if ((datalen
& 0xF) != 0xF)
while (datalen
> 0) { /* loop through interfaces */
u_char metric
, threshold
, ncount
;
log(LOG_WARNING
, 0, "received truncated interface record from %s",
ifc_addr
= htonl(ifc_addr
);
/* Fix up any alias information */
ifc_node
= find_node(ifc_addr
, &routers
);
if (ifc_node
->tries
== 0) { /* new node */
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
;
/* 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
) {
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
)
"inconsistent %s for neighbor %s of %s",
inet_fmt(nb_i
->addr
, s1
),
inet_fmt(node
->addr
, s2
));
if (!nb_n
) { /* no match for this neighbor yet */
nb_i
->next
= ifc_n
->neighbors
;
next_ifc_i
= ifc_i
->next
;
ifc_node
->u
.alias
= node
;
ifc
= find_interface(ifc_addr
, node
);
old_neighbors
= ifc
->neighbors
;
/* Add the neighbors for this interface */
log(LOG_WARNING
, 0, "received truncated neighbor list from %s",
neighbor
= htonl(neighbor
);
for (nb
= old_neighbors
; nb
; nb
= nb
->next
)
if (nb
->addr
== neighbor
) {
if (metric
!= nb
->metric
|| threshold
!= nb
->threshold
)
"inconsistent %s for neighbor %s of %s",
inet_fmt(nb
->addr
, s1
), inet_fmt(node
->addr
, s2
));
nb
= (Neighbor
*) malloc(sizeof(Neighbor
));
nb
->next
= ifc
->neighbors
;
nb
->threshold
= threshold
;
n_node
= find_node(neighbor
, &routers
);
if (n_node
->tries
== 0 && !target_addr
) { /* it's a new router */
void accept_neighbors2(src
, dst
, p
, 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 */
while (datalen
> 0) { /* loop through interfaces */
u_char metric
, threshold
, ncount
, flags
;
log(LOG_WARNING
, 0, "received truncated interface record from %s",
/* Fix up any alias information */
ifc_node
= find_node(ifc_addr
, &routers
);
if (ifc_node
->tries
== 0) { /* new node */
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
;
/* 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
) {
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
)
"inconsistent %s for neighbor %s of %s",
inet_fmt(nb_i
->addr
, s1
),
inet_fmt(node
->addr
, s2
));
if (!nb_n
) { /* no match for this neighbor yet */
nb_i
->next
= ifc_n
->neighbors
;
next_ifc_i
= ifc_i
->next
;
ifc_node
->u
.alias
= node
;
ifc
= find_interface(ifc_addr
, node
);
old_neighbors
= ifc
->neighbors
;
/* Add the neighbors for this interface */
log(LOG_WARNING
, 0, "received truncated neighbor list from %s",
/* make leaf nets point to themselves */
for (nb
= old_neighbors
; nb
; nb
= nb
->next
)
if (nb
->addr
== neighbor
) {
if (metric
!= nb
->metric
|| threshold
!= nb
->threshold
)
"inconsistent %s for neighbor %s of %s",
inet_fmt(nb
->addr
, s1
), inet_fmt(node
->addr
, s2
));
nb
= (Neighbor
*) malloc(sizeof(Neighbor
));
nb
->next
= ifc
->neighbors
;
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 */
log(LOG_NOTICE
, 0, "network marked down...");
result
= retry_requests(node
->left
);
if (node
->tries
> 0 && node
->tries
< retries
) {
return retry_requests(node
->right
) || result
;
e
= gethostbyaddr((char *)&addr
, sizeof(addr
), AF_INET
);
return e
? e
->h_name
: 0;
addr
= inet_fmt(node
->addr
, s1
);
|| (node
->tries
>= 0 && node
->u
.interfaces
)
&& node
->u
.alias
->tries
>= 0
&& node
->u
.alias
->u
.interfaces
)) {
if (show_names
&& (name
= inet_name(node
->addr
)))
printf("%s (%s):", addr
, name
);
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");
printf(" <v%d.%d>", node
->version
& 0xff,
(node
->version
>> 8) & 0xff);
for (ifc
= node
->u
.interfaces
; ifc
; ifc
= ifc
->next
) {
char *ifc_name
= inet_fmt(ifc
->addr
, s1
);
int ifc_len
= strlen(ifc_name
);
printf(" %s:", ifc_name
);
for (nb
= ifc
->neighbors
; nb
; nb
= nb
->next
) {
printf("%*s", ifc_len
+ 5, "");
printf(" %s", inet_fmt(nb
->addr
, s1
));
if (show_names
&& (name
= inet_name(nb
->addr
)))
printf(" [%d/%d", nb
->metric
, nb
->threshold
);
u_short flags
= nb
->flags
;
if (flags
& DVMRP_NF_TUNNEL
)
if (flags
& DVMRP_NF_SRCRT
)
if (flags
& DVMRP_NF_QUERIER
)
if (flags
& DVMRP_NF_DISABLED
)
if (flags
& DVMRP_NF_DOWN
)
char *graph_name(addr
, buf
)
if (show_names
&& (name
= inet_name(addr
)))
printf(" %d {$ NP %d0 %d0 $} \"%s%s\" \n",
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
);
nb_node
= nb_node
->u
.alias
;
(!(nb2
= find_neighbor(node
->addr
, nb_node
))
|| node
->addr
< nb_node
->addr
)) {
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
)
nb
->flags
& DVMRP_NF_SRCRT
? "" :
nb
->flags
& DVMRP_NF_TUNNEL
? "E" : "P",
nb
->flags
& DVMRP_NF_DOWN
? "D" : "");
graph_edges(node
->right
);
elide_aliases(node
->left
);
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
);
nb
->addr
= nb_node
->u
.alias
->addr
;
elide_aliases(node
->right
);
char *nowstr
= ctime(&now
);
nowstr
[24] = '\0'; /* Kill the newline at the end */
printf("GRAPH \"Multicast Router Connectivity: %s\" = UNDIRECTED\n",
int get_number(var
, deflt
, pargv
, pargc
)
if ((*pargv
)[0][2] == '\0') { /* Get the value from the next argument */
if (*pargc
> 1 && isdigit((*pargv
)[1][0])) {
*var
= atoi((*pargv
)[0]);
} else { /* Get value from the rest of this argument */
if (isdigit((*pargv
)[0][2])) {
*var
= atoi((*pargv
)[0] + 2);
struct hostent
*e
= gethostbyname(name
);
memcpy(&addr
, e
->h_addr_list
[0], e
->h_length
);
int flood
= FALSE
, graph
= FALSE
;
setvbuf(stderr
, NULL
, _IOLBF
, 0);
fprintf(stderr
, "must be root\n");
while (argc
> 0 && argv
[0][0] == '-') {
if (!get_number(&debug
, DEFAULT_DEBUG
, &argv
, &argc
))
if (!get_number(&retries
, -1, &argv
, &argc
))
if (!get_number(&timeout
, -1, &argv
, &argc
))
"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");
} else if (argc
== 1 && !(target_addr
= host_addr(argv
[0]))) {
fprintf(stderr
, "Unknown host: %s\n", argv
[0]);
fprintf(stderr
, "Debug level %u\n", debug
);
{ /* Find a good local address for us. */
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");
our_addr
= addr
.sin_addr
.s_addr
;
/* Send initial seed message to all local routers */
ask(target_addr
? target_addr
: allhosts_group
);
Node
*n
= find_node(target_addr
, &routers
);
int count
, recvlen
, dummy
= 0;
FD_SET(igmp_socket
, &fds
);
count
= select(igmp_socket
+ 1, &fds
, 0, 0, &tv
);
log(LOG_DEBUG
, 0, "Timed out receiving neighbor lists");
if (retry_requests(routers
))
recvlen
= recvfrom(igmp_socket
, recv_buf
, sizeof(recv_buf
),
printf("Multicast Router Connectivity:\n\n");