are met:
- Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
+ this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
- Neither the name of the Developers nor the names of its contributors may
- be used to endorse or promote products derived from this software without
- specific prior written permission.
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
+ */
#include <sys/poll.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include "log.h"
+#include "memory.h"
#include "list.h"
#include "client.h"
#include "ssl.h"
#include "version.h"
#include "voicetarget.h"
#include "ban.h"
+#include "util.h"
extern char system_string[], version_string[];
bool_t bPreferAlpha;
extern int* udpsocks;
+extern bool_t hasv4;
void Client_init()
{
void Client_codec_add(client_t *client, int codec)
{
- codec_t *cd = malloc(sizeof(codec_t));
- if (cd == NULL)
- Log_fatal("Out of memory");
+ codec_t *cd = Memory_safeMalloc(1, sizeof(codec_t));
init_list_entry(&cd->node);
cd->codec = codec;
list_add_tail(&cd->node, &client->codecs);
if (client->tokencount >= MAX_TOKENS)
return;
- token = malloc(sizeof(token_t));
- if (token == NULL)
- Log_fatal("Out of memory");
+ token = Memory_safeMalloc(1, sizeof(token_t));
init_list_entry(&token->node);
token->token = strdup(token_string);
if (token->token == NULL)
client->tokencount++;
}
-bool_t Client_token_match(client_t *client, char *str)
+bool_t Client_token_match(client_t *client, char const *str)
{
token_t *token;
struct dlist *itr;
}
}
if (!found) {
- cd = malloc(sizeof(codec_t));
- if (!cd)
- Log_fatal("Out of memory");
+ cd = Memory_safeMalloc(1, sizeof(codec_t));
memset(cd, 0, sizeof(codec_t));
init_list_entry(&cd->node);
cd->codec = codec_itr->codec;
client_itr = NULL;
while (Client_iterate(&client_itr) != NULL) {
if ((client_itr->authenticated || client_itr == connectingClient) &&
- !client_itr->bOpus) {
+ !client_itr->bOpus) {
Client_textmessage(client_itr, OPUS_WARN_SWITCHING);
}
}
int Client_add(int fd, struct sockaddr_storage *remote)
{
- client_t* newclient;
+ client_t* newclient;
message_t *sendmsg;
- char addressPresentation[INET6_ADDRSTRLEN];
- int port;
+ char* addressString = NULL;
-#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));
+ if (Ban_isBannedAddr(remote)) {
+ addressString = Util_addressToString(remote);
+ Log_info("Address %s banned. Disconnecting", addressString);
+ free(addressString);
return -1;
}
-#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 = Memory_safeCalloc(1, sizeof(client_t));
newclient->tcpfd = fd;
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 on port %d", addressPresentation, port);
+ addressString = Util_addressToString(remote);
+ Log_warn("SSL negotiation failed with %s on port %d", addressString, Util_addressToPort(remote));
+ free(addressString);
free(newclient);
return -1;
}
* 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; */
return 0;
}
else if (SSLi_get_error(client->ssl, rc) == SSLI_ERROR_ZERO_RETURN ||
- SSLi_get_error(client->ssl, rc) == 0) {
+ SSLi_get_error(client->ssl, rc) == 0) {
Log_info_client(client, "Connection closed by peer");
Client_close(client);
}
Log_info_client(client, "Connection closed by peer");
else
Log_info_client(client,"Error: %s - Closing connection (code %d)",
- strerror(errno));
+ strerror(errno));
}
else if (SSLi_get_error(client->ssl, rc) == SSLI_ERROR_CONNRESET) {
Log_info_client(client, "Connection reset by peer");
}
else {
if (SSLi_get_error(client->ssl, rc) == SSLI_ERROR_SYSCALL) {
- Log_info_client(client, "Error: %s - Closing connection", strerror(errno));
+ Log_info_client(client, "Error: %s - Closing connection", strerror(errno));
}
else if (SSLi_get_error(client->ssl, rc) == SSLI_ERROR_CONNRESET) {
Log_info_client(client, "Connection reset by peer");
return Client_send_message(client, msg);
else
Msg_free(msg);
+ return -1;
}
int Client_send_message(client_t *client, message_t *msg)
uint32_t *tree_id;
message_t *sendmsg = NULL;
- message = malloc(strlen(text) + 1);
- if (!message)
- Log_fatal("Out of memory");
- tree_id = malloc(sizeof(uint32_t));
- if (!tree_id)
- Log_fatal("Out of memory");
+ message = Memory_safeMalloc(1, strlen(text) + 1);
+ tree_id = Memory_safeMalloc(1, sizeof(uint32_t));
*tree_id = 0;
sendmsg = Msg_create(TextMessage);
sendmsg->payload.textMessage->message = message;
uint8_t key[KEY_LENGTH];
client_t *itr;
UDPMessageType_t msgType;
- uint8_t fromaddress[4 * sizeof(in_addr_t)];
- uint16_t fromport;
+ uint8_t fromaddress[4 * sizeof(in_addr_t)];
+ uint16_t fromport;
#if defined(__LP64__)
uint8_t encbuff[UDP_PACKET_SIZE + 8];
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) {
+ memset(key, 0, KEY_LENGTH);
+
+ fromport = Util_addressToPort(&from);
+
+ if(from.ss_family == AF_INET) {
+ memcpy(fromaddress, &((struct sockaddr_in*)&from)->sin_addr, sizeof(in_addr_t));
+ 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));
+ memcpy(&key[0], &fromport, 2);
+ memcpy(&key[2], fromaddress, 4 * sizeof(in_addr_t));
+ }
+
+ if (len <= 0)
return -1;
- } else if (len < 5) {
- // 4 bytes crypt header + type + session
- return 0;
- } else if (len > UDP_PACKET_SIZE) {
+ else if (len < 5 || len > UDP_PACKET_SIZE) /* 4 bytes crypt header + type + session */
return 0;
- }
- /* Ping packet */
+ /*
+ * Reply to ping packet
+ * The second and third uint32_t are the timestamp, which will be returned unmodified
+ */
if (len == 12 && *encrypted == 0) {
uint32_t *ping = (uint32_t *)encrypted;
ping[0] = htonl((uint32_t)PROTOCOL_VERSION);
- // 1 and 2 will be the timestamp, which we return unmodified.
ping[3] = htonl((uint32_t)clientcount);
ping[4] = htonl((uint32_t)getIntConf(MAX_CLIENTS));
ping[5] = htonl((uint32_t)getIntConf(MAX_BANDWIDTH));
}
}
if (itr == NULL) { /* Unknown peer */
- struct sockaddr_storage itraddressstorage;
- uint8_t itraddress[4 * sizeof(in_addr_t)];
- int addresslength;
+ struct sockaddr_storage itraddressstorage;
+ uint8_t itraddress[4 * sizeof(in_addr_t)];
+ int addresslength;
while (Client_iterate(&itr) != NULL) {
- 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);
- }
+ 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)) {
memcpy(itr->key, key, KEY_LENGTH);
- Log_info_client(itr, "New UDP connection from %s on port %d", itr->addressString, fromport);
+ char* clientAddressString = Util_clientAddressToString(itr);
+ Log_info_client(itr, "New UDP connection from %s on port %d", clientAddressString, fromport);
+ free(clientAddressString);
memcpy(&itr->remote_udp, &from, sizeof(struct sockaddr_storage));
break;
}
itr->bUDP = true;
len -= 4; /* Adjust for crypt header */
msgType = (UDPMessageType_t)((buffer[0] >> 5) & 0x7);
+
+ char *clientAddressString = NULL;
+
switch (msgType) {
- case UDPVoiceSpeex:
- case UDPVoiceCELTAlpha:
- case UDPVoiceCELTBeta:
- if (bOpus)
+ case UDPVoiceSpeex:
+ case UDPVoiceCELTAlpha:
+ case UDPVoiceCELTBeta:
+ if (bOpus)
+ break;
+ case UDPVoiceOpus:
+ Client_voiceMsg(itr, buffer, len);
+ break;
+ case UDPPing:
+ Log_debug("UDP Ping reply len %d", len);
+ Client_send_udp(itr, buffer, len);
+ break;
+ default:
+ clientAddressString = Util_clientAddressToString(itr);
+ Log_debug("Unknown UDP message type from %s port %d", clientAddressString, fromport);
+ free(clientAddressString);
break;
- case UDPVoiceOpus:
- Client_voiceMsg(itr, buffer, len);
- break;
- case UDPPing:
- Log_debug("UDP Ping reply len %d", len);
- Client_send_udp(itr, buffer, len);
- break;
- default:
- Log_debug("Unknown UDP message type from %s port %d", itr->addressString, fromport);
- break;
}
out:
c = list_get_entry(itr, client_t, chan_node);
Client_send_voice(client, c, buffer, pds->offset + 1, poslen);
}
- } else if ((vt = Voicetarget_get_id(client, target)) != NULL) { /* Targeted whisper */
+ } else if ((vt = Voicetarget_get_id(client, target)) != NULL) { /* Targeted whisper */
int i;
channel_t *ch;
/* Channels */
if (vt->channels[i].linked && !list_empty(&ch->channel_links)) {
struct dlist *ch_itr;
list_iterate(ch_itr, &ch->channel_links) {
+ channellist_t *chl;
channel_t *ch_link;
- ch_link = list_get_entry(ch_itr, channel_t, link_node);
+ chl = list_get_entry(ch_itr, channellist_t, node);
+ ch_link = chl->chan;
list_iterate(itr, &ch_link->clients) {
client_t *c;
c = list_get_entry(itr, client_t, chan_node);
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);
+ int udpsock = (client->remote_udp.ss_family == AF_INET) ? udpsocks[0] : udpsocks[(hasv4) ? 1 : 0];
- if (clientport != 0 && CryptState_isValid(&client->cryptState) &&
+ if (Util_clientAddressToPortUDP(client) != 0 && CryptState_isValid(&client->cryptState) &&
client->bUDP) {
#if defined(__LP64__)
- buf = mbuf = malloc(len + 4 + 16);
+ buf = mbuf = Memory_safeMalloc(1, len + 4 + 16);
buf += 4;
#else
- mbuf = buf = malloc(len + 4);
+ mbuf = buf = Memory_safeMalloc(1, len + 4);
#endif
- if (mbuf == NULL)
- Log_fatal("Out of memory");
-
CryptState_encrypt(&client->cryptState, data, buf, len);
- sendto(udpsock, buf, len + 4, 0, (struct sockaddr *)&client->remote_udp, sizeof(struct sockaddr_in));
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
+ sendto(udpsock, buf, len + 4, 0, (struct sockaddr *)&client->remote_udp, client->remote_tcp.ss_len);
+#else
+ sendto(udpsock, buf, len + 4, 0, (struct sockaddr *)&client->remote_udp, sizeof(struct sockaddr_storage));
+#endif
free(mbuf);
} else {