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