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.11 (Berkeley) 10/10/88"; 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 <netinet/in.h> 33 #include <errno.h> 34 #include <stdio.h> 35 #include <netdb.h> 36 #include <protocols/routed.h> 37 38 #define WTIME 5 /* Time to wait for all responses */ 39 #define STIME 500000 /* usec to wait for another response */ 40 41 int s; 42 int timedout, timeout(); 43 char packet[MAXPACKETSIZE]; 44 extern int errno; 45 int nflag; 46 47 main(argc, argv) 48 int argc; 49 char *argv[]; 50 { 51 extern char *optarg; 52 extern int optind; 53 int ch, cc, count, bits; 54 struct sockaddr from; 55 int fromlen = sizeof(from), size = 32*1024; 56 struct timeval shorttime; 57 58 while ((ch = getopt(argc, argv, "n")) != EOF) 59 switch((char)ch) { 60 case 'n': 61 nflag++; 62 break; 63 case '?': 64 default: 65 goto usage; 66 } 67 argv += optind; 68 69 if (!*argv) { 70 usage: printf("usage: query [-n] hosts...\n"); 71 exit(1); 72 } 73 74 s = socket(AF_INET, SOCK_DGRAM, 0); 75 if (s < 0) { 76 perror("socket"); 77 exit(2); 78 } 79 if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) < 0) 80 perror("setsockopt SO_RCVBUF"); 81 82 while (*argv) { 83 query(*argv++); 84 count++; 85 } 86 87 /* 88 * Listen for returning packets; 89 * may be more than one packet per host. 90 */ 91 bits = 1 << s; 92 bzero(&shorttime, sizeof(shorttime)); 93 shorttime.tv_usec = STIME; 94 signal(SIGALRM, timeout); 95 alarm(WTIME); 96 while ((count > 0 && !timedout) || 97 select(20, &bits, 0, 0, &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 &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(&from->sin_addr, sizeof (struct in_addr), 172 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(&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 timeout() 246 { 247 timedout = 1; 248 } 249 250 /* 251 * Return the possible subnetwork number from an internet address. 252 * SHOULD FIND OUT WHETHER THIS IS A LOCAL NETWORK BEFORE LOOKING 253 * INSIDE OF THE HOST PART. We can only believe this if we have other 254 * information (e.g., we can find a name for this number). 255 */ 256 inet_subnetof(in) 257 struct in_addr in; 258 { 259 register u_long i = ntohl(in.s_addr); 260 261 if (IN_CLASSA(i)) 262 return ((i & IN_CLASSB_NET) >> IN_CLASSB_NSHIFT); 263 else if (IN_CLASSB(i)) 264 return ((i & IN_CLASSC_NET) >> IN_CLASSC_NSHIFT); 265 else 266 return ((i & 0xffffffc0) >> 28); 267 } 268