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