1 /* This is a simple name server for GNUstep Distributed Objects
2 Copyright (C) 1996, 1997, 1998, 2002 Free Software Foundation, Inc.
3
4 Written by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
5 Created: October 1996
6
7 This file is part of the GNUstep Base Library.
8
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public
11 License as published by the Free Software Foundation; either
12 version 2 of the License, or (at your option) any later version.
13
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
18
19 You should have received a copy of the GNU General Public
20 License along with this library; if not, write to the Free
21 Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 Boston, MA 02111 USA.
23 */
24
25 /* Ported to mingw 07/12/00 by Bjorn Giesler <Bjoern.Giesler@gmx.de> */
26
27 #include "config.h"
28
29 #if !defined(__MINGW__)
30 # if defined(__MINGW32__) || defined(__MINGW64__)
31 # define __MINGW__
32 # endif
33 #endif
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #include <unistd.h> /* for gethostname() */
39 #include <inttypes.h>
40 #ifndef __MINGW__
41 #include <sys/param.h> /* for MAXHOSTNAMELEN */
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <netinet/in.h>
45 #include <arpa/inet.h> /* for inet_ntoa() */
46 #endif /* !__MINGW__ */
47 #include <errno.h>
48 #include <limits.h>
49 #include <string.h> /* for strchr() */
50 #include <ctype.h> /* for strchr() */
51 #include <fcntl.h>
52 #if defined(__MINGW__)
53 #include <stdint.h>
54 #include <winsock2.h>
55 #include <ws2tcpip.h>
56 #include <wininet.h>
57 #include <process.h>
58 #include <sys/time.h>
59 #else
60 #include <sys/time.h>
61 #include <sys/resource.h>
62 #include <netdb.h>
63 #include <signal.h>
64 #include <sys/socket.h>
65 #include <sys/file.h>
66 #if defined(HAVE_TIME_H)
67 #include <time.h>
68 #endif
69 #if defined(HAVE_PWD_H)
70 #include <pwd.h>
71 #endif
72 #if defined(HAVE_GRP_H)
73 #include <grp.h>
74 #endif
75
76 #if HAVE_GETOPT_H
77 #include <getopt.h>
78 #endif
79
80 /*
81 * Stuff for setting the sockets into non-blocking mode.
82 */
83 #if defined(__POSIX_SOURCE) || defined(__EXT_POSIX1_198808)
84 #define NBLK_OPT O_NONBLOCK
85 #else
86 #define NBLK_OPT FNDELAY
87 #endif
88
89 #include <netinet/in.h>
90 #include <net/if.h>
91 #if !defined(SIOCGIFCONF) || defined(__CYGWIN__)
92 #include <sys/ioctl.h>
93 #ifndef SIOCGIFCONF
94 #include <sys/sockio.h>
95 #endif
96 #endif
97
98 #if defined(__svr4__)
99 #if defined(HAVE_SYS_STROPTS_H)
100 #include <sys/stropts.h>
101 #endif
102 #endif
103 #endif /* !__MINGW__ */
104
105
106 #if defined(HAVE_SYSLOG_H)
107 #include <syslog.h>
108 #elif defined(HAVE_SYS_SLOG_H)
109 # include <sys/slog.h>
110 # if defined(HAVE_SYS_SLOGCODES_H)
111 # include <sys/slogcodes.h>
112 # endif
113 #endif
114
115 #if HAVE_STRERROR
116 #define lastErr() strerror(errno)
117 #else
118 #if defined(__MINGW__)
119 static errbuf[BUFSIZ];
120 #define lastErr() (sprintf(errbuf, "WSAGetLastError()=%d", WSAGetLastError()), errbuf)
121 #else
122 static errbuf[BUFSIZ];
123 #define lastErr() (sprintf(errbuf, "%m"), errbuf)
124 #endif
125 #endif
126
127 #include "gdomap.h"
128 /*
129 * ABOUT THIS PROGRAM
130 *
131 * This is a simple name server for GNUstep Distributed Objects
132 * The server program listens on a well known port (service name 'gdomap')
133 *
134 * The officially assigned port is 538. On most systems port numbers
135 * under 1024 can only be used by root (for security). So this program
136 * needs to be run as root.
137 *
138 * This is UNIX code - I have no idea how portable to other OSs it may be.
139 *
140 * For detailed information about the communication protocol used - see
141 * the include file.
142 */
143
144 /* For IRIX machines, which don't define this */
145 #ifndef IPPORT_USERRESERVED
146 #define IPPORT_USERRESERVED 5000
147 #endif /* IPPORT_USERRESERVED */
148
149 #define QUEBACKLOG (16) /* How many coonections to queue. */
150 #define MAX_IFACE (256) /* How many network interfaces. */
151 #define IASIZE (sizeof(struct in_addr))
152
153 #define MAX_EXTRA ((GDO_NAME_MAX_LEN - 2 * IASIZE)/IASIZE)
154
155 #define ROUND(V, A) \
156 ({ typeof(V) __v=(V); typeof(A) __a=(A); \
157 __a*((__v+__a-1)/__a); })
158
159 typedef unsigned char *uptr;
160 #ifndef __MINGW__
161 static int is_daemon = 0; /* Currently running as daemon. */
162 #endif
163 static int in_config = 0; /* Reading config file. */
164 static int debug = 0; /* Extra debug gdomap_logging. */
165 static int nobcst = 0; /* turn off broadcast probing. */
166 static int nofork = 0; /* turn off fork() for debugging. */
167 static int noprobe = 0; /* disable probe for unknown servers. */
168 static int interval = 600; /* Minimum time (sec) between probes. */
169 static char *pidfile = NULL; /* file to write PID to */
170
171 static int udp_sent = 0;
172 static int tcp_sent = 0;
173 static int udp_read = 0;
174 static int tcp_read = 0;
175 static int soft_int = 0;
176
177 static long last_probe;
178 static struct in_addr loopback;
179
180 static unsigned short my_port; /* Set in init_iface() */
181
182 static struct in_addr class_a_mask;
183 static struct in_addr class_b_mask;
184 static uint32_t class_a_net;
185 static uint32_t class_b_net;
186 static uint32_t class_c_net;
187 struct in_addr class_c_mask;
188
189 static char *local_hostname = 0;
190
191 /*
192 * Predeclare some of the functions used.
193 */
194 static void dump_stats();
195 #ifndef __MINGW__
196 static void dump_tables();
197 #endif
198 static void handle_accept();
199 static void handle_io();
200 static void handle_read(int);
201 static void handle_recv();
202 static void handle_request(int);
203 static void handle_send();
204 static void handle_write(int);
205 static void init_iface();
206 static void load_iface(const char* from);
207 static void init_ports();
208 static void init_probe();
209 static void queue_msg(struct sockaddr_in* a, uptr d, unsigned l);
210 static void queue_pop();
211 static void queue_probe(struct in_addr* to, struct in_addr *from,
212 int num_extras, struct in_addr* extra, int is_reply);
213
214 char *xgethostname (void);
215
216 #if defined(__MINGW__)
217 #ifndef HAVE_GETOPT
218 /* A simple implementation of getopt() */
219
220 static int
indexof(char c,char * string)221 indexof(char c, char *string)
222 {
223 int i;
224
225 for (i = 0; i < strlen(string); i++)
226 {
227 if (string[i] == c)
228 {
229 return i;
230 }
231 }
232 return -1;
233 }
234
235 static char *optarg;
236
237 static char
getopt(int argc,char ** argv,char * options)238 getopt(int argc, char **argv, char *options)
239 {
240 static int argi;
241 static char *arg;
242 int index;
243 char retval = '\0';
244
245 optarg = NULL;
246 if (argi == 0)
247 {
248 argi = 1;
249 }
250 while (argi < argc)
251 {
252 arg = argv[argi];
253 if (strlen(arg) == 2)
254 {
255 if (arg[0] == '-')
256 {
257 if ((index = indexof(arg[1], options)) != -1)
258 {
259 retval = arg[1];
260 if (index < strlen(options))
261 {
262 if (options[index+1] == ':')
263 {
264 if (argi < argc-1)
265 {
266 argi++;
267 optarg = argv[argi];
268 }
269 else
270 {
271 return -1; /* ':' given, but argv exhausted */
272 }
273 }
274 }
275 }
276 }
277 }
278 argi++;
279 return retval;
280 }
281 return -1;
282 }
283 #endif
284 #endif
285
286
287 static char ebuf[2048];
288
289
290 #if defined(HAVE_SYSLOG) || defined(HAVE_SLOGF)
291 # if defined(HAVE_SLOGF)
292 # define LOG_CRIT _SLOG_CRITICAL
293 # define LOG_DEBUG _SLOG_DEBUG1
294 # define LOG_ERR _SLOG_ERROR
295 # define LOG_INFO _SLOG_INFO
296 # define LOG_WARNING _SLOG_WARNING
297 # define syslog(prio, msg,...) slogf(_SLOG_SETCODE(_SLOG_SYSLOG, 0), prio, msg, __VA_ARGS__)
298 # endif
299
300 static int log_priority = 0;
301
302 static void
gdomap_log(int prio)303 gdomap_log (int prio)
304 {
305 if (in_config)
306 {
307 #ifndef __MINGW__
308 if (geteuid () != getuid ())
309 {
310 strcpy(ebuf, "problem with config file");
311 }
312 #endif
313 }
314 if (is_daemon)
315 {
316 #if defined(HAVE_SLOGF)
317 // QNX doesn't like 0 as the prio. It means "shutdown" to them.
318 syslog (prio ? log_priority : prio, "%s", ebuf);
319 # else
320 syslog (log_priority | prio, "%s", ebuf);
321 #endif
322 }
323 else if (prio == LOG_INFO)
324 {
325 write (1, ebuf, strlen (ebuf));
326 write (1, "\n", 1);
327 }
328 else
329 {
330 write (2, ebuf, strlen (ebuf));
331 write (2, "\n", 1);
332 }
333
334 if (prio == LOG_CRIT)
335 {
336 if (is_daemon)
337 {
338 syslog (LOG_CRIT, "%s", "exiting.");
339 }
340 else
341 {
342 fprintf (stderr, "exiting.\n");
343 fflush (stderr);
344 }
345 exit(EXIT_FAILURE);
346 }
347 }
348 #else
349
350 #define LOG_CRIT 2
351 #define LOG_DEBUG 0
352 #define LOG_ERR 1
353 #define LOG_INFO 0
354 #define LOG_WARNING 0
355 void
gdomap_log(int prio)356 gdomap_log (int prio)
357 {
358 if (in_config)
359 {
360 #ifndef __MINGW__
361 if (geteuid () != getuid ())
362 {
363 strcpy(ebuf, "problem with config file");
364 }
365 #endif
366 }
367 write (2, ebuf, strlen (ebuf));
368 write (2, "\n", 1);
369 if (prio == LOG_CRIT)
370 {
371 fprintf (stderr, "exiting.\n");
372 fflush (stderr);
373 exit(EXIT_FAILURE);
374 }
375 }
376 #endif
377
378 /*
379 * Structure for linked list of addresses to probe rather than
380 * probing entire network.
381 */
382 typedef struct plstruct {
383 struct plstruct *next;
384 int direct;
385 struct in_addr addr;
386 } plentry;
387
388 static plentry *plist = 0;
389
390 /*
391 * Variables used for determining if a connection is from a process
392 * on the local host.
393 */
394 static int interfaces = 0; /* Number of interfaces. */
395 static struct in_addr *addr; /* Address of each interface. */
396 static unsigned char *bcok; /* Broadcast OK for interface? */
397 static struct in_addr *bcst; /* Broadcast for interface. */
398 static struct in_addr *mask; /* Netmask of each interface. */
399
400 static int
is_local_host(struct in_addr a)401 is_local_host(struct in_addr a)
402 {
403 int i;
404
405 for (i = 0; i < interfaces; i++)
406 {
407 if (a.s_addr == addr[i].s_addr)
408 {
409 return 1;
410 }
411 }
412 return 0;
413 }
414
415 static int
is_probe_host(struct in_addr a)416 is_probe_host(struct in_addr a)
417 {
418 if (plist)
419 {
420 plentry *p;
421
422 /* Hosts explicitly configured to be probed are ones we treat
423 * as being part of our LAN and therefore trusted.
424 */
425 for (p = plist; p != 0; p = p->next)
426 {
427 if (a.s_addr == p->addr.s_addr)
428 {
429 return 1;
430 }
431 }
432 }
433 return 0;
434 }
435
436 static int
is_local_net(struct in_addr a)437 is_local_net(struct in_addr a)
438 {
439 int i;
440
441 for (i = 0; i < interfaces; i++)
442 {
443 if ((mask[i].s_addr & addr[i].s_addr) == (mask[i].s_addr & a.s_addr))
444 {
445 return 1;
446 }
447 }
448 return 0;
449 }
450
451 /*
452 * Variables used for handling non-blocking I/O on channels.
453 */
454 static int tcp_desc = -1; /* Socket for incoming TCP connections. */
455 static int udp_desc = -1; /* Socket for UDP communications. */
456 static fd_set read_fds; /* Descriptors which are readable. */
457 static fd_set write_fds; /* Descriptors which are writable. */
458
459
460 /* Internal info structures. Rewritten Wed Jul 12 14:51:19 2000 by
461 Bjoern Giesler <Bjoern.Giesler@gmx.de> to work on Win32. */
462
463 typedef struct {
464 #if defined(__MINGW__)
465 SOCKET s;
466 #else
467 int s;
468 #endif /* __MINGW__ */
469 struct sockaddr_in addr; /* Address of process making request. */
470 socklen_t pos; /* Position reading data. */
471 union {
472 gdo_req r;
473 unsigned char b[GDO_REQ_SIZE];
474 } buf;
475 } RInfo; /* State of reading each request. */
476
477 typedef struct {
478 #if defined(__MINGW__)
479 SOCKET s;
480 #else
481 int s;
482 #endif /* __MINGW__ */
483 int len; /* Length of data to be written. */
484 int pos; /* Amount of data already written. */
485 char* buf; /* Buffer for data. */
486 } WInfo;
487
488 static RInfo *_rInfo = NULL;
489 static unsigned _rInfoCapacity = 0;
490 static unsigned _rInfoCount = 0;
491 static WInfo *_wInfo = NULL;
492 static unsigned _wInfoCapacity = 0;
493 static unsigned _wInfoCount = 0;
494
495 static void
496 #if defined(__MINGW__)
delRInfo(SOCKET s)497 delRInfo(SOCKET s)
498 #else
499 delRInfo(int s)
500 #endif /* __MINGW__ */
501 {
502 unsigned int i;
503
504 for (i = 0; i < _rInfoCount; i++)
505 {
506 if (_rInfo[i].s == s)
507 {
508 break;
509 }
510 }
511 if (i == _rInfoCount)
512 {
513 snprintf(ebuf, sizeof(ebuf),
514 "%s requested unallocated RInfo struct (socket %d)",
515 __FUNCTION__, s);
516 gdomap_log(LOG_ERR);
517 return;
518 }
519 _rInfoCount--;
520 if (i != _rInfoCount) /* not last element */
521 {
522 memmove(&(_rInfo[i]), &(_rInfo[i+1]), (_rInfoCount-i)*sizeof(RInfo));
523 }
524 }
525
526
527 static RInfo *
528 #if defined(__MINGW__)
getRInfo(SOCKET s,int make)529 getRInfo(SOCKET s, int make)
530 #else
531 getRInfo(int s, int make)
532 #endif
533 {
534 unsigned int i;
535
536 for (i = 0; i < _rInfoCount; i++)
537 {
538 if (_rInfo[i].s == s)
539 {
540 break;
541 }
542 }
543 if (i == _rInfoCount)
544 {
545 if (make)
546 {
547 if (_rInfoCount >= _rInfoCapacity)
548 {
549 RInfo *tmp;
550
551 _rInfoCapacity = _rInfoCount + 1;
552 tmp = (RInfo *)calloc(_rInfoCapacity, sizeof(RInfo));
553 if (_rInfoCount > 0)
554 {
555 memcpy(tmp, _rInfo, sizeof(RInfo)*_rInfoCount);
556 free(_rInfo);
557 }
558 _rInfo = tmp;
559 }
560 _rInfoCount++;
561 _rInfo[_rInfoCount-1].s = s;
562 return &(_rInfo[_rInfoCount-1]);
563 }
564 return NULL;
565 }
566 return &(_rInfo[i]);
567 }
568
569 static void
570 #if defined(__MINGW__)
delWInfo(SOCKET s)571 delWInfo(SOCKET s)
572 #else
573 delWInfo(int s)
574 #endif /* __MINGW__ */
575 {
576 unsigned int i;
577
578 for (i = 0; i < _wInfoCount; i++)
579 {
580 if (_wInfo[i].s == s)
581 {
582 break;
583 }
584 }
585 if (i == _wInfoCount)
586 {
587 snprintf(ebuf, sizeof(ebuf),
588 "%s requested unallocated WInfo struct (socket %d)",
589 __FUNCTION__, s);
590 gdomap_log(LOG_ERR);
591 return;
592 }
593 _wInfoCount--;
594 if (i != _wInfoCount) /* not last element */
595 {
596 memmove(&(_wInfo[i]), &(_wInfo[i+1]), (_wInfoCount-i)*sizeof(WInfo));
597 }
598 }
599
600
601 static WInfo *
602 #if defined(__MINGW__)
getWInfo(SOCKET s,int make)603 getWInfo(SOCKET s, int make)
604 #else
605 getWInfo(int s, int make)
606 #endif
607 {
608 unsigned int i;
609
610 for (i = 0; i < _wInfoCount; i++)
611 {
612 if (_wInfo[i].s == s)
613 {
614 break;
615 }
616 }
617 if (i == _wInfoCount)
618 {
619 if (make)
620 {
621 if (_wInfoCount >= _wInfoCapacity)
622 {
623 WInfo *tmp;
624
625 _wInfoCapacity = _wInfoCount + 1;
626 tmp = (WInfo *)calloc(_wInfoCapacity, sizeof(WInfo));
627 if (_wInfoCount > 0)
628 {
629 memcpy(tmp, _wInfo, sizeof(WInfo)*_wInfoCount);
630 free(_wInfo);
631 }
632 _wInfo = tmp;
633 }
634 _wInfoCount++;
635 _wInfo[_wInfoCount-1].s = s;
636 return &(_wInfo[_wInfoCount-1]);
637 }
638 return NULL;
639 }
640 return &(_wInfo[i]);
641 }
642
643
644 static struct u_data {
645 struct sockaddr_in addr; /* Address to send to. */
646 int pos; /* Number of bytes already sent. */
647 int len; /* Length of data to send. */
648 uptr dat; /* Data to be sent. */
649 struct u_data *next; /* Next message to send. */
650 } *u_queue = 0;
651 static int udp_pending = 0;
652
653 /*
654 * Name - queue_msg()
655 * Purpose - Add a message to the queue of those to be sent
656 * on the UDP socket.
657 */
658 static void
queue_msg(struct sockaddr_in * a,uptr d,unsigned l)659 queue_msg(struct sockaddr_in* a, uptr d, unsigned l)
660 {
661 struct u_data* entry = (struct u_data*)malloc(sizeof(struct u_data));
662
663 memcpy(&entry->addr, a, sizeof(*a));
664 entry->pos = 0;
665 entry->len = l;
666 entry->dat = malloc(l);
667 memcpy(entry->dat, d, l);
668 entry->next = 0;
669 if (u_queue)
670 {
671 struct u_data* tmp = u_queue;
672
673 while (tmp->next)
674 {
675 tmp = tmp->next;
676 }
677 tmp->next = entry;
678 }
679 else
680 {
681 u_queue = entry;
682 }
683 udp_pending++;
684 }
685
686 static void
queue_pop()687 queue_pop()
688 {
689 struct u_data* tmp = u_queue;
690
691 if (tmp)
692 {
693 u_queue = tmp->next;
694 free(tmp->dat);
695 free(tmp);
696 udp_pending--;
697 }
698 }
699
700 /*
701 * Primitive mapping stuff.
702 */
703 typedef struct {
704 uptr name; /* Service name registered. */
705 unsigned int port; /* Port it was mapped to. */
706 unsigned short size; /* Number of bytes in name. */
707 unsigned char net; /* Type of port registered. */
708 unsigned char svc; /* Type of port registered. */
709 } map_ent;
710
711 static int map_used = 0;
712 static int map_size = 0;
713 static map_ent **map = 0;
714
715 static int
compare(uptr n0,int l0,uptr n1,int l1)716 compare(uptr n0, int l0, uptr n1, int l1)
717 {
718 if (l0 == l1)
719 {
720 return memcmp(n0, n1, l0);
721 }
722 else if (l0 < l1)
723 {
724 return -1;
725 }
726 return 1;
727 }
728
729 /*
730 * Name - map_add()
731 * Purpose - Create a new map entry structure and insert it
732 * into the map in the appropriate position.
733 */
734 static map_ent*
map_add(uptr n,unsigned char l,unsigned int p,unsigned char t)735 map_add(uptr n, unsigned char l, unsigned int p, unsigned char t)
736 {
737 map_ent *m;
738 int i;
739
740 m = (map_ent*)malloc(sizeof(map_ent));
741 if (0 == m)
742 {
743 perror("no memory for map entry");
744 exit(EXIT_FAILURE);
745 }
746 m->port = p;
747 m->name = (unsigned char*)malloc(l);
748 if (0 == m->name)
749 {
750 perror("no memory for map entry name");
751 exit(EXIT_FAILURE);
752 }
753 m->size = l;
754 m->net = (t & GDO_NET_MASK);
755 m->svc = (t & GDO_SVC_MASK);
756 memcpy(m->name, n, l);
757
758 if (map_used == map_size)
759 {
760 map_size += 16;
761 if (map)
762 {
763 map = (map_ent**)realloc(map, map_size * sizeof(map_ent*));
764 }
765 else
766 {
767 map = (map_ent**)calloc(map_size, sizeof(map_ent*));
768 }
769 if (0 == map)
770 {
771 perror("no memory for map");
772 exit(EXIT_FAILURE);
773 }
774 }
775 for (i = 0; i < map_used; i++)
776 {
777 if (compare(map[i]->name, map[i]->size, m->name, m->size) > 0)
778 {
779 int j;
780
781 for (j = map_used; j > i; j--)
782 {
783 map[j] = map[j-1];
784 }
785 break;
786 }
787 }
788 map[i] = m;
789 map_used++;
790 if (debug > 2)
791 {
792 snprintf(ebuf, sizeof(ebuf), "Added port %d to map for %.*s",
793 m->port, m->size, m->name);
794 gdomap_log(LOG_DEBUG);
795 }
796 return m;
797 }
798
799 /*
800 * Name - map_by_name()
801 * Purpose - Search the map for an entry for a particular name
802 */
803 static map_ent*
map_by_name(uptr n,int s)804 map_by_name(uptr n, int s)
805 {
806 int lower = 0;
807 int upper = map_used;
808 int index;
809
810 if (debug > 2)
811 {
812 snprintf(ebuf, sizeof(ebuf), "Searching map for %.*s", s, n);
813 gdomap_log(LOG_DEBUG);
814 }
815 for (index = upper/2; upper != lower; index = lower + (upper - lower)/2)
816 {
817 int i = compare(map[index]->name, map[index]->size, n, s);
818
819 if (i < 0)
820 {
821 lower = index + 1;
822 }
823 else if (i > 0)
824 {
825 upper = index;
826 }
827 else
828 {
829 break;
830 }
831 }
832 if (index<map_used && compare(map[index]->name,map[index]->size,n,s) == 0)
833 {
834 if (debug > 2)
835 {
836 snprintf(ebuf, sizeof(ebuf),
837 "Found port %d for %.*s", map[index]->port, s, n);
838 gdomap_log(LOG_DEBUG);
839 }
840 return map[index];
841 }
842 if (debug > 2)
843 {
844 snprintf(ebuf, sizeof(ebuf), "Failed to find map entry for %.*s", s, n);
845 gdomap_log(LOG_DEBUG);
846 }
847 return 0;
848 }
849
850 /*
851 * Name - map_by_port()
852 * Purpose - Search the map for an entry for a particular port
853 */
854 static map_ent*
map_by_port(unsigned p,unsigned char t)855 map_by_port(unsigned p, unsigned char t)
856 {
857 int index;
858
859 if (debug > 2)
860 {
861 snprintf(ebuf, sizeof(ebuf), "Searching map for %u:%x", p, t);
862 gdomap_log(LOG_DEBUG);
863 }
864 for (index = 0; index < map_used; index++)
865 {
866 map_ent *e = map[index];
867
868 if (e->port == p && (e->net | e->svc) == t)
869 {
870 break;
871 }
872 }
873 if (index < map_used)
874 {
875 if (debug > 2)
876 {
877 snprintf(ebuf, sizeof(ebuf), "Found port %d with name %s",
878 map[index]->port, map[index]->name);
879 gdomap_log(LOG_DEBUG);
880 }
881 return map[index];
882 }
883 if (debug > 2)
884 {
885 snprintf(ebuf, sizeof(ebuf), "Failed to find map entry for %u:%x", p, t);
886 gdomap_log(LOG_DEBUG);
887 }
888 return 0;
889 }
890
891 /*
892 * Name - map_del()
893 * Purpose - Remove a mapping entry from the map and release
894 * the memory it uses.
895 */
896 static void
map_del(map_ent * e)897 map_del(map_ent* e)
898 {
899 int i;
900
901 if (debug > 2)
902 {
903 snprintf(ebuf, sizeof(ebuf), "Removing port %d from map for %.*s",
904 e->port, e->size, e->name);
905 gdomap_log(LOG_DEBUG);
906 }
907 for (i = 0; i < map_used; i++)
908 {
909 if (map[i] == e)
910 {
911 int j;
912
913 free(e->name);
914 free(e);
915 for (j = i + 1; j < map_used; j++)
916 {
917 map[j-1] = map[j];
918 }
919 map_used--;
920 return;
921 }
922 }
923 }
924
925 /*
926 * Variables and functions for keeping track of the IP addresses of
927 * hosts which are running the name server.
928 */
929 static uint32_t prb_used = 0;
930 static uint32_t prb_size = 0;
931 typedef struct {
932 struct in_addr sin;
933 time_t when;
934 } prb_type;
935 static prb_type **prb = 0;
936
937 /*
938 * Name - prb_add()
939 * Purpose - Create a new probe entry in the list.
940 * The new entry is always placed at the end of the list
941 * so that the list remains in the order in which hosts
942 * have been contancted.
943 */
944 static void
prb_add(struct in_addr * p)945 prb_add(struct in_addr *p)
946 {
947 prb_type *n = 0;
948 unsigned int i;
949
950 if (is_local_host(*p) != 0)
951 {
952 return;
953 }
954 if (is_local_net(*p) == 0 && is_probe_host(*p) == 0)
955 {
956 return;
957 }
958
959 /*
960 * If we already have an entry for this address, remove it from the list
961 * ready for re-insertion in the correct place.
962 */
963 i = prb_used;
964 while (i-- > 0)
965 {
966 if (memcmp(&prb[i]->sin, p, IASIZE) == 0)
967 {
968 n = prb[i];
969 prb_used--;
970 while (i++ < prb_used)
971 {
972 prb[i-1] = prb[i];
973 }
974 break;
975 }
976 }
977
978 /*
979 * Create a new entry structure if necessary.
980 * Set the current time in the structure, so we know when we last had contact.
981 */
982 if (0 == n)
983 {
984 n = (prb_type*)calloc(sizeof(prb_type), 1);
985 n->sin = *p;
986 }
987 n->when = time(0);
988
989 /*
990 * Grow the list if we need more space.
991 */
992 if (prb_used >= prb_size)
993 {
994 prb_size = prb_used + 16;
995 if (prb)
996 {
997 prb = (prb_type**)realloc(prb, prb_size * sizeof(prb_type*));
998 }
999 else
1000 {
1001 prb = (prb_type**)calloc(prb_size * sizeof(prb_type*), 1);
1002 }
1003 }
1004
1005 /*
1006 * Append the new item at the end of the list.
1007 */
1008 prb[prb_used++] = n;
1009 }
1010
1011
1012 /*
1013 * Name - prb_del()
1014 * Purpose - Remove an entry from the list.
1015 */
1016 static void
prb_del(struct in_addr * p)1017 prb_del(struct in_addr *p)
1018 {
1019 unsigned int i = prb_used;
1020
1021 while (i-- > 0)
1022 {
1023 if (memcmp(&prb[i]->sin, p, IASIZE) == 0)
1024 {
1025 free(prb[i]);
1026 prb_used--;
1027 while (i++ < prb_used)
1028 {
1029 prb[i - 1] = prb[i];
1030 }
1031 return;
1032 }
1033 }
1034 }
1035
1036 /*
1037 * Remove any server from which we have had no messages in the last
1038 * thirty minutes (as long as we have sent as probe in that time).
1039 */
1040 static void
prb_tim(time_t when)1041 prb_tim(time_t when)
1042 {
1043 int i = prb_used;
1044
1045 when -= 1800;
1046 while (i-- > 0)
1047 {
1048 if (noprobe == 0 && prb[i]->when < when && prb[i]->when < last_probe)
1049 {
1050 prb_del(&prb[i]->sin);
1051 }
1052 }
1053 }
1054
1055 /*
1056 * Name - clear_chan()
1057 * Purpose - Release all resources associated with a channel
1058 * and remove it from the list of requests being
1059 * serviced.
1060 */
1061 static void
clear_chan(int desc)1062 clear_chan(int desc)
1063 {
1064 #if defined(__MINGW__)
1065 if (desc != INVALID_SOCKET)
1066 #else
1067 if (desc >= 0 && desc < FD_SETSIZE)
1068 #endif
1069 {
1070 WInfo *wi;
1071
1072 FD_CLR(desc, &write_fds);
1073 if (desc == tcp_desc || desc == udp_desc)
1074 {
1075 FD_SET(desc, &read_fds);
1076 }
1077 else
1078 {
1079 FD_CLR(desc, &read_fds);
1080 #if defined(__MINGW__)
1081 closesocket(desc);
1082 #else
1083 close(desc);
1084 #endif
1085 }
1086 if ((wi = getWInfo(desc, 0)) != 0)
1087 {
1088 if (wi->buf)
1089 {
1090 free(wi->buf);
1091 wi->buf = 0;
1092 }
1093 wi->len = 0;
1094 wi->pos = 0;
1095 }
1096 if (!(desc == tcp_desc || desc == udp_desc))
1097 {
1098 if (wi != 0)
1099 {
1100 delWInfo(desc);
1101 }
1102 delRInfo(desc);
1103 }
1104 }
1105 }
1106
1107 static void
dump_stats()1108 dump_stats()
1109 {
1110 int tcp_pending = 0;
1111 unsigned int i;
1112
1113 for (i = 0; i < _wInfoCount; i++)
1114 {
1115 if (_wInfo[i].len > 0)
1116 {
1117 tcp_pending++;
1118 }
1119 }
1120 snprintf(ebuf, sizeof(ebuf),
1121 "tcp messages waiting for send - %d", tcp_pending);
1122 gdomap_log(LOG_INFO);
1123 snprintf(ebuf, sizeof(ebuf),
1124 "udp messages waiting for send - %d", udp_pending);
1125 gdomap_log(LOG_INFO);
1126 snprintf(ebuf, sizeof(ebuf), "size of name-to-port map - %d", map_used);
1127 gdomap_log(LOG_INFO);
1128 snprintf(ebuf, sizeof(ebuf), "number of known name servers - %"PRIu32,
1129 prb_used);
1130 gdomap_log(LOG_INFO);
1131 snprintf(ebuf, sizeof(ebuf), "TCP %d read, %d sent", tcp_read, tcp_sent);
1132 gdomap_log(LOG_INFO);
1133 snprintf(ebuf, sizeof(ebuf), "UDP %d read, %d sent", udp_read, udp_sent);
1134 gdomap_log(LOG_INFO);
1135 }
1136
1137 #ifndef __MINGW__
1138 static void
dump_tables()1139 dump_tables()
1140 {
1141 FILE *fptr;
1142
1143 soft_int++;
1144 if (access(".", W_OK) != 0)
1145 {
1146 snprintf(ebuf, sizeof(ebuf),
1147 "Failed to access gdomap.dump file for output\n");
1148 gdomap_log(LOG_ERR);
1149 return;
1150 }
1151 fptr = fopen("gdomap.dump", "w");
1152 if (fptr != 0)
1153 {
1154 fprintf(fptr, "\n");
1155 fprintf(fptr, "Known nameserver addresses\n");
1156 fprintf(fptr, "==========================\n");
1157 if (prb_used == 0)
1158 {
1159 fprintf(fptr, "None.\n");
1160 }
1161 else
1162 {
1163 unsigned int i;
1164
1165 for (i = 0; i < prb_used; i++)
1166 {
1167 fprintf(fptr, "%16s %s\n",
1168 inet_ntoa(prb[i]->sin), (const char*)ctime(&prb[i]->when));
1169 }
1170 }
1171
1172 fprintf(fptr, "\n");
1173 fclose(fptr);
1174 }
1175 else
1176 {
1177 snprintf(ebuf, sizeof(ebuf),
1178 "Failed to open gdomap.dump file for output\n");
1179 gdomap_log(LOG_ERR);
1180 }
1181 }
1182 #endif
1183
1184 /*
1185 * Name - init_iface()
1186 * Purpose - Build up an array of the IP addresses supported on
1187 * the network interfaces of this machine.
1188 */
1189 static void
init_iface()1190 init_iface()
1191 {
1192 #if defined(__MINGW__)
1193 INTERFACE_INFO InterfaceList[20];
1194 uint32_t nBytesReturned;
1195 int i, countActive, nNumInterfaces;
1196 SOCKET desc = WSASocket(PF_INET, SOCK_RAW, AF_INET, 0, 0, 0);
1197
1198 if (desc == INVALID_SOCKET)
1199 {
1200 snprintf(ebuf, sizeof(ebuf),
1201 "Failed to get a socket. Error %d\n", WSAGetLastError());
1202 gdomap_log(LOG_CRIT);
1203 exit(EXIT_FAILURE);
1204 }
1205
1206 memset((void*)InterfaceList, '\0', sizeof(InterfaceList));
1207 if (WSAIoctl(desc, SIO_GET_INTERFACE_LIST, 0, 0, (void*)InterfaceList,
1208 sizeof(InterfaceList), &nBytesReturned, 0, 0) == SOCKET_ERROR)
1209 {
1210 snprintf(ebuf, sizeof(ebuf),
1211 "Failed WSAIoctl. Error %d\n", WSAGetLastError());
1212 gdomap_log(LOG_CRIT);
1213 exit(EXIT_FAILURE);
1214 }
1215
1216 nNumInterfaces = nBytesReturned / sizeof(INTERFACE_INFO);
1217
1218 /*
1219 * See how many active entries there are.
1220 */
1221 countActive = 0;
1222 for (i = 0; i < nNumInterfaces; i++)
1223 {
1224 u_long nFlags = InterfaceList[i].iiFlags;
1225
1226 if ((nFlags & IFF_UP)
1227 && (InterfaceList[i].iiAddress.Address.sa_family == AF_INET))
1228 {
1229 countActive++;
1230 }
1231 }
1232
1233 /*
1234 * Allocate enough space for all interfaces.
1235 */
1236 if (addr != 0) free(addr);
1237 addr = (struct in_addr*)malloc((countActive+1)*IASIZE);
1238 if (bcok != 0) free(bcok);
1239 bcok = (unsigned char*)malloc((countActive+1)*sizeof(unsigned char));
1240 if (bcst != 0) free(bcst);
1241 bcst = (struct in_addr*)malloc((countActive+1)*IASIZE);
1242 if (mask != 0) free(mask);
1243 mask = (struct in_addr*)malloc((countActive+1)*IASIZE);
1244
1245 for (i = 0; i < nNumInterfaces; i++)
1246 {
1247 u_long nFlags = InterfaceList[i].iiFlags;
1248
1249 if ((nFlags & IFF_UP)
1250 && (InterfaceList[i].iiAddress.Address.sa_family == AF_INET))
1251 {
1252 int broadcast = 0;
1253 int pointopoint = 0;
1254 int loopback = 0;
1255
1256 if (nFlags & IFF_BROADCAST)
1257 {
1258 broadcast = 1;
1259 }
1260 if (nFlags & IFF_POINTTOPOINT)
1261 {
1262 pointopoint = 1;
1263 }
1264 if (nFlags & IFF_LOOPBACK)
1265 {
1266 loopback = 1;
1267 }
1268 addr[interfaces] = ((struct sockaddr_in*)
1269 &(InterfaceList[i].iiAddress))->sin_addr;
1270 mask[interfaces] = ((struct sockaddr_in*)
1271 &(InterfaceList[i].iiNetmask))->sin_addr;
1272 bcst[interfaces] = ((struct sockaddr_in*)
1273 &(InterfaceList[i].iiBroadcastAddress))->sin_addr;
1274 bcok[interfaces] = (broadcast | pointopoint);
1275
1276 if (addr[interfaces].s_addr == 0)
1277 {
1278 addr[interfaces].s_addr = htonl(0x8f000001);
1279 fprintf(stderr, "Bad iface addr (0.0.0.0) guess (%s)\n",
1280 inet_ntoa(addr[interfaces]));
1281 }
1282 if (mask[interfaces].s_addr == 0)
1283 {
1284 mask[interfaces].s_addr = htonl(0xffffff00);
1285 fprintf(stderr, "Bad iface mask (0.0.0.0) guess (%s)\n",
1286 inet_ntoa(mask[interfaces]));
1287 }
1288 if (bcst[interfaces].s_addr == 0)
1289 {
1290 u_long l = ntohl(addr[interfaces].s_addr);
1291 bcst[interfaces].s_addr = htonl(l | 0xff);
1292 fprintf(stderr, "Bad iface bcst (0.0.0.0) guess (%s)\n",
1293 inet_ntoa(bcst[interfaces]));
1294 }
1295 interfaces++;
1296 }
1297 }
1298 closesocket(desc);
1299 #else
1300 #if defined(SIOCGIFCONF)
1301 struct ifconf ifc;
1302 struct ifreq ifreq;
1303 void *final;
1304 void *ifr_ptr;
1305 char buf[MAX_IFACE * sizeof(struct ifreq)];
1306 int desc;
1307
1308 if ((desc = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1309 {
1310 perror("socket for init_iface");
1311 exit(EXIT_FAILURE);
1312 }
1313 // QNX seems to disagree about what it means to be SysV r4.
1314 #if defined(__svr4__) && !defined(__QNXNTO__)
1315 {
1316 struct strioctl ioc;
1317
1318 ioc.ic_cmd = SIOCGIFCONF;
1319 ioc.ic_timout = 0;
1320 ioc.ic_len = sizeof(buf);
1321 ioc.ic_dp = buf;
1322 if (ioctl(desc, I_STR, (char*)&ioc) < 0)
1323 {
1324 ioc.ic_len = 0;
1325 }
1326 ifc.ifc_len = ioc.ic_len;
1327 ifc.ifc_buf = ioc.ic_dp;
1328 }
1329 #else
1330 ifc.ifc_len = sizeof(buf);
1331 ifc.ifc_buf = buf;
1332 if (ioctl(desc, SIOCGIFCONF, (char*)&ifc) < 0)
1333 {
1334 ifc.ifc_len = 0;
1335 }
1336 #endif
1337
1338 /*
1339 * Find the IP address of each active network interface.
1340 */
1341 if (ifc.ifc_len == 0)
1342 {
1343 int res = errno;
1344
1345 snprintf(ebuf, sizeof(ebuf),
1346 "SIOCGIFCONF for init_iface found no active interfaces; %s", lastErr());
1347 gdomap_log(LOG_ERR);
1348
1349 if (res == EINVAL)
1350 {
1351 snprintf(ebuf, sizeof(ebuf),
1352 "Either you have too many network interfaces on your machine (in which case\n"
1353 "you need to change the 'MAX_IFACE' constant in gdomap.c and rebuild it), or\n"
1354 "your system is buggy, and you need to use the '-a' command line flag for\n"
1355 "gdomap to manually set the interface addresses and masks to be used.\n"
1356 "Try 'gdomap -C' for more information.\n");
1357 gdomap_log(LOG_INFO);
1358 }
1359 close(desc);
1360 exit(EXIT_FAILURE);
1361 }
1362 /*
1363 * We cannot know the number of interfaces in advance, thus we
1364 * need to malloc to MAX_IFACE toensure sufficient space
1365 */
1366 if (addr != 0) free(addr);
1367 addr = (struct in_addr*)malloc((MAX_IFACE+1)*IASIZE);
1368 if (bcok != 0) free(bcok);
1369 bcok = (unsigned char*)malloc((MAX_IFACE+1)*sizeof(unsigned char));
1370 if (bcst != 0) free(bcst);
1371 bcst = (struct in_addr*)malloc((MAX_IFACE+1)*IASIZE);
1372 if (mask != 0) free(mask);
1373 mask = (struct in_addr*)malloc((MAX_IFACE+1)*IASIZE);
1374
1375 final = &ifc.ifc_buf[ifc.ifc_len];
1376 for (ifr_ptr = ifc.ifc_req; ifr_ptr < final;)
1377 {
1378 ifreq = *(struct ifreq*)ifr_ptr;
1379 #if defined(HAVE_SA_LEN)
1380 ifr_ptr += sizeof(ifreq) - sizeof(ifreq.ifr_addr)
1381 + ROUND(ifreq.ifr_addr.sa_len, sizeof(struct ifreq*));
1382 #else
1383 ifr_ptr += sizeof(ifreq);
1384 #endif
1385
1386 if (ioctl(desc, SIOCGIFFLAGS, (char *)&ifreq) < 0)
1387 {
1388 snprintf(ebuf, sizeof(ebuf), "SIOCGIFFLAGS: %s", lastErr());
1389 gdomap_log(LOG_ERR);
1390 }
1391 else if (ifreq.ifr_flags & IFF_UP)
1392 { /* interface is up */
1393 int broadcast = 0;
1394 int pointopoint = 0;
1395 int loopback = 0;
1396
1397 if (ifreq.ifr_flags & IFF_BROADCAST)
1398 {
1399 broadcast = 1;
1400 }
1401 #if defined(IFF_POINTOPOINT)
1402 if (ifreq.ifr_flags & IFF_POINTOPOINT)
1403 {
1404 pointopoint = 1;
1405 }
1406 #endif
1407 #if defined(IFF_LOOPBACK)
1408 if (ifreq.ifr_flags & IFF_LOOPBACK)
1409 {
1410 loopback = 1;
1411 }
1412 #endif
1413 if (ioctl(desc, SIOCGIFADDR, (char *)&ifreq) < 0)
1414 {
1415 snprintf(ebuf, sizeof(ebuf), "SIOCGIFADDR: %s", lastErr());
1416 gdomap_log(LOG_ERR);
1417 }
1418 else if (ifreq.ifr_addr.sa_family == AF_INET)
1419 { /* IP interface */
1420 if (interfaces >= MAX_IFACE)
1421 {
1422 snprintf(ebuf, sizeof(ebuf),
1423 "You have too many network interfaces on your machine (in which case you need\n"
1424 "to change the 'MAX_IFACE' constant in gdomap.c and rebuild it), or your\n"
1425 "system is buggy, and you need to use the '-a' command line flag for\n"
1426 "gdomap to manually set the interface addresses and masks to be used.\n"
1427 "Try 'gdomap -C' for more information.\n");
1428 gdomap_log(LOG_INFO);
1429 close(desc);
1430 exit(EXIT_FAILURE);
1431 }
1432 addr[interfaces] =
1433 ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
1434 bcok[interfaces] = (broadcast | pointopoint);
1435 #if defined(IFF_POINTOPOINT)
1436 if (pointopoint)
1437 {
1438 if (ioctl(desc, SIOCGIFDSTADDR, (char*)&ifreq) < 0)
1439 {
1440 snprintf(ebuf, sizeof(ebuf),
1441 "SIOCGIFADDR: %s", lastErr());
1442 gdomap_log(LOG_ERR);
1443 bcok[interfaces] = 0;
1444 }
1445 else
1446 {
1447 bcst[interfaces]
1448 = ((struct sockaddr_in *)&ifreq.ifr_dstaddr)->sin_addr;
1449 }
1450 }
1451 else
1452 #endif
1453 {
1454 if (!loopback
1455 && ioctl(desc, SIOCGIFBRDADDR, (char*)&ifreq) < 0)
1456 {
1457 snprintf(ebuf, sizeof(ebuf),
1458 "SIOCGIFBRDADDR: %s", lastErr());
1459 gdomap_log(LOG_ERR);
1460 bcok[interfaces] = 0;
1461 }
1462 else
1463 {
1464 bcst[interfaces]
1465 = ((struct sockaddr_in*)&ifreq.ifr_broadaddr)->sin_addr;
1466 }
1467 }
1468 if (ioctl(desc, SIOCGIFNETMASK, (char *)&ifreq) < 0)
1469 {
1470 snprintf(ebuf, sizeof(ebuf), "SIOCGIFNETMASK: %s", lastErr());
1471 gdomap_log(LOG_ERR);
1472 /*
1473 * If we can't get a netmask - assume a class-c
1474 * network.
1475 */
1476 mask[interfaces] = class_c_mask;
1477 }
1478 else
1479 {
1480 /*
1481 * Some systems don't have ifr_netmask
1482 */
1483 #ifdef ifr_netmask
1484 mask[interfaces] =
1485 ((struct sockaddr_in *)&ifreq.ifr_netmask)->sin_addr;
1486 #else
1487 mask[interfaces] =
1488 ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
1489 #endif
1490 }
1491 interfaces++;
1492 }
1493 }
1494 }
1495 close(desc);
1496 #endif /* SIOCGIFCONF */
1497 #endif /* MINGW */
1498
1499 if (interfaces == 0)
1500 {
1501 snprintf(ebuf, sizeof(ebuf),
1502 "I can't find any network interfaces on this platform - "
1503 "use the '-a' flag to load interface details from a file instead.\n"
1504 "Try 'gdomap -C' for more information.\n");
1505 gdomap_log(LOG_CRIT);
1506 exit(EXIT_FAILURE);
1507 }
1508 }
1509
1510 /*
1511 * Name - load_iface()
1512 * Purpose - Read addresses and netmasks for interfaces on this
1513 * machine from a file.
1514 */
1515 static void
load_iface(const char * from)1516 load_iface(const char* from)
1517 {
1518 FILE *fptr;
1519 char buf[128];
1520 int line = 0;
1521 int num_iface = 0;
1522
1523 in_config = 1;
1524
1525 /* Can we open the fiel with current privs
1526 */
1527 fptr = fopen(from, "rt");
1528 if (fptr == 0)
1529 {
1530 snprintf(ebuf, sizeof(ebuf),
1531 "Unable to open address config - '%s'", from);
1532 gdomap_log(LOG_CRIT);
1533 exit(EXIT_FAILURE);
1534 }
1535 /* Should we be opening it?
1536 */
1537 if (access(from, R_OK) != 0)
1538 {
1539 fclose(fptr);
1540 snprintf(ebuf, sizeof(ebuf),
1541 "Unable to access address config - '%s'", from);
1542 gdomap_log(LOG_CRIT);
1543 exit(EXIT_FAILURE);
1544 }
1545
1546 while (fgets(buf, sizeof(buf), fptr) != 0)
1547 {
1548 char *ptr = buf;
1549
1550 line++;
1551 /*
1552 * Strip leading white space.
1553 */
1554 while (isspace(*ptr))
1555 {
1556 ptr++;
1557 }
1558 if (ptr != buf)
1559 {
1560 strcpy(buf, ptr);
1561 }
1562 /*
1563 * Strip comments.
1564 */
1565 ptr = strchr(buf, '#');
1566 if (ptr)
1567 {
1568 *ptr = '\0';
1569 }
1570 /*
1571 * Strip trailing white space.
1572 */
1573 ptr = buf;
1574 while (*ptr)
1575 {
1576 ptr++;
1577 }
1578 while (ptr > buf && isspace(ptr[-1]))
1579 {
1580 ptr--;
1581 }
1582 *ptr = '\0';
1583 /*
1584 * Ignore blank lines.
1585 */
1586 if (*buf == '\0')
1587 {
1588 continue;
1589 }
1590 if (num_iface++ > 1000)
1591 {
1592 snprintf(ebuf, sizeof(ebuf), "Too many network interfaces found");
1593 gdomap_log(LOG_CRIT);
1594 exit(EXIT_FAILURE);
1595 }
1596 }
1597 fseek(fptr, 0, 0);
1598
1599 if (num_iface == 0)
1600 {
1601 snprintf(ebuf, sizeof(ebuf), "No network interfaces found");
1602 gdomap_log(LOG_CRIT);
1603 exit(EXIT_FAILURE);
1604 }
1605 num_iface++;
1606 addr = (struct in_addr*)malloc((num_iface+1)*IASIZE);
1607 mask = (struct in_addr*)malloc((num_iface+1)*IASIZE);
1608 bcok = (unsigned char*)malloc((num_iface+1)*sizeof(unsigned char));
1609 bcst = (struct in_addr*)malloc((num_iface+1)*IASIZE);
1610
1611 addr[interfaces].s_addr = inet_addr("127.0.0.1");
1612 mask[interfaces].s_addr = inet_addr("255.255.255.0");
1613 bcok[interfaces] = 0;
1614 bcst[interfaces].s_addr = inet_addr("127.0.0.255");
1615 interfaces++;
1616
1617 while (fgets(buf, sizeof(buf), fptr) != 0)
1618 {
1619 char *ptr = buf;
1620 char *msk;
1621
1622 line++;
1623 /*
1624 * Strip leading white space.
1625 */
1626 while (isspace(*ptr))
1627 {
1628 ptr++;
1629 }
1630 if (ptr != buf)
1631 {
1632 strcpy(buf, ptr);
1633 }
1634 /*
1635 * Strip comments.
1636 */
1637 ptr = strchr(buf, '#');
1638 if (ptr)
1639 {
1640 *ptr = '\0';
1641 }
1642 /*
1643 * Strip trailing white space.
1644 */
1645 ptr = buf;
1646 while (*ptr)
1647 {
1648 ptr++;
1649 }
1650 while (ptr > buf && isspace(ptr[-1]))
1651 {
1652 ptr--;
1653 }
1654 *ptr = '\0';
1655 /*
1656 * Ignore blank lines.
1657 */
1658 if (*buf == '\0')
1659 {
1660 continue;
1661 }
1662
1663 ptr = buf;
1664 while (*ptr && (isdigit(*ptr) || (*ptr == '.')))
1665 {
1666 ptr++;
1667 }
1668 while (isspace(*ptr))
1669 {
1670 *ptr++ = '\0';
1671 }
1672 msk = ptr;
1673 while (*ptr && (isdigit(*ptr) || (*ptr == '.')))
1674 {
1675 ptr++;
1676 }
1677 while (isspace(*ptr))
1678 {
1679 *ptr++ = '\0';
1680 }
1681 addr[interfaces].s_addr = inet_addr(buf);
1682 mask[interfaces].s_addr = inet_addr(msk);
1683 if (isdigit(*ptr))
1684 {
1685 bcok[interfaces] = 1;
1686 bcst[interfaces].s_addr = inet_addr(ptr);
1687 }
1688 else
1689 {
1690 bcok[interfaces] = 0;
1691 bcst[interfaces].s_addr = inet_addr("0.0.0.0");
1692 }
1693 if (addr[interfaces].s_addr == (uint32_t)-1)
1694 {
1695 snprintf(ebuf, sizeof(ebuf), "line %d of '%s' bad address (%s)",
1696 line, from, buf);
1697 gdomap_log(LOG_CRIT);
1698 exit(EXIT_FAILURE);
1699 }
1700 else if (mask[interfaces].s_addr == (uint32_t)-1)
1701 {
1702 snprintf(ebuf, sizeof(ebuf), "line %d of '%s' bad netmask (%s)",
1703 line, from, ptr);
1704 gdomap_log(LOG_CRIT);
1705 exit(EXIT_FAILURE);
1706 }
1707 else
1708 {
1709 interfaces++;
1710 }
1711 }
1712 fclose(fptr);
1713 in_config = 0;
1714 }
1715
1716 /*
1717 * Name - init_my_port()
1718 * Purpose - Establish our well-known port (my_port).
1719 */
1720 static void
init_my_port()1721 init_my_port()
1722 {
1723 /*
1724 * First we determine the port for the 'gdomap' service - ideally
1725 * this should be the default port, since we should have registered
1726 * this with the appropriate authority and have it reserved for us.
1727 */
1728 #if defined(GDOMAP_PORT_OVERRIDE)
1729 my_port = htons(GDOMAP_PORT_OVERRIDE);
1730 #else
1731 struct servent *sp;
1732
1733 my_port = htons(GDOMAP_PORT);
1734 if ((sp = getservbyname("gdomap", "tcp")) == 0)
1735 {
1736 if (debug)
1737 {
1738 snprintf(ebuf, sizeof(ebuf), "Unable to find service 'gdomap'");
1739 gdomap_log(LOG_WARNING);
1740 snprintf(ebuf, sizeof(ebuf),
1741 "On a unix host it should be in /etc/services "
1742 "as 'gdomap %d/tcp' and 'gdomap %d/udp'\n",
1743 GDOMAP_PORT, GDOMAP_PORT);
1744 gdomap_log(LOG_INFO);
1745 }
1746 }
1747 else
1748 {
1749 unsigned short tcp_port = sp->s_port;
1750
1751 if ((sp = getservbyname("gdomap", "udp")) == 0)
1752 {
1753 if (debug)
1754 {
1755 snprintf(ebuf, sizeof(ebuf), "Unable to find service 'gdomap'");
1756 snprintf(ebuf, sizeof(ebuf),
1757 "On a unix host it should be in /etc/services "
1758 "as 'gdomap %d/tcp' and 'gdomap %d/udp'\n",
1759 GDOMAP_PORT, GDOMAP_PORT);
1760 gdomap_log(LOG_INFO);
1761 }
1762 }
1763 else if (sp->s_port != tcp_port)
1764 {
1765 snprintf(ebuf, sizeof(ebuf),
1766 "UDP and TCP service entries differ. "
1767 "Using the TCP entry for both!");
1768 gdomap_log(LOG_WARNING);
1769 }
1770 if (tcp_port != my_port)
1771 {
1772 snprintf(ebuf, sizeof(ebuf), "gdomap not running on normal port");
1773 gdomap_log(LOG_WARNING);
1774 }
1775 my_port = tcp_port;
1776 }
1777 #endif
1778 }
1779
1780 /*
1781 * Name - init_ports()
1782 * Purpose - Set up the ports for accepting incoming requests.
1783 */
1784 static void
init_ports()1785 init_ports()
1786 {
1787 int r;
1788 struct sockaddr_in sa;
1789 #if defined(__MINGW__)
1790 uint32_t dummy;
1791 #endif /* __MINGW__ */
1792
1793 /*
1794 * Now we set up the sockets to accept incoming connections and set
1795 * options on it so that if this program is killed, we can restart
1796 * immediately and not find the socket addresses hung.
1797 */
1798
1799 udp_desc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1800 #if defined(__MINGW__)
1801 if (udp_desc == INVALID_SOCKET)
1802 #else
1803 if (udp_desc < 0)
1804 #endif
1805 {
1806 snprintf(ebuf, sizeof(ebuf), "Unable to create UDP socket");
1807 gdomap_log(LOG_CRIT);
1808 exit(EXIT_FAILURE);
1809 }
1810 else if (debug)
1811 {
1812 snprintf(ebuf, sizeof(ebuf), "Opened UDP socket %d", udp_desc);
1813 gdomap_log(LOG_DEBUG);
1814 }
1815 #if 0 && defined(SO_EXCLUSIVEADDRUSE)
1816 r = 1;
1817 if ((setsockopt(udp_desc,SOL_SOCKET,SO_REUSEADDR,(char*)&r,sizeof(r)))<0)
1818 {
1819 snprintf(ebuf, sizeof(ebuf), "Unable to set 're-use' on UDP socket");
1820 gdomap_log(LOG_WARNING);
1821 }
1822 r = 1;
1823 if ((setsockopt
1824 (udp_desc,SOL_SOCKET,SO_EXCLUSIVEADDRUSE,(char*)&r,sizeof(r)))<0)
1825 {
1826 snprintf(ebuf, sizeof(ebuf),
1827 "Unable to set 'exclusive-use' on UDP socket");
1828 gdomap_log(LOG_WARNING);
1829 }
1830 #endif
1831 #ifndef BROKEN_SO_REUSEADDR
1832 /*
1833 * Under decent systems, SO_REUSEADDR means that the port can be reused
1834 * immediately that this process exits. Under some it means
1835 * that multiple processes can serve the same port simultaneously.
1836 * We don't want that broken behavior!
1837 */
1838 r = 1;
1839 if ((setsockopt(udp_desc,SOL_SOCKET,SO_REUSEADDR,(char*)&r,sizeof(r)))<0)
1840 {
1841 snprintf(ebuf, sizeof(ebuf), "Unable to set 're-use' on UDP socket");
1842 gdomap_log(LOG_WARNING);
1843 }
1844 #endif
1845 if (nobcst == 0)
1846 {
1847 r = 1;
1848 if ((setsockopt(udp_desc,SOL_SOCKET,SO_BROADCAST,(char*)&r,sizeof(r)))<0)
1849 {
1850 nobcst++;
1851 snprintf(ebuf, sizeof(ebuf), "Unable to use 'broadcast' for probes");
1852 gdomap_log(LOG_WARNING);
1853 }
1854 }
1855 #if defined(__MINGW__)
1856 dummy = 1;
1857 if (ioctlsocket(udp_desc, FIONBIO, &dummy) < 0)
1858 {
1859 snprintf(ebuf, sizeof(ebuf), "Unable to handle UDP socket non-blocking");
1860 gdomap_log(LOG_CRIT);
1861 exit(EXIT_FAILURE);
1862 }
1863 #else /* !__MINGW__ */
1864 if ((r = fcntl(udp_desc, F_GETFL, 0)) >= 0)
1865 {
1866 r |= NBLK_OPT;
1867 if (fcntl(udp_desc, F_SETFL, r) < 0)
1868 {
1869 snprintf(ebuf, sizeof(ebuf), "Unable to set UDP socket non-blocking");
1870 gdomap_log(LOG_CRIT);
1871 exit(EXIT_FAILURE);
1872 }
1873 }
1874 else
1875 {
1876 snprintf(ebuf, sizeof(ebuf), "Unable to handle UDP socket non-blocking");
1877 gdomap_log(LOG_CRIT);
1878 exit(EXIT_FAILURE);
1879 }
1880 #endif
1881 /*
1882 * Now we bind our address to the socket and prepare to accept incoming
1883 * connections by listening on it.
1884 */
1885 memset(&sa, '\0', sizeof(sa));
1886 sa.sin_family = AF_INET;
1887 sa.sin_addr.s_addr = htonl(INADDR_ANY);
1888 sa.sin_port = my_port;
1889 if (bind(udp_desc, (void*)&sa, sizeof(sa)) < 0)
1890 {
1891 snprintf(ebuf, sizeof(ebuf),
1892 "Unable to bind address to UDP socket. Perhaps gdomap is already running");
1893 gdomap_log(LOG_ERR);
1894 if (errno == EACCES)
1895 {
1896 snprintf(ebuf, sizeof(ebuf),
1897 "You probably need to run gdomap as root/system administrator (recommended),\n"
1898 "or run the nameserver on a non-standard port that does not require root\n"
1899 "privilege (poor option and last resort!!!)");
1900 gdomap_log(LOG_INFO);
1901 }
1902 exit(EXIT_FAILURE);
1903 }
1904
1905 /*
1906 * Now we do the TCP socket.
1907 */
1908 tcp_desc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1909 #if defined(__MINGW__)
1910 if (tcp_desc == INVALID_SOCKET)
1911 #else
1912 if (tcp_desc < 0)
1913 #endif
1914 {
1915 snprintf(ebuf, sizeof(ebuf), "Unable to create TCP socket");
1916 gdomap_log(LOG_CRIT);
1917 exit(EXIT_FAILURE);
1918 }
1919 else if (debug)
1920 {
1921 snprintf(ebuf, sizeof(ebuf), "Opened TDP socket %d", tcp_desc);
1922 gdomap_log(LOG_DEBUG);
1923 }
1924 #if 0 && defined(SO_EXCLUSIVEADDRUSE)
1925 r = 1;
1926 if ((setsockopt(tcp_desc,SOL_SOCKET,SO_REUSEADDR,(char*)&r,sizeof(r)))<0)
1927 {
1928 snprintf(ebuf, sizeof(ebuf), "Unable to set 're-use' on TCP socket");
1929 gdomap_log(LOG_WARNING);
1930 }
1931 r = 1;
1932 if ((setsockopt
1933 (tcp_desc,SOL_SOCKET,SO_EXCLUSIVEADDRUSE,(char*)&r,sizeof(r)))<0)
1934 {
1935 snprintf(ebuf, sizeof(ebuf),
1936 "Unable to set 'exclusive-use' on TCP socket");
1937 gdomap_log(LOG_WARNING);
1938 }
1939 #endif
1940 #ifndef BROKEN_SO_REUSEADDR
1941 /*
1942 * Under decent systems, SO_REUSEADDR means that the port can be reused
1943 * immediately that this process exits. Under some it means
1944 * that multiple processes can serve the same port simultaneously.
1945 * We don't want that broken behavior!
1946 */
1947 r = 1;
1948 if ((setsockopt(tcp_desc,SOL_SOCKET,SO_REUSEADDR,(char*)&r,sizeof(r)))<0)
1949 {
1950 snprintf(ebuf, sizeof(ebuf), "Unable to set 're-use' on TCP socket");
1951 gdomap_log(LOG_WARNING);
1952 }
1953 #endif
1954
1955 #if defined(__MINGW__)
1956 dummy = 1;
1957 if (ioctlsocket(tcp_desc, FIONBIO, &dummy) < 0)
1958 {
1959 snprintf(ebuf, sizeof(ebuf), "Unable to handle TCP socket non-blocking");
1960 gdomap_log(LOG_CRIT);
1961 exit(EXIT_FAILURE);
1962 }
1963 #else /* !__MINGW__ */
1964 if ((r = fcntl(tcp_desc, F_GETFL, 0)) >= 0)
1965 {
1966 r |= NBLK_OPT;
1967 if (fcntl(tcp_desc, F_SETFL, r) < 0)
1968 {
1969 snprintf(ebuf, sizeof(ebuf), "Unable to set TCP socket non-blocking");
1970 gdomap_log(LOG_CRIT);
1971 exit(EXIT_FAILURE);
1972 }
1973 }
1974 else
1975 {
1976 snprintf(ebuf, sizeof(ebuf), "Unable to handle TCP socket non-blocking");
1977 gdomap_log(LOG_CRIT);
1978 exit(EXIT_FAILURE);
1979 }
1980 #endif /* __MINGW__ */
1981
1982 memset(&sa, '\0', sizeof(sa));
1983 sa.sin_family = AF_INET;
1984 sa.sin_addr.s_addr = htonl(INADDR_ANY);
1985 sa.sin_port = my_port;
1986 if (bind(tcp_desc, (void*)&sa, sizeof(sa)) < 0)
1987 {
1988 snprintf(ebuf, sizeof(ebuf),
1989 "Unable to bind address to TCP socket. Perhaps gdomap is already running");
1990 gdomap_log(LOG_ERR);
1991 if (errno == EACCES)
1992 {
1993 snprintf(ebuf, sizeof(ebuf),
1994 "You probably need to run gdomap as root/system administrator (recommended),\n"
1995 "or run the nameserver on a non-standard port that does not require root\n"
1996 "privilege (poor option and last resort!!!)");
1997 gdomap_log(LOG_INFO);
1998 }
1999 exit(EXIT_FAILURE);
2000 }
2001 if (listen(tcp_desc, QUEBACKLOG) < 0)
2002 {
2003 snprintf(ebuf, sizeof(ebuf),
2004 "Unable to listen for connections on TCP socket");
2005 gdomap_log(LOG_CRIT);
2006 exit(EXIT_FAILURE);
2007 }
2008
2009 /*
2010 * Set up masks to say we are interested in these descriptors.
2011 */
2012 memset(&read_fds, '\0', sizeof(read_fds));
2013 memset(&write_fds, '\0', sizeof(write_fds));
2014
2015 getRInfo(tcp_desc, 1);
2016 getRInfo(udp_desc, 1);
2017
2018 FD_SET(tcp_desc, &read_fds);
2019 FD_SET(udp_desc, &read_fds);
2020
2021 #ifndef __MINGW__
2022 /*
2023 * Turn off pipe signals so we don't get interrupted if we attempt
2024 * to write a response to a process which has died.
2025 */
2026 signal(SIGPIPE, SIG_IGN);
2027 /*
2028 * Enable table dumping to /tmp/gdomap.dump
2029 */
2030 signal(SIGUSR1, dump_tables);
2031 #endif /* !__MINGW__ */
2032 }
2033
2034
2035 static int
other_addresses_on_net(struct in_addr old,struct in_addr ** extra)2036 other_addresses_on_net(struct in_addr old, struct in_addr **extra)
2037 {
2038 int numExtra = 0;
2039 int iface;
2040
2041 for (iface = 0; iface < interfaces; iface++)
2042 {
2043 if (addr[iface].s_addr == old.s_addr)
2044 {
2045 continue;
2046 }
2047 if ((addr[iface].s_addr & mask[iface].s_addr) ==
2048 (old.s_addr & mask[iface].s_addr))
2049 {
2050 numExtra++;
2051 }
2052 }
2053 if (numExtra > 0)
2054 {
2055 struct in_addr *addrs;
2056
2057 addrs = (struct in_addr*)malloc(sizeof(struct in_addr)*numExtra);
2058 *extra = addrs;
2059 numExtra = 0;
2060
2061 for (iface = 0; iface < interfaces; iface++)
2062 {
2063 if (addr[iface].s_addr == old.s_addr)
2064 {
2065 continue;
2066 }
2067 if ((addr[iface].s_addr & mask[iface].s_addr) ==
2068 (old.s_addr & mask[iface].s_addr))
2069 {
2070 addrs[numExtra].s_addr = addr[iface].s_addr;
2071 numExtra++;
2072 }
2073 }
2074 }
2075 return numExtra;
2076 }
2077
2078
2079 /*
2080 * Name - init_probe()
2081 * Purpose - Send a request to all hosts on the local network
2082 * to see if there is a name server running on them.
2083 */
2084 static void
init_probe()2085 init_probe()
2086 {
2087 uint32_t nlist[interfaces];
2088 int nlist_size = 0;
2089 int iface;
2090 int i;
2091
2092 if (noprobe > 0)
2093 {
2094 return;
2095 }
2096 if (debug > 2)
2097 {
2098 snprintf(ebuf, sizeof(ebuf), "Initiating probe requests.");
2099 gdomap_log(LOG_DEBUG);
2100 }
2101
2102 /*
2103 * Make a list of the different networks to which we must send.
2104 */
2105 for (iface = 0; iface < interfaces; iface++)
2106 {
2107 uint32_t net = (addr[iface].s_addr & mask[iface].s_addr);
2108
2109 if (addr[iface].s_addr == loopback.s_addr)
2110 {
2111 continue; /* Skip loopback */
2112 }
2113 for (i = 0; i < nlist_size; i++)
2114 {
2115 if (net == nlist[i])
2116 {
2117 break;
2118 }
2119 }
2120 if (i == nlist_size)
2121 {
2122 nlist[i] = net;
2123 nlist_size++;
2124 }
2125 }
2126
2127 for (i = 0; i < nlist_size; i++)
2128 {
2129 int broadcast = 0;
2130 int elen = 0;
2131 struct in_addr *other = 0;
2132 struct in_addr sin = { 0 };
2133 int high = 0;
2134 int low = 0;
2135 uint32_t net = 0;
2136 int j;
2137 struct in_addr b;
2138
2139 /*
2140 * Build up a list of addresses that we serve on this network.
2141 */
2142 for (iface = 0; iface < interfaces; iface++)
2143 {
2144 if ((addr[iface].s_addr & mask[iface].s_addr) == nlist[i])
2145 {
2146 sin = addr[iface];
2147 if (bcok[iface])
2148 {
2149 /*
2150 * Simple broadcast for this address.
2151 */
2152 b.s_addr = bcst[iface].s_addr;
2153 broadcast = 1;
2154 }
2155 else
2156 {
2157 uint32_t ha; /* full host address. */
2158 uint32_t hm; /* full netmask. */
2159
2160 ha = ntohl(addr[iface].s_addr);
2161 hm = ntohl(mask[iface].s_addr);
2162
2163 /*
2164 * Make sure that our netmasks are restricted
2165 * to class-c networks and subnets of those
2166 * networks - we don't want to be probing
2167 * more than a couple of hundred hosts!
2168 */
2169 if ((mask[iface].s_addr | class_c_mask.s_addr)
2170 != mask[iface].s_addr)
2171 {
2172 snprintf(ebuf, sizeof(ebuf), "netmask %s will be "
2173 "treated as 255.255.255.0 for ",
2174 inet_ntoa(mask[iface]));
2175 strncat(ebuf, inet_ntoa(addr[iface]),
2176 sizeof(ebuf) - strlen(ebuf) - 1);
2177 gdomap_log(LOG_WARNING);
2178 hm |= ~255;
2179 }
2180 net = ha & hm & ~255; /* class-c net number. */
2181 low = ha & hm & 255; /* low end of subnet. */
2182 high = low | (255 & ~hm); /* high end of subnet. */
2183 elen = other_addresses_on_net(sin, &other);
2184 }
2185 break;
2186 }
2187 }
2188
2189 if (plist)
2190 {
2191 plentry *p;
2192
2193 /*
2194 * Now start probes for servers on machines in our probe config
2195 * list for which we have a direct connection.
2196 */
2197 for (p = plist; p != 0; p = p->next)
2198 {
2199 if ((p->addr.s_addr & mask[iface].s_addr) ==
2200 (addr[iface].s_addr & mask[iface].s_addr))
2201 {
2202 unsigned int len = elen;
2203
2204 p->direct = 1;
2205 /* Kick off probe. */
2206 if (is_local_host(p->addr))
2207 {
2208 continue; /* Don't probe self. */
2209 }
2210 while (len > MAX_EXTRA)
2211 {
2212 len -= MAX_EXTRA;
2213 queue_probe(&p->addr, &sin, MAX_EXTRA, &other[len], 0);
2214 }
2215 queue_probe(&p->addr, &sin, len, other, 0);
2216 }
2217 }
2218 }
2219 else if (broadcast)
2220 {
2221 /*
2222 * Now broadcast probe on this network.
2223 */
2224 queue_probe(&b, &sin, 0, 0, 0);
2225 }
2226 else
2227 {
2228 /*
2229 * Now start probes for servers on machines which may be on
2230 * any network for which we have an interface.
2231 *
2232 * Assume 'low' and 'high' are not valid host addresses as 'low'
2233 * is the network address and 'high' is the broadcast address.
2234 */
2235 for (j = low + 1; j < high; j++)
2236 {
2237 struct in_addr a;
2238 unsigned int len = elen;
2239
2240 a.s_addr = htonl(net + j);
2241 if (is_local_host(a))
2242 {
2243 continue; /* Don't probe self - that's silly. */
2244 }
2245 /* Kick off probe. */
2246 while (len > MAX_EXTRA)
2247 {
2248 len -= MAX_EXTRA;
2249 queue_probe(&a, &sin, MAX_EXTRA, &other[len], 0);
2250 }
2251 queue_probe(&a, &sin, len, other, 0);
2252 }
2253 }
2254
2255 if (other != NULL)
2256 {
2257 free(other);
2258 }
2259 }
2260
2261 if (plist)
2262 {
2263 plentry *p;
2264 int indirect = 0;
2265
2266 /*
2267 * Are there any hosts for which we do not have a direct
2268 * network connection, and to which we have therefore not
2269 * queued a probe?
2270 */
2271 for (p = plist; p != 0; p = p->next)
2272 {
2273 if (p->direct == 0)
2274 {
2275 indirect = 1;
2276 }
2277 }
2278 if (indirect)
2279 {
2280 struct in_addr *other = 0;
2281 int elen;
2282
2283 /*
2284 * Queue probes for indirect connections to hosts from our
2285 * primary interface and let the routing system handle it.
2286 */
2287 elen = other_addresses_on_net(addr[0], &other);
2288 for (p = plist; p != 0; p = p->next)
2289 {
2290 if (p->direct == 0)
2291 {
2292 unsigned int len = elen;
2293
2294 if (is_local_host(p->addr))
2295 {
2296 continue; /* Don't probe self. */
2297 }
2298 /* Kick off probe. */
2299 while (len > MAX_EXTRA)
2300 {
2301 len -= MAX_EXTRA;
2302 queue_probe(&p->addr, addr, MAX_EXTRA, &other[len], 0);
2303 }
2304 queue_probe(&p->addr, addr, len, other, 0);
2305 }
2306 }
2307 if (0 != other)
2308 {
2309 free(other);
2310 }
2311 }
2312 }
2313
2314 if (debug > 2)
2315 {
2316 snprintf(ebuf, sizeof(ebuf), "Probe requests initiated.");
2317 gdomap_log(LOG_DEBUG);
2318 }
2319 last_probe = time(0);
2320 }
2321
2322 /*
2323 * Name - handle_accept()
2324 * Purpose - Handle an incoming connection, setting up resources
2325 * for the request. Ensure that the channel is in
2326 * non-blocking mode so that we can't hang.
2327 */
2328 static void
handle_accept()2329 handle_accept()
2330 {
2331 struct sockaddr_in sa;
2332 socklen_t len = sizeof(sa);
2333 int desc;
2334
2335 memset(&sa, '\0', len);
2336 desc = accept(tcp_desc, (void*)&sa, &len);
2337 if (desc >= 0)
2338 {
2339 RInfo *ri;
2340 #if defined(__MINGW__)
2341 uint32_t dummy = 1;
2342 #else
2343 int r;
2344 #endif /* !__MINGW__ */
2345
2346 FD_SET(desc, &read_fds);
2347 ri = getRInfo(desc, 1);
2348 ri->pos = 0;
2349 memcpy((char*)&ri->addr, (char*)&sa, sizeof(sa));
2350
2351 if (debug)
2352 {
2353 snprintf(ebuf, sizeof(ebuf), "accept from %s(%d) to chan %d",
2354 inet_ntoa(sa.sin_addr), ntohs(sa.sin_port), desc);
2355 gdomap_log(LOG_DEBUG);
2356 }
2357 /*
2358 * Ensure that the connection is non-blocking.
2359 */
2360 #if defined(__MINGW__)
2361 if (ioctlsocket(desc, FIONBIO, &dummy) < 0)
2362 {
2363 if (debug)
2364 {
2365 snprintf(ebuf, sizeof(ebuf),
2366 "failed to set chan %d non-blocking", desc);
2367 gdomap_log(LOG_DEBUG);
2368 }
2369 clear_chan(desc);
2370 }
2371 #else /* !__MINGW__ */
2372 if ((r = fcntl(desc, F_GETFL, 0)) >= 0)
2373 {
2374 r |= NBLK_OPT;
2375 if (fcntl(desc, F_SETFL, r) < 0)
2376 {
2377 if (debug)
2378 {
2379 snprintf(ebuf, sizeof(ebuf),
2380 "failed to set chan %d non-blocking", desc);
2381 gdomap_log(LOG_DEBUG);
2382 }
2383 clear_chan(desc);
2384 }
2385 }
2386 else
2387 {
2388 if (debug)
2389 {
2390 snprintf(ebuf, sizeof(ebuf),
2391 "failed to set chan %d non-blocking", desc);
2392 gdomap_log(LOG_DEBUG);
2393 }
2394 clear_chan(desc);
2395 }
2396 #endif /* __MINGW__ */
2397 }
2398 else if (debug)
2399 {
2400 snprintf(ebuf, sizeof(ebuf), "accept failed - errno %d",
2401 #if defined(__MINGW__)
2402 WSAGetLastError());
2403 #else
2404 errno);
2405 #endif /* __MINGW__ */
2406 gdomap_log(LOG_DEBUG);
2407 }
2408 }
2409
2410 /*
2411 * Name - handle_io()
2412 * Purpose - Main loop to handle I/O on multiple simultaneous
2413 * connections. All non-blocking stuff.
2414 */
2415 static void
handle_io()2416 handle_io()
2417 {
2418 struct timeval timeout;
2419 void *to;
2420 int rval = 0;
2421 int i;
2422 fd_set rfds;
2423 fd_set wfds;
2424
2425 while (rval >= 0)
2426 {
2427 rfds = read_fds;
2428 wfds = write_fds;
2429 to = 0;
2430
2431 /*
2432 * If there is anything waiting to be sent on the UDP socket
2433 * we must check to see if it is writable.
2434 */
2435 if (u_queue != 0)
2436 {
2437 FD_SET(udp_desc, &wfds);
2438 }
2439
2440 timeout.tv_sec = 10;
2441 timeout.tv_usec = 0;
2442 to = &timeout;
2443 soft_int = 0;
2444 rval = select(FD_SETSIZE, &rfds, &wfds, 0, to);
2445
2446 if (rval < 0)
2447 {
2448 /*
2449 * Let's handle any error return.
2450 */
2451 if (errno == EBADF)
2452 {
2453 fd_set efds;
2454
2455 /*
2456 * Almost certainly lost a connection - try each
2457 * descriptor in turn to see which one it is.
2458 * Remove descriptor from bitmask and close it.
2459 * If the error is on the listener socket we die.
2460 */
2461 memset(&efds, '\0', sizeof(efds));
2462 for (i = 0; i < FD_SETSIZE; i++)
2463 {
2464 if (FD_ISSET(i, &rfds) || FD_ISSET(i, &wfds))
2465 {
2466 FD_SET(i, &efds);
2467 timeout.tv_sec = 0;
2468 timeout.tv_usec = 0;
2469 to = &timeout;
2470 rval = select(FD_SETSIZE, &efds, 0, 0, to);
2471 FD_CLR(i, &efds);
2472 if (rval < 0 && errno == EBADF)
2473 {
2474 clear_chan(i);
2475 if (i == tcp_desc || i == udp_desc)
2476 {
2477 snprintf(ebuf, sizeof(ebuf),
2478 "Fatal error on socket.");
2479 gdomap_log(LOG_CRIT);
2480 exit(EXIT_FAILURE);
2481 }
2482 }
2483 }
2484 }
2485 rval = 0;
2486 }
2487 else if (soft_int > 0)
2488 {
2489 /*
2490 * We were interrupted - but it was one we were expecting.
2491 */
2492 rval = 0;
2493 }
2494 else if (errno == EINTR)
2495 {
2496 rval = 0;
2497 }
2498 else
2499 {
2500 snprintf(ebuf, sizeof(ebuf),
2501 "Interrupted in select: %s",strerror(errno));
2502 gdomap_log(LOG_CRIT);
2503 exit(EXIT_FAILURE);
2504 }
2505 }
2506 else if (rval == 0)
2507 {
2508 long now = time(0);
2509
2510 /*
2511 * Let's handle a timeout.
2512 */
2513 prb_tim(now); /* Remove dead servers */
2514 if (udp_pending == 0 && (now - last_probe) >= interval)
2515 {
2516 /*
2517 * If there is no output pending on the udp channel and
2518 * it is at least five minutes since we sent out a probe
2519 * we can re-probe the network for other name servers.
2520 */
2521 init_probe();
2522 }
2523 }
2524 else
2525 {
2526 /*
2527 * Got some descriptor activity - deal with it.
2528 */
2529 #if defined(__MINGW__)
2530 /* read file descriptors */
2531 for (i = 0; i < rfds.fd_count; i++)
2532 {
2533 if (rfds.fd_array[i] == tcp_desc)
2534 {
2535 handle_accept();
2536 }
2537 else if (rfds.fd_array[i] == udp_desc)
2538 {
2539 handle_recv();
2540 }
2541 else
2542 {
2543 handle_read(rfds.fd_array[i]);
2544 }
2545 if (debug > 2)
2546 {
2547 dump_stats();
2548 }
2549 }
2550 for (i = 0; i < wfds.fd_count; i++)
2551 {
2552 if (wfds.fd_array[i] == udp_desc)
2553 {
2554 handle_send();
2555 }
2556 else
2557 {
2558 handle_write(wfds.fd_array[i]);
2559 }
2560 }
2561 #else /* !__MINGW__ */
2562 for (i = 0; i < FD_SETSIZE; i++)
2563 {
2564 if (FD_ISSET(i, &rfds))
2565 {
2566 if (i == tcp_desc)
2567 {
2568 handle_accept();
2569 }
2570 else if (i == udp_desc)
2571 {
2572 handle_recv();
2573 }
2574 else
2575 {
2576 handle_read(i);
2577 }
2578 if (debug > 2)
2579 {
2580 dump_stats();
2581 }
2582 }
2583 /* Look for a descriptor found to be writeable and which
2584 * was not closed (due to reading eof etc)
2585 */
2586 if (FD_ISSET(i, &wfds)
2587 && (FD_ISSET(i, &write_fds) || i == udp_desc))
2588 {
2589 if (i == udp_desc)
2590 {
2591 handle_send();
2592 }
2593 else
2594 {
2595 handle_write(i);
2596 }
2597 }
2598 }
2599 #endif /* __MINGW__ */
2600 }
2601 }
2602 }
2603
2604 /*
2605 * Name - handle_read()
2606 * Purpose - Read a request from a channel. This may be called in
2607 * many stages if the read is blocking.
2608 */
2609 static void
handle_read(int desc)2610 handle_read(int desc)
2611 {
2612 RInfo *ri;
2613 uptr ptr;
2614 int nothingRead = 1;
2615 int done = 0;
2616 int r;
2617
2618 ri = getRInfo(desc, 0);
2619 if (0 == ri)
2620 {
2621 snprintf(ebuf, sizeof(ebuf),
2622 "request not found on descriptor %d", desc);
2623 gdomap_log(LOG_DEBUG);
2624 return;
2625 }
2626 ptr = ri->buf.b;
2627
2628 while (ri->pos < GDO_REQ_SIZE && done == 0)
2629 {
2630 #if defined(__MINGW__)
2631 r = recv(desc, (char *)&ptr[ri->pos], GDO_REQ_SIZE - ri->pos, 0);
2632 #else
2633 r = read(desc, &ptr[ri->pos], GDO_REQ_SIZE - ri->pos);
2634 #endif
2635 if (r > 0)
2636 {
2637 nothingRead = 0;
2638 ri->pos += r;
2639 }
2640 else
2641 {
2642 done = 1;
2643 }
2644 }
2645 if (ri->pos == GDO_REQ_SIZE)
2646 {
2647 tcp_read++;
2648 handle_request(desc);
2649 }
2650 #if defined(__MINGW__)
2651 else if (WSAGetLastError() != WSAEWOULDBLOCK || nothingRead == 1)
2652 #else
2653 else if (errno != EWOULDBLOCK || nothingRead == 1)
2654 #endif
2655 {
2656 /*
2657 * If there is an error or end-of-file on the descriptor then
2658 * we must close it down.
2659 */
2660 clear_chan(desc);
2661 }
2662 }
2663
2664 /*
2665 * Name - handle_recv()
2666 * Purpose - Read a request from the UDP socket.
2667 */
2668 static void
handle_recv()2669 handle_recv()
2670 {
2671 RInfo *ri;
2672 uptr ptr;
2673 struct sockaddr_in* addr;
2674 socklen_t len = sizeof(struct sockaddr_in);
2675 int r;
2676
2677 ri = getRInfo(udp_desc, 0);
2678 if (0 == ri)
2679 {
2680 snprintf(ebuf, sizeof(ebuf),
2681 "request not found on descriptor %d", udp_desc);
2682 gdomap_log(LOG_DEBUG);
2683 return;
2684 }
2685 addr = &(ri->addr);
2686 ptr = ri->buf.b;
2687
2688 r = recvfrom(udp_desc, (char *)ptr, GDO_REQ_SIZE, 0, (void*)addr, &len);
2689 if (r == GDO_REQ_SIZE)
2690 {
2691 udp_read++;
2692 ri->pos = GDO_REQ_SIZE;
2693 if (debug)
2694 {
2695 snprintf(ebuf, sizeof(ebuf),
2696 "recvfrom %s", inet_ntoa(addr->sin_addr));
2697 gdomap_log(LOG_DEBUG);
2698 }
2699 if (is_local_host(addr->sin_addr) == 1)
2700 {
2701 if (debug)
2702 {
2703 snprintf(ebuf, sizeof(ebuf),
2704 "recvfrom packet from self discarded");
2705 gdomap_log(LOG_DEBUG);
2706 }
2707 return;
2708 }
2709 handle_request(udp_desc);
2710 }
2711 else
2712 {
2713 if (debug)
2714 {
2715 snprintf(ebuf, sizeof(ebuf),
2716 "recvfrom returned %d - %s", r, lastErr());
2717 gdomap_log(LOG_DEBUG);
2718 }
2719 }
2720 }
2721
2722 /*
2723 * Name - handle_request()
2724 * Purpose - Once we have read a full request, we come here
2725 * to take action depending on the request type.
2726 */
2727 static void
handle_request(int desc)2728 handle_request(int desc)
2729 {
2730 RInfo *ri;
2731 WInfo *wi;
2732 unsigned char type;
2733 unsigned char size;
2734 unsigned char ptype;
2735 uint32_t port;
2736 unsigned char *buf;
2737 map_ent *m;
2738
2739 ri = getRInfo(desc, 0);
2740 if (0 == ri)
2741 {
2742 snprintf(ebuf, sizeof(ebuf), "request not found on descriptor %d", desc);
2743 gdomap_log(LOG_DEBUG);
2744 return;
2745 }
2746 type = ri->buf.r.rtype;
2747 size = ri->buf.r.nsize;
2748 ptype = ri->buf.r.ptype;
2749 port = ntohl(ri->buf.r.port);
2750 buf = (unsigned char*)ri->buf.r.name;
2751
2752 FD_CLR(desc, &read_fds);
2753 FD_SET(desc, &write_fds);
2754
2755 if (debug > 1)
2756 {
2757 if (desc == udp_desc)
2758 {
2759 snprintf(ebuf, sizeof(ebuf), "request type '%c' on UDP chan", type);
2760 gdomap_log(LOG_DEBUG);
2761 }
2762 else
2763 {
2764 snprintf(ebuf, sizeof(ebuf),
2765 "request type '%c' from chan %d", type, desc);
2766 gdomap_log(LOG_DEBUG);
2767 }
2768 if (type == GDO_PROBE || type == GDO_PREPLY || type == GDO_SERVERS
2769 || type == GDO_NAMES)
2770 {
2771 /* fprintf(stderr, "\n"); */
2772 }
2773 else
2774 {
2775 snprintf(ebuf, sizeof(ebuf),
2776 " name: '%.*s' port: %"PRIu32, size, buf, port);
2777 gdomap_log(LOG_DEBUG);
2778 }
2779 }
2780
2781 wi = getWInfo(desc, 1);
2782 wi->pos = 0;
2783
2784 if (ptype != GDO_TCP_GDO && ptype != GDO_TCP_FOREIGN
2785 && ptype != GDO_UDP_GDO && ptype != GDO_UDP_FOREIGN)
2786 {
2787 if (ptype != 0 || (type != GDO_PROBE && type != GDO_PREPLY
2788 && type != GDO_SERVERS && type != GDO_NAMES))
2789 {
2790 if (debug)
2791 {
2792 snprintf(ebuf, sizeof(ebuf), "Illegal port type in request");
2793 gdomap_log(LOG_DEBUG);
2794 }
2795 clear_chan(desc);
2796 return;
2797 }
2798 }
2799
2800 /*
2801 * The default return value is a four byte number set to zero.
2802 * We assume that malloc returns data aligned on a 4 byte boundary.
2803 */
2804 wi->len = 4;
2805 wi->buf = (char*)malloc(4);
2806 wi->buf[0] = 0;
2807 wi->buf[1] = 0;
2808 wi->buf[2] = 0;
2809 wi->buf[3] = 0;
2810
2811 if (type == GDO_REGISTER)
2812 {
2813 /*
2814 * See if this is a request from a local process.
2815 */
2816 if (is_local_host(ri->addr.sin_addr) == 0)
2817 {
2818 snprintf(ebuf, sizeof(ebuf), "Illegal attempt to register!");
2819 gdomap_log(LOG_ERR);
2820 clear_chan(desc); /* Only local progs may register. */
2821 return;
2822 }
2823
2824 /*
2825 * What should we do if we already have the name registered?
2826 * Simple algorithm -
2827 * We check to see if we can bind to the old port,
2828 * and if we can we assume that the original process
2829 * has gone away and permit a new registration for the
2830 * same name.
2831 * This is not foolproof - if the machine has more
2832 * than one IP address, we could bind to the port on
2833 * one address even though the server is using it on
2834 * another.
2835 * Also - the operating system is not guaranteed to
2836 * let us bind to the port if another process has only
2837 * recently stopped using it.
2838 * Also - what if an old server used the port that the
2839 * new one is using? In this case the registration
2840 * attempt will be refused even though it shouldn't be!
2841 * On the other hand - the occasional registration
2842 * failure MUST be better than permitting a process to
2843 * grab a name already in use! If a server fails to
2844 * register a name/port combination, it can always be
2845 * coded to retry on a different port.
2846 */
2847 m = map_by_name(buf, size);
2848 if (m != 0 && port == m->port)
2849 {
2850 /*
2851 * Special case - we already have this name registered for this
2852 * port - so everything is already ok.
2853 */
2854 if (debug)
2855 {
2856 snprintf(ebuf, sizeof(ebuf), "Already registered ... success");
2857 gdomap_log(LOG_DEBUG);
2858 }
2859 *(uint32_t*)wi->buf = htonl(port);
2860 }
2861 else if (m != 0)
2862 {
2863 int sock = -1;
2864
2865 if ((ptype & GDO_NET_MASK) == GDO_NET_TCP)
2866 {
2867 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
2868 }
2869 else if ((ptype & GDO_NET_MASK) == GDO_NET_UDP)
2870 {
2871 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
2872 }
2873
2874 if (sock < 0)
2875 {
2876 perror("unable to create new socket");
2877 }
2878 else
2879 {
2880 #ifndef BROKEN_SO_REUSEADDR
2881 int r = 1;
2882
2883 /*
2884 * Under decent systems, SO_REUSEADDR means that the port can
2885 * be reused immediately that this process exits. Under some
2886 * it means that multiple processes can serve the same port
2887 * simultaneously.
2888 * We don't want that broken behavior!
2889 */
2890 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
2891 (char*)&r, sizeof(r)) < 0)
2892 {
2893 perror("unable to set socket options");
2894 }
2895 else
2896 #endif
2897 {
2898 struct sockaddr_in sa;
2899 int result;
2900 short p = m->port;
2901
2902 memset(&sa, '\0', sizeof(sa));
2903 sa.sin_family = AF_INET;
2904 sa.sin_addr.s_addr = htonl(INADDR_ANY);
2905 sa.sin_port = htons(p);
2906 result = bind(sock, (void*)&sa, sizeof(sa));
2907 if (result == 0)
2908 {
2909 if (debug > 1)
2910 {
2911 snprintf(ebuf, sizeof(ebuf),
2912 "re-register from %d to %"PRIu32,
2913 m->port, port);
2914 gdomap_log(LOG_DEBUG);
2915 }
2916 m->port = port;
2917 m->net = (ptype & GDO_NET_MASK);
2918 m->svc = (ptype & GDO_SVC_MASK);
2919 port = htonl(m->port);
2920 *(uint32_t*)wi->buf = port;
2921 }
2922 }
2923 #if defined(__MINGW__)
2924 /* closesocket(sock); */
2925 #else
2926 close(sock);
2927 #endif
2928 }
2929 }
2930 else if (port == 0)
2931 { /* Port not provided! */
2932 if (debug)
2933 {
2934 snprintf(ebuf, sizeof(ebuf), "Port not provided in request!");
2935 gdomap_log(LOG_DEBUG);
2936 }
2937 *(uint32_t*)wi->buf = 0;
2938 }
2939 else
2940 { /* Use port provided in request. */
2941 if (debug)
2942 {
2943 snprintf(ebuf, sizeof(ebuf), "Registered on port %"PRIu32, port);
2944 gdomap_log(LOG_DEBUG);
2945 }
2946 m = map_add(buf, size, port, ptype);
2947 port = htonl(m->port);
2948 *(uint32_t*)wi->buf = port;
2949 }
2950 }
2951 else if (type == GDO_LOOKUP)
2952 {
2953 m = map_by_name(buf, size);
2954 if (m != 0 && (m->net | m->svc) != ptype)
2955 {
2956 if (debug > 1)
2957 {
2958 snprintf(ebuf, sizeof(ebuf),
2959 "requested service is of wrong type");
2960 gdomap_log(LOG_DEBUG);
2961 }
2962 m = 0; /* Name exists but is of wrong type. */
2963 }
2964 if (m)
2965 {
2966 int sock = -1;
2967
2968 /*
2969 * We check to see if we can bind to the old port, and if we can
2970 * we assume that the process has gone away and remove it from
2971 * the map.
2972 * This is not foolproof - if the machine has more
2973 * than one IP address, we could bind to the port on
2974 * one address even though the server is using it on
2975 * another.
2976 */
2977 if ((ptype & GDO_NET_MASK) == GDO_NET_TCP)
2978 {
2979 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
2980 }
2981 else if ((ptype & GDO_NET_MASK) == GDO_NET_UDP)
2982 {
2983 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
2984 }
2985
2986 if (sock < 0)
2987 {
2988 perror("unable to create new socket");
2989 }
2990 else
2991 {
2992 #ifndef BROKEN_SO_REUSEADDR
2993 int r = 1;
2994
2995 /*
2996 * Under decent systems, SO_REUSEADDR means that the port can
2997 * be reused immediately that this process exits. Under some
2998 * it means that multiple processes can serve the same port
2999 * simultaneously.
3000 * We don't want that broken behavior!
3001 */
3002 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
3003 (char*)&r, sizeof(r)) < 0)
3004 {
3005 perror("unable to set socket options");
3006 }
3007 else
3008 #endif
3009 {
3010 struct sockaddr_in sa;
3011 int result;
3012 unsigned short p = (unsigned short)m->port;
3013
3014 memset(&sa, '\0', sizeof(sa));
3015 sa.sin_family = AF_INET;
3016
3017 #if defined(__MINGW__)
3018 /* COMMENT: (3 Nov 2004 by Wim Oudshoorn):
3019 The comment below might be true. But
3020 using addr[0].s_addr has on windows 2003 server
3021 (and some other versions of windows.)
3022 exactly the same sympton as it tries to avoid.
3023 The funny thing is that the original line, just
3024 using INADDR_ANY seems to work on windows.
3025 However, I assume the FIXME below was put there
3026 for a reason. But for now I just revert it because
3027 the platform independent code seems to work.
3028 */
3029 /* FIXME: This must not be INADDR_ANY on Win,
3030 otherwise the system will try to bind on any of
3031 the local addresses (including 127.0.0.1), which
3032 works. - bjoern */
3033 /* sa.sin_addr.s_addr = addr[0].s_addr; */
3034 sa.sin_addr.s_addr = htonl(INADDR_ANY);
3035 #else
3036 sa.sin_addr.s_addr = htonl(INADDR_ANY);
3037 #endif /* __MINGW__ */
3038 sa.sin_port = htons(p);
3039 result = bind(sock, (void*)&sa, sizeof(sa));
3040 if (result == 0)
3041 {
3042 map_del(m);
3043 m = 0;
3044 }
3045 }
3046 #if defined(__MINGW__)
3047 closesocket(sock);
3048 #else
3049 close(sock);
3050 #endif
3051 }
3052 }
3053 if (m)
3054 { /* Lookup found live server. */
3055 *(uint32_t*)wi->buf = htonl(m->port);
3056 }
3057 else
3058 { /* Not found. */
3059 if (debug > 1)
3060 {
3061 snprintf(ebuf, sizeof(ebuf), "requested service not found");
3062 gdomap_log(LOG_DEBUG);
3063 }
3064 *(unsigned short*)wi->buf = 0;
3065 }
3066 }
3067 else if (type == GDO_UNREG)
3068 {
3069 /*
3070 * See if this is a request from a local process.
3071 */
3072 if (is_local_host(ri->addr.sin_addr) == 0)
3073 {
3074 snprintf(ebuf, sizeof(ebuf), "Illegal attempt to un-register!");
3075 gdomap_log(LOG_ERR);
3076 clear_chan(desc);
3077 return;
3078 }
3079 if (port == 0 || size > 0)
3080 {
3081 m = map_by_name(buf, size);
3082 if (m)
3083 {
3084 if ((m->net | m->svc) != ptype)
3085 {
3086 if (debug)
3087 {
3088 snprintf(ebuf, sizeof(ebuf),
3089 "Attempted unregister with wrong type");
3090 gdomap_log(LOG_DEBUG);
3091 }
3092 }
3093 else
3094 {
3095 *(uint32_t*)wi->buf = htonl(m->port);
3096 map_del(m);
3097 }
3098 }
3099 else
3100 {
3101 if (debug > 1)
3102 {
3103 snprintf(ebuf, sizeof(ebuf), "requested service not found");
3104 gdomap_log(LOG_DEBUG);
3105 }
3106 }
3107 }
3108 else
3109 {
3110 *(uint32_t*)wi->buf = 0;
3111
3112 while ((m = map_by_port(port, ptype)) != 0)
3113 {
3114 *(uint32_t*)wi->buf = htonl(m->port);
3115 map_del(m);
3116 }
3117 }
3118 }
3119 else if (type == GDO_SERVERS)
3120 {
3121 unsigned int i;
3122 unsigned int j;
3123
3124 /* See if this is a request from a local process.
3125 *
3126 * This request is only useful locally. Do not allow remote
3127 * requests for the server list. Our response can be large,
3128 * so it would make a great UDP amplification attack.
3129 */
3130 if (is_local_host(ri->addr.sin_addr) == 0)
3131 {
3132 snprintf(ebuf, sizeof(ebuf), "Illegal attempt to list servers!");
3133 gdomap_log(LOG_ERR);
3134 clear_chan(desc);
3135 return;
3136 }
3137
3138 free(wi->buf);
3139 wi->buf = (char*)calloc(sizeof(uint32_t)
3140 + (prb_used+1)*IASIZE, 1);
3141 *(uint32_t*)wi->buf = htonl(prb_used+1);
3142 memcpy(&wi->buf[4], &ri->addr.sin_addr, IASIZE);
3143
3144 /*
3145 * Copy the addresses of the hosts we have probed into the buffer.
3146 * During the copy, reverse the order of the addresses so that the
3147 * address we have contacted most recently is first. This should
3148 * ensure that the client process will attempt to contact live
3149 * hosts before dead ones.
3150 */
3151 for (i = 0, j = prb_used; i < prb_used; i++)
3152 {
3153 memcpy(&wi->buf[4+(i+1)*IASIZE], &prb[--j]->sin, IASIZE);
3154 }
3155 wi->len = 4 + (prb_used+1)*IASIZE;
3156 }
3157 else if (type == GDO_NAMES)
3158 {
3159 int bytes = 0;
3160 uptr ptr;
3161 int i;
3162
3163 free(wi->buf);
3164
3165 /*
3166 * Size buffer for names.
3167 */
3168 for (i = 0; i < map_used; i++)
3169 {
3170 bytes += 2 + map[i]->size;
3171 }
3172 /*
3173 * Allocate with space for number of names and set it up.
3174 */
3175 wi->buf = (char*)malloc(4 + bytes);
3176 *(uint32_t*)wi->buf = htonl(bytes);
3177 ptr = (uptr)wi->buf;
3178 ptr += 4;
3179 for (i = 0; i < map_used; i++)
3180 {
3181 ptr[0] = (unsigned char)map[i]->size;
3182 ptr[1] = (unsigned char)(map[i]->net | map[i]->svc);
3183 memcpy(&ptr[2], map[i]->name, ptr[0]);
3184 ptr += 2 + ptr[0];
3185 }
3186 wi->len = 4 + bytes;
3187 }
3188 else if (type == GDO_PROBE)
3189 {
3190 /*
3191 * If the client is a name server, we add it to the list.
3192 */
3193 if (ri->addr.sin_port == my_port)
3194 {
3195 struct in_addr sin;
3196
3197 memcpy(&sin, ri->buf.r.name, IASIZE);
3198 if (debug > 2)
3199 {
3200 snprintf(ebuf, sizeof(ebuf), "Probe from '%s'", inet_ntoa(sin));
3201 gdomap_log(LOG_DEBUG);
3202 }
3203 prb_add(&sin);
3204
3205 /*
3206 * Irrespective of what we are told to do - we also add the
3207 * interface from which this packet arrived so we have a
3208 * route we KNOW we can use.
3209 */
3210 prb_add(&ri->addr.sin_addr);
3211
3212 #if 0
3213 {
3214 struct in_addr *ptr;
3215 uint32_t net;
3216 int c;
3217
3218 #if defined(__MINGW__)
3219 if (IN_CLASSA(sin.s_addr))
3220 {
3221 net = sin.s_addr & IN_CLASSA_NET;
3222 }
3223 else if (IN_CLASSB(sin.s_addr))
3224 {
3225 net = sin.s_addr & IN_CLASSB_NET;
3226 }
3227 else if (IN_CLASSC(sin.s_addr))
3228 {
3229 net = sin.s_addr & IN_CLASSC_NET;
3230 }
3231 #else
3232 net = inet_netof(sin);
3233 #endif
3234 ptr = (struct in_addr*)&ri->buf.r.name[2*IASIZE];
3235 c = (ri->buf.r.nsize - 2*IASIZE)/IASIZE;
3236 while (c-- > 0)
3237 {
3238 if (debug > 2)
3239 {
3240 snprintf(ebuf, sizeof(ebuf),
3241 "Add server '%s'", inet_ntoa(*ptr));
3242 gdomap_log(LOG_DEBUG);
3243 }
3244 prb_add(ptr);
3245 ptr++;
3246 }
3247 }
3248 #endif
3249 }
3250 /*
3251 * For a UDP request from another name server, we send a reply
3252 * packet. We shouldn't be getting probes from anywhere else,
3253 * but just to be nice, we send back our port number anyway.
3254 */
3255 if (desc == udp_desc && ri->addr.sin_port == my_port)
3256 {
3257 struct in_addr laddr;
3258 struct in_addr raddr;
3259 struct in_addr *other = 0;
3260 unsigned int elen;
3261 void *rbuf = ri->buf.r.name;
3262 void *wbuf;
3263 int i;
3264 gdo_req *r;
3265
3266 free(wi->buf);
3267 r = (gdo_req*)calloc(GDO_REQ_SIZE, 1);
3268 wi->buf = (char*)r;
3269 wbuf = r->name;
3270 r->rtype = GDO_PREPLY;
3271 r->nsize = IASIZE*2;
3272
3273 memcpy(&raddr, rbuf, IASIZE);
3274 memcpy(&laddr, rbuf+IASIZE, IASIZE);
3275 if (debug > 2)
3276 {
3277 snprintf(ebuf, sizeof(ebuf),
3278 "Probe sent remote '%s'", inet_ntoa(raddr));
3279 snprintf(ebuf, sizeof(ebuf),
3280 "Probe sent local '%s'", inet_ntoa(laddr));
3281 }
3282
3283 memcpy(wbuf+IASIZE, &raddr, IASIZE);
3284 /*
3285 * If the other end did not tell us which of our addresses it was
3286 * probing, try to select one on the same network to send back.
3287 * otherwise, respond with the address it was probing.
3288 */
3289 if (is_local_host(laddr) == 0
3290 || laddr.s_addr == loopback.s_addr)
3291 {
3292 for (i = 0; i < interfaces; i++)
3293 {
3294 if (addr[i].s_addr == loopback.s_addr)
3295 {
3296 continue;
3297 }
3298 if ((mask[i].s_addr & addr[i].s_addr) ==
3299 (mask[i].s_addr & ri->addr.sin_addr.s_addr))
3300 {
3301 laddr = addr[i];
3302 memcpy(wbuf, &laddr, IASIZE);
3303 break;
3304 }
3305 }
3306 }
3307 else
3308 {
3309 memcpy(wbuf, &laddr, IASIZE);
3310 }
3311 wi->len = GDO_REQ_SIZE;
3312
3313 elen = other_addresses_on_net(laddr, &other);
3314 if (elen > 0)
3315 {
3316 while (elen > MAX_EXTRA)
3317 {
3318 elen -= MAX_EXTRA;
3319 queue_probe(&raddr, &laddr, MAX_EXTRA, &other[elen], 1);
3320 }
3321 queue_probe(&raddr, &laddr, elen, other, 1);
3322 }
3323 if (0 != other)
3324 {
3325 free(other);
3326 }
3327 }
3328 else
3329 {
3330 port = my_port;
3331 *(uint32_t*)wi->buf = htonl(port);
3332 }
3333 }
3334 else if (type == GDO_PREPLY)
3335 {
3336 /*
3337 * This should really be a reply by UDP to a probe we sent
3338 * out earlier. We should add the name server to our list.
3339 */
3340 if (ri->addr.sin_port == my_port)
3341 {
3342 struct in_addr sin;
3343
3344 memcpy(&sin, &ri->buf.r.name, IASIZE);
3345 if (debug > 2)
3346 {
3347 snprintf(ebuf, sizeof(ebuf),
3348 "Probe reply from '%s'", inet_ntoa(sin));
3349 gdomap_log(LOG_DEBUG);
3350 }
3351 prb_add(&sin);
3352 /*
3353 * Irrespective of what we are told to do - we also add the
3354 * interface from which this packet arrived so we have a
3355 * route we KNOW we can use.
3356 */
3357 prb_add(&ri->addr.sin_addr);
3358 }
3359 /*
3360 * Because this is really a reply to us, we don't want to reply
3361 * to it or we would get a feedback loop.
3362 */
3363 clear_chan(desc);
3364 return;
3365 }
3366 else
3367 {
3368 snprintf(ebuf, sizeof(ebuf), "Illegal operation code received!");
3369 gdomap_log(LOG_ERR);
3370 clear_chan(desc);
3371 return;
3372 }
3373
3374 /*
3375 * If the request was via UDP, we send a response back by queuing
3376 * rather than letting the normal 'write_handler()' function do it.
3377 */
3378 if (desc == udp_desc)
3379 {
3380 queue_msg(&ri->addr, (unsigned char*)wi->buf, wi->len);
3381 clear_chan(desc);
3382 }
3383 }
3384
3385 /*
3386 * Name - handle_send()
3387 * Purpose - Send any pending message on UDP socket.
3388 * The code is designed to send the message in parts if
3389 * the 'sendto()' function returns a positive integer
3390 * indicating that only part of the message has been
3391 * written. This should never happen - but I coded it
3392 * this way in case we have to run on a system which
3393 * implements sendto() badly (I used such a system
3394 * many years ago).
3395 */
3396 static void
handle_send()3397 handle_send()
3398 {
3399 struct u_data* entry = u_queue;
3400
3401 if (entry)
3402 {
3403 int r;
3404
3405 r = sendto(udp_desc, (const char *)&entry->dat[entry->pos],
3406 entry->len - entry->pos, 0, (void*)&entry->addr, sizeof(entry->addr));
3407 /*
3408 * 'r' is the number of bytes sent. This should be the number
3409 * of bytes we asked to send, or -1 to indicate failure.
3410 */
3411 if (r > 0)
3412 {
3413 entry->pos += r;
3414 }
3415
3416 /*
3417 * If we haven't written all the data, it should have been
3418 * because we blocked. Anything else is a major problem
3419 * so we remove the message from the queue.
3420 */
3421 if (entry->pos != entry->len)
3422 {
3423 #if defined(__MINGW__)
3424 if (WSAGetLastError() != WSAEWOULDBLOCK)
3425 #else
3426 if (errno != EWOULDBLOCK)
3427 #endif
3428 {
3429 if (debug)
3430 {
3431 snprintf(ebuf, sizeof(ebuf),
3432 "failed sendto on %d for %s - %s",
3433 udp_desc, inet_ntoa(entry->addr.sin_addr), strerror(errno));
3434 gdomap_log(LOG_DEBUG);
3435 }
3436 queue_pop();
3437 }
3438 }
3439 else
3440 {
3441 udp_sent++;
3442 if (debug > 1)
3443 {
3444 snprintf(ebuf, sizeof(ebuf), "performed sendto for %s",
3445 inet_ntoa(entry->addr.sin_addr));
3446 gdomap_log(LOG_DEBUG);
3447 }
3448 /*
3449 * If we have sent the entire message - remove it from queue.
3450 */
3451 if (entry->pos == entry->len)
3452 {
3453 queue_pop();
3454 }
3455 }
3456 }
3457 }
3458
3459 /*
3460 * Name - handle_write()
3461 * Purpose - Write data to a channel. When all writing for the
3462 * channel is complete, close the channel down.
3463 *
3464 * This is all probably totally paranoid - the reply
3465 * to any request is so short that the write operation
3466 * should not block so there shouldn't be any need to
3467 * handle non-blocking I/O.
3468 */
3469 static void
handle_write(int desc)3470 handle_write(int desc)
3471 {
3472 WInfo *wi;
3473 char *ptr;
3474 int len;
3475 int r;
3476
3477 wi = getWInfo(desc, 0);
3478 if (wi == 0)
3479 {
3480 snprintf(ebuf, sizeof(ebuf),
3481 "handle_write for unknown descriptor (%d)", desc);
3482 gdomap_log(LOG_ERR);
3483 return;
3484 }
3485 ptr = wi->buf;
3486 len = wi->len;
3487
3488 #if defined(__MINGW__)
3489 r = send(desc, &ptr[wi->pos], len - wi->pos, 0);
3490 #else
3491 r = write(desc, &ptr[wi->pos], len - wi->pos);
3492 #endif
3493 if (r < 0)
3494 {
3495 if (debug > 1)
3496 {
3497 snprintf(ebuf, sizeof(ebuf),
3498 "Failed write on chan %d - closing", desc);
3499 gdomap_log(LOG_DEBUG);
3500 }
3501 /*
3502 * Failure - close connection silently.
3503 */
3504 clear_chan(desc);
3505 }
3506 else
3507 {
3508 wi->pos += r;
3509 if (wi->pos >= len)
3510 {
3511 tcp_sent++;
3512 if (debug > 1)
3513 {
3514 snprintf(ebuf, sizeof(ebuf),
3515 "Completed write on chan %d - closing", desc);
3516 gdomap_log(LOG_DEBUG);
3517 }
3518 /*
3519 * Success - written all information.
3520 */
3521 clear_chan(desc);
3522 }
3523 }
3524 }
3525
3526 /*
3527 * Name - tryRead()
3528 * Purpose - Attempt to read from a non blocking channel.
3529 * Time out in specified time.
3530 * If length of data is zero then just wait for
3531 * descriptor to be readable.
3532 * If the length is negative then attempt to
3533 * read the absolute value of length but return
3534 * as soon as anything is read.
3535 *
3536 * Return -1 on failure
3537 * Return -2 on timeout
3538 * Return number of bytes read
3539 */
3540 static int
tryRead(int desc,int tim,unsigned char * dat,int len)3541 tryRead(int desc, int tim, unsigned char* dat, int len)
3542 {
3543 struct timeval timeout;
3544 fd_set fds;
3545 void *to;
3546 int rval;
3547 int pos = 0;
3548 time_t when = 0;
3549 int neg = 0;
3550
3551 if (len < 0)
3552 {
3553 neg = 1;
3554 len = -len;
3555 }
3556
3557 /*
3558 * First time round we do a select with an instant timeout to see
3559 * if the descriptor is already readable.
3560 */
3561 timeout.tv_sec = 0;
3562 timeout.tv_usec = 0;
3563
3564 for (;;)
3565 {
3566 to = &timeout;
3567 memset(&fds, '\0', sizeof(fds));
3568 FD_SET(desc, &fds);
3569
3570 rval = select(FD_SETSIZE, &fds, 0, 0, to);
3571 if (rval == 0)
3572 {
3573 time_t now = time(0);
3574
3575 if (when == 0)
3576 {
3577 when = now;
3578 }
3579 else if (now - when >= tim)
3580 {
3581 return -2; /* Timed out. */
3582 }
3583 else
3584 {
3585 /*
3586 * Set the timeout for a new call to select next time
3587 * round the loop.
3588 */
3589 timeout.tv_sec = tim - (now - when);
3590 timeout.tv_usec = 0;
3591 }
3592 }
3593 else if (rval < 0)
3594 {
3595 return -1; /* Error in select. */
3596 }
3597 else if (len > 0)
3598 {
3599 #if defined(__MINGW__)
3600 rval = recv(desc, (char *)&dat[pos], len - pos, 0);
3601 #else
3602 rval = read(desc, &dat[pos], len - pos);
3603 #endif
3604 if (rval < 0)
3605 {
3606 #if defined(__MINGW__)
3607 if (WSAGetLastError() != WSAEWOULDBLOCK)
3608 #else
3609 if (errno != EWOULDBLOCK)
3610 #endif
3611 {
3612 return -1; /* Error in read. */
3613 }
3614 }
3615 else if (rval == 0)
3616 {
3617 return -1; /* End of file. */
3618 }
3619 else
3620 {
3621 pos += rval;
3622 if (pos == len || neg == 1)
3623 {
3624 return pos; /* Read as needed. */
3625 }
3626 }
3627 }
3628 else
3629 {
3630 return 0; /* Not actually asked to read. */
3631 }
3632 }
3633 }
3634
3635 /*
3636 * Name - tryWrite()
3637 * Purpose - Attempt to write to a non blocking channel.
3638 * Time out in specified time.
3639 * If length of data is zero then just wait for
3640 * descriptor to be writable.
3641 * If the length is negative then attempt to
3642 * write the absolute value of length but return
3643 * as soon as anything is written.
3644 *
3645 * Return -1 on failure
3646 * Return -2 on timeout
3647 * Return number of bytes written
3648 */
3649 static int
tryWrite(int desc,int tim,unsigned char * dat,int len)3650 tryWrite(int desc, int tim, unsigned char* dat, int len)
3651 {
3652 struct timeval timeout;
3653 fd_set fds;
3654 void *to;
3655 int rval;
3656 int pos = 0;
3657 time_t when = 0;
3658 int neg = 0;
3659
3660 if (len < 0) {
3661 neg = 1;
3662 len = -len;
3663 }
3664
3665 /*
3666 * First time round we do a select with an instant timeout to see
3667 * if the descriptor is already writable.
3668 */
3669 timeout.tv_sec = 0;
3670 timeout.tv_usec = 0;
3671
3672 for (;;)
3673 {
3674 to = &timeout;
3675 memset(&fds, '\0', sizeof(fds));
3676 FD_SET(desc, &fds);
3677
3678 rval = select(FD_SETSIZE, 0, &fds, 0, to);
3679 if (rval == 0)
3680 {
3681 time_t now = time(0);
3682
3683 if (when == 0)
3684 {
3685 when = now;
3686 }
3687 else if (now - when >= tim)
3688 {
3689 return -2; /* Timed out. */
3690 }
3691 else
3692 {
3693 /* Set the timeout for a new call to select next time round
3694 * the loop. */
3695 timeout.tv_sec = tim - (now - when);
3696 timeout.tv_usec = 0;
3697 }
3698 }
3699 else if (rval < 0)
3700 {
3701 return -1; /* Error in select. */
3702 }
3703 else if (len > 0)
3704 {
3705 #if defined(__MINGW__) /* FIXME: Is this correct? */
3706 rval = send(desc, (const char*)&dat[pos], len - pos, 0);
3707 #else
3708 void (*ifun)();
3709
3710 /*
3711 * Should be able to write this short a message immediately, but
3712 * if the connection is lost we will get a signal we must trap.
3713 */
3714 ifun = signal(SIGPIPE, (void(*)(int))SIG_IGN);
3715 rval = write(desc, &dat[pos], len - pos);
3716 signal(SIGPIPE, ifun);
3717 #endif
3718
3719 if (rval <= 0)
3720 {
3721 #if defined(__MINGW__)
3722 if (WSAGetLastError() != WSAEWOULDBLOCK)
3723 #else
3724 if (errno != EWOULDBLOCK)
3725 #endif
3726 {
3727 return -1; /* Error in write. */
3728 }
3729 }
3730 else
3731 {
3732 pos += rval;
3733 if (pos == len || neg == 1)
3734 {
3735 return pos; /* Written as needed. */
3736 }
3737 }
3738 }
3739 else
3740 {
3741 return 0; /* Not actually asked to write. */
3742 }
3743 }
3744 }
3745
3746 /*
3747 * Name - tryHost()
3748 * Purpose - Perform a name server operation with a given
3749 * request packet to a server at specified address.
3750 * On error - return non-zero with reason in 'errno'
3751 */
3752 static int
tryHost(unsigned char op,unsigned char len,const unsigned char * name,int ptype,struct sockaddr_in * addr,unsigned short * p,uptr * v)3753 tryHost(unsigned char op, unsigned char len, const unsigned char *name,
3754 int ptype, struct sockaddr_in *addr, unsigned short *p, uptr *v)
3755 {
3756 int desc = socket(AF_INET, SOCK_STREAM, 0);
3757 int e = 0;
3758 uint32_t port = *p;
3759 gdo_req msg;
3760 struct sockaddr_in sin;
3761 #if defined(__MINGW__)
3762 uint32_t dummy;
3763 #endif /* __MINGW__ */
3764
3765 *p = 0;
3766 if (desc < 0)
3767 {
3768 return 1; /* Couldn't create socket. */
3769 }
3770
3771 #if defined(__MINGW__)
3772 dummy = 1;
3773 if (ioctlsocket(desc, FIONBIO, &dummy) < 0)
3774 {
3775 e = WSAGetLastError();
3776 closesocket(desc);
3777 WSASetLastError(e);
3778 return 2; /* Couldn't set non-blocking. */
3779 }
3780 #else /* !__MINGW__ */
3781 if ((e = fcntl(desc, F_GETFL, 0)) >= 0)
3782 {
3783 e |= NBLK_OPT;
3784 if (fcntl(desc, F_SETFL, e) < 0)
3785 {
3786 e = errno;
3787 close(desc);
3788 errno = e;
3789 return 2; /* Couldn't set non-blocking. */
3790 }
3791 }
3792 else
3793 {
3794 e = errno;
3795 close(desc);
3796 errno = e;
3797 return 2; /* Couldn't set non-blocking. */
3798 }
3799 #endif /* __MINGW__ */
3800
3801 memcpy(&sin, addr, sizeof(sin));
3802 if (connect(desc, (struct sockaddr*)&sin, sizeof(sin)) != 0)
3803 {
3804 #if defined(__MINGW__)
3805 if (WSAGetLastError() == WSAEWOULDBLOCK)
3806 #else
3807 if (errno == EINPROGRESS)
3808 #endif
3809 {
3810 e = tryWrite(desc, 10, 0, 0);
3811 if (e == -2)
3812 {
3813 e = errno;
3814 #if defined(__MINGW__)
3815 closesocket(desc);
3816 #else
3817 close(desc);
3818 #endif
3819 errno = e;
3820 return 3; /* Connect timed out. */
3821 }
3822 else if (e == -1)
3823 {
3824 e = errno;
3825 #if defined(__MINGW__)
3826 closesocket(desc);
3827 #else
3828 close(desc);
3829 #endif
3830 errno = e;
3831 return 3; /* Select failed. */
3832 }
3833 }
3834 else
3835 {
3836 e = errno;
3837 #if defined(__MINGW__)
3838 closesocket(desc);
3839 #else
3840 close(desc);
3841 #endif
3842 errno = e;
3843 return 3; /* Failed connect. */
3844 }
3845 }
3846
3847 memset((char*)&msg, '\0', GDO_REQ_SIZE);
3848 msg.rtype = op;
3849 msg.nsize = len;
3850 msg.ptype = ptype;
3851 if (op != GDO_REGISTER)
3852 {
3853 port = 0;
3854 }
3855 msg.port = htonl(port);
3856 if (name && len)
3857 {
3858 memcpy(msg.name, name, len);
3859 }
3860
3861 e = tryWrite(desc, 10, (uptr)&msg, GDO_REQ_SIZE);
3862 if (e != GDO_REQ_SIZE)
3863 {
3864 #if defined(__MINGW__)
3865 e = WSAGetLastError();
3866 closesocket(desc);
3867 WSASetLastError(e);
3868 #else
3869 e = errno;
3870 close(desc);
3871 errno = e;
3872 #endif
3873 return 4;
3874 }
3875 e = tryRead(desc, 3, (uptr)&port, 4);
3876 if (e != 4)
3877 {
3878 #if defined(__MINGW__)
3879 e = WSAGetLastError();
3880 closesocket(desc);
3881 WSASetLastError(e);
3882 #else
3883 e = errno;
3884 close(desc);
3885 errno = e;
3886 #endif
3887 return 5; /* Read timed out. */
3888 }
3889 port = ntohl(port);
3890
3891 if (port > 0xffff)
3892 {
3893 if (GDO_NAMES == op)
3894 {
3895 if (port > 10000000)
3896 {
3897 snprintf(ebuf, sizeof(ebuf),
3898 "Insanely large list of registered names");
3899 gdomap_log(LOG_ERR);
3900 close(desc);
3901 return 5; // Unreasonable number of registrations
3902 }
3903 }
3904 else
3905 {
3906 snprintf(ebuf, sizeof(ebuf),
3907 "Port number of incoming message is out of range");
3908 gdomap_log(LOG_ERR);
3909 close(desc);
3910 return 5; // Unreasonable port number
3911 }
3912 }
3913
3914 /*
3915 * Special case for GDO_SERVERS - allocate buffer and read list.
3916 */
3917 if (op == GDO_SERVERS)
3918 {
3919 int len = port * sizeof(struct in_addr);
3920 uptr b;
3921
3922 b = (uptr)malloc(len);
3923 if (tryRead(desc, 3, b, len) != len)
3924 {
3925 free(b);
3926 #if defined(__MINGW__)
3927 e = WSAGetLastError();
3928 closesocket(desc);
3929 WSASetLastError(e);
3930 #else
3931 e = errno;
3932 close(desc);
3933 errno = e;
3934 #endif
3935 return 5;
3936 }
3937 if (0 != v)
3938 {
3939 *v = b;
3940 }
3941 }
3942 /*
3943 * Special case for GDO_NAMES - allocate buffer and read list.
3944 */
3945 else if (op == GDO_NAMES)
3946 {
3947 int len = port;
3948 uptr ptr;
3949 uptr b;
3950
3951 b = (uptr)malloc(len);
3952 if (tryRead(desc, 3, b, len) != len)
3953 {
3954 free(b);
3955 #if defined(__MINGW__)
3956 e = WSAGetLastError();
3957 closesocket(desc);
3958 WSASetLastError(e);
3959 #else
3960 e = errno;
3961 close(desc);
3962 errno = e;
3963 #endif
3964 return 5;
3965 }
3966 /*
3967 * Count the number of registered names and return them.
3968 */
3969 ptr = b;
3970 port = 0;
3971 while (ptr < &b[len])
3972 {
3973 ptr += 2 + ptr[0];
3974 port++;
3975 }
3976 if ((port & 0xffff) != port)
3977 {
3978 snprintf(ebuf, sizeof(ebuf),
3979 "Insanely large number of registered names");
3980 gdomap_log(LOG_ERR);
3981 port = 0;
3982 }
3983 if (0 != v)
3984 {
3985 *v = b;
3986 }
3987 }
3988
3989 *p = (unsigned short)port;
3990 #if defined(__MINGW__)
3991 closesocket(desc);
3992 #else
3993 close(desc);
3994 #endif
3995 errno = 0;
3996 return 0;
3997 }
3998
3999 /*
4000 * Name - nameFail()
4001 * Purpose - If given a failure status from tryHost()
4002 * raise an appropriate exception.
4003 */
4004 static void
nameFail(int why)4005 nameFail(int why)
4006 {
4007 switch (why)
4008 {
4009 case 0: break;
4010
4011 case 1:
4012 snprintf(ebuf, sizeof(ebuf),
4013 "failed to contact name server - socket - %s",
4014 strerror(errno));
4015 gdomap_log(LOG_ERR);
4016 break;
4017
4018 case 2:
4019 snprintf(ebuf, sizeof(ebuf),
4020 "failed to contact name server - socket - %s",
4021 strerror(errno));
4022 gdomap_log(LOG_ERR);
4023 break;
4024
4025 case 3:
4026 snprintf(ebuf, sizeof(ebuf),
4027 "failed to contact name server - socket - %s",
4028 strerror(errno));
4029 gdomap_log(LOG_ERR);
4030 break;
4031
4032 case 4:
4033 snprintf(ebuf, sizeof(ebuf),
4034 "failed to contact name server - socket - %s",
4035 strerror(errno));
4036 gdomap_log(LOG_ERR);
4037 break;
4038 }
4039 }
4040
4041 /*
4042 * Name - nameServer()
4043 * Purpose - Perform name server lookup or registration.
4044 * Return success/failure status and set up an
4045 * address structure for use in bind or connect.
4046 * Restrictions - 0xffff byte name limit
4047 * Uses old style host lookup - only handles the
4048 * primary network interface for each host!
4049 */
4050 static int
nameServer(const char * name,const char * host,int op,int ptype,struct sockaddr_in * addr,int pnum,int max)4051 nameServer(const char* name, const char* host, int op, int ptype, struct sockaddr_in* addr, int pnum, int max)
4052 {
4053 struct sockaddr_in sin;
4054 unsigned short p;
4055 unsigned short port = 0;
4056 int len = strlen(name);
4057 int multi = 0;
4058 int found = 0;
4059 int rval;
4060 char *first_dot = 0;
4061
4062 if (len == 0)
4063 {
4064 snprintf(ebuf, sizeof(ebuf), "no name specified.");
4065 gdomap_log(LOG_ERR);
4066 return -1;
4067 }
4068 if (len > 0xffff)
4069 {
4070 snprintf(ebuf, sizeof(ebuf), "name length to large.");
4071 gdomap_log(LOG_ERR);
4072 return -1;
4073 }
4074
4075 memset((char*)&sin, '\0', sizeof(sin));
4076 sin.sin_family = AF_INET;
4077
4078 #if GDOMAP_PORT_OVERRIDE
4079 p = htons(GDOMAP_PORT_OVERRIDE);
4080 #else
4081 {
4082 struct servent *sp;
4083 /*
4084 * Ensure we have port number to connect to name server.
4085 * The TCP service name 'gdomap' overrides the default port.
4086 */
4087 if ((sp = getservbyname("gdomap", "tcp")) != 0)
4088 {
4089 p = sp->s_port; /* Network byte order. */
4090 }
4091 else
4092 {
4093 p = htons(GDOMAP_PORT);
4094 }
4095 }
4096 #endif
4097 sin.sin_port = p;
4098
4099 /*
4100 * The host name '*' matches any host on the local network.
4101 */
4102 if (host && host[0] == '*' && host[1] == '\0')
4103 {
4104 multi = 1;
4105 }
4106 /*
4107 * If no host name is given, we use the name of the local host.
4108 * NB. This should always be the case for operations other than lookup.
4109 */
4110 if (multi || host == 0 || *host == '\0')
4111 {
4112 first_dot = strchr(local_hostname, '.');
4113 if (first_dot)
4114 {
4115 *first_dot = '\0';
4116 }
4117 host = local_hostname;
4118 }
4119
4120 #if HAVE_GETADDRINFO
4121 {
4122 struct addrinfo hints;
4123 struct addrinfo *info;
4124 int err;
4125
4126 memset(&hints, '\0', sizeof(hints));
4127 hints.ai_family = AF_INET;
4128
4129 if (getaddrinfo(host, NULL, &hints, &info) != 0 && first_dot != 0)
4130 {
4131 *first_dot = '.';
4132 if ((err = getaddrinfo(host, NULL, &hints, &info)) != 0)
4133 {
4134 snprintf(ebuf, sizeof(ebuf),
4135 "getaddrinfo('%s') failed: %s", host, gai_strerror(err));
4136 gdomap_log(LOG_ERR);
4137 return -1;
4138 }
4139 }
4140 sin.sin_addr = ((struct sockaddr_in *)info->ai_addr)->sin_addr;
4141 freeaddrinfo(info);
4142 }
4143 #else
4144 {
4145 struct hostent *hp;
4146
4147 if ((hp = gethostbyname(host)) == 0 && first_dot != 0)
4148 {
4149 *first_dot = '.';
4150 hp = gethostbyname(host);
4151 }
4152 if (hp == 0)
4153 {
4154 snprintf(ebuf, sizeof(ebuf),
4155 "gethostbyname('%s') failed: %s", host, strerror(errno));
4156 gdomap_log(LOG_ERR);
4157 return -1;
4158 }
4159 if (hp->h_addrtype != AF_INET)
4160 {
4161 snprintf(ebuf, sizeof(ebuf),
4162 "non-internet network not supported for %s", host);
4163 gdomap_log(LOG_ERR);
4164 return -1;
4165 }
4166 memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
4167 }
4168 #endif
4169
4170 if (multi)
4171 {
4172 unsigned short num;
4173 struct in_addr *b;
4174
4175 /*
4176 * A host name of '*' is a special case which should do lookup on
4177 * all machines on the local network until one is found which has
4178 * the specified server on it.
4179 */
4180 rval = tryHost(GDO_SERVERS, 0, 0, ptype, &sin, &num, (uptr*)&b);
4181 if (0 == rval)
4182 {
4183 int i;
4184
4185 for (i = 0; found == 0 && i < num; i++)
4186 {
4187 memset((char*)&sin, '\0', sizeof(sin));
4188 sin.sin_family = AF_INET;
4189 sin.sin_port = p;
4190 memcpy(&sin.sin_addr, &b[i], sizeof(struct in_addr));
4191 if (sin.sin_addr.s_addr == 0)
4192 {
4193 continue;
4194 }
4195
4196 if (tryHost(GDO_LOOKUP, len, (unsigned char*)name,
4197 ptype, &sin, &port, 0)==0)
4198 {
4199 if (port != 0)
4200 {
4201 memset((char*)&addr[found], '\0', sizeof(*addr));
4202 memcpy(&addr[found].sin_addr, &sin.sin_addr,
4203 sizeof(sin.sin_addr));
4204 addr[found].sin_family = AF_INET;
4205 addr[found].sin_port = htons(port);
4206 found++;
4207 if (found == max)
4208 {
4209 break;
4210 }
4211 }
4212 }
4213 }
4214 free(b);
4215 return found;
4216 }
4217 else
4218 {
4219 snprintf(ebuf, sizeof(ebuf),
4220 "failed to contact gdomap on %s(%s) - %s",
4221 local_hostname, inet_ntoa(sin.sin_addr), strerror(errno));
4222 gdomap_log(LOG_ERR);
4223 return -1;
4224 }
4225 }
4226 else
4227 {
4228 if (op == GDO_REGISTER)
4229 {
4230 port = (unsigned short)pnum;
4231 if (port == 0 || htons(port) == p)
4232 {
4233 snprintf(ebuf, sizeof(ebuf),
4234 "attempted registration with bad port (%d).", port);
4235 gdomap_log(LOG_ERR);
4236 return -1;
4237 }
4238 }
4239 rval = tryHost(op, len, (unsigned char*)name, ptype, &sin, &port, 0);
4240 if (rval != 0)
4241 {
4242 snprintf(ebuf, sizeof(ebuf),
4243 "failed to contact gdomap on %s(%s) - %s",
4244 local_hostname, inet_ntoa(sin.sin_addr), strerror(errno));
4245 gdomap_log(LOG_ERR);
4246 return -1;
4247 }
4248 nameFail(rval);
4249 }
4250
4251 if (op == GDO_REGISTER)
4252 {
4253 if (port == 0 || (pnum != 0 && port != pnum))
4254 {
4255 snprintf(ebuf, sizeof(ebuf),
4256 "service already registered.");
4257 gdomap_log(LOG_ERR);
4258 return -1;
4259 }
4260 }
4261 if (port == 0)
4262 {
4263 return 0;
4264 }
4265 memset((char*)addr, '\0', sizeof(*addr));
4266 memcpy(&addr->sin_addr, &sin.sin_addr, sizeof(sin.sin_addr));
4267 addr->sin_family = AF_INET;
4268 addr->sin_port = htons(port);
4269 return 1;
4270 }
4271
4272 static void
lookup(const char * name,const char * host,int ptype)4273 lookup(const char *name, const char *host, int ptype)
4274 {
4275 struct sockaddr_in sin[100];
4276 int found;
4277 int i;
4278
4279 found = nameServer(name, host, GDO_LOOKUP, ptype, sin, 0, 100);
4280 for (i = 0; i < found; i++)
4281 {
4282 snprintf(ebuf, sizeof(ebuf), "Found %s on '%s' port %d", name,
4283 inet_ntoa(sin[i].sin_addr), ntohs(sin[i].sin_port));
4284 gdomap_log(LOG_INFO);
4285 }
4286 if (found == 0)
4287 {
4288 snprintf(ebuf, sizeof(ebuf), "Unable to find %s.", name);
4289 gdomap_log(LOG_INFO);
4290 }
4291 }
4292
4293 static void
donames(const char * host)4294 donames(const char *host)
4295 {
4296 struct sockaddr_in sin;
4297 unsigned short p;
4298 unsigned short num = 0;
4299 int rval;
4300 uptr b;
4301 char *first_dot = 0;
4302
4303 if (host == 0 || *host == '\0')
4304 {
4305 /*
4306 * If no host name is given, we use the name of the local host.
4307 */
4308 first_dot = strchr(local_hostname, '.');
4309 if (first_dot)
4310 {
4311 *first_dot = '\0';
4312 }
4313 host = local_hostname;
4314 }
4315
4316 memset((char*)&sin, '\0', sizeof(sin));
4317 sin.sin_family = AF_INET;
4318
4319 #if GDOMAP_PORT_OVERRIDE
4320 p = htons(GDOMAP_PORT_OVERRIDE);
4321 #else
4322 {
4323 struct servent *sp;
4324 /*
4325 * Ensure we have port number to connect to name server.
4326 * The TCP service name 'gdomap' overrides the default port.
4327 */
4328 if ((sp = getservbyname("gdomap", "tcp")) != 0)
4329 {
4330 p = sp->s_port; /* Network byte order. */
4331 }
4332 else
4333 {
4334 p = htons(GDOMAP_PORT);
4335 }
4336 }
4337 #endif
4338
4339 sin.sin_port = p;
4340
4341 #if HAVE_GETADDRINFO
4342 {
4343 struct addrinfo hints;
4344 struct addrinfo *info;
4345 int err;
4346
4347 memset(&hints, '\0', sizeof(hints));
4348 hints.ai_family = AF_INET;
4349
4350 if ((err = getaddrinfo(host, NULL, &hints, &info) != 0) && first_dot != 0)
4351 {
4352 *first_dot = '.';
4353 err = getaddrinfo(host, NULL, &hints, &info);
4354 }
4355 if (err != 0)
4356 {
4357 snprintf(ebuf, sizeof(ebuf),
4358 "getaddrinfo('%s') failed: %s", host, gai_strerror(err));
4359 gdomap_log(LOG_ERR);
4360 return;
4361 }
4362 sin.sin_addr = ((struct sockaddr_in *)info->ai_addr)->sin_addr;
4363 freeaddrinfo(info);
4364 }
4365 #else
4366 {
4367 struct hostent *hp;
4368
4369 if ((hp = gethostbyname(host)) == 0 && first_dot != 0)
4370 {
4371 *first_dot = '.';
4372 hp = gethostbyname(host);
4373 }
4374 if (hp == 0)
4375 {
4376 snprintf(ebuf, sizeof(ebuf),
4377 "gethostbyname('%s') failed: %s", host, strerror(errno));
4378 gdomap_log(LOG_ERR);
4379 return;
4380 }
4381 if (hp->h_addrtype != AF_INET)
4382 {
4383 snprintf(ebuf, sizeof(ebuf),
4384 "non-internet network not supported for %s", host);
4385 gdomap_log(LOG_ERR);
4386 return;
4387 }
4388
4389 memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
4390 }
4391 #endif
4392
4393 rval = tryHost(GDO_NAMES, 0, 0, 0, &sin, &num, (uptr*)&b);
4394 if (rval != 0)
4395 {
4396 snprintf(ebuf, sizeof(ebuf), "failed to contact gdomap on %s(%s) - %s",
4397 local_hostname, inet_ntoa(sin.sin_addr), strerror(errno));
4398 gdomap_log(LOG_ERR);
4399 return;
4400 }
4401 if (num == 0)
4402 {
4403 snprintf(ebuf, sizeof(ebuf), "No names currently registered with gdomap");
4404 gdomap_log(LOG_INFO);
4405 }
4406 else
4407 {
4408 uptr p = b;
4409
4410 snprintf(ebuf, sizeof(ebuf), "Registered names are -");
4411 gdomap_log(LOG_INFO);
4412 while (num-- > 0)
4413 {
4414 char buf[256];
4415
4416 memcpy(buf, &p[2], p[0]);
4417 buf[p[0]] = '\0';
4418 snprintf(ebuf, sizeof(ebuf), " %s", buf);
4419 gdomap_log(LOG_INFO);
4420 p += 2 + p[0];
4421 }
4422 }
4423 free(b);
4424 }
4425
4426 static void
doservers(const char * host)4427 doservers(const char *host)
4428 {
4429 struct sockaddr_in sin;
4430 unsigned short p;
4431 unsigned short num = 0;
4432 int rval;
4433 uptr b;
4434 char *first_dot = 0;
4435
4436 if (host == 0 || *host == '\0')
4437 {
4438 /*
4439 * If no host name is given, we use the name of the local host.
4440 */
4441 first_dot = strchr(local_hostname, '.');
4442 if (first_dot)
4443 {
4444 *first_dot = '\0';
4445 }
4446 host = local_hostname;
4447 }
4448
4449 memset((char*)&sin, '\0', sizeof(sin));
4450 sin.sin_family = AF_INET;
4451
4452 #if GDOMAP_PORT_OVERRIDE
4453 p = htons(GDOMAP_PORT_OVERRIDE);
4454 #else
4455 {
4456 struct servent *sp;
4457 /*
4458 * Ensure we have port number to connect to name server.
4459 * The TCP service name 'gdomap' overrides the default port.
4460 */
4461 if ((sp = getservbyname("gdomap", "tcp")) != 0)
4462 {
4463 p = sp->s_port; /* Network byte order. */
4464 }
4465 else
4466 {
4467 p = htons(GDOMAP_PORT);
4468 }
4469 }
4470 #endif
4471
4472 sin.sin_port = p;
4473
4474 #if HAVE_GETADDRINFO
4475 {
4476 struct addrinfo hints;
4477 struct addrinfo *info;
4478 int err;
4479
4480 memset(&hints, '\0', sizeof(hints));
4481 hints.ai_family = AF_INET;
4482
4483 if ((err = getaddrinfo(host, NULL, &hints, &info) != 0) && first_dot != 0)
4484 {
4485 *first_dot = '.';
4486 err = getaddrinfo(host, NULL, &hints, &info);
4487 }
4488 if (err != 0)
4489 {
4490 snprintf(ebuf, sizeof(ebuf),
4491 "getaddrinfo('%s') failed: %s", host, gai_strerror(err));
4492 gdomap_log(LOG_ERR);
4493 return;
4494 }
4495 sin.sin_addr = ((struct sockaddr_in *)info->ai_addr)->sin_addr;
4496 freeaddrinfo(info);
4497 }
4498 #else
4499 {
4500 struct hostent *hp;
4501
4502 if ((hp = gethostbyname(host)) == 0 && first_dot != 0)
4503 {
4504 *first_dot = '.';
4505 hp = gethostbyname(host);
4506 }
4507 if (hp == 0)
4508 {
4509 snprintf(ebuf, sizeof(ebuf),
4510 "gethostbyname('%s') failed: %s", host, strerror(errno));
4511 gdomap_log(LOG_ERR);
4512 return;
4513 }
4514 if (hp->h_addrtype != AF_INET)
4515 {
4516 snprintf(ebuf, sizeof(ebuf),
4517 "non-internet network not supported for %s", host);
4518 gdomap_log(LOG_ERR);
4519 return;
4520 }
4521
4522 memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
4523 }
4524 #endif
4525
4526 rval = tryHost(GDO_SERVERS, 0, 0, 0, &sin, &num, (uptr*)&b);
4527 if (rval != 0)
4528 {
4529 snprintf(ebuf, sizeof(ebuf), "failed to contact gdomap on %s(%s) - %s",
4530 local_hostname, inet_ntoa(sin.sin_addr), strerror(errno));
4531 gdomap_log(LOG_ERR);
4532 return;
4533 }
4534 if (num == 0)
4535 {
4536 snprintf(ebuf, sizeof(ebuf), "No servers currently known to gdomap");
4537 gdomap_log(LOG_INFO);
4538 }
4539 else
4540 {
4541 struct in_addr *p = (struct in_addr*)(b + 4);
4542
4543 snprintf(ebuf, sizeof(ebuf), "Known servers are -");
4544 gdomap_log(LOG_INFO);
4545 while (num-- > 0)
4546 {
4547 snprintf(ebuf, sizeof(ebuf), " %s", inet_ntoa(*p));
4548 gdomap_log(LOG_INFO);
4549 p++;
4550 }
4551 }
4552 free(b);
4553 }
4554
4555 static void
doregister(const char * name,int port,int ptype)4556 doregister(const char *name, int port, int ptype)
4557 {
4558 struct sockaddr_in sin;
4559 int found;
4560 int i;
4561
4562 found = nameServer(name, 0, GDO_REGISTER, ptype, &sin, port, 1);
4563 for (i = 0; i < found; i++)
4564 {
4565 snprintf(ebuf, sizeof(ebuf), "Registered %s on '%s' port %d", name,
4566 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
4567 gdomap_log(LOG_INFO);
4568 }
4569 if (found == 0)
4570 {
4571 snprintf(ebuf, sizeof(ebuf),
4572 "Unable to register %s on port %d.", name, port);
4573 gdomap_log(LOG_ERR);
4574 }
4575 }
4576
4577 static void
unregister(const char * name,int port,int ptype)4578 unregister(const char *name, int port, int ptype)
4579 {
4580 struct sockaddr_in sin;
4581 int found;
4582 int i;
4583
4584 found = nameServer(name, 0, GDO_UNREG, ptype, &sin, port, 1);
4585 for (i = 0; i < found; i++)
4586 {
4587 snprintf(ebuf, sizeof(ebuf), "Unregistered %s on '%s' port %d", name,
4588 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
4589 gdomap_log(LOG_INFO);
4590 }
4591 if (found == 0)
4592 {
4593 snprintf(ebuf, sizeof(ebuf), "Unable to unregister %s.", name);
4594 gdomap_log(LOG_INFO);
4595 }
4596 }
4597
do_help(int argc,char ** argv,char * options)4598 static void do_help(int argc, char **argv, char *options)
4599 {
4600 /*
4601 * Where argc > 0 we check to see if there is a '--help' argument
4602 * and do nothing if there isn't.
4603 */
4604 if (argc > 0)
4605 {
4606 int i;
4607
4608 for (i = 1; i < argc; i++)
4609 {
4610 if (strcmp(argv[i], "--help") == 0)
4611 {
4612 break;
4613 }
4614 }
4615 if (i == argc)
4616 {
4617 return; // --help not found ...
4618 }
4619 }
4620 printf("%s -[%s]\n", argv[0], options);
4621 printf("GNU Distributed Objects name server\n");
4622 printf("-C help about interfaces and configuration\n");
4623 printf("-H general help\n");
4624 printf("-I pid file to write pid\n");
4625 printf("-L name perform lookup for name then quit.\n");
4626 printf("-M name machine name for -L and -N\n");
4627 printf("-N list all names registered on host\n");
4628 printf("-P number port number required for R option.\n");
4629 printf("-R name register name locally then quit.\n");
4630 printf("-S list all gdomap servers known to host\n");
4631 printf("-T type port type for L, R and U options -\n");
4632 printf(" tcp_gdo, udp_gdo,\n");
4633 printf(" tcp_foreign, udp_foreign.\n");
4634 printf("-U name unregister name locally then quit.\n");
4635 printf("-a file use config file for interface list.\n");
4636 printf("-c file use config file for probe.\n");
4637 printf("-d extra debug logging (normally via syslog).\n");
4638 printf("-f avoid fork() to make debugging easy\n");
4639 printf("-i seconds re-probe at this interval (roughly), min 60\n");
4640 #if !defined(__MINGW__)
4641 printf("-j path specify a jail directory the process is to\n");
4642 printf(" run in (if omitted, /tmp is used).\n");
4643 #endif
4644 printf("-p disable probing for other servers\n");
4645 printf("\n");
4646 printf("Kill with SIGUSR1 to obtain a dump of all known peers\n");
4647 printf("in /tmp/gdomap.dump\n");
4648 printf("\n");
4649 exit(EXIT_SUCCESS);
4650 }
4651
4652 #if defined(__MINGW__)
4653 static char*
quoteArg(const char * arg)4654 quoteArg(const char *arg)
4655 {
4656 int len = strlen(arg);
4657 int in;
4658 int out = 0;
4659 int quote = 0;
4660 char *ptr = malloc(len*2+3);
4661
4662 /*
4663 * Check for white space ... if present, must quote argument.
4664 */
4665 for (in = 0; in < len; in++)
4666 {
4667 if (isspace(arg[in]))
4668 {
4669 quote = 1;
4670 break;
4671 }
4672 }
4673
4674 if (quote)
4675 {
4676 ptr[out++] = '"';
4677 }
4678
4679 for (in = 0; in < len; in++)
4680 {
4681 if (arg[in] == '\\')
4682 {
4683 int pos = in + 1;
4684
4685 // Step past any backslashes
4686 while (pos < len && ptr[pos] == '\\')
4687 {
4688 pos++;
4689 }
4690 // If backslashes precede a quote ... double them.
4691 if (pos < len && ptr[pos] == '"')
4692 {
4693 int num = pos - in;
4694
4695 while (num-- > 0)
4696 {
4697 ptr[out++] = '\\';
4698 }
4699 }
4700 // Copy the original backslashes
4701 while (in < pos)
4702 {
4703 ptr[out++] = arg[in++];
4704 }
4705 // Copy the character after the backslashes
4706 if (in < len)
4707 {
4708 ptr[out++] = arg[in];
4709 }
4710 }
4711 else if (arg[in] == '"')
4712 {
4713 ptr[out++] = '\\'; // Escape the quote.
4714 ptr[out++] = arg[in];
4715 }
4716 else
4717 {
4718 ptr[out++] = arg[in];
4719 }
4720 }
4721
4722
4723 if (quote)
4724 {
4725 ptr[out++] = '"';
4726 }
4727
4728 ptr[out] = '\0';
4729
4730 return ptr;
4731 }
4732 #endif
4733
4734 /**
4735 * (A dummy comment to help autogsdoc realize this is a command-line tool.)
4736 */
4737 #if GS_FAKE_MAIN
4738 /* Since we don't link gnustep-base, the main function below has to be
4739 * the real main function. */
4740 #undef main
4741 #endif
4742 int
main(int argc,char ** argv)4743 main(int argc, char** argv)
4744 {
4745 extern char *optarg;
4746 #if defined(__MINGW__)
4747 char *options = "-CHI:L:M:NP:R:ST:U:a:bc:dfi:p";
4748 #else
4749 char *options = "-CHI:L:M:NP:R:ST:U:a:bc:dfi:j:p";
4750 const char *jail = 0;
4751 #endif
4752 int c;
4753 int ptype = GDO_TCP_GDO;
4754 int port = 0;
4755 const char *machine = 0;
4756 const char *lookupf = 0;
4757 int donamesf = 0;
4758 int doserversf = 0;
4759
4760 #if defined(__MINGW__)
4761 WORD wVersionRequested;
4762 WSADATA wsaData;
4763
4764 wVersionRequested = MAKEWORD(2, 2);
4765 WSAStartup(wVersionRequested, &wsaData);
4766 #else
4767 int forked = 0;
4768 #endif
4769
4770 local_hostname = xgethostname();
4771 if (!local_hostname)
4772 {
4773 snprintf(ebuf, sizeof(ebuf),
4774 "gethostname() failed: %s", strerror(errno));
4775 gdomap_log(LOG_CRIT);
4776 exit(EXIT_FAILURE);
4777 }
4778
4779 /*
4780 * Would use inet_aton(), but older systems don't have it.
4781 */
4782 loopback.s_addr = inet_addr("127.0.0.1");
4783 #if defined(__MINGW__)
4784 class_a_net = IN_CLASSA_NET;
4785 class_a_mask.s_addr = class_a_net;
4786 class_b_net = IN_CLASSB_NET;
4787 class_b_mask.s_addr = class_b_net;
4788 class_c_net = IN_CLASSC_NET;
4789 class_c_mask.s_addr = class_c_net;
4790 #else
4791 class_a_net = inet_network("255.0.0.0");
4792 class_a_mask = inet_makeaddr(class_a_net, 0);
4793 class_b_net = inet_network("255.255.0.0");
4794 class_b_mask = inet_makeaddr(class_b_net, 0);
4795 class_c_net = inet_network("255.255.255.0");
4796 class_c_mask = inet_makeaddr(class_c_net, 0);
4797 #endif
4798
4799 do_help(argc, argv, options);
4800 while ((c = getopt(argc, argv, options)) != -1)
4801 {
4802 switch(c)
4803 {
4804 case 'H':
4805 do_help(0, argv, options);
4806 exit(EXIT_SUCCESS);
4807
4808 case 'C':
4809 printf("\n");
4810 printf(
4811 "Gdomap normally probes every machine on the local network to see if there\n"
4812 "is a copy of gdomap running on it. This is done for class-C networks and\n"
4813 "subnets of class-C networks. If your host is on a class-B or class-A net\n"
4814 "then the default behaviour is to treat it as a class-C net and probe only\n"
4815 "the hosts that would be expected on a class-C network of the same number.\n");
4816 printf("\n");
4817 printf(
4818 "If you are running on a class-A or class-B network, or if your net has a\n"
4819 "large number of hosts which will not have gdomap on them - you may want to\n"
4820 "supply a configuration file listing the hosts to be probed explicitly,\n"
4821 "rather than getting gdomap to probe all hosts on the local net.\n");
4822 printf("\n");
4823 printf(
4824 "You may also want to supply the configuration file so that hosts which are\n"
4825 "not actually on your local network can still be found when your code tries\n"
4826 "to connect to a host using @\"*\" as the host name. NB. this functionality\n"
4827 "does not exist in OpenStep.\n");
4828 printf("\n");
4829 printf(
4830 "A configuration file consists of a list of IP addresses to be probed.\n"
4831 "The IP addresses should be in standard 'dot' notation, one per line.\n"
4832 "Empty lines are permitted in the configuration file.\n"
4833 "Anything on a line after a hash ('#') is ignored.\n"
4834 "You tell gdomap about the config file with the '-c' command line option.\n");
4835 printf("\n");
4836 printf("\n");
4837 printf(
4838 "gdomap uses the SIOCGIFCONF ioctl to build a list of IP addresses and\n"
4839 "netmasks for the network interface cards on your machine. On some operating\n"
4840 "systems, this facility is not available (or is broken), so you must tell\n"
4841 "gdomap the addresses and masks of the interfaces using the '-a' command line\n"
4842 "option. The file named with '-a' should contain a series of lines with\n"
4843 "space separated pairs of addresses and masks in 'dot' notation, eg.\n"
4844 "192.168.1.2 255.255.255.0\n"
4845 "You must NOT include loopback interfaces in this list.\n"
4846 "If you want to support broadcasting of probe information on a network,\n"
4847 "you may supply the broadcast address as a third item on the line, eg.\n"
4848 "192.168.1.9 255.255.255.0 192.168.1.255\n"
4849 "If your operating system has some other method of giving you a list of\n"
4850 "network interfaces and masks, please send me example code so that I can\n"
4851 "implement it in gdomap.\n");
4852 printf("\n");
4853 exit(EXIT_SUCCESS);
4854
4855 case 'L':
4856 lookupf = optarg;
4857 break;
4858
4859 case 'M':
4860 machine = optarg;
4861 break;
4862
4863 case 'N':
4864 donamesf = 1;
4865 break;
4866
4867 case 'P':
4868 port = atoi(optarg);
4869 break;
4870
4871 case 'R':
4872 if (machine && *machine)
4873 {
4874 fprintf(stderr, "-M flag is ignored for registration.\n");
4875 fprintf(stderr, "Registration will take place locally.\n");
4876 }
4877 doregister(optarg, port, ptype);
4878 exit(EXIT_SUCCESS);
4879
4880 case 'S':
4881 doserversf = 1;
4882 break;
4883
4884 case 'T':
4885 if (strcmp(optarg, "tcp_gdo") == 0)
4886 {
4887 ptype = GDO_TCP_GDO;
4888 }
4889 else if (strcmp(optarg, "udp_gdo") == 0)
4890 {
4891 ptype = GDO_UDP_GDO;
4892 }
4893 else if (strcmp(optarg, "tcp_foreign") == 0)
4894 {
4895 ptype = GDO_TCP_FOREIGN;
4896 }
4897 else if (strcmp(optarg, "udp_foreign") == 0)
4898 {
4899 ptype = GDO_UDP_FOREIGN;
4900 }
4901 else
4902 {
4903 fprintf(stderr, "Warning - -P selected unknown type -");
4904 fprintf(stderr, " using tcp_gdo.\n");
4905 ptype = GDO_TCP_GDO;
4906 }
4907 break;
4908
4909 case 'U':
4910 if (machine && *machine)
4911 {
4912 fprintf(stderr, "-M flag is ignored for unregistration.\n");
4913 fprintf(stderr, "Operation will take place locally.\n");
4914 }
4915 unregister(optarg, port, ptype);
4916 exit(EXIT_SUCCESS);
4917
4918 case 'a':
4919 load_iface(optarg);
4920 break;
4921
4922 case 'b':
4923 nobcst++;
4924 break;
4925
4926 case 'c':
4927 {
4928 FILE *fptr;
4929 int line = 0;
4930 int count = 0;
4931 char buf[128];
4932
4933 in_config = 1;
4934 /* First see if we *can* access the file.
4935 */
4936 fptr = fopen(optarg, "rt");
4937 if (fptr == 0)
4938 {
4939 snprintf(ebuf, sizeof(ebuf),
4940 "Unable to open probe config - '%s'\n",
4941 optarg);
4942 gdomap_log(LOG_CRIT);
4943 exit(EXIT_FAILURE);
4944 }
4945 /* Now check that we *should* be accessing it.
4946 */
4947 if (access(optarg, R_OK) != 0)
4948 {
4949 fclose(fptr);
4950 snprintf(ebuf, sizeof(ebuf),
4951 "Unable to access probe config - '%s'\n",
4952 optarg);
4953 gdomap_log(LOG_CRIT);
4954 exit(EXIT_FAILURE);
4955 }
4956 while (fgets(buf, sizeof(buf), fptr) != 0)
4957 {
4958 char *ptr = buf;
4959 plentry *prb;
4960
4961 line++;
4962 /*
4963 * Strip leading white space.
4964 */
4965 while (isspace(*ptr))
4966 {
4967 ptr++;
4968 }
4969 if (ptr != buf)
4970 {
4971 strcpy(buf, ptr);
4972 }
4973 /*
4974 * Strip comments.
4975 */
4976 ptr = strchr(buf, '#');
4977 if (ptr)
4978 {
4979 *ptr = '\0';
4980 }
4981 /*
4982 * Strip trailing white space.
4983 */
4984 ptr = buf;
4985 while (*ptr)
4986 {
4987 ptr++;
4988 }
4989 while (ptr > buf && isspace(ptr[-1]))
4990 {
4991 ptr--;
4992 }
4993 *ptr = '\0';
4994 /*
4995 * Ignore blank lines.
4996 */
4997 if (*buf == '\0')
4998 {
4999 continue;
5000 }
5001
5002 if (count++ > 1000)
5003 {
5004 snprintf(ebuf, sizeof(ebuf),
5005 "Too many probe configurations found");
5006 gdomap_log(LOG_CRIT);
5007 exit(EXIT_FAILURE);
5008 }
5009 prb = (plentry*)malloc(sizeof(plentry));
5010 memset((char*)prb, '\0', sizeof(plentry));
5011 prb->addr.s_addr = inet_addr(buf);
5012 if (prb->addr.s_addr == (uint32_t)-1)
5013 {
5014 snprintf(ebuf, sizeof(ebuf),
5015 "line %d of '%s' (%s) is not a valid address\n",
5016 line, optarg, buf);
5017 free(prb);
5018 gdomap_log(LOG_CRIT);
5019 exit(EXIT_FAILURE);
5020 }
5021 else
5022 {
5023 /*
5024 * Add this address at the end of the list.
5025 */
5026 if (plist == 0)
5027 {
5028 plist = prb;
5029 }
5030 else
5031 {
5032 plentry *tmp = plist;
5033
5034 while (tmp->next)
5035 {
5036 if (tmp->addr.s_addr == prb->addr.s_addr)
5037 {
5038 snprintf(ebuf, sizeof(ebuf),
5039 "'%s' repeat in '%s'\n",
5040 buf, optarg);
5041 free(prb);
5042 gdomap_log(LOG_CRIT);
5043 exit(EXIT_FAILURE);
5044 break;
5045 }
5046 tmp = tmp->next;
5047 }
5048 if (tmp->next == 0)
5049 {
5050 tmp->next = prb;
5051 }
5052 }
5053 }
5054 }
5055 fclose(fptr);
5056 in_config = 0;
5057 }
5058 break;
5059
5060 case 'I':
5061 pidfile = optarg;
5062 break;
5063
5064 case 'd':
5065 debug++;
5066 break;
5067
5068 case 'f':
5069 nofork++;
5070 break;
5071
5072 case 'i':
5073 interval = atoi(optarg);
5074 if (interval < 60)
5075 {
5076 interval = 60;
5077 }
5078 break;
5079
5080 #if !defined(__MINGW__)
5081 case 'j':
5082 jail = optarg;
5083 break;
5084 #endif
5085
5086 case 'p':
5087 noprobe++;
5088 break;
5089
5090 default:
5091 printf("%s - GNU Distributed Objects name server\n", argv[0]);
5092 printf("-H for help\n");
5093 exit(EXIT_SUCCESS);
5094 }
5095 }
5096 if (donamesf || doserversf || lookupf)
5097 {
5098 if (donamesf)
5099 {
5100 donames(machine);
5101 }
5102 if (doserversf)
5103 {
5104 doservers(machine);
5105 }
5106 if (lookupf)
5107 {
5108 lookup(lookupf, machine, ptype);
5109 }
5110 exit (0);
5111 }
5112
5113 #if defined(__MINGW__) /* On Win32, we don't fork */
5114 if (nofork == 0)
5115 {
5116 char **a = malloc((argc+2) * sizeof(char*));
5117 int i;
5118
5119 for (i = 0; i < argc; i++)
5120 {
5121 a[i] = quoteArg(argv[i]);
5122 }
5123 a[argc] = "-f";
5124 a[argc+1] = 0;
5125 if (_spawnv(_P_NOWAIT, argv[0], (const char* const*)a) == -1)
5126 {
5127 fprintf(stderr, "gdomap - spawn '%s' failed - bye.\n", argv[0]);
5128 exit(EXIT_FAILURE);
5129 }
5130 if (debug)
5131 {
5132 snprintf(ebuf, sizeof(ebuf), "initialisation complete.");
5133 gdomap_log(LOG_DEBUG);
5134 }
5135 exit(EXIT_SUCCESS);
5136 }
5137 #else
5138 if (nofork == 0)
5139 {
5140 /*
5141 * Now fork off child process to run in background.
5142 */
5143 switch (fork())
5144 {
5145 case -1:
5146 fprintf(stderr, "gdomap - fork failed - bye.\n");
5147 exit(EXIT_FAILURE);
5148
5149 case 0:
5150 /*
5151 * Try to run in background.
5152 */
5153 forked = 1;
5154 #if defined(NeXT)
5155 setpgrp(0, getpid());
5156 #else
5157 setsid();
5158 #endif
5159 break;
5160
5161 default:
5162 if (debug)
5163 {
5164 snprintf(ebuf, sizeof(ebuf), "initialisation complete.");
5165 gdomap_log(LOG_DEBUG);
5166 }
5167 exit(EXIT_SUCCESS);
5168 }
5169 }
5170
5171 /*
5172 * Ensure we don't have any open file descriptors which may refer
5173 * to sockets bound to ports we may try to use.
5174 *
5175 * Use '/dev/null' for stdin and stdout. Assume stderr is ok.
5176 */
5177 for (c = 0; c < FD_SETSIZE; c++)
5178 {
5179 if (is_daemon || (c != 2))
5180 {
5181 (void)close(c);
5182 }
5183 }
5184 if (open("/dev/null", O_RDONLY) != 0)
5185 {
5186 snprintf(ebuf, sizeof(ebuf),
5187 "failed to open stdin from /dev/null (%s)\n", strerror(errno));
5188 gdomap_log(LOG_CRIT);
5189 exit(EXIT_FAILURE);
5190 }
5191 if (open("/dev/null", O_WRONLY) != 1)
5192 {
5193 snprintf(ebuf, sizeof(ebuf),
5194 "failed to open stdout from /dev/null (%s)\n", strerror(errno));
5195 gdomap_log(LOG_CRIT);
5196 exit(EXIT_FAILURE);
5197 }
5198 if (is_daemon && open("/dev/null", O_WRONLY) != 2)
5199 {
5200 snprintf(ebuf, sizeof(ebuf),
5201 "failed to open stderr from /dev/null (%s)\n", strerror(errno));
5202 gdomap_log(LOG_CRIT);
5203 exit(EXIT_FAILURE);
5204 }
5205 if (debug)
5206 {
5207 snprintf(ebuf, sizeof(ebuf), "Closed descriptors");
5208 gdomap_log(LOG_DEBUG);
5209 }
5210
5211 if (forked)
5212 {
5213 is_daemon = 1;
5214 #if defined(HAVE_SYSLOG)
5215 #if defined(SYSLOG_4_2)
5216 openlog ("gdomap", LOG_NDELAY);
5217 log_priority = LOG_DAEMON;
5218 #elif !defined(HAVE_SLOGF)
5219 openlog ("gdomap", LOG_NDELAY, LOG_DAEMON);
5220 #endif
5221 #endif
5222 }
5223
5224 #endif /* !__MINGW__ */
5225
5226 init_my_port(); /* Determine port to listen on. */
5227 init_ports(); /* Create ports to handle requests. */
5228
5229 if (interfaces == 0)
5230 {
5231 init_iface(); /* Build up list of network interfaces. */
5232 }
5233
5234 if (!is_local_host(loopback))
5235 {
5236 snprintf(ebuf, sizeof(ebuf),
5237 "I can't find the loopback interface on this machine.");
5238 gdomap_log(LOG_ERR);
5239 snprintf(ebuf, sizeof(ebuf),
5240 "Perhaps you should correct your machine configuration or use the -a flag.\n"
5241 "Try 'gdomap -C' for more information.\n");
5242 gdomap_log(LOG_INFO);
5243 if (interfaces < MAX_IFACE)
5244 {
5245 addr[interfaces].s_addr = loopback.s_addr;
5246 mask[interfaces] = class_c_mask;
5247 interfaces++;
5248 snprintf(ebuf, sizeof(ebuf),
5249 "I am assuming loopback interface on 127.0.0.1");
5250 gdomap_log(LOG_INFO);
5251 }
5252 else
5253 {
5254 snprintf(ebuf, sizeof(ebuf),
5255 "You have too many network interfaces to add the loopback interface on "
5256 "127.0.0.1 - you need to change the 'MAX_IFACE' constant in gdomap.c and "
5257 "rebuild it.");
5258 gdomap_log(LOG_CRIT);
5259 exit(EXIT_FAILURE);
5260 }
5261 }
5262
5263 /* Write the pidfile, but only if the user is root. This allows us
5264 to write to restricted directories without allowing normal users
5265 to mess it up. Because we are writing as root, we must be careful
5266 to create/open the file in exclusive mode */
5267 if (pidfile)
5268 {
5269 FILE *fptr;
5270
5271 #ifndef __MINGW__
5272 if (getuid () == 0)
5273 #endif
5274 {
5275 int desc = open(pidfile, O_EXCL|O_CREAT|O_WRONLY, 0644);
5276 fptr = fdopen(desc, "w");
5277
5278 if (fptr == 0)
5279 {
5280 snprintf(ebuf, sizeof(ebuf),
5281 "Unable to create new pid file - '%s'", pidfile);
5282 gdomap_log(LOG_CRIT);
5283 exit(EXIT_FAILURE);
5284 }
5285 fprintf(fptr, "%d\n", (int) getpid());
5286 fclose(fptr);
5287 chmod(pidfile, 0644);
5288 }
5289 #ifndef __MINGW__
5290 else
5291 {
5292 snprintf(ebuf, sizeof(ebuf),
5293 "Only root user can write to pid file\n");
5294 gdomap_log(LOG_WARNING);
5295 }
5296 #endif
5297 }
5298 {
5299 #ifndef __MINGW__
5300 uid_t uid = -2;
5301 gid_t gid = -2;
5302 #endif
5303
5304 #if defined(HAVE_PWD_H)
5305 #if defined(HAVE_GETPWNAM)
5306 struct passwd *pw = getpwnam("nobody");
5307
5308 if (pw != 0)
5309 {
5310 uid = pw->pw_uid;
5311 gid = pw->pw_gid;
5312 }
5313 #endif
5314 #endif
5315
5316 #if !defined(__svr4__)
5317 /*
5318 * As another level of paranoia - jail this process to a directory
5319 */
5320 #ifndef __MINGW__
5321 if (0 == jail)
5322 {
5323 jail = "/tmp"; /* Not great, but better than nothing */
5324 }
5325 if (chdir(jail) < 0)
5326 {
5327 snprintf(ebuf, sizeof(ebuf), "Unable to change directory to %s", jail);
5328 gdomap_log(LOG_CRIT);
5329 exit(EXIT_FAILURE);
5330 }
5331
5332 if (geteuid() == 0)
5333 {
5334 if (chroot(jail) < 0)
5335 {
5336 snprintf(ebuf, sizeof(ebuf), "Unable to change root to %s", jail);
5337 gdomap_log(LOG_CRIT);
5338 exit(EXIT_FAILURE);
5339 }
5340 chdir("/");
5341 }
5342 #endif /* __MINGW__ */
5343 #endif /* __svr4__ */
5344
5345 #ifndef __MINGW__
5346 /*
5347 * Try to become a 'safe' user now that we have
5348 * done everything that needs root priv.
5349 *
5350 * Try to be the user who launched us ... so they can kill us too.
5351 * Otherwise default to user nobody.
5352 */
5353 if (getuid () != 0)
5354 {
5355 uid = getuid();
5356 gid = getgid();
5357 }
5358 /* The call to setgroups may fail if we don't have that capability ...
5359 * but in that case we aren't too bothered anyway.
5360 */
5361 setgroups (1, &gid);
5362 if (setgid (gid) < 0)
5363 {
5364 snprintf(ebuf, sizeof(ebuf),
5365 "Failed setgid(%d) - %s", gid, strerror(errno));
5366 gdomap_log(LOG_CRIT);
5367 exit(EXIT_FAILURE);
5368 }
5369 if (setuid (uid) < 0)
5370 {
5371 snprintf(ebuf, sizeof(ebuf),
5372 "Failed setuid(%d) - %s", uid, strerror(errno));
5373 gdomap_log(LOG_CRIT);
5374 exit(EXIT_FAILURE);
5375 }
5376 if (getuid () == 0)
5377 {
5378 snprintf(ebuf, sizeof(ebuf),
5379 "Still running as root after trying to change");
5380 gdomap_log(LOG_CRIT);
5381 exit(EXIT_FAILURE);
5382 }
5383 #endif /* __MINGW__ */
5384 }
5385
5386 init_probe(); /* Probe other name servers on net. */
5387
5388 if (debug)
5389 {
5390 snprintf(ebuf, sizeof(ebuf), "entering main loop.\n");
5391 gdomap_log(LOG_DEBUG);
5392 }
5393 handle_io();
5394 return 0;
5395 }
5396
5397 /*
5398 * Name - queue_probe()
5399 * Purpose - Send a probe request to a specified host so we
5400 * can see if a name server is running on it.
5401 * We don't bother to check to see if it worked.
5402 */
5403 static void
queue_probe(struct in_addr * to,struct in_addr * from,int l,struct in_addr * e,int f)5404 queue_probe(struct in_addr* to, struct in_addr* from, int l, struct in_addr* e, int f)
5405 {
5406 struct sockaddr_in sin;
5407 gdo_req msg;
5408
5409 if (debug > 2)
5410 {
5411 snprintf(ebuf, sizeof(ebuf),
5412 "Probing for server on '%s' from '", inet_ntoa(*to));
5413 strncat(ebuf, inet_ntoa(*from), sizeof(ebuf) - strlen(ebuf) - 1);
5414 strncat(ebuf, "'", sizeof(ebuf) - strlen(ebuf) - 1);
5415 gdomap_log(LOG_DEBUG);
5416 if (l > 0)
5417 {
5418 int i;
5419
5420 snprintf(ebuf, sizeof(ebuf),
5421 " %d additional local addresses sent -", l);
5422 gdomap_log(LOG_DEBUG);
5423 for (i = 0; i < l; i++)
5424 {
5425 snprintf(ebuf, sizeof(ebuf), " '%s'", inet_ntoa(e[i]));
5426 gdomap_log(LOG_DEBUG);
5427 }
5428 }
5429 }
5430 memset(&sin, '\0', sizeof(sin));
5431 sin.sin_family = AF_INET;
5432 memcpy(&sin.sin_addr, to, sizeof(*to));
5433 sin.sin_port = my_port;
5434
5435 memset((char*)&msg, '\0', GDO_REQ_SIZE);
5436 if (f)
5437 {
5438 msg.rtype = GDO_PREPLY;
5439 }
5440 else
5441 {
5442 msg.rtype = GDO_PROBE;
5443 }
5444 msg.nsize = 2*IASIZE;
5445 msg.ptype = 0;
5446 msg.dummy = 0;
5447 msg.port = 0;
5448 memcpy(msg.name, from, IASIZE);
5449 memcpy(&msg.name[IASIZE], to, IASIZE);
5450 if (l > 0)
5451 {
5452 memcpy(&msg.name[msg.nsize], e, l*IASIZE);
5453 msg.nsize += l*IASIZE;
5454 }
5455
5456 queue_msg(&sin, (uptr)&msg, GDO_REQ_SIZE);
5457 }
5458
5459 /* Copyright (c) 2001 Neal H Walfield <neal@cs.uml.edu>.
5460
5461 This file is placed into the public domain. Its distribution
5462 is unlimited.
5463
5464 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
5465 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5466 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5467 IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
5468 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5469 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
5470 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
5471 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
5472 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
5473 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
5474 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5475 */
5476
5477 /* NAME
5478
5479 xgethostname - get the host name.
5480
5481 SYNOPSIS
5482
5483 char *xgethostname (void);
5484
5485 DESCRIPTION
5486
5487 The xhostname function is intended to replace gethostname(2), a
5488 function used to access the host name. The old interface is
5489 inflexable given that it assumes the existance of the
5490 MAXHOSTNAMELEN macro, which neither POSIX nor the proposed
5491 Single Unix Specification version 3 guarantee to be defined.
5492
5493 RETURN VALUE
5494
5495 On success, a malloced, null terminated (possibly truncated)
5496 string containing the host name is returned. On failure,
5497 NULL is returned and errno is set.
5498 */
5499
5500 char *
xgethostname(void)5501 xgethostname (void)
5502 {
5503 int size = 0;
5504 int addnull = 0;
5505 char *buf;
5506 int err;
5507
5508 #if defined(MAXHOSTNAMELEN)
5509 size = MAXHOSTNAMELEN;
5510 addnull = 1;
5511 #else /* MAXHOSTNAMELEN */
5512 #if defined(_SC_HOST_NAME_MAX)
5513 size = sysconf (_SC_HOST_NAME_MAX);
5514 addnull = 1;
5515 #endif /* _SC_HOST_NAME_MAX */
5516 #if defined(INTERNET_MAX_HOST_NAME_LENGTH)
5517 size = INTERNET_MAX_HOST_NAME_LENGTH;
5518 addnull = 1;
5519 #endif
5520 if (size <= 0)
5521 size = 256;
5522 #endif /* MAXHOSTNAMELEN */
5523
5524 buf = malloc (size + addnull);
5525 if (! buf)
5526 {
5527 errno = ENOMEM;
5528 return NULL;
5529 }
5530
5531 err = gethostname (buf, size);
5532 while (err == -1 && errno == ENAMETOOLONG)
5533 {
5534 free (buf);
5535
5536 size *= 2;
5537 buf = malloc (size + addnull);
5538 if (! buf)
5539 {
5540 errno = ENOMEM;
5541 return NULL;
5542 }
5543
5544 err = gethostname (buf, size);
5545 }
5546
5547 if (err)
5548 {
5549 if (buf)
5550 free (buf);
5551 errno = err;
5552 return NULL;
5553 }
5554
5555 if (addnull)
5556 buf[size] = '\0';
5557
5558 return buf;
5559 }
5560