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