summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhemagx <hemagx2@gmail.com>2016-03-28 21:54:46 +0200
committerHaru <haru@dotalux.com>2016-04-16 07:38:31 +0200
commitd60ef91d8355f117c1ad5209b3f43647b9656892 (patch)
tree6cd5c3de31116b04a9b57ef0ad1edc1947c4c410 /src
parent9defceef6a3371d09b580ac8f2cffd0476033ea6 (diff)
downloadhercules-d60ef91d8355f117c1ad5209b3f43647b9656892.tar.gz
hercules-d60ef91d8355f117c1ad5209b3f43647b9656892.tar.bz2
hercules-d60ef91d8355f117c1ad5209b3f43647b9656892.tar.xz
hercules-d60ef91d8355f117c1ad5209b3f43647b9656892.zip
Rewrite client interface for login server (part 3)
Rewritten login clif parser, using a packet db Signed-off-by: Haru <haru@dotalux.com>
Diffstat (limited to 'src')
-rw-r--r--src/login/login.c507
-rw-r--r--src/login/login.h19
2 files changed, 311 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 <account.userid>.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 <md5 hash>.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 <version>.L <username>.24B <password>.24B <clienttype>.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 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.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 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B <g_isGravityID>.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 <version>.L <username>.24B <password hash>.16B <clienttype>.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 <version>.L <username>.24B <password hash>.16B <clienttype>.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 <version>.L <username>.24B <password hash>.16B <clienttype>.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 <packetsize>.W <version>.L <clienttype>.B <userid>.24B <password>.27B <mac>.17B <ip>.15B <token>.(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