1 /*- 2 * Copyright (c) 1982, 1986 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1982, 1986 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)query.c 5.14 (Berkeley) 07/28/91"; 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 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 bzero(&shorttime, sizeof(shorttime)); 89 shorttime.tv_usec = STIME; 90 bzero(&sigact, 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 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 bzero((char *)&router, 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 bcopy(hp->h_addr, &router.sin_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 (bcmp(&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 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