Merge branch 'gnutls' into ipv6
authorFelix Morgner <felix.morgner@gmail.com>
Thu, 1 May 2014 07:07:48 +0000 (09:07 +0200)
committerFelix Morgner <felix.morgner@gmail.com>
Thu, 1 May 2014 07:07:48 +0000 (09:07 +0200)
src/ban.c
src/ban.h
src/client.c
src/client.h
src/conf.c
src/conf.h
src/log.c
src/main.c
src/messagehandler.c
src/server.c

index e1855de2cb830be0c4d9ff12ab15c8031c90d6a9..e5294ba3f45f2d2229a7d3a45decb5a1377e71cb 100644 (file)
--- a/src/ban.c
+++ b/src/ban.c
@@ -74,8 +74,13 @@ void Ban_UserBan(client_t *client, char *reason)
        memset(ban, 0, sizeof(ban_t));
 
        memcpy(ban->hash, client->hash, 20);
-       memcpy(&ban->address, &client->remote_tcp.sin_addr, sizeof(in_addr_t));
-       ban->mask = 128;
+  if (client->remote_tcp.ss_family == AF_INET) {
+    memcpy(&ban->address, &(((struct sockaddr_in*)&client->remote_tcp)->sin_addr), sizeof(in_addr_t));
+    ban->mask = sizeof(in_addr_t);
+  } else {
+    memcpy(&ban->address, &(((struct sockaddr_in6*)&client->remote_tcp)->sin6_addr), 4 * sizeof(in_addr_t));
+    ban->mask = 4 * sizeof(in_addr_t);
+  }
        ban->reason = strdup(reason);
        ban->name = strdup(client->username);
        ban->time = time(NULL);
@@ -88,8 +93,16 @@ void Ban_UserBan(client_t *client, char *reason)
                Ban_saveBanFile();
 
        SSLi_hash2hex(ban->hash, hexhash);
+
+  char addressPresentation[INET6_ADDRSTRLEN];
+
+  if(client->remote_tcp.ss_family == AF_INET)
+    inet_ntop(AF_INET, &((struct sockaddr_in*)&client->remote_tcp)->sin_addr, addressPresentation, INET6_ADDRSTRLEN);
+  else
+    inet_ntop(AF_INET6, &((struct sockaddr_in6*)&client->remote_tcp)->sin6_addr, addressPresentation, INET6_ADDRSTRLEN);
+
        Log_info_client(client, "User kickbanned. Reason: '%s' Hash: %s IP: %s Banned for: %d seconds",
-                       ban->reason, hexhash, inet_ntoa(*((struct in_addr *)&ban->address)), ban->duration);
+                       ban->reason, hexhash, addressPresentation, ban->duration);
 }
 
 
