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