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