migrate joinServer, update

This commit is contained in:
Protryon 2019-04-17 06:04:44 -07:00
parent b0b43eed0b
commit f714ecea98
10 changed files with 275 additions and 257 deletions

View File

@ -9,7 +9,7 @@ bind-port = 25565
#OR
#bind-file = basin.sock
threads = 5
max-players = 20
max-players_by_entity_id = 20
motd = A Minecraft Server
level-seed =
online-mode = false

View File

@ -23,7 +23,7 @@ struct connection {
uint16_t host_port;
struct player* player;
int disconnect;
uint32_t protocolVersion;
uint32_t protocol_version;
uint32_t verifyToken;
char* online_username;
uint8_t shared_secret[16];

View File

@ -57,7 +57,7 @@ struct player {
uint8_t spawnedIn;
size_t llTick;
uint8_t triggerRechunk;
uint32_t protocolVersion;
uint32_t protocol_version;
uint16_t chunksSent;
float reachDistance;
acstate_t acstate;

View File

@ -43,8 +43,8 @@ struct plugin {
float (*onEntityAttacked)(struct world* world, struct entity* attacker, uint8_t slot_index, struct slot* slot, struct entity* attacked, float damage); // called when a player attacks an entity return = damage, 0 for cancel.
float (*onEntityDamaged)(struct world* world, struct entity* entity, float damage); // called when any entity is damaged for any reason.
int (*onInventoryUpdate)(struct world* world, struct player* player, struct inventory* inventory, int16_t slot, struct slot* item);
int (*onPacketReceive)(int state, struct conn* conn, struct packet* packet); // UNSAFE! breaks protocol intercompatibilty - check conn->protocolVersion setting return = drop packet
int (*onPacketSend)(int state, struct conn* conn, struct packet* packet); // UNSAFE! breaks protocol intercompatibilty - check conn->protocolVersion setting return = drop packet
int (*onPacketReceive)(int state, struct conn* conn, struct packet* packet); // UNSAFE! breaks protocol intercompatibilty - check conn->protocol_version setting return = drop packet
int (*onPacketSend)(int state, struct conn* conn, struct packet* packet); // UNSAFE! breaks protocol intercompatibilty - check conn->protocol_version setting return = drop packet
void (*onEntitySpawn)(struct world* world, struct entity* entity); // called after an entity spawns
void (*onPlayerSpawn)(struct world* world, struct player* player); // called after a player spawns
void (*onPlayerFullySpawned)(struct world* world, struct player* player); // called after a player spawns and has moved

View File

@ -26,7 +26,7 @@ struct server {
struct world* endworld;
struct list* worlds;
struct queue* prepared_connections;
struct hashmap* players;
struct hashmap* players_by_entity_id;
// struct queue* playersToLoad;
};

View File

@ -113,7 +113,7 @@ void command_list(struct player* player, char** args, size_t args_count) {
struct player* player = (struct player*) value;
cptr = xstrncat(cptr, 16, player->name);
END_HASHMAP_ITERATION (players)
snprintf(cptr, 32, " (%lu players total)", players->entry_count);
snprintf(cptr, 32, " (%lu players_by_entity_id total)", players->entry_count);
sendMessageToPlayer(player, plist, "gray");
xfree(plist);
}

View File

@ -8,14 +8,181 @@
#include <basin/packet.h>
#include <basin/globals.h>
#include <basin/version.h>
#include <basin/game.h>
#include <avuna/string.h>
#include <avuna/json.h>
#include <avuna/util.h>
#include <avuna/pmem_hooks.h>
#include <openssl/ssl.h>
#include <openssl/md5.h>
#include <netdb.h>
#include <arpa/inet.h>
int work_joinServer(struct connection* conn, struct mempool* pool, char* username, char* uuid_string) {
struct uuid uuid;
unsigned char* uuidx = (unsigned char*) &uuid;
if (uuid_string == NULL) {
if (conn->server->online_mode) return 1;
MD5_CTX context;
MD5_Init(&context);
MD5_Update(&context, username, strlen(username));
MD5_Final(uuidx, &context);
} else {
if (strlen(uuid_string) != 32) return 1;
char ups[9];
memcpy(ups, uuid_string, 8);
ups[8] = 0;
uuid.uuid1 = ((uint64_t) strtoll(ups, NULL, 16)) << 32;
memcpy(ups, uuid_string + 8, 8);
uuid.uuid1 |= ((uint64_t) strtoll(ups, NULL, 16)) & 0xFFFFFFFF;
memcpy(ups, uuid_string + 16, 8);
uuid.uuid2 = ((uint64_t) strtoll(ups, NULL, 16)) << 32;
memcpy(ups, uuid_string + 24, 8);
uuid.uuid2 |= ((uint64_t) strtoll(ups, NULL, 16)) & 0xFFFFFFFF;
}
struct packet* resp = packet_new(pool, PKT_LOGIN_CLIENT_LOGINSUCCESS);
resp->data.login_client.loginsuccess.username = username;
resp->data.login_client.loginsuccess.uuid = pmalloc(pool, 38);
snprintf(resp->data.login_client.loginsuccess.uuid, 10, "%08X-", ((uint32_t*) uuidx)[0]);
snprintf(resp->data.login_client.loginsuccess.uuid + 9, 6, "%04X-", ((uint16_t*) uuidx)[2]);
snprintf(resp->data.login_client.loginsuccess.uuid + 14, 6, "%04X-", ((uint16_t*) uuidx)[3]);
snprintf(resp->data.login_client.loginsuccess.uuid + 19, 6, "%04X-", ((uint16_t*) uuidx)[4]);
snprintf(resp->data.login_client.loginsuccess.uuid + 24, 9, "%08X", ((uint32_t*) (uuidx + 4))[2]);
snprintf(resp->data.login_client.loginsuccess.uuid + 32, 5, "%04X", ((uint16_t*) uuidx)[7]);
if (packet_write(conn, resp) < 0) {
return 1;
}
conn->protocol_state = STATE_PLAY;
struct entity* ep = newEntity(nextEntityID++, (double) conn->server->overworld->spawnpos.x + .5, (double) conn->server->overworld->spawnpos.y, (double) conn->server->overworld->spawnpos.z + .5, ENT_PLAYER, 0., 0.);
struct player* player = newPlayer(ep, str_dup(resp->data.login_client.loginsuccess.username, 1, pool), uuid, conn, 0); // TODO default gamemode
player->protocol_version = conn->protocol_version;
conn->player = player;
hashmap_putint(conn->server->players_by_entity_id, (uint64_t) player->entity->id, player);
resp->id = PKT_PLAY_CLIENT_JOINGAME;
resp->data.play_client.joingame.entity_id = ep->id;
resp->data.play_client.joingame.gamemode = player->gamemode;
resp->data.play_client.joingame.dimension = conn->server->overworld->dimension;
resp->data.play_client.joingame.difficulty = (uint8_t) conn->server->difficulty;
resp->data.play_client.joingame.max_players = (uint8_t) conn->server->max_players;
resp->data.play_client.joingame.level_type = conn->server->overworld->levelType;
resp->data.play_client.joingame.reduced_debug_info = 0; // TODO
if (packet_write(conn, resp) < 0) {
return 1;
}
resp->id = PKT_PLAY_CLIENT_PLUGINMESSAGE;
resp->data.play_client.pluginmessage.channel = "MC|Brand";
resp->data.play_client.pluginmessage.data = pmalloc(pool, 16);
size_t str_length_length = (size_t) writeVarInt(5, (unsigned char*) resp->data.play_client.pluginmessage.data);
memcpy(resp->data.play_client.pluginmessage.data + str_length_length, "Basin", 5);
resp->data.play_client.pluginmessage.data_size = str_length_length + 5;
if (packet_write(conn, resp) < 0) {
return 1;
}
resp->id = PKT_PLAY_CLIENT_SERVERDIFFICULTY;
resp->data.play_client.serverdifficulty.difficulty = (uint8_t) conn->server->difficulty;
if (packet_write(conn, resp) < 0) {
return 1;
}
resp->id = PKT_PLAY_CLIENT_SPAWNPOSITION;
memcpy(&resp->data.play_client.spawnposition.location, &conn->server->overworld->spawnpos, sizeof(struct encpos));
if (packet_write(conn, resp) < 0) {
return 1;
}
resp->id = PKT_PLAY_CLIENT_PLAYERABILITIES;
resp->data.play_client.playerabilities.flags = 0; // TODO: allows flying, remove
resp->data.play_client.playerabilities.flying_speed = 0.05;
resp->data.play_client.playerabilities.field_of_view_modifier = .1;
if (packet_write(conn, resp) < 0) {
return 1;
}
resp->id = PKT_PLAY_CLIENT_PLAYERPOSITIONANDLOOK;
resp->data.play_client.playerpositionandlook.x = ep->x;
resp->data.play_client.playerpositionandlook.y = ep->y;
resp->data.play_client.playerpositionandlook.z = ep->z;
resp->data.play_client.playerpositionandlook.yaw = ep->yaw;
resp->data.play_client.playerpositionandlook.pitch = ep->pitch;
resp->data.play_client.playerpositionandlook.flags = 0x0;
resp->data.play_client.playerpositionandlook.teleport_id = 0;
if (packet_write(conn, resp) < 0) {
return 1;
}
resp->id = PKT_PLAY_CLIENT_PLAYERLISTITEM;
pthread_rwlock_rdlock(&conn->server->players_by_entity_id->rwlock);
resp->data.play_client.playerlistitem.action_id = 0;
resp->data.play_client.playerlistitem.number_of_players = (int32_t) (conn->server->players_by_entity_id->entry_count + 1);
resp->data.play_client.playerlistitem.players = pmalloc(pool, resp->data.play_client.playerlistitem.number_of_players * sizeof(struct listitem_player));
size_t players_written = 0;
ITER_MAP(conn->server->players_by_entity_id) {
struct player* iter_player = (struct player*) value;
if (players_written < resp->data.play_client.playerlistitem.number_of_players) {
memcpy(&resp->data.play_client.playerlistitem.players[players_written].uuid, &iter_player->uuid, sizeof(struct uuid));
resp->data.play_client.playerlistitem.players[players_written].action.addplayer.name = iter_player->name;
resp->data.play_client.playerlistitem.players[players_written].action.addplayer.number_of_properties = 0;
resp->data.play_client.playerlistitem.players[players_written].action.addplayer.properties = NULL;
resp->data.play_client.playerlistitem.players[players_written].action.addplayer.gamemode = iter_player->gamemode;
resp->data.play_client.playerlistitem.players[players_written].action.addplayer.ping = 0; // TODO
resp->data.play_client.playerlistitem.players[players_written].action.addplayer.has_display_name = 0;
resp->data.play_client.playerlistitem.players[players_written].action.addplayer.display_name = NULL;
players_written++;
}
if (player == iter_player) continue;
struct packet* pkt = packet_new(mempool_new(), PKT_PLAY_CLIENT_PLAYERLISTITEM);
pkt->data.play_client.playerlistitem.action_id = 0;
pkt->data.play_client.playerlistitem.number_of_players = 1;
pkt->data.play_client.playerlistitem.players = pmalloc(pkt->pool, sizeof(struct listitem_player));
memcpy(&pkt->data.play_client.playerlistitem.players->uuid, &player->uuid, sizeof(struct uuid));
pkt->data.play_client.playerlistitem.players->action.addplayer.name = str_dup(player->name, 0, pkt->pool);
pkt->data.play_client.playerlistitem.players->action.addplayer.number_of_properties = 0;
pkt->data.play_client.playerlistitem.players->action.addplayer.properties = NULL;
pkt->data.play_client.playerlistitem.players->action.addplayer.gamemode = player->gamemode;
pkt->data.play_client.playerlistitem.players->action.addplayer.ping = 0; // TODO
pkt->data.play_client.playerlistitem.players->action.addplayer.has_display_name = 0;
pkt->data.play_client.playerlistitem.players->action.addplayer.display_name = NULL;
queue_push(iter_player->outgoingPacket, pkt);
flush_outgoing(iter_player);
ITER_MAP_END();
}
pthread_rwlock_unlock(&conn->server->players_by_entity_id->rwlock);
memcpy(&resp->data.play_client.playerlistitem.players[players_written].uuid, &player->uuid, sizeof(struct uuid));
resp->data.play_client.playerlistitem.players[players_written].action.addplayer.name = player->name;
resp->data.play_client.playerlistitem.players[players_written].action.addplayer.number_of_properties = 0;
resp->data.play_client.playerlistitem.players[players_written].action.addplayer.properties = NULL;
resp->data.play_client.playerlistitem.players[players_written].action.addplayer.gamemode = player->gamemode;
resp->data.play_client.playerlistitem.players[players_written].action.addplayer.ping = 0; // TODO
resp->data.play_client.playerlistitem.players[players_written].action.addplayer.has_display_name = 0;
resp->data.play_client.playerlistitem.players[players_written].action.addplayer.display_name = NULL;
players_written++;
if (packet_write(conn, resp) < 0) {
return 1;
}
resp->id = PKT_PLAY_CLIENT_TIMEUPDATE;
resp->data.play_client.timeupdate.time_of_day = conn->server->overworld->time;
resp->data.play_client.timeupdate.world_age = conn->server->overworld->age;
if (packet_write(conn, resp) < 0) {
return 1;
}
add_collection(playersToLoad, player);
broadcastf("yellow", "%s has joined the server!", player->name);
const char* ip_string = NULL;
char tip[48];
if (conn->addr.in6.sin6_family == AF_INET) {
ip_string = inet_ntop(AF_INET, &conn->addr.in.sin_addr, tip, 48);
} else if (conn->addr.in6.sin6_family == AF_INET6) {
if (memseq((unsigned char*) &conn->addr.in6.sin6_addr, 10, 0) && memseq((unsigned char*) &conn->addr.in6.sin6_addr + 10, 2, 0xff)) {
ip_string = inet_ntop(AF_INET, ((unsigned char*) &conn->addr.in6.sin6_addr) + 12, tip, 48);
} else ip_string = inet_ntop(AF_INET6, &conn->addr.in6.sin6_addr, tip, 48);
} else {
ip_string = "UNKNOWN";
}
printf("Player '%s' has joined with IP '%s'\n", player->name, ip_string);
return 0;
}
int handle_packet_handshake(struct connection* conn, struct packet* packet) {
conn->host_ip = str_dup(packet->data.handshake_server.handshake.server_address, 0, conn->pool);
conn->host_port = packet->data.handshake_server.handshake.server_port;
conn->protocolVersion = (uint32_t) packet->data.handshake_server.handshake.protocol_version;
conn->protocol_version = (uint32_t) packet->data.handshake_server.handshake.protocol_version;
if ((packet->data.handshake_server.handshake.protocol_version < MC_PROTOCOL_VERSION_MIN || packet->data.handshake_server.handshake.protocol_version > MC_PROTOCOL_VERSION_MAX) && packet->data.handshake_server.handshake.next_state != STATE_STATUS) return -2;
if (packet->data.handshake_server.handshake.next_state == STATE_STATUS) {
conn->protocol_state = STATE_STATUS;
@ -30,7 +197,7 @@ int handle_packet_status(struct connection* conn, struct packet* packet) {
struct packet* resp = packet_new(packet->pool, PKT_STATUS_CLIENT_RESPONSE);
resp->data.status_client.response.json_response = pmalloc(packet->pool, 1000);
resp->data.status_client.response.json_response[999] = 0;
snprintf(resp->data.status_client.response.json_response, 999, "{\"version\":{\"name\":\"1.11.2\",\"protocol\":%i},\"players\":{\"max\":%lu,\"online\":%lu},\"description\":{\"text\":\"%s\"}}", MC_PROTOCOL_VERSION_MIN, conn->server->max_players, conn->server->players->entry_count, conn->server->motd);
snprintf(resp->data.status_client.response.json_response, 999, "{\"version\":{\"name\":\"1.11.2\",\"protocol\":%i},\"players_by_entity_id\":{\"max\":%lu,\"online\":%lu},\"description\":{\"text\":\"%s\"}}", MC_PROTOCOL_VERSION_MIN, conn->server->max_players, conn->server->players_by_entity_id->entry_count, conn->server->motd);
if (packet_write(conn, resp) < 0) return 1;
} else if (packet->id == PKT_STATUS_SERVER_PING) {
struct packet* resp = packet_new(packet->pool, PKT_STATUS_CLIENT_PONG);
@ -55,145 +222,146 @@ void decrypt_free(EVP_CIPHER_CTX* ctx) {
}
int handle_encryption_response(struct connection* conn, struct packet* packet) {
if (conn->verifyToken == 0 || packet->data.login_server.encryptionresponse.shared_secret_length > 162 || packet->data.login_server.encryptionresponse.verify_token_length > 162) goto rete;
unsigned char decSecret[162];
int secLen = RSA_private_decrypt(packet->data.login_server.encryptionresponse.shared_secret_length, packet->data.login_server.encryptionresponse.shared_secret, decSecret, public_rsa, RSA_PKCS1_PADDING);
if (secLen != 16) goto rete;
unsigned char decVerifyToken[162];
int vtLen = RSA_private_decrypt(packet->data.login_server.encryptionresponse.verify_token_length, packet->data.login_server.encryptionresponse.verify_token, decVerifyToken, public_rsa, RSA_PKCS1_PADDING);
if (vtLen != 4) goto rete;
uint32_t vt = *((uint32_t*) decVerifyToken);
if (vt != conn->verifyToken) goto rete;
memcpy(conn->shared_secret, decSecret, 16);
uint8_t pubkey[162];
memcpy(pubkey, public_rsa_publickey, 162);
if (conn->verifyToken == 0 || packet->data.login_server.encryptionresponse.shared_secret_length > 162 || packet->data.login_server.encryptionresponse.verify_token_length > 162) {
return 1;
}
unsigned char shared_secret[162];
int secret_length = RSA_private_decrypt(packet->data.login_server.encryptionresponse.shared_secret_length, packet->data.login_server.encryptionresponse.shared_secret, shared_secret, public_rsa, RSA_PKCS1_PADDING);
if (secret_length != 16) {
return 1;
}
unsigned char verify_token[162];
int verify_token_length = RSA_private_decrypt(packet->data.login_server.encryptionresponse.verify_token_length, packet->data.login_server.encryptionresponse.verify_token, verify_token, public_rsa, RSA_PKCS1_PADDING);
if (verify_token_length != 4) {
return 1;
}
uint32_t verify_token_int = *((uint32_t*) verify_token);
if (verify_token_int != conn->verifyToken) goto rete;
memcpy(conn->shared_secret, shared_secret, 16);
uint8_t public_key[162];
memcpy(public_key, public_rsa_publickey, 162);
uint8_t hash[20];
SHA_CTX context;
SHA1_Init(&context);
SHA1_Update(&context, decSecret, 16);
SHA1_Update(&context, pubkey, 162);
SHA1_Update(&context, shared_secret, 16);
SHA1_Update(&context, public_key, 162);
SHA1_Final(hash, &context);
int m = 0;
int is_signed = 0;
if (hash[0] & 0x80) {
m = 1;
is_signed = 1;
for (int i = 0; i < 20; i++) {
hash[i] = ~hash[i];
}
(hash[19])++;
}
char fhash[32];
char* fhash2 = fhash + 1;
char hex_hash[32];
char* hex_hash_signed = hex_hash + 1;
for (int i = 0; i < 20; i++) {
snprintf(fhash + 1 + (i * 2), 3, "%02X", hash[i]);
snprintf(hex_hash + 1 + (i * 2), 3, "%02X", hash[i]);
}
for (int i = 1; i < 41; i++) {
if (fhash[i] == '0') fhash2++;
if (hex_hash[i] == '0') hex_hash_signed++;
else break;
}
fhash2--;
if (m) fhash2[0] = '-';
else fhash2++;
hex_hash_signed--;
struct mempool* ssl_pool = mempool_new();
if (is_signed) hex_hash_signed[0] = '-';
else hex_hash_signed++;
struct sockaddr_in sin;
//TODO: use getaddrinfo
struct hostent *host = gethostbyname("sessionserver.mojang.com");
if (host != NULL) {
struct in_addr **adl = (struct in_addr **) host->h_addr_list;
if (adl[0] != NULL) {
sin.sin_addr.s_addr = adl[0]->s_addr;
} else goto merr;
} else goto merr;
} else goto ssl_error;
} else goto ssl_error;
sin.sin_port = htons(443);
sin.sin_family = AF_INET;
int mfd = socket(AF_INET, SOCK_STREAM, 0);
SSL* sct = NULL;
int initssl = 0;
int val = 0;
if (mfd < 0) goto merr;
if (connect(mfd, (struct sockaddr*) &sin, sizeof(struct sockaddr_in))) goto merr;
sct = SSL_new(mojang_ctx);
SSL_set_connect_state(sct);
SSL_set_fd(sct, mfd);
if (SSL_connect(sct) != 1) goto merr;
else initssl = 1;
char cbuf[4096];
int tl = snprintf(cbuf, 1024, "GET /session/minecraft/hasJoined?username=%s&serverId=%s HTTP/1.1\r\nHost: sessionserver.mojang.com\r\nUser-Agent: Basin " VERSION "\r\nConnection: close\r\n\r\n", conn->online_username, fhash2);
int tw = 0;
while (tw < tl) {
int r = SSL_write(sct, cbuf, tl);
if (r <= 0) goto merr;
else tw += r;
SSL* ssl = NULL;
int session_server_successful = 0;
if (mfd < 0) goto ssl_error;
phook(ssl_pool, close_hook, mfd);
if (connect(mfd, (struct sockaddr*) &sin, sizeof(struct sockaddr_in))) goto ssl_error;
ssl = SSL_new(mojang_ctx);
phook(ssl_pool, (void (*)(void*)) SSL_shutdown, ssl);
phook(ssl_pool, (void (*)(void*)) SSL_free, ssl);
SSL_set_connect_state(ssl);
SSL_set_fd(ssl, mfd);
if (SSL_connect(ssl) != 1) goto ssl_error;
char write_buf[4096];
int write_length = snprintf(write_buf, 1024, "GET /session/minecraft/hasJoined?username=%s&serverId=%s HTTP/1.1\r\nHost: sessionserver.mojang.com\r\nUser-Agent: Basin " VERSION "\r\nConnection: close\r\n\r\n", conn->online_username, hex_hash_signed);
int written = 0;
while (written < write_length) {
int r = SSL_write(ssl, write_buf, write_length);
if (r <= 0) goto ssl_error;
else written += r;
}
tw = 0;
int read = 0;
int r = 0;
while ((r = SSL_read(sct, cbuf + tw, 4095 - tw)) > 0) {
tw += r;
while ((r = SSL_read(ssl, write_buf + read, 4095 - read)) > 0) { // we reuse write_buf as read_buf here
read += r;
}
cbuf[tw] = 0;
char* data = strstr(cbuf, "\r\n\r\n");
if (data == NULL) goto merr;
write_buf[read] = 0;
char* data = strstr(write_buf, "\r\n\r\n");
if (data == NULL) goto ssl_error;
data += 4;
struct json_object json;
json_parse(&json, data);
struct json_object* json = json_make_object(ssl_pool, NULL, 0);
json_parse(ssl_pool, &json, data);
struct json_object* tmp = json_get(&json, "id");
if (tmp == NULL || tmp->type != JSON_STRING) {
freeJSON(&json);
goto merr;
goto ssl_error;
}
char* id = trim(tmp->data.string);
tmp = json_get(&json, "name");
char* id = str_trim(tmp->data.string);
tmp = json_get(json, "name");
if (tmp == NULL || tmp->type != JSON_STRING) {
freeJSON(&json);
goto merr;
goto ssl_error;
}
char* name = trim(tmp->data.string);
char* name = str_trim(tmp->data.string);
size_t sl = strlen(name);
if (sl < 2 || sl > 16) {
freeJSON(&json);
goto merr;
goto ssl_error;
}
BEGIN_HASHMAP_ITERATION (players)
struct player* player = (struct player*) value;
if (streq_nocase(name, player->name)) {
kickPlayer(player, "You have logged in from another location!");
goto pbn2;
pthread_rwlock_rdlock(&conn->server->players_by_entity_id->rwlock);
ITER_MAP(conn->server->players_by_entity_id) {
struct player* player = (struct player*) value;
if (str_eq(name, player->name)) {
kickPlayer(player, "You have logged in from another location!");
goto post_map_iteration;
}
ITER_MAP_END();
}
END_HASHMAP_ITERATION (players)
pbn2: ;
val = 1;
post_map_iteration:;
pthread_rwlock_unlock(&conn->server->players_by_entity_id->rwlock);
session_server_successful = 1;
conn->aes_ctx_enc = EVP_CIPHER_CTX_new();
if (conn->aes_ctx_enc == NULL) goto rete;
//EVP_CIPHER_CTX_set_padding(conn->aes_ctx_enc, 0);
if (EVP_EncryptInit_ex(conn->aes_ctx_enc, EVP_aes_128_cfb8(), NULL, conn->sharedSecret, conn->sharedSecret) != 1) goto rete;
if (EVP_EncryptInit_ex(conn->aes_ctx_enc, EVP_aes_128_cfb8(), NULL, conn->shared_secret, conn->shared_secret) != 1) goto rete;
if (conn->aes_ctx_enc != NULL) {
phook(conn->pool, encrypt_free, conn->aes_ctx_enc);
phook(conn->pool, (void (*)(void*)) encrypt_free, conn->aes_ctx_enc);
}
conn->aes_ctx_dec = EVP_CIPHER_CTX_new();
if (conn->aes_ctx_dec == NULL) goto rete;
//EVP_CIPHER_CTX_set_padding(conn->aes_ctx_dec, 0);
if (EVP_DecryptInit_ex(conn->aes_ctx_dec, EVP_aes_128_cfb8(), NULL, conn->sharedSecret, conn->sharedSecret) != 1) goto rete;
if (EVP_DecryptInit_ex(conn->aes_ctx_dec, EVP_aes_128_cfb8(), NULL, conn->shared_secret, conn->shared_secret) != 1) goto rete;
if (conn->aes_ctx_dec != NULL) {
phook(conn->pool, decrypt_free, conn->aes_ctx_dec);
phook(conn->pool, (void (*)(void*)) decrypt_free, conn->aes_ctx_dec);
}
if (work_joinServer(conn, name, id)) {
freeJSON(&json);
if (initssl) SSL_shutdown(sct);
if (mfd >= 0) close(mfd);
if (sct != NULL) SSL_free(sct);
goto rete;
}
freeJSON(&json);
merr: ;
if (initssl) SSL_shutdown(sct);
if (mfd >= 0) close(mfd);
if (sct != NULL) SSL_free(sct);
if (!val) {
rep.id = PKT_LOGIN_CLIENT_DISCONNECT;
rep.data.login_client.disconnect.reason = xstrdup("{\"text\": \"There was an unresolvable issue with the Mojang sessionserver! Please try again.\"}", 0);
if (packet_write(conn, &rep) < 0) goto rete;
conn->disconnect = 1;
goto ret;
pfree(ssl_pool);
return 1;
}
pfree(ssl_pool);
return 0;
ssl_error: ;
pfree(ssl_pool);
struct packet* resp = packet_new(packet->pool, PKT_LOGIN_CLIENT_DISCONNECT);
resp->data.login_client.disconnect.reason = "{\"text\": \"There was an unresolvable issue with the Mojang sessionserver! Please try again.\"}";
conn->disconnect = 1;
packet_write(conn, resp); // failure is ignored, we disconnect regardless
return 1;
}
int handle_login_start(struct connection* conn, struct packet* packet) {

View File

@ -148,12 +148,12 @@ struct server* server_load(struct config_node* server) {
errlog(delog, "Invalid threads for server: %s, must be greater than 1.", server->name);
return NULL;
}
const char* max_player_str = config_get(server, "max-players");
const char* max_player_str = config_get(server, "max-players_by_entity_id");
if (max_player_str == NULL) {
max_player_str = "20";
}
if (!str_isunum(max_player_str)) {
errlog(delog, "Invalid max-players for server: %s", server->name);
errlog(delog, "Invalid max-players_by_entity_id for server: %s", server->name);
return NULL;
}
size_t max_players = strtoul(max_player_str, NULL, 10);
@ -275,7 +275,7 @@ struct server* server_load(struct config_node* server) {
list_append(serv->worlds, serv->overworld);
//add_collection(worlds, nether);
//add_collection(worlds, endworld);
serv-> players = hashmap_thread_new(32, global_pool);
serv-> players_by_entity_id = hashmap_thread_new(32, global_pool);
// playersToLoad = queue_new(0, 1, global_pool);
hashmap_put(server_map, serv->name, serv);

View File

@ -471,7 +471,7 @@ ssize_t packet_read(struct connection* conn, unsigned char* buf, size_t buflen,
rx = readVarInt(&packet->data.play_server.playerblockplacement.hand, pbuf, ps);
ADRX
//cursor_position_x
if (conn->protocolVersion > 210) {
if (conn->protocol_version > 210) {
CPS(4)
memcpy(&packet->data.play_server.playerblockplacement.cursor_position_x, pbuf, 4);
swapEndian(&packet->data.play_server.playerblockplacement.cursor_position_x, 4);
@ -483,7 +483,7 @@ ssize_t packet_read(struct connection* conn, unsigned char* buf, size_t buflen,
ADX(1)
}
//cursor_position_y
if (conn->protocolVersion > 210) {
if (conn->protocol_version > 210) {
CPS(4)
memcpy(&packet->data.play_server.playerblockplacement.cursor_position_y, pbuf, 4);
swapEndian(&packet->data.play_server.playerblockplacement.cursor_position_y, 4);
@ -495,7 +495,7 @@ ssize_t packet_read(struct connection* conn, unsigned char* buf, size_t buflen,
ADX(1)
}
//cursor_position_z
if (conn->protocolVersion > 210) {
if (conn->protocol_version > 210) {
CPS(4)
memcpy(&packet->data.play_server.playerblockplacement.cursor_position_z, pbuf, 4);
swapEndian(&packet->data.play_server.playerblockplacement.cursor_position_z, 4);
@ -685,7 +685,7 @@ ssize_t packet_write(struct connection* conn, struct packet* packet) {
swapEndian(pktbuf + pi, 16);
pi += 16;
//type
if (conn->protocolVersion > 210) {
if (conn->protocol_version > 210) {
ENS(4)
pi += writeVarInt(packet->data.play_client.spawnmob.type, pktbuf + pi);
} else {
@ -1812,7 +1812,7 @@ ssize_t packet_write(struct connection* conn, struct packet* packet) {
ENS(4)
pi += writeVarInt(packet->data.play_client.collectitem.collector_entity_id, pktbuf + pi);
//pickup_item_count
if (conn->protocolVersion > 210) {
if (conn->protocol_version > 210) {
ENS(4)
pi += writeVarInt(packet->data.play_client.collectitem.pickup_item_count, pktbuf + pi);
}

View File

@ -42,156 +42,6 @@
#include <avuna/util.h>
int work_joinServer(struct conn* conn, char* username, char* uuids) {
struct packet rep;
rep.id = PKT_LOGIN_CLIENT_LOGINSUCCESS;
rep.data.login_client.loginsuccess.username = username;
struct uuid uuid;
unsigned char* uuidx = (unsigned char*) &uuid;
if (uuids == NULL) {
if (online_mode) return 1;
MD5_CTX context;
MD5_Init(&context);
MD5_Update(&context, username, strlen(username));
MD5_Final(uuidx, &context);
} else {
if (strlen(uuids) != 32) return 1;
char ups[9];
memcpy(ups, uuids, 8);
ups[8] = 0;
uuid.uuid1 = ((uint64_t) strtoll(ups, NULL, 16)) << 32;
memcpy(ups, uuids + 8, 8);
uuid.uuid1 |= ((uint64_t) strtoll(ups, NULL, 16)) & 0xFFFFFFFF;
memcpy(ups, uuids + 16, 8);
uuid.uuid2 = ((uint64_t) strtoll(ups, NULL, 16)) << 32;
memcpy(ups, uuids + 24, 8);
uuid.uuid2 |= ((uint64_t) strtoll(ups, NULL, 16)) & 0xFFFFFFFF;
}
rep.data.login_client.loginsuccess.uuid = xmalloc(38);
snprintf(rep.data.login_client.loginsuccess.uuid, 10, "%08X-", ((uint32_t*) uuidx)[0]);
snprintf(rep.data.login_client.loginsuccess.uuid + 9, 6, "%04X-", ((uint16_t*) uuidx)[2]);
snprintf(rep.data.login_client.loginsuccess.uuid + 14, 6, "%04X-", ((uint16_t*) uuidx)[3]);
snprintf(rep.data.login_client.loginsuccess.uuid + 19, 6, "%04X-", ((uint16_t*) uuidx)[4]);
snprintf(rep.data.login_client.loginsuccess.uuid + 24, 9, "%08X", ((uint32_t*) (uuidx + 4))[2]);
snprintf(rep.data.login_client.loginsuccess.uuid + 32, 5, "%04X", ((uint16_t*) uuidx)[7]);
if (packet_write(conn, &rep) < 0) return 1;
xfree(rep.data.login_client.loginsuccess.uuid);
conn->state = STATE_PLAY;
struct entity* ep = newEntity(nextEntityID++, (double) overworld->spawnpos.x + .5, (double) overworld->spawnpos.y, (double) overworld->spawnpos.z + .5, ENT_PLAYER, 0., 0.);
struct player* player = newPlayer(ep, xstrdup(rep.data.login_client.loginsuccess.username, 1), uuid, conn, 0); // TODO default gamemode
player->protocolVersion = conn->protocolVersion;
conn->player = player;
put_hashmap(players, player->entity->id, player);
rep.id = PKT_PLAY_CLIENT_JOINGAME;
rep.data.play_client.joingame.entity_id = ep->id;
rep.data.play_client.joingame.gamemode = player->gamemode;
rep.data.play_client.joingame.dimension = overworld->dimension;
rep.data.play_client.joingame.difficulty = difficulty;
rep.data.play_client.joingame.max_players = max_players;
rep.data.play_client.joingame.level_type = overworld->levelType;
rep.data.play_client.joingame.reduced_debug_info = 0; // TODO
if (packet_write(conn, &rep) < 0) return 1;
rep.id = PKT_PLAY_CLIENT_PLUGINMESSAGE;
rep.data.play_client.pluginmessage.channel = "MC|Brand";
rep.data.play_client.pluginmessage.data = xmalloc(16);
int rx2 = writeVarInt(5, rep.data.play_client.pluginmessage.data);
memcpy(rep.data.play_client.pluginmessage.data + rx2, "Basin", 5);
rep.data.play_client.pluginmessage.data_size = rx2 + 5;
if (packet_write(conn, &rep) < 0) return 1;
xfree(rep.data.play_client.pluginmessage.data);
rep.id = PKT_PLAY_CLIENT_SERVERDIFFICULTY;
rep.data.play_client.serverdifficulty.difficulty = difficulty;
if (packet_write(conn, &rep) < 0) return 1;
rep.id = PKT_PLAY_CLIENT_SPAWNPOSITION;
memcpy(&rep.data.play_client.spawnposition.location, &overworld->spawnpos, sizeof(struct encpos));
if (packet_write(conn, &rep) < 0) return 1;
rep.id = PKT_PLAY_CLIENT_PLAYERABILITIES;
rep.data.play_client.playerabilities.flags = 0; // TODO: allows flying, remove
rep.data.play_client.playerabilities.flying_speed = 0.05;
rep.data.play_client.playerabilities.field_of_view_modifier = .1;
if (packet_write(conn, &rep) < 0) return 1;
rep.id = PKT_PLAY_CLIENT_PLAYERPOSITIONANDLOOK;
rep.data.play_client.playerpositionandlook.x = ep->x;
rep.data.play_client.playerpositionandlook.y = ep->y;
rep.data.play_client.playerpositionandlook.z = ep->z;
rep.data.play_client.playerpositionandlook.yaw = ep->yaw;
rep.data.play_client.playerpositionandlook.pitch = ep->pitch;
rep.data.play_client.playerpositionandlook.flags = 0x0;
rep.data.play_client.playerpositionandlook.teleport_id = 0;
if (packet_write(conn, &rep) < 0) return 1;
rep.id = PKT_PLAY_CLIENT_PLAYERLISTITEM;
pthread_rwlock_rdlock(&players->data_mutex);
rep.data.play_client.playerlistitem.action_id = 0;
rep.data.play_client.playerlistitem.number_of_players = players->entry_count + 1;
rep.data.play_client.playerlistitem.players = xmalloc(rep.data.play_client.playerlistitem.number_of_players * sizeof(struct listitem_player));
size_t px = 0;
BEGIN_HASHMAP_ITERATION (players)
struct player* plx = (struct player*) value;
if (px < rep.data.play_client.playerlistitem.number_of_players) {
memcpy(&rep.data.play_client.playerlistitem.players[px].uuid, &plx->uuid, sizeof(struct uuid));
rep.data.play_client.playerlistitem.players[px].action.addplayer.name = xstrdup(plx->name, 0);
rep.data.play_client.playerlistitem.players[px].action.addplayer.number_of_properties = 0;
rep.data.play_client.playerlistitem.players[px].action.addplayer.properties = NULL;
rep.data.play_client.playerlistitem.players[px].action.addplayer.gamemode = plx->gamemode;
rep.data.play_client.playerlistitem.players[px].action.addplayer.ping = 0; // TODO
rep.data.play_client.playerlistitem.players[px].action.addplayer.has_display_name = 0;
rep.data.play_client.playerlistitem.players[px].action.addplayer.display_name = NULL;
px++;
}
if (player == plx) continue;
struct packet* pkt = xmalloc(sizeof(struct packet));
pkt->id = PKT_PLAY_CLIENT_PLAYERLISTITEM;
pkt->data.play_client.playerlistitem.action_id = 0;
pkt->data.play_client.playerlistitem.number_of_players = 1;
pkt->data.play_client.playerlistitem.players = xmalloc(sizeof(struct listitem_player));
memcpy(&pkt->data.play_client.playerlistitem.players->uuid, &player->uuid, sizeof(struct uuid));
pkt->data.play_client.playerlistitem.players->action.addplayer.name = xstrdup(player->name, 0);
pkt->data.play_client.playerlistitem.players->action.addplayer.number_of_properties = 0;
pkt->data.play_client.playerlistitem.players->action.addplayer.properties = NULL;
pkt->data.play_client.playerlistitem.players->action.addplayer.gamemode = player->gamemode;
pkt->data.play_client.playerlistitem.players->action.addplayer.ping = 0; // TODO
pkt->data.play_client.playerlistitem.players->action.addplayer.has_display_name = 0;
pkt->data.play_client.playerlistitem.players->action.addplayer.display_name = NULL;
add_queue(plx->outgoingPacket, pkt);
flush_outgoing(plx);
END_HASHMAP_ITERATION (players)
pthread_rwlock_unlock(&players->data_mutex);
memcpy(&rep.data.play_client.playerlistitem.players[px].uuid, &player->uuid, sizeof(struct uuid));
rep.data.play_client.playerlistitem.players[px].action.addplayer.name = xstrdup(player->name, 0);
rep.data.play_client.playerlistitem.players[px].action.addplayer.number_of_properties = 0;
rep.data.play_client.playerlistitem.players[px].action.addplayer.properties = NULL;
rep.data.play_client.playerlistitem.players[px].action.addplayer.gamemode = player->gamemode;
rep.data.play_client.playerlistitem.players[px].action.addplayer.ping = 0; // TODO
rep.data.play_client.playerlistitem.players[px].action.addplayer.has_display_name = 0;
rep.data.play_client.playerlistitem.players[px].action.addplayer.display_name = NULL;
px++;
if (packet_write(conn, &rep) < 0) return 1;
rep.id = PKT_PLAY_CLIENT_TIMEUPDATE;
rep.data.play_client.timeupdate.time_of_day = overworld->time;
rep.data.play_client.timeupdate.world_age = overworld->age;
if (packet_write(conn, &rep) < 0) return 1;
add_collection(playersToLoad, player);
broadcastf("yellow", "%s has joined the server!", player->name);
const char* mip = NULL;
char tip[48];
if (conn->addr.sin6_family == AF_INET) {
struct sockaddr_in *sip4 = (struct sockaddr_in*) &conn->addr;
mip = inet_ntop(AF_INET, &sip4->sin_addr, tip, 48);
} else if (conn->addr.sin6_family == AF_INET6) {
struct sockaddr_in6 *sip6 = (struct sockaddr_in6*) &conn->addr;
if (memseq((unsigned char*) &sip6->sin6_addr, 10, 0) && memseq((unsigned char*) &sip6->sin6_addr + 10, 2, 0xff)) {
mip = inet_ntop(AF_INET, ((unsigned char*) &sip6->sin6_addr) + 12, tip, 48);
} else mip = inet_ntop(AF_INET6, &sip6->sin6_addr, tip, 48);
} else if (conn->addr.sin6_family == AF_LOCAL) {
mip = "UNIX";
} else {
mip = "UNKNOWN";
}
printf("Player '%s' has joined with IP '%s'\n", player->name, mip);
return 0;
}
int connection_read(struct netmgr_connection* netmgr_conn, uint8_t* read_buf, size_t read_buf_len) {
struct connection* conn = netmgr_conn->extra;
if (conn->disconnect) {