index 89cd14099c5924ec705ce271acf3ce12189feb5e..98550a4dca5fc9b0f462f2ba5807a37a742fea6b 100644 (file)
--- a/src/ban.h
+++ b/src/ban.h
@@ -38,7 +38,7 @@
 
 typedef struct {
        uint8_t hash[20];
-       in_addr_t address;
+       uint8_t address[16];
        uint32_t mask;
        char *reason;
        char *name;
index f7d2b709d35255a996d21541f20620f16ea6a7f7..e3787a4832d3c1486f3fe2a3779b345e1dddcd1b 100644 (file)
@@ -62,7 +62,7 @@ bool_t bOpus = true;
 int iCodecAlpha, iCodecBeta;
 bool_t bPreferAlpha;
 
-extern int udpsock;
+extern int* udpsocks;
 
 void Client_init()
 {
@@ -317,26 +317,39 @@ static int findFreeSessionId()
        return -1;
 }
 
-int Client_add(int fd, struct sockaddr_in *remote)
+int Client_add(int fd, struct sockaddr_storage *remote)
 {
-       client_t *newclient;
+  client_t* newclient;
        message_t *sendmsg;
+  char addressPresentation[INET6_ADDRSTRLEN];
+  int port;
 
+#warning FIX BANNING BEFORE RELEASE
+#if 0
        if (Ban_isBannedAddr((in_addr_t *)&remote->sin_addr)) {
                Log_info("Address %s banned. Disconnecting", inet_ntoa(remote->sin_addr));
                return -1;
        }
-       newclient = malloc(sizeof(client_t));
-       if (newclient == NULL)
-               Log_fatal("Out of memory");
-       memset(newclient, 0, sizeof(client_t));
+#endif
+
+       if ((newclient = calloc(1, sizeof(client_t))) == NULL)
+               Log_fatal("Out of memory (%s:%s)", __FILE__, __LINE__);
+
+  if(remote->ss_family == AF_INET) {
+    inet_ntop(AF_INET, &((struct sockaddr_in*)remote)->sin_addr, addressPresentation, INET6_ADDRSTRLEN);
+    port = ntohs(((struct sockaddr_in*)remote)->sin_port);
+  } else {
+    inet_ntop(AF_INET6, &((struct sockaddr_in6*)remote)->sin6_addr, addressPresentation, INET6_ADDRSTRLEN);
+    port = ntohs(((struct sockaddr_in6*)remote)->sin6_port);
+  }
+
+  memcpy(newclient->addressString, addressPresentation, INET6_ADDRSTRLEN);
 
        newclient->tcpfd = fd;
-       memcpy(&newclient->remote_tcp, remote, sizeof(struct sockaddr_in));
+       memcpy(&newclient->remote_tcp, remote, sizeof(struct sockaddr_storage));
        newclient->ssl = SSLi_newconnection(&newclient->tcpfd, &newclient->SSLready);
        if (newclient->ssl == NULL) {
-               Log_warn("SSL negotiation failed with %s:%d", inet_ntoa(remote->sin_addr),
-                                ntohs(remote->sin_port));
+               Log_warn("SSL negotiation failed with %s on port %d", addressPresentation, port);
                free(newclient);
                return -1;
        }
@@ -493,8 +506,8 @@ int Client_read(client_t *client)
                                 * 1. A valid size. The only message that is this big is UserState message with a big texture
                                 * 2. An invalid size = protocol error, e.g. connecting with a 1.1.x client
                                 */
-                               Log_warn("Too big message received (%d bytes). Playing safe and disconnecting client %s:%d",
-                                                client->msgsize, inet_ntoa(client->remote_tcp.sin_addr), ntohs(client->remote_tcp.sin_port));
+//                             Log_warn("Too big message received (%d bytes). Playing safe and disconnecting client %s:%d",
+//                                              client->msgsize, inet_ntoa(client->remote_tcp.sin_addr), ntohs(client->remote_tcp.sin_port));
                                Client_free(client);
                                return -1;
                                /* client->rxcount = client->msgsize = 0; */
@@ -751,14 +764,16 @@ static bool_t checkDecrypt(client_t *client, const uint8_t *encrypted, uint8_t *
 }
 
 #define UDP_PACKET_SIZE 1024
-int Client_read_udp()
+int Client_read_udp(int udpsock)
 {
        int len;
-       struct sockaddr_in from;
-       socklen_t fromlen = sizeof(struct sockaddr_in);
-       uint64_t key;
+       struct sockaddr_storage from;
+       socklen_t fromlen = sizeof(struct sockaddr_storage);
+       uint8_t key[KEY_LENGTH];
        client_t *itr;
        UDPMessageType_t msgType;
+  uint8_t fromaddress[4 * sizeof(in_addr_t)];
+  uint16_t fromport;
 
 #if defined(__LP64__)
        uint8_t encbuff[UDP_PACKET_SIZE + 8];
@@ -769,6 +784,21 @@ int Client_read_udp()
        uint8_t buffer[UDP_PACKET_SIZE];
 
        len = recvfrom(udpsock, encrypted, UDP_PACKET_SIZE, MSG_TRUNC, (struct sockaddr *)&from, &fromlen);
+
+  memset(key, 0, KEY_LENGTH);
+
+  if(from.ss_family == AF_INET) {
+    memcpy(fromaddress, &((struct sockaddr_in*)&from)->sin_addr, sizeof(in_addr_t));
+    fromport = ntohs(((struct sockaddr_in*)&from)->sin_port);
+    memcpy(&key[0], &fromport, 2);
+    memcpy(&key[2], fromaddress, sizeof(in_addr_t));
+  } else {
+    memcpy(fromaddress, &((struct sockaddr_in6*)&from)->sin6_addr, 4 * sizeof(in_addr_t));
+    fromport = ntohs(((struct sockaddr_in6*)&from)->sin6_port);
+    memcpy(&key[0], &fromport, 2);
+    memcpy(&key[2], fromaddress, 4 * sizeof(in_addr_t));
+  }
+
        if (len == 0) {
                return -1;
        } else if (len < 0) {
@@ -793,23 +823,35 @@ int Client_read_udp()
                return 0;
        }
 
-       key = (((uint64_t)from.sin_addr.s_addr) << 16) ^ from.sin_port;
        itr = NULL;
 
        while (Client_iterate(&itr) != NULL) {
-               if (itr->key == key) {
+               if (memcmp(itr->key, key, KEY_LENGTH) == 0) {
                        if (!checkDecrypt(itr, encrypted, buffer, len))
                                goto out;
                        break;
                }
        }
        if (itr == NULL) { /* Unknown peer */
+    struct sockaddr_storage itraddressstorage;
+    uint8_t itraddress[4 * sizeof(in_addr_t)];
+    int addresslength;
+
                while (Client_iterate(&itr) != NULL) {
-                       if (itr->remote_tcp.sin_addr.s_addr == from.sin_addr.s_addr) {
+      itraddressstorage = itr->remote_tcp;
+      if(itraddressstorage.ss_family == AF_INET) {
+        memcpy(itraddress, &((struct sockaddr_in*)&from)->sin_addr, sizeof(in_addr_t));
+        addresslength = sizeof(in_addr_t);
+      } else {
+        memcpy(itraddress, &((struct sockaddr_in6*)&from)->sin6_addr, 4 * sizeof(in_addr_t));
+        addresslength = 4 * sizeof(in_addr_t);
+      }
+
+                       if (memcmp(itraddress, fromaddress, addresslength) == 0) {
                                if (checkDecrypt(itr, encrypted, buffer, len)) {
-                                       itr->key = key;
-                                       Log_info_client(itr, "New UDP connection port %d", ntohs(from.sin_port));
-                                       memcpy(&itr->remote_udp, &from, sizeof(struct sockaddr_in));
+                                       memcpy(itr->key, key, KEY_LENGTH);
+                                       Log_info_client(itr, "New UDP connection from %s on port %d", itr->addressString, fromport);
+                                       memcpy(&itr->remote_udp, &from, sizeof(struct sockaddr_storage));
                                        break;
                                }
                        }
@@ -836,7 +878,7 @@ int Client_read_udp()
                Client_send_udp(itr, buffer, len);
                break;
        default:
-               Log_debug("Unknown UDP message type from %s port %d", inet_ntoa(from.sin_addr), ntohs(from.sin_port));
+               Log_debug("Unknown UDP message type from %s port %d", itr->addressString, fromport);
                break;
        }
 
@@ -980,12 +1022,18 @@ out:
        return 0;
 }
 
-
 static int Client_send_udp(client_t *client, uint8_t *data, int len)
 {
        uint8_t *buf, *mbuf;
+  uint16_t clientport;
+  int udpsock = (client->remote_udp.ss_family == AF_INET) ? udpsocks[0] : udpsocks[1];
+
+  if (client->remote_udp.ss_family == AF_INET)
+    clientport = ntohs(((struct sockaddr_in*)&client->remote_udp)->sin_port);
+  else
+    clientport = ntohs(((struct sockaddr_in6*)&client->remote_udp)->sin6_port);
 
-       if (client->remote_udp.sin_port != 0 && CryptState_isValid(&client->cryptState) &&
+       if (clientport != 0 && CryptState_isValid(&client->cryptState) &&
                client->bUDP) {
 #if defined(__LP64__)
                buf = mbuf = malloc(len + 4 + 16);
index c6085d298e6563779f4763f60d4d6f9b0ab284dd..f403945c8a4daf87729d5345188e7fac333e933e 100644 (file)
@@ -55,6 +55,7 @@
 #define MAX_CODECS 10
 #define MAX_TOKENSIZE 64
 #define MAX_TOKENS 32
+#define KEY_LENGTH sizeof(uint16_t) + 4 * sizeof(in_addr_t)
 
 #define IS_AUTH(_a_) ((_a_)->authenticated)
 
@@ -66,12 +67,13 @@ typedef struct {
        cryptState_t cryptState;
        bool_t readBlockedOnWrite, writeBlockedOnRead;
 
-       struct sockaddr_in remote_tcp;
-       struct sockaddr_in remote_udp;
+       struct sockaddr_storage remote_tcp;
+       struct sockaddr_storage remote_udp;
+  char addressString[INET6_ADDRSTRLEN];
        uint8_t rxbuf[BUFSIZE], txbuf[BUFSIZE];
        uint32_t rxcount, msgsize, drainleft, txcount, txsize;
        int sessionId;
-       uint64_t key;
+       uint8_t key[KEY_LENGTH];
        char *username;
        bool_t bUDP, authenticated, deaf, mute, self_deaf, self_mute, recording, bOpus;
        char *os, *release, *os_version;
@@ -109,7 +111,7 @@ typedef struct {
 void Client_init();
 int Client_getfds(struct pollfd *pollfds);
 void Client_janitor();
-int Client_add(int fd, struct sockaddr_in *remote);
+int Client_add(int fd, struct sockaddr_storage *remote);
 int Client_read_fd(int fd);
 int Client_write_fd(int fd);
 int Client_send_message(client_t *client, message_t *msg);
@@ -119,7 +121,7 @@ int Client_count(void);
 void Client_close(client_t *client);
 client_t *Client_iterate(client_t **client);
 int Client_send_message_except(client_t *client, message_t *msg);
-int Client_read_udp(void);
+int Client_read_udp(int udpsock);
 void Client_disconnect_all();
 int Client_voiceMsg(client_t *client, uint8_t *data, int len);
 void recheckCodecVersions(client_t *connectingClient);
index 2c6f56f9ffa5fd404fd2f10618a241cf42488d6c..d716312e444b90615e0be9a1b59efc92f9c0f6fe 100644 (file)
@@ -144,12 +144,23 @@ const char *getStrConf(param_t param)
        case BINDADDR:
                setting = config_lookup(&configuration, "bindaddr");
                if (!setting)
-                       return "";
+                       return NULL;
                else {
                        if ((strsetting = config_setting_get_string(setting)) != NULL)
                                return strsetting;
                        else
-                               return "";
+                               return NULL;
+               }
+               break;
+       case BINDADDR6:
+               setting = config_lookup(&configuration, "bindaddr6");
+               if (!setting)
+                       return NULL;
+               else {
+                       if ((strsetting = config_setting_get_string(setting)) != NULL)
+                               return strsetting;
+                       else
+                               return NULL;
                }
                break;
        case WELCOMETEXT:
@@ -238,6 +249,14 @@ int getIntConf(param_t param)
                        return config_setting_get_int(setting);
                }
                break;
+       case BINDPORT6:
+               setting = config_lookup(&configuration, "bindport6");
+               if (!setting)
+                       return DEFAULT_BINDPORT;
+               else {
+                       return config_setting_get_int(setting);
+               }
+               break;
        case BAN_LENGTH:
                setting = config_lookup(&configuration, "ban_length");
                if (!setting)
index 8253fb330ba3c190f0d6331e2b07671c83bdd81f..8113d85d0c2a1cb7b49563895efd0739aad9decb 100644 (file)
@@ -40,7 +40,9 @@ typedef enum param {
        PASSPHRASE,
        CAPATH,
        BINDPORT,
+  BINDPORT6,
        BINDADDR,
+  BINDADDR6,
        WELCOMETEXT,
        MAX_BANDWIDTH,
        MAX_CLIENTS,
index ebb5cd1c0ae1e4b4965da971df41a3484f538928..17bbe14a56e804bd9aea4b9b68475e06a3cbc088 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -182,6 +182,7 @@ void Log_info_client(client_t *client, const char *logstring, ...)
        va_list argp;
        char buf[STRSIZE + 1];
        int offset = 0;
+  uint16_t port;
 
        if (termprint || logfile)
                offset = sprintf(buf, "INFO: ");
@@ -190,11 +191,17 @@ void Log_info_client(client_t *client, const char *logstring, ...)
        offset += vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp);
        va_end(argp);
 
+  if(client->remote_tcp.ss_family == AF_INET)
+    port = ntohs(((struct sockaddr_in*)&client->remote_tcp)->sin_port);
+  else
+    port = ntohs(((struct sockaddr_in6*)&client->remote_tcp)->sin6_port);
+
        offset += snprintf(&buf[offset], STRSIZE - offset, " - [%d] %s@%s:%d",
                                           client->sessionId,
                                           client->username == NULL ? "" : client->username,
-                                          inet_ntoa(client->remote_tcp.sin_addr),
-                                          ntohs(client->remote_tcp.sin_port));
+                                          client->addressString,
+                                          port);
+
        if (termprint)
                fprintf(stderr, "%s\n", buf);
        else if (logfile)
index bfff28ab0b4696d2d36138aea05796b11c7d736f..ebff0e523163b91fe99ae6594cbcf8bb2014f0d8 100644 (file)
@@ -58,7 +58,9 @@
 
 char system_string[64], version_string[64];
 int bindport;
+int bindport6;
 char *bindaddr;
+char *bindaddr6;
 
 void lockfile(const char *pidfile)
 {
@@ -249,9 +251,9 @@ int main(int argc, char **argv)
 
        /* Arguments */
 #ifdef POSIX_PRIORITY_SCHEDULING
-       while ((c = getopt(argc, argv, "drp:c:a:b:ht")) != EOF) {
+       while ((c = getopt(argc, argv, "drp:c:a:A:b:B:ht")) != EOF) {
 #else
-       while ((c = getopt(argc, argv, "dp:c:a:b:ht")) != EOF) {
+       while ((c = getopt(argc, argv, "dp:c:a:A:b:B:ht")) != EOF) {
 #endif
                switch(c) {
                case 'c':
@@ -263,9 +265,15 @@ int main(int argc, char **argv)
                case 'a':
                        bindaddr = optarg;
                        break;
+    case 'A':
+      bindaddr6 = optarg;
+      break;
                case 'b':
                        bindport = atoi(optarg);
                        break;
+    case 'B':
+      bindport6 = atoi(optarg);
+      break;
                case 'd':
                        nodaemon = true;
                        break;
index f1a753f9e81495764d20f120f9e371ea51959b34..696cad3c6d750f90f642ee2c5aa734b07b9f0be1 100644 (file)
@@ -878,8 +878,11 @@ void Mh_handle_message(client_t *client, message_t *msg)
                                Log_fatal("Out of memory");
                        memset(sendmsg->payload.userStats->address.data, 0, 16);
                        /* ipv4 representation as ipv6 address. Supposedly correct. */
-                       memcpy(&sendmsg->payload.userStats->address.data[12], &target->remote_tcp.sin_addr, 4);
                        memset(&sendmsg->payload.userStats->address.data[10], 0xff, 2); /* IPv4 */
+      if(target->remote_tcp.ss_family == AF_INET)
+        memcpy(&sendmsg->payload.userStats->address.data[12], &((struct sockaddr_in*)&target->remote_tcp)->sin_addr, 4);
+      else
+        memcpy(&sendmsg->payload.userStats->address.data[0], &((struct sockaddr_in6*)&target->remote_tcp)->sin6_addr, 16);
                        sendmsg->payload.userStats->address.len = 16;
                }
                /* BW */
index 05f5213abc058575cd22b1591ecb68553188cf3d..36e2d47af50cd618e2aa069d87ac64bd07cf7382 100644 (file)
 #include "timer.h"
 #include "version.h"
 
-#define LISTEN_SOCK 0
-#define TCP_SOCK 0
-#define UDP_SOCK 1
+#define TCP_SOCK  0
+#define TCP_SOCK6 1
+
+#define UDP_SOCK  2
+#define UDP_SOCK6 3
 
 /* globals */
-int udpsock;
 bool_t shutdown_server;
 extern char *bindaddr;
+extern char *bindaddr6;
 extern int bindport;
+extern int bindport6;
 
-void Server_run()
+int* udpsocks;
+
+/* Initialize the address structures for IPv4 and IPv6 */
+struct sockaddr_storage** Server_setupAddressesAndPorts()
 {
-       int timeout = 1000, rc;
-       struct pollfd *pollfds;
-       int tcpsock, sockopt = 1;
-       struct sockaddr_in sin;
-       int val, clientcount;
-       etimer_t janitorTimer;
-       unsigned short port;
-       in_addr_t inet_address;
+  struct sockaddr_storage** addresses = malloc(2 * sizeof(void*));
 
-       /* max clients + listen sock + udp sock + client connecting that will be disconnected */
-       pollfds = malloc((getIntConf(MAX_CLIENTS) + 3) * sizeof(struct pollfd));
-       if (pollfds == NULL)
-               Log_fatal("out of memory");
+  struct sockaddr_storage* v4address = calloc(1, sizeof(struct sockaddr_storage));
+  v4address->ss_family = AF_INET;
+  v4address->ss_len = sizeof(struct sockaddr_storage);
+  struct sockaddr_storage* v6address = calloc(1, sizeof(struct sockaddr_storage));
+  v6address->ss_family = AF_INET6;
+  v6address->ss_len = sizeof(struct sockaddr_storage);
 
-       /* Figure out bind address and port */
-       if (bindport != 0)
-               port = htons(bindport);
-       else
-               port = htons(getIntConf(BINDPORT));
-
-       if (bindaddr != NULL && inet_addr(bindaddr) != -1)
-               inet_address = inet_addr(bindaddr);
-       else if (inet_addr(getStrConf(BINDADDR)) !=  -1)
-               inet_address = inet_addr(getStrConf(BINDADDR));
-       else
-               inet_address = inet_addr("0.0.0.0");
-       Log_info("Bind to %s:%hu", inet_address == 0 ? "*" : inet_ntoa(*((struct in_addr *)&inet_address)), ntohs(port));
-
-       /* Prepare TCP socket */
-       memset(&sin, 0, sizeof(sin));
-       tcpsock = socket(PF_INET, SOCK_STREAM, 0);
-       if (tcpsock < 0)
-               Log_fatal("socket");
-       if (setsockopt(tcpsock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)) != 0)
-               Log_fatal("setsockopt: %s", strerror(errno));
-       sin.sin_family = AF_INET;
-       sin.sin_port = port;
-       sin.sin_addr.s_addr = inet_address;
-
-       rc = bind(tcpsock, (struct sockaddr *) &sin, sizeof (struct sockaddr_in));
-       if (rc < 0) Log_fatal("bind: %s", strerror(errno));
-       rc = listen(tcpsock, 3);
-       if (rc < 0) Log_fatal("listen");
-       fcntl(tcpsock, F_SETFL, O_NONBLOCK);
-
-       pollfds[LISTEN_SOCK].fd = tcpsock;
-       pollfds[LISTEN_SOCK].events = POLLIN;
-
-       /* Prepare UDP socket */
-       memset(&sin, 0, sizeof(sin));
-       udpsock = socket(PF_INET, SOCK_DGRAM, 0);
-       sin.sin_family = AF_INET;
-       sin.sin_port = port;
-       sin.sin_addr.s_addr = inet_address;
-
-       rc = bind(udpsock, (struct sockaddr *) &sin, sizeof (struct sockaddr_in));
-       if (rc < 0)
-               Log_fatal("bind %d %s: %s", getIntConf(BINDPORT), getStrConf(BINDADDR), strerror(errno));
-       val = 0xe0;
-       rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val));
-       if (rc < 0)
-               Log_warn("Server: Failed to set TOS for UDP Socket");
-       val = 0x80;
-       rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val));
-       if (rc < 0)
-               Log_warn("Server: Failed to set TOS for UDP Socket");
+  int error = 0;
 
-       fcntl(udpsock, F_SETFL, O_NONBLOCK);
-       pollfds[UDP_SOCK].fd = udpsock;
-       pollfds[UDP_SOCK].events = POLLIN | POLLHUP | POLLERR;
+  const char* confadd = getStrConf(BINDADDR);
+  error = inet_pton(AF_INET, (!bindaddr) ? ((getStrConf(BINDADDR)) ? getStrConf(BINDADDR) : "0.0.0.0")
+                                         : bindaddr, &(((struct sockaddr_in*)v4address)->sin_addr));
+  if (error == 0) Log_fatal("Invalid IPv4 address supplied!");
 
-       Timer_init(&janitorTimer);
+  error = inet_pton(AF_INET6, (!bindaddr6) ? ((getStrConf(BINDADDR6)) ? getStrConf(BINDADDR6) : "::")
+                                         : bindaddr6, &(((struct sockaddr_in6*)v6address)->sin6_addr));
+  if (error == 0) Log_fatal("Invalid IPv6 address supplied!");
 
-       Log_info("uMurmur version %s ('%s') protocol version %d.%d.%d",
-                UMURMUR_VERSION, UMURMUR_CODENAME, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH);
-       Log_info("Visit http://code.google.com/p/umurmur/");
+  ((struct sockaddr_in*)v4address)->sin_port = htons((bindport) ? bindport : getIntConf(BINDPORT));
+  ((struct sockaddr_in6*)v6address)->sin6_port = htons((bindport6) ? bindport6 : getIntConf(BINDPORT6));
+
+  addresses[0] = v4address;
+  addresses[1] = v6address;
+
+  return addresses;
+}
+
+void Server_runLoop(struct pollfd* pollfds)
+  {
+  int timeout = 1000, rc, clientcount;
+
+       etimer_t janitorTimer;
+       Timer_init(&janitorTimer);
 
-       /* Main server loop */
        while (!shutdown_server) {
-               struct sockaddr_in remote;
+               struct sockaddr_storage remote;
                int i;
 
                pollfds[UDP_SOCK].revents = 0;
+               pollfds[UDP_SOCK6].revents = 0;
                pollfds[TCP_SOCK].revents = 0;
-               clientcount = Client_getfds(&pollfds[2]);
+               pollfds[TCP_SOCK6].revents = 0;
+               clientcount = Client_getfds(&pollfds[4]);
 
                timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
                if (timeout <= 0) {
@@ -151,7 +117,7 @@ void Server_run()
                        Timer_restart(&janitorTimer);
                        timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL;
                }
-               rc = poll(pollfds, clientcount + 2, timeout);
+               rc = poll(pollfds, clientcount + 4, timeout);
                if (rc == 0) { /* Timeout */
                        /* Do maintenance */
                        Timer_restart(&janitorTimer);
@@ -164,35 +130,164 @@ void Server_run()
                        else
                                Log_fatal("poll: error %d", errno);
                }
-               if (pollfds[LISTEN_SOCK].revents) { /* New tcp connection */
+               if (pollfds[TCP_SOCK].revents) { /* New tcp connection */
                        int tcpfd, flag = 1;
                        uint32_t addrlen;
                        addrlen = sizeof(struct sockaddr_in);
-                       tcpfd = accept(pollfds[LISTEN_SOCK].fd, (struct sockaddr*)&remote, &addrlen);
+                       tcpfd = accept(pollfds[TCP_SOCK].fd, (struct sockaddr*)&remote, &addrlen);
+                       fcntl(tcpfd, F_SETFL, O_NONBLOCK);
+                       setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
+      Log_debug("Connection from %s port %d\n", inet_ntoa(((struct sockaddr_in*)&remote)->sin_addr),
+                                         ntohs(((struct sockaddr_in*)&remote)->sin_port));
+                       if (Client_add(tcpfd, &remote) < 0)
+                               close(tcpfd);
+               }
+
+               if (pollfds[TCP_SOCK6].revents) { /* New tcp connection */
+                       int tcpfd, flag = 1;
+                       uint32_t addrlen;
+                       addrlen = sizeof(struct sockaddr_in6);
+                       tcpfd = accept(pollfds[TCP_SOCK6].fd, (struct sockaddr*)&remote, &addrlen);
                        fcntl(tcpfd, F_SETFL, O_NONBLOCK);
                        setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
-                       Log_debug("Connection from %s port %d\n", inet_ntoa(remote.sin_addr),
-                                         ntohs(remote.sin_port));
                        if (Client_add(tcpfd, &remote) < 0)
                                close(tcpfd);
                }
 
                if (pollfds[UDP_SOCK].revents) {
-                       Client_read_udp();
+                       Client_read_udp(udpsocks[0]);
+               }
+               if (pollfds[UDP_SOCK6].revents) {
+                       Client_read_udp(udpsocks[1]);
                }
                for (i = 0; i < clientcount; i++) {
-                       if (pollfds[i + 2].revents & POLLIN) {
-                               Client_read_fd(pollfds[i + 2].fd);
+                       if (pollfds[i + 4].revents & POLLIN) {
+                               Client_read_fd(pollfds[i + 4].fd);
                        }
-                       if (pollfds[i + 2].revents & POLLOUT) {
-                               Client_write_fd(pollfds[i + 2].fd);
+                       if (pollfds[i + 4].revents & POLLOUT) {
+                               Client_write_fd(pollfds[i + 4].fd);
                        }
                }
        }
+  free(udpsocks);
+  }
+
+void Server_setupTCPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds)
+  {
+  uint8_t yes = 1;
+  int error = 0;
+  int sockets[2];
+
+  /* IPv4 socket setup */
+       sockets[0] = socket(PF_INET, SOCK_STREAM, 0);
+       if (sockets[0] < 0)
+               Log_fatal("socket IPv4");
+       if (setsockopt(sockets[0], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0)
+               Log_fatal("setsockopt IPv4: %s", strerror(errno));
+       if (bind(sockets[0], (struct sockaddr *)addresses[0], sizeof (struct sockaddr_in)) < 0)
+    Log_fatal("bind IPv4: %s", strerror(errno));
+       if (listen(sockets[0], 3) < 0)
+    Log_fatal("listen IPv4");
+       fcntl(sockets[0], F_SETFL, O_NONBLOCK);
+
+       pollfds[TCP_SOCK].fd = sockets[0];
+       pollfds[TCP_SOCK].events = POLLIN;
+
+  /* IPv6 socket setup */
+       sockets[1] = socket(PF_INET6, SOCK_STREAM, 0);
+       if (sockets[1] < 0)
+               Log_fatal("socket IPv6");
+       if (setsockopt(sockets[1], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0)
+               Log_fatal("setsockopt IPv6: %s", strerror(errno));
+       if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(int)) != 0)
+               Log_fatal("setsockopt IPv6: %s", strerror(errno));
+       if (bind(sockets[1], (struct sockaddr *)addresses[1], sizeof (struct sockaddr_in6)) < 0)
+    Log_fatal("bind IPv6: %s", strerror(errno));
+       if (listen(sockets[1], 3) < 0)
+    Log_fatal("listen IPv6");
+       fcntl(sockets[1], F_SETFL, O_NONBLOCK);
+
+       pollfds[TCP_SOCK6].fd = sockets[1];
+       pollfds[TCP_SOCK6].events = POLLIN;
+  }
+
+void Server_setupUDPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds)
+  {
+  uint8_t yes = 1;
+  int val = 0;
+  int error = 0;
+  int sockets[2];
+  char ipv6Representation[INET6_ADDRSTRLEN];
+
+  if((udpsocks = malloc(2 * sizeof(int))) == NULL)
+    Log_fatal("Out of memory (%s:%s)", __FILE__, __LINE__);
+
+  inet_ntop(AF_INET6, &((struct sockaddr_in6*)addresses[1])->sin6_addr, ipv6Representation, sizeof(INET6_ADDRSTRLEN));
+
+  sockets[0] = socket(PF_INET, SOCK_DGRAM, 0);
+       if (bind(sockets[0], (struct sockaddr *) addresses[0], sizeof (struct sockaddr_in)) < 0)
+               Log_fatal("bind %d %s: %s", ((struct sockaddr_in*)addresses[0])->sin_port,
+              inet_ntoa(((struct sockaddr_in*)addresses[0])->sin_addr), strerror(errno));
+       val = 0xe0;
+       if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0)
+               Log_warn("Server: Failed to set TOS for UDP Socket");
+       val = 0x80;
+       if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0)
+               Log_warn("Server: Failed to set TOS for UDP Socket");
+
+       fcntl(sockets[0], F_SETFL, O_NONBLOCK);
+       pollfds[UDP_SOCK].fd = sockets[0];
+       pollfds[UDP_SOCK].events = POLLIN | POLLHUP | POLLERR;
+
+  sockets[1] = socket(PF_INET6, SOCK_DGRAM, 0);
+       if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(int)) != 0)
+               Log_fatal("setsockopt IPv6: %s", strerror(errno));
+       if (bind(sockets[1], (struct sockaddr *) addresses[1], sizeof (struct sockaddr_in6)) < 0)
+               Log_fatal("bind %d %s: %s", ((struct sockaddr_in*)addresses[1])->sin_port, ipv6Representation, strerror(errno));
+       val = 0xe0;
+       if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0)
+               Log_warn("Server: Failed to set TOS for UDP Socket");
+       val = 0x80;
+       if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0)
+               Log_warn("Server: Failed to set TOS for UDP Socket");
+
+       fcntl(sockets[1], F_SETFL, O_NONBLOCK);
+       pollfds[UDP_SOCK6].fd = sockets[1];
+       pollfds[UDP_SOCK6].events = POLLIN | POLLHUP | POLLERR;
+  udpsocks[0] = sockets[0];
+  udpsocks[1] = sockets[1];
+  }
+
+void Server_run()
+{
+       struct pollfd *pollfds;
+
+       /* max clients + listen sock + udp sock + client connecting that will be disconnected */
+       if ((pollfds = calloc((getIntConf(MAX_CLIENTS) + 5) , sizeof(struct pollfd))) == NULL)
+               Log_fatal("out of memory");
+
+       /* Figure out bind address and port */
+  struct sockaddr_storage** addresses = Server_setupAddressesAndPorts();
+
+       /* Prepare TCP sockets */
+  Server_setupTCPSockets(addresses, pollfds);
+
+       /* Prepare UDP sockets */
+  Server_setupUDPSockets(addresses, pollfds);
+
+       Log_info("uMurmur version %s ('%s') protocol version %d.%d.%d",
+                UMURMUR_VERSION, UMURMUR_CODENAME, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH);
+       Log_info("Visit http://code.google.com/p/umurmur/");
+
+       /* Main server loop */
+  Server_runLoop(pollfds);
 
-       /* Disconnect clients */
+       /* Disconnect clients and cleanup memory */
        Client_disconnect_all();
        free(pollfds);
+  free(addresses[0]);
+  free(addresses[1]);
+  free(addresses);
 }
 
 void Server_shutdown()