xref: /original-bsd/sbin/routed/query/query.c (revision b4971bb3)
1 /*-
2  * Copyright (c) 1982, 1986, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1982, 1986, 1993\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)query.c	8.1 (Berkeley) 06/05/93";
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 	struct sigaction sigact;
51 	int fromlen = sizeof(from), size = 32*1024;
52 	struct timeval shorttime;
53 
54 	while ((ch = getopt(argc, argv, "n")) != EOF)
55 		switch (ch) {
56 		case 'n':
57 			nflag++;
58 			break;
59 		case '?':
60 		default:
61 			goto usage;
62 		}
63 	argv += optind;
64 
65 	if (!*argv) {
66 usage:		printf("usage: query [-n] hosts...\n");
67 		exit(1);
68 	}
69 
70 	s = socket(AF_INET, SOCK_DGRAM, 0);
71 	if (s < 0) {
72 		perror("socket");
73 		exit(2);
74 	}
75 	if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) < 0)
76 		perror("setsockopt SO_RCVBUF");
77 
78 	while (*argv) {
79 		query(*argv++);
80 		count++;
81 	}
82 
83 	/*
84 	 * Listen for returning packets;
85 	 * may be more than one packet per host.
86 	 */
87 	bits = 1 << s;
88 	bzero(&shorttime, sizeof(shorttime));
89 	shorttime.tv_usec = STIME;
90 	bzero(&sigact, sizeof(sigact));
91 	sigact.sa_handler = timeout;
92 	/*sigact.sa_flags = 0;		/* no restart */
93 	if (sigaction(SIGALRM, &sigact, (struct sigaction *)NULL) == -1)
94 		perror("sigaction");
95 	alarm(WTIME);
96 	while ((count > 0 && !timedout) ||
97 	    select(20, (fd_set *)&bits, NULL, NULL, &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 	  (struct sockaddr *)&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((char *)&from->sin_addr,
172 		    sizeof (struct in_addr), 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((char *)&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 void
246 timeout()
247 {
248 	timedout = 1;
249 }
250 
251 /*
252  * Return the possible subnetwork number from an internet address.
253  * SHOULD FIND OUT WHETHER THIS IS A LOCAL NETWORK BEFORE LOOKING
254  * INSIDE OF THE HOST PART.  We can only believe this if we have other
255  * information (e.g., we can find a name for this number).
256  */
257 inet_subnetof(in)
258 	struct in_addr in;
259 {
260 	register u_long i = ntohl(in.s_addr);
261 
262 	if (IN_CLASSA(i))
263 		return ((i & IN_CLASSB_NET) >> IN_CLASSB_NSHIFT);
264 	else if (IN_CLASSB(i))
265 		return ((i & IN_CLASSC_NET) >> IN_CLASSC_NSHIFT);
266 	else
267 		return ((i & 0xffffffc0) >> 28);
268 }
269