mirror of https://github.com/basinserver/basin/
Encryption/online mode wip
This commit is contained in:
parent
6a29bcc777
commit
e6b7887024
|
@ -12,7 +12,7 @@ threads = 30
|
||||||
max-players = 20
|
max-players = 20
|
||||||
motd = A Minecraft Server
|
motd = A Minecraft Server
|
||||||
level-seed =
|
level-seed =
|
||||||
online-mode = false
|
online-mode = true
|
||||||
white-list = false
|
white-list = false
|
||||||
spawn-animals = true
|
spawn-animals = true
|
||||||
spawn-npcs = true
|
spawn-npcs = true
|
||||||
|
|
|
@ -42,11 +42,16 @@ void run_accept(struct accept_param* param) {
|
||||||
c->writeBuffer_capacity = 0;
|
c->writeBuffer_capacity = 0;
|
||||||
c->comp = -1;
|
c->comp = -1;
|
||||||
c->state = 0;
|
c->state = 0;
|
||||||
|
c->onll_username = NULL;
|
||||||
c->disconnect = 0;
|
c->disconnect = 0;
|
||||||
c->host_ip = NULL;
|
c->host_ip = NULL;
|
||||||
c->player = NULL;
|
c->player = NULL;
|
||||||
c->host_port = 0;
|
c->host_port = 0;
|
||||||
c->protocolVersion = 0;
|
c->protocolVersion = 0;
|
||||||
|
c->verifyToken = 0;
|
||||||
|
c->aes_ctx_enc = NULL;
|
||||||
|
c->aes_ctx_dec = NULL;
|
||||||
|
memset(c->sharedSecret, 0, 16);
|
||||||
if (poll(&spfd, 1, -1) < 0) {
|
if (poll(&spfd, 1, -1) < 0) {
|
||||||
printf("Error while polling server: %s\n", strerror(errno));
|
printf("Error while polling server: %s\n", strerror(errno));
|
||||||
xfree(c);
|
xfree(c);
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include "work.h"
|
#include "work.h"
|
||||||
#include <netinet/ip6.h>
|
#include <netinet/ip6.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/aes.h>
|
||||||
|
|
||||||
struct accept_param {
|
struct accept_param {
|
||||||
int server_fd;
|
int server_fd;
|
||||||
|
@ -41,6 +43,11 @@ struct conn {
|
||||||
struct player* player;
|
struct player* player;
|
||||||
int disconnect;
|
int disconnect;
|
||||||
uint32_t protocolVersion;
|
uint32_t protocolVersion;
|
||||||
|
uint32_t verifyToken;
|
||||||
|
char* onll_username;
|
||||||
|
uint8_t sharedSecret[16];
|
||||||
|
EVP_CIPHER_CTX* aes_ctx_enc;
|
||||||
|
EVP_CIPHER_CTX* aes_ctx_dec;
|
||||||
};
|
};
|
||||||
|
|
||||||
void run_accept(struct accept_param* param);
|
void run_accept(struct accept_param* param);
|
||||||
|
|
|
@ -13,6 +13,94 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "world.h"
|
#include "world.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
#define ENT_PLAYER 0
|
||||||
|
#define ENT_ITEM 1
|
||||||
|
#define ENT_XP_ORB 2
|
||||||
|
#define ENT_AREA_EFFECT_CLOUD 3
|
||||||
|
#define ENT_ELDER_GUARDIAN 4
|
||||||
|
#define ENT_WITHER_SKELETON 5
|
||||||
|
#define ENT_STRAY 6
|
||||||
|
#define ENT_EGG 7
|
||||||
|
#define ENT_LEASH_KNOT 8
|
||||||
|
#define ENT_PAINTING 9
|
||||||
|
#define ENT_ARROW 10
|
||||||
|
#define ENT_SNOWBALL 11
|
||||||
|
#define ENT_FIREBALL 12
|
||||||
|
#define ENT_SMALL_FIREBALL 13
|
||||||
|
#define ENT_ENDER_PEARL 14
|
||||||
|
#define ENT_EYE_OF_ENDER_SIGNAL 15
|
||||||
|
#define ENT_POTION 16
|
||||||
|
#define ENT_XP_BOTTLE 17
|
||||||
|
#define ENT_ITEM_FRAME 18
|
||||||
|
#define ENT_WITHER_SKULL 19
|
||||||
|
#define ENT_TNT 20
|
||||||
|
#define ENT_FALLING_BLOCK 21
|
||||||
|
#define ENT_FIREWORKS_ROCKET 22
|
||||||
|
#define ENT_HUSK 23
|
||||||
|
#define ENT_SPECTRAL_ARROW 24
|
||||||
|
#define ENT_SHULKER_BULLET 25
|
||||||
|
#define ENT_DRAGON_FIREBALL 26
|
||||||
|
#define ENT_ZOMBIE_VILLAGER 27
|
||||||
|
#define ENT_SKELETON_HORSE 28
|
||||||
|
#define ENT_ZOMBIE_HORSE 29
|
||||||
|
#define ENT_ARMOR_STAND 30
|
||||||
|
#define ENT_DONKEY 31
|
||||||
|
#define ENT_MULE 32
|
||||||
|
#define ENT_EVOCATION_FANGS 33
|
||||||
|
#define ENT_EVOCATION_ILLAGER 34
|
||||||
|
#define ENT_VEX 35
|
||||||
|
#define ENT_VINDICATION_ILLAGER 36
|
||||||
|
#define ENT_COMMANDBLOCK_MINECART 40
|
||||||
|
#define ENT_BOAT 41
|
||||||
|
#define ENT_MINECART 42
|
||||||
|
#define ENT_CHEST_MINECART 43
|
||||||
|
#define ENT_FURNACE_MINECART 44
|
||||||
|
#define ENT_TNT_MINECART 45
|
||||||
|
#define ENT_HOPPER_MINECART 46
|
||||||
|
#define ENT_SPAWNER_MINECART 47
|
||||||
|
#define ENT_CREEPER 50
|
||||||
|
#define ENT_SKELETON 51
|
||||||
|
#define ENT_SPIDER 52
|
||||||
|
#define ENT_GIANT 53
|
||||||
|
#define ENT_ZOMBIE 54
|
||||||
|
#define ENT_SLIME 55
|
||||||
|
#define ENT_GHAST 56
|
||||||
|
#define ENT_ZOMBIE_PIGMAN 57
|
||||||
|
#define ENT_ENDERMAN 58
|
||||||
|
#define ENT_CAVE_SPIDER 59
|
||||||
|
#define ENT_SILVERFISH 60
|
||||||
|
#define ENT_BLAZE 61
|
||||||
|
#define ENT_MAGMA_CUBE 62
|
||||||
|
#define ENT_ENDER_DRAGON 63
|
||||||
|
#define ENT_WITHER 64
|
||||||
|
#define ENT_BAT 65
|
||||||
|
#define ENT_WITCH 66
|
||||||
|
#define ENT_ENDERMITE 67
|
||||||
|
#define ENT_GUARDIAN 68
|
||||||
|
#define ENT_SHULKER 69
|
||||||
|
#define ENT_PIG 90
|
||||||
|
#define ENT_SHEEP 91
|
||||||
|
#define ENT_COW 92
|
||||||
|
#define ENT_CHICKEN 93
|
||||||
|
#define ENT_SQUID 94
|
||||||
|
#define ENT_WOLF 95
|
||||||
|
#define ENT_MOOSHROOM 96
|
||||||
|
#define ENT_SNOWMAN 97
|
||||||
|
#define ENT_OCELOT 98
|
||||||
|
#define ENT_VILLAGER_GOLEM 99
|
||||||
|
#define ENT_HORSE 100
|
||||||
|
#define ENT_RABBIT 101
|
||||||
|
#define ENT_POLAR_BEAR 102
|
||||||
|
#define ENT_LLAMA 103
|
||||||
|
#define ENT_LLAMA_SPIT 104
|
||||||
|
#define ENT_VILLAGER 120
|
||||||
|
#define ENT_ENDER_CRYSTAL 200
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
#define ENT_UNDEFINED 1
|
#define ENT_UNDEFINED 1
|
||||||
#define ENT_PLAYER 2
|
#define ENT_PLAYER 2
|
||||||
#define ENT_CREEPER 3
|
#define ENT_CREEPER 3
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
#include "profile.h"
|
#include "profile.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
|
||||||
void main_tick() {
|
void main_tick() {
|
||||||
pthread_cond_broadcast (&glob_tick_cond);
|
pthread_cond_broadcast (&glob_tick_cond);
|
||||||
|
@ -116,7 +117,9 @@ int main(int argc, char* argv[]) {
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
srand(ts.tv_sec * 1000000 + ts.tv_nsec / 1000);
|
size_t us = ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
|
||||||
|
srand(us);
|
||||||
|
RAND_seed(&us, sizeof(size_t));
|
||||||
printf("Loading %s %s\n", DAEMON_NAME, VERSION);
|
printf("Loading %s %s\n", DAEMON_NAME, VERSION);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printf("Running in Debug mode!\n");
|
printf("Running in Debug mode!\n");
|
||||||
|
@ -204,6 +207,8 @@ int main(int argc, char* argv[]) {
|
||||||
printf("Commands Initialized\n");
|
printf("Commands Initialized\n");
|
||||||
init_plugins();
|
init_plugins();
|
||||||
printf("Plugins Initialized\n");
|
printf("Plugins Initialized\n");
|
||||||
|
init_encryption();
|
||||||
|
printf("Encryption Initialized\n");
|
||||||
for (int i = 0; i < servsl; i++) {
|
for (int i = 0; i < servsl; i++) {
|
||||||
struct cnode* serv = servs[i];
|
struct cnode* serv = servs[i];
|
||||||
const char* bind_mode = getConfigValue(serv, "bind-mode");
|
const char* bind_mode = getConfigValue(serv, "bind-mode");
|
||||||
|
|
|
@ -23,6 +23,31 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/x509.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
|
||||||
|
void init_encryption() {
|
||||||
|
public_rsa = RSA_new();
|
||||||
|
BIGNUM* pn = BN_new();
|
||||||
|
if (BN_set_word(pn, RSA_F4) != 1) {
|
||||||
|
printf("Error generating RSA BIGNUM!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (RSA_generate_key_ex(public_rsa, 1024, pn, NULL) != 1) {
|
||||||
|
printf("Error generating RSA keypair!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size_t s = i2d_RSA_PUBKEY(public_rsa, &public_rsa_publickey);
|
||||||
|
if (s != 162) {
|
||||||
|
printf("[WARNING] RSA Public Key size was not 162! Size = %lu\n", s);
|
||||||
|
}
|
||||||
|
OpenSSL_add_all_algorithms();
|
||||||
|
SSL_load_error_strings();
|
||||||
|
SSL_library_init();
|
||||||
|
const SSL_METHOD* method = SSLv23_client_method();
|
||||||
|
mojang_ctx = SSL_CTX_new(method);
|
||||||
|
}
|
||||||
|
|
||||||
void swapEndian(void* dou, size_t ss) {
|
void swapEndian(void* dou, size_t ss) {
|
||||||
uint8_t* pxs = (uint8_t*) dou;
|
uint8_t* pxs = (uint8_t*) dou;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#include "accept.h"
|
#include "accept.h"
|
||||||
#include "inventory.h"
|
#include "inventory.h"
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
|
||||||
struct packet;
|
struct packet;
|
||||||
|
|
||||||
|
@ -29,6 +30,12 @@ struct entity_metadata {
|
||||||
size_t metadata_size;
|
size_t metadata_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
RSA* public_rsa;
|
||||||
|
uint8_t* public_rsa_publickey;
|
||||||
|
SSL_CTX* mojang_ctx;
|
||||||
|
|
||||||
|
void init_encryption();
|
||||||
|
|
||||||
void swapEndian(void* dou, size_t ss);
|
void swapEndian(void* dou, size_t ss);
|
||||||
|
|
||||||
int getVarIntSize(int32_t input);
|
int getVarIntSize(int32_t input);
|
||||||
|
|
|
@ -35,24 +35,42 @@ ssize_t readPacket(struct conn* conn, unsigned char* buf, size_t buflen, struct
|
||||||
void* pktbuf = buf;
|
void* pktbuf = buf;
|
||||||
int32_t pktlen = buflen;
|
int32_t pktlen = buflen;
|
||||||
int tf = 0;
|
int tf = 0;
|
||||||
|
if (conn->aes_ctx_dec != NULL) {
|
||||||
|
if (EVP_DecryptInit_ex(conn->aes_ctx_dec, EVP_aes_128_cfb8(), NULL, conn->sharedSecret, conn->sharedSecret) != 1) return -1;
|
||||||
|
int csl = pktlen + 32; // 16 extra just in case
|
||||||
|
void* edata = xmalloc(csl);
|
||||||
|
if (EVP_DecryptUpdate(conn->aes_ctx_dec, edata, &csl, pktbuf, pktlen) != 1) {
|
||||||
|
xfree(edata);
|
||||||
|
goto rer;
|
||||||
|
}
|
||||||
|
int csl2 = 0;
|
||||||
|
if (EVP_DecryptFinal_ex(conn->aes_ctx_dec, edata + csl, &csl2) != 1) {
|
||||||
|
xfree(edata);
|
||||||
|
goto rer;
|
||||||
|
}
|
||||||
|
csl += csl2;
|
||||||
|
pktbuf = edata;
|
||||||
|
pktlen = csl;
|
||||||
|
tf = 1;
|
||||||
|
}
|
||||||
if (conn->comp >= 0) {
|
if (conn->comp >= 0) {
|
||||||
int32_t dl = 0;
|
int32_t dl = 0;
|
||||||
int rx = readVarInt(&dl, pktbuf, pktlen);
|
int rx = readVarInt(&dl, pktbuf, pktlen);
|
||||||
if (rx == 0) return -1;
|
if (rx == 0) goto rer;
|
||||||
pktlen -= rx;
|
pktlen -= rx;
|
||||||
pktbuf += rx;
|
pktbuf += rx;
|
||||||
if (dl > 0 && pktlen > 0) {
|
if (dl > 0 && pktlen > 0) {
|
||||||
pktlen = dl;
|
pktlen = dl;
|
||||||
void* decmpbuf = malloc(dl);
|
void* decmpbuf = xmalloc(dl);
|
||||||
z_stream strm;
|
z_stream strm;
|
||||||
strm.zalloc = Z_NULL;
|
strm.zalloc = Z_NULL;
|
||||||
strm.zfree = Z_NULL;
|
strm.zfree = Z_NULL;
|
||||||
strm.opaque = Z_NULL;
|
strm.opaque = Z_NULL;
|
||||||
int dr = 0;
|
int dr = 0;
|
||||||
if ((dr = inflateInit(&strm)) != Z_OK) {
|
if ((dr = inflateInit(&strm)) != Z_OK) {
|
||||||
free(decmpbuf);
|
xfree(decmpbuf);
|
||||||
printf("Compression initialization error!\n");
|
printf("Compression initialization error!\n");
|
||||||
return -1;
|
goto rer;
|
||||||
}
|
}
|
||||||
strm.avail_in = pktlen;
|
strm.avail_in = pktlen;
|
||||||
strm.next_in = pktbuf;
|
strm.next_in = pktbuf;
|
||||||
|
@ -61,9 +79,9 @@ ssize_t readPacket(struct conn* conn, unsigned char* buf, size_t buflen, struct
|
||||||
do {
|
do {
|
||||||
dr = inflate(&strm, Z_FINISH);
|
dr = inflate(&strm, Z_FINISH);
|
||||||
if (dr == Z_STREAM_ERROR) {
|
if (dr == Z_STREAM_ERROR) {
|
||||||
free(decmpbuf);
|
xfree(decmpbuf);
|
||||||
printf("Compression Read Error\n");
|
printf("Compression Read Error\n");
|
||||||
return -1;
|
goto rer;
|
||||||
}
|
}
|
||||||
strm.avail_out = pktlen - strm.total_out;
|
strm.avail_out = pktlen - strm.total_out;
|
||||||
strm.next_out = decmpbuf + strm.total_out;
|
strm.next_out = decmpbuf + strm.total_out;
|
||||||
|
@ -543,6 +561,7 @@ ssize_t readPacket(struct conn* conn, unsigned char* buf, size_t buflen, struct
|
||||||
}
|
}
|
||||||
goto rx;
|
goto rx;
|
||||||
rer: ;
|
rer: ;
|
||||||
|
if (tf) xfree(pktbuf);
|
||||||
return -1;
|
return -1;
|
||||||
rx: ;
|
rx: ;
|
||||||
if (tf) xfree(pktbuf);
|
if (tf) xfree(pktbuf);
|
||||||
|
@ -1920,14 +1939,14 @@ ssize_t writePacket(struct conn* conn, struct packet* packet) {
|
||||||
pi += writeVarInt(packet->data.login_client.encryptionrequest.public_key_length, pktbuf + pi);
|
pi += writeVarInt(packet->data.login_client.encryptionrequest.public_key_length, pktbuf + pi);
|
||||||
//public_key
|
//public_key
|
||||||
ENS(packet->data.login_client.encryptionrequest.public_key_length)
|
ENS(packet->data.login_client.encryptionrequest.public_key_length)
|
||||||
memcpy(pktbuf + pi, &packet->data.login_client.encryptionrequest.public_key, packet->data.login_client.encryptionrequest.public_key_length);
|
memcpy(pktbuf + pi, packet->data.login_client.encryptionrequest.public_key, packet->data.login_client.encryptionrequest.public_key_length);
|
||||||
pi += packet->data.login_client.encryptionrequest.public_key_length;
|
pi += packet->data.login_client.encryptionrequest.public_key_length;
|
||||||
//verify_token_length
|
//verify_token_length
|
||||||
ENS(4)
|
ENS(4)
|
||||||
pi += writeVarInt(packet->data.login_client.encryptionrequest.verify_token_length, pktbuf + pi);
|
pi += writeVarInt(packet->data.login_client.encryptionrequest.verify_token_length, pktbuf + pi);
|
||||||
//verify_token
|
//verify_token
|
||||||
ENS(packet->data.login_client.encryptionrequest.verify_token_length)
|
ENS(packet->data.login_client.encryptionrequest.verify_token_length)
|
||||||
memcpy(pktbuf + pi, &packet->data.login_client.encryptionrequest.verify_token, packet->data.login_client.encryptionrequest.verify_token_length);
|
memcpy(pktbuf + pi, packet->data.login_client.encryptionrequest.verify_token, packet->data.login_client.encryptionrequest.verify_token_length);
|
||||||
pi += packet->data.login_client.encryptionrequest.verify_token_length;
|
pi += packet->data.login_client.encryptionrequest.verify_token_length;
|
||||||
} else if (id == PKT_LOGIN_CLIENT_LOGINSUCCESS) {
|
} else if (id == PKT_LOGIN_CLIENT_LOGINSUCCESS) {
|
||||||
//uuid
|
//uuid
|
||||||
|
@ -1962,27 +1981,26 @@ ssize_t writePacket(struct conn* conn, struct packet* packet) {
|
||||||
}
|
}
|
||||||
strm.avail_in = pi;
|
strm.avail_in = pi;
|
||||||
strm.next_in = pktbuf;
|
strm.next_in = pktbuf;
|
||||||
void* cdata = malloc(16384);
|
size_t cc = pi + 32;
|
||||||
|
void* cdata = xmalloc(cc);
|
||||||
size_t ts = 0;
|
size_t ts = 0;
|
||||||
size_t cc = 16384;
|
|
||||||
strm.avail_out = cc - ts;
|
strm.avail_out = cc - ts;
|
||||||
strm.next_out = cdata + ts;
|
strm.next_out = cdata + ts;
|
||||||
do {
|
do {
|
||||||
dr = deflate(&strm, Z_FINISH);
|
dr = deflate(&strm, Z_FINISH);
|
||||||
ts = strm.total_out;
|
ts = strm.total_out;
|
||||||
if (ts >= cc) {
|
if (ts >= cc) {
|
||||||
cc = ts + 16384;
|
cc = ts + 1024;
|
||||||
cdata = realloc(cdata, cc);
|
cdata = xrealloc(cdata, cc);
|
||||||
}
|
}
|
||||||
if (dr == Z_STREAM_ERROR) {
|
if (dr == Z_STREAM_ERROR) {
|
||||||
free(cdata);
|
xfree(cdata);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
strm.avail_out = cc - ts;
|
strm.avail_out = cc - ts;
|
||||||
strm.next_out = cdata + ts;
|
strm.next_out = cdata + ts;
|
||||||
} while (strm.avail_out == 0);
|
} while (strm.avail_out == 0);
|
||||||
deflateEnd(&strm);
|
deflateEnd(&strm);
|
||||||
cdata = xrealloc(cdata, ts); // shrink
|
|
||||||
preps += writeVarInt(ts + getVarIntSize(pi), prep + preps);
|
preps += writeVarInt(ts + getVarIntSize(pi), prep + preps);
|
||||||
preps += writeVarInt(pi, prep + preps);
|
preps += writeVarInt(pi, prep + preps);
|
||||||
wrt = cdata;
|
wrt = cdata;
|
||||||
|
@ -1997,7 +2015,63 @@ ssize_t writePacket(struct conn* conn, struct packet* packet) {
|
||||||
wrt = pktbuf;
|
wrt = pktbuf;
|
||||||
wrt_s = pi;
|
wrt_s = pi;
|
||||||
}
|
}
|
||||||
//TODO: encrypt
|
if (conn->aes_ctx_enc != NULL) {
|
||||||
|
if (EVP_EncryptInit_ex(conn->aes_ctx_enc, EVP_aes_128_cfb8(), NULL, conn->sharedSecret, conn->sharedSecret) != 1) {
|
||||||
|
wrt_s = -1;
|
||||||
|
goto rret;
|
||||||
|
}
|
||||||
|
int csl = wrt_s + 32; // 16 extra just in case
|
||||||
|
void* edata = xcalloc(csl);
|
||||||
|
if (EVP_EncryptUpdate(conn->aes_ctx_enc, edata, &csl, wrt, wrt_s) != 1) {
|
||||||
|
xfree(edata);
|
||||||
|
wrt_s = -1;
|
||||||
|
goto rret;
|
||||||
|
}
|
||||||
|
int csl2 = 0;
|
||||||
|
if (EVP_EncryptFinal_ex(conn->aes_ctx_enc, edata + csl, &csl2) != 1) {
|
||||||
|
xfree(edata);
|
||||||
|
wrt_s = -1;
|
||||||
|
goto rret;
|
||||||
|
}
|
||||||
|
csl += csl2;
|
||||||
|
void* owrt = wrt;
|
||||||
|
size_t owrts = wrt_s;
|
||||||
|
//xfree(wrt);
|
||||||
|
if (!frp) pktbuf = NULL;
|
||||||
|
wrt = edata;
|
||||||
|
wrt_s = csl;
|
||||||
|
//
|
||||||
|
if (EVP_DecryptInit_ex(conn->aes_ctx_dec, EVP_aes_128_cfb8(), NULL, conn->sharedSecret, conn->sharedSecret) != 1) return -1;
|
||||||
|
csl = wrt_s + 32; // 16 extra just in case
|
||||||
|
edata = xcalloc(csl);
|
||||||
|
if (EVP_DecryptUpdate(conn->aes_ctx_dec, edata, &csl, wrt, wrt_s) != 1) {
|
||||||
|
xfree(edata);
|
||||||
|
wrt_s = -1;
|
||||||
|
goto rret;
|
||||||
|
}
|
||||||
|
csl2 = 0;
|
||||||
|
if (EVP_DecryptFinal_ex(conn->aes_ctx_dec, edata + csl, &csl2) != 1) {
|
||||||
|
xfree(edata);
|
||||||
|
wrt_s = -1;
|
||||||
|
goto rret;
|
||||||
|
}
|
||||||
|
csl += csl2;
|
||||||
|
if (csl != owrts) {
|
||||||
|
printf("length mismatch! %i != %i\n", csl, owrts);
|
||||||
|
} else {
|
||||||
|
printf("original data: ");
|
||||||
|
for (int i = 0; i < owrts; i++) {
|
||||||
|
printf("%02X", ((uint8_t*) owrt)[i]);
|
||||||
|
}
|
||||||
|
printf("\ndec/enc data: ");
|
||||||
|
for (int i = 0; i < csl; i++) {
|
||||||
|
printf("%02X", ((uint8_t*) edata)[i]);
|
||||||
|
}
|
||||||
|
printf("\n%s\n", memeq(owrt, owrts, edata, csl) ? "equal!" : "not equal!");
|
||||||
|
}
|
||||||
|
xfree(owrt);
|
||||||
|
xfree(edata);
|
||||||
|
}
|
||||||
if (conn->writeBuffer == NULL) {
|
if (conn->writeBuffer == NULL) {
|
||||||
conn->writeBuffer = xmalloc(preps);
|
conn->writeBuffer = xmalloc(preps);
|
||||||
memcpy(conn->writeBuffer, prep, preps);
|
memcpy(conn->writeBuffer, prep, preps);
|
||||||
|
@ -2017,6 +2091,7 @@ ssize_t writePacket(struct conn* conn, struct packet* packet) {
|
||||||
}
|
}
|
||||||
memcpy(conn->writeBuffer + conn->writeBuffer_size, wrt, wrt_s);
|
memcpy(conn->writeBuffer + conn->writeBuffer_size, wrt, wrt_s);
|
||||||
conn->writeBuffer_size += wrt_s;
|
conn->writeBuffer_size += wrt_s;
|
||||||
|
rret: ;
|
||||||
if (frp) xfree(wrt);
|
if (frp) xfree(wrt);
|
||||||
xfree(pktbuf);
|
xfree(pktbuf);
|
||||||
return wrt_s;
|
return wrt_s;
|
||||||
|
|
|
@ -1082,9 +1082,9 @@ struct pkt_login_client_disconnect {
|
||||||
struct pkt_login_client_encryptionrequest {
|
struct pkt_login_client_encryptionrequest {
|
||||||
char* server_id;
|
char* server_id;
|
||||||
int32_t public_key_length;
|
int32_t public_key_length;
|
||||||
int8_t* public_key;
|
uint8_t* public_key;
|
||||||
int32_t verify_token_length;
|
int32_t verify_token_length;
|
||||||
int8_t* verify_token;
|
uint8_t* verify_token;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PKT_LOGIN_CLIENT_LOGINSUCCESS 2
|
#define PKT_LOGIN_CLIENT_LOGINSUCCESS 2
|
||||||
|
@ -1110,9 +1110,9 @@ struct pkt_login_server_loginstart {
|
||||||
|
|
||||||
struct pkt_login_server_encryptionresponse {
|
struct pkt_login_server_encryptionresponse {
|
||||||
int32_t shared_secret_length;
|
int32_t shared_secret_length;
|
||||||
int8_t* shared_secret;
|
uint8_t* shared_secret;
|
||||||
int32_t verify_token_length;
|
int32_t verify_token_length;
|
||||||
int8_t* verify_token;
|
uint8_t* verify_token;
|
||||||
};
|
};
|
||||||
|
|
||||||
union pkt_handshake_client {
|
union pkt_handshake_client {
|
||||||
|
|
444
basin/src/work.c
444
basin/src/work.c
|
@ -32,6 +32,11 @@
|
||||||
#include "item.h"
|
#include "item.h"
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include "version.h"
|
||||||
|
#include "json.h"
|
||||||
|
|
||||||
void closeConn(struct work_param* param, struct conn* conn) {
|
void closeConn(struct work_param* param, struct conn* conn) {
|
||||||
close(conn->fd);
|
close(conn->fd);
|
||||||
|
@ -43,12 +48,160 @@ void closeConn(struct work_param* param, struct conn* conn) {
|
||||||
conn->player->defunct = 1;
|
conn->player->defunct = 1;
|
||||||
conn->player->conn = NULL;
|
conn->player->conn = NULL;
|
||||||
}
|
}
|
||||||
|
if (conn->aes_ctx_enc != NULL) EVP_CIPHER_CTX_free(conn->aes_ctx_enc);
|
||||||
|
if (conn->aes_ctx_dec != NULL) EVP_CIPHER_CTX_free(conn->aes_ctx_dec);
|
||||||
if (conn->host_ip != NULL) xfree(conn->host_ip);
|
if (conn->host_ip != NULL) xfree(conn->host_ip);
|
||||||
if (conn->readBuffer != NULL) xfree(conn->readBuffer);
|
if (conn->readBuffer != NULL) xfree(conn->readBuffer);
|
||||||
if (conn->writeBuffer != NULL) xfree(conn->writeBuffer);
|
if (conn->writeBuffer != NULL) xfree(conn->writeBuffer);
|
||||||
|
if (conn->onll_username != NULL) xfree(conn->onll_username);
|
||||||
xfree(conn);
|
xfree(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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[17];
|
||||||
|
memcpy(ups, uuids, 16);
|
||||||
|
ups[16] = 0;
|
||||||
|
uuid.uuid1 = strtoll(ups, NULL, 16);
|
||||||
|
memcpy(ups, uuids + 16, 16);
|
||||||
|
uuid.uuid2 = strtoll(ups, NULL, 16);
|
||||||
|
}
|
||||||
|
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 (writePacket(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 (writePacket(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 rx = writeVarInt(5, rep.data.play_client.pluginmessage.data);
|
||||||
|
memcpy(rep.data.play_client.pluginmessage.data + rx, "Basin", 5);
|
||||||
|
rep.data.play_client.pluginmessage.data_size = rx + 5;
|
||||||
|
if (writePacket(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 (writePacket(conn, &rep) < 0) return 1;
|
||||||
|
rep.id = PKT_PLAY_CLIENT_SPAWNPOSITION;
|
||||||
|
memcpy(&rep.data.play_client.spawnposition.location, &overworld->spawnpos, sizeof(struct encpos));
|
||||||
|
if (writePacket(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 (writePacket(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 (writePacket(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 (writePacket(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 (writePacket(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 handleRead(struct conn* conn, struct work_param* param, int fd) {
|
int handleRead(struct conn* conn, struct work_param* param, int fd) {
|
||||||
if (conn->disconnect) return 0;
|
if (conn->disconnect) return 0;
|
||||||
while (conn->readBuffer != NULL && conn->readBuffer_size > 0) {
|
while (conn->readBuffer != NULL && conn->readBuffer_size > 0) {
|
||||||
|
@ -96,10 +249,145 @@ int handleRead(struct conn* conn, struct work_param* param, int fd) {
|
||||||
conn->state = -1;
|
conn->state = -1;
|
||||||
} else goto rete;
|
} else goto rete;
|
||||||
} else if (conn->state == STATE_LOGIN) {
|
} else if (conn->state == STATE_LOGIN) {
|
||||||
if (inp->id == PKT_LOGIN_SERVER_LOGINSTART) {
|
if (inp->id == PKT_LOGIN_SERVER_ENCRYPTIONRESPONSE) {
|
||||||
|
if (conn->verifyToken == 0 || inp->data.login_server.encryptionresponse.shared_secret_length > 162 || inp->data.login_server.encryptionresponse.verify_token_length > 162) goto rete;
|
||||||
|
unsigned char decSecret[162];
|
||||||
|
int secLen = RSA_private_decrypt(inp->data.login_server.encryptionresponse.shared_secret_length, inp->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(inp->data.login_server.encryptionresponse.verify_token_length, inp->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;
|
||||||
|
uint8_t hash[20];
|
||||||
|
SHA_CTX context;
|
||||||
|
SHA1_Init(&context);
|
||||||
|
SHA1_Update(&context, decSecret, 16);
|
||||||
|
SHA1_Update(&context, public_rsa_publickey, 162);
|
||||||
|
SHA1_Final(hash, &context);
|
||||||
|
int m = 0;
|
||||||
|
if (hash[0] & 0x80) {
|
||||||
|
m = 1;
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
hash[i] = ~hash[i];
|
||||||
|
}
|
||||||
|
(hash[19])++;
|
||||||
|
}
|
||||||
|
char fhash[32];
|
||||||
|
char* fhash2 = fhash + 1;
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
snprintf(fhash + 1 + (i * 2), 3, "%02X", hash[i]);
|
||||||
|
}
|
||||||
|
for (int i = 1; i < 41; i++) {
|
||||||
|
if (fhash[i] == '0') fhash2++;
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
fhash2--;
|
||||||
|
if (m) fhash2[0] = '-';
|
||||||
|
else fhash2++;
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
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;
|
||||||
|
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->onll_username, fhash2);
|
||||||
|
int tw = 0;
|
||||||
|
while (tw < tl) {
|
||||||
|
int r = SSL_write(sct, cbuf, tl);
|
||||||
|
if (r <= 0) goto merr;
|
||||||
|
else tw += r;
|
||||||
|
}
|
||||||
|
tw = 0;
|
||||||
|
int r = 0;
|
||||||
|
while ((r = SSL_read(sct, cbuf + tw, 4095 - tw)) > 0) {
|
||||||
|
tw += r;
|
||||||
|
}
|
||||||
|
cbuf[tw] = 0;
|
||||||
|
char* data = strstr(cbuf, "\r\n\r\n");
|
||||||
|
if (data == NULL) goto merr;
|
||||||
|
data += 4;
|
||||||
|
struct json_object json;
|
||||||
|
parseJSON(&json, data);
|
||||||
|
struct json_object* tmp = getJSONValue(&json, "id");
|
||||||
|
if (tmp == NULL || tmp->type != JSON_STRING) {
|
||||||
|
freeJSON(&json);
|
||||||
|
goto merr;
|
||||||
|
}
|
||||||
|
char* id = trim(tmp->data.string);
|
||||||
|
tmp = getJSONValue(&json, "name");
|
||||||
|
if (tmp == NULL || tmp->type != JSON_STRING) {
|
||||||
|
freeJSON(&json);
|
||||||
|
goto merr;
|
||||||
|
}
|
||||||
|
char* name = trim(tmp->data.string);
|
||||||
|
size_t sl = strlen(name);
|
||||||
|
if (sl < 2 || sl > 16) {
|
||||||
|
freeJSON(&json);
|
||||||
|
goto merr;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
END_HASHMAP_ITERATION (players)
|
||||||
|
pbn2: ;
|
||||||
|
val = 1;
|
||||||
|
memcpy(conn->sharedSecret, decSecret, 16);
|
||||||
|
conn->aes_ctx_enc = EVP_CIPHER_CTX_new();
|
||||||
|
if (conn->aes_ctx_enc == NULL) goto rete;
|
||||||
|
conn->aes_ctx_dec = EVP_CIPHER_CTX_new();
|
||||||
|
if (conn->aes_ctx_dec == NULL) goto rete;
|
||||||
|
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 (writePacket(conn, &rep) < 0) goto rete;
|
||||||
|
conn->disconnect = 1;
|
||||||
|
goto ret;
|
||||||
|
}
|
||||||
|
} else if (inp->id == PKT_LOGIN_SERVER_LOGINSTART) {
|
||||||
if (online_mode) {
|
if (online_mode) {
|
||||||
//TODO
|
if (conn->verifyToken) goto rete;
|
||||||
return -1;
|
conn->onll_username = xstrdup(inp->data.login_server.loginstart.name, 0);
|
||||||
|
rep.id = PKT_LOGIN_CLIENT_ENCRYPTIONREQUEST;
|
||||||
|
rep.data.login_client.encryptionrequest.server_id = "";
|
||||||
|
rep.data.login_client.encryptionrequest.public_key = public_rsa_publickey;
|
||||||
|
rep.data.login_client.encryptionrequest.public_key_length = 162;
|
||||||
|
conn->verifyToken = rand();
|
||||||
|
if (conn->verifyToken == 0) conn->verifyToken = 1;
|
||||||
|
rep.data.login_client.encryptionrequest.verify_token = (uint8_t*) &conn->verifyToken;
|
||||||
|
rep.data.login_client.encryptionrequest.verify_token_length = 4;
|
||||||
|
if (writePacket(conn, &rep) < 0) goto rete;
|
||||||
} else {
|
} else {
|
||||||
int bn = 0;
|
int bn = 0;
|
||||||
char* rna = trim(inp->data.login_server.loginstart.name);
|
char* rna = trim(inp->data.login_server.loginstart.name);
|
||||||
|
@ -110,161 +398,19 @@ int handleRead(struct conn* conn, struct work_param* param, int fd) {
|
||||||
struct player* player = (struct player*) value;
|
struct player* player = (struct player*) value;
|
||||||
if (streq_nocase(rna, player->name)) {
|
if (streq_nocase(rna, player->name)) {
|
||||||
bn = 1;
|
bn = 1;
|
||||||
break;
|
goto pbn;
|
||||||
}
|
}
|
||||||
END_HASHMAP_ITERATION (players)
|
END_HASHMAP_ITERATION (players)
|
||||||
|
pbn: ;
|
||||||
}
|
}
|
||||||
if (bn) {
|
if (bn) {
|
||||||
rep.id = PKT_LOGIN_CLIENT_DISCONNECT;
|
rep.id = PKT_LOGIN_CLIENT_DISCONNECT;
|
||||||
rep.data.login_client.disconnect.reason = xstrdup(bn == 2 ? "{\"text\": \"Invalid name!\"}" : "{\"text\", \"You are already in the server!\"}", 0);
|
rep.data.login_client.disconnect.reason = xstrdup(bn == 2 ? "{\"text\": \"Invalid name!\"}" : "{\"text\", \"You are already in the server!\"}", 0);
|
||||||
if (writePacket(conn, &rep) < 0) goto rete;
|
if (writePacket(conn, &rep) < 0) goto rete;
|
||||||
conn->disconnect = 1;
|
conn->disconnect = 1;
|
||||||
return 0;
|
goto ret;
|
||||||
}
|
}
|
||||||
rep.id = PKT_LOGIN_CLIENT_LOGINSUCCESS;
|
if (work_joinServer(conn, rna, NULL)) goto rete;
|
||||||
rep.data.login_client.loginsuccess.username = rna;
|
|
||||||
struct uuid uuid;
|
|
||||||
unsigned char* uuidx = (unsigned char*) &uuid;
|
|
||||||
MD5_CTX context;
|
|
||||||
MD5_Init(&context);
|
|
||||||
MD5_Update(&context, rna, strlen(rna));
|
|
||||||
MD5_Final(uuidx, &context);
|
|
||||||
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 (writePacket(conn, &rep) < 0) goto rete;
|
|
||||||
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 (writePacket(conn, &rep) < 0) goto rete;
|
|
||||||
rep.id = PKT_PLAY_CLIENT_PLUGINMESSAGE;
|
|
||||||
rep.data.play_client.pluginmessage.channel = "MC|Brand";
|
|
||||||
rep.data.play_client.pluginmessage.data = xmalloc(16);
|
|
||||||
int rx = writeVarInt(5, rep.data.play_client.pluginmessage.data);
|
|
||||||
memcpy(rep.data.play_client.pluginmessage.data + rx, "Basin", 5);
|
|
||||||
rep.data.play_client.pluginmessage.data_size = rx + 5;
|
|
||||||
if (writePacket(conn, &rep) < 0) goto rete;
|
|
||||||
xfree(rep.data.play_client.pluginmessage.data);
|
|
||||||
rep.id = PKT_PLAY_CLIENT_SERVERDIFFICULTY;
|
|
||||||
rep.data.play_client.serverdifficulty.difficulty = difficulty;
|
|
||||||
if (writePacket(conn, &rep) < 0) goto rete;
|
|
||||||
rep.id = PKT_PLAY_CLIENT_SPAWNPOSITION;
|
|
||||||
memcpy(&rep.data.play_client.spawnposition.location, &overworld->spawnpos, sizeof(struct encpos));
|
|
||||||
if (writePacket(conn, &rep) < 0) goto rete;
|
|
||||||
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 (writePacket(conn, &rep) < 0) goto rete;
|
|
||||||
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 (writePacket(conn, &rep) < 0) goto rete;
|
|
||||||
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 (writePacket(conn, &rep) < 0) goto rete;
|
|
||||||
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 (writePacket(conn, &rep) < 0) goto rete;
|
|
||||||
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);
|
|
||||||
/*for (int x = -9; x < 10; x++) {
|
|
||||||
for (int z = -9; z < 10; z++) {
|
|
||||||
struct chunk* ch = getChunk(overworld, x + (int32_t) ep->x / 16, z + (int32_t) ep->z / 16);
|
|
||||||
if (ch != NULL) {
|
|
||||||
struct packet* pkt = xmalloc(sizeof(struct packet));
|
|
||||||
pkt->id = PKT_PLAY_CLIENT_CHUNKDATA;
|
|
||||||
pkt->data.play_client.chunkdata.data = ch;
|
|
||||||
pkt->data.play_client.chunkdata.ground_up_continuous = 1;
|
|
||||||
pkt->data.play_client.chunkdata.number_of_block_entities = 0;
|
|
||||||
pkt->data.play_client.chunkdata.block_entities = NULL;
|
|
||||||
add_queue(player->conn->outgoingPacket, pkt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (conn->state == STATE_PLAY) {
|
} else if (conn->state == STATE_PLAY) {
|
||||||
|
|
Loading…
Reference in New Issue