Clarified the dscp-tos documentation a bit.
[doldaconnect.git] / daemon / net.c
1 /*
2  *  Dolda Connect - Modular multiuser Direct Connect-style client
3  *  Copyright (C) 2004 Fredrik Tolf <fredrik@dolda2000.com>
4  *  
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *  
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *  
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 /* XXX: Implement SOCKS proxyability */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <string.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <sys/ioctl.h>
29 #include <sys/socket.h>
30 #include <sys/un.h>
31 #include <sys/select.h>
32 #include <arpa/inet.h>
33 #include <netinet/in.h>
34 #include <netdb.h>
35 #include <sys/signal.h>
36 #include <sys/stat.h>       /* For rebindunix() */
37 #ifdef HAVE_LINUX_SOCKIOS_H
38 #include <linux/sockios.h>
39 #endif
40 #include <errno.h>
41 #include <net/if.h>
42
43 #include "conf.h"
44 #include "net.h"
45 #include "module.h"
46 #include "log.h"
47 #include "utils.h"
48 #include "sysevents.h"
49
50 static struct configvar myvars[] =
51 {
52     /** The network mode to use. Currently supported values are 0 for
53      * active mode and 1 for passive mode. In the future, SOCKS5 proxy
54      * support may be added. */
55     {CONF_VAR_INT, "mode", {.num = 0}},
56     /** Set the SO_REUSEADDR socket option on listening sockets, so
57      * that dead TCP connections waiting for timeout are ignored. */
58     {CONF_VAR_BOOL, "reuseaddr", {.num = 0}},
59     /** Overrides the IPv4 address reported to other clients in active
60      * mode. Useful for servers behind NAT routers. If both this and
61      * net.publicif are unspecified the address of the hub connection
62      * is used. */
63     {CONF_VAR_IPV4, "visibleipv4", {.ipv4 = {0}}},
64     /** Specifies an interface name from which to fetch the IPv4
65      * address reported to other clients in active mode. If both this
66      * and net.visibleipv4 are unspecified the address of the hub
67      * connection is used. */
68     {CONF_VAR_STRING, "publicif", {.str = L""}},
69     /** The Diffserv value to use on IPv6 connections when the
70      * minimize cost TOS value is used (see the TOS VALUES
71      * section). */
72     {CONF_VAR_INT, "diffserv-mincost", {.num = 0}},
73     /** The Diffserv value to use on IPv6 connections when the
74      * maximize reliability TOS value is used (see the TOS VALUES
75      * section). */
76     {CONF_VAR_INT, "diffserv-maxrel", {.num = 0}},
77     /** The Diffserv value to use on IPv6 connections when the
78      * maximize throughput TOS value is used (see the TOS VALUES
79      * section). */
80     {CONF_VAR_INT, "diffserv-maxtp", {.num = 0}},
81     /** The Diffserv value to use on IPv6 connections when the
82      * minimize delay TOS value is used (see the TOS VALUES
83      * section). */
84     {CONF_VAR_INT, "diffserv-mindelay", {.num = 0}},
85     /** If enabled, the IP TOS interface will be used to set Diffserv
86      * codepoints on IPv4 sockets, by shifting the DSCP value two bits
87      * to the left (remember, the DSCP field in the IPv4 header is
88      * defined as the 6 uppermost bits of the TOS field, the lower two
89      * being left for ECN). This may only work on Linux. */
90     {CONF_VAR_BOOL, "dscp-tos", {.num = 0}},
91     {CONF_VAR_END}
92 };
93
94 static struct socket *sockets = NULL;
95 int numsocks = 0;
96
97 /* XXX: Get autoconf for all this... */
98 int getpublicaddr(int af, struct sockaddr **addr, socklen_t *lenbuf)
99 {
100     struct sockaddr_in *ipv4;
101     struct configvar *var;
102     void *bufend;
103     int sock;
104     struct ifconf conf;
105     struct ifreq *ifr, req;
106     char *pif;
107     
108     if(af == AF_INET)
109     {
110         var = confgetvar("net", "visibleipv4");
111         if(var->val.ipv4.s_addr != 0)
112         {
113             ipv4 = smalloc(sizeof(*ipv4));
114             ipv4->sin_family = AF_INET;
115             ipv4->sin_addr.s_addr = var->val.ipv4.s_addr;
116             *addr = (struct sockaddr *)ipv4;
117             *lenbuf = sizeof(*ipv4);
118             return(0);
119         }
120         if((pif = icswcstombs(confgetstr("net", "publicif"), NULL, NULL)) == NULL)
121         {
122             flog(LOG_ERR, "could not convert net.publicif into local charset: %s", strerror(errno));
123             return(-1);
124         }
125         if(!strcmp(pif, ""))
126             return(1);
127         if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
128             return(-1);
129         conf.ifc_buf = smalloc(conf.ifc_len = 65536);
130         if(ioctl(sock, SIOCGIFCONF, &conf) < 0)
131         {
132             free(conf.ifc_buf);
133             close(sock);
134             return(-1);
135         }
136         bufend = ((char *)conf.ifc_buf) + conf.ifc_len;
137         ipv4 = NULL;
138         for(ifr = conf.ifc_ifcu.ifcu_req; (void *)ifr < bufend; ifr++)
139         {
140             if(strcmp(ifr->ifr_name, pif))
141                 continue;
142             memset(&req, 0, sizeof(req));
143             memcpy(req.ifr_name, ifr->ifr_name, sizeof(ifr->ifr_name));
144             if(ioctl(sock, SIOCGIFFLAGS, &req) < 0)
145                 break;
146             if(!(req.ifr_flags & IFF_UP))
147             {
148                 flog(LOG_WARNING, "public interface is down");
149                 break;
150             }
151             if(ifr->ifr_addr.sa_family != AF_INET)
152             {
153                 flog(LOG_WARNING, "address of the public interface is not AF_INET");
154                 break;
155             }
156             ipv4 = smalloc(sizeof(*ipv4));
157             memcpy(ipv4, &ifr->ifr_addr, sizeof(ifr->ifr_addr));
158             break;
159         }
160         free(conf.ifc_buf);
161         close(sock);
162         if(ipv4 != NULL)
163         {
164             *addr = (struct sockaddr *)ipv4;
165             *lenbuf = sizeof(*ipv4);
166             return(0);
167         }
168         errno = ENETDOWN;
169         return(-1);
170     }
171     return(1);
172 }
173
174 static struct socket *newsock(int type)
175 {
176     struct socket *new;
177     
178     new = smalloc(sizeof(*new));
179     memset(new, 0, sizeof(*new));
180     new->refcount = 2;
181     new->fd = -1;
182     new->isrealsocket = 1;
183     new->family = -1;
184     new->tos = 0;
185     new->type = type;
186     new->state = -1;
187     new->ignread = 0;
188     new->close = 0;
189     new->remote = NULL;
190     new->remotelen = 0;
191     new->ucred.uid = -1;
192     new->ucred.gid = -1;
193     switch(type)
194     {
195     case SOCK_STREAM:
196         new->outbuf.s.buf = NULL;
197         new->outbuf.s.bufsize = 0;
198         new->outbuf.s.datasize = 0;
199         new->inbuf.s.buf = NULL;
200         new->inbuf.s.bufsize = 0;
201         new->inbuf.s.datasize = 0;
202         break;
203     case SOCK_DGRAM:
204         new->outbuf.d.f = new->outbuf.d.l = NULL;
205         new->inbuf.d.f = new->inbuf.d.l = NULL;
206         break;
207     }
208     new->conncb = NULL;
209     new->errcb = NULL;
210     new->readcb = NULL;
211     new->writecb = NULL;
212     new->acceptcb = NULL;
213     new->next = sockets;
214     new->prev = NULL;
215     if(sockets != NULL)
216         sockets->prev = new;
217     sockets = new;
218     numsocks++;
219     return(new);
220 }
221
222 static struct socket *mksock(int domain, int type)
223 {
224     int fd;
225     struct socket *new;
226     
227     if((fd = socket(domain, type, 0)) < 0)
228     {
229         flog(LOG_CRIT, "could not create socket: %s", strerror(errno));
230         return(NULL);
231     }
232     new = newsock(type);
233     new->fd = fd;
234     new->family = domain;
235     fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
236     return(new);
237 }
238
239 struct socket *wrapsock(int fd)
240 {
241     struct socket *new;
242     
243     new = newsock(SOCK_STREAM);
244     new->fd = fd;
245     new->state = SOCK_EST;
246     new->isrealsocket = 0;
247     fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
248     return(new);
249 }
250
251 static void unlinksock(struct socket *sk)
252 {
253     if(sk->prev != NULL)
254         sk->prev->next = sk->next;
255     if(sk->next != NULL)
256         sk->next->prev = sk->prev;
257     if(sk == sockets)
258         sockets = sk->next;
259     putsock(sk);
260     numsocks--;
261 }
262
263 void getsock(struct socket *sk)
264 {
265     sk->refcount++;
266 }
267
268 void putsock(struct socket *sk)
269 {
270     struct dgrambuf *buf;
271     
272     if(--(sk->refcount) == 0)
273     {
274         switch(sk->type)
275         {
276         case SOCK_STREAM:
277             if(sk->outbuf.s.buf != NULL)
278                 free(sk->outbuf.s.buf);
279             if(sk->inbuf.s.buf != NULL)
280                 free(sk->inbuf.s.buf);
281             break;
282         case SOCK_DGRAM:
283             while((buf = sk->outbuf.d.f) != NULL)
284             {
285                 sk->outbuf.d.f = buf->next;
286                 free(buf->data);
287                 free(buf->addr);
288                 free(buf);
289             }
290             while((buf = sk->inbuf.d.f) != NULL)
291             {
292                 sk->inbuf.d.f = buf->next;
293                 free(buf->data);
294                 free(buf->addr);
295                 free(buf);
296             }
297             break;
298         }
299         closesock(sk);
300         if(sk->remote != NULL)
301             free(sk->remote);
302         free(sk);
303     }
304 }
305
306 void sockpushdata(struct socket *sk, void *buf, size_t size)
307 {
308     switch(sk->type)
309     {
310     case SOCK_STREAM:
311         sizebuf(&sk->inbuf.s.buf, &sk->inbuf.s.bufsize, sk->inbuf.s.datasize + size, 1, 1);
312         memmove(sk->inbuf.s.buf + size, sk->inbuf.s.buf, sk->inbuf.s.datasize);
313         memcpy(sk->inbuf.s.buf, buf, size);
314         sk->inbuf.s.datasize += size;
315         break;
316     case SOCK_DGRAM:
317         /* XXX */
318         break;
319     }
320     return;
321 }
322
323 void *sockgetinbuf(struct socket *sk, size_t *size)
324 {
325     void *buf;
326     struct dgrambuf *dbuf;
327     
328     switch(sk->type)
329     {
330     case SOCK_STREAM:
331         if((sk->inbuf.s.buf == NULL) || (sk->inbuf.s.datasize == 0))
332         {
333             *size = 0;
334             return(NULL);
335         }
336         buf = sk->inbuf.s.buf;
337         *size = sk->inbuf.s.datasize;
338         sk->inbuf.s.buf = NULL;
339         sk->inbuf.s.bufsize = sk->inbuf.s.datasize = 0;
340         return(buf);
341     case SOCK_DGRAM:
342         if((dbuf = sk->inbuf.d.f) == NULL)
343             return(NULL);
344         sk->inbuf.d.f = dbuf->next;
345         if(dbuf->next == NULL)
346             sk->inbuf.d.l = NULL;
347         buf = dbuf->data;
348         *size = dbuf->size;
349         free(dbuf->addr);
350         free(dbuf);
351         return(buf);
352     }
353     return(NULL);
354 }
355
356 static void recvcmsg(struct socket *sk, struct msghdr *msg)
357 {
358     struct cmsghdr *cmsg;
359     
360     for(cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg))
361     {
362 #if UNIX_AUTH_STYLE == 1
363         if((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SCM_CREDENTIALS))
364         {
365             struct ucred *cred;
366             if(sk->ucred.uid == -1)
367             {
368                 cred = (struct ucred *)CMSG_DATA(cmsg);
369                 sk->ucred.uid = cred->uid;
370                 sk->ucred.gid = cred->gid;
371             }
372         }
373 #endif
374     }
375 }
376
377 static void sockrecv(struct socket *sk)
378 {
379     int ret, inq;
380     struct dgrambuf *dbuf;
381     struct msghdr msg;
382     char cbuf[65536];
383     struct iovec bufvec;
384     
385     memset(&msg, 0, sizeof(msg));
386     msg.msg_iov = &bufvec;
387     msg.msg_iovlen = 1;
388     msg.msg_control = cbuf;
389     msg.msg_controllen = sizeof(cbuf);
390     switch(sk->type)
391     {
392     case SOCK_STREAM:
393 #if defined(HAVE_LINUX_SOCKIOS_H) && defined(SIOCINQ)
394         /* SIOCINQ is Linux-specific AFAIK, but I really have no idea
395          * how to read the inqueue size on other OSs */
396         if(sk->isrealsocket) {
397             if(ioctl(sk->fd, SIOCINQ, &inq))
398             {
399                 /* I don't really know what could go wrong here, so let's
400                  * assume it's transient. */
401                 flog(LOG_WARNING, "SIOCINQ return %s on socket %i, falling back to 2048 bytes", strerror(errno), sk->fd);
402                 inq = 2048;
403             }
404         } else {
405             /* There are perils when trying to use SIOCINQ on files >2GiB... */
406             inq = 65536;
407         }
408 #else
409         inq = 2048;
410 #endif
411         if(inq > 65536)
412             inq = 65536;
413         sizebuf(&sk->inbuf.s.buf, &sk->inbuf.s.bufsize, sk->inbuf.s.datasize + inq, 1, 1);
414         if(sk->isrealsocket)
415         {
416             bufvec.iov_base = sk->inbuf.s.buf + sk->inbuf.s.datasize;
417             bufvec.iov_len = inq;
418             ret = recvmsg(sk->fd, &msg, 0);
419         } else {
420             ret = read(sk->fd, sk->inbuf.s.buf + sk->inbuf.s.datasize, inq);
421             msg.msg_controllen = 0;
422             msg.msg_flags = 0;
423         }
424         if(ret < 0)
425         {
426             if((errno == EINTR) || (errno == EAGAIN))
427                 return;
428             if(sk->errcb != NULL)
429                 sk->errcb(sk, errno, sk->data);
430             closesock(sk);
431             return;
432         }
433         if(msg.msg_flags & MSG_CTRUNC)
434             flog(LOG_DEBUG, "ancillary data was truncated");
435         else
436             recvcmsg(sk, &msg);
437         if(ret == 0)
438         {
439             if(sk->errcb != NULL)
440                 sk->errcb(sk, 0, sk->data);
441             closesock(sk);
442             return;
443         }
444         sk->inbuf.s.datasize += ret;
445         if(sk->readcb != NULL)
446             sk->readcb(sk, sk->data);
447         break;
448     case SOCK_DGRAM:
449 #if defined(HAVE_LINUX_SOCKIOS_H) && defined(SIOCINQ)
450         if(ioctl(sk->fd, SIOCINQ, &inq))
451         {
452             /* I don't really know what could go wrong here, so let's
453              * assume it's transient. */
454             flog(LOG_WARNING, "SIOCINQ return %s on socket %i", strerror(errno), sk->fd);
455             return;
456         }
457 #else
458         inq = 65536;
459 #endif
460         dbuf = smalloc(sizeof(*dbuf));
461         dbuf->data = smalloc(inq);
462         dbuf->addr = smalloc(dbuf->addrlen = sizeof(struct sockaddr_storage));
463         /*
464         ret = recvfrom(sk->fd, dbuf->data, inq, 0, dbuf->addr, &dbuf->addrlen);
465         */
466         msg.msg_name = dbuf->addr;
467         msg.msg_namelen = dbuf->addrlen;
468         bufvec.iov_base = dbuf->data;
469         bufvec.iov_len = inq;
470         ret = recvmsg(sk->fd, &msg, 0);
471         dbuf->addrlen = msg.msg_namelen;
472         if(ret < 0)
473         {
474             free(dbuf->addr);
475             free(dbuf->data);
476             free(dbuf);
477             if((errno == EINTR) || (errno == EAGAIN))
478                 return;
479             if(sk->errcb != NULL)
480                 sk->errcb(sk, errno, sk->data);
481             closesock(sk);
482             return;
483         }
484         if(msg.msg_flags & MSG_CTRUNC)
485             flog(LOG_DEBUG, "ancillary data was truncated");
486         else
487             recvcmsg(sk, &msg);
488         /* On UDP/IPv[46], ret == 0 doesn't mean EOF (since UDP can't
489          * have EOF), but rather an empty packet. I don't know if any
490          * other potential DGRAM protocols might have an EOF
491          * condition, so let's play safe. */
492         if(ret == 0)
493         {
494             free(dbuf->addr);
495             free(dbuf->data);
496             free(dbuf);
497             if(!((sk->family == AF_INET) || (sk->family == AF_INET6)))
498             {
499                 if(sk->errcb != NULL)
500                     sk->errcb(sk, 0, sk->data);
501                 closesock(sk);
502             }
503             return;
504         }
505         dbuf->addr = srealloc(dbuf->addr, dbuf->addrlen);
506         dbuf->data = srealloc(dbuf->data, dbuf->size = ret);
507         dbuf->next = NULL;
508         if(sk->inbuf.d.l != NULL)
509             sk->inbuf.d.l->next = dbuf;
510         else
511             sk->inbuf.d.f = dbuf;
512         sk->inbuf.d.l = dbuf;
513         if(sk->readcb != NULL)
514             sk->readcb(sk, sk->data);
515         break;
516     }
517 }
518
519 static void sockflush(struct socket *sk)
520 {
521     int ret;
522     struct dgrambuf *dbuf;
523     
524     switch(sk->type)
525     {
526     case SOCK_STREAM:
527         if(sk->isrealsocket)
528             ret = send(sk->fd, sk->outbuf.s.buf, sk->outbuf.s.datasize, MSG_DONTWAIT | MSG_NOSIGNAL);
529         else
530             ret = write(sk->fd, sk->outbuf.s.buf, sk->outbuf.s.datasize);
531         if(ret < 0)
532         {
533             if((errno != EINTR) && (errno != EAGAIN))
534             {
535                 if(sk->errcb != NULL)
536                     sk->errcb(sk, errno, sk->data);
537                 closesock(sk);
538             }
539             break;
540         }
541         if(ret > 0)
542         {
543             memmove(sk->outbuf.s.buf, ((char *)sk->outbuf.s.buf) + ret, sk->outbuf.s.datasize -= ret);
544             if(sk->writecb != NULL)
545                 sk->writecb(sk, sk->data);
546         }
547         break;
548     case SOCK_DGRAM:
549         dbuf = sk->outbuf.d.f;
550         if((sk->outbuf.d.f = dbuf->next) == NULL)
551             sk->outbuf.d.l = NULL;
552         sendto(sk->fd, dbuf->data, dbuf->size, MSG_DONTWAIT | MSG_NOSIGNAL, dbuf->addr, dbuf->addrlen);
553         free(dbuf->data);
554         free(dbuf->addr);
555         free(dbuf);
556         if(sk->writecb != NULL)
557             sk->writecb(sk, sk->data);
558         break;
559     }
560 }
561
562 void closesock(struct socket *sk)
563 {
564     struct sockaddr_un *un;
565     
566     if((sk->family == AF_UNIX) && !sockgetlocalname(sk, (struct sockaddr **)(void *)&un, NULL) && (un->sun_family == PF_UNIX))
567     {
568         if((sk->state == SOCK_LST) && strchr(un->sun_path, '/'))
569         {
570             if(unlink(un->sun_path))
571                 flog(LOG_WARNING, "could not unlink Unix socket %s: %s", un->sun_path, strerror(errno));
572         }
573     }
574     sk->state = SOCK_STL;
575     close(sk->fd);
576     sk->fd = -1;
577     sk->close = 0;
578 }
579
580 void sockqueue(struct socket *sk, void *data, size_t size)
581 {
582     struct dgrambuf *new;
583     
584     if(sk->state == SOCK_STL)
585         return;
586     switch(sk->type)
587     {
588     case SOCK_STREAM:
589         sizebuf(&(sk->outbuf.s.buf), &(sk->outbuf.s.bufsize), sk->outbuf.s.datasize + size, 1, 1);
590         memcpy(sk->outbuf.s.buf + sk->outbuf.s.datasize, data, size);
591         sk->outbuf.s.datasize += size;
592         break;
593     case SOCK_DGRAM:
594         if(sk->remote == NULL)
595             return;
596         new = smalloc(sizeof(*new));
597         new->next = NULL;
598         memcpy(new->data = smalloc(size), data, new->size = size);
599         memcpy(new->addr = smalloc(sk->remotelen), sk->remote, new->addrlen = sk->remotelen);
600         if(sk->outbuf.d.l == NULL)
601         {
602             sk->outbuf.d.l = sk->outbuf.d.f = new;
603         } else {
604             sk->outbuf.d.l->next = new;
605             sk->outbuf.d.l = new;
606         }
607         break;
608     }
609 }
610
611 size_t sockgetdatalen(struct socket *sk)
612 {
613     struct dgrambuf *b;
614     size_t ret;
615     
616     switch(sk->type)
617     {
618     case SOCK_STREAM:
619         ret = sk->inbuf.s.datasize;
620         break;
621     case SOCK_DGRAM:
622         ret = 0;
623         for(b = sk->inbuf.d.f; b != NULL; b = b->next)
624             ret += b->size;
625         break;
626     }
627     return(ret);
628 }
629
630 size_t sockqueuesize(struct socket *sk)
631 {
632     struct dgrambuf *b;
633     size_t ret;
634     
635     switch(sk->type)
636     {
637     case SOCK_STREAM:
638         ret = sk->outbuf.s.datasize;
639         break;
640     case SOCK_DGRAM:
641         ret = 0;
642         for(b = sk->outbuf.d.f; b != NULL; b = b->next)
643             ret += b->size;
644         break;
645     }
646     return(ret);
647 }
648
649 /*
650  * Seriously, I don't know if it's naughty or not to remove
651  * pre-existing Unix sockets.
652  */
653 static int rebindunix(struct socket *sk, struct sockaddr *name, socklen_t namelen)
654 {
655     struct sockaddr_un *un;
656     struct stat sb;
657     
658     if((sk->family != AF_UNIX) || (name->sa_family != PF_UNIX))
659         return(-1);
660     un = (struct sockaddr_un *)name;
661     if(stat(un->sun_path, &sb))
662         return(-1);
663     if(!S_ISSOCK(sb.st_mode))
664         return(-1);
665     if(unlink(un->sun_path))
666         return(-1);
667     if(bind(sk->fd, name, namelen) < 0)
668         return(-1);
669     return(0);
670 }
671
672 /*
673  * The difference between netcslisten() and netcslistenlocal() is that
674  * netcslistenlocal() always listens on the local host, instead of
675  * following proxy/passive mode directions. It is suitable for eg. the
676  * UI channel, while the file sharing networks should, naturally, use
677  * netcslisten() instead.
678 */
679
680 struct socket *netcslistenlocal(int type, struct sockaddr *name, socklen_t namelen, void (*func)(struct socket *, struct socket *, void *), void *data)
681 {
682     struct socket *sk;
683     int intbuf;
684     
685     /* I don't know if this is actually correct (it probably isn't),
686      * but since, at on least Linux systems, PF_* are specifically
687      * #define'd to their AF_* counterparts, it allows for a severely
688      * smoother implementation. If it breaks something on your
689      * platform, please tell me so.
690      */
691     if((sk = mksock(name->sa_family, type)) == NULL)
692         return(NULL);
693     sk->state = SOCK_LST;
694     if(confgetint("net", "reuseaddr"))
695     {
696         intbuf = 1;
697         setsockopt(sk->fd, SOL_SOCKET, SO_REUSEADDR, &intbuf, sizeof(intbuf));
698     }
699     if((bind(sk->fd, name, namelen) < 0) && ((errno != EADDRINUSE) || (rebindunix(sk, name, namelen) < 0)))
700     {
701         putsock(sk);
702         return(NULL);
703     }
704     if(listen(sk->fd, 16) < 0)
705     {
706         putsock(sk);
707         return(NULL);
708     }
709     sk->acceptcb = func;
710     sk->data = data;
711     return(sk);
712 }
713
714 struct socket *netcslisten(int type, struct sockaddr *name, socklen_t namelen, void (*func)(struct socket *, struct socket *, void *), void *data)
715 {
716     if(confgetint("net", "mode") == 1)
717     {
718         errno = EOPNOTSUPP;
719         return(NULL);
720     }
721     if(confgetint("net", "mode") == 0)
722         return(netcslistenlocal(type, name, namelen, func, data));
723     errno = EOPNOTSUPP;
724     return(NULL);
725 }
726
727 struct socket *netcstcplisten(int port, int local, void (*func)(struct socket *, struct socket *, void *), void *data)
728 {
729     struct sockaddr_in addr;
730 #ifdef HAVE_IPV6
731     struct sockaddr_in6 addr6;
732 #endif
733     struct socket *(*csfunc)(int, struct sockaddr *, socklen_t, void (*)(struct socket *, struct socket *, void *), void *);
734     struct socket *ret;
735     
736     if(local)
737         csfunc = netcslistenlocal;
738     else
739         csfunc = netcslisten;
740 #ifdef HAVE_IPV6
741     memset(&addr6, 0, sizeof(addr6));
742     addr6.sin6_family = AF_INET6;
743     addr6.sin6_port = htons(port);
744     addr6.sin6_addr = in6addr_any;
745     if((ret = csfunc(SOCK_STREAM, (struct sockaddr *)&addr6, sizeof(addr6), func, data)) != NULL)
746         return(ret);
747     if((ret == NULL) && (errno != EAFNOSUPPORT))
748         return(NULL);
749 #endif
750     memset(&addr, 0, sizeof(addr));
751     addr.sin_family = AF_INET;
752     addr.sin_port = htons(port);
753     return(csfunc(SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr), func, data));
754 }
755
756 struct socket *netcsdgram(struct sockaddr *name, socklen_t namelen)
757 {
758     struct socket *sk;
759     int mode;
760     
761     mode = confgetint("net", "mode");
762     if((mode == 0) || (mode == 1))
763     {
764         if((sk = mksock(name->sa_family, SOCK_DGRAM)) == NULL)
765             return(NULL);
766         if(bind(sk->fd, name, namelen) < 0)
767         {
768             putsock(sk);
769             return(NULL);
770         }
771         sk->state = SOCK_EST;
772         return(sk);
773     }
774     errno = EOPNOTSUPP;
775     return(NULL);
776 }
777
778 struct socket *netdupsock(struct socket *sk)
779 {
780     struct socket *newsk;
781     
782     newsk = newsock(sk->type);
783     if((newsk->fd = dup(sk->fd)) < 0)
784     {
785         flog(LOG_WARNING, "could not dup() socket: %s", strerror(errno));
786         putsock(newsk);
787         return(NULL);
788     }
789     newsk->state = sk->state;
790     newsk->ignread = sk->ignread;
791     if(sk->remote != NULL)
792         memcpy(newsk->remote = smalloc(sk->remotelen), sk->remote, newsk->remotelen = sk->remotelen);
793     return(newsk);
794 }
795
796 void netdgramconn(struct socket *sk, struct sockaddr *addr, socklen_t addrlen)
797 {
798     if(sk->remote != NULL)
799         free(sk->remote);
800     memcpy(sk->remote = smalloc(addrlen), addr, sk->remotelen = addrlen);
801     sk->ignread = 1;
802 }
803
804 struct socket *netcsconn(struct sockaddr *addr, socklen_t addrlen, void (*func)(struct socket *, int, void *), void *data)
805 {
806     struct socket *sk;
807     int mode;
808     
809     mode = confgetint("net", "mode");
810     if((mode == 0) || (mode == 1))
811     {
812         if((sk = mksock(addr->sa_family, SOCK_STREAM)) == NULL)
813             return(NULL);
814         memcpy(sk->remote = smalloc(addrlen), addr, sk->remotelen = addrlen);
815         if(!connect(sk->fd, addr, addrlen))
816         {
817             sk->state = SOCK_EST;
818             func(sk, 0, data);
819             return(sk);
820         }
821         if(errno == EINPROGRESS)
822         {
823             sk->state = SOCK_SYN;
824             sk->conncb = func;
825             sk->data = data;
826             return(sk);
827         }
828         putsock(sk);
829         return(NULL);
830     }
831     errno = EOPNOTSUPP;
832     return(NULL);
833 }
834
835 static void acceptunix(struct socket *sk)
836 {
837     int buf;
838     
839     buf = 1;
840 #if UNIX_AUTH_STYLE == 1
841     if(setsockopt(sk->fd, SOL_SOCKET, SO_PASSCRED, &buf, sizeof(buf)) < 0)
842         flog(LOG_WARNING, "could not enable SO_PASSCRED on Unix socket %i: %s", sk->fd, strerror(errno));
843 #elif UNIX_AUTH_STYLE == 2
844     if(getpeereid(sk->fd, &sk->ucred.uid, &sk->ucred.gid) < 0)
845     {
846         flog(LOG_WARNING, "could not get peer creds on Unix socket %i: %s", sk->fd, strerror(errno));
847         sk->ucred.uid = -1;
848         sk->ucred.gid = -1;
849     }
850 #endif
851 }
852
853 int pollsocks(int timeout)
854 {
855     int ret, fd;
856     socklen_t retlen;
857     int newfd, maxfd;
858     fd_set rfds, wfds, efds;
859     struct socket *sk, *next, *newsk;
860     struct sockaddr_storage ss;
861     socklen_t sslen;
862     struct timeval tv;
863     
864     FD_ZERO(&rfds);
865     FD_ZERO(&wfds);
866     FD_ZERO(&efds);
867     for(maxfd = 0, sk = sockets; sk != NULL; sk = sk->next)
868     {
869         if((sk->state == SOCK_STL) || (sk->fd < 0))
870             continue;
871         if(!sk->ignread)
872             FD_SET(sk->fd, &rfds);
873         if((sk->state == SOCK_SYN) || (sockqueuesize(sk) > 0))
874             FD_SET(sk->fd, &wfds);
875         FD_SET(sk->fd, &efds);
876         if(sk->fd > maxfd)
877             maxfd = sk->fd;
878     }
879     tv.tv_sec = timeout / 1000;
880     tv.tv_usec = (timeout % 1000) * 1000;
881     ret = select(maxfd + 1, &rfds, &wfds, &efds, (timeout < 0)?NULL:&tv);
882     if(ret < 0)
883     {
884         if(errno != EINTR)
885         {
886             flog(LOG_CRIT, "pollsocks: select errored out: %s", strerror(errno));
887             /* To avoid CPU hogging in case it's bad, which it
888              * probably is. */
889             sleep(1);
890         }
891         return(1);
892     }
893     for(sk = sockets; sk != NULL; sk = next)
894     {
895         next = sk->next;
896         fd = sk->fd;
897         switch(sk->state)
898         {
899         case SOCK_LST:
900             if(FD_ISSET(fd, &rfds))
901             {
902                 sslen = sizeof(ss);
903                 if((newfd = accept(fd, (struct sockaddr *)&ss, &sslen)) < 0)
904                 {
905                     if(sk->errcb != NULL)
906                         sk->errcb(sk, errno, sk->data);
907                 }
908                 newsk = newsock(sk->type);
909                 newsk->fd = newfd;
910                 newsk->family = sk->family;
911                 newsk->state = SOCK_EST;
912                 memcpy(newsk->remote = smalloc(sslen), &ss, sslen);
913                 newsk->remotelen = sslen;
914                 if(ss.ss_family == PF_UNIX)
915                     acceptunix(newsk);
916                 if(sk->acceptcb != NULL)
917                     sk->acceptcb(sk, newsk, sk->data);
918                 putsock(newsk);
919             }
920             if(FD_ISSET(fd, &efds))
921             {
922                 retlen = sizeof(ret);
923                 getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &retlen);
924                 if(sk->errcb != NULL)
925                     sk->errcb(sk, ret, sk->data);
926                 continue;
927             }
928             break;
929         case SOCK_SYN:
930             if(FD_ISSET(fd, &efds))
931             {
932                 retlen = sizeof(ret);
933                 getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &retlen);
934                 if(sk->conncb != NULL)
935                     sk->conncb(sk, ret, sk->data);
936                 closesock(sk);
937                 continue;
938             }
939             if(FD_ISSET(fd, &rfds) || FD_ISSET(fd, &wfds))
940             {
941                 sk->state = SOCK_EST;
942                 if(sk->conncb != NULL)
943                     sk->conncb(sk, 0, sk->data);
944             }
945             break;
946         case SOCK_EST:
947             if(FD_ISSET(fd, &efds))
948             {
949                 retlen = sizeof(ret);
950                 getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &retlen);
951                 if(sk->errcb != NULL)
952                     sk->errcb(sk, ret, sk->data);
953                 closesock(sk);
954                 continue;
955             }
956             if(FD_ISSET(fd, &rfds))
957                 sockrecv(sk);
958             if(FD_ISSET(fd, &wfds))
959             {
960                 if(sockqueuesize(sk) > 0)
961                     sockflush(sk);
962             }
963             break;
964         }
965     }
966     for(sk = sockets; sk != NULL; sk = next)
967     {
968         next = sk->next;
969         if(sk->refcount == 1 && (sockqueuesize(sk) == 0))
970         {
971             unlinksock(sk);
972             continue;
973         }
974         if(sk->close && (sockqueuesize(sk) == 0))
975             closesock(sk);
976         if(sk->state == SOCK_STL)
977         {
978             unlinksock(sk);
979             continue;
980         }
981     }
982     return(1);
983 }
984
985 int socksettos(struct socket *sk, int tos)
986 {
987     int buf;
988     int dscp2tos;
989     
990     if(sk->family == AF_UNIX)
991         return(0); /* Unix sockets are always perfect. :) */
992     if(sk->family == AF_INET)
993     {
994         dscp2tos = confgetint("net", "dscp-tos");
995         switch(tos)
996         {
997         case 0:
998             buf = 0;
999             break;
1000         case SOCK_TOS_MINCOST:
1001             if(dscp2tos)
1002                 buf = confgetint("net", "diffserv-mincost") << 2;
1003             else
1004                 buf = 0x02;
1005             break;
1006         case SOCK_TOS_MAXREL:
1007             if(dscp2tos)
1008                 buf = confgetint("net", "diffserv-maxrel") << 2;
1009             else
1010                 buf = 0x04;
1011             break;
1012         case SOCK_TOS_MAXTP:
1013             if(dscp2tos)
1014                 buf = confgetint("net", "diffserv-maxtp") << 2;
1015             else
1016                 buf = 0x08;
1017             break;
1018         case SOCK_TOS_MINDELAY:
1019             if(dscp2tos)
1020                 buf = confgetint("net", "diffserv-mindelay") << 2;
1021             else
1022                 buf = 0x10;
1023             break;
1024         default:
1025             flog(LOG_WARNING, "attempted to set unknown TOS value %i to IPv4 sock", tos);
1026             return(-1);
1027         }
1028         if(setsockopt(sk->fd, IPPROTO_IP, IP_TOS, &buf, sizeof(buf)) < 0)
1029         {
1030             flog(LOG_WARNING, "could not set sock TOS to %i: %s", tos, strerror(errno));
1031             return(-1);
1032         }
1033         return(0);
1034     }
1035     if(sk->family == AF_INET6)
1036     {
1037         switch(tos)
1038         {
1039         case 0:
1040             buf = 0;
1041         case SOCK_TOS_MINCOST:
1042             buf = confgetint("net", "diffserv-mincost");
1043             break;
1044         case SOCK_TOS_MAXREL:
1045             buf = confgetint("net", "diffserv-maxrel");
1046             break;
1047         case SOCK_TOS_MAXTP:
1048             buf = confgetint("net", "diffserv-maxtp");
1049             break;
1050         case SOCK_TOS_MINDELAY:
1051             buf = confgetint("net", "diffserv-mindelay");
1052             break;
1053         default:
1054             flog(LOG_WARNING, "attempted to set unknown TOS value %i to IPv4 sock", tos);
1055             return(-1);
1056         }
1057         /*
1058           On Linux, the API IPv6 flow label management doesn't seem to
1059           be entirely complete, so I guess this will have to wait.
1060           
1061         if(setsockopt(...) < 0)
1062         {
1063             flog(LOG_WARNING, "could not set sock traffic class to %i: %s", tos, strerror(errno));
1064             return(-1);
1065         }
1066         */
1067         return(0);
1068     }
1069     flog(LOG_WARNING, "could not set TOS on sock of family %i", sk->family);
1070     return(1);
1071 }
1072
1073 struct resolvedata
1074 {
1075     int fd;
1076     void (*callback)(struct sockaddr *addr, int addrlen, void *data);
1077     void *data;
1078     struct sockaddr_storage addr;
1079     int addrlen;
1080 };
1081
1082 static void resolvecb(pid_t pid, int status, struct resolvedata *data)
1083 {
1084     static char buf[80];
1085     int ret;
1086     struct sockaddr_in *ipv4;
1087     
1088     if(!status)
1089     {
1090         if((ret = read(data->fd, buf, sizeof(buf))) != 4)
1091         {
1092             errno = ENOENT;
1093             data->callback(NULL, 0, data->data);
1094         } else {
1095             ipv4 = (struct sockaddr_in *)&data->addr;
1096             memcpy(&ipv4->sin_addr, buf, 4);
1097             data->callback((struct sockaddr *)ipv4, sizeof(*ipv4), data->data);
1098         }
1099     } else {
1100         errno = ENOENT;
1101         data->callback(NULL, 0, data->data);
1102     }
1103     close(data->fd);
1104     free(data);
1105 }
1106
1107 int netresolve(char *addr, void (*callback)(struct sockaddr *addr, int addrlen, void *data), void *data)
1108 {
1109     int i;
1110     char *p;
1111     int port;
1112     int pfd[2];
1113     pid_t child;
1114     struct resolvedata *rdata;
1115     struct sockaddr_in ipv4;
1116     struct hostent *he;
1117     sigset_t sigset;
1118     
1119     /* IPv4 */
1120     port = -1;
1121     if((p = strchr(addr, ':')) != NULL)
1122     {
1123         *p = 0;
1124         port = atoi(p + 1);
1125     }
1126     ipv4.sin_family = AF_INET;
1127     ipv4.sin_port = htons(port);
1128     if(inet_aton(addr, &ipv4.sin_addr))
1129     {
1130         callback((struct sockaddr *)&ipv4, sizeof(ipv4), data);
1131     } else {
1132         sigemptyset(&sigset);
1133         sigaddset(&sigset, SIGCHLD);
1134         sigprocmask(SIG_BLOCK, &sigset, NULL);
1135         if((pipe(pfd) < 0) || ((child = fork()) < 0))
1136         {
1137             sigprocmask(SIG_UNBLOCK, &sigset, NULL);
1138             return(-1);
1139         }
1140         if(child == 0)
1141         {
1142             sigprocmask(SIG_UNBLOCK, &sigset, NULL);
1143             for(i = 3; i < FD_SETSIZE; i++)
1144             {
1145                 if(i != pfd[1])
1146                     close(i);
1147             }
1148             signal(SIGALRM, SIG_DFL);
1149             alarm(30);
1150             if((he = gethostbyname(addr)) == NULL)
1151                 exit(1);
1152             write(pfd[1], he->h_addr_list[0], 4);
1153             exit(0);
1154         } else {
1155             close(pfd[1]);
1156             fcntl(pfd[0], F_SETFL, fcntl(pfd[0], F_GETFL) | O_NONBLOCK);
1157             rdata = smalloc(sizeof(*rdata));
1158             rdata->fd = pfd[0];
1159             rdata->callback = callback;
1160             rdata->data = data;
1161             memcpy(&rdata->addr, &ipv4, rdata->addrlen = sizeof(ipv4));
1162             childcallback(child, (void (*)(pid_t, int, void *))resolvecb, rdata);
1163             sigprocmask(SIG_UNBLOCK, &sigset, NULL);
1164             return(1);
1165         }
1166     }
1167     return(0);
1168 }
1169
1170 int sockgetlocalname(struct socket *sk, struct sockaddr **namebuf, socklen_t *lenbuf)
1171 {
1172     socklen_t len;
1173     struct sockaddr_storage name;
1174     
1175     *namebuf = NULL;
1176     if((sk->state == SOCK_STL) || (sk->fd < 0))
1177         return(-1);
1178     len = sizeof(name);
1179     if(getsockname(sk->fd, (struct sockaddr *)&name, &len) < 0)
1180     {
1181         flog(LOG_ERR, "BUG: alive socket with dead fd in sockgetlocalname (%s)", strerror(errno));
1182         return(-1);
1183     }
1184     *namebuf = memcpy(smalloc(len), &name, len);
1185     if(lenbuf != NULL)
1186         *lenbuf = len;
1187     return(0);
1188 }
1189
1190 static void sethostaddr(struct sockaddr *dst, struct sockaddr *src)
1191 {
1192     if(dst->sa_family != src->sa_family)
1193     {
1194         flog(LOG_ERR, "BUG: non-matching socket families in sethostaddr (%i -> %i)", src->sa_family, dst->sa_family);
1195         return;
1196     }
1197     switch(src->sa_family)
1198     {
1199     case AF_INET:
1200         ((struct sockaddr_in *)dst)->sin_addr = ((struct sockaddr_in *)src)->sin_addr;
1201         break;
1202     case AF_INET6:
1203         ((struct sockaddr_in6 *)dst)->sin6_addr = ((struct sockaddr_in6 *)src)->sin6_addr;
1204         break;
1205     default:
1206         flog(LOG_WARNING, "sethostaddr unimplemented for family %i", src->sa_family);
1207         break;
1208     }
1209 }
1210
1211 static int makepublic(struct sockaddr *addr)
1212 {
1213     int ret;
1214     socklen_t plen;
1215     struct sockaddr *pname;
1216     
1217     if((ret = getpublicaddr(addr->sa_family, &pname, &plen)) < 0)
1218     {
1219         flog(LOG_ERR, "could not get public address: %s", strerror(errno));
1220         return(-1);
1221     }
1222     if(ret)
1223         return(0);
1224     sethostaddr(addr, pname);
1225     free(pname);
1226     return(0);
1227 }
1228
1229 int sockgetremotename(struct socket *sk, struct sockaddr **namebuf, socklen_t *lenbuf)
1230 {
1231     socklen_t len;
1232     struct sockaddr *name;
1233     
1234     switch(confgetint("net", "mode"))
1235     {
1236     case 0:
1237         *namebuf = NULL;
1238         if((sk->state == SOCK_STL) || (sk->fd < 0))
1239         {
1240             errno = EBADF;
1241             return(-1);
1242         }
1243         if(!sockgetlocalname(sk, &name, &len))
1244         {
1245             *namebuf = name;
1246             *lenbuf = len;
1247             makepublic(name);
1248             return(0);
1249         }
1250         flog(LOG_ERR, "could not get remotely accessible name by any means");
1251         return(-1);
1252     case 1:
1253         errno = EOPNOTSUPP;
1254         return(-1);
1255     default:
1256         flog(LOG_CRIT, "unknown net mode %i active", confgetint("net", "mode"));
1257         errno = EOPNOTSUPP;
1258         return(-1);
1259     }
1260 }
1261
1262 int sockgetremotename2(struct socket *sk, struct socket *sk2, struct sockaddr **namebuf, socklen_t *lenbuf)
1263 {
1264     struct sockaddr *name1, *name2;
1265     socklen_t len1, len2;
1266     
1267     if(sk->family != sk2->family)
1268     {
1269         flog(LOG_ERR, "using sockgetremotename2 with sockets of differing family: %i %i", sk->family, sk2->family);
1270         return(-1);
1271     }
1272     if(sockgetremotename(sk, &name1, &len1))
1273         return(-1);
1274     if(sockgetremotename(sk2, &name2, &len2)) {
1275         free(name1);
1276         return(-1);
1277     }
1278     sethostaddr(name1, name2);
1279     free(name2);
1280     *namebuf = name1;
1281     *lenbuf = len1;
1282     return(0);
1283 }
1284
1285 int addreq(struct sockaddr *x, struct sockaddr *y)
1286 {
1287     struct sockaddr_un *u1, *u2;
1288     struct sockaddr_in *n1, *n2;
1289 #ifdef HAVE_IPV6
1290     struct sockaddr_in6 *s1, *s2;
1291 #endif
1292     
1293     if(x->sa_family != y->sa_family)
1294         return(0);
1295     switch(x->sa_family) {
1296     case AF_UNIX:
1297         u1 = (struct sockaddr_un *)x; u2 = (struct sockaddr_un *)y;
1298         if(strncmp(u1->sun_path, u2->sun_path, sizeof(u1->sun_path)))
1299             return(0);
1300         break;
1301     case AF_INET:
1302         n1 = (struct sockaddr_in *)x; n2 = (struct sockaddr_in *)y;
1303         if(n1->sin_port != n2->sin_port)
1304             return(0);
1305         if(n1->sin_addr.s_addr != n2->sin_addr.s_addr)
1306             return(0);
1307         break;
1308 #ifdef HAVE_IPV6
1309     case AF_INET6:
1310         s1 = (struct sockaddr_in6 *)x; s2 = (struct sockaddr_in6 *)y;
1311         if(s1->sin6_port != s2->sin6_port)
1312             return(0);
1313         if(memcmp(s1->sin6_addr.s6_addr, s2->sin6_addr.s6_addr, sizeof(s1->sin6_addr.s6_addr)))
1314             return(0);
1315         break;
1316 #endif
1317     }
1318     return(1);
1319 }
1320
1321 char *formataddress(struct sockaddr *arg, socklen_t arglen)
1322 {
1323     struct sockaddr_in *ipv4;
1324 #ifdef HAVE_IPV6
1325     struct sockaddr_in6 *ipv6;
1326 #endif
1327     static char *ret = NULL;
1328     char buf[1024];
1329     
1330     if(ret != NULL)
1331         free(ret);
1332     ret = NULL;
1333     switch(arg->sa_family)
1334     {
1335     case AF_UNIX:
1336         ret = sstrdup("Unix socket");
1337         break;
1338     case AF_INET:
1339         ipv4 = (struct sockaddr_in *)arg;
1340         if(inet_ntop(AF_INET, &ipv4->sin_addr, buf, sizeof(buf)) == NULL)
1341             return(NULL);
1342         ret = sprintf2("%s:%i", buf, (int)ntohs(ipv4->sin_port));
1343         break;
1344 #ifdef HAVE_IPV6
1345     case AF_INET6:
1346         ipv6 = (struct sockaddr_in6 *)arg;
1347         if(inet_ntop(AF_INET6, &ipv6->sin6_addr, buf, sizeof(buf)) == NULL)
1348             return(NULL);
1349         ret = sprintf2("[%s]:%i", buf, (int)ntohs(ipv6->sin6_port));
1350         break;
1351 #endif
1352     default:
1353         errno = EPFNOSUPPORT;
1354         break;
1355     }
1356     return(ret);
1357 }
1358
1359 #if 0
1360
1361 /* 
1362  * It was very nice to use this, but it seems
1363  * to mess things up, so I guess it has to go... :-(
1364  */
1365
1366 static int formataddress(FILE *stream, const struct printf_info *info, const void *const *args)
1367 {
1368     struct sockaddr *arg;
1369     socklen_t arglen;
1370     struct sockaddr_un *UNIX; /* Some wise guy has #defined unix with
1371                                * lowercase letters to 1, so I do this
1372                                * instead. */
1373     struct sockaddr_in *ipv4;
1374     int ret;
1375     
1376     arg = *(struct sockaddr **)(args[0]);
1377     arglen = *(socklen_t *)(args[1]);
1378     switch(arg->sa_family)
1379     {
1380     case AF_UNIX:
1381         UNIX = (struct sockaddr_un *)arg;
1382         ret = fprintf(stream, "%s", UNIX->sun_path);
1383         break;
1384     case AF_INET:
1385         ipv4 = (struct sockaddr_in *)arg;
1386         ret = fprintf(stream, "%s:%i", inet_ntoa(ipv4->sin_addr), (int)ntohs(ipv4->sin_port));
1387         break;
1388     default:
1389         ret = -1;
1390         errno = EPFNOSUPPORT;
1391         break;
1392     }
1393     return(ret);
1394 }
1395
1396 static int formataddress_arginfo(const struct printf_info *info, size_t n, int *argtypes)
1397 {
1398     if(n > 0)
1399         argtypes[0] = PA_POINTER;
1400     if(n > 1)
1401         argtypes[1] = PA_INT; /* Sources tell me that socklen_t _must_
1402                                * be an int, so I guess this should be
1403                                * safe. */
1404     return(2);
1405 }
1406 #endif
1407
1408 static int init(int hup)
1409 {
1410     if(!hup)
1411     {
1412         /*
1413         if(register_printf_function('N', formataddress, formataddress_arginfo))
1414         {
1415             flog(LOG_CRIT, "could not register printf handler %%N: %s", strerror(errno));
1416             return(1);
1417         }
1418         */
1419     }
1420     return(0);
1421 }
1422
1423 static void terminate(void)
1424 {
1425     while(sockets != NULL)
1426         unlinksock(sockets);
1427 }
1428
1429 static struct module me =
1430 {
1431     .name = "net",
1432     .conf =
1433     {
1434         .vars = myvars
1435     },
1436     .init = init,
1437     .terminate = terminate
1438 };
1439
1440 MODULE(me)