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