From a56b3ea671e9cc74b3f9ea723bc149e83212b998 Mon Sep 17 00:00:00 2001 From: gumi Date: Sun, 30 Dec 2018 16:06:06 -0500 Subject: pre-send the auth details to map servers instead of blindly trusting 0x0072 --- src/char/char.cpp | 175 ++++++++++++++++++++++++++++++++++++---------------- src/map/chrif.cpp | 24 +++++++ src/map/chrif.hpp | 2 + src/map/clif.cpp | 27 +++++++- src/map/fwd.hpp | 2 + src/map/globals.cpp | 3 + src/map/globals.hpp | 3 + src/map/intif.cpp | 10 +++ src/map/map.hpp | 15 +++++ tools/protocol.py | 32 ++++++++++ 10 files changed, 238 insertions(+), 55 deletions(-) diff --git a/src/char/char.cpp b/src/char/char.cpp index eac1e06..81b2ab7 100644 --- a/src/char/char.cpp +++ b/src/char/char.cpp @@ -103,6 +103,7 @@ struct char_session_data : SessionData SEX sex; ClientVersion client_version; AccountEmail email; + int consumed_by; // amount of map servers for which we are authed }; } // namespace char_ @@ -1600,6 +1601,37 @@ void map_anti_freeze_system(TimerData *, tick_t) } } +static +int search_mapserver(XString map) +{ + for (int i = 0; i < MAX_MAP_SERVERS; i++) + { + if (server_session[i]) + { + for (int j = 0; server[i].maps[j]; j++) + { + if (server[i].maps[j] == map) + return i; + } + } + } + + return -1; +} + +//----------------------------------------------------- +// Test to know if an IP come from LAN or WAN. by [Yor] +//----------------------------------------------------- +static +int lan_ip_check(IP4Address addr) +{ + bool lancheck = char_lan_conf.lan_subnet.covers(addr); + + PRINTF("LAN test (result): %s.\n"_fmt, + (lancheck) ? SGR_BOLD SGR_CYAN "LAN source" SGR_RESET ""_s : SGR_BOLD SGR_GREEN "WAN source" SGR_RESET ""_s); + return lancheck; +} + static void parse_frommap(Session *ms) { @@ -2105,6 +2137,86 @@ void parse_frommap(Session *ms) } } + case 0x3830: + { + Packet_Fixed<0x3830> fixed; + rv = recv_fpacket<0x3830, 22>(ms, fixed); + if (rv != RecvResult::Complete) + break; + + for (io::FD i : iter_fds()) + { + Session *s2 = get_session(i); + if (!s2) + continue; + struct char_session_data *sd = static_cast(s2->session_data.get()); + + if (sd && sd->account_id == fixed.account_id && + sd->login_id1 == fixed.login_id1 && + sd->login_id2 == fixed.login_id2 /*&& + sd->ip == fixed.ip &&*/) + { + sd->consumed_by++; // one char server consumed this + + CHAR_LOG_AND_ECHO("Map server %i accepted pre-auth details for account %d [%s].\n"_fmt, + id, fixed.account_id, fixed.ip); + + int server_count = 0; + // FIXME: this is silly, we should have a active_map_servers global var + for (Session *ss : iter_map_sessions()) + if (ss) + server_count++; + + if (sd->consumed_by == server_count) { + + CHAR_LOG_AND_ECHO("All map servers accepted pre-auth details for account %d [%s], sending authorization to client...\n"_fmt, + fixed.account_id, fixed.ip); + + CharPair *cp = nullptr; + for (CharPair& cdi : char_keys) + { + if (cdi.key.account_id == sd->account_id && cdi.key.char_id == fixed.char_id) + { + cp = &cdi; + break; + } + } + + if (!cp) + return; + CharKey *ck = &cp->key; + CharData *cd = cp->data.get(); + int mi = search_mapserver(cd->last_point.map_); + + // now that preauth is done we prepare for actual auth + if (auth_fifo_iter == auth_fifo.end()) + auth_fifo_iter = auth_fifo.begin(); + auth_fifo_iter->account_id = sd->account_id; + auth_fifo_iter->char_id = ck->char_id; + auth_fifo_iter->login_id1 = sd->login_id1; + auth_fifo_iter->login_id2 = sd->login_id2; + auth_fifo_iter->delflag = 3; + auth_fifo_iter->sex = sd->sex; + auth_fifo_iter->ip = s2->client_ip; + auth_fifo_iter->client_version = sd->client_version; + auth_fifo_iter++; + + Packet_Fixed<0x0071> fixed_71; + fixed_71.char_id = ck->char_id; + fixed_71.map_name = cd->last_point.map_; + if (lan_ip_check(s2->client_ip)) + fixed_71.ip = char_lan_conf.lan_map_ip; + else + fixed_71.ip = server[mi].ip; + fixed_71.port = server[mi].port; + send_fpacket<0x0071, 28>(s2, fixed_71); + } + break; + } + } + break; + } + default: // inter server処理に渡す { @@ -2125,37 +2237,6 @@ void parse_frommap(Session *ms) ms->set_eof(); } -static -int search_mapserver(XString map) -{ - for (int i = 0; i < MAX_MAP_SERVERS; i++) - { - if (server_session[i]) - { - for (int j = 0; server[i].maps[j]; j++) - { - if (server[i].maps[j] == map) - return i; - } - } - } - - return -1; -} - -//----------------------------------------------------- -// Test to know if an IP come from LAN or WAN. by [Yor] -//----------------------------------------------------- -static -int lan_ip_check(IP4Address addr) -{ - bool lancheck = char_lan_conf.lan_subnet.covers(addr); - - PRINTF("LAN test (result): %s.\n"_fmt, - (lancheck) ? SGR_BOLD SGR_CYAN "LAN source" SGR_RESET ""_s : SGR_BOLD SGR_GREEN "WAN source" SGR_RESET ""_s); - return lancheck; -} - static void handle_x0066(Session *s, struct char_session_data *sd, uint8_t rfifob_2, IP4Address ip) { @@ -2206,27 +2287,16 @@ void handle_x0066(Session *s, struct char_session_data *sd, uint8_t rfifob_2, IP } } - Packet_Fixed<0x0071> fixed_71; - fixed_71.char_id = ck->char_id; - fixed_71.map_name = cd->last_point.map_; - if (lan_ip_check(ip)) - fixed_71.ip = char_lan_conf.lan_map_ip; - else - fixed_71.ip = server[i].ip; - fixed_71.port = server[i].port; - send_fpacket<0x0071, 28>(s, fixed_71); - - if (auth_fifo_iter == auth_fifo.end()) - auth_fifo_iter = auth_fifo.begin(); - auth_fifo_iter->account_id = sd->account_id; - auth_fifo_iter->char_id = ck->char_id; - auth_fifo_iter->login_id1 = sd->login_id1; - auth_fifo_iter->login_id2 = sd->login_id2; - auth_fifo_iter->delflag = 3; - auth_fifo_iter->sex = sd->sex; - auth_fifo_iter->ip = s->client_ip; - auth_fifo_iter->client_version = sd->client_version; - auth_fifo_iter++; + // send auth details to map server, wait for a reply + Packet_Fixed<0x3829> fixed_3829; + fixed_3829.account_id = ck->account_id; + fixed_3829.char_id = ck->char_id; + fixed_3829.login_id1 = sd->login_id1; + fixed_3829.login_id2 = sd->login_id2; + fixed_3829.ip = ip; + sd->consumed_by = 0; + for (Session *ss : iter_map_sessions()) + send_fpacket<0x3829, 22>(ss, fixed_3829); } } } @@ -2305,6 +2375,7 @@ void parse_char(Session *s) sd->login_id2 = fixed.login_id2; sd->sex = fixed.sex; sd->auth = false; // not authed yet + sd->consumed_by = 0; // formerly: send back account_id Packet_Payload<0x8000> special; diff --git a/src/map/chrif.cpp b/src/map/chrif.cpp index 42a13cf..9361c2e 100644 --- a/src/map/chrif.cpp +++ b/src/map/chrif.cpp @@ -340,6 +340,30 @@ int chrif_charselectreq(dumb_ptr sd) return 0; } +void chrif_parse_preauth(Session *s, const Packet_Fixed<0x3829>& fixed) +{ + if (auth_fifo_iter == auth_fifo.end()) + auth_fifo_iter = auth_fifo.begin(); + auth_fifo_iter->account_id = fixed.account_id; + auth_fifo_iter->char_id = fixed.char_id; + auth_fifo_iter->login_id1 = fixed.login_id1; + auth_fifo_iter->login_id2 = fixed.login_id2; + auth_fifo_iter->ip = fixed.ip; + auth_fifo_iter->delflag = 0; + auth_fifo_iter++; + + // tell char server we accepted the auth details + Packet_Fixed<0x3830> fixed_3830; + fixed_3830.account_id = fixed.account_id; + fixed_3830.char_id = fixed.char_id; + fixed_3830.login_id1 = fixed.login_id1; + fixed_3830.login_id2 = fixed.login_id2; + fixed_3830.ip = fixed.ip; + send_fpacket<0x3830, 22>(s, fixed_3830); + + MAP_LOG_AND_ECHO("Received pre-auth details for account %d [%s], replying to char server\n"_fmt, fixed.account_id, fixed.ip); +} + /*========================================== * Change Email *------------------------------------------ diff --git a/src/map/chrif.hpp b/src/map/chrif.hpp index 655103d..ea8096c 100644 --- a/src/map/chrif.hpp +++ b/src/map/chrif.hpp @@ -44,6 +44,8 @@ void chrif_char_ask_name(AccountId id, CharName character_name, short operation_ int chrif_saveaccountreg2(dumb_ptr sd); int chrif_send_divorce(CharId char_id); +void chrif_parse_preauth(Session *s, const Packet_Fixed<0x3829>& fixed); + void do_init_chrif(void); } // namespace map } // namespace tmwa diff --git a/src/map/clif.cpp b/src/map/clif.cpp index f2667ac..a2f3b3a 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -3539,15 +3539,36 @@ RecvResult clif_parse_WantToConnection(Session *s, dumb_ptr sd if (rv != RecvResult::Complete) return rv; - { - account_id = fixed.account_id; - } + account_id = fixed.account_id; // formerly: account id Packet_Payload<0x8000> special; special.magic_packet_length = 4; send_ppacket<0x8000>(s, special); + bool is_valid = false; + for (AuthFifoEntry& afi : auth_fifo) + { + if (afi.account_id == fixed.account_id + && afi.char_id == fixed.char_id + && afi.login_id1 == fixed.login_id1 + //&& afi.login_id2 == sd->login_id2 + && afi.ip == s->client_ip + && afi.delflag == 0) + { + is_valid = true; + afi.delflag = 1; + break; + } + } + + if (!is_valid) + { + MAP_LOG_AND_ECHO("Attempt to connect without correct authentication (REJECTED IP: %s)!\n"_fmt, s->client_ip); + s->set_eof(); + return RecvResult::Complete; + } + // if same account already connected, we disconnect the 2 sessions dumb_ptr old_sd = map_id2sd(account_to_block(account_id)); if (old_sd) diff --git a/src/map/fwd.hpp b/src/map/fwd.hpp index 74e0ccf..fc6b284 100644 --- a/src/map/fwd.hpp +++ b/src/map/fwd.hpp @@ -69,5 +69,7 @@ struct ScriptState; struct str_data_t; class SIR; +struct AuthFifoEntry; + } // namespace map } // namespace tmwa diff --git a/src/map/globals.cpp b/src/map/globals.cpp index 49d6074..97533c8 100644 --- a/src/map/globals.cpp +++ b/src/map/globals.cpp @@ -51,6 +51,9 @@ namespace tmwa Map item_db; Map quest_db; + std::array auth_fifo; + decltype(auth_fifo)::iterator auth_fifo_iter = auth_fifo.begin(); + DMap> id_db; UPMap maps_db; DMap> nick_db; diff --git a/src/map/globals.hpp b/src/map/globals.hpp index 1c8e70d..acf52fd 100644 --- a/src/map/globals.hpp +++ b/src/map/globals.hpp @@ -95,5 +95,8 @@ namespace tmwa extern earray skill_db; extern BlockId skill_area_temp_id; extern int skill_area_temp_hp; + + extern std::array auth_fifo; + extern AuthFifoEntry *auth_fifo_iter; } // namespace map } // namespace tmwa diff --git a/src/map/intif.cpp b/src/map/intif.cpp index fc34a64..379bb1d 100644 --- a/src/map/intif.cpp +++ b/src/map/intif.cpp @@ -743,6 +743,16 @@ RecvResult intif_parse(Session *s, uint16_t packet_id) intif_parse_PartyLeaderChanged(s, fixed); break; } + case 0x3829: + { + Packet_Fixed<0x3829> fixed; + rv = recv_fpacket<0x3829, 22>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + chrif_parse_preauth(s, fixed); + break; + } default: return RecvResult::Error; } diff --git a/src/map/map.hpp b/src/map/map.hpp index 24037e9..2f6ef21 100644 --- a/src/map/map.hpp +++ b/src/map/map.hpp @@ -584,6 +584,12 @@ void map_log(XString line); #define MAP_LOG(format, ...) \ map_log(STRPRINTF(format, ## __VA_ARGS__)) +#define MAP_LOG_AND_ECHO(...) \ + do { \ + PRINTF(__VA_ARGS__); \ + MAP_LOG(__VA_ARGS__); \ + } while (0) + #define MAP_LOG_PC(sd, fmt, ...) \ MAP_LOG("PC%d %s:%d,%d " fmt, \ sd->status_key.char_id, (sd->bl_m->name_), sd->bl_x, sd->bl_y, ## __VA_ARGS__) @@ -692,5 +698,14 @@ struct charid2nick CharName nick; int req_id; }; + +struct AuthFifoEntry +{ + AccountId account_id; + CharId char_id; + int login_id1, login_id2; + IP4Address ip; + int delflag; +}; } // namespace map } // namespace tmwa diff --git a/tools/protocol.py b/tools/protocol.py index 2940744..413bb67 100755 --- a/tools/protocol.py +++ b/tools/protocol.py @@ -6231,6 +6231,38 @@ def build_context(): Party leader was changed. ''', ) + char_map.s(0x3829, 'account auth', + fixed=[ + at(0, u16, 'packet id'), + at(2, account_id, 'account id'), + at(6, char_id, 'char id'), + at(10, u32, 'login id1'), + at(14, u32, 'login id2'), + at(18, ip4, 'ip'), + ], + fixed_size=22, + pre=[], + post=[], + desc=''' + send auth data to map server + ''', + ) + char_map.r(0x3830, 'account auth reply', + fixed=[ + at(0, u16, 'packet id'), + at(2, account_id, 'account id'), + at(6, char_id, 'char id'), + at(10, u32, 'login id1'), + at(14, u32, 'login id2'), + at(18, ip4, 'ip'), + ], + fixed_size=22, + pre=[], + post=[], + desc=''' + reply to char server + ''', + ) # TOC_MISC # any client -- cgit v1.2.3-60-g2f50