2 Copyright (c) 2003-2006 by Juliusz Chroboczek
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 #ifdef IPV6_PREFER_TEMPADDR
27 #define HAVE_IPV6_PREFER_TEMPADDR 1
31 #ifdef HAVE_IPV6_PREFER_TEMPADDR
32 int useTemporarySourceAddress
= 1;
38 #ifdef HAVE_IPV6_PREFER_TEMPADDR
39 CONFIG_VARIABLE_SETTABLE(useTemporarySourceAddress
, CONFIG_TRISTATE
,
41 "Prefer IPv6 temporary source address.");
45 /* Load the winsock dll */
47 WORD wVersionRequested
= MAKEWORD(2, 2);
48 int err
= WSAStartup( wVersionRequested
, &wsaData
);
50 do_log_error(L_ERROR
, err
, "Couldn't load winsock dll");
64 do_stream(int operation
, int fd
, int offset
, char *buf
, int len
,
65 int (*handler
)(int, FdEventHandlerPtr
, StreamRequestPtr
),
68 assert(len
> offset
|| (operation
& (IO_END
| IO_IMMEDIATE
)));
69 return schedule_stream(operation
, fd
, offset
,
70 NULL
, 0, buf
, len
, NULL
, 0, NULL
, 0, NULL
,
75 do_stream_2(int operation
, int fd
, int offset
,
76 char *buf
, int len
, char *buf2
, int len2
,
77 int (*handler
)(int, FdEventHandlerPtr
, StreamRequestPtr
),
80 assert(len
+ len2
> offset
|| (operation
& (IO_END
| IO_IMMEDIATE
)));
81 return schedule_stream(operation
, fd
, offset
,
82 NULL
, 0, buf
, len
, buf2
, len2
, NULL
, 0, NULL
,
87 do_stream_3(int operation
, int fd
, int offset
,
88 char *buf
, int len
, char *buf2
, int len2
, char *buf3
, int len3
,
89 int (*handler
)(int, FdEventHandlerPtr
, StreamRequestPtr
),
92 assert(len
+ len2
> offset
|| (operation
& (IO_END
| IO_IMMEDIATE
)));
93 return schedule_stream(operation
, fd
, offset
,
94 NULL
, 0, buf
, len
, buf2
, len2
, buf3
, len3
, NULL
,
99 do_stream_h(int operation
, int fd
, int offset
,
100 char *header
, int hlen
, char *buf
, int len
,
101 int (*handler
)(int, FdEventHandlerPtr
, StreamRequestPtr
),
104 assert(hlen
+ len
> offset
|| (operation
& (IO_END
| IO_IMMEDIATE
)));
105 return schedule_stream(operation
, fd
, offset
,
106 header
, hlen
, buf
, len
, NULL
, 0, NULL
, 0, NULL
,
111 do_stream_buf(int operation
, int fd
, int offset
, char **buf_location
, int len
,
112 int (*handler
)(int, FdEventHandlerPtr
, StreamRequestPtr
),
115 assert((len
> offset
|| (operation
& (IO_END
| IO_IMMEDIATE
)))
116 && len
<= CHUNK_SIZE
);
117 return schedule_stream(operation
, fd
, offset
,
118 NULL
, 0, *buf_location
, len
,
119 NULL
, 0, NULL
, 0, buf_location
,
124 chunkHeaderLen(int i
)
141 chunkHeader(char *buf
, int buflen
, int i
)
146 n
= snprintf(buf
, buflen
, "%x\r\n", i
);
152 schedule_stream(int operation
, int fd
, int offset
,
153 char *header
, int hlen
,
154 char *buf
, int len
, char *buf2
, int len2
, char *buf3
, int len3
,
156 int (*handler
)(int, FdEventHandlerPtr
, StreamRequestPtr
),
159 StreamRequestRec request
;
160 FdEventHandlerPtr event
;
163 request
.operation
= operation
;
166 assert(hlen
== 0 && buf_location
== NULL
);
167 request
.u
.b
.len3
= len3
;
168 request
.u
.b
.buf3
= buf3
;
169 request
.operation
|= IO_BUF3
;
170 } else if(buf_location
) {
172 request
.u
.l
.buf_location
= buf_location
;
173 request
.operation
|= IO_BUF_LOCATION
;
175 request
.u
.h
.hlen
= hlen
;
176 request
.u
.h
.header
= header
;
182 if((operation
& IO_CHUNKED
) ||
183 (!(request
.operation
& (IO_BUF3
| IO_BUF_LOCATION
)) && hlen
> 0)) {
185 request
.offset
= -hlen
;
186 if(operation
& IO_CHUNKED
)
187 request
.offset
+= -chunkHeaderLen(len
+ len2
);
189 request
.offset
= offset
;
191 request
.handler
= handler
;
193 event
= makeFdEvent(fd
,
194 (operation
& IO_MASK
) == IO_WRITE
?
197 sizeof(StreamRequestRec
), &request
);
199 done
= (*handler
)(-ENOMEM
, NULL
, &request
);
204 if(!(operation
& IO_NOTNOW
)) {
205 done
= event
->handler(0, event
);
212 if(operation
& IO_IMMEDIATE
) {
213 assert(hlen
== 0 && !(operation
& IO_CHUNKED
));
214 done
= (*handler
)(0, event
, &request
);
220 event
= registerFdEventHelper(event
);
224 static const char *endChunkTrailer
= "\r\n0\r\n\r\n";
227 do_scheduled_stream(int status
, FdEventHandlerPtr event
)
229 StreamRequestPtr request
= (StreamRequestPtr
)&event
->data
;
232 int chunk_header_len
;
233 char chunk_header
[10];
234 int len12
= request
->len
+ request
->len2
;
236 request
->len
+ request
->len2
+
237 ((request
->operation
& IO_BUF3
) ? request
->u
.b
.len3
: 0);
240 done
= request
->handler(status
, event
, request
);
246 if(request
->offset
< 0) {
247 assert((request
->operation
& (IO_MASK
| IO_BUF3
| IO_BUF_LOCATION
)) ==
249 if(request
->operation
& IO_CHUNKED
) {
250 chunk_header_len
= chunkHeaderLen(len123
);
252 chunk_header_len
= 0;
255 if(request
->offset
< -chunk_header_len
) {
256 assert(request
->offset
>= -(request
->u
.h
.hlen
+ chunk_header_len
));
257 iov
[i
].iov_base
= request
->u
.h
.header
;
258 iov
[i
].iov_len
= -request
->offset
- chunk_header_len
;
262 if(chunk_header_len
> 0) {
263 chunkHeader(chunk_header
, 10, len123
);
264 if(request
->offset
< -chunk_header_len
) {
265 iov
[i
].iov_base
= chunk_header
;
266 iov
[i
].iov_len
= chunk_header_len
;
268 iov
[i
].iov_base
= chunk_header
+
269 chunk_header_len
+ request
->offset
;
270 iov
[i
].iov_len
= -request
->offset
;
276 if(request
->len
> 0) {
277 if(request
->buf
== NULL
&&
278 (request
->operation
& IO_BUF_LOCATION
)) {
279 assert(*request
->u
.l
.buf_location
== NULL
);
280 request
->buf
= *request
->u
.l
.buf_location
= get_chunk();
281 if(request
->buf
== NULL
) {
282 done
= request
->handler(-ENOMEM
, event
, request
);
286 if(request
->offset
<= 0) {
287 iov
[i
].iov_base
= request
->buf
;
288 iov
[i
].iov_len
= request
->len
;
290 } else if(request
->offset
< request
->len
) {
291 iov
[i
].iov_base
= request
->buf
+ request
->offset
;
292 iov
[i
].iov_len
= request
->len
- request
->offset
;
297 if(request
->len2
> 0) {
298 if(request
->offset
<= request
->len
) {
299 iov
[i
].iov_base
= request
->buf2
;
300 iov
[i
].iov_len
= request
->len2
;
302 } else if(request
->offset
< request
->len
+ request
->len2
) {
303 iov
[i
].iov_base
= request
->buf2
+ request
->offset
- request
->len
;
304 iov
[i
].iov_len
= request
->len2
- request
->offset
+ request
->len
;
309 if((request
->operation
& IO_BUF3
) && request
->u
.b
.len3
> 0) {
310 if(request
->offset
<= len12
) {
311 iov
[i
].iov_base
= request
->u
.b
.buf3
;
312 iov
[i
].iov_len
= request
->u
.b
.len3
;
314 } else if(request
->offset
< len12
+ request
->u
.b
.len3
) {
315 iov
[i
].iov_base
= request
->u
.b
.buf3
+ request
->offset
- len12
;
316 iov
[i
].iov_len
= request
->u
.b
.len3
- request
->offset
+ len12
;
321 if((request
->operation
& IO_CHUNKED
)) {
324 if(request
->operation
& IO_END
) {
326 trailer
= endChunkTrailer
+ 2;
329 trailer
= endChunkTrailer
;
333 trailer
= endChunkTrailer
;
337 if(request
->offset
<= len123
) {
338 iov
[i
].iov_base
= (char*)trailer
;
341 } else if(request
->offset
< len123
+ l
) {
343 (char*)endChunkTrailer
+ request
->offset
- len123
;
344 iov
[i
].iov_len
= l
- request
->offset
+ len123
;
351 if((request
->operation
& IO_MASK
) == IO_WRITE
) {
353 rc
= WRITEV(request
->fd
, iov
, i
);
355 rc
= WRITE(request
->fd
, iov
[0].iov_base
, iov
[0].iov_len
);
358 rc
= READV(request
->fd
, iov
, i
);
360 rc
= READ(request
->fd
, iov
[0].iov_base
, iov
[0].iov_len
);
364 request
->offset
+= rc
;
365 if(request
->offset
< 0) return 0;
366 done
= request
->handler(0, event
, request
);
368 } else if(rc
== 0 || errno
== EPIPE
) {
369 done
= request
->handler(1, event
, request
);
370 } else if(errno
== EAGAIN
|| errno
== EINTR
) {
372 } else if(errno
== EFAULT
|| errno
== EBADF
) {
375 done
= request
->handler(-errno
, event
, request
);
382 streamRequestDone(StreamRequestPtr request
)
385 request
->len
+ request
->len2
+
386 ((request
->operation
& IO_BUF3
) ? request
->u
.b
.len3
: 0);
388 if(request
->offset
< 0)
390 else if(request
->offset
< len123
)
392 else if(request
->operation
& IO_CHUNKED
) {
393 if(request
->operation
& IO_END
) {
394 if(request
->offset
< len123
+ (len123
? 7 : 5))
397 if(request
->offset
< len123
+ 2)
410 fd
= socket(PF_INET
, SOCK_STREAM
, 0);
413 fd
= socket(PF_INET6
, SOCK_STREAM
, 0);
416 errno
= EAFNOSUPPORT
;
423 rc
= setNonblocking(fd
, 1);
425 int errno_save
= errno
;
430 #ifdef HAVE_IPV6_PREFER_TEMPADDR
431 if (af
== 6 && useTemporarySourceAddress
!= 1) {
433 value
= (useTemporarySourceAddress
== 2) ? 1 : 0;
434 rc
= setsockopt(fd
, IPPROTO_IPV6
, IPV6_PREFER_TEMPADDR
,
435 &value
, sizeof(value
));
437 /* no error, warning only */
438 do_log_error(L_WARN
, errno
, "Couldn't set IPV6CTL_USETEMPADDR");
448 do_connect(AtomPtr addr
, int index
, int port
,
449 int (*handler
)(int, FdEventHandlerPtr
, ConnectRequestPtr
),
452 ConnectRequestRec request
;
453 FdEventHandlerPtr event
;
456 assert(addr
->length
> 0 && addr
->string
[0] == DNS_A
);
457 assert(addr
->length
% sizeof(HostAddressRec
) == 1);
459 if(index
>= (addr
->length
- 1)/ sizeof(HostAddressRec
))
462 request
.firstindex
= index
;
464 request
.handler
= handler
;
467 af
= addr
->string
[1 + index
* sizeof(HostAddressRec
)];
468 fd
= serverSocket(af
);
473 request
.index
= index
;
476 int n
= (addr
->length
- 1) / sizeof(HostAddressRec
);
477 if(errno
== EAFNOSUPPORT
|| errno
== EPROTONOSUPPORT
) {
478 if((index
+ 1) % n
!= request
.firstindex
) {
479 index
= (index
+ 1) % n
;
483 do_log_error(L_ERROR
, errno
, "Couldn't create socket");
484 done
= (*handler
)(-errno
, NULL
, &request
);
489 /* POLLIN is apparently needed on Windows */
490 event
= registerFdEvent(fd
, POLLIN
| POLLOUT
,
491 do_scheduled_connect
,
492 sizeof(ConnectRequestRec
), &request
);
494 done
= (*handler
)(-ENOMEM
, NULL
, &request
);
499 done
= event
->handler(0, event
);
501 unregisterFdEvent(event
);
508 do_scheduled_connect(int status
, FdEventHandlerPtr event
)
510 ConnectRequestPtr request
= (ConnectRequestPtr
)&event
->data
;
511 AtomPtr addr
= request
->addr
;
515 struct sockaddr_in servaddr
;
517 struct sockaddr_in6 servaddr6
;
520 assert(addr
->length
> 0 && addr
->string
[0] == DNS_A
);
521 assert(addr
->length
% sizeof(HostAddressRec
) == 1);
522 assert(request
->index
< (addr
->length
- 1) / sizeof(HostAddressRec
));
525 done
= request
->handler(status
, event
, request
);
528 request
->addr
= NULL
;
535 host
= (HostAddressPtr
)&addr
->string
[1 +
537 sizeof(HostAddressRec
)];
538 if(host
->af
!= request
->af
) {
540 /* Ouch. Our socket has a different protocol than the host
543 newfd
= serverSocket(host
->af
);
545 if(errno
== EAFNOSUPPORT
|| errno
== EPROTONOSUPPORT
) {
546 int n
= request
->addr
->length
/ sizeof(HostAddressRec
);
547 if((request
->index
+ 1) % n
!= request
->firstindex
) {
548 request
->index
= (request
->index
+ 1) % n
;
553 done
= request
->handler(-errno
, event
, request
);
557 if(newfd
!= request
->fd
) {
558 request
->fd
= dup2(newfd
, request
->fd
);
560 if(request
->fd
< 0) {
561 done
= request
->handler(-errno
, event
, request
);
566 request
->af
= host
->af
;
570 memset(&servaddr
, 0, sizeof(servaddr
));
571 servaddr
.sin_family
= AF_INET
;
572 servaddr
.sin_port
= htons(request
->port
);
573 memcpy(&servaddr
.sin_addr
, &host
->data
, sizeof(struct in_addr
));
574 rc
= connect(request
->fd
,
575 (struct sockaddr
*)&servaddr
, sizeof(servaddr
));
579 memset(&servaddr6
, 0, sizeof(servaddr6
));
580 servaddr6
.sin6_family
= AF_INET6
;
581 servaddr6
.sin6_port
= htons(request
->port
);
582 memcpy(&servaddr6
.sin6_addr
, &host
->data
, sizeof(struct in6_addr
));
583 rc
= connect(request
->fd
,
584 (struct sockaddr
*)&servaddr6
, sizeof(servaddr6
));
587 errno
= EAFNOSUPPORT
;
594 if(rc
>= 0 || errno
== EISCONN
) {
595 done
= request
->handler(1, event
, request
);
597 releaseAtom(request
->addr
);
598 request
->addr
= NULL
;
602 if(errno
== EINPROGRESS
|| errno
== EINTR
) {
604 } else if(errno
== EFAULT
|| errno
== EBADF
) {
607 int n
= request
->addr
->length
/ sizeof(HostAddressRec
);
608 if((request
->index
+ 1) % n
!= request
->firstindex
) {
609 request
->index
= (request
->index
+ 1) % n
;
612 done
= request
->handler(-errno
, event
, request
);
614 releaseAtom(request
->addr
);
615 request
->addr
= NULL
;
622 int (*handler
)(int, FdEventHandlerPtr
, AcceptRequestPtr
),
625 FdEventHandlerPtr event
;
628 event
= schedule_accept(fd
, handler
, data
);
630 done
= (*handler
)(-ENOMEM
, NULL
, NULL
);
634 /* But don't invoke it now - this will delay accept if under load. */
639 schedule_accept(int fd
,
640 int (*handler
)(int, FdEventHandlerPtr
, AcceptRequestPtr
),
643 FdEventHandlerPtr event
;
644 AcceptRequestRec request
;
648 request
.handler
= handler
;
650 event
= registerFdEvent(fd
, POLLOUT
|POLLIN
,
651 do_scheduled_accept
, sizeof(request
), &request
);
653 done
= (*handler
)(-ENOMEM
, NULL
, NULL
);
660 do_scheduled_accept(int status
, FdEventHandlerPtr event
)
662 AcceptRequestPtr request
= (AcceptRequestPtr
)&event
->data
;
665 struct sockaddr_in addr
;
668 done
= request
->handler(status
, event
, request
);
669 if(done
) return done
;
672 len
= sizeof(struct sockaddr_in
);
674 rc
= accept(request
->fd
, (struct sockaddr
*)&addr
, &len
);
677 done
= request
->handler(rc
, event
, request
);
679 done
= request
->handler(-errno
, event
, request
);
684 create_listener(char *address
, int port
,
685 int (*handler
)(int, FdEventHandlerPtr
, AcceptRequestPtr
),
691 struct sockaddr_in addr
;
694 struct sockaddr_in6 addr6
;
699 if(inet6
&& address
) {
701 rc
= inet_aton(address
, &buf
);
706 errno
= EAFNOSUPPORT
;
710 fd
= socket(PF_INET6
, SOCK_STREAM
, 0);
714 if(fd
< 0 && (errno
== EPROTONOSUPPORT
|| errno
== EAFNOSUPPORT
)) {
716 fd
= socket(PF_INET
, SOCK_STREAM
, 0);
720 done
= (*handler
)(-errno
, NULL
, NULL
);
725 rc
= setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *)&one
, sizeof(one
));
726 if(rc
< 0) do_log_error(L_WARN
, errno
, "Couldn't set SO_REUSEADDR");
730 rc
= setV6only(fd
, 0);
732 /* Reportedly OpenBSD returns an error for that. So only
733 log it as a debugging message. */
734 do_log_error(D_CLIENT_CONN
, errno
, "Couldn't reset IPV6_V6ONLY");
736 memset(&addr6
, 0, sizeof(addr6
));
737 rc
= inet_pton(AF_INET6
, address
, &addr6
.sin6_addr
);
739 done
= (*handler
)(rc
== 0 ? -ESYNTAX
: -errno
, NULL
, NULL
);
743 addr6
.sin6_family
= AF_INET6
;
744 addr6
.sin6_port
= htons(port
);
745 rc
= bind(fd
, (struct sockaddr
*)&addr6
, sizeof(addr6
));
748 errno
= EAFNOSUPPORT
;
751 memset(&addr
, 0, sizeof(addr
));
752 rc
= inet_aton(address
, &addr
.sin_addr
);
754 done
= (*handler
)(rc
== 0 ? -ESYNTAX
: -errno
, NULL
, NULL
);
758 addr
.sin_family
= AF_INET
;
759 addr
.sin_port
= htons(port
);
760 rc
= bind(fd
, (struct sockaddr
*)&addr
, sizeof(addr
));
764 do_log_error(L_ERROR
, errno
, "Couldn't bind");
766 done
= (*handler
)(-errno
, NULL
, NULL
);
771 rc
= setNonblocking(fd
, 1);
773 do_log_error(L_ERROR
, errno
, "Couldn't set non blocking mode");
775 done
= (*handler
)(-errno
, NULL
, NULL
);
780 rc
= listen(fd
, 1024);
782 do_log_error(L_ERROR
, errno
, "Couldn't listen");
784 done
= (*handler
)(-errno
, NULL
, NULL
);
789 do_log(L_INFO
, "Established listening socket on port %d.\n", port
);
791 return schedule_accept(fd
, handler
, data
);
796 #define SOL_TCP IPPROTO_TCP
800 setNonblocking(int fd
, int nonblocking
)
803 return mingw_setnonblocking(fd
, nonblocking
);
806 rc
= fcntl(fd
, F_GETFL
, 0);
810 rc
= fcntl(fd
, F_SETFL
, nonblocking
?(rc
| O_NONBLOCK
):(rc
& ~O_NONBLOCK
));
819 setNodelay(int fd
, int nodelay
)
821 int val
= nodelay
? 1 : 0;
823 rc
= setsockopt(fd
, SOL_TCP
, TCP_NODELAY
, (char *)&val
, sizeof(val
));
831 setV6only(int fd
, int v6only
)
833 int val
= v6only
? 1 : 0;
835 rc
= setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *)&val
, sizeof(val
));
842 setV6only(int fd
, int v6only
)
848 typedef struct _LingeringClose
{
850 FdEventHandlerPtr handler
;
851 TimeEventHandlerPtr timeout
;
852 } LingeringCloseRec
, *LingeringClosePtr
;
855 lingeringCloseTimeoutHandler(TimeEventHandlerPtr event
)
857 LingeringClosePtr l
= *(LingeringClosePtr
*)event
->data
;
858 assert(l
->timeout
== event
);
861 pokeFdEvent(l
->fd
, -ESHUTDOWN
, POLLIN
| POLLOUT
);
870 lingeringCloseHandler(int status
, FdEventHandlerPtr event
)
872 LingeringClosePtr l
= *(LingeringClosePtr
*)event
->data
;
876 assert(l
->handler
== event
);
879 if(status
&& status
!= -EDOGRACEFUL
)
882 rc
= READ(l
->fd
, &buf
, 17);
883 if(rc
== 0 || (rc
< 0 && errno
!= EAGAIN
&& errno
!= EINTR
))
886 /* The client is still sending data. Ignore it in order to let
887 TCP's flow control do its work. The timeout will close the
893 cancelTimeEvent(l
->timeout
);
902 lingeringClose(int fd
)
907 rc
= shutdown(fd
, 1);
909 if(errno
!= ENOTCONN
) {
910 do_log_error(L_ERROR
, errno
, "Shutdown failed");
911 } else if(errno
== EFAULT
|| errno
== EBADF
) {
918 l
= malloc(sizeof(LingeringCloseRec
));
925 l
->timeout
= scheduleTimeEvent(10, lingeringCloseTimeoutHandler
,
926 sizeof(LingeringClosePtr
), &l
);
927 if(l
->timeout
== NULL
) {
932 l
->handler
= registerFdEvent(fd
, POLLIN
,
933 lingeringCloseHandler
,
934 sizeof(LingeringClosePtr
), &l
);
935 if(l
->handler
== NULL
) {
936 do_log(L_ERROR
, "Couldn't schedule lingering close handler.\n");
937 /* But don't close -- the timeout will do its work. */
942 do_log(L_ERROR
, "Couldn't schedule lingering close.\n");
948 parseNetAddress(AtomListPtr list
)
955 struct in6_addr ina6
;
958 nl
= malloc((list
->length
+ 1) * sizeof(NetAddressRec
));
960 do_log(L_ERROR
, "Couldn't allocate network list.\n");
964 for(i
= 0; i
< list
->length
; i
++) {
966 char *s
= list
->list
[i
]->string
, *p
;
967 int n
= list
->list
[i
]->length
;
970 while(*s
== ' ' || *s
== '\t') {
976 do_log(L_ERROR
, "Network name too long.\n");
979 p
= memchr(s
, '/', n
);
981 memcpy(buf
, s
, p
- s
);
983 prefix
= strtol(p
+ 1, &suffix
, 10);
989 s2
= strchr(s
, '\t');
990 if(s1
== NULL
) suffix
= s2
;
991 else if(s2
== NULL
) suffix
= s1
;
992 else if(s1
< s2
) suffix
= s1
;
998 if(!isWhitespace(suffix
)) {
999 do_log(L_ERROR
, "Couldn't parse network %s.\n", buf
);
1004 rc
= inet_aton(buf
, &ina
);
1007 rc6
= inet_pton(AF_INET6
, buf
, &ina6
);
1010 if(rc
== 0 && rc6
== 0) {
1011 do_log(L_ERROR
, "Couldn't parse network %s.\n", buf
);
1014 nl
[i
].prefix
= prefix
;
1017 memcpy(nl
[i
].data
, &ina
, 4);
1021 memcpy(nl
[i
].data
, &ina6
, 16);
1035 /* Returns 1 if the first n bits of a and b are equal */
1037 bitmatch(const unsigned char *a
, const unsigned char *b
, int n
)
1040 if(memcmp(a
, b
, n
/ 8) != 0)
1045 int mask
= (~0) << (8 - n
% 8);
1046 if((a
[n
/ 8] & mask
) != (b
[n
/ 8] & mask
))
1053 /* Returns 1 if the address in data is in list */
1055 match(int af
, unsigned char *data
, NetAddressPtr list
)
1059 static const unsigned char v6mapped
[] =
1060 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };
1064 while(list
[i
].af
!= 0) {
1065 if(af
== 4 && list
[i
].af
== 4) {
1066 if(bitmatch(data
, list
[i
].data
,
1067 list
[i
].prefix
>= 0 ? list
[i
].prefix
: 32))
1070 } else if(af
== 6 && list
[i
].af
== 6) {
1071 if(bitmatch(data
, list
[i
].data
,
1072 list
[i
].prefix
>= 0 ? list
[i
].prefix
: 128))
1074 } else if(af
== 6 && list
[i
].af
== 4) {
1075 if(bitmatch(data
, v6mapped
, 96)) {
1076 if(bitmatch(data
+ 12, list
[i
].data
,
1077 list
[i
].prefix
>= 0 ? list
[i
].prefix
: 32))
1080 } else if(af
== 4 && list
[i
].af
== 6) {
1081 if(bitmatch(list
[i
].data
, v6mapped
, 96)) {
1082 if(bitmatch(data
, list
[i
].data
+ 12,
1083 list
[i
].prefix
>= 96 ?
1084 list
[i
].prefix
- 96 : 32))
1097 netAddressMatch(int fd
, NetAddressPtr list
)
1101 struct sockaddr_in sain
;
1103 struct sockaddr_in6 sain6
;
1107 rc
= getpeername(fd
, (struct sockaddr
*)&sain
, &len
);
1109 do_log_error(L_ERROR
, errno
, "Couldn't get peer name");
1113 if(sain
.sin_family
== AF_INET
) {
1114 return match(4, (unsigned char*)&sain
.sin_addr
, list
);
1116 } else if(sain
.sin_family
== AF_INET6
) {
1117 len
= sizeof(sain6
);
1118 rc
= getpeername(fd
, (struct sockaddr
*)&sain6
, &len
);
1120 do_log_error(L_ERROR
, errno
, "Couldn't get peer name");
1123 if(sain6
.sin6_family
!= AF_INET6
) {
1124 do_log(L_ERROR
, "Inconsistent peer name");
1127 return match(6, (unsigned char*)&sain6
.sin6_addr
, list
);
1130 do_log(L_ERROR
, "Unknown address family %d\n", sain
.sin_family
);