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