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
, chunk_trailer_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
);
251 chunk_trailer_len
= 2;
253 chunk_header_len
= 0;
254 chunk_trailer_len
= 0;
257 if(request
->offset
< -chunk_header_len
) {
258 assert(request
->offset
>= -(request
->u
.h
.hlen
+ chunk_header_len
));
259 iov
[i
].iov_base
= request
->u
.h
.header
;
260 iov
[i
].iov_len
= -request
->offset
- chunk_header_len
;
264 if(chunk_header_len
> 0) {
265 chunkHeader(chunk_header
, 10, len123
);
266 if(request
->offset
< -chunk_header_len
) {
267 iov
[i
].iov_base
= chunk_header
;
268 iov
[i
].iov_len
= chunk_header_len
;
270 iov
[i
].iov_base
= chunk_header
+
271 chunk_header_len
+ request
->offset
;
272 iov
[i
].iov_len
= -request
->offset
;
278 if(request
->len
> 0) {
279 if(request
->buf
== NULL
&&
280 (request
->operation
& IO_BUF_LOCATION
)) {
281 assert(*request
->u
.l
.buf_location
== NULL
);
282 request
->buf
= *request
->u
.l
.buf_location
= get_chunk();
283 if(request
->buf
== NULL
) {
284 done
= request
->handler(-ENOMEM
, event
, request
);
288 if(request
->offset
<= 0) {
289 iov
[i
].iov_base
= request
->buf
;
290 iov
[i
].iov_len
= request
->len
;
292 } else if(request
->offset
< request
->len
) {
293 iov
[i
].iov_base
= request
->buf
+ request
->offset
;
294 iov
[i
].iov_len
= request
->len
- request
->offset
;
299 if(request
->len2
> 0) {
300 if(request
->offset
<= request
->len
) {
301 iov
[i
].iov_base
= request
->buf2
;
302 iov
[i
].iov_len
= request
->len2
;
304 } else if(request
->offset
< request
->len
+ request
->len2
) {
305 iov
[i
].iov_base
= request
->buf2
+ request
->offset
- request
->len
;
306 iov
[i
].iov_len
= request
->len2
- request
->offset
+ request
->len
;
311 if((request
->operation
& IO_BUF3
) && request
->u
.b
.len3
> 0) {
312 if(request
->offset
<= len12
) {
313 iov
[i
].iov_base
= request
->u
.b
.buf3
;
314 iov
[i
].iov_len
= request
->u
.b
.len3
;
316 } else if(request
->offset
< len12
+ request
->u
.b
.len3
) {
317 iov
[i
].iov_base
= request
->u
.b
.buf3
+ request
->offset
- len12
;
318 iov
[i
].iov_len
= request
->u
.b
.len3
- request
->offset
+ len12
;
323 if((request
->operation
& IO_CHUNKED
)) {
326 if(request
->operation
& IO_END
) {
328 trailer
= endChunkTrailer
+ 2;
331 trailer
= endChunkTrailer
;
335 trailer
= endChunkTrailer
;
339 if(request
->offset
<= len123
) {
340 iov
[i
].iov_base
= (char*)trailer
;
343 } else if(request
->offset
< len123
+ l
) {
345 (char*)endChunkTrailer
+ request
->offset
- len123
;
346 iov
[i
].iov_len
= l
- request
->offset
+ len123
;
353 if((request
->operation
& IO_MASK
) == IO_WRITE
) {
355 rc
= WRITEV(request
->fd
, iov
, i
);
357 rc
= WRITE(request
->fd
, iov
[0].iov_base
, iov
[0].iov_len
);
360 rc
= READV(request
->fd
, iov
, i
);
362 rc
= READ(request
->fd
, iov
[0].iov_base
, iov
[0].iov_len
);
366 request
->offset
+= rc
;
367 if(request
->offset
< 0) return 0;
368 done
= request
->handler(0, event
, request
);
370 } else if(rc
== 0 || errno
== EPIPE
) {
371 done
= request
->handler(1, event
, request
);
372 } else if(errno
== EAGAIN
|| errno
== EINTR
) {
374 } else if(errno
== EFAULT
|| errno
== EBADF
) {
377 done
= request
->handler(-errno
, event
, request
);
384 streamRequestDone(StreamRequestPtr request
)
387 request
->len
+ request
->len2
+
388 ((request
->operation
& IO_BUF3
) ? request
->u
.b
.len3
: 0);
390 if(request
->offset
< 0)
392 else if(request
->offset
< len123
)
394 else if(request
->operation
& IO_CHUNKED
) {
395 if(request
->operation
& IO_END
) {
396 if(request
->offset
< len123
+ (len123
? 7 : 5))
399 if(request
->offset
< len123
+ 2)
412 fd
= socket(PF_INET
, SOCK_STREAM
, 0);
415 fd
= socket(PF_INET6
, SOCK_STREAM
, 0);
418 errno
= EAFNOSUPPORT
;
425 rc
= setNonblocking(fd
, 1);
427 int errno_save
= errno
;
432 #ifdef HAVE_IPV6_PREFER_TEMPADDR
433 if (af
== 6 && useTemporarySourceAddress
!= 1) {
435 value
= (useTemporarySourceAddress
== 2) ? 1 : 0;
436 rc
= setsockopt(fd
, IPPROTO_IPV6
, IPV6_PREFER_TEMPADDR
,
437 &value
, sizeof(value
));
439 /* no error, warning only */
440 do_log_error(L_WARN
, errno
, "Couldn't set IPV6CTL_USETEMPADDR");
450 do_connect(AtomPtr addr
, int index
, int port
,
451 int (*handler
)(int, FdEventHandlerPtr
, ConnectRequestPtr
),
454 ConnectRequestRec request
;
455 FdEventHandlerPtr event
;
458 assert(addr
->length
> 0 && addr
->string
[0] == DNS_A
);
459 assert(addr
->length
% sizeof(HostAddressRec
) == 1);
461 if(index
>= (addr
->length
- 1)/ sizeof(HostAddressRec
))
464 request
.firstindex
= index
;
466 request
.handler
= handler
;
469 af
= addr
->string
[1 + index
* sizeof(HostAddressRec
)];
470 fd
= serverSocket(af
);
475 request
.index
= index
;
478 int n
= (addr
->length
- 1) / sizeof(HostAddressRec
);
479 if(errno
== EAFNOSUPPORT
|| errno
== EPROTONOSUPPORT
) {
480 if((index
+ 1) % n
!= request
.firstindex
) {
481 index
= (index
+ 1) % n
;
485 do_log_error(L_ERROR
, errno
, "Couldn't create socket");
486 done
= (*handler
)(-errno
, NULL
, &request
);
491 /* POLLIN is apparently needed on Windows */
492 event
= registerFdEvent(fd
, POLLIN
| POLLOUT
,
493 do_scheduled_connect
,
494 sizeof(ConnectRequestRec
), &request
);
496 done
= (*handler
)(-ENOMEM
, NULL
, &request
);
501 done
= event
->handler(0, event
);
503 unregisterFdEvent(event
);
510 do_scheduled_connect(int status
, FdEventHandlerPtr event
)
512 ConnectRequestPtr request
= (ConnectRequestPtr
)&event
->data
;
513 AtomPtr addr
= request
->addr
;
517 struct sockaddr_in servaddr
;
519 struct sockaddr_in6 servaddr6
;
522 assert(addr
->length
> 0 && addr
->string
[0] == DNS_A
);
523 assert(addr
->length
% sizeof(HostAddressRec
) == 1);
524 assert(request
->index
< (addr
->length
- 1) / sizeof(HostAddressRec
));
527 done
= request
->handler(status
, event
, request
);
530 request
->addr
= NULL
;
537 host
= (HostAddressPtr
)&addr
->string
[1 +
539 sizeof(HostAddressRec
)];
540 if(host
->af
!= request
->af
) {
542 /* Ouch. Our socket has a different protocol than the host
545 newfd
= serverSocket(host
->af
);
547 if(errno
== EAFNOSUPPORT
|| errno
== EPROTONOSUPPORT
) {
548 int n
= request
->addr
->length
/ sizeof(HostAddressRec
);
549 if((request
->index
+ 1) % n
!= request
->firstindex
) {
550 request
->index
= (request
->index
+ 1) % n
;
555 done
= request
->handler(-errno
, event
, request
);
559 if(newfd
!= request
->fd
) {
560 request
->fd
= dup2(newfd
, request
->fd
);
562 if(request
->fd
< 0) {
563 done
= request
->handler(-errno
, event
, request
);
568 request
->af
= host
->af
;
572 memset(&servaddr
, 0, sizeof(servaddr
));
573 servaddr
.sin_family
= AF_INET
;
574 servaddr
.sin_port
= htons(request
->port
);
575 memcpy(&servaddr
.sin_addr
, &host
->data
, sizeof(struct in_addr
));
576 rc
= connect(request
->fd
,
577 (struct sockaddr
*)&servaddr
, sizeof(servaddr
));
581 memset(&servaddr6
, 0, sizeof(servaddr6
));
582 servaddr6
.sin6_family
= AF_INET6
;
583 servaddr6
.sin6_port
= htons(request
->port
);
584 memcpy(&servaddr6
.sin6_addr
, &host
->data
, sizeof(struct in6_addr
));
585 rc
= connect(request
->fd
,
586 (struct sockaddr
*)&servaddr6
, sizeof(servaddr6
));
589 errno
= EAFNOSUPPORT
;
596 if(rc
>= 0 || errno
== EISCONN
) {
597 done
= request
->handler(1, event
, request
);
599 releaseAtom(request
->addr
);
600 request
->addr
= NULL
;
604 if(errno
== EINPROGRESS
|| errno
== EINTR
) {
606 } else if(errno
== EFAULT
|| errno
== EBADF
) {
609 int n
= request
->addr
->length
/ sizeof(HostAddressRec
);
610 if((request
->index
+ 1) % n
!= request
->firstindex
) {
611 request
->index
= (request
->index
+ 1) % n
;
614 done
= request
->handler(-errno
, event
, request
);
616 releaseAtom(request
->addr
);
617 request
->addr
= NULL
;
624 int (*handler
)(int, FdEventHandlerPtr
, AcceptRequestPtr
),
627 FdEventHandlerPtr event
;
630 event
= schedule_accept(fd
, handler
, data
);
632 done
= (*handler
)(-ENOMEM
, NULL
, NULL
);
636 /* But don't invoke it now - this will delay accept if under load. */
641 schedule_accept(int fd
,
642 int (*handler
)(int, FdEventHandlerPtr
, AcceptRequestPtr
),
645 FdEventHandlerPtr event
;
646 AcceptRequestRec request
;
650 request
.handler
= handler
;
652 event
= registerFdEvent(fd
, POLLOUT
|POLLIN
,
653 do_scheduled_accept
, sizeof(request
), &request
);
655 done
= (*handler
)(-ENOMEM
, NULL
, NULL
);
662 do_scheduled_accept(int status
, FdEventHandlerPtr event
)
664 AcceptRequestPtr request
= (AcceptRequestPtr
)&event
->data
;
667 struct sockaddr_in addr
;
670 done
= request
->handler(status
, event
, request
);
671 if(done
) return done
;
674 len
= sizeof(struct sockaddr_in
);
676 rc
= accept(request
->fd
, (struct sockaddr
*)&addr
, &len
);
679 done
= request
->handler(rc
, event
, request
);
681 done
= request
->handler(-errno
, event
, request
);
686 create_listener(char *address
, int port
,
687 int (*handler
)(int, FdEventHandlerPtr
, AcceptRequestPtr
),
693 struct sockaddr_in addr
;
696 struct sockaddr_in6 addr6
;
701 if(inet6
&& address
) {
703 rc
= inet_aton(address
, &buf
);
708 errno
= EAFNOSUPPORT
;
712 fd
= socket(PF_INET6
, SOCK_STREAM
, 0);
716 if(fd
< 0 && (errno
== EPROTONOSUPPORT
|| errno
== EAFNOSUPPORT
)) {
718 fd
= socket(PF_INET
, SOCK_STREAM
, 0);
722 done
= (*handler
)(-errno
, NULL
, NULL
);
727 rc
= setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *)&one
, sizeof(one
));
728 if(rc
< 0) do_log_error(L_WARN
, errno
, "Couldn't set SO_REUSEADDR");
732 rc
= setV6only(fd
, 0);
734 /* Reportedly OpenBSD returns an error for that. So only
735 log it as a debugging message. */
736 do_log_error(D_CLIENT_CONN
, errno
, "Couldn't reset IPV6_V6ONLY");
738 memset(&addr6
, 0, sizeof(addr6
));
739 rc
= inet_pton(AF_INET6
, address
, &addr6
.sin6_addr
);
741 done
= (*handler
)(rc
== 0 ? -ESYNTAX
: -errno
, NULL
, NULL
);
745 addr6
.sin6_family
= AF_INET6
;
746 addr6
.sin6_port
= htons(port
);
747 rc
= bind(fd
, (struct sockaddr
*)&addr6
, sizeof(addr6
));
750 errno
= EAFNOSUPPORT
;
753 memset(&addr
, 0, sizeof(addr
));
754 rc
= inet_aton(address
, &addr
.sin_addr
);
756 done
= (*handler
)(rc
== 0 ? -ESYNTAX
: -errno
, NULL
, NULL
);
760 addr
.sin_family
= AF_INET
;
761 addr
.sin_port
= htons(port
);
762 rc
= bind(fd
, (struct sockaddr
*)&addr
, sizeof(addr
));
766 do_log_error(L_ERROR
, errno
, "Couldn't bind");
768 done
= (*handler
)(-errno
, NULL
, NULL
);
773 rc
= setNonblocking(fd
, 1);
775 do_log_error(L_ERROR
, errno
, "Couldn't set non blocking mode");
777 done
= (*handler
)(-errno
, NULL
, NULL
);
784 do_log_error(L_ERROR
, errno
, "Couldn't listen");
786 done
= (*handler
)(-errno
, NULL
, NULL
);
791 do_log(L_INFO
, "Established listening socket on port %d.\n", port
);
793 return schedule_accept(fd
, handler
, data
);
798 #define SOL_TCP IPPROTO_TCP
802 setNonblocking(int fd
, int nonblocking
)
805 return mingw_setnonblocking(fd
, nonblocking
);
808 rc
= fcntl(fd
, F_GETFL
, 0);
812 rc
= fcntl(fd
, F_SETFL
, nonblocking
?(rc
| O_NONBLOCK
):(rc
& ~O_NONBLOCK
));
821 setNodelay(int fd
, int nodelay
)
823 int val
= nodelay
? 1 : 0;
825 rc
= setsockopt(fd
, SOL_TCP
, TCP_NODELAY
, (char *)&val
, sizeof(val
));
833 setV6only(int fd
, int v6only
)
835 int val
= v6only
? 1 : 0;
837 rc
= setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *)&val
, sizeof(val
));
844 setV6only(int fd
, int v6only
)
850 typedef struct _LingeringClose
{
852 FdEventHandlerPtr handler
;
853 TimeEventHandlerPtr timeout
;
854 } LingeringCloseRec
, *LingeringClosePtr
;
857 lingeringCloseTimeoutHandler(TimeEventHandlerPtr event
)
859 LingeringClosePtr l
= *(LingeringClosePtr
*)event
->data
;
860 assert(l
->timeout
== event
);
863 pokeFdEvent(l
->fd
, -ESHUTDOWN
, POLLIN
| POLLOUT
);
872 lingeringCloseHandler(int status
, FdEventHandlerPtr event
)
874 LingeringClosePtr l
= *(LingeringClosePtr
*)event
->data
;
878 assert(l
->handler
== event
);
881 if(status
&& status
!= -EDOGRACEFUL
)
884 rc
= READ(l
->fd
, &buf
, 17);
885 if(rc
== 0 || (rc
< 0 && errno
!= EAGAIN
&& errno
!= EINTR
))
888 /* The client is still sending data. Ignore it in order to let
889 TCP's flow control do its work. The timeout will close the
895 cancelTimeEvent(l
->timeout
);
904 lingeringClose(int fd
)
909 rc
= shutdown(fd
, 1);
911 if(errno
!= ENOTCONN
) {
912 do_log_error(L_ERROR
, errno
, "Shutdown failed");
913 } else if(errno
== EFAULT
|| errno
== EBADF
) {
920 l
= malloc(sizeof(LingeringCloseRec
));
927 l
->timeout
= scheduleTimeEvent(10, lingeringCloseTimeoutHandler
,
928 sizeof(LingeringClosePtr
), &l
);
929 if(l
->timeout
== NULL
) {
934 l
->handler
= registerFdEvent(fd
, POLLIN
,
935 lingeringCloseHandler
,
936 sizeof(LingeringClosePtr
), &l
);
937 if(l
->handler
== NULL
) {
938 do_log(L_ERROR
, "Couldn't schedule lingering close handler.\n");
939 /* But don't close -- the timeout will do its work. */
944 do_log(L_ERROR
, "Couldn't schedule lingering close.\n");
950 parseNetAddress(AtomListPtr list
)
957 struct in6_addr ina6
;
960 nl
= malloc((list
->length
+ 1) * sizeof(NetAddressRec
));
962 do_log(L_ERROR
, "Couldn't allocate network list.\n");
966 for(i
= 0; i
< list
->length
; i
++) {
968 char *s
= list
->list
[i
]->string
, *p
;
969 int n
= list
->list
[i
]->length
;
972 while(*s
== ' ' || *s
== '\t') {
978 do_log(L_ERROR
, "Network name too long.\n");
981 p
= memchr(s
, '/', n
);
983 memcpy(buf
, s
, p
- s
);
985 prefix
= strtol(p
+ 1, &suffix
, 10);
991 s2
= strchr(s
, '\t');
992 if(s1
== NULL
) suffix
= s2
;
993 else if(s2
== NULL
) suffix
= s1
;
994 else if(s1
< s2
) suffix
= s1
;
1000 if(!isWhitespace(suffix
)) {
1001 do_log(L_ERROR
, "Couldn't parse network %s.\n", buf
);
1006 rc
= inet_aton(buf
, &ina
);
1009 rc6
= inet_pton(AF_INET6
, buf
, &ina6
);
1012 if(rc
== 0 && rc6
== 0) {
1013 do_log(L_ERROR
, "Couldn't parse network %s.\n", buf
);
1016 nl
[i
].prefix
= prefix
;
1019 memcpy(nl
[i
].data
, &ina
, 4);
1023 memcpy(nl
[i
].data
, &ina6
, 16);
1037 /* Returns 1 if the first n bits of a and b are equal */
1039 bitmatch(const unsigned char *a
, const unsigned char *b
, int n
)
1042 if(memcmp(a
, b
, n
/ 8) != 0)
1047 int mask
= (~0) << (8 - n
% 8);
1048 if((a
[n
/ 8] & mask
) != (b
[n
/ 8] & mask
))
1055 /* Returns 1 if the address in data is in list */
1057 match(int af
, unsigned char *data
, NetAddressPtr list
)
1061 static const unsigned char v6mapped
[] =
1062 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };
1066 while(list
[i
].af
!= 0) {
1067 if(af
== 4 && list
[i
].af
== 4) {
1068 if(bitmatch(data
, list
[i
].data
,
1069 list
[i
].prefix
>= 0 ? list
[i
].prefix
: 32))
1072 } else if(af
== 6 && list
[i
].af
== 6) {
1073 if(bitmatch(data
, list
[i
].data
,
1074 list
[i
].prefix
>= 0 ? list
[i
].prefix
: 128))
1076 } else if(af
== 6 && list
[i
].af
== 4) {
1077 if(bitmatch(data
, v6mapped
, 96)) {
1078 if(bitmatch(data
+ 12, list
[i
].data
,
1079 list
[i
].prefix
>= 0 ? list
[i
].prefix
: 32))
1082 } else if(af
== 4 && list
[i
].af
== 6) {
1083 if(bitmatch(list
[i
].data
, v6mapped
, 96)) {
1084 if(bitmatch(data
, list
[i
].data
+ 12,
1085 list
[i
].prefix
>= 96 ?
1086 list
[i
].prefix
- 96 : 32))
1099 netAddressMatch(int fd
, NetAddressPtr list
)
1103 struct sockaddr_in sain
;
1105 struct sockaddr_in6 sain6
;
1109 rc
= getpeername(fd
, (struct sockaddr
*)&sain
, &len
);
1111 do_log_error(L_ERROR
, errno
, "Couldn't get peer name");
1115 if(sain
.sin_family
== AF_INET
) {
1116 return match(4, (unsigned char*)&sain
.sin_addr
, list
);
1118 } else if(sain
.sin_family
== AF_INET6
) {
1119 len
= sizeof(sain6
);
1120 rc
= getpeername(fd
, (struct sockaddr
*)&sain6
, &len
);
1122 do_log_error(L_ERROR
, errno
, "Couldn't get peer name");
1125 if(sain6
.sin6_family
!= AF_INET6
) {
1126 do_log(L_ERROR
, "Inconsistent peer name");
1129 return match(6, (unsigned char*)&sain6
.sin6_addr
, list
);
1132 do_log(L_ERROR
, "Unknown address family %d\n", sain
.sin_family
);