xref: /csrg-svn/sbin/routed/query/query.c (revision 22643)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)query.c	5.1 (Berkeley) 06/07/85";
9 #endif not lint
10 
11 #include <sys/param.h>
12 #include <sys/protosw.h>
13 #include <sys/socket.h>
14 #include <sys/time.h>
15 #include <netinet/in.h>
16 #include <errno.h>
17 #include <stdio.h>
18 #include <netdb.h>
19 #include "../protocol.h"
20 
21 #define	WTIME	5		/* Time to wait for responses */
22 
23 int	s;
24 int	timedout, timeout();
25 char	packet[MAXPACKETSIZE];
26 extern int errno;
27 
28 main(argc, argv)
29 	int argc;
30 	char *argv[];
31 {
32 	int cc, count, bits;
33 	struct sockaddr from;
34 	int fromlen = sizeof(from);
35 	struct timeval notime;
36 
37 	if (argc < 2) {
38 		printf("usage: query hosts...\n");
39 		exit(1);
40 	}
41 	s = socket(AF_INET, SOCK_DGRAM, 0);
42 	if (s < 0) {
43 		perror("socket");
44 		exit(2);
45 	}
46 
47 	argv++, argc--;
48 	count = argc;
49 	while (argc > 0) {
50 		query(*argv);
51 		argv++, argc--;
52 	}
53 
54 	/*
55 	 * Listen for returning packets;
56 	 * may be more than one packet per host.
57 	 */
58 	bits = 1 << s;
59 	bzero(&notime, sizeof(notime));
60 	signal(SIGALRM, timeout);
61 	alarm(WTIME);
62 	while ((count > 0 && !timedout) ||
63 	    select(20, &bits, 0, 0, &notime) > 0) {
64 		cc = recvfrom(s, packet, sizeof (packet), 0,
65 		  &from, &fromlen);
66 		if (cc <= 0) {
67 			if (cc < 0) {
68 				if (errno == EINTR)
69 					continue;
70 				perror("recvfrom");
71 				(void) close(s);
72 				exit(1);
73 			}
74 			continue;
75 		}
76 		rip_input(&from, cc);
77 		count--;
78 	}
79 }
80 
81 query(host)
82 	char *host;
83 {
84 	struct sockaddr_in router;
85 	register struct rip *msg = (struct rip *)packet;
86 	struct hostent *hp;
87 	struct servent *sp;
88 
89 	bzero((char *)&router, sizeof (router));
90 	hp = gethostbyname(host);
91 	if (hp == 0) {
92 		printf("%s: unknown\n", host);
93 		exit(1);
94 	}
95 	bcopy(hp->h_addr, &router.sin_addr, hp->h_length);
96 	router.sin_family = AF_INET;
97 	sp = getservbyname("router", "udp");
98 	if (sp == 0) {
99 		printf("udp/router: service unknown\n");
100 		exit(1);
101 	}
102 	router.sin_port = sp->s_port;
103 	msg->rip_cmd = RIPCMD_REQUEST;
104 	msg->rip_vers = RIPVERSION;
105 	msg->rip_nets[0].rip_dst.sa_family = htons(AF_UNSPEC);
106 	msg->rip_nets[0].rip_metric = htonl(HOPCNT_INFINITY);
107 	if (sendto(s, packet, sizeof (struct rip), 0,
108 	  &router, sizeof(router)) < 0)
109 		perror(host);
110 }
111 
112 /*
113  * Handle an incoming routing packet.
114  */
115 rip_input(from, size)
116 	struct sockaddr_in *from;
117 	int size;
118 {
119 	register struct rip *msg = (struct rip *)packet;
120 	struct netinfo *n;
121 	char *name;
122 	int lna, net, subnet;
123 	struct hostent *hp;
124 	struct netent *np;
125 
126 	if (msg->rip_cmd != RIPCMD_RESPONSE)
127 		return;
128 	hp = gethostbyaddr(&from->sin_addr, sizeof (struct in_addr), AF_INET);
129 	name = hp == 0 ? "???" : hp->h_name;
130 	printf("from %s(%s):\n", name, inet_ntoa(from->sin_addr));
131 	size -= sizeof (int);
132 	n = msg->rip_nets;
133 	while (size > 0) {
134 		register struct sockaddr_in *sin;
135 
136 		if (size < sizeof (struct netinfo))
137 			break;
138 		if (msg->rip_vers > 0) {
139 			n->rip_dst.sa_family =
140 				ntohs(n->rip_dst.sa_family);
141 			n->rip_metric = ntohl(n->rip_metric);
142 		}
143 		sin = (struct sockaddr_in *)&n->rip_dst;
144 		net = inet_netof(sin->sin_addr);
145 		subnet = inet_subnetof(sin->sin_addr);
146 		lna = inet_lnaof(sin->sin_addr);
147 		name = "???";
148 		if (lna == INADDR_ANY) {
149 			np = getnetbyaddr(net, AF_INET);
150 			if (np)
151 				name = np->n_name;
152 			else if (net == 0)
153 				name = "default";
154 		} else if ((subnet != net) && ((lna & 0xff) == 0) &&
155 		    (np = getnetbyaddr(subnet, AF_INET))) {
156 			struct in_addr subnaddr, inet_makeaddr();
157 
158 			subnaddr = inet_makeaddr(subnet, INADDR_ANY);
159 			if (bcmp(&sin->sin_addr, &subnaddr, sizeof(subnaddr)) == 0)
160 				name = np->n_name;
161 			else
162 				goto host;
163 		} else {
164 host:
165 			hp = gethostbyaddr(&sin->sin_addr,
166 			    sizeof (struct in_addr), AF_INET);
167 			if (hp)
168 				name = hp->h_name;
169 		}
170 		printf("\t%s(%s), metric %d\n", name,
171 			inet_ntoa(sin->sin_addr), n->rip_metric);
172 		size -= sizeof (struct netinfo), n++;
173 	}
174 }
175 
176 timeout()
177 {
178 	timedout = 1;
179 }
180 
181 /*
182  * Return the possible subnetwork number from an internet address.
183  * If the address is of the form of a subnet address (most significant
184  * bit of the host part is set), believe the subnet exists.
185  * Otherwise, return the network number.
186  * SHOULD FIND OUT WHETHER THIS IS A LOCAL NETWORK BEFORE LOOKING
187  * INSIDE OF THE HOST PART.  We can only believe this if we have other
188  * information (e.g., we can find a name for this number).
189  */
190 inet_subnetof(in)
191 	struct in_addr in;
192 {
193 	register u_long i = ntohl(in.s_addr);
194 
195 	if (IN_CLASSA(i)) {
196 		if (IN_SUBNETA(i))
197 			return ((i & IN_CLASSA_SUBNET) >> IN_CLASSA_SUBNSHIFT);
198 		else
199 			return ((i & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT);
200 	} else if (IN_CLASSB(i)) {
201 		if (IN_SUBNETB(i))
202 			return ((i & IN_CLASSB_SUBNET) >> IN_CLASSB_SUBNSHIFT);
203 		else
204 			return ((i & IN_CLASSB_NET) >> IN_CLASSB_NSHIFT);
205 	} else
206 		return ((i & IN_CLASSC_NET) >> IN_CLASSC_NSHIFT);
207 }
208