xref: /386bsd/usr/src/libexec/routed/query/query.c (revision a2142627)
1 /*-
2  * Copyright (c) 1982, 1986 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 char copyright[] =
36 "@(#) Copyright (c) 1982, 1986 The Regents of the University of California.\n\
37  All rights reserved.\n";
38 #endif /* not lint */
39 
40 #ifndef lint
41 static char sccsid[] = "@(#)query.c	5.13 (Berkeley) 4/16/91";
42 #endif /* not lint */
43 
44 #include <sys/param.h>
45 #include <sys/protosw.h>
46 #include <sys/socket.h>
47 #include <sys/time.h>
48 #include <signal.h>
49 #include <netinet/in.h>
50 #include <protocols/routed.h>
51 #include <arpa/inet.h>
52 #include <netdb.h>
53 #include <errno.h>
54 #include <unistd.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 
59 #define	WTIME	5		/* Time to wait for all responses */
60 #define	STIME	500000		/* usec to wait for another response */
61 
62 int	s;
63 int	timedout;
64 void	timeout();
65 char	packet[MAXPACKETSIZE];
66 int	nflag;
67 
main(argc,argv)68 main(argc, argv)
69 	int argc;
70 	char *argv[];
71 {
72 	extern char *optarg;
73 	extern int optind;
74 	int ch, cc, count, bits;
75 	struct sockaddr from;
76 	int fromlen = sizeof(from), size = 32*1024;
77 	struct timeval shorttime;
78 
79 	while ((ch = getopt(argc, argv, "n")) != EOF)
80 		switch((char)ch) {
81 		case 'n':
82 			nflag++;
83 			break;
84 		case '?':
85 		default:
86 			goto usage;
87 		}
88 	argv += optind;
89 
90 	if (!*argv) {
91 usage:		printf("usage: query [-n] hosts...\n");
92 		exit(1);
93 	}
94 
95 	s = socket(AF_INET, SOCK_DGRAM, 0);
96 	if (s < 0) {
97 		perror("socket");
98 		exit(2);
99 	}
100 	if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) < 0)
101 		perror("setsockopt SO_RCVBUF");
102 
103 	while (*argv) {
104 		query(*argv++);
105 		count++;
106 	}
107 
108 	/*
109 	 * Listen for returning packets;
110 	 * may be more than one packet per host.
111 	 */
112 	bits = 1 << s;
113 	bzero(&shorttime, sizeof(shorttime));
114 	shorttime.tv_usec = STIME;
115 	signal(SIGALRM, timeout);
116 	alarm(WTIME);
117 	while ((count > 0 && !timedout) ||
118 	    select(20, (fd_set *)&bits, NULL, NULL, &shorttime) > 0) {
119 		cc = recvfrom(s, packet, sizeof (packet), 0,
120 		  &from, &fromlen);
121 		if (cc <= 0) {
122 			if (cc < 0) {
123 				if (errno == EINTR)
124 					continue;
125 				perror("recvfrom");
126 				(void) close(s);
127 				exit(1);
128 			}
129 			continue;
130 		}
131 		rip_input(&from, cc);
132 		count--;
133 	}
134 	exit (count > 0 ? count : 0);
135 }
136 
query(host)137 query(host)
138 	char *host;
139 {
140 	struct sockaddr_in router;
141 	register struct rip *msg = (struct rip *)packet;
142 	struct hostent *hp;
143 	struct servent *sp;
144 
145 	bzero((char *)&router, sizeof (router));
146 	router.sin_family = AF_INET;
147 	router.sin_addr.s_addr = inet_addr(host);
148 	if (router.sin_addr.s_addr == -1) {
149 		hp = gethostbyname(host);
150 		if (hp == NULL) {
151 			fprintf(stderr, "query: %s: ", host);
152 			herror((char *)NULL);
153 			exit(1);
154 		}
155 		bcopy(hp->h_addr, &router.sin_addr, hp->h_length);
156 	}
157 	sp = getservbyname("router", "udp");
158 	if (sp == 0) {
159 		printf("udp/router: service unknown\n");
160 		exit(1);
161 	}
162 	router.sin_port = sp->s_port;
163 	msg->rip_cmd = RIPCMD_REQUEST;
164 	msg->rip_vers = RIPVERSION;
165 	msg->rip_nets[0].rip_dst.sa_family = htons(AF_UNSPEC);
166 	msg->rip_nets[0].rip_metric = htonl(HOPCNT_INFINITY);
167 	if (sendto(s, packet, sizeof (struct rip), 0,
168 	  (struct sockaddr *)&router, sizeof(router)) < 0)
169 		perror(host);
170 }
171 
172 /*
173  * Handle an incoming routing packet.
174  */
175 rip_input(from, size)
176 	struct sockaddr_in *from;
177 	int size;
178 {
179 	register struct rip *msg = (struct rip *)packet;
180 	register struct netinfo *n;
181 	char *name;
182 	int lna, net, subnet;
183 	struct hostent *hp;
184 	struct netent *np;
185 
186 	if (msg->rip_cmd != RIPCMD_RESPONSE)
187 		return;
188 	printf("%d bytes from ", size);
189 	if (nflag)
190 		printf("%s:\n", inet_ntoa(from->sin_addr));
191 	else {
192 		hp = gethostbyaddr((char *)&from->sin_addr,
193 		    sizeof (struct in_addr), AF_INET);
194 		name = hp == 0 ? "???" : hp->h_name;
195 		printf("%s(%s):\n", name, inet_ntoa(from->sin_addr));
196 	}
197 	size -= sizeof (int);
198 	n = msg->rip_nets;
199 	while (size > 0) {
200 	    if (size < sizeof (struct netinfo))
201 		    break;
202 	    if (msg->rip_vers > 0) {
203 		    n->rip_dst.sa_family =
204 			    ntohs(n->rip_dst.sa_family);
205 		    n->rip_metric = ntohl(n->rip_metric);
206 	    }
207 	    switch (n->rip_dst.sa_family) {
208 
209 	    case AF_INET:
210 		{ register struct sockaddr_in *sin;
211 
212 		sin = (struct sockaddr_in *)&n->rip_dst;
213 		net = inet_netof(sin->sin_addr);
214 		subnet = inet_subnetof(sin->sin_addr);
215 		lna = inet_lnaof(sin->sin_addr);
216 		name = "???";
217 		if (!nflag) {
218 			if (sin->sin_addr.s_addr == 0)
219 				name = "default";
220 			else if (lna == INADDR_ANY) {
221 				np = getnetbyaddr(net, AF_INET);
222 				if (np)
223 					name = np->n_name;
224 				else if (net == 0)
225 					name = "default";
226 			} else if ((lna & 0xff) == 0 &&
227 			    (np = getnetbyaddr(subnet, AF_INET))) {
228 				struct in_addr subnaddr, inet_makeaddr();
229 
230 				subnaddr = inet_makeaddr(subnet, INADDR_ANY);
231 				if (bcmp(&sin->sin_addr, &subnaddr,
232 				    sizeof(subnaddr)) == 0)
233 					name = np->n_name;
234 				else
235 					goto host;
236 			} else {
237 	host:
238 				hp = gethostbyaddr((char *)&sin->sin_addr,
239 				    sizeof (struct in_addr), AF_INET);
240 				if (hp)
241 					name = hp->h_name;
242 			}
243 			printf("\t%-17s metric %2d name %s\n",
244 				inet_ntoa(sin->sin_addr), n->rip_metric, name);
245 		} else
246 			printf("\t%-17s metric %2d\n",
247 				inet_ntoa(sin->sin_addr), n->rip_metric);
248 		break;
249 		}
250 
251 	    default:
252 		{ u_short *p = (u_short *)n->rip_dst.sa_data;
253 
254 		printf("\t(af %d) %x %x %x %x %x %x %x, metric %d\n",
255 		    p[0], p[1], p[2], p[3], p[4], p[5], p[6],
256 		    n->rip_dst.sa_family,
257 		    n->rip_metric);
258 		break;
259 		}
260 
261 	    }
262 	    size -= sizeof (struct netinfo), n++;
263 	}
264 }
265 
266 void
timeout()267 timeout()
268 {
269 	timedout = 1;
270 }
271 
272 /*
273  * Return the possible subnetwork number from an internet address.
274  * SHOULD FIND OUT WHETHER THIS IS A LOCAL NETWORK BEFORE LOOKING
275  * INSIDE OF THE HOST PART.  We can only believe this if we have other
276  * information (e.g., we can find a name for this number).
277  */
278 inet_subnetof(in)
279 	struct in_addr in;
280 {
281 	register u_long i = ntohl(in.s_addr);
282 
283 	if (IN_CLASSA(i))
284 		return ((i & IN_CLASSB_NET) >> IN_CLASSB_NSHIFT);
285 	else if (IN_CLASSB(i))
286 		return ((i & IN_CLASSC_NET) >> IN_CLASSC_NSHIFT);
287 	else
288 		return ((i & 0xffffffc0) >> 28);
289 }
290