1 /*
2 * XPilot NG, a multiplayer space war game.
3 *
4 * Copyright (C) 1991-2001 by
5 *
6 * Bj�rn Stabell <bjoern@xpilot.org>
7 * Ken Ronny Schouten <ken@xpilot.org>
8 * Bert Gijsbers <bert@xpilot.org>
9 * Dick Balaska <dick@xpilot.org>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26 #include "xpclient.h"
27
28
29 #if defined(_WINDOWS)
30 # ifndef QUERY_FUDGED
31 # define QUERY_FUDGED
32 # endif
33 #endif
34 #ifdef _IBMESA
35 # define _SOCKADDR_LEN
36 #endif
37
38 #ifndef MAX_INTERFACE
39 #define MAX_INTERFACE 16 /* Max. number of network interfaces. */
40 #endif
41 #ifdef DEBUGBROADCAST
42 #undef D
43 #define D(x) x
44 #endif
45
46 /*
47 * Query all hosts on a subnet one after another.
48 * This should be avoided as much as possible.
49 * It may cause network congestion and therefore fail,
50 * because UDP is unreliable.
51 * We only allow this horrible kludge for subnets with 8 or less
52 * bits in the host part of the subnet mask.
53 * Subnets with irregular subnet bits are properly handled (I hope).
54 */
Query_subnet(sock_t * sock,struct sockaddr_in * host_addr,struct sockaddr_in * mask_addr,char * msg,size_t msglen)55 static int Query_subnet(sock_t *sock,
56 struct sockaddr_in *host_addr,
57 struct sockaddr_in *mask_addr,
58 char *msg,
59 size_t msglen)
60 {
61 int i, nbits, max;
62 unsigned long bit, mask, dest, host, hostmask, hostbits[256];
63 struct sockaddr_in addr;
64
65 addr = *host_addr;
66 host = ntohl(host_addr->sin_addr.s_addr);
67 mask = ntohl(mask_addr->sin_addr.s_addr);
68 memset ((void *)hostbits, 0, sizeof hostbits);
69 nbits = 0;
70 hostmask = 0;
71
72 /*
73 * Only the lower 32 bits of an unsigned long are used.
74 */
75 for (bit = 1; (bit & 0xffffffff) != 0; bit <<= 1) {
76 if ((mask & bit) != 0)
77 continue;
78
79 if (nbits >= 8) {
80 /* break; ? */
81 warn("too many host bits in subnet mask");
82 return (-1);
83 }
84 hostmask |= bit;
85 for (i = (1 << nbits); i < 256; i++) {
86 if ((i & (1 << nbits)) != 0)
87 hostbits[i] |= bit;
88 }
89 nbits++;
90 }
91 if (nbits < 2) {
92 warn("malformed subnet mask");
93 return (-1);
94 }
95
96 /*
97 * The first and the last address are reserved for the subnet.
98 * So, for an 8 bit host part only 254 hosts are tried, not 256.
99 */
100 max = (1 << nbits) - 2;
101 for (i=1; i <= max; i++) {
102 dest = (host & ~hostmask) | hostbits[i];
103 addr.sin_addr.s_addr = htonl(dest);
104 sock_get_error(sock);
105 sendto(sock->fd, msg, msglen, 0,
106 (struct sockaddr *)&addr, sizeof(addr));
107 D( printf("sendto %s/%d\n",
108 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)) );
109 /*
110 * Imagine a server responding to our query while we
111 * are still transmitting packets for non-existing servers
112 * and the server packet colliding with one of our packets.
113 */
114 micro_delay((unsigned)10000);
115 }
116
117 return 0;
118 }
119
120
Query_fudged(sock_t * sock,int port,char * msg,size_t msglen)121 static int Query_fudged(sock_t *sock, int port, char *msg, size_t msglen)
122 {
123 int i, count = 0;
124 unsigned char *p;
125 struct sockaddr_in addr, subnet;
126 struct hostent *h;
127 unsigned long addrmask, netmask;
128 char host_name[64];
129
130 gethostname(host_name, sizeof(host_name));
131 if ((h = gethostbyname(host_name)) == NULL) {
132 error("gethostbyname");
133 return -1;
134 }
135 if (h->h_addrtype != AF_INET || h->h_length != 4) {
136 warn("Dunno about addresses with address type %d and length %d\n",
137 h->h_addrtype, h->h_length);
138 return -1;
139 }
140 for (i = 0; h->h_addr_list[i]; i++) {
141 memset(&addr, 0, sizeof(addr));
142 addr.sin_family = AF_INET;
143 addr.sin_port = (unsigned short)htons((unsigned short)port);
144 p = (unsigned char *) h->h_addr_list[i];
145 addrmask = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
146 addr.sin_addr.s_addr = htonl(addrmask);
147 subnet = addr;
148 if (addrmask == 0x7F000001) {
149 sock_get_error(sock);
150 if (sendto(sock->fd, msg, msglen, 0,
151 (struct sockaddr *)&addr, sizeof(addr)) != -1)
152 count++;
153 } else {
154 netmask = 0xFFFFFF00;
155 subnet.sin_addr.s_addr = htonl(netmask);
156 if (Query_subnet(sock, &addr, &subnet, msg, msglen) != -1)
157 count++;
158 }
159 }
160 if (count == 0) {
161 errno = 0;
162 count = -1;
163 }
164 return count;
165 }
166
167
168 /*
169 * Send a datagram on all network interfaces of the local host. Return the
170 * number of packets succesfully transmitted.
171 * We only use the loopback interface if we didn't do a broadcast
172 * on one of the other interfaces in order to reduce the chance that
173 * we get multiple responses from the same server.
174 */
175
Query_all(sock_t * sock,int port,char * msg,size_t msglen)176 int Query_all(sock_t *sock, int port, char *msg, size_t msglen)
177 {
178 #ifdef QUERY_FUDGED
179 return Query_fudged(sock, port, msg, msglen);
180 #else
181
182 int fd, len, ifflags, count = 0;
183 /* int broadcasts = 0; */
184 int haslb = 0;
185 struct sockaddr_in addr, mask, loopback;
186 struct ifconf ifconf;
187 struct ifreq *ifreqp, ifreq, ifbuf[MAX_INTERFACE];
188
189 /*
190 * Broadcasting on a socket must be explicitly enabled.
191 */
192 if (sock_set_broadcast(sock, 1) == -1) {
193 error("set broadcast");
194 return (-1);
195 }
196
197 /*
198 * Create an unbound datagram socket. Only used for ioctls.
199 */
200 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
201 error("socket");
202 return (-1);
203 }
204
205 /*
206 * Get names and addresses of all local network interfaces.
207 */
208 ifconf.ifc_len = sizeof(ifbuf);
209 ifconf.ifc_buf = (caddr_t)ifbuf;
210 memset((void *)ifbuf, 0, sizeof(ifbuf));
211 if (ioctl(fd, SIOCGIFCONF, (char *)&ifconf) == -1) {
212 error("ioctl SIOCGIFCONF");
213 close(fd);
214 return Query_fudged(sock, port, msg, msglen);
215 }
216 for (len = 0; len + (int)sizeof(struct ifreq) <= ifconf.ifc_len;) {
217 ifreqp = (struct ifreq *)&ifconf.ifc_buf[len];
218
219 D( printf("interface name %s\n", ifreqp->ifr_name) );
220 D( printf("\taddress family %d\n", ifreqp->ifr_addr.sa_family) );
221
222 len += sizeof(struct ifreq);
223 #if (defined(BSD) && BSD >= 199006) \
224 || (defined(HAVE_SA_LEN) && HAVE_SA_LEN != 0) \
225 || defined(_SOCKADDR_LEN) || defined(_AIX)
226 /*
227 * Recent TCP/IP implementations have a sa_len member in the socket
228 * address structure in order to support protocol families that have
229 * bigger addresses.
230 */
231 if (ifreqp->ifr_addr.sa_len > sizeof(ifreqp->ifr_addr)) {
232 len += ifreqp->ifr_addr.sa_len - sizeof(ifreqp->ifr_addr);
233 D( printf("\textra address length %d\n",
234 ifreqp->ifr_addr.sa_len - sizeof(ifreqp->ifr_addr)) );
235 }
236 #endif
237 if (ifreqp->ifr_addr.sa_family != AF_INET)
238 /*
239 * Not supported.
240 */
241 continue;
242
243 addr = *(struct sockaddr_in *)&ifreqp->ifr_addr;
244 D( printf("\taddress %s\n", inet_ntoa(addr.sin_addr)) );
245
246 /*
247 * Get interface flags.
248 */
249 ifreq = *ifreqp;
250 if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifreq) == -1) {
251 error("ioctl SIOCGIFFLAGS");
252 continue;
253 }
254 ifflags = ifreq.ifr_flags;
255
256 if ((ifflags & IFF_UP) == 0) {
257 D( printf("\tinterface is down\n") );
258 continue;
259 }
260 D( printf("\tinterface %s running\n",
261 (ifflags & IFF_RUNNING) ? "is" : "not") );
262
263 if ((ifflags & IFF_LOOPBACK) != 0) {
264 D( printf("\tloopback interface\n") );
265 /*
266 * Only send on the loopback if we don't broadcast.
267 */
268 if (haslb == 0) {
269 loopback = *(struct sockaddr_in *)&ifreq.ifr_addr;
270 haslb = 1;
271 }
272 continue;
273 } else if ((ifflags & IFF_POINTOPOINT) != 0) {
274 D( printf("\tpoint-to-point interface\n") );
275 ifreq = *ifreqp;
276 if (ioctl(fd, SIOCGIFDSTADDR, (char *)&ifreq) == -1) {
277 error("ioctl SIOCGIFDSTADDR");
278 continue;
279 }
280 addr = *(struct sockaddr_in *)&ifreq.ifr_addr;
281 D(printf("\tdestination address %s\n", inet_ntoa(addr.sin_addr)));
282 } else if ((ifflags & IFF_BROADCAST) != 0) {
283 D( printf("\tbroadcast interface\n") );
284 ifreq = *ifreqp;
285 if (ioctl(fd, SIOCGIFBRDADDR, (char *)&ifreq) == -1) {
286 error("ioctl SIOCGIFBRDADDR");
287 continue;
288 }
289 addr = *(struct sockaddr_in *)&ifreq.ifr_addr;
290 D( printf("\tbroadcast address %s\n", inet_ntoa(addr.sin_addr)) );
291 } else {
292 /*
293 * Huh? It's not a loopback and not a point-to-point
294 * and it doesn't have a broadcast address???
295 * Something must be rotten here...
296 */
297 }
298
299 if ((ifflags & (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST)) != 0) {
300 /*
301 * Well, we have an address (at last).
302 */
303 addr.sin_port = htons(port);
304 if (sendto(sock->fd, msg, msglen, 0, (struct sockaddr *)&addr,
305 sizeof addr) == (ssize_t)msglen) {
306 D(printf("\tsendto %s/%d\n", inet_ntoa(addr.sin_addr), port));
307 /*
308 * Success!
309 */
310 count++;
311 /* if ((ifflags & (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST))
312 == IFF_BROADCAST) {
313 broadcasts++;
314 } */
315 continue;
316 }
317
318 /*
319 * Failure.
320 */
321 error("sendto %s/%d failed", inet_ntoa(addr.sin_addr), port);
322
323 if ((ifflags & (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST))
324 != IFF_BROADCAST)
325 /*
326 * It wasn't the broadcasting that failed.
327 */
328 continue;
329
330 /*
331 * Broadcasting failed.
332 * Try it in a different (kludgy) manner.
333 */
334 }
335
336 /*
337 * Get the netmask for this interface.
338 */
339 ifreq = *ifreqp;
340 if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifreq) == -1) {
341 error("ioctl SIOCGIFNETMASK");
342 continue;
343 }
344 mask = *(struct sockaddr_in *)&ifreq.ifr_addr;
345 D( printf("\tmask %s\n", inet_ntoa(mask.sin_addr)) );
346
347 addr.sin_port = htons(port);
348 if (Query_subnet(sock, &addr, &mask, msg, msglen) != -1) {
349 count++;
350 /* broadcasts++; */
351 }
352 }
353
354 /*
355 * Normally we wouldn't send a query over the loopback interface
356 * if we successfully have sent one or more broadcast queries,
357 * but it happens that some Linux machines which have firewalling
358 * packet filters installed don't copy outgoing broadcast packets
359 * to their local sockets. Therefore we now always also send
360 * one query to the loopback address just to be sure we reach
361 * our own server. That we now may receive two or more replies
362 * from the same server is not as serious as not receiving any
363 * reply would be.
364 */
365 if (haslb /* && broadcasts == 0 */) {
366 /*
367 * We may not have reached the localhost yet.
368 */
369 memset(&addr, 0, sizeof(addr));
370 addr.sin_addr = loopback.sin_addr;
371 addr.sin_port = htons(port);
372 if (sendto(sock->fd, msg, msglen, 0, (struct sockaddr *)&addr,
373 sizeof addr) == (ssize_t)msglen) {
374 D(printf("\tsendto %s/%d\n", inet_ntoa(addr.sin_addr), port));
375 count++;
376 } else
377 error("sendto %s/%d failed", inet_ntoa(addr.sin_addr), port);
378 }
379
380 close(fd);
381
382 if (count == 0) {
383 errno = 0;
384 count = -1;
385 }
386
387 return count;
388
389 #endif /* QUERY_FUDGED */
390 }
391
392