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