----------------------------------------------------------------------------------------------------------------------------- Open ../common/socket.h and after: #define FIFOSIZE_SERVERLINK 256*1024 ==== add: ==== extern bool is_gepard_active; extern uint32 min_allowed_gepard_version; #define MATRIX_SIZE (2048 + 1) #define KEY_SIZE (32 + 1) #define GEPARD_ID 0x10000025 #define UNIQUE_ID_XOR 0x5938C9F1 #define SRAND_CONST 0xB6391781 #define POS_1_START 0x78 #define POS_2_START 0x39 #define RAND_1_START 0x6C #define RAND_2_START 0xE0 struct gepard_crypt_link { unsigned char key[KEY_SIZE]; unsigned char pos_1; unsigned char pos_2; unsigned char pos_3; }; struct gepard_info_data { bool is_init_ack_received; uint32 unique_id; uint64 sync_tick; uint32 gepard_shield_version; }; enum gepard_server_types { GEPARD_MAP = 0xAAAA, GEPARD_LOGIN = 0xBBBB, }; enum gepard_info_type { GEPARD_INFO_BANNED, GEPARD_INFO_OLD_VERSION, GEPARD_INFO_DUAL_LOGIN, GEPARD_INFO_CORUPTED_UID, GEPARD_INFO_WRONG_LICENSE_ID, GEPARD_WRONG_GRF_HASH, }; enum gepard_packets { CS_LOGIN_PACKET = 0x0064, CS_LOAD_END_ACK = 0x007D, CS_WALK_TO_XY = 0x0437, CS_WHISPER_TO = 0x0096, CS_USE_SKILL_TO_ID = 0x083c, CS_USE_SKILL_TO_POS = 0x0438, SC_CHANGE_OPTION = 0x0229, SC_STATUS_CHANGE = 0x0983, SC_SKILL_CASTING = 0x07fb, SC_SKILL_DAMAGE = 0x01de, SC_SKILL_NODAMAGE = 0x011a, SC_SET_UNIT_WALKING = 0x0856, SC_SET_UNIT_IDLE = 0x0857, SC_WHISPER_FROM = 0x0097, SC_WHISPER_SEND_ACK = 0x0098, CS_GEPARD_SYNC = 0x2000, CS_GEPARD_INIT_ACK = 0x1002, SC_GEPARD_INIT = 0xABCD, SC_GEPARD_INFO = 0xBCDE, }; enum gepard_internal_packets { GEPARD_M2C_BLOCK_REQ = 0x5000, GEPARD_C2M_BLOCK_ACK = 0x5001, GEPARD_M2C_UNBLOCK_REQ = 0x5002, GEPARD_C2M_UNBLOCK_ACK = 0x5003, }; #define GEPARD_REASON_LENGTH 99 #define GEPARD_TIME_STR_LENGTH 24 #define GEPARD_RESULT_STR_LENGTH 100 void gepard_config_read(); void gepard_init(int fd, uint16 packet_id); void gepard_send_info(int fd, unsigned short info_type, char* message); bool gepard_process_packet(int fd, uint8* packet_data, uint32 packet_size, struct gepard_crypt_link* link); void gepard_enc_dec(uint8* in_data, uint8* out_data, unsigned int data_size, struct gepard_crypt_link* link); ==== after: ==== void* session_data; // stores application-specific data related to the session ==== add: ==== // Gepard Shield struct gepard_info_data gepard_info; struct gepard_crypt_link send_crypt; struct gepard_crypt_link recv_crypt; struct gepard_crypt_link sync_crypt; // Gepard Shield ----------------------------------------------------------------------------------------------------------------------------- Open ../common/socket.c and in the function WFIFOSET before (!!!!before!!!!): s->wdata_size += len; ==== add: ==== // Gepard Shield if (is_gepard_active == true && SERVER_TYPE != SERVER_TYPE_CHAR) { gepard_process_packet(fd, s->wdata + s->wdata_size, len, &s->send_crypt); } // Gepard Shield ======================= In the function socket_init after: ======================= socket_config_read(SOCKET_CONF_FILENAME); ==== add: ==== // Gepard Shield gepard_config_read(); // Gepard Shield ================================= At the end of the file ../common/socket.c add: ================================= bool is_gepard_active; uint32 min_allowed_gepard_version; uint32 allowed_gepard_grf_hash; uint32 gepard_rand_seed; const unsigned char* shield_matrix = (const unsigned char*) "\xdb\x6e\xd0\x05\x23\xfa\x70\xa4\x5d\xbc\xb1\xbe\xa5\x98\x92\x17" "\x2c\x51\x03\xec\xc5\xf7\xec\xf2\x56\xae\x38\xc7\xab\xb4\x72\x1c" "\x7b\xf3\xfa\x30\x93\x22\x5c\xe9\x03\xb6\xab\xba\x2d\x81\x1a\xef" "\x27\xe3\x26\x4a\x49\x45\x79\x63\x4b\xbc\x69\x3e\xe0\x39\xb6\x11" "\xa8\x56\x78\x25\x61\x3a\x48\xd6\x3f\x37\x20\x8e\xcc\xb5\x08\xc2" "\xa7\xf8\x7c\xe1\xa9\xd7\x27\xa9\xa3\x22\xdb\x49\xc9\xc8\xf0\x61" "\x8a\x42\x64\x2d\xd0\xf8\xe1\x7e\x01\x9d\x98\xbe\x1e\x85\x88\x2b" "\x80\x3f\x9b\x0f\xf6\x21\x3e\x87\xb4\x97\x53\xbe\x09\x95\xa7\x19" "\x1b\xe5\x51\x36\xbb\xd1\x8d\x54\x84\xc8\x94\xee\x51\x86\xfb\x28" "\xd6\x66\x0f\x50\x53\x57\xbc\x24\x29\x27\x87\x16\x57\x18\x95\x2a" "\x2b\x76\xc3\x50\x8f\x9b\xe2\x33\xdf\x9c\x85\x6b\xa6\x91\x77\x9a" "\xa0\x26\x55\xc8\x76\xf4\x53\x8b\xfc\x53\xa4\xe9\x82\x8b\x28\x68" "\xdb\xab\xb3\x30\x4d\x73\xad\xd6\xf9\x04\x50\xa0\x76\xc3\x43\xca" "\xad\x36\xe2\xbe\x2b\x37\x69\xac\x83\xc8\xcb\xfb\xe8\x6d\x04\x0d" "\x24\xbf\x0f\xaf\x89\xb9\xec\xe2\x8e\xea\xcf\xa0\x29\x7e\xda\x62" "\x9d\xd5\x1d\x1e\x51\x21\x96\x5b\x62\x35\x11\xaf\x7f\x82\xfc\xb2" "\xcf\x72\xb7\xca\x6e\x91\xd3\xda\x2e\xc0\xd2\x21\xbd\xe6\xf0\xed" "\xe3\xc5\xe0\x75\x5c\x78\x2a\xcf\x93\xca\x7a\x0c\xcd\xd0\x9f\x5a" "\xfc\x88\x01\xa3\x39\xe2\xca\x28\xbb\xfb\x1a\x7b\xc5\xe6\xe7\xe2" "\x4b\x4c\x7b\xf6\xd2\xc7\xa3\x23\xe3\x40\x85\xbd\x72\xa4\xa9\x68" "\x1e\x49\xb5\xfc\xba\xda\xec\x1a\xee\x93\x5d\xaf\x69\x2a\xd8\x95" "\x6f\xb1\xb0\x7a\x51\x5d\x3a\x56\x75\xd0\x22\x94\x9a\x0c\x0d\x27" "\xf9\x22\x11\x41\x58\xe9\x0b\x60\xd4\x05\xc4\xde\x61\x23\x90\x41" "\xc1\xc5\xb6\xfb\x05\xca\xd7\x4d\x3e\xbb\x34\x04\x0e\xda\xf1\xbf" "\x2b\x7d\x45\xfd\x0c\xc3\x26\x90\xcb\xd1\xee\xcd\xfb\x06\x90\x04" "\x87\xd8\x3a\x17\x33\x65\x97\xcd\x08\x42\x13\xa4\xa1\xa8\xb1\x45" "\xa1\x93\x77\xe1\x62\xde\xf7\xa4\x08\xfc\xed\xe6\x1c\x4c\x0c\x60" "\x57\xc0\xd8\x11\x32\x49\xcc\x84\xf0\x2c\x0c\xb1\xc2\x4f\xda\x2a" "\x9f\x1b\x3f\x44\x7c\x7a\x6a\xf9\x11\x0f\xc8\x38\xb7\x33\x6c\xbc" "\xa0\x57\x26\x51\x6d\xd3\xfd\x22\x6a\x43\xde\x8c\x73\xed\xb0\x48" "\xbb\x70\xab\x1c\x10\x94\x1e\x51\x43\x97\xf7\x73\xd8\xbb\x4d\x63" "\x22\x79\xa9\xe1\x63\xa6\x61\xb4\xba\xd6\x3f\xb6\x45\xe8\x29\xda" "\xdf\x71\x3d\x08\xe5\x72\x66\x50\xce\x23\x6a\xef\x1f\xaa\x7f\x03" "\xf1\x8a\x5d\xef\x29\xa8\xe7\x79\xf9\xb9\x54\x5a\x63\x67\x6e\x04" "\x4d\x03\xe6\xc6\xdc\x1b\xca\x81\xb6\xc8\x02\x25\xba\x8a\x87\xad" "\x77\xed\xb0\x51\x64\x04\xb0\x09\x97\xc1\x3b\xc1\x87\xd3\xdf\xc6" "\x14\x8b\x94\x3f\xe3\xda\x07\xd0\x53\xa1\x15\xb2\x73\x28\x9e\xda" "\x71\x0f\x86\xfb\xd0\x26\x93\x04\xd4\x4a\x84\xdd\x03\x5d\x8f\x8b" "\x1c\x77\x22\xf9\x02\xc3\x89\x8f\x4f\xc9\x6c\x59\x22\x13\xb0\xe2" "\x6e\x5b\xb6\x0a\x3e\xc0\x18\xec\x48\x31\x33\x41\xb9\x78\xc3\x9f" "\x9f\xb7\x5f\xa3\xcf\x27\xf6\xf4\xaa\xe0\xc7\x01\xb7\x22\xdd\x06" "\xd4\xc3\x8c\xb9\x10\xcb\x7c\x2c\xd9\xd9\xbe\x26\x25\x5a\xf6\x32" "\x2f\xbe\x93\x8c\xfa\x9f\x27\x18\xba\x0c\x58\xb1\x33\x6d\x7b\x65" "\x5d\xbe\xc4\x70\x3d\x80\xb2\x8b\x49\x2a\x14\x66\xcf\xfd\xd8\xd8" "\x2b\x03\xf5\x2a\xc3\x08\xa3\x78\xa5\x74\xc3\x19\x2e\x53\x12\x09" "\x14\xc4\x94\x33\xcf\x5c\x5e\xbb\x27\x0e\x14\x02\x5b\xa4\xca\x0b" "\x4d\x82\xb4\x15\x81\x22\x2e\x75\x68\xc6\xa4\x8a\x50\xf2\x5d\xd8" "\x59\xd4\xa1\xae\x69\xa2\x5b\xcf\x59\x72\x92\x1e\xfb\xd0\x64\xa5" "\x1d\xbb\x6f\x8a\x1b\x6d\x3a\x56\x51\x33\x09\x7b\x59\xb3\xce\x26" "\xe3\x6f\x08\x2f\x3b\x58\x37\x40\x9a\xcb\x55\x02\x79\x48\x6e\x68" "\x7a\xb1\xbc\x6b\x0f\x77\xec\xc3\x05\xee\x72\x05\x99\x3e\x8a\xa1" "\xba\x1b\xd6\x29\x0d\xc8\x32\x66\xf7\x10\x9a\x99\xaf\x97\xe8\xf9" "\x99\x6d\xa5\x3c\xee\x0a\x24\xca\x7b\xb1\xd6\xe5\x7a\x7e\x68\xe1" "\x3b\x60\x10\x33\x3b\x82\xc1\x02\x52\x39\x91\x74\x10\x0e\x86\xdf" "\x7f\x79\x26\x27\x5e\xd5\x6e\x5d\x80\x39\x21\x22\x73\x27\x75\x61" "\x16\xce\x2c\x89\x34\xd5\x8f\xb8\xe0\x46\xde\xc6\x1e\xbd\x2d\x87" "\x09\xe5\xaf\x77\x19\x4e\x90\xcf\xb3\xc5\x2f\xd8\x14\xab\x73\x7d" "\xcf\xf6\x14\x88\xfa\x59\xf9\x0f\xac\x3b\x19\x68\x72\xfd\xf6\xc2" "\xe2\x46\x27\x1e\x6a\x2c\x80\xdc\x08\x9b\xd2\x9b\x7e\xc6\xd4\xfa" "\x42\xed\x29\xb4\xa7\xe8\x12\x72\x94\x1c\xcd\x56\x39\x6a\xb2\xc3" "\x8f\xb2\xe5\x32\xb4\x6c\xe9\xa2\x47\x03\xd0\x93\x69\x74\x44\x7f" "\x98\x4e\x3d\xb5\xe4\x20\x1d\xb0\x49\x76\x7d\xae\xb1\x62\xe2\xa4" "\xe7\xc5\xb8\x69\xec\x4d\xac\x20\x0b\x4a\xe4\x34\x1e\xf6\x9c\x14" "\xd4\x35\x17\xd4\xf1\xe3\x95\xfe\xcf\xd6\x1b\xb5\x32\x08\xbe\x61" "\x16\x21\x60\xa3\x9b\xd3\xdc\x3c\x44\x41\x3d\x94\xfb\xd1\xee\xa7" "\x4b\xc4\xf1\x01\x22\xd7\xa7\xf3\x84\x50\x0e\x54\xa1\x44\x31\xd8" "\x17\xe5\x13\x60\xdf\x48\x41\xbf\xb6\xbb\xfa\x6c\x74\x50\xfe\x0d" "\xa5\xa2\x7e\xce\xdd\x68\x35\x89\x13\xf9\xb2\x95\x7c\xbf\x56\x51" "\xbf\xbd\xf7\xc4\xe8\x37\x56\x58\xf8\x93\x34\x9a\x0e\x7e\x47\x7b" "\x5e\x77\x5c\x73\x9e\x42\xd3\x21\x7d\xee\xda\x2a\x53\xeb\x83\x73" "\xb6\x53\x2e\x18\xfc\xef\xc9\x18\x78\x25\x72\xa1\x62\x2d\x72\x8b" "\x49\x71\xa5\xca\xf4\xd6\xcd\xfd\x1a\xcc\x47\x64\xca\x7a\x3d\xc9" "\xf5\x56\xc4\xc9\xf5\x87\x81\x73\xf4\xd0\x34\xa6\xa1\x72\x61\x3c" "\x88\xc2\xe3\x52\x83\x5f\x20\xc6\x12\x37\xb3\x3e\x99\xe3\xbf\x46" "\x4b\x7b\x42\xe9\x40\x56\x93\xc4\x01\x7a\x6c\xf2\x0c\x26\x2a\x71" "\x96\xa0\x17\xae\x01\x52\xfc\x07\x64\x53\x49\x52\x0e\x62\xf7\xbc" "\x5c\x79\x1f\xac\xdc\xf6\x4b\xc7\x04\x0c\x01\x76\xf9\xe6\x13\xee" "\x3e\xc4\x31\xa6\x3b\xef\xc8\x2e\xe0\xcd\xa9\xe0\x86\x75\x89\x65" "\x9d\x8b\xc8\x6b\xe1\x4a\x29\x20\x3c\x72\x4a\x41\x53\x94\x1a\xe1" "\x23\xec\x99\x24\x8e\x3a\x9d\x8f\x2f\x53\xe7\xcc\xf8\xdf\xc9\x5d" "\xda\x71\x9f\xa3\x79\x74\xdf\xd1\xb6\x9c\x18\x0a\x18\x55\x6f\x57" "\x38\x5a\x2b\x37\x6f\xf7\x48\xe3\x48\x97\x0d\x20\x6b\x29\xc4\x25" "\x31\xef\x78\xf4\xde\xde\xd7\x45\xd9\x01\x2b\xaa\x59\x12\x77\xc1" "\x47\x53\x36\x91\x65\xb1\xcb\x44\x79\x52\x94\x05\x7d\x1c\xb7\x9f" "\x16\x4e\x9c\xa6\x63\xb3\xab\x4a\x5b\x17\xba\xa0\xbe\x77\x4a\x76" "\xeb\x22\xfb\x0a\x0b\xb5\x5c\x31\x66\xbb\x6e\x4c\x5c\x48\x95\x95" "\x4e\xd6\x4a\x1e\x6e\x64\xab\x11\xc7\x5c\xef\x0e\x81\x76\xb4\xb1" "\x96\x92\x34\x9c\x90\x17\xe3\x0f\x02\x94\xfd\x69\x4f\x80\x06\xb5" "\x76\x5b\xb0\xea\xf6\x24\xda\xae\xfd\x50\xe8\xb8\xef\x46\x38\x11" "\x0e\x76\x8a\x68\xb8\x2c\x80\x23\x98\x1e\x9c\x75\xab\xdc\xe1\x8d" "\x7b\xae\x75\xbd\x8b\xeb\x70\x1d\xb3\xf8\xb7\x0b\x6d\xdc\x88\x17" "\xe9\x25\x1d\xae\x5a\x0e\x03\x1b\xc6\x20\x95\x2a\xdd\x37\x38\x13" "\x21\xa7\xb2\xe9\xcd\x77\x59\xb9\xee\xde\xe2\x12\xee\x7a\x8e\x2a" "\x96\x77\xfe\xd7\xe1\x1c\xf0\x84\x7e\xe3\xa9\x68\xe8\x2e\x4c\x9d" "\xfc\xa1\x74\x6a\x72\x47\xb3\x45\x0c\x8d\xe3\x81\xfe\x1e\x66\x95" "\x55\x4a\xb8\x6d\xcd\xf6\x84\x54\x05\x39\x0b\x34\x5e\x27\x14\x6b" "\x7b\xfd\x3b\xda\xc2\x20\x53\xe5\x3b\x96\xa8\xac\x3d\x8d\x60\x85" "\xba\x80\x43\x20\x31\x86\xaa\xe0\xf5\x73\xe3\xb6\xe8\x48\xb9\x9b" "\x5a\x20\x7d\x7b\x9b\x88\x40\xa5\x22\x8d\x14\x10\xd9\x52\x01\x8d" "\x2f\x22\x8e\xc1\xb4\x73\x05\xe4\xbc\xe6\xcf\x39\x42\xfb\x9c\xb2" "\xac\xed\xa3\xb2\x6f\x4e\x35\xef\xb1\x0d\x7b\xc6\x9c\xb9\x02\x24" "\x71\xb0\xfd\x49\x91\xac\x69\x02\x9c\x6f\xdc\x2e\xbc\xf1\x4e\x97" "\xd9\xd4\x89\x09\x42\x22\x23\x17\xfc\x2f\x29\x95\x5e\xd3\xce\x25" "\x8f\x01\x68\xd0\x18\xe4\x61\xb9\x2b\x6c\x91\x28\xba\x9e\x16\x99" "\x9b\xc3\x81\x2b\xad\xf2\x2c\xd1\xe0\x17\xda\xdf\x8f\xf6\x08\x4c" "\x70\xe2\x97\x19\x2c\x90\xa9\x74\xd0\x40\xe5\xdd\xb6\xb6\x6d\x67" "\x01\xae\xd0\xe9\x5e\x3e\xa7\x37\x31\x68\x43\xb1\x30\x3b\x82\x3e" "\xcb\x4c\xcb\x83\x43\xea\xb3\x7d\xcd\x51\x43\x2e\xba\xb6\x84\x16" "\x6d\x0c\xaf\x3a\x18\xbf\x23\x47\x96\x4b\x07\x38\x59\xfe\xc6\x7f" "\xae\x36\xb8\x97\x6b\xf2\xa6\x83\x32\x09\x0c\x17\xe8\x5d\xbc\x1d" "\x17\x59\xcb\x35\x2d\x96\xdb\x60\x0b\x6d\xc1\xc4\xb2\x62\x90\xfb" "\xf9\x1f\x04\x80\x41\xe8\xda\x9a\xe3\x58\x93\xbc\x74\x2f\xad\xda" "\x09\x16\xc5\x97\x88\xa6\x46\xca\x60\xfd\x01\x4d\xfa\xca\x52\x81" "\xe1\x07\xc9\x8d\x79\xd4\x5e\xba\x1d\xb0\xa2\xe5\xa6\x71\x21\x8d" "\xa1\x44\xb2\xc1\x27\x97\x0b\xae\x39\x33\xc5\x6b\x84\x62\xae\xc1" "\x6f\x75\x98\xaf\xda\x7f\x71\x3d\xea\x08\xf3\x01\x5b\x30\x94\xd9" "\x93\x6d\x1b\xb9\x9a\xd7\x83\x99\x8d\x44\x07\x5e\x37\x15\x7e\xd4" "\x22\xf3\xf2\xfe\x41\x77\x0b\x63\xb0\x5a\x38\x9c\x81\x3b\xbb\xc9" "\xe6\x1b\xfc\xa7\x08\x14\xc0\x7c\x29\x6f\x2f\x08\x0b\x93\x4f\xb3" "\x44\x8e\x50\xb6\x1b\x0f\x55\x50\xa2\x26\x13\x6d\x9e\xa3\x7d\xc7" "\xf4\x5f\xc8\x59\xa7\xc4\x05\xac\x2c\x73\x9b\xec\x10\x55\xdf\xbd" "\xc0\xd7\x1c\xb5\xeb\xdc\xaa\x8a\xca\xec\x1d\xc9\x4b\x43\xf3\x25" "\x6d\xcb\x63\x3e\xc7\x9e\x49\x64\x89\x17\x9e\xb7\x67\x10\x27\xb4" "\x4d\x65\xb4\xfd\x4c\x3a\x20\xfe\x08\xb6\x62\x2e\xb3\x33\xec\x17" "\x52\xf8\x27\x6c\xc9\x1e\xb8\xc0\x89\x22\x7d\xb5\x48\xc4\x4b\xbe" "\x18\xd1\xec\x38\xe4\xc5\xf9\xfa\x0b\x0e\xe2\xba\x97\xd3\x6c\x35" "\x7a\x83\x5f\x9b\xa2\x05\xb2\xc2\x49\x60\x73\xd9\xfb\x32\xaa\xe6" "\x22\x39\x8d\x2d\x77\xe0\x30\x34\x59\x7f\x91\x34\xca\x47\xa7\xfa"; void gepard_config_read() { char* conf_name = "conf/gepard_shield.conf"; char line[1024], w1[1024], w2[1024]; FILE* fp = fopen(conf_name, "r"); is_gepard_active = false; if (fp == NULL) { ShowError("Gepard configuration file (%s) not found. Shield disabled.\n", conf_name); return; } while(fgets(line, sizeof(line), fp)) { if (line[0] == '/' && line[1] == '/') continue; if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) < 2) continue; if (!strcmpi(w1, "gepard_shield_enabled")) { is_gepard_active = (bool)config_switch(w2); } } fclose(fp); conf_name = "conf/gepard_version.txt"; if ((fp = fopen(conf_name, "r")) == NULL) { min_allowed_gepard_version = 0; ShowError("Gepard version file (%s) not found.\n", conf_name); return; } fscanf(fp, "%u", &min_allowed_gepard_version); fclose(fp); } bool gepard_process_packet(int fd, uint8* packet_data, uint32 packet_size, struct gepard_crypt_link* link) { uint16 packet_id = RBUFW(packet_data, 0); switch (packet_id) { case CS_GEPARD_SYNC: { uint32 control_value; if (RFIFOREST(fd) < 6) { return true; } gepard_enc_dec(packet_data + 2, packet_data + 2, 4, &sockt->session[fd]->sync_crypt); control_value = RFIFOL(fd, 2); if (control_value == 0xDDCCBBAA) { sockt->session[fd]->gepard_info.sync_tick = timer->gettick(); } RFIFOSKIP(fd, 6); return true; } break; case CS_LOGIN_PACKET: { if (RFIFOREST(fd) < 55) { return false; } if (sockt->session[fd]->gepard_info.is_init_ack_received == false) { RFIFOSKIP(fd, RFIFOREST(fd)); gepard_init(fd, GEPARD_LOGIN); return true; } gepard_enc_dec(packet_data + 2, packet_data + 2, RFIFOREST(fd) - 2, link); } break; case CS_WHISPER_TO: { if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < (packet_size = RBUFW(packet_data, 2)) || packet_size < 4) { return true; } gepard_enc_dec(packet_data + 4, packet_data + 4, packet_size - 4, link); } break; case CS_WALK_TO_XY: case CS_USE_SKILL_TO_ID: case CS_USE_SKILL_TO_POS: { if (RFIFOREST(fd) < packet_size) { return true; } gepard_enc_dec(packet_data + 2, packet_data + 2, packet_size - 2, link); } break; case SC_WHISPER_FROM: case SC_SET_UNIT_IDLE: case SC_SET_UNIT_WALKING: { gepard_enc_dec(packet_data + 4, packet_data + 4, packet_size - 4, link); } break; case SC_CHANGE_OPTION: case SC_STATUS_CHANGE: case SC_SKILL_CASTING: case SC_SKILL_DAMAGE: case SC_SKILL_NODAMAGE: { gepard_enc_dec(packet_data + 2, packet_data + 2, packet_size - 2, link); } break; case CS_GEPARD_INIT_ACK: { uint32 unique_id, unique_id_, shield_ver; if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < (packet_size = RFIFOW(fd, 2))) { return true; } if (packet_size < 16) { ShowWarning("gepard_process_packet: invalid size of CS_GEPARD_INIT_ACK packet: %u\n", packet_size); set_eof(fd); return true; } gepard_enc_dec(packet_data + 4, packet_data + 4, packet_size - 4, link); unique_id = RFIFOL(fd, 4); shield_ver = RFIFOL(fd, 8); unique_id_ = RFIFOL(fd, 12) ^ UNIQUE_ID_XOR; RFIFOSKIP(fd, packet_size); if (!unique_id || !unique_id_ || unique_id != unique_id_) { WFIFOHEAD(fd, 6); WFIFOW(fd, 0) = SC_GEPARD_INFO; WFIFOL(fd, 2) = 3; WFIFOSET(fd, 6); set_eof(fd); } sockt->session[fd]->gepard_info.is_init_ack_received = true; sockt->session[fd]->gepard_info.unique_id = unique_id; sockt->session[fd]->gepard_info.gepard_shield_version = shield_ver; return true; } break; } return false; } inline void gepard_srand(unsigned int seed) { gepard_rand_seed = seed; } inline unsigned int gepard_rand() { return (((gepard_rand_seed = gepard_rand_seed * 214013L + 2531011L) >> 16) & 0x7fff); } void gepard_session_init(int fd, unsigned int recv_key, unsigned int send_key, unsigned int sync_key) { uint32 i; uint8 random_1 = RAND_1_START; uint8 random_2 = RAND_2_START; sockt->session[fd]->recv_crypt.pos_1 = sockt->session[fd]->send_crypt.pos_1 = sockt->session[fd]->sync_crypt.pos_1 = POS_1_START; sockt->session[fd]->recv_crypt.pos_2 = sockt->session[fd]->send_crypt.pos_2 = sockt->session[fd]->sync_crypt.pos_2 = POS_2_START; sockt->session[fd]->recv_crypt.pos_3 = sockt->session[fd]->send_crypt.pos_3 = sockt->session[fd]->sync_crypt.pos_3 = 0; gepard_srand(recv_key ^ SRAND_CONST); for (i = 0; i < (KEY_SIZE-1); ++i) { random_1 ^= shield_matrix[gepard_rand() % (MATRIX_SIZE-1)]; random_1 -= (6 * random_2) + 3; random_2 ^= shield_matrix[gepard_rand() % (MATRIX_SIZE-1)]; random_2 += (7 * random_1) + 2; random_1 += random_2 ^ shield_matrix[gepard_rand() % (MATRIX_SIZE-1)]; sockt->session[fd]->recv_crypt.key[i] = random_1; } random_1 = RAND_1_START; random_2 = RAND_2_START; gepard_srand(send_key | SRAND_CONST); for (i = 0; i < (KEY_SIZE-1); ++i) { random_1 ^= shield_matrix[gepard_rand() % (MATRIX_SIZE-1)]; random_1 -= (2 * random_2) - 9; random_2 ^= shield_matrix[gepard_rand() % (MATRIX_SIZE-1)]; random_2 -= (5 * random_1) + 6; random_1 += random_2 ^ shield_matrix[gepard_rand() % (MATRIX_SIZE-1)]; sockt->session[fd]->send_crypt.key[i] = random_1; } random_1 = RAND_1_START; random_2 = RAND_2_START; gepard_srand(sync_key | SRAND_CONST); for (i = 0; i < (KEY_SIZE-1); ++i) { random_1 ^= shield_matrix[gepard_rand() % (MATRIX_SIZE-1)]; random_1 -= (3 * random_2) + 8; random_2 ^= shield_matrix[gepard_rand() % (MATRIX_SIZE-1)]; random_2 += (2 * random_1) - 7; random_1 -= random_2 ^ shield_matrix[gepard_rand() % (MATRIX_SIZE-1)]; sockt->session[fd]->sync_crypt.key[i] = random_1; } } void gepard_init(int fd, uint16 server_type) { const uint16 init_packet_size = 20; uint16 recv_key = (gepard_rand() % 0xFFFF); uint16 send_key = (gepard_rand() % 0xFFFF); uint16 sync_key = (gepard_rand() % 0xFFFF); gepard_srand((unsigned)time(NULL) ^ clock()); WFIFOHEAD(fd, init_packet_size); WFIFOW(fd, 0) = SC_GEPARD_INIT; WFIFOW(fd, 2) = init_packet_size; WFIFOW(fd, 4) = recv_key; WFIFOW(fd, 6) = send_key; WFIFOW(fd, 8) = server_type; WFIFOL(fd, 10) = GEPARD_ID; WFIFOL(fd, 14) = min_allowed_gepard_version; WFIFOW(fd, 18) = sync_key; WFIFOSET(fd, init_packet_size); gepard_session_init(fd, recv_key, send_key, sync_key); } void gepard_enc_dec(uint8* in_data, uint8* out_data, uint32 data_size, struct gepard_crypt_link* link) { uint32 i; for(i = 0; i < data_size; ++i) { link->pos_1 += link->key[link->pos_3 % (KEY_SIZE-1)]; link->pos_2 -= link->pos_1 * 4; link->key[link->pos_2 % (KEY_SIZE-1)] ^= link->pos_1; link->pos_1 += ((link->pos_2 - link->pos_3) * 3) + 3; link->key[link->pos_3 % (KEY_SIZE-1)] ^= link->pos_1; out_data[i] = in_data[i] ^ link->pos_1; link->pos_1 += 3; link->pos_2 -= data_size % 0xFF; link->pos_3++; } } void gepard_send_info(int fd, unsigned short info_type, char* message) { int message_len = strlen(message) + 1; int packet_len = 2 + 2 + 2 + message_len; WFIFOHEAD(fd, packet_len); WFIFOW(fd, 0) = SC_GEPARD_INFO; WFIFOW(fd, 2) = packet_len; WFIFOW(fd, 4) = info_type; safestrncpy((char*)WFIFOP(fd, 6), message, message_len); WFIFOSET(fd, packet_len); } ----------------------------------------------------------------------------------------------------------------------------- Open ../src/login/login.c and in the function login_parse_login after: while( RFIFOREST(fd) >= 2 ) { uint16 command = RFIFOW(fd,0); ==== add: ==== // Gepard Shield by Functor if (is_gepard_active == true) { bool is_processed = gepard_process_packet(fd, sockt->session[fd]->rdata + sockt->session[fd]->rdata_pos, 0, &sockt->session[fd]->recv_crypt); if (is_processed == true) { if (command == CS_GEPARD_INIT_ACK) { gepard_check_unique_id(fd, sockt->session[fd]->gepard_info.unique_id); } return 0; } } // Gepard Shield by Functor =========================== In the function login_auth_ok change: =========================== login_log(ip, sd->userid, 100, "login ok"); === to: === gepard_update_last_unique_id(sd->account_id, sockt->session[fd]->gepard_info.unique_id); login_log(fd, ip, sd->userid, 100, "login ok"); ============================================ In the function login_fromchar_parse_wrong_pincode change: ============================================ login_log(sockt->host2ip(acc.last_ip), acc.userid, 100, "PIN Code check failed"); // FIXME: Do we really want to log this with the same code as successful logins? === to: === login_log(fd, sockt->host2ip(acc.last_ip), acc.userid, 100, "PIN Code check failed"); // FIXME: Do we really want to log this with the same code as successful logins? ============================= In the function login_auth_failed change: ============================= login_log(ip, sd->userid, result, error); // FIXME: result can be 100, conflicting with the value 100 we use for successful login... === to: === login_log(fd, ip, sd->userid, result, error); // FIXME: result can be 100, conflicting with the value 100 we use for successful login... ========================================= In the function login_parse_request_connection change: ========================================= login_log(sockt->session[fd]->client_addr, sd->userid, 100, message); === to: === login_log(fd, sockt->session[fd]->client_addr, sd->userid, 100, message); ============================== In the function login_parse_login change: ============================== login_log(ipl, "unknown", -3, "ip banned"); === to: === login_log(0, ipl, "unknown", -3, "ip banned"); ======================= In the function do_final change: ======================= login_log(0, "login server", 100, "login server shutdown"); === to: === login_log(0, 0, "login server", 100, "login server shutdown"); ====================== In the function do_init change: ====================== login_log(0, "login server", 100, "login server started"); === to: === login_log(0, 0, "login server", 100, "login server started"); ----------------------------------------------------------------------------------------------------------------------------- Open ../src/login/loginlog.h and change: void login_log(uint32 ip, const char* username, int rcode, const char* message); === to: === void login_log(int fd, uint32 ip, const char* username, int rcode, const char* message); ----------------------------------------------------------------------------------------------------------------------------- Open ../src/login/loginlog_sql.c and change code of the function login_log to: void login_log(int fd, uint32 ip, const char* username, int rcode, const char* message) { char esc_username[NAME_LENGTH*2+1]; char esc_message[255*2+1]; unsigned int unique_id = 0; int retcode; if( !enabled ) return; if (fd != 0) { unique_id = sockt->session[fd]->gepard_info.unique_id; } SQL->EscapeStringLen(sql_handle, esc_username, username, strnlen(username, NAME_LENGTH)); SQL->EscapeStringLen(sql_handle, esc_message, message, strnlen(message, 255)); retcode = SQL->Query(sql_handle, "INSERT INTO `%s`(`time`,`ip`,`user`,`rcode`,`unique_id`,`log`) VALUES (NOW(), '%s', '%s', '%d', '%u', '%s')", log_login_db, sockt->ip2str(ip,NULL), esc_username, rcode, unique_id, esc_message); if( retcode != SQL_SUCCESS ) Sql_ShowDebug(sql_handle); } ------------------------------------------------------------------------------------------------------------------------------------------------------------------ Open ../src/login/ipban_sql.c and after: #include "common/timer.h" ==== add: ==== #include "common/socket.h" ===================== Add to the end of the file add: ===================== void gepard_update_last_unique_id(int account_id, uint32 unique_id) { if (SQL_SUCCESS != SQL->Query(sql_handle, "UPDATE `login` SET `last_unique_id`= '%u' WHERE `account_id` = '%d'", unique_id, account_id)) { Sql_ShowDebug(sql_handle); } else if (SQL_SUCCESS == SQL->NextRow(sql_handle)) { Sql_ShowDebug(sql_handle); } SQL->FreeResult(sql_handle); } bool gepard_check_unique_id(int fd, uint32 unique_id) { if (SQL_SUCCESS != SQL->Query(sql_handle, "SELECT `unban_time`, `reason` FROM `gepard_block` WHERE `unique_id` = '%u'", unique_id)) { Sql_ShowDebug(sql_handle); gepard_send_info(fd, GEPARD_INFO_BANNED, "Tell administrator about SQL problem."); } else if (SQL_SUCCESS == SQL->NextRow(sql_handle)) { char* data; struct tm unblock_tm; time_t time_unban, time_server; int year, month, day, hour, min, sec; char reason_str[GEPARD_REASON_LENGTH]; char unban_time_str[GEPARD_TIME_STR_LENGTH]; memset((void*)&unblock_tm, 0, sizeof(unblock_tm)); SQL->GetData(sql_handle, 0, &data, NULL); safestrncpy(unban_time_str, data, sizeof(unban_time_str)); sscanf(unban_time_str, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &min, &sec); unblock_tm.tm_year = year - 1900; unblock_tm.tm_mon = month - 1; unblock_tm.tm_mday = day; unblock_tm.tm_hour = hour; unblock_tm.tm_min = min; unblock_tm.tm_sec = sec; time_unban = mktime(&unblock_tm); time(&time_server); if (time_server <= time_unban) { char message_info[200]; SQL->GetData(sql_handle, 1, &data, NULL); safestrncpy(reason_str, data, sizeof(reason_str)); safesnprintf(message_info, sizeof(message_info), "Unique ID has been banned!\r\rDate of unban: %s\r\rUnique id: %u\r\rReason: %s", unban_time_str, unique_id, reason_str); sockt->session[fd]->gepard_info.is_init_ack_received = false; gepard_send_info(fd, GEPARD_INFO_BANNED, message_info); } else if (SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `gepard_block` WHERE `unique_id` = '%u'", unique_id)) { Sql_ShowDebug(sql_handle); } } SQL->FreeResult(sql_handle); return false; } ------------------------------------------------------------------------------------------------------------------------------------------------------------------ Open ../src/login/ipban.h and after: #endif /* LOGIN_IPBAN_H */ ==== add: ==== bool gepard_check_unique_id(int fd, uint32 unique_id); void gepard_update_last_unique_id(int account_id, uint32 unique_id); ------------------------------------------------------------------------------------------------------------------------------------------------------------------ Open ../src/char/char.c and in the function char_parse_frommap after: switch(RFIFOW(fd,0)) { ==== add: ==== case GEPARD_M2C_BLOCK_REQ: chmapif_parse_gepard_block(fd); break; case GEPARD_M2C_UNBLOCK_REQ: chmapif_parse_gepard_unblock(fd); break; =============================== Add to the end of the file ../src/char/char.c: =============================== int chmapif_parse_gepard_block(int fd) { unsigned int unique_id; char* sql_data; char result_str[GEPARD_RESULT_STR_LENGTH]; char reason_str_esc[GEPARD_REASON_LENGTH*2+1]; char unban_time_str_esc[GEPARD_TIME_STR_LENGTH*2+1]; int initiator_aid = 0, violator_aid = 0, offset; char violator_name_esc[NAME_LENGTH*2+1], initiator_name_esc[NAME_LENGTH*2+1]; const char* violator_name, *initiator_name, *reason_str, *unban_time_str; unsigned int packet_len = (2 + 4 + 4 + 4 + NAME_LENGTH + NAME_LENGTH + GEPARD_TIME_STR_LENGTH + GEPARD_REASON_LENGTH); safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: unknown"); if (RFIFOREST(fd) < packet_len) { return 0; } unique_id = RFIFOL(fd, 2); violator_aid = RFIFOL(fd, 6); initiator_aid = RFIFOL(fd, 10); offset = (2 + 4 + 4 + 4); unban_time_str = (char*)RFIFOP(fd,offset); offset += GEPARD_TIME_STR_LENGTH; reason_str = (char*)RFIFOP(fd,offset); offset += GEPARD_REASON_LENGTH; violator_name = (char*)RFIFOP(fd,offset); offset += NAME_LENGTH; initiator_name = (char*)RFIFOP(fd,offset); offset += NAME_LENGTH; while ("Gepard") { SQL->EscapeStringLen(inter->sql_handle, violator_name_esc, violator_name, strnlen(violator_name, NAME_LENGTH)); if (violator_aid == 0 && *violator_name != '\0') { // Get violator's account ID if (SQL_ERROR == SQL->Query(inter->sql_handle, "SELECT `account_id` FROM `char` WHERE `name` = '%s'", violator_name_esc)) { Sql_ShowDebug(inter->sql_handle); safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: An error has been occurred. You should see console.."); break; } else if (SQL->NumRows(inter->sql_handle) == 0) { safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: The player has not found."); break; } else if (SQL_SUCCESS != SQL->NextRow(inter->sql_handle)) { safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: An error has been occurred. You should see console.."); Sql_ShowDebug(inter->sql_handle); break; } SQL->GetData(inter->sql_handle, 0, &sql_data, NULL); violator_aid = atoi(sql_data); SQL->FreeResult(inter->sql_handle); } if (unique_id == 0) { if (violator_aid == 0) { safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: unique_id and violator_aid == 0! ERROR"); break; } // Get violator's unique ID if (SQL_ERROR == SQL->Query(inter->sql_handle, "SELECT `last_unique_id` FROM `login` WHERE `account_id` = '%d'", violator_aid)) { Sql_ShowDebug(inter->sql_handle); safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: An error has been occurred. You should see console.."); break; } else if (SQL->NumRows(inter->sql_handle) == 0) { safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: The account has not been found."); break; } else if (SQL_SUCCESS != SQL->NextRow(inter->sql_handle)) { safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: An error has been occurred. You should see console.."); Sql_ShowDebug(inter->sql_handle); break; } SQL->GetData(inter->sql_handle, 0, &sql_data, NULL); unique_id = strtoul(sql_data, NULL, 10); SQL->FreeResult(inter->sql_handle); } if (unique_id == 0) { safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: You can not block unique_id which equal 0."); break; } if (violator_aid != 0) { if (SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `login` SET `blocked_unique_id` = '%u' WHERE `account_id` = '%d'", unique_id, violator_aid)) { safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: An error has been occurred. You should see console.."); Sql_ShowDebug(inter->sql_handle); break; } SQL->FreeResult(inter->sql_handle); } if (SQL_ERROR == SQL->Query(inter->sql_handle, "SELECT * FROM `gepard_block` WHERE `unique_id` = '%u'", unique_id)) { safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: An error has been occurred. You should see console.."); Sql_ShowDebug(inter->sql_handle); break; } else if (SQL->NumRows(inter->sql_handle) > 0) { if (SQL_ERROR == SQL->Query(inter->sql_handle, "DELETE FROM `gepard_block` WHERE `unique_id` = '%u'", unique_id)) { Sql_ShowDebug(inter->sql_handle); } } SQL->EscapeStringLen(inter->sql_handle, unban_time_str_esc, unban_time_str, strnlen(unban_time_str, GEPARD_TIME_STR_LENGTH)); SQL->EscapeStringLen(inter->sql_handle, initiator_name_esc, initiator_name, strnlen(initiator_name, NAME_LENGTH)); SQL->EscapeStringLen(inter->sql_handle, reason_str_esc, reason_str, strnlen(reason_str, GEPARD_REASON_LENGTH)); if (SQL_ERROR == SQL->Query(inter->sql_handle, "INSERT INTO `gepard_block` (`unique_id`, `unban_time`, `reason`) VALUES ('%u', '%s', '%s')", unique_id, unban_time_str_esc, reason_str_esc)) { safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: An error has been occurred. You should see console.."); Sql_ShowDebug(inter->sql_handle); break; } if (SQL_ERROR == SQL->Query(inter->sql_handle, "INSERT INTO `gepard_block_log` (`unique_id`,`block_time`,`unban_time`,`violator_name`,`violator_account_id`,`initiator_name`,`initiator_account_id`,`reason`)" "VALUES ('%u', NOW(), '%s', '%s', '%u', '%s', '%u', '%s')", unique_id, unban_time_str_esc, violator_name_esc, violator_aid, initiator_name_esc, initiator_aid, reason_str_esc)) { safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: An error has been occurred. You should see console.."); Sql_ShowDebug(inter->sql_handle); break; } safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: Success!"); break; } SQL->FreeResult(inter->sql_handle); WFIFOHEAD(fd, 2 + 4 + 4 + 4 + GEPARD_TIME_STR_LENGTH + GEPARD_TIME_STR_LENGTH + GEPARD_RESULT_STR_LENGTH); WFIFOW(fd, 0) = GEPARD_C2M_BLOCK_ACK; WFIFOL(fd, 2) = unique_id; WFIFOL(fd, 6) = violator_aid; WFIFOL(fd,10) = initiator_aid; offset = (2 + 4 + 4 + 4); safestrncpy((char*)WFIFOP(fd, offset), (char*)RFIFOP(fd, offset), GEPARD_TIME_STR_LENGTH); offset += GEPARD_TIME_STR_LENGTH; safestrncpy((char*)WFIFOP(fd, offset), (char*)RFIFOP(fd, offset), GEPARD_REASON_LENGTH); offset += GEPARD_REASON_LENGTH; safestrncpy((char*)WFIFOP(fd, offset), result_str, GEPARD_RESULT_STR_LENGTH); offset += GEPARD_RESULT_STR_LENGTH; WFIFOSET(fd, offset); RFIFOSKIP(fd, packet_len); return 1; } int chmapif_parse_gepard_unblock(int fd) { unsigned int unique_id; char* sql_data; char result_str[GEPARD_RESULT_STR_LENGTH]; int initiator_aid = 0, violator_aid = 0, offset; char violator_name_esc[NAME_LENGTH*2+1]; char* violator_name; unsigned int packet_len = (2 + 4 + 4 + 4 + NAME_LENGTH); if (RFIFOREST(fd) < packet_len) { return 0; } unique_id = RFIFOL(fd, 2); violator_aid = RFIFOL(fd, 6); initiator_aid = RFIFOL(fd, 10); offset = (2 + 4 + 4 + 4); violator_name = (char*)RFIFOP(fd,offset); offset += NAME_LENGTH; while ("Gepard") { if (violator_aid == 0 && *violator_name != '\0') { SQL->EscapeStringLen(inter->sql_handle, violator_name_esc, violator_name, strnlen(violator_name, NAME_LENGTH)); offset += NAME_LENGTH; if (SQL_ERROR == SQL->Query(inter->sql_handle, "SELECT `account_id` FROM `char` WHERE `name` = '%s'", violator_name)) { Sql_ShowDebug(inter->sql_handle); safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: An error has been occurred. You should see console.."); break; } else if (SQL->NumRows(inter->sql_handle) == 0) { safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: The player has not found."); break; } else if (SQL_SUCCESS != SQL->NextRow(inter->sql_handle)) { safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: An error has been occurred. You should see console.."); Sql_ShowDebug(inter->sql_handle); break; } SQL->GetData(inter->sql_handle, 0, &sql_data, NULL); violator_aid = atoi(sql_data); SQL->FreeResult(inter->sql_handle); } if (violator_aid != 0) { if (SQL_ERROR == SQL->Query(inter->sql_handle, "SELECT `blocked_unique_id` FROM `login` WHERE `account_id` = '%d'", violator_aid)) { Sql_ShowDebug(inter->sql_handle); safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: An error has been occurred. You should see console.."); break; } else if (SQL->NumRows(inter->sql_handle) == 0) { safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: The account has not been found."); break; } else if (SQL_SUCCESS != SQL->NextRow(inter->sql_handle)) { safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: An error has been occurred. You should see console.."); Sql_ShowDebug(inter->sql_handle); SQL->FreeResult(inter->sql_handle); break; } SQL->GetData(inter->sql_handle, 0, &sql_data, NULL); unique_id = strtoul(sql_data, NULL, 10); SQL->FreeResult(inter->sql_handle); if (unique_id == 0) { safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: account don't have block information."); break; } } if (SQL_ERROR == SQL->Query(inter->sql_handle, "DELETE FROM `gepard_block` WHERE `unique_id` = '%u'", unique_id)) { safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: An error has been occurred. You should see console.."); Sql_ShowDebug(inter->sql_handle); SQL->FreeResult(inter->sql_handle); break; } safesnprintf(result_str, GEPARD_RESULT_STR_LENGTH, "Result: Success!"); break; } WFIFOHEAD(fd, 2 + 4 + GEPARD_RESULT_STR_LENGTH); WFIFOW(fd, 0) = GEPARD_C2M_UNBLOCK_ACK; WFIFOL(fd, 2) = initiator_aid; offset = 2 + 4; safestrncpy((char*)WFIFOP(fd, offset), result_str, GEPARD_RESULT_STR_LENGTH); offset += GEPARD_RESULT_STR_LENGTH; WFIFOSET(fd, offset); RFIFOSKIP(fd, packet_len); return 1; } ------------------------------------------------------------------------------------------------------------------------------------------------------------------ Open ../src/char/char.h and before: #endif /* CHAR_CHAR_H */ ==== add: ==== int chmapif_parse_gepard_block(int fd); int chmapif_parse_gepard_unblock(int fd); ------------------------------------------------------------------------------------------------------------------------------------------------------------------ Open ../src/map/chrif.c and in the function chrif_parse after: cmd = RFIFOW(fd,0); ==== add: ==== if (cmd == GEPARD_C2M_BLOCK_ACK) { if (chrif_gepard_ack_block(fd) == true) continue; else return 0; } else if (cmd == GEPARD_C2M_UNBLOCK_ACK) { if (chrif_gepard_ack_unblock(fd) == true) continue; else return 0; } =============================== Add to the end of the file ../src/map/chrif.c: =============================== int chrif_gepard_req_block(unsigned int unique_id, const char* violator_name, unsigned int violator_aid, const char* initiator_name, unsigned int initiator_aid, const char* unban_time_str, const char* reason_str) { unsigned int offset; char send_buffer[2 + 4 + 4 + 4 + GEPARD_TIME_STR_LENGTH + GEPARD_REASON_LENGTH + NAME_LENGTH + NAME_LENGTH]; chrif_check(-1); memset(send_buffer, '\0', sizeof(send_buffer)); WBUFW(send_buffer, 0) = GEPARD_M2C_BLOCK_REQ; WBUFL(send_buffer, 2) = unique_id; WBUFL(send_buffer, 6) = violator_aid; WBUFL(send_buffer,10) = initiator_aid; offset = (2 + 4 + 4 + 4); if (unban_time_str != NULL) safestrncpy((char*)WBUFP(send_buffer, offset), unban_time_str, GEPARD_TIME_STR_LENGTH); offset += GEPARD_TIME_STR_LENGTH; if (reason_str != NULL) safestrncpy((char*)WBUFP(send_buffer, offset), reason_str, GEPARD_REASON_LENGTH); offset += GEPARD_REASON_LENGTH; if (violator_name != NULL) safestrncpy((char*)WBUFP(send_buffer, offset), violator_name, NAME_LENGTH); offset += NAME_LENGTH; if (initiator_name != NULL) safestrncpy((char*)WBUFP(send_buffer, offset), initiator_name, NAME_LENGTH); offset += NAME_LENGTH; WFIFOHEAD(chrif->fd, offset); memcpy((void*)WFIFOP(chrif->fd, 0), send_buffer, offset); WFIFOSET(chrif->fd, offset); return 0; } bool chrif_gepard_ack_block(int fd) { struct map_session_data* sd; int violator_aid, initiator_aid; unsigned int unique_id, offset; char reason_str[GEPARD_REASON_LENGTH]; char result_str[GEPARD_RESULT_STR_LENGTH]; char unban_time_str[GEPARD_TIME_STR_LENGTH]; unsigned int packet_len = (2 + 4 + 4 + 4 + GEPARD_TIME_STR_LENGTH + GEPARD_REASON_LENGTH + GEPARD_RESULT_STR_LENGTH); if (RFIFOREST(fd) < packet_len) return false; unique_id = RFIFOL(fd, 2); violator_aid = RFIFOL(fd, 6); initiator_aid = RFIFOL(fd, 10); offset = (2 + 4 + 4 + 4); safestrncpy(unban_time_str, (char*)RFIFOP(fd, offset), GEPARD_TIME_STR_LENGTH); offset += GEPARD_TIME_STR_LENGTH; safestrncpy(reason_str, (char*)RFIFOP(fd, offset), GEPARD_REASON_LENGTH); offset += GEPARD_REASON_LENGTH; safestrncpy(result_str, (char*)RFIFOP(fd, offset), GEPARD_RESULT_STR_LENGTH); offset += GEPARD_RESULT_STR_LENGTH; if (violator_aid != 0 && (sd = map->id2sd(violator_aid)) != NULL) { char message_info[300]; struct s_mapiterator* iter; safesnprintf(message_info, 300, "Unique ID has been banned!\r\rDate of unban: %s\r\rUnique id: %u\r\rReason: %s", unban_time_str, unique_id, reason_str); iter = mapit_getallusers(); for (sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter)) { if (sockt->session[sd->fd]->gepard_info.unique_id == unique_id) { gepard_send_info(sd->fd, GEPARD_INFO_BANNED, message_info); sockt->session[sd->fd]->recv_crypt.pos_1 = rand() % 255; sockt->session[sd->fd]->recv_crypt.pos_2 = rand() % 255; sockt->session[sd->fd]->recv_crypt.pos_3 = rand() % 255; } } mapit->free(iter); } RFIFOSKIP(fd, offset); if (initiator_aid != 0 && (sd = map->id2sd(initiator_aid)) != NULL) { clif->message(sd->fd, result_str); } return true; } int chrif_gepard_req_unblock(unsigned int unique_id, const char* violator_name, unsigned int violator_aid, unsigned int initiator_aid) { unsigned int offset; char send_buffer[2 + 4 + 4 + 4 + NAME_LENGTH]; chrif_check(-1); memset(send_buffer, '\0', sizeof(send_buffer)); WBUFW(send_buffer, 0) = GEPARD_M2C_UNBLOCK_REQ; WBUFL(send_buffer, 2) = unique_id; WBUFL(send_buffer, 6) = violator_aid; WBUFL(send_buffer,10) = initiator_aid; offset = (2 + 4 + 4 + 4); if (violator_name != NULL) safestrncpy((char*)WBUFP(send_buffer, offset), violator_name, NAME_LENGTH); offset += NAME_LENGTH; WFIFOHEAD(chrif->fd, offset); memcpy((void*)WFIFOP(chrif->fd, 0), send_buffer, offset); WFIFOSET(chrif->fd, offset); return 0; } bool chrif_gepard_ack_unblock(int fd) { struct map_session_data* sd; int initiator_aid, offset; char result_str[GEPARD_RESULT_STR_LENGTH]; unsigned int packet_len = (2 + 4 + GEPARD_RESULT_STR_LENGTH); if (RFIFOREST(fd) < packet_len) return false; initiator_aid = RFIFOL(fd, 2); offset = 2 + 4; safestrncpy(result_str, (char*)RFIFOP(fd, offset), GEPARD_RESULT_STR_LENGTH); offset += GEPARD_RESULT_STR_LENGTH; RFIFOSKIP(fd, offset); if (initiator_aid != 0 && (sd = map->id2sd(initiator_aid)) != NULL) { clif->message(sd->fd, result_str); } return true; } ------------------------------------------------------------------------------------------------------------------------------------------------------------------ Open ../src/map/chrif.h and before: #endif /* MAP_CHRIF_H */ ==== add: ==== int chrif_gepard_req_block(unsigned int unique_id, const char* violator_name, unsigned int violator_aid, const char* initiator_name, unsigned int initiator_aid, const char* unban_time_str, const char* reason_str); bool chrif_gepard_ack_block(int fd); int chrif_gepard_req_unblock(unsigned int unique_id, const char* violator_name, unsigned int violator_aid, unsigned int initiator_aid); bool chrif_gepard_ack_unblock(int fd); ------------------------------------------------------------------------------------------------------------------------------------------------------------------ Open ../src/map/atcommand.c and before: /** * Fills the reference of available commands in atcommand DBMap **/ #define ACMD_DEF(x) { #x, atcommand_ ## x, NULL, NULL } #define ACMD_DEF2(x2, x) { x2, atcommand_ ## x, NULL, NULL } ==== add: ==== ACMD(gepard_block_nick) { struct map_session_data* violator_sd; time_t time_server; unsigned int duration; unsigned int violator_account_id = 0; unsigned int violator_unique_id = 0; char reason_str[GEPARD_REASON_LENGTH]; char unban_time_str[GEPARD_TIME_STR_LENGTH]; char violator_name[NAME_LENGTH]; char duration_type, *command_info = "Wrong input (usage: @gepard_block_nick \"\" )"; nullpo_retr(-1, sd); memset(atcmd_player_name, '\0', sizeof(atcmd_player_name)); if (!message || !*message || sscanf(message, "%u %c \"%23[^\"]\" %99[^\n]", &duration, &duration_type, violator_name, reason_str) < 4) { clif->message(fd, command_info); return false; } time(&time_server); switch (duration_type) { case 'm': time_server += (duration * 60); break; case 'h': time_server += (duration * 3600); break; case 'd': time_server += (duration * 86400); break; default: duration = 0; break; } if (duration == 0) { clif->message(fd, command_info); return false; } strftime(unban_time_str, sizeof(unban_time_str), "%Y-%m-%d %H:%M:%S", localtime(&time_server)); sprintf(atcmd_output, "Request: block by name - %s", violator_name); clif->message(fd, atcmd_output); violator_sd = map->nick2sd(violator_name); if (violator_sd != NULL) { violator_account_id = violator_sd->status.account_id; violator_unique_id = sockt->session[violator_sd->fd]->gepard_info.unique_id; } chrif_gepard_req_block(violator_unique_id, violator_name, violator_account_id, sd->status.name, sd->status.account_id, unban_time_str, reason_str); return true; } ACMD(gepard_block_account_id) { struct map_session_data* violator_sd; time_t time_server; unsigned int duration; unsigned int violator_account_id = 0; unsigned int violator_unique_id = 0; char reason_str[GEPARD_REASON_LENGTH]; char unban_time_str[GEPARD_TIME_STR_LENGTH]; char duration_type, *command_info = "Wrong input (usage: @gepard_block_account_id )"; nullpo_retr(-1, sd); memset(atcmd_player_name, '\0', sizeof(atcmd_player_name)); if (!message || !*message || sscanf(message, "%u %c %u %99[^\n]", &duration, &duration_type, &violator_account_id, reason_str) < 4) { clif->message(fd, command_info); return false; } time(&time_server); switch (duration_type) { case 'm': time_server += (duration * 60); break; case 'h': time_server += (duration * 3600); break; case 'd': time_server += (duration * 86400); break; default: duration = 0; break; } if (duration == 0) { clif->message(fd, command_info); return false; } strftime(unban_time_str, sizeof(unban_time_str), "%Y-%m-%d %H:%M:%S", localtime(&time_server)); sprintf(atcmd_output, "Request: block by account ID: %u", violator_account_id); clif->message(fd, atcmd_output); violator_sd = map->id2sd(violator_account_id); if (violator_sd != NULL) { violator_account_id = violator_sd->status.account_id; violator_unique_id = sockt->session[violator_sd->fd]->gepard_info.unique_id; } chrif_gepard_req_block(violator_unique_id, atcmd_player_name, violator_account_id, sd->status.name, sd->status.account_id, unban_time_str, reason_str); return true; } ACMD(gepard_block_unique_id) { time_t time_server; unsigned int duration; unsigned int violator_unique_id = 0; char reason_str[GEPARD_REASON_LENGTH]; char unban_time_str[GEPARD_TIME_STR_LENGTH]; char duration_type, *command_info = "Wrong input (usage: @gepard_block_unique_id )"; nullpo_retr(-1, sd); memset(atcmd_player_name, '\0', sizeof(atcmd_player_name)); if (!message || !*message || sscanf(message, "%u %c %u %99[^\n]", &duration, &duration_type, &violator_unique_id, reason_str) < 4) { clif->message(fd, command_info); return false; } time(&time_server); switch (duration_type) { case 'm': time_server += (duration * 60); break; case 'h': time_server += (duration * 3600); break; case 'd': time_server += (duration * 86400); break; default: duration = 0; break; } if (duration == 0) { clif->message(fd, command_info); return false; } strftime(unban_time_str, sizeof(unban_time_str), "%Y-%m-%d %H:%M:%S", localtime(&time_server)); sprintf(atcmd_output, "Request: block by unqiue ID: %u", violator_unique_id); clif->message(fd, atcmd_output); chrif_gepard_req_block(violator_unique_id, NULL, 0, sd->status.name, sd->status.account_id, unban_time_str, reason_str); return true; } ACMD(gepard_unblock_nick) { char violator_name[NAME_LENGTH]; char* command_info = "Wrong input (usage: @gepard_unblock_nick )"; nullpo_retr(-1, sd); if (!message || !*message || sscanf(message, "\"%23[^\"]\"[^\n]", violator_name) < 1) { clif->message(fd, command_info); return false; } sprintf(atcmd_output, "Request: unblock by name - %s", violator_name); clif->message(fd, atcmd_output); chrif_gepard_req_unblock(0, violator_name, 0, sd->status.account_id); return true; } ACMD(gepard_unblock_account_id) { int violator_aid; char* command_info = "Wrong input (usage: @gepard_unblock_account_id )"; nullpo_retr(-1, sd); memset(atcmd_player_name, '\0', sizeof(atcmd_player_name)); if (!message || !*message || sscanf(message, "%d", &violator_aid) < 1) { clif->message(fd, command_info); return false; } sprintf(atcmd_output, "Request: unblock by account id - %d", violator_aid); clif->message(fd, atcmd_output); chrif_gepard_req_unblock(0, NULL, violator_aid, sd->status.account_id); return true; } ACMD(gepard_unblock_unique_id) { unsigned int violator_unique_id; char* command_info = "Wrong input (usage: @gepard_unblock_unique_id )"; nullpo_retr(-1, sd); if (!message || !*message || sscanf(message, "%u", &violator_unique_id) < 1) { clif->message(fd, command_info); return false; } sprintf(atcmd_output, "Request: unblock by unique id - %u", violator_unique_id); clif->message(fd, atcmd_output); chrif_gepard_req_unblock(violator_unique_id, NULL, 0, sd->status.account_id); return true; } ACMD(set_allowed_gepard_version) { FILE* fp; unsigned int gepard_version; nullpo_retr(-1, sd); gepard_version = strtoul(message, NULL, 10); if ((fp = fopen("conf/gepard_version.txt", "w+")) == NULL) { clif->message(fd, "Can not open conf/gepard_version.txt !"); return -1; } fprintf (fp, "%u", gepard_version); fclose(fp); min_allowed_gepard_version = gepard_version; sprintf(atcmd_output, "Min allowed Gepard version was set to %u !", min_allowed_gepard_version); clif->message(fd, atcmd_output); return true; } ACMD(get_allowed_gepard_version) { sprintf(atcmd_output, "Min allowed version of Gepard Shield is %u", min_allowed_gepard_version); clif->message(fd, atcmd_output); return true; } ==== after: ==== AtCommandInfo atcommand_base[] = { ==== add: ==== ACMD_DEF(gepard_block_nick), ACMD_DEF(gepard_block_account_id), ACMD_DEF(gepard_block_unique_id), ACMD_DEF(gepard_unblock_nick), ACMD_DEF(gepard_unblock_account_id), ACMD_DEF(gepard_unblock_unique_id), ACMD_DEF(set_allowed_gepard_version), ACMD_DEF(get_allowed_gepard_version), ----------------------------------------------------------------------------------------------------------------------------- Open ../src/map/clif.h and before: #endif /* MAP_CLIF_H */ ==== add: ==== // Gepard Shield bool clif_gepard_process_packet(struct map_session_data* sd); // Gepard Shield ----------------------------------------------------------------------------------------------------------------------------- Open ../src/map/clif.c and in the function clif_parse_WantToConnection before: pc->setnewpc(sd, account_id, char_id, login_id1, client_tick, sex, fd); ==== add: ==== // Gepard Shield if (is_gepard_active) { gepard_init(fd, GEPARD_MAP); sockt->session[fd]->gepard_info.sync_tick = timer->gettick(); } // Gepard Shield ====================== In the function clif_parse after: ====================== if (RFIFOREST(fd) < 2) return 0; ==== add: ==== // Gepard Shield if (is_gepard_active == true && sd != NULL && clif_gepard_process_packet(sd) == true) { return 0; } // Gepard Shield ============================== Add to the end of the file ../src/map/clif.c: ============================== int clif_gepard_timer_kick(int tid, int64 tick, int id, intptr_t data) { struct map_session_data* sd = map->id2sd(id); if (sd != NULL) { clif->GM_kick(NULL, sd); } return 0; } bool clif_gepard_process_packet(struct map_session_data* sd) { int fd = sd->fd; int packet_id = RFIFOW(fd, 0); unsigned int packet_len = (packet_id <= MAX_PACKET_DB) ? packet_db[packet_id].len : 0; int64 diff_time = timer->gettick() - sockt->session[fd]->gepard_info.sync_tick; if (diff_time > 40000) { clif_authfail_fd(sd->fd, 15); } switch (packet_id) { case CS_LOAD_END_ACK: { if (sockt->session_is_active(fd) && pc_get_group_level(sd) != 99) { const uint16 packet_info_size = 6; if (sockt->session[fd]->gepard_info.gepard_shield_version < min_allowed_gepard_version) { WFIFOHEAD(fd, packet_info_size); WFIFOW(fd, 0) = SC_GEPARD_INFO; WFIFOW(fd, 2) = packet_info_size; WFIFOW(fd, 4) = GEPARD_INFO_OLD_VERSION; WFIFOSET(fd, packet_info_size); timer->add(timer->gettick() + 5000, clif_gepard_timer_kick, sd->bl.id, 0); } } } break; } return gepard_process_packet(fd, sockt->session[fd]->rdata + sockt->session[fd]->rdata_pos, packet_len, &sockt->session[fd]->recv_crypt); } ------------------------------------------------------------------------------------------------------------------------------------------------------------------ Open ../src/map/script.c and before: // declarations that were supposed to be exported from npc_chat.c #ifdef PCRE_SUPPORT ==== add: ==== BUILDIN(get_unique_id) { struct map_session_data* sd = script_rid2sd(st); if (sd == NULL) { script_pushint(st,0); return 0; } script_pushint(st, sockt->session[sd->fd]->gepard_info.unique_id); return 0; } ==== after: ==== struct script_function BUILDIN[] = { ==== add: ==== BUILDIN_DEF(get_unique_id,""), ----------------------------------------------------------------------------------------------------------------------------- You should create file gepard_shield.conf in the "conf" folder with content: // Gepard Shield configuration file // enable/disable shield gepard_shield_enabled: yes ----------------------------------------------------------------------------------------------------------------------------- Value of parameter "packet_obfuscation" from ../conf/battle/client.conf has to be 0 or 1 ----------------------------------------------------------------------------------------------------------------------------- Current version of gepard module is 2016011401 Players can't connect with lower version. It will be useful for updates. Admins with 99 GM can bypass this restriction. You can view and set it in the game by using user commands without restarting the server. Examples: @get_allowed_gepard_version @set_allowed_gepard_version 2016011401 You should create file "gepard_version.txt" in the "conf" folder with content: 2016011401 ------------------------------------------------------------------------------------------------------------------------------------------------------------------ DB modifications ALTER TABLE `login` ADD `last_unique_id` INT( 11 ) UNSIGNED NOT NULL DEFAULT '0'; ALTER TABLE `login` ADD `blocked_unique_id` INT( 11 ) UNSIGNED NOT NULL DEFAULT '0'; ALTER TABLE `loginlog` ADD `unique_id` INT( 11 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `rcode`; CREATE TABLE IF NOT EXISTS `gepard_block` ( `unique_id` int(11) unsigned NOT NULL DEFAULT '0', `unban_time` datetime NOT NULL, `reason` varchar(50) NOT NULL, UNIQUE KEY `unique_id` (`unique_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `gepard_block_log` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `unique_id` int(11) unsigned NOT NULL DEFAULT '0', `block_time` datetime NOT NULL, `unban_time` datetime NOT NULL, `violator_name` varchar(24) NOT NULL, `violator_account_id` int(11) NOT NULL, `initiator_name` varchar(24) NOT NULL, `initiator_account_id` int(11) NOT NULL, `reason` varchar(50) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1; ------------------------------------------------------------------------------------------------------------------------------------------------------------------ Example: m - minutes h - hours d - days usage: @gepard_block_nick "" @gepard_block_nick 5 m "Functor" Cheater usage: @gepard_block_account_id @gepard_block_account_id 5 d 2000001 Cheater usage: @gepard_block_unique_id @gepard_block_unique_id 7 h 2343543253 Cheater usage: @gepard_unblock_nick @gepard_unblock_nick "Functor" usage: @gepard_unblock_account_id @gepard_unblock_account_id 2000001 usage: @gepard_unblock_unique_id @gepard_unblock_unique_id 2343543253 ------------------------------------------------------------------------------------------------------------------------------------------------------------------ Script command: get_unique_id(); ------------------------------------------------------------------------------------------------------------------------------------------------------------------