Commit 97c022f0 authored by Kristin Wright's avatar Kristin Wright

Initial version

parent ba7452fe
PROGS = cli serv
all: ${PROGS}
cli:
gcc -g -c -Wall cli.c
gcc -g -c -Wall get_ifi_info.c
gcc -g -c -Wall get_rtaddrs.c
gcc -g -c -Wall net_rt_iflist.c
gcc -g -c -Wall sock_ntop.c
gcc -g -c -Wall util.c
gcc -g -Wall -o cli cli.o get_ifi_info.o \
util.o sock_ntop.o net_rt_iflist.o \
get_rtaddrs.o
serv:
gcc -g -c -Wall serv_listen.c
gcc -g -c -Wall sock_ntop.c
gcc -g -c -Wall recvfromflags.c
gcc -g -c -Wall if_indextoname.c
gcc -g -c -Wall get_ifi_info.c
gcc -g -c -Wall get_rtaddrs.c
gcc -g -c -Wall net_rt_iflist.c
gcc -g -c -Wall recvfromflags.c
gcc -g -c -Wall reply.c
gcc -g -c -Wall serv.c
gcc -g -c -Wall util.c
gcc -g -c -Wall forw_requests.c
gcc -o serv serv.o serv_listen.o sock_ntop.o \
get_rtaddrs.o get_ifi_info.o util.o \
net_rt_iflist.o if_indextoname.o \
reply.o forw_requests.o recvfromflags.o
/*
* Copyright (c) 2000 The University of Utah and the Flux Group.
* All rights reserved.
*
* Permission to use, copy, modify and distribute this software is hereby
* granted provided that (1) source code retains these copyright, permission,
* and disclaimer notices, and (2) redistributions including binaries
* reproduce the notices in supporting documentation.
*
* THE UNIVERSITY OF UTAH ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. THE UNIVERSITY OF UTAH DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* ---------------------------
*
* Filename: cli.c
* -- Author: Kristin Wright <kwright@cs.utah.edu>
*
* ---------------------------
*
* $Id: cli.c,v 1.1 2000-07-06 17:42:35 kwright Exp $
*/
#include "discvr.h"
#include "packet.h"
#include "util.h"
u_char *
find_nodeID(void)
{
int i;
struct sockaddr *sa;
char *ptr;
u_char *myNodeIDtmp = 0;
struct ifi_info *ifi, *ifihead;
/*
* Get interface info for all inet4 interfaces
* and don't return aliases.
*/
for (ifihead = ifi = get_ifi_info(AF_INET, 0);
ifi != NULL; ifi = ifi->ifi_next) {
printf("%s: <", ifi->ifi_name);
if (ifi->ifi_flags & IFF_UP) printf("UP ");
if (ifi->ifi_flags & IFF_BROADCAST) printf("BCAST ");
if (ifi->ifi_flags & IFF_MULTICAST) printf("MCAST ");
if (ifi->ifi_flags & IFF_LOOPBACK) printf("LOOP ");
if (ifi->ifi_flags & IFF_POINTOPOINT) printf("P2P ");
printf(">\n");
if ( (i = ifi->ifi_hlen) > 0) {
ptr = ifi->ifi_haddr;
do {
printf("%s%x", (i == ifi->ifi_hlen) ? " " : ":", *ptr++);
} while (--i > 0);
}
/*
* We update myNodeIDtmp in block separate from above
* since the above is just a debug clause and may be
* compiled out eventually. -lkw
*/
if ( ifi->ifi_hlen > 0) {
myNodeIDtmp = max_haddr(myNodeIDtmp, ifi->ifi_haddr);
}
if ( (sa = ifi->ifi_addr) != NULL)
printf(" IP addr: %s\n", sock_ntop(sa, sa->sa_len));
if ( (sa = ifi->ifi_brdaddr) != NULL)
printf(" broadcast addr: %s\n", sock_ntop(sa, sa->sa_len));
if ( (sa = ifi->ifi_dstaddr) != NULL)
printf(" destination addr: %s\n", sock_ntop(sa, sa->sa_len));
}
fprintf(stderr, "My node id:");
print_nodeID(myNodeIDtmp);
return myNodeIDtmp;
}
void
make_inquiry(topd_inqid_t *tip)
{
struct timeval tv;
u_char *nid;
/* First goes the the time of day... */
if (gettimeofday(&tv, NULL) == -1) {
perror("Unable to get time-of-day.");
exit(1);
}
tip->tdi_tv.tv_sec = htonl(tv.tv_sec);
tip->tdi_tv.tv_usec = htonl(tv.tv_usec);
/* ...and now our nodeID */
nid = find_nodeID();
memcpy((void *)tip->tdi_nodeID, nid, ETHADDRSIZ);
}
void
cli(FILE *fp, int sockfd, const struct sockaddr *pservaddr, socklen_t servlen)
{
u_int32_t n;
char recvline[MAXLINE + 1];
topd_inqid_t ti;
make_inquiry(&ti);
sendto(sockfd, &ti, TOPD_INQ_SIZ, 0, pservaddr, servlen);
print_tdinq((char *)&ti);
n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);
print_tdreply(recvline);
}
int
main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
if (argc != 2) {
fprintf(stderr, "usage: cli <Server IPaddress>\n");
exit(1);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
cli(stdin, sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
exit(0);
}
#include <stdarg.h>
void
error_exit(char *fmt, ...)
{
va_list ap;
char *msg;
va_start(ap, fmt);
printf(
perror("Unable to get time-of-day.");
exit(1);
}
/*$Id: discvr.h,v 1.1 2000-07-06 17:42:35 kwright Exp $*/
#ifndef _TOPD_DISCVR_H_
#define _TOPD_DISCVR_H_
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <arpa/inet.h>
#define MAX_HOSTNAME 256
#define INET6_ADDRSTRLEN 46 /* Max size of IPv6 address string: */
#define SERV_PORT 9788 /* Server port */
#define IFHADDRSIZ 8 /* UNP recommends allowing for 64-bit EUI-64 in future */
#define ETHADDRSIZ 6 /* Cheat and use for for many MAC address sizes */
#define MAXLINE 4096 /* Max text line length; only
* needed until true packets are generated. -lkw
*/
#define print_nodeID(x) println_haddr((x), ETHADDRSIZ)
#define INCR_ALIGN(x,y) ((x) += (y); ALIGN(x);)
#define socklen_t unsigned int /* Length of sockaddr address */
/* The structure returned by recvfrom_flags() */
struct in_pktinfo {
int ipi_ifindex; /* received interface index */
struct in_addr ipi_addr; /* dst IPv4 address */
};
#define MY_IFF_RECVIF 0x1 /* receiving interface */
struct ifi_info {
char ifi_name[IFNAMSIZ]; /* interface name, null terminated */
u_char ifi_haddr[IFHADDRSIZ];/* hardware address */
u_short ifi_hlen; /* #bytes in hardware address: 0, 6, 8 */
short ifi_flags; /* IFF_xxx constants from <net/if.h> */
short ifi_myflags; /* our own IFI_xxx flags */
struct sockaddr *ifi_addr; /* primary address */
struct sockaddr *ifi_brdaddr;/* broadcast address */
struct sockaddr *ifi_dstaddr;/* destination address */
struct ifi_info *ifi_next; /* next of these structures */
struct topd_nborlist *ifi_nbors;/* neighbors */
};
/* Prototypes */
void
serv_listen(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen);
char *
forward_request(struct ifi_info *ifi, const struct in_pktinfo *pktinfo,
const char *mesg, const int mesglen);
struct ifi_info *
get_ifi_info(int, int);
void
free_ifi_info(struct ifi_info *);
ssize_t
recvfrom_flags(int, void *, size_t, int *, struct sockaddr *, socklen_t *,
struct in_pktinfo *);
char*
if_indextoname(unsigned int, char *);
char*
sock_ntop(const struct sockaddr *, socklen_t);
char*
net_rt_iflist(int, int, size_t *);
void
get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
u_int32_t
compose_reply(struct ifi_info *ifi, char *mesg, const int mesglen);
#endif /* _TOPD_DISCVR_H_ */
/*
* Copyright (c) 2000 The University of Utah and the Flux Group.
* All rights reserved.
*
* Permission to use, copy, modify and distribute this software is hereby
* granted provided that (1) source code retains these copyright, permission,
* and disclaimer notices, and (2) redistributions including binaries
* reproduce the notices in supporting documentation.
*
* THE UNIVERSITY OF UTAH ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. THE UNIVERSITY OF UTAH DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* ---------------------------
*
* Filename: forw_requests.c
* -- Author: Kristin Wright <kwright@cs.utah.edu>
*
* ---------------------------
*
* $Id: forw_requests.c,v 1.1 2000-07-06 17:42:36 kwright Exp $
*/
#include "discvr.h"
#include "packet.h"
#include "util.h"
/*
* Send a request on to each interface
*/
char recvbuf[BUFSIZ];
char *
forward_request(struct ifi_info *ifi, const struct in_pktinfo *pktinfo,
const char *mesg, int mesglen)
{
int s, n;
fd_set rset;
const int on = 1;
char ifname[IFNAMSIZ];
char *reply;
struct topd_nborlist *save;
struct sockaddr_in sin;
struct ifi_info *ifihead;
struct timeval tv;
for (ifihead = ifi = get_ifi_info(AF_INET, 0);
ifi != NULL; ifi = ifi->ifi_next) {
/*
* Don't send a message if the interface is down,
* a loopback interface, or it's the receiving
* interface.
*
* Add check for control net. -lkw
*/
if (ifi->ifi_flags & !IFF_UP ||
ifi->ifi_flags & IFF_LOOPBACK ||
strcmp(ifi->ifi_name, if_indextoname(pktinfo->ipi_ifindex, ifname)) == 0) {
ifi->ifi_myflags |= MY_IFF_RECVIF; /* may be unnec. -lkw */
continue;
}
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s == -1) {
perror("Unable to get socket");
exit(1);
}
if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) != 0) {
perror("setsockopt died.");
/* Do something intelligent. -lkw */
}
bzero(&sin, sizeof(sin));
sin.sin_len = htons(sizeof sin);
sin.sin_family = PF_INET;
sin.sin_port = htons(SERV_PORT);
/* sin.sin_addr.s_addr = inet_addr(BROADCAST_IP); */
/*
* struct sockaddr_in sin
* -> struct in_addr sin_addr
* -> u_int32_t s_addr
*
* struct sockaddr *ifi_brdaddr
* -> ifi_brdaddr->sa_data
*/
sin.sin_addr.s_addr = inet_addr(ifi->ifi_brdaddr->sa_data);
/*
* though sendto() returns the correct number of bytes,
* tcpdump is showing two packets for this one line. -lkw
*
* 60 eureka:testbed/discvr> tcpdump port 9877
* tcpdump: listening on fxp0
* 15:04:59.357514 eureka.cs.utah.edu.1192 > 155.99.212.255.9877: udp 15
* 15:04:59.357528 eureka.cs.utah.edu.1192 > 155.99.212.255.9877: udp 15
* 15:20:02.075858 kamas.cs.utah.edu.9877 > eureka.cs.utah.edu.1214: udp 15
*/
n = sendto(s, mesg, mesglen, 0,
(struct sockaddr *)&sin, sizeof(struct sockaddr_in));
fprintf(stderr, "sent: ");
print_tdinq(mesg);
if (n != mesglen) {
perror("Didn't send all of packet");
exit(1);
}
/*
* Can't wait forever because
* there may be either no nodes on this interface or
* the nodes that are there may not be responding.
* Also, the packet size *might* exceed our buffer size.
* Put in some mechanism to check. -lkw
*/
tv.tv_sec = 5;
tv.tv_usec = 0;
FD_ZERO(&rset);
FD_SET(s, &rset);
select(s + 1, &rset, NULL, NULL, &tv);
if (!FD_ISSET(s, &rset)) {
/* socket is not readable */
fprintf(stderr, "Socket not readable before timeout.\n");
continue;
}
n = recvfrom(s, recvbuf, BUFSIZ, 0, NULL, NULL);
/*
* Be sure to malloc enough space for all of the mesg.
* See note above about possible datagram truncation. -lkw
*/
save = ifi->ifi_nbors;
if ( (ifi->ifi_nbors = (struct topd_nborlist *)malloc(sizeof(struct topd_nborlist))) == NULL) {
perror("Not enough memory for neighbor list.");
exit(1);
}
if (( ifi->ifi_nbors->tdnbl_nbors = (u_char *)malloc(n)) == NULL) {
perror("Not enough memory for neighbor list.");
exit(1);
}
memcpy((void *)ifi->ifi_nbors->tdnbl_nbors, recvbuf, n);
ifi->ifi_nbors->tdnbl_next = save;
}
if ( (reply=(char *)malloc(BUFSIZ)) == NULL) {
fprintf(stderr, "Ran out of memory for reply mesg.\n");
exit(1);
}
n = compose_reply(ifihead, reply, BUFSIZ);
return reply;
}
/*
* This is a very slightly modified version of
* example code from Unix Netwok Programming, edition 2.
*/
/*
* need:
* - flags (IFF_UP, IFF_LOOPBACK)
* - index (really need string name which we get from if_indextoname()
* - broadcast addr (brdaddr)
* set:
* - nbors
*
*/
#include "discvr.h"
#define min(a,b) ((a) < (b) ? (a) : (b))
struct ifi_info *
get_ifi_info(int family, int doaliases)
{
int flags;
char *buf, *next, *lim;
size_t len;
struct if_msghdr *ifm;
struct ifa_msghdr *ifam;
struct sockaddr *sa, *rti_info[RTAX_MAX];
struct sockaddr_dl *sdl;
struct ifi_info *ifi, *ifisave, *ifihead, **ifipnext;
buf = net_rt_iflist(family, 0, &len);
ifihead = NULL;
ifipnext = &ifihead;
lim = buf + len;
for (next = buf; next < lim; next += ifm->ifm_msglen) {
ifm = (struct if_msghdr *) next;
if (ifm->ifm_type == RTM_IFINFO) {
if ( ((flags = ifm->ifm_flags) & IFF_UP) == 0)
continue; /* ignore if interface not up */
sa = (struct sockaddr *) (ifm + 1);
get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
if ( (sa = rti_info[RTAX_IFP]) != NULL) {
ifi = calloc(1, sizeof(struct ifi_info));
*ifipnext = ifi; /* prev points to this new one */
ifipnext = &ifi->ifi_next; /* ptr to next one goes here */
ifi->ifi_flags = flags;
if (sa->sa_family == AF_LINK) {
sdl = (struct sockaddr_dl *) sa;
if (sdl->sdl_nlen > 0)
snprintf(ifi->ifi_name, IFNAMSIZ, "%*s",
sdl->sdl_nlen, &sdl->sdl_data[0]);
else
snprintf(ifi->ifi_name, IFNAMSIZ, "index %d",
sdl->sdl_index);
if ( (ifi->ifi_hlen = sdl->sdl_alen) > 0)
memcpy(ifi->ifi_haddr, LLADDR(sdl),
min(IFHADDRSIZ, sdl->sdl_alen));
}
}
} else if (ifm->ifm_type == RTM_NEWADDR) {
if (ifi->ifi_addr) { /* already have an IP addr for i/f */
if (doaliases == 0)
continue;
/* 4we have a new IP addr for existing interface */
ifisave = ifi;
ifi = (struct ifi_info *)calloc(1, sizeof(struct ifi_info));
*ifipnext = ifi; /* prev points to this new one */
ifipnext = &ifi->ifi_next; /* ptr to next one goes here */
ifi->ifi_flags = ifisave->ifi_flags;
ifi->ifi_hlen = ifisave->ifi_hlen;
memcpy(ifi->ifi_name, ifisave->ifi_name, IFNAMSIZ);
memcpy(ifi->ifi_haddr, ifisave->ifi_haddr, IFHADDRSIZ);
}
ifam = (struct ifa_msghdr *) next;
sa = (struct sockaddr *) (ifam + 1);
get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
if ( (sa = rti_info[RTAX_IFA]) != NULL) {
ifi->ifi_addr = (struct sockaddr *)calloc(1, sa->sa_len);
memcpy(ifi->ifi_addr, sa, sa->sa_len);
}
if ((flags & IFF_BROADCAST) &&
(sa = rti_info[RTAX_BRD]) != NULL) {
ifi->ifi_brdaddr = (struct sockaddr *)calloc(1, sa->sa_len);
memcpy(ifi->ifi_brdaddr, sa, sa->sa_len);
}
if ((flags & IFF_POINTOPOINT) &&
(sa = rti_info[RTAX_BRD]) != NULL) {
ifi->ifi_dstaddr = (struct sockaddr *)calloc(1, sa->sa_len);
memcpy(ifi->ifi_dstaddr, sa, sa->sa_len);
}
} else {
fprintf(stderr, "unexpected message type %d", ifm->ifm_type);
exit(1);
}
}
/* "ifihead" points to the first structure in the linked list */
return(ifihead); /* ptr to first structure in linked list */
}
void
free_ifi_info(struct ifi_info *ifihead)
{
struct ifi_info *ifi, *ifinext;
for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
if (ifi->ifi_addr != NULL)
free(ifi->ifi_addr);
if (ifi->ifi_brdaddr != NULL)
free(ifi->ifi_brdaddr);
if (ifi->ifi_dstaddr != NULL)
free(ifi->ifi_dstaddr);
ifinext = ifi->ifi_next; /* can't fetch ifi_next after free() */
free(ifi); /* the ifi_info{} itself */
}
}
/*
* This is a very slightly modified version of
* example code from Unix Netwok Programming, edition 2.
*/
#include "discvr.h"
/*
* Round up 'a' to next multiple of 'size'
*/
#define ROUNDUP(a, size) (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
/*
* Step to next socket address structure;
* if sa_len is 0, assume it is sizeof(u_long).
*/
#define NEXT_SA(ap) ap = (struct sockaddr *) \
((caddr_t) ap + (ap->sa_len ? ROUNDUP(ap->sa_len, sizeof (u_long)) : \
sizeof(u_long)))
void
get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
{
int i;
for (i = 0; i < RTAX_MAX; i++) {
if (addrs & (1 << i)) {
rti_info[i] = sa;
NEXT_SA(sa);
} else
rti_info[i] = NULL;
}
}
/*
* This is a very slightly modified version of
* example code from Unix Netwok Programming, edition 2.
*/
#include "discvr.h"
#include <sys/sysctl.h>
char *
if_indextoname(unsigned int index, char *name)
{
char *buf, *next, *lim;
size_t len;
struct if_msghdr *ifm;
struct sockaddr *sa, *rti_info[RTAX_MAX];
struct sockaddr_dl *sdl;
if ( (buf = net_rt_iflist(0, index, &len)) == NULL)
return(NULL);
lim = buf + len;
for (next = buf; next < lim; next += ifm->ifm_msglen) {
ifm = (struct if_msghdr *) next;
if (ifm->ifm_type == RTM_IFINFO) {
sa = (struct sockaddr *) (ifm + 1);
get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
if ( (sa = rti_info[RTAX_IFP]) != NULL) {
if (sa->sa_family == AF_LINK) {
sdl = (struct sockaddr_dl *) sa;
if (sdl->sdl_index == index) {
strncpy(name, sdl->sdl_data, sdl->sdl_nlen);
name[sdl->sdl_nlen] = 0; /* null terminate */
free(buf);
return(name);
}
}
}
}
}
free(buf);
return(NULL); /* no match for index */
}
/*
* This is a very slightly modified version of
* example code from Unix Netwok Programming, edition 2.
*/
#include "discvr.h"
char *
net_rt_iflist(int family, int flags, size_t *lenp)
{
int mib[6];
char *buf;
mib[0] = CTL_NET;
mib[1] = AF_ROUTE;
mib[2] = 0;
mib[3] = family; /* only addresses of this family */
mib[4] = NET_RT_IFLIST;
mib[5] = flags; /* interface index, or 0 */
if (sysctl(mib, 6, NULL, lenp, NULL, 0) < 0)
return(NULL);
if ( (buf = malloc(*lenp)) == NULL)
return(NULL);
if (sysctl(mib, 6, buf, lenp, NULL, 0) < 0)
return(NULL);
return(buf);
}
/*
* Copyright (c) 2000 The University of Utah and the Flux Group.
* All rights reserved.
*
* Permission to use, copy, modify and distribute this software is hereby
* granted provided that (1) source code retains these copyright, permission,
* and disclaimer notices, and (2) redistributions including binaries
* reproduce the notices in supporting documentation.
*
* THE UNIVERSITY OF UTAH ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. THE UNIVERSITY OF UTAH DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* ---------------------------
*
* Filename: packet.h
* -- Author: Kristin Wright <kwright@cs.utah.edu>
*
* ---------------------------
*
* $Id: packet.h,v 1.1 2000-07-06 17:42:37 kwright Exp $
*/
#ifndef _TOPD_PACKET_H_
#define _TOPD_PACKET_H_
#include "discvr.h"
/*
* Node IDs are the highest MAC address on the machine.
* The easiest but not the most portable thing to
* do is assume a 6-byte hardware address. This isn't
* completely ridiculous as most of this tool's
* target platforms use ethernet.
*
* typedef u_char topd_nodeID_t[ETHADDRSIZ];
*/
/*
* Inquiry packet has only a unique Inquiry ID
* comprised of [timestamp, sender-nodeID] pair. Timestamps
* are struct timevals returned by gettimeofday().
*/
typedef struct topd_inqid {
struct timeval tdi_tv;
u_char tdi_nodeID[ETHADDRSIZ];
} topd_inqid_t;
#define TOPD_INQ_SIZ ALIGN(sizeof(struct topd_inqid))
/*
* Neighbor (reply) packets consist of
*
* [Neighbor ID, Route]
*
* pairs. Routes identify the interface through which
* the node can reach the neighbor. These interfaces
* are not necessarily local. Rather, they are
* interfaces belonging to the neighbor's parent.
*/
struct topd_nbor {