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.3 (Berkeley) 04/28/95";
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
main(argc,argv)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 memset(&shorttime, 0, sizeof(shorttime));
89 shorttime.tv_usec = STIME;
90 memset(&sigact, 0, 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
query(host)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 memset(&router, 0, 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 memmove(&router.sin_addr, hp->h_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 (memcmp(&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
timeout()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