From d60ef91d8355f117c1ad5209b3f43647b9656892 Mon Sep 17 00:00:00 2001 From: hemagx Date: Mon, 28 Mar 2016 21:54:46 +0200 Subject: Rewrite client interface for login server (part 3) Rewritten login clif parser, using a packet db Signed-off-by: Haru --- src/login/login.c | 507 ++++++++++++++++++++++++----------------- src/login/login.h | 19 +- tools/HPMHookGen/HPMHookGen.pl | 2 + 3 files changed, 313 insertions(+), 215 deletions(-) diff --git a/src/login/login.c b/src/login/login.c index f20959979..bbd16abab 100644 --- a/src/login/login.c +++ b/src/login/login.c @@ -52,6 +52,8 @@ struct mmo_char_server server[MAX_SERVERS]; // char server data #define MIN_PACKET_DB 0x0064 #define MAX_PACKET_DB 0x08ff +/* Enums */ + /// Packet IDs enum login_packet_id { // CA (Client to Login) @@ -76,76 +78,109 @@ enum login_packet_id { PACKET_ID_AC_REFUSE_LOGIN_R2 = 0x083e, }; +/* Function Typedefs */ +typedef enum parsefunc_rcode (LoginParseFunc)(int fd, struct login_session_data *sd); + +/* Structs */ +/// Login packet DB entry +struct login_packet_db { + int16 len; ///< Packet length + LoginParseFunc *pFunc; ///< Packet parsing function +}; + /* Packets Structs */ #if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute #pragma pack(push, 1) #endif // not NetBSD < 6 / Solaris +/** + * Packet structure for CA_LOGIN. + */ struct packet_CA_LOGIN { - int16 packet_id; - uint32 version; - char id[24]; - char password[24]; - uint8 clienttype; + int16 packet_id; ///< Packet ID (#PACKET_ID_CA_LOGIN) + uint32 version; ///< Client Version + char id[24]; ///< Username + char password[24]; ///< Password + uint8 clienttype; ///< Client Type } __attribute__((packed)); +/** + * Packet structure for CA_LOGIN2. + */ struct packet_CA_LOGIN2 { - int16 packet_id; - uint32 version; - char id[24]; - uint8 password_md5[16]; - uint8 clienttype; + int16 packet_id; ///< Packet ID (#PACKET_ID_CA_LOGIN2) + uint32 version; ///< Client Version + char id[24]; ///< Username + uint8 password_md5[16]; ///< Password hash + uint8 clienttype; ///< Client Type } __attribute__((packed)); +/** + * Packet structure for CA_LOGIN3. + */ struct packet_CA_LOGIN3 { - int16 packet_id; - uint32 version; - char id[24]; - uint8 password_md5[16]; - uint8 clienttype; - uint8 clientinfo; + int16 packet_id; ///< Packet ID (#PACKET_ID_CA_LOGIN3) + uint32 version; ///< Client Version + char id[24]; ///< Username + uint8 password_md5[16]; ///< Password hash + uint8 clienttype; ///< Client Type + uint8 clientinfo; ///< Index of the connection in the clientinfo file (+10 if the command-line contains "pc") } __attribute__((packed)); +/** + * Packet structure for CA_LOGIN4. + */ struct packet_CA_LOGIN4 { - int16 packet_id; - uint32 version; - char id[24]; - uint8 password_md5[16]; - uint8 clienttype; - char mac_address[13]; + int16 packet_id; ///< Packet ID (#PACKET_ID_CA_LOGIN4) + uint32 version; ///< Client Version + char id[24]; ///< Username + uint8 password_md5[16]; ///< Password hash + uint8 clienttype; ///< Client Type + char mac_address[13]; ///< MAC Address } __attribute__((packed)); +/** + * Packet structure for CA_LOGIN_PCBANG. + */ struct packet_CA_LOGIN_PCBANG { - int16 packet_id; - uint32 version; - char id[24]; - char password[24]; - uint8 clienttype; - char ip[16]; - char mac_address[13]; + int16 packet_id; ///< Packet ID (#PACKET_ID_CA_LOGIN_PCBANG) + uint32 version; ///< Client Version + char id[24]; ///< Username + char password[24]; ///< Password + uint8 clienttype; ///< Client Type + char ip[16]; ///< IP Address + char mac_address[13]; ///< MAC Address } __attribute__((packed)); +/** + * Packet structure for CA_LOGIN_HAN. + */ struct packet_CA_LOGIN_HAN { - int16 packet_id; - uint32 version; - char id[24]; - char password[24]; - uint8 clienttype; - char ip[16]; - char mac_address[13]; - uint8 is_han_game_user; + int16 packet_id; ///< Packet ID (#PACKET_ID_CA_LOGIN_HAN) + uint32 version; ///< Client Version + char id[24]; ///< Username + char password[24]; ///< Password + uint8 clienttype; ///< Client Type + char ip[16]; ///< IP Address + char mac_address[13]; ///< MAC Address + uint8 is_han_game_user; ///< 'isGravityID' } __attribute__((packed)); +/** + * Packet structure for CA_SSO_LOGIN_REQ. + * + * Variable-length packet. + */ struct packet_CA_SSO_LOGIN_REQ { - int16 packet_id; - int16 packet_len; - uint32 version; - uint8 clienttype; - char id[24]; - char password[27]; - int8 mac_address[17]; - char ip[15]; - char t1[]; + int16 packet_id; ///< Packet ID (#PACKET_ID_CA_SSO_LOGIN_REQ) + int16 packet_len; ///< Length (variable length) + uint32 version; ///< Clientver + uint8 clienttype; ///< Clienttype + char id[24]; ///< Username + char password[27]; ///< Password + int8 mac_address[17]; ///< MAC Address + char ip[15]; ///< IP Address + char t1[]; ///< SSO Login Token (variable length) } __attribute__((packed)); #if 0 // Unused @@ -161,18 +196,31 @@ struct packet_CA_SSO_LOGIN_REQa { } __attribute__((packed)); #endif // unused +/** + * Packet structure for CA_CONNECT_INFO_CHANGED. + * + * New alive packet. Used to verify if client is always alive. + */ struct packet_CA_CONNECT_INFO_CHANGED { - int16 packet_id; - char id[24]; + int16 packet_id; ///< Packet ID (#PACKET_ID_CA_CONNECT_INFO_CHANGED) + char id[24]; ///< account.userid } __attribute__((packed)); +/** + * Packet structure for CA_EXE_HASHCHECK. + * + * (kRO 2004-05-31aSakexe langtype 0 and 6) + */ struct packet_CA_EXE_HASHCHECK { - int16 packet_id; - uint8 hash_value[16]; + int16 packet_id; ///< Packet ID (#PACKET_ID_CA_EXE_HASHCHECK) + uint8 hash_value[16]; ///< Client MD5 hash } __attribute__((packed)); +/** + * Packet structure for CA_REQ_HASH. + */ struct packet_CA_REQ_HASH { - int16 packet_id; + int16 packet_id; ///< Packet ID (#PACKET_ID_CA_REQ_HASH) } __attribute__((packed)); struct packet_CA_CHARSERVERCONNECT { @@ -238,6 +286,8 @@ struct Account_engine account_engine[] = { {account_db_sql, NULL} }; +struct login_packet_db packet_db[MAX_PACKET_DB + 1]; + // account database AccountDB* accounts = NULL; @@ -1597,26 +1647,23 @@ void login_login_error(int fd, uint8 error) WFIFOSET(fd, sizeof(*packet)); } -// CA_CONNECT_INFO_CHANGED -void login_parse_ping(int fd, struct login_session_data* sd) __attribute__((nonnull (2))); -void login_parse_ping(int fd, struct login_session_data* sd) +enum parsefunc_rcode login_parse_CA_CONNECT_INFO_CHANGED(int fd, struct login_session_data *sd) __attribute__((nonnull (2))); +enum parsefunc_rcode login_parse_CA_CONNECT_INFO_CHANGED(int fd, struct login_session_data *sd) { - RFIFOSKIP(fd, sizeof(struct packet_CA_CONNECT_INFO_CHANGED)); + return PACKET_VALID; } -// CA_EXE_HASHCHECK -void login_parse_client_md5(int fd, struct login_session_data* sd) __attribute__((nonnull (2))); -void login_parse_client_md5(int fd, struct login_session_data* sd) +enum parsefunc_rcode login_parse_CA_EXE_HASHCHECK(int fd, struct login_session_data *sd) __attribute__((nonnull (2))); +enum parsefunc_rcode login_parse_CA_EXE_HASHCHECK(int fd, struct login_session_data *sd) { const struct packet_CA_EXE_HASHCHECK *packet = RP2PTR(fd); sd->has_client_hash = 1; memcpy(sd->client_hash, packet->hash_value, 16); - RFIFOSKIP(fd,sizeof(*packet)); + return PACKET_VALID; } -// CA_LOGIN -void login_parse_CA_LOGIN(int fd, struct login_session_data *sd) __attribute__((nonnull (2))); -void login_parse_CA_LOGIN(int fd, struct login_session_data *sd) +enum parsefunc_rcode login_parse_CA_LOGIN(int fd, struct login_session_data *sd) __attribute__((nonnull (2))); +enum parsefunc_rcode login_parse_CA_LOGIN(int fd, struct login_session_data *sd) { const struct packet_CA_LOGIN *packet = RP2PTR(fd); @@ -1625,16 +1672,16 @@ void login_parse_CA_LOGIN(int fd, struct login_session_data *sd) safestrncpy(sd->userid, packet->id, NAME_LENGTH); safestrncpy(sd->passwd, packet->password, PASSWD_LEN); - RFIFOSKIP(fd, sizeof(*packet)); - if (login->config->use_md5_passwds) MD5_String(sd->passwd, sd->passwd); sd->passwdenc = PWENC_NONE; + + login->client_login(fd, sd); + return PACKET_VALID; } -// CA_LOGIN2 -void login_parse_CA_LOGIN2(int fd, struct login_session_data *sd) __attribute__((nonnull (2))); -void login_parse_CA_LOGIN2(int fd, struct login_session_data *sd) +enum parsefunc_rcode login_parse_CA_LOGIN2(int fd, struct login_session_data *sd) __attribute__((nonnull (2))); +enum parsefunc_rcode login_parse_CA_LOGIN2(int fd, struct login_session_data *sd) { const struct packet_CA_LOGIN2 *packet = RP2PTR(fd); @@ -1644,12 +1691,12 @@ void login_parse_CA_LOGIN2(int fd, struct login_session_data *sd) bin2hex(sd->passwd, packet->password_md5, 16); sd->passwdenc = PASSWORDENC; - RFIFOSKIP(fd, sizeof(*packet)); + login->client_login(fd, sd); + return PACKET_VALID; } -// CA_LOGIN3 -void login_parse_CA_LOGIN3(int fd, struct login_session_data *sd) __attribute__((nonnull (2))); -void login_parse_CA_LOGIN3(int fd, struct login_session_data *sd) +enum parsefunc_rcode login_parse_CA_LOGIN3(int fd, struct login_session_data *sd) __attribute__((nonnull (2))); +enum parsefunc_rcode login_parse_CA_LOGIN3(int fd, struct login_session_data *sd) { const struct packet_CA_LOGIN3 *packet = RP2PTR(fd); @@ -1661,12 +1708,12 @@ void login_parse_CA_LOGIN3(int fd, struct login_session_data *sd) bin2hex(sd->passwd, packet->password_md5, 16); sd->passwdenc = PASSWORDENC; - RFIFOSKIP(fd, sizeof(*packet)); + login->client_login(fd, sd); + return PACKET_VALID; } -// CA_LOGIN4 -void login_parse_CA_LOGIN4(int fd, struct login_session_data *sd) __attribute__((nonnull (2))); -void login_parse_CA_LOGIN4(int fd, struct login_session_data *sd) +enum parsefunc_rcode login_parse_CA_LOGIN4(int fd, struct login_session_data *sd) __attribute__((nonnull (2))); +enum parsefunc_rcode login_parse_CA_LOGIN4(int fd, struct login_session_data *sd) { const struct packet_CA_LOGIN4 *packet = RP2PTR(fd); @@ -1678,12 +1725,12 @@ void login_parse_CA_LOGIN4(int fd, struct login_session_data *sd) bin2hex(sd->passwd, packet->password_md5, 16); sd->passwdenc = PASSWORDENC; - RFIFOSKIP(fd, sizeof(*packet)); + login->client_login(fd, sd); + return PACKET_VALID; } -// CA_LOGIN_PCBANG -void login_parse_CA_LOGIN_PCBANG(int fd, struct login_session_data *sd) __attribute__((nonnull (2))); -void login_parse_CA_LOGIN_PCBANG(int fd, struct login_session_data *sd) +enum parsefunc_rcode login_parse_CA_LOGIN_PCBANG(int fd, struct login_session_data *sd) __attribute__((nonnull (2))); +enum parsefunc_rcode login_parse_CA_LOGIN_PCBANG(int fd, struct login_session_data *sd) { const struct packet_CA_LOGIN_PCBANG *packet = RP2PTR(fd); @@ -1695,16 +1742,16 @@ void login_parse_CA_LOGIN_PCBANG(int fd, struct login_session_data *sd) safestrncpy(sd->userid, packet->id, NAME_LENGTH); safestrncpy(sd->passwd, packet->password, PASSWD_LEN); - RFIFOSKIP(fd, sizeof(*packet)); - if (login->config->use_md5_passwds) MD5_String(sd->passwd, sd->passwd); sd->passwdenc = PWENC_NONE; + + login->client_login(fd, sd); + return PACKET_VALID; } -// CA_LOGIN_HAN -void login_parse_CA_LOGIN_HAN(int fd, struct login_session_data *sd) __attribute__((nonnull (2))); -void login_parse_CA_LOGIN_HAN(int fd, struct login_session_data *sd) +enum parsefunc_rcode login_parse_CA_LOGIN_HAN(int fd, struct login_session_data *sd) __attribute__((nonnull (2))); +enum parsefunc_rcode login_parse_CA_LOGIN_HAN(int fd, struct login_session_data *sd) { const struct packet_CA_LOGIN_HAN *packet = RP2PTR(fd); @@ -1717,23 +1764,24 @@ void login_parse_CA_LOGIN_HAN(int fd, struct login_session_data *sd) safestrncpy(sd->userid, packet->id, NAME_LENGTH); safestrncpy(sd->passwd, packet->password, PASSWD_LEN); - RFIFOSKIP(fd, sizeof(*packet)); - if (login->config->use_md5_passwds) MD5_String(sd->passwd, sd->passwd); sd->passwdenc = PWENC_NONE; + + login->client_login(fd, sd); + return PACKET_VALID; } -// CA_SSO_LOGIN_REQ -bool login_parse_CA_SSO_LOGIN_REQ(int fd, struct login_session_data *sd) __attribute__((nonnull (2))); -bool login_parse_CA_SSO_LOGIN_REQ(int fd, struct login_session_data *sd) +enum parsefunc_rcode login_parse_CA_SSO_LOGIN_REQ(int fd, struct login_session_data *sd) __attribute__((nonnull (2))); +enum parsefunc_rcode login_parse_CA_SSO_LOGIN_REQ(int fd, struct login_session_data *sd) { const struct packet_CA_SSO_LOGIN_REQ *packet = RP2PTR(fd); int tokenlen = (int)RFIFOREST(fd) - (int)sizeof(*packet); if (tokenlen > PASSWD_LEN || tokenlen < 1) { - RFIFOSKIP(fd, RFIFOREST(fd)); // assume no other packet was sent - return false; + ShowError("login_parse_CA_SSO_LOGIN_REQ: Token length is not between allowed password length, kicking player ('%s')", packet->id); + sockt->eof(fd); + return PACKET_VALID; } sd->clienttype = packet->clienttype; @@ -1741,50 +1789,21 @@ bool login_parse_CA_SSO_LOGIN_REQ(int fd, struct login_session_data *sd) safestrncpy(sd->userid, packet->id, NAME_LENGTH); safestrncpy(sd->passwd, packet->t1, min(tokenlen + 1, PASSWD_LEN)); // Variable-length field, don't copy more than necessary - RFIFOSKIP(fd, sizeof(*packet)); - if (login->config->use_md5_passwds) MD5_String(sd->passwd, sd->passwd); sd->passwdenc = PWENC_NONE; - return true; + + login->client_login(fd, sd); + return PACKET_VALID; } -bool login_parse_client_login(int fd, struct login_session_data* sd, const char *const ip) __attribute__((nonnull (2))); -bool login_parse_client_login(int fd, struct login_session_data* sd, const char *const ip) +bool login_client_login(int fd, struct login_session_data *sd) __attribute__((nonnull (2))); +bool login_client_login(int fd, struct login_session_data *sd) { int result; - uint16 command = RFIFOW(fd,0); - - switch (command) { - case PACKET_ID_CA_SSO_LOGIN_REQ: - if (!login_parse_CA_SSO_LOGIN_REQ(fd, sd)) { - login->auth_failed(sd, 3); - return true; - } - break; - case PACKET_ID_CA_LOGIN: - login_parse_CA_LOGIN(fd, sd); - break; - case PACKET_ID_CA_LOGIN2: - login_parse_CA_LOGIN2(fd, sd); - break; - case PACKET_ID_CA_LOGIN3: - login_parse_CA_LOGIN3(fd, sd); - break; - case PACKET_ID_CA_LOGIN4: - login_parse_CA_LOGIN4(fd, sd); - break; - case PACKET_ID_CA_LOGIN_PCBANG: - login_parse_CA_LOGIN_PCBANG(fd, sd); - break; - case PACKET_ID_CA_LOGIN_HAN: - login_parse_CA_LOGIN_HAN(fd, sd); - break; - default: - RFIFOSKIP(fd,RFIFOREST(fd)); // assume no other packet was sent - login->auth_failed(sd, 3); // send "rejected from server" - return true; - } + char ip[16]; + uint32 ipl = sockt->session[fd]->client_addr; + sockt->ip2str(ipl, ip); ShowStatus("Request for connection %sof %s (ip: %s).\n", sd->passwdenc == PASSWORDENC ? " (passwdenc mode)" : "", sd->userid, ip); @@ -1794,11 +1813,11 @@ bool login_parse_client_login(int fd, struct login_session_data* sd, const char } result = login->mmo_auth(sd, false); - if( result == -1 ) login->auth_ok(sd); else login->auth_failed(sd, result); + return false; } @@ -1816,16 +1835,15 @@ void login_send_coding_key(int fd, struct login_session_data* sd) WFIFOSET(fd, size); } -// CA_REQ_HASH -void login_parse_request_coding_key(int fd, struct login_session_data* sd) __attribute__((nonnull (2))); -void login_parse_request_coding_key(int fd, struct login_session_data* sd) +enum parsefunc_rcode login_parse_CA_REQ_HASH(int fd, struct login_session_data *sd) __attribute__((nonnull (2))); +enum parsefunc_rcode login_parse_CA_REQ_HASH(int fd, struct login_session_data *sd) { - RFIFOSKIP(fd, sizeof(struct packet_CA_REQ_HASH)); memset(sd->md5key, '\0', sizeof(sd->md5key)); sd->md5keylen = (uint16)(12 + rnd() % 4); MD5_Salt(sd->md5keylen, sd->md5key); login->send_coding_key(fd, sd); + return PACKET_VALID; } void login_char_server_connection_status(int fd, struct login_session_data* sd, uint8 status) __attribute__((nonnull (2))); @@ -1837,7 +1855,18 @@ void login_char_server_connection_status(int fd, struct login_session_data* sd, WFIFOSET(fd,3); } -// CA_CHARSERVERCONNECT +enum parsefunc_rcode login_parse_CA_CHARSERVERCONNECT(int fd, struct login_session_data *sd) __attribute__((nonnull (2))); +enum parsefunc_rcode login_parse_CA_CHARSERVERCONNECT(int fd, struct login_session_data *sd) +{ + char ip[16]; + uint32 ipl = sockt->session[fd]->client_addr; + sockt->ip2str(ipl, ip); + + login->parse_request_connection(fd, sd, ip, ipl); + + return PACKET_STOPPARSE; +} + void login_parse_request_connection(int fd, struct login_session_data* sd, const char *const ip, uint32 ipl) __attribute__((nonnull (2, 3))); void login_parse_request_connection(int fd, struct login_session_data* sd, const char *const ip, uint32 ipl) { @@ -1860,7 +1889,6 @@ void login_parse_request_connection(int fd, struct login_session_data* sd, const safestrncpy(server_name, RFIFOP(fd,60), 20); type = RFIFOW(fd,82); new_ = RFIFOW(fd,84); - RFIFOSKIP(fd,86); ShowInfo("Connection request of the char-server '%s' @ %u.%u.%u.%u:%u (account: '%s', pass: '%s', ip: '%s')\n", server_name, CONVIP(server_ip), server_port, sd->userid, sd->passwd, ip); sprintf(message, "charserver - %s@%u.%u.%u.%u:%u", server_name, CONVIP(server_ip), server_port); @@ -1898,6 +1926,25 @@ void login_parse_request_connection(int fd, struct login_session_data* sd, const } } +struct login_packet_db *login_lclif_packet(int16 packet_id) +{ + if (packet_id == PACKET_ID_CA_CHARSERVERCONNECT) + return &packet_db[0]; + + if (packet_id > MAX_PACKET_DB || packet_id < MIN_PACKET_DB) + return NULL; + + return &packet_db[packet_id]; +} + +enum parsefunc_rcode login_parse_packet(const struct login_packet_db *lpd, int fd, struct login_session_data *sd) +{ + int result; + result = lpd->pFunc(fd, sd); + RFIFOSKIP(fd, (lpd->len == -1) ? RFIFOW(fd, 2) : lpd->len); + return result; +} + //---------------------------------------------------------------------------------------- // Default packet parsing (normal players or char-server connection requests) //---------------------------------------------------------------------------------------- @@ -1931,93 +1978,86 @@ int login_parse_login(int fd) } while (RFIFOREST(fd) >= 2) { + enum parsefunc_rcode result; int16 packet_id = RFIFOW(fd, 0); int packet_len = (int)RFIFOREST(fd); if (packet_len < 2) return 0; - if (VECTOR_LENGTH(HPM->packets[hpParse_Login]) > 0) { - int result = HPM->parse_packets(fd, packet_id, hpParse_Login); - if (result == 1) - continue; - if (result == 2) - return 0; - } + result = login->parse_login_sub(fd, sd); - switch (packet_id) { - case PACKET_ID_CA_CONNECT_INFO_CHANGED: // New alive packet: structure: 0x200 .24B. used to verify if client is always alive. - if (packet_len < (int)sizeof(struct packet_CA_CONNECT_INFO_CHANGED)) - return 0; - login->parse_ping(fd, sd); - break; - case PACKET_ID_CA_EXE_HASHCHECK: // S 0204 .16B (kRO 2004-05-31aSakexe langtype 0 and 6) - if (packet_len < (int)sizeof(struct packet_CA_EXE_HASHCHECK)) - return 0; - login->parse_client_md5(fd, sd); - break; - case PACKET_ID_CA_LOGIN: // S 0064 .L .24B .24B .B - if (packet_len < (int)sizeof(struct packet_CA_LOGIN)) - return 0; - if (login->parse_client_login(fd, sd, ip)) - return 0; - break; - case PACKET_ID_CA_LOGIN_PCBANG: // S 0277 .L .24B .24B .B .16B .13B - if (packet_len < (int)sizeof(struct packet_CA_LOGIN_PCBANG)) - return 0; - if (login->parse_client_login(fd, sd, ip)) - return 0; - break; - case PACKET_ID_CA_LOGIN_HAN: // S 02b0 .L .24B .24B .B .16B .13B .B - if (packet_len < (int)sizeof(struct packet_CA_LOGIN_HAN)) - return 0; - if (login->parse_client_login(fd, sd, ip)) - return 0; - break; - case PACKET_ID_CA_LOGIN2: // S 01dd .L .24B .16B .B - if (packet_len < (int)sizeof(struct packet_CA_LOGIN2)) - return 0; - if (login->parse_client_login(fd, sd, ip)) - return 0; - break; - case PACKET_ID_CA_LOGIN3: // S 01fa .L .24B .16B .B .B(index of the connection in the clientinfo file (+10 if the command-line contains "pc")) - if (packet_len < (int)sizeof(struct packet_CA_LOGIN3)) - return 0; - if (login->parse_client_login(fd, sd, ip)) - return 0; - break; - case PACKET_ID_CA_LOGIN4: // S 027c .L .24B .16B .B .13B(junk) - if (packet_len < (int)sizeof(struct packet_CA_LOGIN4)) - return 0; - if (login->parse_client_login(fd, sd, ip)) - return 0; - break; - case PACKET_ID_CA_SSO_LOGIN_REQ: // S 0825 .W .L .B .24B .27B .17B .15B .(packetsize - 0x5C)B - if (packet_len < (int)sizeof(struct packet_CA_SSO_LOGIN_REQ) || packet_len < RFIFOW(fd, 2)) - return 0; - if (login->parse_client_login(fd, sd, ip)) - return 0; - break; - case PACKET_ID_CA_REQ_HASH: - if (packet_len < (int)sizeof(struct packet_CA_REQ_HASH)) - return 0; - login->parse_request_coding_key(fd, sd); - break; - case PACKET_ID_CA_CHARSERVERCONNECT: - if (packet_len < (int)sizeof(struct packet_CA_CHARSERVERCONNECT)) - return 0; - login->parse_request_connection(fd, sd, ip, ipl); - return 0; // processing will continue elsewhere - default: - ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, (unsigned int)packet_id); + switch (result) { + case PACKET_SKIP: + continue; + case PACKET_INCOMPLETE: + case PACKET_STOPPARSE: + return 0; + case PACKET_UNKNOWN: + ShowWarning("login_parse_login: Received unsupported packet (packet 0x%04x, %d bytes received), disconnecting session #%d.\n", (unsigned int)packet_id, packet_len, fd); +#ifdef DUMP_INVALID_PACKET + ShowDump(RFIFOP(fd, 0), RFIFOREST(fd)); +#endif + sockt->eof(fd); + return 0; + case PACKET_INVALIDLENGTH: + ShowWarning("login_parse_login: Received packet 0x%04x specifies invalid packet_len (%d), disconnecting session #%d.\n", (unsigned int)packet_id, packet_len, fd); +#ifdef DUMP_INVALID_PACKET + ShowDump(RFIFOP(fd, 0), RFIFOREST(fd)); +#endif sockt->eof(fd); return 0; } } - return 0; } +enum parsefunc_rcode login_parse_login_sub(int fd, struct login_session_data *sd) +{ + int packet_len = (int)RFIFOREST(fd); + int16 packet_id = RFIFOW(fd, 0); + const struct login_packet_db *lpd; + + if (VECTOR_LENGTH(HPM->packets[hpParse_Login]) > 0) { + int result = HPM->parse_packets(fd, packet_id, hpParse_Login); + if (result == 1) + return PACKET_VALID; + if (result == 2) + return PACKET_INCOMPLETE; // Packet not completed yet + } + + lpd = login_lclif_packet(packet_id); + + if (lpd == NULL) + return PACKET_UNKNOWN; + + if (lpd->len == 0) + return PACKET_UNKNOWN; + + if (lpd->len > 0 && lpd->pFunc == NULL) + return PACKET_UNKNOWN; //This Packet is defined for length purpose ? should never be sent from client ? + + if (lpd->len == -1) { + uint16 packet_var_len = 0; //Max Variable Packet length is signed int16 size + + if (packet_len < 4) + return PACKET_INCOMPLETE; //Packet incomplete + + packet_var_len = RFIFOW(fd, 2); + + if (packet_var_len < 4 || packet_var_len > SINT16_MAX) + return PACKET_INVALIDLENGTH; //Something is wrong, close connection. + + if (RFIFOREST(fd) < packet_var_len) + return PACKET_INCOMPLETE; //Packet incomplete again. + + return login->parse_packet(lpd, fd, sd); + } else if (lpd->len <= packet_len) { + return login->parse_packet(lpd, fd, sd); + } + + return PACKET_VALID; +} void login_config_set_defaults(void) { @@ -2286,6 +2326,47 @@ void cmdline_args_init_local(void) CMDLINEARG_DEF2(net-config, netconfig, "Alternative subnet configuration.", CMDLINE_OPT_PARAM); } +void packetdb_loaddb(void) +{ + + int i; + struct packet { + int16 packet_id; + int16 packet_len; + int (*pFunc)(int, struct login_session_data *); + } packet[] = { +#define packet_def(name) { PACKET_ID_ ## name, sizeof(struct packet_ ## name), login_parse_ ## name } +#define packet_def2(name, len) { PACKET_ID_ ## name, (len), login_parse_ ## name } + packet_def(CA_CONNECT_INFO_CHANGED), + packet_def(CA_EXE_HASHCHECK), + packet_def(CA_LOGIN), + packet_def(CA_LOGIN2), + packet_def(CA_LOGIN3), + packet_def(CA_LOGIN4), + packet_def(CA_LOGIN_PCBANG), + packet_def(CA_LOGIN_HAN), + packet_def2(CA_SSO_LOGIN_REQ, -1), + packet_def(CA_REQ_HASH), +#undef packet_def +#undef packet_def2 + }; + int length = ARRAYLENGTH(packet); + + memset(packet_db, '\0', sizeof(packet_db)); + + for (i = 0; i < length; ++i) { + int16 packet_id = packet[i].packet_id; + Assert_retb(packet_id >= MIN_PACKET_DB && packet_id < MAX_PACKET_DB); + packet_db[packet_id].len = packet[i].packet_len; + packet_db[packet_id].pFunc = packet[i].pFunc; + } + + //Explict case, we will save character login packet in position 0 which is unused and not valid by normal + packet_db[0].len = sizeof(struct packet_CA_CHARSERVERCONNECT); + packet_db[0].pFunc = login_parse_CA_CHARSERVERCONNECT; + +} + //------------------------------ // Login server initialization //------------------------------ @@ -2318,6 +2399,8 @@ int do_init(int argc, char** argv) login_config_read(login->LOGIN_CONF_NAME); sockt->net_config_read(login->NET_CONF_NAME); + packetdb_loaddb(); + for( i = 0; i < ARRAYLENGTH(server); ++i ) chrif_server_init(i); @@ -2429,11 +2512,6 @@ void login_defaults(void) { login->parse_fromchar = login_parse_fromchar; login->parse_login = login_parse_login; - login->parse_ping = login_parse_ping; - login->parse_client_md5 = login_parse_client_md5; - login->parse_client_login = login_parse_client_login; - login->parse_request_coding_key = login_parse_request_coding_key; - login->parse_request_connection = login_parse_request_connection; login->auth_ok = login_auth_ok; login->auth_failed = login_auth_failed; login->char_server_connection_status = login_char_server_connection_status; @@ -2446,4 +2524,7 @@ void login_defaults(void) { login->config_read = login_config_read; login->LOGIN_CONF_NAME = NULL; login->NET_CONF_NAME = NULL; + + login->parse_packet = login_parse_packet; + login->parse_login_sub = login_parse_login_sub; } diff --git a/src/login/login.h b/src/login/login.h index 0676aee1f..e29953b9e 100644 --- a/src/login/login.h +++ b/src/login/login.h @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2012-2015 Hercules Dev Team + * Copyright (C) 2012-2016 Hercules Dev Team * Copyright (C) Athena Dev Teams * * Hercules is free software: you can redistribute it and/or modify @@ -28,6 +28,7 @@ struct mmo_account; struct AccountDB; +struct login_packet_db; enum E_LOGINSERVER_ST { @@ -43,6 +44,16 @@ enum password_enc { PWENC_BOTH = PWENC_ENCRYPT|PWENC_ENCRYPT2, ///< both the above }; +/// Parse function return code +enum parsefunc_rcode { + PACKET_VALID = 1, + PACKET_INCOMPLETE = 0, + PACKET_UNKNOWN = -1, + PACKET_INVALIDLENGTH = -2, + PACKET_STOPPARSE = -3, + PACKET_SKIP = -4, //internal parser will skip this packet and go parser another, meant for plugins. [hemagx] +}; + #define PASSWORDENC PWENC_BOTH #define PASSWD_LEN (32+1) // 23+1 for plaintext, 32+1 for md5-ed passwords @@ -203,7 +214,7 @@ struct login_interface { void (*login_error) (int fd, uint8 error); void (*parse_ping) (int fd, struct login_session_data* sd); void (*parse_client_md5) (int fd, struct login_session_data* sd); - bool (*parse_client_login) (int fd, struct login_session_data* sd, const char *ip); + bool (*client_login) (int fd, struct login_session_data *sd); void (*send_coding_key) (int fd, struct login_session_data* sd); void (*parse_request_coding_key) (int fd, struct login_session_data* sd); void (*char_server_connection_status) (int fd, struct login_session_data* sd, uint8 status); @@ -213,6 +224,10 @@ struct login_interface { int (*config_read) (const char *cfgName); char *LOGIN_CONF_NAME; char *NET_CONF_NAME; ///< Network configuration filename + + // lclif + enum parsefunc_rcode (*parse_packet)(const struct login_packet_db *lpd, int fd, struct login_session_data *sd); + enum parsefunc_rcode (*parse_login_sub)(int fd, struct login_session_data *sd); }; #ifdef HERCULES_CORE diff --git a/tools/HPMHookGen/HPMHookGen.pl b/tools/HPMHookGen/HPMHookGen.pl index 9b6fcdf8b..74cc0f863 100755 --- a/tools/HPMHookGen/HPMHookGen.pl +++ b/tools/HPMHookGen/HPMHookGen.pl @@ -237,6 +237,8 @@ sub parse($$) { $rtinit = ' = HCS_STATUS_FAIL'; } elsif ($x =~ /^enum\s+bg_queue_types$/) { # Known enum bg_queue_types $rtinit = ' = BGQT_INVALID'; + } elsif ($x =~ /^enum\s+parsefunc_rcode$/) { # Known enum parsefunc_rcode + $rtinit = ' = PACKET_UNKNOWN'; } elsif ($x =~ /^(?:enum\s+)?DBOptions$/) { # Known enum DBOptions $rtinit = ' = DB_OPT_BASE'; } elsif ($x eq 'DBComparator' or $x eq 'DBHasher' or $x eq 'DBReleaser') { # DB function pointers -- cgit v1.2.3-60-g2f50