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