From: Felix Morgner Date: Thu, 1 May 2014 07:05:56 +0000 (+0200) Subject: Initial IPv6 support X-Git-Url: http://git.code-monkey.de/?p=umurmur.git;a=commitdiff_plain;h=14130a16fbe48dcba15d6e215ddaa0775074f3a7 Initial IPv6 support Needs testing and maybe cleanup --- diff --git a/src/client.c b/src/client.c index f7d2b70..e3787a4 100644 --- a/src/client.c +++ b/src/client.c @@ -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); diff --git a/src/client.h b/src/client.h index 66470de..f403945 100644 --- a/src/client.h +++ b/src/client.h @@ -121,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); diff --git a/src/server.c b/src/server.c index 722e618..36e2d47 100644 --- a/src/server.c +++ b/src/server.c @@ -47,9 +47,6 @@ #include "timer.h" #include "version.h" -#define LISTEN_SOCK 0 -#define LISTEN_SOCK6 1 - #define TCP_SOCK 0 #define TCP_SOCK6 1 @@ -57,13 +54,14 @@ #define UDP_SOCK6 3 /* globals */ -int udpsock, udpsock6; bool_t shutdown_server; extern char *bindaddr; extern char *bindaddr6; extern int bindport; extern int bindport6; +int* udpsocks; + /* Initialize the address structures for IPv4 and IPv6 */ struct sockaddr_storage** Server_setupAddressesAndPorts() { @@ -104,12 +102,14 @@ void Server_runLoop(struct pollfd* pollfds) Timer_init(&janitorTimer); 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) { @@ -117,7 +117,7 @@ void Server_runLoop(struct pollfd* pollfds) 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); @@ -130,122 +130,150 @@ void Server_runLoop(struct pollfd* pollfds) 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_run() -{ - int rc; - struct pollfd *pollfds; - int tcpsock, tcpsock6, sockopt = 1; - int val; - unsigned short port; - in_addr_t inet_address; - - /* 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"); - - /* Figure out bind address and port */ - struct sockaddr_storage** addresses = Server_setupAddressesAndPorts(); +void Server_setupTCPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds) + { + uint8_t yes = 1; + int error = 0; + int sockets[2]; - /* Prepare TCP sockets */ - tcpsock = socket(PF_INET, SOCK_STREAM, 0); - if (tcpsock < 0) + /* IPv4 socket setup */ + sockets[0] = socket(PF_INET, SOCK_STREAM, 0); + if (sockets[0] < 0) Log_fatal("socket IPv4"); - if (setsockopt(tcpsock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)) != 0) + if (setsockopt(sockets[0], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0) Log_fatal("setsockopt IPv4: %s", strerror(errno)); - - tcpsock6 = socket(PF_INET6, SOCK_STREAM, 0); - if (tcpsock6 < 0) + 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(tcpsock6, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)) != 0) + if (setsockopt(sockets[1], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0) Log_fatal("setsockopt IPv6: %s", strerror(errno)); - if (setsockopt(tcpsock6, IPPROTO_IPV6, IPV6_V6ONLY, &sockopt, sizeof(int)) != 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 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; + } - rc = bind(tcpsock, (struct sockaddr *)addresses[0], sizeof (struct sockaddr_in)); - if (rc < 0) Log_fatal("bind IPv4: %s", strerror(errno)); - rc = listen(tcpsock, 3); - if (rc < 0) Log_fatal("listen IPv4"); - fcntl(tcpsock, F_SETFL, O_NONBLOCK); - - rc = bind(tcpsock6, (struct sockaddr *)addresses[1], sizeof (struct sockaddr_in6)); - if (rc < 0) Log_fatal("bind IPv6: %s", strerror(errno)); - rc = listen(tcpsock6, 3); - if (rc < 0) Log_fatal("listen IPv6"); - fcntl(tcpsock6, F_SETFL, O_NONBLOCK); - - pollfds[LISTEN_SOCK].fd = tcpsock; - pollfds[LISTEN_SOCK].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]; - pollfds[LISTEN_SOCK6].fd = tcpsock; - pollfds[LISTEN_SOCK6].events = POLLIN; + if((udpsocks = malloc(2 * sizeof(int))) == NULL) + Log_fatal("Out of memory (%s:%s)", __FILE__, __LINE__); - /* Prepare UDP sockets */ - udpsock = socket(PF_INET, SOCK_DGRAM, 0); - udpsock6 = socket(PF_INET6, SOCK_DGRAM, 0); + inet_ntop(AF_INET6, &((struct sockaddr_in6*)addresses[1])->sin6_addr, ipv6Representation, sizeof(INET6_ADDRSTRLEN)); - rc = bind(udpsock, (struct sockaddr *) addresses[0], sizeof (struct sockaddr_in)); - if (rc < 0) - Log_fatal("bind %d %s: %s", getIntConf(BINDPORT), getStrConf(BINDADDR), strerror(errno)); + 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; - rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val)); - if (rc < 0) + if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 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) + if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0) Log_warn("Server: Failed to set TOS for UDP Socket"); - fcntl(udpsock, F_SETFL, O_NONBLOCK); - pollfds[UDP_SOCK].fd = udpsock; + fcntl(sockets[0], F_SETFL, O_NONBLOCK); + pollfds[UDP_SOCK].fd = sockets[0]; pollfds[UDP_SOCK].events = POLLIN | POLLHUP | POLLERR; - - if (setsockopt(udpsock6, IPPROTO_IPV6, IPV6_V6ONLY, &sockopt, sizeof(int)) != 0) + 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)); - - rc = bind(udpsock6, (struct sockaddr *) addresses[1], sizeof (struct sockaddr_in6)); - if (rc < 0) - Log_fatal("bind %d %s: %s", getIntConf(BINDPORT), getStrConf(BINDADDR), 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; - rc = setsockopt(udpsock6, IPPROTO_IP, IP_TOS, &val, sizeof(val)); - if (rc < 0) + if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0) Log_warn("Server: Failed to set TOS for UDP Socket"); val = 0x80; - rc = setsockopt(udpsock6, IPPROTO_IP, IP_TOS, &val, sizeof(val)); - if (rc < 0) + if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0) Log_warn("Server: Failed to set TOS for UDP Socket"); - fcntl(udpsock6, F_SETFL, O_NONBLOCK); - pollfds[UDP_SOCK6].fd = udpsock6; + 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);