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