Hugo, thanks a lot for the great software and great support!! So far, that patch seems to works as expected!
On a sidenote, what are your thoughts about IPv4-over-IPv6 Mapped Addresses? While debugging this issue I noted that because of the dual-stack the IPv4 addreses are both logged and forwarded in the proxy headers in their hybrid notation. My personal preference would be to record the IPv4-over-IPv6 mapped addresses in their IPv4 representation instead. I haven't been able to figure out with the RFC-guidelines on this are.
While this might be categorized as a feature request, it also seems to result in a bug or at least into unexpected behavior: among others, a quick test seems to indicate that using the IPv6-mapped representation will result in circumvention of the access control.
For example, using IPv6-mapped representation will allow to bypass
AccessList = deny 10.11.12.13
To block it, one needs the IPv6-mapped representation instead:
AccessList = deny ::ffff:10.11.12.13
Haven't fully debugged this, so I guess this will only happen when one uses a single binding for all interfaces, i.e. Interface = :: .
With some searching on the web, I coded the following patch... Not sure if it is all fully correct, but on first glance it seems to do what I want it to do...
--- hiawatha.c.orig 2013-04-29 19:40:47.512425668 +0200
+++ hiawatha.c 2013-04-29 19:40:47.512425668 +0200
@@ -114,6 +114,18 @@
#endif
;
+#ifdef ENABLE_IPV6
+#ifndef IN6_IS_ADDR_V4MAPPED
+#define IN6_IS_ADDR_V4MAPPED(a) \
+ ((((a)->s6_words[0]) == 0) && \
+ (((a)->s6_words[1]) == 0) && \
+ (((a)->s6_word[2]) == 0) && \
+ (((a)->s6_word[3]) == 0) && \
+ (((a)->s6_word[4]) == 0) && \
+ (((a)->s6_word[5]) == 0xFFFF))
+#endif
+#endif
+
/* Create all logfiles with the right ownership and accessrights
*/
void touch_logfiles(t_config *config) {
@@ -432,9 +444,24 @@
return -1;
}
+ if (IN6_IS_ADDR_V4MAPPED(&caddr6.sin6_addr))
+ {
+ session->ip_address.family = AF_INET;
+ session->ip_address.size = IPv4_LEN;
+
+ const uint8_t *bytes = caddr6.sin6_addr.s6_addr;
+ bytes += 12;
+ struct in_addr addr = { *(const in_addr_t *)bytes };
+
+ memcpy(&(session->ip_address.value), (char*)(&addr), session->ip_address.size);
+ }
+ else
+ {
session->ip_address.family = AF_INET6;
session->ip_address.size = IPv6_LEN;
+
memcpy(&(session->ip_address.value), (char*)&caddr6.sin6_addr.s6_addr, session->ip_address.size);
+ }
#endif
} else {