1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 char copyright[] = 20 "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 21 All rights reserved.\n"; 22 #endif /* not lint */ 23 24 #ifndef lint 25 static char sccsid[] = "@(#)query.c 5.12 (Berkeley) 02/28/91"; 26 #endif /* not lint */ 27 28 #include <sys/param.h> 29 #include <sys/protosw.h> 30 #include <sys/socket.h> 31 #include <sys/time.h> 32 #include <signal.h> 33 #include <netinet/in.h> 34 #include <protocols/routed.h> 35 #include <arpa/inet.h> 36 #include <netdb.h> 37 #include <errno.h> 38 #include <unistd.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 43 #define WTIME 5 /* Time to wait for all responses */ 44 #define STIME 500000 /* usec to wait for another response */ 45 46 int s; 47 int timedout; 48 void timeout(); 49 char packet[MAXPACKETSIZE]; 50 int nflag; 51 52 main(argc, argv) 53 int argc; 54 char *argv[]; 55 { 56 extern char *optarg; 57 extern int optind; 58 int ch, cc, count, bits; 59 struct sockaddr from; 60 int fromlen = sizeof(from), size = 32*1024; 61 struct timeval shorttime; 62 63 while ((ch = getopt(argc, argv, "n")) != EOF) 64 switch((char)ch) { 65 case 'n': 66 nflag++; 67 break; 68 case '?': 69 default: 70 goto usage; 71 } 72 argv += optind; 73 74 if (!*argv) { 75 usage: printf("usage: query [-n] hosts...\n"); 76 exit(1); 77 } 78 79 s = socket(AF_INET, SOCK_DGRAM, 0); 80 if (s < 0) { 81 perror("socket"); 82 exit(2); 83 } 84 if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) < 0) 85 perror("setsockopt SO_RCVBUF"); 86 87 while (*argv) { 88 query(*argv++); 89 count++; 90 } 91 92 /* 93 * Listen for returning packets; 94 * may be more than one packet per host. 95 */ 96 bits = 1 << s; 97 bzero(&shorttime, sizeof(shorttime)); 98 shorttime.tv_usec = STIME; 99 signal(SIGALRM, timeout); 100 alarm(WTIME); 101 while ((count > 0 && !timedout) || 102 select(20, (fd_set *)&bits, NULL, NULL, &shorttime) > 0) { 103 cc = recvfrom(s, packet, sizeof (packet), 0, 104 &from, &fromlen); 105 if (cc <= 0) { 106 if (cc < 0) { 107 if (errno == EINTR) 108 continue; 109 perror("recvfrom"); 110 (void) close(s); 111 exit(1); 112 } 113 continue; 114 } 115 rip_input(&from, cc); 116 count--; 117 } 118 exit (count > 0 ? count : 0); 119 } 120 121 query(host) 122 char *host; 123 { 124 struct sockaddr_in router; 125 register struct rip *msg = (struct rip *)packet; 126 struct hostent *hp; 127 struct servent *sp; 128 129 bzero((char *)&router, sizeof (router)); 130 router.sin_family = AF_INET; 131 router.sin_addr.s_addr = inet_addr(host); 132 if (router.sin_addr.s_addr == -1) { 133 hp = gethostbyname(host); 134 if (hp == NULL) { 135 fprintf(stderr, "query: %s: ", host); 136 herror((char *)NULL); 137 exit(1); 138 } 139 bcopy(hp->h_addr, &router.sin_addr, hp->h_length); 140 } 141 sp = getservbyname("router", "udp"); 142 if (sp == 0) { 143 printf("udp/router: service unknown\n"); 144 exit(1); 145 } 146 router.sin_port = sp->s_port; 147 msg->rip_cmd = RIPCMD_REQUEST; 148 msg->rip_vers = RIPVERSION; 149 msg->rip_nets[0].rip_dst.sa_family = htons(AF_UNSPEC); 150 msg->rip_nets[0].rip_metric = htonl(HOPCNT_INFINITY); 151 if (sendto(s, packet, sizeof (struct rip), 0, 152 (struct sockaddr *)&router, sizeof(router)) < 0) 153 perror(host); 154 } 155 156 /* 157 * Handle an incoming routing packet. 158 */ 159 rip_input(from, size) 160 struct sockaddr_in *from; 161 int size; 162 { 163 register struct rip *msg = (struct rip *)packet; 164 register struct netinfo *n; 165 char *name; 166 int lna, net, subnet; 167 struct hostent *hp; 168 struct netent *np; 169 170 if (msg->rip_cmd != RIPCMD_RESPONSE) 171 return; 172 printf("%d bytes from ", size); 173 if (nflag) 174 printf("%s:\n", inet_ntoa(from->sin_addr)); 175 else { 176 hp = gethostbyaddr((char *)&from->sin_addr, 177 sizeof (struct in_addr), AF_INET); 178 name = hp == 0 ? "???" : hp->h_name; 179 printf("%s(%s):\n", name, inet_ntoa(from->sin_addr)); 180 } 181 size -= sizeof (int); 182 n = msg->rip_nets; 183 while (size > 0) { 184 if (size < sizeof (struct netinfo)) 185 break; 186 if (msg->rip_vers > 0) { 187 n->rip_dst.sa_family = 188 ntohs(n->rip_dst.sa_family); 189 n->rip_metric = ntohl(n->rip_metric); 190 } 191 switch (n->rip_dst.sa_family) { 192 193 case AF_INET: 194 { register struct sockaddr_in *sin; 195 196 sin = (struct sockaddr_in *)&n->rip_dst; 197 net = inet_netof(sin->sin_addr); 198 subnet = inet_subnetof(sin->sin_addr); 199 lna = inet_lnaof(sin->sin_addr); 200 name = "???"; 201 if (!nflag) { 202 if (sin->sin_addr.s_addr == 0) 203 name = "default"; 204 else if (lna == INADDR_ANY) { 205 np = getnetbyaddr(net, AF_INET); 206 if (np) 207 name = np->n_name; 208 else if (net == 0) 209 name = "default"; 210 } else if ((lna & 0xff) == 0 && 211 (np = getnetbyaddr(subnet, AF_INET))) { 212 struct in_addr subnaddr, inet_makeaddr(); 213 214 subnaddr = inet_makeaddr(subnet, INADDR_ANY); 215 if (bcmp(&sin->sin_addr, &subnaddr, 216 sizeof(subnaddr)) == 0) 217 name = np->n_name; 218 else 219 goto host; 220 } else { 221 host: 222 hp = gethostbyaddr((char *)&sin->sin_addr, 223 sizeof (struct in_addr), AF_INET); 224 if (hp) 225 name = hp->h_name; 226 } 227 printf("\t%-17s metric %2d name %s\n", 228 inet_ntoa(sin->sin_addr), n->rip_metric, name); 229 } else 230 printf("\t%-17s metric %2d\n", 231 inet_ntoa(sin->sin_addr), n->rip_metric); 232 break; 233 } 234 235 default: 236 { u_short *p = (u_short *)n->rip_dst.sa_data; 237 238 printf("\t(af %d) %x %x %x %x %x %x %x, metric %d\n", 239 p[0], p[1], p[2], p[3], p[4], p[5], p[6], 240 n->rip_dst.sa_family, 241 n->rip_metric); 242 break; 243 } 244 245 } 246 size -= sizeof (struct netinfo), n++; 247 } 248 } 249 250 void 251 timeout() 252 { 253 timedout = 1; 254 } 255 256 /* 257 * Return the possible subnetwork number from an internet address. 258 * SHOULD FIND OUT WHETHER THIS IS A LOCAL NETWORK BEFORE LOOKING 259 * INSIDE OF THE HOST PART. We can only believe this if we have other 260 * information (e.g., we can find a name for this number). 261 */ 262 inet_subnetof(in) 263 struct in_addr in; 264 { 265 register u_long i = ntohl(in.s_addr); 266 267 if (IN_CLASSA(i)) 268 return ((i & IN_CLASSB_NET) >> IN_CLASSB_NSHIFT); 269 else if (IN_CLASSB(i)) 270 return ((i & IN_CLASSC_NET) >> IN_CLASSC_NSHIFT); 271 else 272 return ((i & 0xffffffc0) >> 28); 273 } 274