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