1 /*- 2 * Copyright 2001, David Leonard. All rights reserved. 3 * Redistribution and use in source and binary forms with or without 4 * modification are permitted provided that this notice is preserved. 5 * This software is provided ``as is'' without express or implied warranty. 6 * 7 * $OpenBSD: list.c,v 1.5 2007/09/04 22:39:31 hshoexer Exp $ 8 */ 9 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <netdb.h> 14 #include <unistd.h> 15 #include <errno.h> 16 #include <err.h> 17 18 #include <sys/types.h> 19 #include <sys/socket.h> 20 #include <sys/sockio.h> 21 #include <sys/ioctl.h> 22 23 #include <netinet/in.h> 24 #include <net/if.h> 25 26 #include <arpa/inet.h> 27 28 #include "hunt.h" 29 #include "list.h" 30 31 /* Wait at most 5 seconds for a reply */ 32 #define LIST_DELAY 5 33 34 struct driver *drivers = NULL; 35 int numdrivers = 0; 36 int maxdrivers = 0; 37 38 u_int16_t Server_port; 39 40 static int numprobes = 0; 41 static int probe_sock[64]; 42 static struct timeval probe_timeout; 43 44 struct driver * 45 next_driver(void) 46 { 47 48 return next_driver_fd(-1); 49 } 50 51 struct driver * 52 next_driver_fd(int fd) 53 { 54 fd_set r; 55 int maxfd = -1; 56 int i, s, ret; 57 socklen_t len; 58 struct driver *driver; 59 u_int16_t resp; 60 61 if (fd == -1 && numprobes == 0) 62 return NULL; 63 64 again: 65 FD_ZERO(&r); 66 if (fd != -1) { 67 FD_SET(fd, &r); 68 maxfd = fd; 69 } 70 for (i = 0; i < numprobes; i++) { 71 FD_SET(probe_sock[i], &r); 72 if (probe_sock[i] > maxfd) 73 maxfd = probe_sock[i]; 74 } 75 76 probe_timeout.tv_sec = LIST_DELAY; 77 probe_timeout.tv_usec = 0; 78 ret = select(maxfd + 1, &r, NULL, NULL, &probe_timeout); 79 80 if (ret == -1) { 81 if (errno == EINTR) 82 goto again; 83 err(1, "select"); 84 } 85 86 if (ret == 0) { 87 /* Timeout - close all sockets */ 88 for (i = 0; i < numprobes; i++) 89 close(probe_sock[i]); 90 numprobes = 0; 91 return NULL; 92 } 93 94 if (fd != -1 && FD_ISSET(fd, &r)) 95 /* Keypress. Return magic number */ 96 return (struct driver *)-1; 97 98 for (i = 0; i < numprobes; i++) 99 /* Find the first ready socket */ 100 if (FD_ISSET(probe_sock[i], &r)) 101 break; 102 103 s = probe_sock[i]; 104 105 if (numdrivers >= maxdrivers) { 106 if (maxdrivers) { 107 maxdrivers *= 2; 108 drivers = realloc(drivers, sizeof *driver * maxdrivers); 109 } else { 110 maxdrivers = 16; 111 drivers = calloc(sizeof *driver, maxdrivers); 112 } 113 if (drivers == NULL) 114 err(1, "malloc"); 115 } 116 driver = &drivers[numdrivers]; 117 len = sizeof driver->addr; 118 ret = recvfrom(s, &resp, sizeof resp, 0, &driver->addr, &len); 119 if (ret == -1) 120 goto again; 121 driver->response = ntohs(resp); 122 123 switch (driver->addr.sa_family) { 124 case AF_INET: 125 case AF_INET6: 126 ((struct sockaddr_in *)&driver->addr)->sin_port = 127 htons(driver->response); 128 break; 129 } 130 numdrivers++; 131 return driver; 132 } 133 134 /* Return the hostname for a driver. */ 135 const char * 136 driver_name(struct driver *driver) 137 { 138 const char *name; 139 static char buf[80]; 140 struct hostent *hp; 141 struct sockaddr_in *sin; 142 143 name = NULL; 144 145 if (driver->addr.sa_family == AF_INET) { 146 sin = (struct sockaddr_in *)&driver->addr; 147 hp = gethostbyaddr(&sin->sin_addr, sizeof sin->sin_addr, 148 AF_INET); 149 if (hp != NULL) 150 name = hp->h_name; 151 else { 152 name = inet_ntop(AF_INET, &sin->sin_addr, 153 buf, sizeof buf); 154 } 155 } 156 157 return name; 158 } 159 160 static int 161 start_probe(struct sockaddr *addr, u_int16_t req) 162 { 163 u_int16_t msg; 164 int s; 165 int enable; 166 167 if (numprobes >= (int)(sizeof probe_sock / sizeof probe_sock[0])) { 168 /* Just ridiculous */ 169 return -1; 170 } 171 172 s = socket(addr->sa_family, SOCK_DGRAM, 0); 173 if (s < 0) { 174 warn("socket"); 175 return -1; 176 } 177 178 enable = 1; 179 setsockopt(s, SOL_SOCKET, SO_BROADCAST, &enable, sizeof enable); 180 181 switch (addr->sa_family) { 182 case AF_INET: 183 case AF_INET6: 184 ((struct sockaddr_in *)addr)->sin_port = 185 htons(Server_port); 186 break; 187 } 188 189 msg = htons(req); 190 if (sendto(s, &msg, sizeof msg, 0, addr, addr->sa_len) == -1) 191 warn("sendto"); 192 probe_sock[numprobes++] = s; 193 194 return 0; 195 } 196 197 void 198 probe_cleanup(void) 199 { 200 int i; 201 202 for (i = 0; i < numprobes; i++) 203 close(probe_sock[i]); 204 numprobes = 0; 205 } 206 207 /* 208 * If we have no preferred host then send a broadcast message to everyone. 209 * Otherwise, send the request message only to the preferred host. 210 */ 211 void 212 probe_drivers(u_int16_t req, char *preferred) 213 { 214 struct sockaddr_in *target; 215 struct sockaddr_in localhost; 216 struct hostent *he; 217 char *inbuf = NULL, *ninbuf; 218 struct ifconf ifc; 219 struct ifreq *ifr; 220 int fd, inlen = 8192; 221 int i, len; 222 223 numdrivers = 0; 224 225 probe_cleanup(); 226 227 /* Send exclusively to a preferred host. */ 228 if (preferred) { 229 struct sockaddr_in sin; 230 231 target = NULL; 232 233 if (!target) { 234 sin.sin_family = AF_INET; 235 sin.sin_len = sizeof sin; 236 if (inet_pton(AF_INET, preferred, &sin.sin_addr) == 1) 237 target = &sin; 238 } 239 240 if (!target && (he = gethostbyname(preferred)) != NULL) { 241 sin.sin_family = he->h_addrtype; 242 sin.sin_len = sizeof sin; 243 memcpy(&sin.sin_addr, he->h_addr, he->h_length); 244 target = &sin; 245 } 246 247 if (!target) 248 errx(1, "Bad hostname: %s", preferred); 249 250 start_probe((struct sockaddr *)target, req); 251 return; 252 } 253 254 /* Send a query to the local machine: */ 255 localhost.sin_family = AF_INET; 256 localhost.sin_len = sizeof localhost; 257 localhost.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 258 start_probe((struct sockaddr *)&localhost, req); 259 260 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 261 err(1, "socket"); 262 263 /* Find all attached networks: */ 264 while (1) { 265 ifc.ifc_len = inlen; 266 if ((ninbuf = realloc(inbuf, inlen)) == NULL) 267 err(1, "malloc"); 268 ifc.ifc_buf = inbuf = ninbuf; 269 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0) 270 err(1, "SIOCGIFCONF"); 271 if (ifc.ifc_len + (int)sizeof(*ifr) < inlen) 272 break; 273 inlen *= 2; 274 } 275 276 /* Send a request to every attached broadcast address: */ 277 ifr = ifc.ifc_req; 278 for (i = 0; i < ifc.ifc_len; 279 i += len, ifr = (struct ifreq *)((caddr_t)ifr + len)) { 280 len = sizeof(ifr->ifr_name) + 281 (ifr->ifr_addr.sa_len > sizeof(struct sockaddr) ? 282 ifr->ifr_addr.sa_len : sizeof(struct sockaddr)); 283 284 if (ifr->ifr_addr.sa_family != AF_INET) 285 continue; 286 287 if (ioctl(fd, SIOCGIFFLAGS, (caddr_t)ifr) < 0) { 288 warn("%s: SIOCGIFFLAGS", ifr->ifr_name); 289 continue; 290 } 291 if ((ifr->ifr_flags & IFF_UP) == 0) 292 continue; 293 if ((ifr->ifr_flags & IFF_BROADCAST) != 0) { 294 if (ioctl(fd, SIOCGIFBRDADDR, (caddr_t)ifr) < 0) { 295 warn("%s: SIOCGIFBRDADDR", ifr->ifr_name); 296 continue; 297 } 298 target = (struct sockaddr_in *)&ifr->ifr_dstaddr; 299 } else if ((ifr->ifr_flags & IFF_POINTOPOINT) != 0) { 300 if (ioctl(fd, SIOCGIFDSTADDR, (caddr_t)ifr) < 0) { 301 warn("%s: SIOCGIFDSTADDR", ifr->ifr_name); 302 continue; 303 } 304 target = (struct sockaddr_in *)&ifr->ifr_broadaddr; 305 } else 306 continue; 307 308 start_probe((struct sockaddr *)target, req); 309 } 310 free(inbuf); 311 close(fd); 312 } 313