1 /*
2 * This file is part of DGD, https://github.com/dworkin/dgd
3 * Copyright (C) 1993-2010 Dworkin B.V.
4 * Copyright (C) 2010-2014 DGD Authors (see the commit log for details)
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 # include <sys/time.h>
21 # include <sys/socket.h>
22 # include <netinet/in.h>
23 # include <arpa/inet.h>
24 # include <netdb.h>
25 # include <signal.h>
26 # include <errno.h>
27 # define INCLUDE_FILE_IO
28 # include "dgd.h"
29 # include "hash.h"
30 # include "comm.h"
31
32 #ifdef NETWORK_EXTENSIONS
33 #undef INET6
34 #undef AF_INET6
35 #endif
36
37 # ifdef INET6 /* INET6 defined */
38 # if INET6 == 0
39 # undef INET6 /* ... but turned off */
40 # endif
41 # else
42 # ifdef AF_INET6 /* define INET6 if AF_INET6 exists */
43 # define INET6
44 # endif
45 # endif
46
47 # ifndef MAXHOSTNAMELEN
48 # define MAXHOSTNAMELEN 1025
49 # endif
50
51 # ifndef INADDR_NONE
52 # define INADDR_NONE 0xffffffffL
53 # endif
54
55 # define NFREE 32
56
57 typedef struct {
58 union {
59 # ifdef INET6
60 struct in6_addr addr6; /* IPv6 addr */
61 # endif
62 struct in_addr addr; /* IPv4 addr */
63 int fd; /* file descriptor */
64 } in;
65 char ipv6; /* IPv6? */
66 } in46addr;
67
68 typedef struct _ipaddr_ {
69 struct _ipaddr_ *link; /* next in hash table */
70 struct _ipaddr_ *prev; /* previous in linked list */
71 struct _ipaddr_ *next; /* next in linked list */
72 Uint ref; /* reference count */
73 in46addr ipnum; /* ip number */
74 char name[MAXHOSTNAMELEN]; /* ip name */
75 } ipaddr;
76
77 static int in = -1, out = -1; /* pipe to/from name resolver */
78 static int addrtype; /* network address family */
79 static ipaddr **ipahtab; /* ip address hash table */
80 static unsigned int ipahtabsz; /* hash table size */
81 static ipaddr *qhead, *qtail; /* request queue */
82 static ipaddr *ffirst, *flast; /* free list */
83 static int nfree; /* # in free list */
84 static ipaddr *lastreq; /* last request */
85 static bool busy; /* name resolver busy */
86
87
88 /*
89 * NAME: ipaddr->run()
90 * DESCRIPTION: host name lookup sub-program
91 */
ipa_run(int in,int out)92 static void ipa_run(int in, int out)
93 {
94 char buf[sizeof(in46addr)];
95 struct hostent *host;
96 int len;
97
98 signal(SIGINT, SIG_IGN);
99 signal(SIGTRAP, SIG_IGN);
100 signal(SIGPIPE, SIG_IGN);
101 signal(SIGTSTP, SIG_IGN);
102
103 while (read(in, buf, sizeof(in46addr)) > 0) {
104 if (((in46addr *) &buf)->ipv6 > 1) {
105 /* close fd copied after hotboot */
106 close(((in46addr *) &buf)->in.fd);
107 continue;
108 }
109 /* lookup host */
110 # ifdef INET6
111 if (((in46addr *) &buf)->ipv6) {
112 host = gethostbyaddr(buf, sizeof(struct in6_addr), AF_INET6);
113 if (host == (struct hostent *) NULL) {
114 sleep(2);
115 host = gethostbyaddr(buf, sizeof(struct in6_addr), AF_INET6);
116 }
117 } else
118 # endif
119 {
120 host = gethostbyaddr(buf, sizeof(struct in_addr), AF_INET);
121 if (host == (struct hostent *) NULL) {
122 sleep(2);
123 host = gethostbyaddr(buf, sizeof(struct in_addr), AF_INET);
124 }
125 }
126
127 if (host != (struct hostent *) NULL) {
128 char *name;
129
130 /* write host name */
131 name = (char *) host->h_name;
132 len = strlen(name);
133 if (len >= MAXHOSTNAMELEN) {
134 len = MAXHOSTNAMELEN - 1;
135 }
136 (void) write(out, name, len);
137 name[0] = '\0';
138 } else {
139 (void) write(out, "", 1); /* failure */
140 }
141 }
142
143 exit(0); /* pipe closed */
144 }
145
146 /*
147 * NAME: ipaddr->init()
148 * DESCRIPTION: initialize name lookup
149 */
ipa_init(int maxusers)150 static bool ipa_init(int maxusers)
151 {
152 if (in < 0) {
153 int fd[4], pid;
154
155 if (pipe(fd) < 0) {
156 perror("pipe");
157 return FALSE;
158 }
159 if (pipe(fd + 2) < 0) {
160 perror("pipe");
161 close(fd[0]);
162 close(fd[1]);
163 return FALSE;
164 }
165 pid = fork();
166 if (pid < 0) {
167 perror("fork");
168 close(fd[0]);
169 close(fd[1]);
170 close(fd[2]);
171 close(fd[3]);
172 return FALSE;
173 }
174 if (pid == 0) {
175 /* child process */
176 close(fd[1]);
177 close(fd[2]);
178 ipa_run(fd[0], fd[3]);
179 }
180 close(fd[0]);
181 close(fd[3]);
182 in = fd[2];
183 out = fd[1];
184 } else if (busy) {
185 char buf[MAXHOSTNAMELEN];
186
187 /* discard ip name */
188 (void) read(in, buf, MAXHOSTNAMELEN);
189 }
190
191 ipahtab = ALLOC(ipaddr*, ipahtabsz = maxusers);
192 memset(ipahtab, '\0', ipahtabsz * sizeof(ipaddr*));
193 qhead = qtail = ffirst = flast = lastreq = (ipaddr *) NULL;
194 nfree = 0;
195 busy = FALSE;
196
197 return TRUE;
198 }
199
200 /*
201 * NAME: ipaddr->finish()
202 * DESCRIPTION: stop name lookup
203 */
ipa_finish()204 static void ipa_finish()
205 {
206 close(out);
207 close(in);
208 }
209
210 /*
211 * NAME: ipaddr->close()
212 * DESCRIPTION: close a fd duplicated after a hotboot
213 */
ipa_close(int fd)214 static void ipa_close(int fd)
215 {
216 in46addr ipnum;
217
218 ipnum.ipv6 = 2;
219 ipnum.in.fd = fd;
220 (void) write(out, &ipnum, sizeof(in46addr));
221 }
222
223 /*
224 * NAME: ipaddr->new()
225 * DESCRIPTION: return a new ipaddr
226 */
ipa_new(in46addr * ipnum)227 static ipaddr *ipa_new(in46addr *ipnum)
228 {
229 ipaddr *ipa, **hash;
230
231 /* check hash table */
232 # ifdef INET6
233 if (ipnum->ipv6) {
234 hash = &ipahtab[hashmem((char *) ipnum,
235 sizeof(struct in6_addr)) % ipahtabsz];
236 } else
237 # endif
238 {
239 hash = &ipahtab[(Uint) ipnum->in.addr.s_addr % ipahtabsz];
240 }
241 while (*hash != (ipaddr *) NULL) {
242 ipa = *hash;
243 # ifdef INET6
244 if (ipnum->ipv6 == ipa->ipnum.ipv6 &&
245 ((ipnum->ipv6) ?
246 memcmp(&ipnum->in.addr6, &ipa->ipnum.in.addr6,
247 sizeof(struct in6_addr)) == 0 :
248 ipnum->in.addr.s_addr == ipa->ipnum.in.addr.s_addr)) {
249 # else
250 if (ipnum->in.addr.s_addr == ipa->ipnum.in.addr.s_addr) {
251 # endif
252 /*
253 * found it
254 */
255 if (ipa->ref == 0) {
256 /* remove from free list */
257 if (ipa->prev == (ipaddr *) NULL) {
258 ffirst = ipa->next;
259 } else {
260 ipa->prev->next = ipa->next;
261 }
262 if (ipa->next == (ipaddr *) NULL) {
263 flast = ipa->prev;
264 } else {
265 ipa->next->prev = ipa->prev;
266 }
267 ipa->prev = ipa->next = (ipaddr *) NULL;
268 --nfree;
269 }
270 ipa->ref++;
271
272 if (ipa->name[0] == '\0' && ipa != lastreq &&
273 ipa->prev == (ipaddr *) NULL && ipa != qhead) {
274 if (!busy) {
275 /* send query to name resolver */
276 (void) write(out, (char *) ipnum, sizeof(in46addr));
277 lastreq = ipa;
278 busy = TRUE;
279 } else {
280 /* put in request queue */
281 ipa->prev = qtail;
282 if (qtail == (ipaddr *) NULL) {
283 qhead = ipa;
284 } else {
285 qtail->next = ipa;
286 }
287 qtail = ipa;
288 }
289 }
290 return ipa;
291 }
292 hash = &ipa->link;
293 }
294
295 if (nfree >= NFREE) {
296 ipaddr **h;
297
298 /*
299 * use first ipaddr in free list
300 */
301 ipa = ffirst;
302 ffirst = ipa->next;
303 ffirst->prev = (ipaddr *) NULL;
304 --nfree;
305
306 if (ipa == lastreq) {
307 lastreq = (ipaddr *) NULL;
308 }
309
310 if (hash != &ipa->link) {
311 /* remove from hash table */
312 # ifdef INET6
313 if (ipa->ipnum.ipv6) {
314 h = &ipahtab[hashmem((char *) &ipa->ipnum,
315 sizeof(struct in6_addr)) % ipahtabsz];
316 } else
317 # endif
318 {
319 h = &ipahtab[(Uint) ipa->ipnum.in.addr.s_addr % ipahtabsz];
320 }
321 while (*h != ipa) {
322 h = &(*h)->link;
323 }
324 *h = ipa->link;
325
326 /* put in hash table */
327 ipa->link = *hash;
328 *hash = ipa;
329 }
330 } else {
331 /*
332 * allocate new ipaddr
333 */
334 m_static();
335 ipa = ALLOC(ipaddr, 1);
336 m_dynamic();
337
338 /* put in hash table */
339 ipa->link = *hash;
340 *hash = ipa;
341 }
342
343 ipa->ref = 1;
344 ipa->ipnum = *ipnum;
345 ipa->name[0] = '\0';
346 ipa->prev = ipa->next = (ipaddr *) NULL;
347
348 if (!busy) {
349 /* send query to name resolver */
350 (void) write(out, (char *) ipnum, sizeof(in46addr));
351 lastreq = ipa;
352 busy = TRUE;
353 } else {
354 /* put in request queue */
355 ipa->prev = qtail;
356 if (qtail == (ipaddr *) NULL) {
357 qhead = ipa;
358 } else {
359 qtail->next = ipa;
360 }
361 qtail = ipa;
362 }
363
364 return ipa;
365 }
366
367 /*
368 * NAME: ipaddr->del()
369 * DESCRIPTION: delete an ipaddr
370 */
371 static void ipa_del(ipaddr *ipa)
372 {
373 if (--ipa->ref == 0) {
374 if (ipa->prev != (ipaddr *) NULL || qhead == ipa) {
375 /* remove from queue */
376 if (ipa->prev != (ipaddr *) NULL) {
377 ipa->prev->next = ipa->next;
378 } else {
379 qhead = ipa->next;
380 }
381 if (ipa->next != (ipaddr *) NULL) {
382 ipa->next->prev = ipa->prev;
383 } else {
384 qtail = ipa->prev;
385 }
386 }
387
388 /* add to free list */
389 if (flast != (ipaddr *) NULL) {
390 flast->next = ipa;
391 ipa->prev = flast;
392 flast = ipa;
393 } else {
394 ffirst = flast = ipa;
395 ipa->prev = (ipaddr *) NULL;
396 }
397 ipa->next = (ipaddr *) NULL;
398 nfree++;
399 }
400 }
401
402 /*
403 * NAME: ipaddr->lookup()
404 * DESCRIPTION: lookup another ip name
405 */
406 static void ipa_lookup()
407 {
408 ipaddr *ipa;
409
410 if (lastreq != (ipaddr *) NULL) {
411 /* read ip name */
412 lastreq->name[read(in, lastreq->name, MAXHOSTNAMELEN)] = '\0';
413 } else {
414 char buf[MAXHOSTNAMELEN];
415
416 /* discard ip name */
417 (void) read(in, buf, MAXHOSTNAMELEN);
418 }
419
420 /* if request queue not empty, write new query */
421 if (qhead != (ipaddr *) NULL) {
422 ipa = qhead;
423 (void) write(out, (char *) &ipa->ipnum, sizeof(in46addr));
424 qhead = ipa->next;
425 if (qhead == (ipaddr *) NULL) {
426 qtail = (ipaddr *) NULL;
427 } else {
428 qhead->prev = (ipaddr *) NULL;
429 }
430 ipa->prev = ipa->next = (ipaddr *) NULL;
431 lastreq = ipa;
432 busy = TRUE;
433 } else {
434 lastreq = (ipaddr *) NULL;
435 busy = FALSE;
436 }
437 }
438
439 struct _connection_ {
440 hte chain; /* UDP challenge hash chain */
441 int fd; /* file descriptor */
442 int npkts; /* # packets in buffer */
443 int bufsz; /* # bytes in buffer */
444 char *udpbuf; /* datagram buffer */
445 ipaddr *addr; /* internet address of connection */
446 unsigned short port; /* UDP port of connection */
447 short at; /* port connection was accepted at */
448 struct _connection_ *next; /* next in list */
449 };
450
451 typedef struct {
452 int in6; /* IPv6 port descriptor */
453 int in4; /* IPv4 port descriptor */
454 } portdesc;
455
456 static int nusers; /* # of users */
457 static connection *connections; /* connections array */
458 static connection *flist; /* list of free connections */
459 static connection **udphtab; /* UDP hash table */
460 static int udphtabsz; /* UDP hash table size */
461 static hashtab *chtab; /* challenge hash table */
462 static portdesc *tdescs, *bdescs; /* telnet & binary descriptor arrays */
463 static int ntdescs, nbdescs; /* # telnet & binary ports */
464 static portdesc *udescs; /* UDP port descriptor array */
465 static fd_set infds; /* file descriptor input bitmap */
466 static fd_set outfds; /* file descriptor output bitmap */
467 static fd_set waitfds; /* file descriptor wait-write bitmap */
468 static fd_set readfds; /* file descriptor read bitmap */
469 static fd_set writefds; /* file descriptor write map */
470 static int maxfd; /* largest fd opened yet */
471 static int npackets; /* # packets buffered */
472 static int closed; /* #fds closed in write */
473
474 # ifdef INET6
475 /*
476 * NAME: conn->port6()
477 * DESCRIPTION: open an IPv6 port
478 */
479 static int conn_port6(int *fd, int type, struct sockaddr_in6 *sin6, unsigned int port)
480 {
481 int on;
482
483 if ((*fd=socket(AF_INET6, type, 0)) < 0) {
484 perror("socket IPv6");
485 return FALSE;
486 }
487 if (*fd > maxfd) {
488 maxfd = *fd;
489 }
490 on = 1;
491 if (setsockopt(*fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
492 perror("setsockopt");
493 return FALSE;
494 }
495 # if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
496 on = 1;
497 if (setsockopt(*fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
498 perror("setsockopt");
499 return FALSE;
500 }
501 # endif
502 # ifdef SO_OOBINLINE
503 if (type == SOCK_STREAM) {
504 on = 1;
505 if (setsockopt(*fd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)) < 0) {
506 perror("setsockopt");
507 return FALSE;
508 }
509 }
510 # endif
511 sin6->sin6_port = htons(port);
512 if (bind(*fd, (struct sockaddr *) sin6, sizeof(struct sockaddr_in6)) < 0) {
513 perror("bind");
514 return FALSE;
515 }
516
517 FD_SET(*fd, &infds);
518 return TRUE;
519 }
520 # endif
521
522 /*
523 * NAME: conn->port()
524 * DESCRIPTION: open an IPv4 port
525 */
526 static int conn_port(int *fd, int type, struct sockaddr_in *sin, unsigned int port)
527 {
528 int on;
529
530 if ((*fd=socket(AF_INET, type, 0)) < 0) {
531 perror("socket");
532 return FALSE;
533 }
534 if (*fd > maxfd) {
535 maxfd = *fd;
536 }
537 on = 1;
538 if (setsockopt(*fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
539 perror("setsockopt");
540 return FALSE;
541 }
542 # ifdef SO_OOBINLINE
543 if (type == SOCK_STREAM) {
544 on = 1;
545 if (setsockopt(*fd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)) < 0) {
546 perror("setsockopt");
547 return FALSE;
548 }
549 }
550 # endif
551 sin->sin_port = htons(port);
552 if (bind(*fd, (struct sockaddr *) sin, sizeof(struct sockaddr_in)) < 0) {
553 perror("bind");
554 return FALSE;
555 }
556
557 FD_SET(*fd, &infds);
558 return TRUE;
559 }
560
561 /*
562 * NAME: conn->init()
563 * DESCRIPTION: initialize connection handling
564 */
565 bool conn_init(int maxusers, char **thosts, char **bhosts,
566 unsigned short *tports, unsigned short *bports, int ntports,
567 int nbports)
568 {
569 # ifdef INET6
570 struct sockaddr_in6 sin6;
571 # endif
572 struct sockaddr_in sin;
573 struct hostent *host;
574 int n;
575 connection *conn;
576 bool ipv6, ipv4;
577 # ifdef AI_DEFAULT
578 int err;
579 # endif
580
581 if (!ipa_init(maxusers)) {
582 return FALSE;
583 }
584
585 addrtype = PF_INET;
586
587 nusers = 0;
588
589 maxfd = 0;
590 FD_ZERO(&infds);
591 FD_ZERO(&outfds);
592 FD_ZERO(&waitfds);
593 FD_SET(in, &infds);
594 npackets = 0;
595 closed = 0;
596
597 #ifndef NETWORK_EXTENSIONS
598 ntdescs = ntports;
599 if (ntports != 0) {
600 tdescs = ALLOC(portdesc, ntports);
601 memset(tdescs, -1, ntports * sizeof(portdesc));
602 }
603 nbdescs = nbports;
604 if (nbports != 0) {
605 bdescs = ALLOC(portdesc, nbports);
606 memset(bdescs, -1, nbports * sizeof(portdesc));
607 udescs = ALLOC(portdesc, nbports);
608 memset(udescs, -1, nbports * sizeof(portdesc));
609 }
610 #endif
611
612 # ifdef INET6
613 memset(&sin6, '\0', sizeof(sin6));
614 sin6.sin6_family = AF_INET6;
615 # endif
616 memset(&sin, '\0', sizeof(sin));
617 sin.sin_family = AF_INET;
618
619 for (n = 0; n < ntdescs; n++) {
620 /* telnet ports */
621 ipv6 = FALSE;
622 ipv4 = FALSE;
623 if (thosts[n] == (char *) NULL) {
624 # ifdef INET6
625 sin6.sin6_addr = in6addr_any;
626 ipv6 = TRUE;
627 # endif
628 sin.sin_addr.s_addr = INADDR_ANY;
629 ipv4 = TRUE;
630 } else {
631 # ifdef INET6
632 if (inet_pton(AF_INET6, thosts[n], &sin6) > 0) {
633 sin6.sin6_family = AF_INET6;
634 ipv6 = TRUE;
635 } else {
636 # ifdef AI_DEFAULT
637 host = getipnodebyname(thosts[n], AF_INET6, 0, &err);
638 if (host != (struct hostent *) NULL) {
639 if (host->h_length != 4) {
640 memcpy(&sin6.sin6_addr, host->h_addr, host->h_length);
641 ipv6 = TRUE;
642 }
643 freehostent(host);
644 }
645 # else
646 host = gethostbyname2(thosts[n], AF_INET6);
647 if (host != (struct hostent *) NULL && host->h_length != 4) {
648 memcpy(&sin6.sin6_addr, host->h_addr, host->h_length);
649 ipv6 = TRUE;
650 }
651 # endif
652 }
653 # endif
654 if ((sin.sin_addr.s_addr=inet_addr(thosts[n])) != INADDR_NONE) {
655 ipv4 = TRUE;
656 } else {
657 host = gethostbyname(thosts[n]);
658 if (host != (struct hostent *) NULL) {
659 memcpy(&sin.sin_addr, host->h_addr, host->h_length);
660 ipv4 = TRUE;
661 }
662 }
663 }
664
665 if (!ipv6 && !ipv4) {
666 message("unknown host %s\012", thosts[n]); /* LF */
667 return FALSE;
668 }
669
670 # ifdef INET6
671 if (ipv6 && !conn_port6(&tdescs[n].in6, SOCK_STREAM, &sin6, tports[n]))
672 {
673 return FALSE;
674 }
675 # endif
676 if (ipv4 && !conn_port(&tdescs[n].in4, SOCK_STREAM, &sin, tports[n])) {
677 return FALSE;
678 }
679 }
680
681 for (n = 0; n < nbdescs; n++) {
682 /* binary ports */
683 ipv6 = FALSE;
684 ipv4 = FALSE;
685 if (bhosts[n] == (char *) NULL) {
686 # ifdef INET6
687 sin6.sin6_addr = in6addr_any;
688 ipv6 = TRUE;
689 # endif
690 sin.sin_addr.s_addr = INADDR_ANY;
691 ipv4 = TRUE;
692 } else {
693 # ifdef INET6
694 if (inet_pton(AF_INET6, bhosts[n], &sin6) > 0) {
695 sin6.sin6_family = AF_INET6;
696 ipv6 = TRUE;
697 } else {
698 # ifdef AI_DEFAULT
699 host = getipnodebyname(bhosts[n], AF_INET6, 0, &err);
700 if (host != (struct hostent *) NULL) {
701 if (host->h_length != 4) {
702 memcpy(&sin6.sin6_addr, host->h_addr, host->h_length);
703 ipv6 = TRUE;
704 }
705 freehostent(host);
706 }
707 # else
708 host = gethostbyname2(bhosts[n], AF_INET6);
709 if (host != (struct hostent *) NULL && host->h_length != 4) {
710 memcpy(&sin6.sin6_addr, host->h_addr, host->h_length);
711 ipv6 = TRUE;
712 }
713 # endif
714 }
715 # endif
716 if ((sin.sin_addr.s_addr=inet_addr(bhosts[n])) != INADDR_NONE) {
717 ipv4 = TRUE;
718 } else {
719 host = gethostbyname(bhosts[n]);
720 if (host != (struct hostent *) NULL) {
721 memcpy(&sin.sin_addr, host->h_addr, host->h_length);
722 ipv4 = TRUE;
723 }
724 }
725 }
726
727 if (!ipv6 && !ipv4) {
728 message("unknown host %s\012", bhosts[n]); /* LF */
729 return FALSE;
730 }
731
732 # ifdef INET6
733 if (ipv6) {
734 if (!conn_port6(&bdescs[n].in6, SOCK_STREAM, &sin6, bports[n])) {
735 return FALSE;
736 }
737 if (!conn_port6(&udescs[n].in6, SOCK_DGRAM, &sin6, bports[n])) {
738 return FALSE;
739 }
740 }
741 # endif
742 if (ipv4) {
743 if (!conn_port(&bdescs[n].in4, SOCK_STREAM, &sin, bports[n])) {
744 return FALSE;
745 }
746 if (!conn_port(&udescs[n].in4, SOCK_DGRAM, &sin, bports[n])) {
747 return FALSE;
748 }
749 }
750 }
751
752 flist = (connection *) NULL;
753 #ifndef NETWORK_EXTENSIONS
754 connections = ALLOC(connection, nusers = maxusers);
755 #else
756 connections = ALLOC(connection, nusers = maxusers+1);
757 #endif
758 for (n = nusers, conn = connections; n > 0; --n, conn++) {
759 conn->fd = -1;
760 conn->chain.next = (hte *) flist;
761 flist = conn;
762 }
763
764 #ifndef NETWORK_EXTENSIONS
765 udphtab = ALLOC(connection*, udphtabsz = maxusers);
766 memset(udphtab, '\0', udphtabsz * sizeof(connection*));
767 chtab = ht_new(maxusers, UDPHASHSZ, TRUE);
768 #endif
769
770 return TRUE;
771 }
772
773 /*
774 * NAME: conn->clear()
775 * DESCRIPTION: clean up connections
776 */
777 void conn_clear()
778 {
779 int n;
780
781 for (n = 0; n < ntdescs; n++) {
782 if (tdescs[n].in6 >= 0) {
783 close(tdescs[n].in6);
784 }
785 if (tdescs[n].in4 >= 0) {
786 close(tdescs[n].in4);
787 }
788 }
789 for (n = 0; n < nbdescs; n++) {
790 if (bdescs[n].in6 >= 0) {
791 close(bdescs[n].in6);
792 }
793 if (bdescs[n].in4 >= 0) {
794 close(bdescs[n].in4);
795 }
796 if (udescs[n].in6 >= 0) {
797 close(udescs[n].in6);
798 }
799 if (udescs[n].in4 >= 0) {
800 close(udescs[n].in4);
801 }
802 }
803
804 ipa_finish();
805 }
806
807 /*
808 * NAME: conn->finish()
809 * DESCRIPTION: terminate connections
810 */
811 void conn_finish()
812 {
813 int n;
814 connection *conn;
815
816 for (n = nusers, conn = connections; n > 0; --n, conn++) {
817 if (conn->fd >= 0) {
818 close(conn->fd);
819 }
820 }
821 }
822
823 #ifndef NETWORK_EXTENSIONS
824 /*
825 * NAME: conn->listen()
826 * DESCRIPTION: start listening on telnet port and binary port
827 */
828 void conn_listen()
829 {
830 int n;
831
832 for (n = 0; n < ntdescs; n++) {
833 if (tdescs[n].in6 >= 0) {
834 if (listen(tdescs[n].in6, 64) < 0) {
835 perror("listen");
836 } else if (fcntl(tdescs[n].in6, F_SETFL, FNDELAY) < 0) {
837 perror("fcntl");
838 } else {
839 continue;
840 }
841 fatal("conn_listen failed");
842 }
843 }
844 for (n = 0; n < ntdescs; n++) {
845 if (tdescs[n].in4 >= 0) {
846 if (listen(tdescs[n].in4, 64) < 0) {
847 # ifdef INET6
848 close(tdescs[n].in4);
849 FD_CLR(tdescs[n].in4, &infds);
850 tdescs[n].in4 = -1;
851 continue;
852 # else
853 perror("listen");
854 # endif
855 } else if (fcntl(tdescs[n].in4, F_SETFL, FNDELAY) < 0) {
856 perror("fcntl");
857 } else {
858 continue;
859 }
860 fatal("conn_listen failed");
861 }
862 }
863 for (n = 0; n < nbdescs; n++) {
864 if (bdescs[n].in6 >= 0) {
865 if (listen(bdescs[n].in6, 64) < 0) {
866 perror("listen");
867 } else if (fcntl(bdescs[n].in6, F_SETFL, FNDELAY) < 0) {
868 perror("fcntl");
869 } else if (fcntl(udescs[n].in6, F_SETFL, FNDELAY) < 0) {
870 perror("fcntl");
871 } else {
872 continue;
873 }
874 fatal("conn_listen failed");
875 }
876 }
877 for (n = 0; n < nbdescs; n++) {
878 if (bdescs[n].in4 >= 0) {
879 if (listen(bdescs[n].in4, 64) < 0) {
880 # ifdef INET6
881 close(bdescs[n].in4);
882 FD_CLR(bdescs[n].in4, &infds);
883 bdescs[n].in4 = -1;
884 continue;
885 # else
886 perror("listen");
887 # endif
888 } else if (fcntl(bdescs[n].in4, F_SETFL, FNDELAY) < 0) {
889 perror("fcntl");
890 } else if (fcntl(udescs[n].in4, F_SETFL, FNDELAY) < 0) {
891 perror("fcntl");
892 } else {
893 continue;
894 }
895 fatal("conn_listen failed");
896 }
897 }
898 }
899
900 # ifdef INET6
901 /*
902 * NAME: conn->accept6()
903 * DESCRIPTION: accept a new ipv6 connection
904 */
905 static connection *conn_accept6(int portfd, int port)
906 {
907 int fd;
908 unsigned int len;
909 struct sockaddr_in6 sin6;
910 in46addr addr;
911 connection *conn;
912
913 if (!FD_ISSET(portfd, &readfds)) {
914 return (connection *) NULL;
915 }
916 len = sizeof(sin6);
917 fd = accept(portfd, (struct sockaddr *) &sin6, &len);
918 if (fd < 0) {
919 FD_CLR(portfd, &readfds);
920 return (connection *) NULL;
921 }
922 fcntl(fd, F_SETFL, FNDELAY);
923
924 conn = flist;
925 flist = (connection *) conn->chain.next;
926 conn->chain.name = (char *) NULL;
927 conn->fd = fd;
928 conn->udpbuf = (char *) NULL;
929 if (IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)) {
930 /* convert to IPv4 address */
931 addr.in.addr = *(struct in_addr *) &sin6.sin6_addr.s6_addr[12];
932 addr.ipv6 = FALSE;
933 } else {
934 addr.in.addr6 = sin6.sin6_addr;
935 addr.ipv6 = TRUE;
936 }
937 conn->addr = ipa_new(&addr);
938 conn->at = port;
939 FD_SET(fd, &infds);
940 FD_SET(fd, &outfds);
941 FD_CLR(fd, &readfds);
942 FD_SET(fd, &writefds);
943 if (fd > maxfd) {
944 maxfd = fd;
945 }
946
947 return conn;
948 }
949 # endif
950
951 /*
952 * NAME: conn->accept()
953 * DESCRIPTION: accept a new ipv4 connection
954 */
955 static connection *conn_accept(int portfd, int port)
956 {
957 int fd;
958 unsigned int len;
959 struct sockaddr_in sin;
960 in46addr addr;
961 connection *conn;
962
963 if (!FD_ISSET(portfd, &readfds)) {
964 return (connection *) NULL;
965 }
966 len = sizeof(sin);
967 fd = accept(portfd, (struct sockaddr *) &sin, &len);
968 if (fd < 0) {
969 FD_CLR(portfd, &readfds);
970 return (connection *) NULL;
971 }
972 fcntl(fd, F_SETFL, FNDELAY);
973
974 conn = flist;
975 flist = (connection *) conn->chain.next;
976 conn->chain.name = (char *) NULL;
977 conn->fd = fd;
978 conn->udpbuf = (char *) NULL;
979 addr.in.addr = sin.sin_addr;
980 addr.ipv6 = FALSE;
981 conn->addr = ipa_new(&addr);
982 conn->at = port;
983 FD_SET(fd, &infds);
984 FD_SET(fd, &outfds);
985 FD_CLR(fd, &readfds);
986 FD_SET(fd, &writefds);
987 if (fd > maxfd) {
988 maxfd = fd;
989 }
990
991 return conn;
992 }
993
994 /*
995 * NAME: conn->tnew6()
996 * DESCRIPTION: accept a new telnet connection
997 */
998 connection *conn_tnew6(int port)
999 {
1000 # ifdef INET6
1001 int fd;
1002
1003 fd = tdescs[port].in6;
1004 if (fd >= 0) {
1005 return conn_accept6(fd, port);
1006 }
1007 # endif
1008 return (connection *) NULL;
1009 }
1010
1011 /*
1012 * NAME: conn->bnew6()
1013 * DESCRIPTION: accept a new binary connection
1014 */
1015 connection *conn_bnew6(int port)
1016 {
1017 # ifdef INET6
1018 int fd;
1019
1020 fd = bdescs[port].in6;
1021 if (fd >= 0) {
1022 return conn_accept6(fd, port);
1023 }
1024 # endif
1025 return (connection *) NULL;
1026 }
1027
1028 /*
1029 * NAME: conn->tnew()
1030 * DESCRIPTION: accept a new telnet connection
1031 */
1032 connection *conn_tnew(int port)
1033 {
1034 int fd;
1035
1036 fd = tdescs[port].in4;
1037 if (fd >= 0) {
1038 return conn_accept(fd, port);
1039 }
1040 return (connection *) NULL;
1041 }
1042
1043 /*
1044 * NAME: conn->bnew()
1045 * DESCRIPTION: accept a new binary connection
1046 */
1047 connection *conn_bnew(int port)
1048 {
1049 int fd;
1050
1051 fd = bdescs[port].in4;
1052 if (fd >= 0) {
1053 return conn_accept(fd, port);
1054 }
1055 return (connection *) NULL;
1056 }
1057
1058 /*
1059 * NAME: conn->udp()
1060 * DESCRIPTION: set the challenge for attaching a UDP channel
1061 */
1062 bool conn_udp(connection *conn, char *challenge, unsigned int len)
1063 {
1064 char buffer[UDPHASHSZ];
1065 connection **hash;
1066
1067 if (len == 0 || len > BINBUF_SIZE || conn->udpbuf != (char *) NULL) {
1068 return FALSE; /* invalid challenge */
1069 }
1070
1071 if (len >= UDPHASHSZ) {
1072 memcpy(buffer, challenge, UDPHASHSZ);
1073 } else {
1074 memset(buffer, '\0', UDPHASHSZ);
1075 memcpy(buffer, challenge, len);
1076 }
1077 hash = (connection **) ht_lookup(chtab, buffer, FALSE);
1078 while (*hash != (connection *) NULL &&
1079 memcmp((*hash)->chain.name, buffer, UDPHASHSZ) == 0) {
1080 if ((*hash)->bufsz == len &&
1081 memcmp((*hash)->udpbuf, challenge, len) == 0) {
1082 return FALSE; /* duplicate challenge */
1083 }
1084 }
1085
1086 conn->chain.next = (hte *) *hash;
1087 *hash = conn;
1088 conn->npkts = 0;
1089 m_static();
1090 conn->udpbuf = ALLOC(char, BINBUF_SIZE);
1091 m_dynamic();
1092 memset(conn->udpbuf, '\0', UDPHASHSZ);
1093 memcpy(conn->chain.name = conn->udpbuf, challenge, conn->bufsz = len);
1094
1095 return TRUE;
1096 }
1097 #endif
1098
1099 /*
1100 * NAME: conn->del()
1101 * DESCRIPTION: delete a connection
1102 */
1103 void conn_del(connection *conn)
1104 {
1105 connection **hash;
1106
1107 if (conn->fd >= 0) {
1108 close(conn->fd);
1109 FD_CLR(conn->fd, &infds);
1110 FD_CLR(conn->fd, &outfds);
1111 FD_CLR(conn->fd, &waitfds);
1112 conn->fd = -1;
1113 } else {
1114 --closed;
1115 }
1116 if (conn->udpbuf != (char *) NULL) {
1117 if (conn->chain.name != (char *) NULL) {
1118 hash = (connection **) ht_lookup(chtab, conn->chain.name, FALSE);
1119 # ifdef INET6
1120 } else if (conn->addr->ipnum.ipv6) {
1121 hash = &udphtab[(hashmem((char *) &conn->addr->ipnum,
1122 sizeof(struct in6_addr)) ^ conn->port) % udphtabsz];
1123 # endif
1124 } else {
1125 hash = &udphtab[(((Uint) conn->addr->ipnum.in.addr.s_addr) ^
1126 conn->port) % udphtabsz];
1127 }
1128 while (*hash != conn) {
1129 hash = (connection **) &(*hash)->chain.next;
1130 }
1131 *hash = (connection *) conn->chain.next;
1132 npackets -= conn->npkts;
1133 FREE(conn->udpbuf);
1134 }
1135 if (conn->addr != (ipaddr *) NULL) {
1136 ipa_del(conn->addr);
1137 }
1138 conn->chain.next = (hte *) flist;
1139 flist = conn;
1140 }
1141
1142 /*
1143 * NAME: conn->block()
1144 * DESCRIPTION: block or unblock input from connection
1145 */
1146 void conn_block(connection *conn, int flag)
1147 {
1148 if (conn->fd >= 0) {
1149 if (flag) {
1150 FD_CLR(conn->fd, &infds);
1151 FD_CLR(conn->fd, &readfds);
1152 } else {
1153 FD_SET(conn->fd, &infds);
1154 }
1155 }
1156 }
1157
1158 # ifdef INET6
1159 /*
1160 * NAME: conn->udprecv6()
1161 * DESCRIPTION: receive an UDP packet
1162 */
1163 static void conn_udprecv6(int n)
1164 {
1165 char buffer[BINBUF_SIZE];
1166 struct sockaddr_in6 from;
1167 unsigned int fromlen;
1168 int size;
1169 connection **hash, *conn;
1170 char *p;
1171
1172 memset(buffer, '\0', UDPHASHSZ);
1173 fromlen = sizeof(struct sockaddr_in6);
1174 size = recvfrom(udescs[n].in6, buffer, BINBUF_SIZE, 0,
1175 (struct sockaddr *) &from, &fromlen);
1176 if (size < 0) {
1177 return;
1178 }
1179
1180 hash = &udphtab[(hashmem((char *) &from.sin6_addr,
1181 sizeof(struct in6_addr)) ^
1182 from.sin6_port) % udphtabsz];
1183 for (;;) {
1184 conn = *hash;
1185 if (conn == (connection *) NULL) {
1186 /*
1187 * see if the packet matches an outstanding challenge
1188 */
1189 hash = (connection **) ht_lookup(chtab, buffer, FALSE);
1190 while ((conn=*hash) != (connection *) NULL &&
1191 memcmp(conn->chain.name, buffer, UDPHASHSZ) == 0) {
1192 if (conn->bufsz == size &&
1193 memcmp(conn->udpbuf, buffer, size) == 0 &&
1194 conn->addr->ipnum.ipv6 &&
1195 memcmp(&conn->addr->ipnum, &from.sin6_addr,
1196 sizeof(struct in6_addr)) == 0) {
1197 /*
1198 * attach new UDP channel
1199 */
1200 *hash = (connection *) conn->chain.next;
1201 conn->chain.name = (char *) NULL;
1202 conn->bufsz = 0;
1203 conn->port = from.sin6_port;
1204 hash = &udphtab[(hashmem((char *) &from.sin6_addr,
1205 sizeof(struct in6_addr)) ^ conn->port) % udphtabsz];
1206 conn->chain.next = (hte *) *hash;
1207 *hash = conn;
1208
1209 break;
1210 }
1211 hash = (connection **) &conn->chain.next;
1212 }
1213 break;
1214 }
1215
1216 if (conn->at == n && conn->port == from.sin6_port &&
1217 memcmp(&conn->addr->ipnum, &from.sin6_addr,
1218 sizeof(struct in6_addr)) == 0) {
1219 /*
1220 * packet from known correspondent
1221 */
1222 if (conn->bufsz + size <= BINBUF_SIZE - 2) {
1223 p = conn->udpbuf + conn->bufsz;
1224 *p++ = size >> 8;
1225 *p++ = size;
1226 memcpy(p, buffer, size);
1227 conn->bufsz += size + 2;
1228 conn->npkts++;
1229 npackets++;
1230 }
1231 break;
1232 }
1233 hash = (connection **) &conn->chain.next;
1234 }
1235 }
1236 # endif
1237
1238 /*
1239 * NAME: conn->udprecv()
1240 * DESCRIPTION: receive an UDP packet
1241 */
1242 static void conn_udprecv(int n)
1243 {
1244 char buffer[BINBUF_SIZE];
1245 struct sockaddr_in from;
1246 unsigned int fromlen;
1247 int size;
1248 connection **hash, *conn;
1249 char *p;
1250
1251 memset(buffer, '\0', UDPHASHSZ);
1252 fromlen = sizeof(struct sockaddr_in);
1253 size = recvfrom(udescs[n].in4, buffer, BINBUF_SIZE, 0,
1254 (struct sockaddr *) &from, &fromlen);
1255 if (size < 0) {
1256 return;
1257 }
1258
1259 hash = &udphtab[((Uint) from.sin_addr.s_addr ^ from.sin_port) % udphtabsz];
1260 for (;;) {
1261 conn = *hash;
1262 if (conn == (connection *) NULL) {
1263 /*
1264 * see if the packet matches an outstanding challenge
1265 */
1266 hash = (connection **) ht_lookup(chtab, buffer, FALSE);
1267 while ((conn=*hash) != (connection *) NULL &&
1268 memcmp((*hash)->chain.name, buffer, UDPHASHSZ) == 0) {
1269 if (conn->bufsz == size &&
1270 memcmp(conn->udpbuf, buffer, size) == 0 &&
1271 !conn->addr->ipnum.ipv6 &&
1272 conn->addr->ipnum.in.addr.s_addr == from.sin_addr.s_addr) {
1273 /*
1274 * attach new UDP channel
1275 */
1276 *hash = (connection *) conn->chain.next;
1277 conn->chain.name = (char *) NULL;
1278 conn->bufsz = 0;
1279 conn->port = from.sin_port;
1280 hash = &udphtab[((Uint) from.sin_addr.s_addr ^
1281 conn->port) % udphtabsz];
1282 conn->chain.next = (hte *) *hash;
1283 *hash = conn;
1284
1285 break;
1286 }
1287 hash = (connection **) &conn->chain.next;
1288 }
1289 break;
1290 }
1291
1292 if (conn->at == n &&
1293 conn->addr->ipnum.in.addr.s_addr == from.sin_addr.s_addr &&
1294 conn->port == from.sin_port) {
1295 /*
1296 * packet from known correspondent
1297 */
1298 if (conn->bufsz + size <= BINBUF_SIZE - 2) {
1299 p = conn->udpbuf + conn->bufsz;
1300 *p++ = size >> 8;
1301 *p++ = size;
1302 memcpy(p, buffer, size);
1303 conn->bufsz += size + 2;
1304 conn->npkts++;
1305 npackets++;
1306 }
1307 break;
1308 }
1309 hash = (connection **) &conn->chain.next;
1310 }
1311 }
1312
1313 /*
1314 * NAME: conn->select()
1315 * DESCRIPTION: wait for input from connections
1316 */
1317 int conn_select(Uint t, unsigned int mtime)
1318 {
1319 struct timeval timeout;
1320 int retval;
1321 int n;
1322
1323 /*
1324 * First, check readability and writability for binary sockets with pending
1325 * data only.
1326 */
1327 memcpy(&readfds, &infds, sizeof(fd_set));
1328 if (flist == (connection *) NULL) {
1329 /* can't accept new connections, so don't check for them */
1330 for (n = ntdescs; n != 0; ) {
1331 --n;
1332 if (tdescs[n].in6 >= 0) {
1333 FD_CLR(tdescs[n].in6, &readfds);
1334 }
1335 if (tdescs[n].in4 >= 0) {
1336 FD_CLR(tdescs[n].in4, &readfds);
1337 }
1338 }
1339 for (n = nbdescs; n != 0; ) {
1340 --n;
1341 if (bdescs[n].in6 >= 0) {
1342 FD_CLR(bdescs[n].in6, &readfds);
1343 }
1344 if (bdescs[n].in4 >= 0) {
1345 FD_CLR(bdescs[n].in4, &readfds);
1346 }
1347 }
1348 }
1349 memcpy(&writefds, &waitfds, sizeof(fd_set));
1350 if (npackets + closed != 0) {
1351 t = 0;
1352 mtime = 0;
1353 }
1354 if (mtime != 0xffff) {
1355 timeout.tv_sec = t;
1356 timeout.tv_usec = mtime * 1000L;
1357 retval = select(maxfd + 1, &readfds, &writefds, (fd_set *) NULL,
1358 &timeout);
1359 } else {
1360 retval = select(maxfd + 1, &readfds, &writefds, (fd_set *) NULL,
1361 (struct timeval *) NULL);
1362 }
1363 if (retval < 0) {
1364 FD_ZERO(&readfds);
1365 retval = 0;
1366 }
1367
1368 /* check for UDP packets */
1369 for (n = 0; n < nbdescs; n++) {
1370 # ifdef INET6
1371 if (udescs[n].in6 >= 0 && FD_ISSET(udescs[n].in6, &readfds)) {
1372 conn_udprecv6(n);
1373 }
1374 # endif
1375 if (udescs[n].in4 >= 0 && FD_ISSET(udescs[n].in4, &readfds)) {
1376 conn_udprecv(n);
1377 }
1378 }
1379 retval += npackets + closed;
1380
1381 /*
1382 * Now check writability for all sockets in a polling call.
1383 */
1384 memcpy(&writefds, &outfds, sizeof(fd_set));
1385 timeout.tv_sec = 0;
1386 timeout.tv_usec = 0;
1387 select(maxfd + 1, (fd_set *) NULL, &writefds, (fd_set *) NULL, &timeout);
1388
1389 /* handle ip name lookup */
1390 if (FD_ISSET(in, &readfds)) {
1391 ipa_lookup();
1392 }
1393 return retval;
1394 }
1395
1396 #ifndef NETWORK_EXTENSIONS
1397 /*
1398 * NAME: conn->udpcheck()
1399 * DESCRIPTION: check if UDP challenge met
1400 */
1401 bool conn_udpcheck(connection *conn)
1402 {
1403 return (conn->chain.name == (char *) NULL);
1404 }
1405 #endif
1406
1407 /*
1408 * NAME: conn->read()
1409 * DESCRIPTION: read from a connection
1410 */
1411 int conn_read(connection *conn, char *buf, unsigned int len)
1412 {
1413 int size;
1414
1415 if (conn->fd < 0) {
1416 return -1;
1417 }
1418 if (!FD_ISSET(conn->fd, &readfds)) {
1419 return 0;
1420 }
1421 size = read(conn->fd, buf, len);
1422 if (size < 0) {
1423 close(conn->fd);
1424 FD_CLR(conn->fd, &infds);
1425 FD_CLR(conn->fd, &outfds);
1426 FD_CLR(conn->fd, &waitfds);
1427 conn->fd = -1;
1428 closed++;
1429 }
1430 return (size == 0) ? -1 : size;
1431 }
1432
1433 /*
1434 * NAME: conn->udpread()
1435 * DESCRIPTION: read a message from a UDP channel
1436 */
1437 int conn_udpread(connection *conn, char *buf, unsigned int len)
1438 {
1439 unsigned short size, n;
1440 char *p, *q;
1441
1442 while (conn->bufsz != 0) {
1443 /* udp buffer is not empty */
1444 size = (UCHAR(conn->udpbuf[0]) << 8) | UCHAR(conn->udpbuf[1]);
1445 if (size <= len) {
1446 memcpy(buf, conn->udpbuf + 2, len = size);
1447 }
1448 --conn->npkts;
1449 --npackets;
1450 conn->bufsz -= size + 2;
1451 for (p = conn->udpbuf, q = p + size + 2, n = conn->bufsz; n != 0; --n) {
1452 *p++ = *q++;
1453 }
1454 if (len == size) {
1455 return len;
1456 }
1457 }
1458 return -1;
1459 }
1460
1461 /*
1462 * NAME: conn->write()
1463 * DESCRIPTION: write to a connection; return the amount of bytes written
1464 */
1465 int conn_write(connection *conn, char *buf, unsigned int len)
1466 {
1467 int size;
1468
1469 if (conn->fd < 0) {
1470 return -1;
1471 }
1472 if (len == 0) {
1473 return 0;
1474 }
1475 if (!FD_ISSET(conn->fd, &writefds)) {
1476 /* the write would fail */
1477 FD_SET(conn->fd, &waitfds);
1478 return 0;
1479 }
1480 if ((size=write(conn->fd, buf, len)) < 0 && errno != EWOULDBLOCK) {
1481 close(conn->fd);
1482 FD_CLR(conn->fd, &infds);
1483 FD_CLR(conn->fd, &outfds);
1484 conn->fd = -1;
1485 closed++;
1486 } else if (size != len) {
1487 /* waiting for wrdone */
1488 FD_SET(conn->fd, &waitfds);
1489 FD_CLR(conn->fd, &writefds);
1490 if (size < 0) {
1491 return 0;
1492 }
1493 }
1494 return size;
1495 }
1496
1497 /*
1498 * NAME: conn->udpwrite()
1499 * DESCRIPTION: write a message to a UDP channel
1500 */
1501 int conn_udpwrite(connection *conn, char *buf, unsigned int len)
1502 {
1503 if (conn->fd >= 0) {
1504 # ifdef INET6
1505 if (conn->addr->ipnum.ipv6) {
1506 struct sockaddr_in6 to;
1507
1508 memset(&to, '\0', sizeof(struct sockaddr_in6));
1509 to.sin6_family = AF_INET6;
1510 memcpy(&to.sin6_addr, &conn->addr->ipnum.in.addr6,
1511 sizeof(struct in6_addr));
1512 to.sin6_port = conn->port;
1513 return sendto(udescs[conn->at].in6, buf, len, 0,
1514 (struct sockaddr *) &to, sizeof(struct sockaddr_in6));
1515 } else
1516 # endif
1517 {
1518 struct sockaddr_in to;
1519
1520 memset(&to, '\0', sizeof(struct sockaddr_in));
1521 to.sin_family = AF_INET;
1522 to.sin_addr = conn->addr->ipnum.in.addr;
1523 to.sin_port = conn->port;
1524 return sendto(udescs[conn->at].in4, buf, len, 0,
1525 (struct sockaddr *) &to, sizeof(struct sockaddr_in));
1526 }
1527 }
1528 return -1;
1529 }
1530
1531 #ifdef NETWORK_EXTENSIONS
1532 int conn_udpsend(connection *conn, char *buf, unsigned int len, char *addr,
1533 unsigned short port)
1534 {
1535 struct sockaddr_in to;
1536
1537 to.sin_family=addrtype;
1538 inet_aton(addr, &to.sin_addr); /* should have been checked for valid
1539 addresses already, so it should not
1540 fail */
1541 to.sin_port = htons(port);
1542 if (!sendto(conn->fd, buf, len, 0, (struct sockaddr *) &to,
1543 sizeof(struct sockaddr_in)))
1544 {
1545 if (errno==EAGAIN) {
1546 return -1;
1547 }
1548 perror("sendto");
1549 return -2;
1550 }
1551 return 0;
1552 }
1553
1554 /*
1555 * NAME: conn->checkaddr()
1556 * DESCRIPTION: checks for valid ip address
1557 */
1558 int conn_checkaddr(char *ip)
1559 {
1560 struct in_addr dummy;
1561 return inet_aton(ip, &dummy);
1562 }
1563 #endif
1564
1565 /*
1566 * NAME: conn->wrdone()
1567 * DESCRIPTION: return TRUE if a connection is ready for output
1568 */
1569 bool conn_wrdone(connection *conn)
1570 {
1571 if (conn->fd < 0 || !FD_ISSET(conn->fd, &waitfds)) {
1572 return TRUE;
1573 }
1574 if (FD_ISSET(conn->fd, &writefds)) {
1575 FD_CLR(conn->fd, &waitfds);
1576 return TRUE;
1577 }
1578 return FALSE;
1579 }
1580
1581 /*
1582 * NAME: conn->ipnum()
1583 * DESCRIPTION: return the ip number of a connection
1584 */
1585 void conn_ipnum(connection *conn, char *buf)
1586 {
1587 # ifdef INET6
1588 /* IPv6: maxlen 39 */
1589 if (conn->addr->ipnum.ipv6) {
1590 inet_ntop(AF_INET6, &conn->addr->ipnum, buf, 40);
1591 } else
1592 # endif
1593 {
1594 strcpy(buf, inet_ntoa(conn->addr->ipnum.in.addr));
1595 }
1596
1597 }
1598
1599 /*
1600 * NAME: conn->ipname()
1601 * DESCRIPTION: return the ip name of a connection
1602 */
1603 void conn_ipname(connection *conn, char *buf)
1604 {
1605 if (conn->addr->name[0] != '\0') {
1606 strcpy(buf, conn->addr->name);
1607 } else {
1608 conn_ipnum(conn, buf);
1609 }
1610 }
1611
1612 /*
1613 * NAME: conn->host()
1614 * DESCRIPTION: look up a host
1615 */
1616 void *conn_host(char *addr, unsigned short port, int *len)
1617 {
1618 struct hostent *host;
1619 static union {
1620 struct sockaddr_in sin;
1621 # ifdef INET6
1622 struct sockaddr_in6 sin6;
1623 # endif
1624 } inaddr;
1625
1626 memset(&inaddr.sin, '\0', sizeof(struct sockaddr_in));
1627 inaddr.sin.sin_family = AF_INET;
1628 inaddr.sin.sin_port = htons(port);
1629 *len = sizeof(struct sockaddr_in);
1630 if ((inaddr.sin.sin_addr.s_addr=inet_addr(addr)) != INADDR_NONE) {
1631 return &inaddr;
1632 } else {
1633 host = gethostbyname(addr);
1634 if (host != (struct hostent *) NULL) {
1635 memcpy(&inaddr.sin.sin_addr, host->h_addr, host->h_length);
1636 return &inaddr;
1637 }
1638 }
1639
1640 # ifdef INET6
1641 memset(&inaddr.sin6, '\0', sizeof(struct sockaddr_in6));
1642 inaddr.sin6.sin6_family = AF_INET6;
1643 *len = sizeof(struct sockaddr_in6);
1644 if (inet_pton(AF_INET6, addr, &inaddr.sin6) > 0) {
1645 inaddr.sin6.sin6_family = AF_INET6;
1646 inaddr.sin6.sin6_port = htons(port);
1647 return &inaddr;
1648 } else {
1649 # ifdef AI_DEFAULT
1650 int err;
1651
1652 host = getipnodebyname(addr, AF_INET6, 0, &err);
1653 # else
1654 host = gethostbyname2(addr, AF_INET6);
1655 # endif
1656 if (host != (struct hostent *) NULL) {
1657 if (host->h_length != 4) {
1658 memcpy(&inaddr.sin6.sin6_addr, host->h_addr, host->h_length);
1659 # ifdef AI_DEFAULT
1660 freehostent(host);
1661 # endif
1662 inaddr.sin6.sin6_port = htons(port);
1663 return &inaddr;
1664 }
1665 # ifdef AI_DEFAULT
1666 freehostent(host);
1667 # endif
1668 }
1669 }
1670 # endif
1671
1672 return (void *) NULL;
1673 }
1674
1675 /*
1676 * NAME: conn->connect()
1677 * DESCRIPTION: establish an oubound connection
1678 */
1679 connection *conn_connect(void *addr, int len)
1680 {
1681 connection *conn;
1682 int sock;
1683 int on;
1684 long arg;
1685
1686 if (flist == (connection *) NULL) {
1687 return NULL;
1688 }
1689
1690 sock = socket(((struct sockaddr_in *) addr)->sin_family, SOCK_STREAM, 0);
1691 if (sock < 0) {
1692 perror("socket");
1693 return NULL;
1694 }
1695 on = 1;
1696 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
1697 sizeof(on)) < 0) {
1698 perror("setsockopt");
1699 close(sock);
1700 return NULL;
1701 }
1702 #ifdef SO_OOBINLINE
1703 on = 1;
1704 if (setsockopt(sock, SOL_SOCKET, SO_OOBINLINE, (char *) &on,
1705 sizeof(on)) < 0) {
1706 perror("setsockopt");
1707 close(sock);
1708 return NULL;
1709 }
1710 #endif
1711 if ((arg = fcntl(sock, F_GETFL, NULL)) < 0) {
1712 perror("fcntl");
1713 close(sock);
1714 return NULL;
1715 }
1716 arg |= O_NONBLOCK;
1717 if (fcntl(sock, F_SETFL, arg) < 0) {
1718 perror("fcntl");
1719 close(sock);
1720 return NULL;
1721 }
1722
1723 connect(sock, (struct sockaddr *) addr, len);
1724
1725 conn = flist;
1726 flist = (connection *) conn->chain.next;
1727 conn->fd = sock;
1728 conn->chain.name = (char *) NULL;
1729 conn->udpbuf = (char *) NULL;
1730 conn->addr = (ipaddr *) NULL;
1731 conn->at = -1;
1732 FD_SET(sock, &infds);
1733 FD_SET(sock, &outfds);
1734 FD_CLR(sock, &readfds);
1735 FD_CLR(sock, &writefds);
1736 FD_SET(sock, &waitfds);
1737 if (sock > maxfd) {
1738 maxfd = sock;
1739 }
1740 return conn;
1741 }
1742
1743 /*
1744 * check for a connection in pending state and see if it is connected.
1745 */
1746 int conn_check_connected(connection *conn, bool *refused)
1747 {
1748 int optval;
1749 socklen_t lon;
1750
1751 /*
1752 * indicate that our fd became invalid.
1753 */
1754 if (conn->fd < 0) {
1755 return -2;
1756 }
1757
1758 if (!FD_ISSET(conn->fd, &writefds)) {
1759 return 0;
1760 }
1761 FD_CLR(conn->fd, &waitfds);
1762
1763 /*
1764 * Delayed connect completed, check for errors
1765 */
1766 lon = sizeof(int);
1767 /*
1768 * Get error state for the socket
1769 */
1770 *refused = FALSE;
1771 if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, (void *)(&optval), &lon) < 0)
1772 {
1773 return -1;
1774 }
1775 if (optval != 0) {
1776 if (optval == ECONNREFUSED) {
1777 *refused = TRUE;
1778 }
1779 errno = optval;
1780 return -1;
1781 } else {
1782 # ifdef INET6
1783 struct sockaddr_in6 sin;
1784 # else
1785 struct sockaddr_in sin;
1786 # endif
1787 socklen_t len;
1788 in46addr inaddr;
1789
1790 len = sizeof(sin);
1791 getpeername(conn->fd, (struct sockaddr *) &sin, &len);
1792 inaddr.ipv6 = FALSE;
1793 # ifdef INET6
1794 if (sin.sin6_family == AF_INET6) {
1795 inaddr.in.addr6 = sin.sin6_addr;
1796 inaddr.ipv6 = TRUE;
1797 } else
1798 # endif
1799 inaddr.in.addr = ((struct sockaddr_in *) &sin)->sin_addr;
1800 conn->addr = ipa_new(&inaddr);
1801 errno = 0;
1802 return 1;
1803 }
1804 }
1805
1806
1807 #ifdef NETWORK_EXTENSIONS
1808 /*
1809 * Name: conn->openlisten()
1810 * DESCRIPTION: open a new listening connection
1811 */
1812 connection *conn_openlisten(unsigned char protocol, unsigned short port)
1813 {
1814 struct sockaddr_in sin;
1815 connection *conn;
1816 int on, n, sock;
1817 unsigned int sz;
1818
1819
1820 switch (protocol) {
1821 case P_TCP:
1822 sock = socket(addrtype, SOCK_STREAM, 0);
1823 if (sock < 0){
1824 perror("socket");
1825 return NULL;
1826 }
1827 on = 1;
1828 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
1829 sizeof(on)) < 0){
1830 perror("setsockopt");
1831 close(sock);
1832 return NULL;
1833 }
1834 # ifdef SO_OOBINLINE
1835 on = 1;
1836 if (setsockopt(sock, SOL_SOCKET, SO_OOBINLINE, (char *) &on,
1837 sizeof(on)) < 0) {
1838 perror("setsockopt");
1839 close(sock);
1840 return NULL;
1841 }
1842 # endif
1843 memset(&sin, '\0', sizeof(sin));
1844 sin.sin_port = htons(port);
1845 sin.sin_family = addrtype;
1846 sin.sin_addr.s_addr = INADDR_ANY;
1847 if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
1848 perror("bind");
1849 close(sock);
1850 return NULL;
1851 }
1852
1853 if (listen(sock,64)) {
1854 perror("listen");
1855 close(sock);
1856 return NULL;
1857 }
1858
1859 FD_SET(sock, &infds);
1860 if (maxfd < sock) {
1861 maxfd = sock;
1862 }
1863
1864 conn = flist;
1865 flist = (connection *) conn->chain.next;
1866 conn->fd = sock;
1867 conn->chain.name = (char *) NULL;
1868 conn->udpbuf = (char *) NULL;
1869 conn->addr = (ipaddr *) NULL;
1870 sz = sizeof(sin);
1871 getsockname(conn->fd, (struct sockaddr *) &sin, &sz);
1872 conn->port = ntohs(sin.sin_port);
1873 conn->at = -1;
1874 return conn;
1875 case P_UDP:
1876 sock = socket(addrtype, SOCK_DGRAM, 0);
1877 if (sock < 0) {
1878 perror("socket");
1879 return NULL;
1880 }
1881 on = 0;
1882 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
1883 sizeof(on)) < 0) {
1884 perror("setsockopt");
1885 close(sock);
1886 return NULL;
1887 }
1888 memset(&sin, '\0', sizeof(sin));
1889 sin.sin_port = htons(port);
1890 sin.sin_family = addrtype;
1891 sin.sin_addr.s_addr = INADDR_ANY;
1892 if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
1893 perror("bind");
1894 close(sock);
1895 return NULL;
1896 }
1897 if (fcntl(sock, F_SETFL, FNDELAY)) {
1898 perror("fcntl");
1899 close(sock);
1900 return NULL;
1901 }
1902 FD_SET(sock, &infds);
1903 if (maxfd < sock) {
1904 maxfd = sock;
1905 }
1906 conn = flist;
1907 flist = (connection *) conn->chain.next;
1908 conn->fd = sock;
1909 conn->chain.name = (char *) NULL;
1910 conn->udpbuf = (char *) NULL;
1911 conn->addr = (ipaddr *) NULL;
1912 sz = sizeof(sin);
1913 getsockname(conn->fd, (struct sockaddr *) &sin, &sz);
1914 conn->port = ntohs(sin.sin_port);
1915 conn->at = -1;
1916 return conn;
1917 default:
1918 return NULL;
1919 }
1920 }
1921
1922 /*
1923 * NAME: conn->port()
1924 * DESCRIPTION: return the port number of a connection
1925 */
1926 int conn_at(connection *conn)
1927 {
1928 return conn->port;
1929 }
1930
1931 /*
1932 * NAME: conn->accept()
1933 * DESCRIPTION: return a new connction structure
1934 */
1935 connection *conn_accept(connection *conn)
1936 {
1937 int fd;
1938 unsigned int len;
1939 struct sockaddr_in sin;
1940 in46addr addr;
1941 connection *newconn;
1942
1943 if (!FD_ISSET(conn->fd, &readfds)) {
1944 return (connection *) NULL;
1945 }
1946
1947 len = sizeof(sin);
1948 fd = accept(conn->fd, (struct sockaddr *) &sin, &len);
1949 if (fd < 0) {
1950 return (connection *) NULL;
1951 }
1952 if (fcntl(fd, F_SETFL, FNDELAY)) {
1953 perror("fcntl");
1954 close(fd);
1955 return NULL;
1956 }
1957
1958 newconn = flist;
1959 flist = (connection *)newconn->chain.next;
1960 newconn->fd = fd;
1961 newconn->chain.name = (char *) NULL;
1962 newconn->udpbuf = (char *) NULL;
1963 addr.in.addr = sin.sin_addr;
1964 addr.ipv6 = FALSE;
1965 newconn->addr = ipa_new(&addr);
1966 newconn->port = ntohs(sin.sin_port);
1967 newconn->at = -1;
1968 FD_SET(fd, &infds);
1969 FD_SET(fd, &outfds);
1970 FD_CLR(fd, &readfds);
1971 FD_SET(fd, &writefds);
1972 if (fd > maxfd) {
1973 maxfd = fd;
1974 }
1975
1976 return newconn;
1977 }
1978
1979 int conn_udpreceive(connection *conn, char *buffer, int size, char **host,
1980 int *port)
1981 {
1982 if (FD_ISSET(conn->fd, &readfds)) {
1983 struct sockaddr_in from;
1984 unsigned int fromlen;
1985 int sz;
1986
1987 fromlen = sizeof(struct sockaddr_in);
1988 sz = recvfrom(conn->fd, buffer, size, 0, (struct sockaddr *) &from,
1989 &fromlen);
1990 if (sz < 0) {
1991 perror("recvfrom");
1992 return sz;
1993 }
1994 *host = inet_ntoa(from.sin_addr);
1995 *port = ntohs(from.sin_port);
1996 return sz;
1997 }
1998 return -1;
1999 }
2000
2001 #endif
2002
2003 # define CONN_READF 0x01 /* read flag set */
2004 # define CONN_WRITEF 0x02 /* write flag set */
2005 # define CONN_WAITF 0x04 /* wait flag set */
2006 # define CONN_UCHAL 0x08 /* UDP challenge issued */
2007 # define CONN_UCHAN 0x10 /* UDP channel established */
2008 # define CONN_ADDR 0x20 /* has an address */
2009
2010 /*
2011 * NAME: conn->export()
2012 * DESCRIPTION: export a connection
2013 */
2014 bool conn_export(connection *conn, int *fd, unsigned short *port, short *at,
2015 int *npkts, int *bufsz, char **buf, char *flags)
2016 {
2017 *fd = conn->fd;
2018 *port = conn->port;
2019 if (conn->fd >= 0) {
2020 *flags = 0;
2021 *at = conn->at;
2022 *npkts = conn->npkts;
2023 *bufsz = conn->bufsz;
2024 *buf = conn->udpbuf;
2025 if (FD_ISSET(conn->fd, &readfds)) {
2026 *flags |= CONN_READF;
2027 }
2028 if (FD_ISSET(conn->fd, &writefds)) {
2029 *flags |= CONN_WRITEF;
2030 }
2031 if (FD_ISSET(conn->fd, &waitfds)) {
2032 *flags |= CONN_WAITF;
2033 }
2034 if (conn->udpbuf != (char *) NULL) {
2035 if (conn->chain.name != NULL) {
2036 *flags |= CONN_UCHAL;
2037 } else {
2038 *flags |= CONN_UCHAN;
2039 }
2040 }
2041 if (conn->addr != (ipaddr *) NULL) {
2042 *flags |= CONN_ADDR;
2043 }
2044 }
2045
2046 return TRUE;
2047 }
2048
2049 /*
2050 * NAME: conn->import()
2051 * DESCRIPTION: import a connection
2052 */
2053 connection *conn_import(int fd, unsigned short port, short at, int npkts,
2054 int bufsz, char *buf, char flags, bool telnet)
2055 {
2056 # ifdef INET6
2057 struct sockaddr_in6 sin;
2058 # else
2059 struct sockaddr_in sin;
2060 # endif
2061 socklen_t len;
2062 in46addr inaddr;
2063 connection *conn;
2064
2065 if (fd >= 0) {
2066 len = sizeof(sin);
2067 if (getpeername(fd, (struct sockaddr *) &sin, &len) != 0) {
2068 if (errno == EBADF || errno == ENOTCONN || (flags & CONN_ADDR)) {
2069 return (connection *) NULL;
2070 }
2071 } else {
2072 ipa_close(fd);
2073 inaddr.ipv6 = FALSE;
2074 # ifdef INET6
2075 if (sin.sin6_family == AF_INET6) {
2076 inaddr.in.addr6 = sin.sin6_addr;
2077 inaddr.ipv6 = TRUE;
2078 } else
2079 # endif
2080 inaddr.in.addr = ((struct sockaddr_in *) &sin)->sin_addr;
2081 }
2082 } else {
2083 closed++;
2084 }
2085
2086 conn = flist;
2087 flist = (connection *) conn->chain.next;
2088 conn->fd = fd;
2089 conn->chain.name = (char *) NULL;
2090 conn->udpbuf = (char *) NULL;
2091 conn->addr = (ipaddr *) NULL;
2092 conn->bufsz = 0;
2093 conn->npkts = 0;
2094 conn->port = port;
2095 conn->at = -1;
2096
2097 if (fd >= 0) {
2098 FD_SET(fd, &infds);
2099 FD_SET(fd, &outfds);
2100 if (flags & CONN_READF) {
2101 FD_SET(fd, &readfds);
2102 }
2103 if (flags & CONN_WRITEF) {
2104 FD_SET(fd, &writefds);
2105 }
2106 if (flags & CONN_WAITF) {
2107 FD_SET(fd, &waitfds);
2108 }
2109 if (fd > maxfd) {
2110 maxfd = fd;
2111 }
2112
2113 if (at >= 0 && at >= ((telnet) ? ntdescs : nbdescs)) {
2114 at = -1;
2115 }
2116 conn->at = at;
2117 if (flags & CONN_ADDR) {
2118 conn->addr = ipa_new(&inaddr);
2119 }
2120
2121 # ifndef NETWORK_EXTENSIONS
2122 if (at >= 0) {
2123 if (flags & CONN_UCHAL) {
2124 conn_udp(conn, buf, bufsz);
2125 }
2126 if (flags & CONN_UCHAN) {
2127 connection **hash;
2128
2129 conn->bufsz = bufsz;
2130 m_static();
2131 conn->udpbuf = ALLOC(char, BINBUF_SIZE);
2132 m_dynamic();
2133 memcpy(conn->udpbuf, buf, bufsz);
2134 # ifdef INET6
2135 if (inaddr.ipv6) {
2136 hash = &udphtab[(hashmem((char *) &inaddr.in.addr6,
2137 sizeof(struct in6_addr)) ^ conn->port) % udphtabsz];
2138 } else
2139 # endif
2140 hash = &udphtab[((Uint) inaddr.in.addr.s_addr ^ conn->port) %
2141 udphtabsz];
2142 conn->chain.next = (hte *) *hash;
2143 *hash = conn;
2144 }
2145 conn->npkts = npkts;
2146 npackets += npkts;
2147 }
2148 # endif
2149 }
2150
2151 return conn;
2152 }
2153