
A port can be enabled for IPv6 by using bind ::0; (or some other IPv6 address) in the configuration block for that port. Resolving IPv6 hostnames is not supported yet. The ipmask token in the port block is also ignored. --- include/h.h | 1 + include/struct.h | 1 + src/clones.c | 6 ++++++ src/s_auth.c | 21 +++++++++++++++++++++ src/s_bsd.c | 38 +++++++++++++++++++++++++++++++++++--- src/s_user.c | 11 ++++++++++- src/support.c | 25 ++++++++++++++++++++++++- 7 files changed, 98 insertions(+), 5 deletions(-) diff --git a/include/h.h b/include/h.h index 137fcba..8fc4181 100644 --- a/include/h.h +++ b/include/h.h @@ -180,6 +180,7 @@ extern char *getreply(int); extern char *strerror(int); extern int dgets(int, char *, int); extern char *inetntoa(char *); +extern char *inet6ntoa(char *); extern char *cipntoa(aClient *); extern int dbufalloc, dbufblocks, debuglevel, errno; extern int highest_fd, debuglevel, portnum, diff --git a/include/struct.h b/include/struct.h index c68b05d..10074df 100644 --- a/include/struct.h +++ b/include/struct.h @@ -890,6 +890,7 @@ struct Client union { struct in_addr ip4; + struct in6_addr ip6; } ip; /* keep real ip# too */ char hostip[HOSTIPLEN + 1]; /* Keep real ip as string * too - Dianora */ diff --git a/src/clones.c b/src/clones.c index 63e9fb1..c4751a0 100644 --- a/src/clones.c +++ b/src/clones.c @@ -282,6 +282,9 @@ clones_add(aClient *cptr) if (cptr->ip_family == AF_INET && cptr->ip.ip4.s_addr == 0) return; + if (cptr->ip_family == AF_INET6 && + memcmp(&cptr->ip.ip6, &in6addr_any, sizeof(struct in6_addr)) == 0) + return; get_clones(cptr, &ceip, &ce24, 1); @@ -314,6 +317,9 @@ clones_remove(aClient *cptr) if (cptr->ip_family == AF_INET && cptr->ip.ip4.s_addr == 0) return; + if (cptr->ip_family == AF_INET6 && + memcmp(&cptr->ip.ip6, &in6addr_any, sizeof(struct in6_addr)) == 0) + return; get_clones(cptr, &ceip, &ce24, 0); diff --git a/src/s_auth.c b/src/s_auth.c index 6163af6..de8469a 100644 --- a/src/s_auth.c +++ b/src/s_auth.c @@ -54,11 +54,13 @@ void start_auth(aClient *cptr) { struct sockaddr sa; struct sockaddr_in addr4; + struct sockaddr_in6 addr6; } sock; union { struct sockaddr sa; struct sockaddr_in addr4; + struct sockaddr_in6 addr6; } localaddr; unsigned int locallen; @@ -98,6 +100,8 @@ void start_auth(aClient *cptr) getsockname(cptr->fd, &localaddr.sa, &locallen); if (localaddr.sa.sa_family == AF_INET) localaddr.addr4.sin_port = htons(0); + else if (localaddr.sa.sa_family == AF_INET6) + localaddr.addr6.sin6_port = htons(0); if (bind(cptr->authfd, &localaddr.sa, sizeof(localaddr)) == -1) @@ -116,6 +120,13 @@ void start_auth(aClient *cptr) sock.addr4.sin_port = htons(113); sock.addr4.sin_family = AF_INET; } + else if (cptr->ip_family == AF_INET6) + { + memcpy((char *) &sock.addr6.sin6_addr, (char *) &cptr->ip.ip6, + sizeof(struct in6_addr)); + sock.addr6.sin6_port = htons(113); + sock.addr6.sin6_family = AF_INET6; + } if (connect(cptr->authfd, &sock.sa, sizeof(sock)) == -1 && errno != EINPROGRESS) @@ -153,11 +164,13 @@ void send_authports(aClient *cptr) { struct sockaddr sa; struct sockaddr_in addr4; + struct sockaddr_in6 addr6; } us; union { struct sockaddr sa; struct sockaddr_in addr4; + struct sockaddr_in6 addr6; } them; char authbuf[32]; unsigned int ulen = sizeof(us), tlen = sizeof(them); @@ -184,6 +197,14 @@ void send_authports(aClient *cptr) Debug((DEBUG_SEND, "sending [%s] to auth port %s.113", authbuf, inetntoa((char *) &them.sin_addr))); } + else if (us.sa.sa_family == AF_INET6) + { + (void) ircsprintf(authbuf, "%u , %u\r\n", + (unsigned int) ntohs(them.addr6.sin6_port), + (unsigned int) ntohs(us.addr6.sin6_port)); + Debug((DEBUG_SEND, "sending [%s] to auth port %s.113", + authbuf, inet6ntoa((char *) &them.sin_addr))); + } if (send(cptr->authfd, authbuf, strlen(authbuf), 0) != strlen(authbuf)) { authsenderr(cptr); diff --git a/src/s_bsd.c b/src/s_bsd.c index 0c596ec..dc3a231 100644 --- a/src/s_bsd.c +++ b/src/s_bsd.c @@ -276,6 +276,7 @@ int add_listener(aPort *aport) { struct sockaddr sa; struct sockaddr_in addr4; + struct sockaddr_in6 addr6; } server; unsigned int len = sizeof(server); #ifdef USE_SSL @@ -290,9 +291,17 @@ int add_listener(aPort *aport) { strncpyzt(lstn.vhost_string, aport->address, sizeof(lstn.vhost_string)); - server.addr4.sin_family = AF_INET; - server.addr4.sin_addr.s_addr = inet_addr(aport->address); - server.addr4.sin_port = htons(lstn.port); + if (inet_pton(AF_INET6, aport->address, &server.addr6.sin6_addr) == 1) + { + server.addr6.sin6_family = AF_INET6; + server.addr6.sin6_port = htons(lstn.port); + } + else + { + server.addr4.sin_family = AF_INET; + server.addr4.sin_addr.s_addr = inet_addr(aport->address); + server.addr4.sin_port = htons(lstn.port); + } } else { @@ -584,6 +593,7 @@ static int check_init(aClient * cptr, char *sockn) { struct sockaddr sa; struct sockaddr_in addr4; + struct sockaddr_in6 addr6; } sk; unsigned int len = sizeof(sk); @@ -605,6 +615,13 @@ static int check_init(aClient * cptr, char *sockn) cptr->port = (int) (ntohs(sk.addr4.sin_port)); } + else if (sk.sa.sa_family == AF_INET6) + { + strcpy(sockn, (char *) inet6ntoa((char *) &sk.addr6.sin6_addr)); + memcpy((char *) &cptr->ip.ip6, (char *) &sk.addr6.sin6_addr, + sizeof(struct in6_addr)); + cptr->port = (int) (ntohs(sk.addr6.sin6_port)); + } return 0; } @@ -1243,6 +1260,7 @@ aClient *add_connection(aListener *lptr, int fd) { struct sockaddr sa; struct sockaddr_in addr4; + struct sockaddr_in6 addr6; } addr; unsigned int len = sizeof(addr); struct userBan *ban; @@ -1291,6 +1309,14 @@ aClient *add_connection(aListener *lptr, int fd) return NULL; } } + else if (acptr->ip_family == AF_INET6) + { + get_sockhost(acptr, (char *) inet6ntoa((char *) &addr.addr6.sin6_addr)); + memcpy((char *) &acptr->ip.ip6, (char *) &addr.addr6.sin6_addr, + sizeof(struct in6_addr)); + acptr->port = ntohs(addr.addr6.sin6_port); + } + lptr->ccount++; lptr->clients++; @@ -1592,6 +1618,7 @@ void accept_connection(aListener *lptr) { struct sockaddr sa; struct sockaddr_in addr4; + struct sockaddr_in6 addr6; } addr; unsigned int addrlen = sizeof(addr); char host[HOSTLEN + 2]; @@ -1628,6 +1655,11 @@ void accept_connection(aListener *lptr) strncpyzt(host, (char *) inetntoa((char *) &addr.addr4.sin_addr), sizeof(host)); } + else if (addr.sa.sa_family == AF_INET6) + { + strncpyzt(host, (char *) inet6ntoa((char *) &addr.addr6.sin6_addr), + sizeof(host)); + } else { /* unknown address family. */ diff --git a/src/s_user.c b/src/s_user.c index 2a75ee9..17da791 100644 --- a/src/s_user.c +++ b/src/s_user.c @@ -539,8 +539,17 @@ register_user(aClient *cptr, aClient *sptr, char *nick, char *username, /* * Check that the hostname has AT LEAST ONE dot (.) in it. If * not, drop the client (spoofed host) -ThemBones + * + * allow valid IPv6 addresses, though. */ - if (!dots) + if (sptr->ip_family == AF_INET6 && + inet_pton(AF_INET6, user->host, tmpstr2) == 1) + { + bad_dns = NO; + dots = 1; + } + + if (!dots) { sendto_realops("Invalid hostname for %s, dumping user %s", sptr->hostip, sptr->name); diff --git a/src/support.c b/src/support.c index 280f7d0..ebfd144 100644 --- a/src/support.c +++ b/src/support.c @@ -24,6 +24,7 @@ #include "h.h" #include "numeric.h" #include "memcount.h" +#include "inet.h" #define FOREVER for(;;) @@ -130,13 +131,35 @@ char *inetntoa(char *in) return buf; } +/* inet6ntoa - return the string notation of a given IPv6 address. */ +char *inet6ntoa(char *in) +{ + static char buf[HOSTIPLEN + 2]; + + buf[1] = '\0'; + if (inet_ntop(AF_INET6, in, buf + 1, sizeof(buf) - 1)) + { + /* addresses should not start with a ':' character */ + if (buf[1] == ':') + { + buf[0] = '0'; + return buf; + } + } + return buf + 1; +} + /* cipntoa - Return the client IP address as a string. */ char *cipntoa(aClient *cptr) { if (cptr->hostip[0] != '\0') return cptr->hostip; + else if (cptr->ip_family == AF_INET) + return inetntoa((char *)&cptr->ip.ip4); + else if (cptr->ip_family == AF_INET6) + return inet6ntoa((char *)&cptr->ip.ip6); else - return inetntoa((char *)&cptr->ip); + return "invalid.address.family.invalid"; } #if !defined( HAVE_INET_NETOF ) -- 1.7.2.3