network: check Console ID conflicts

As Console ID can be sensitive data sometimes, this implementation sent a SHA256 hash of it instead.
This commit is contained in:
zhupengfei 2018-10-31 23:07:03 +08:00
parent 3c589f473f
commit c396e3c6e5
14 changed files with 109 additions and 23 deletions

View file

@ -31,10 +31,11 @@ public:
std::string password; ///< The password required to connect to this room.
struct Member {
std::string nickname; ///< The nickname of the member.
GameInfo game_info; ///< The current game of the member
MacAddress mac_address; ///< The assigned mac address of the member.
ENetPeer* peer; ///< The remote peer.
std::string nickname; ///< The nickname of the member.
std::string console_id_hash; ///< A hash of the console ID of the member.
GameInfo game_info; ///< The current game of the member
MacAddress mac_address; ///< The assigned mac address of the member.
ENetPeer* peer; ///< The remote peer.
};
using MemberList = std::vector<Member>;
MemberList members; ///< Information about the members of this room
@ -69,6 +70,12 @@ public:
*/
bool IsValidMacAddress(const MacAddress& address) const;
/**
* Returns whether the console ID (hash) is valid, ie. isn't already taken by someone else in
* the room.
*/
bool IsValidConsoleId(const std::string& console_id_hash) const;
/**
* Sends a ID_ROOM_IS_FULL message telling the client that the room is full.
*/
@ -84,6 +91,12 @@ public:
*/
void SendMacCollision(ENetPeer* client);
/**
* Sends a IdConsoleIdCollison message telling the client that another member with the same
* console ID exists.
*/
void SendConsoleIdCollision(ENetPeer* client);
/**
* Sends a ID_ROOM_VERSION_MISMATCH message telling the client that the version is invalid.
*/
@ -212,6 +225,9 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) {
std::string nickname;
packet >> nickname;
std::string console_id_hash;
packet >> console_id_hash;
MacAddress preferred_mac;
packet >> preferred_mac;
@ -242,6 +258,11 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) {
preferred_mac = GenerateMacAddress();
}
if (!IsValidConsoleId(console_id_hash)) {
SendConsoleIdCollision(event->peer);
return;
}
if (client_version != network_version) {
SendVersionMismatch(event->peer);
return;
@ -250,6 +271,7 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) {
// At this point the client is ready to be added to the room.
Member member{};
member.mac_address = preferred_mac;
member.console_id_hash = console_id_hash;
member.nickname = nickname;
member.peer = event->peer;
@ -282,6 +304,14 @@ bool Room::RoomImpl::IsValidMacAddress(const MacAddress& address) const {
[&address](const auto& member) { return member.mac_address != address; });
}
bool Room::RoomImpl::IsValidConsoleId(const std::string& console_id_hash) const {
// A Console ID is valid if it is not already taken by anybody else in the room.
std::lock_guard<std::mutex> lock(member_mutex);
return std::all_of(members.begin(), members.end(), [&console_id_hash](const auto& member) {
return member.console_id_hash != console_id_hash;
});
}
void Room::RoomImpl::SendNameCollision(ENetPeer* client) {
Packet packet;
packet << static_cast<u8>(IdNameCollision);
@ -302,6 +332,16 @@ void Room::RoomImpl::SendMacCollision(ENetPeer* client) {
enet_host_flush(server);
}
void Room::RoomImpl::SendConsoleIdCollision(ENetPeer* client) {
Packet packet;
packet << static_cast<u8>(IdConsoleIdCollision);
ENetPacket* enet_packet =
enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE);
enet_peer_send(client, 0, enet_packet);
enet_host_flush(server);
}
void Room::RoomImpl::SendWrongPassword(ENetPeer* client) {
Packet packet;
packet << static_cast<u8>(IdWrongPassword);

View file

@ -59,6 +59,7 @@ enum RoomMessageTypes : u8 {
IdWrongPassword,
IdCloseRoom,
IdRoomIsFull,
IdConsoleIdCollision,
};
/// This is what a server [person creating a server] would use.

View file

@ -73,11 +73,12 @@ public:
* Sends a request to the server, asking for permission to join a room with the specified
* nickname and preferred mac.
* @params nickname The desired nickname.
* @params console_id_hash A hash of the Console ID.
* @params preferred_mac The preferred MAC address to use in the room, the NoPreferredMac tells
* @params password The password for the room
* the server to assign one for us.
*/
void SendJoinRequest(const std::string& nickname,
void SendJoinRequest(const std::string& nickname, const std::string& console_id_hash,
const MacAddress& preferred_mac = NoPreferredMac,
const std::string& password = "");
@ -163,6 +164,9 @@ void RoomMember::RoomMemberImpl::MemberLoop() {
case IdMacCollision:
SetState(State::MacCollision);
break;
case IdConsoleIdCollision:
SetState(State::ConsoleIdCollision);
break;
case IdVersionMismatch:
SetState(State::WrongVersion);
break;
@ -204,11 +208,13 @@ void RoomMember::RoomMemberImpl::Send(Packet&& packet) {
}
void RoomMember::RoomMemberImpl::SendJoinRequest(const std::string& nickname,
const std::string& console_id_hash,
const MacAddress& preferred_mac,
const std::string& password) {
Packet packet;
packet << static_cast<u8>(IdJoinRequest);
packet << nickname;
packet << console_id_hash;
packet << preferred_mac;
packet << network_version;
packet << password;
@ -392,9 +398,9 @@ RoomInformation RoomMember::GetRoomInformation() const {
return room_member_impl->room_information;
}
void RoomMember::Join(const std::string& nick, const char* server_addr, u16 server_port,
u16 client_port, const MacAddress& preferred_mac,
const std::string& password) {
void RoomMember::Join(const std::string& nick, const std::string& console_id_hash,
const char* server_addr, u16 server_port, u16 client_port,
const MacAddress& preferred_mac, const std::string& password) {
// If the member is connected, kill the connection first
if (room_member_impl->loop_thread && room_member_impl->loop_thread->joinable()) {
Leave();
@ -427,7 +433,7 @@ void RoomMember::Join(const std::string& nick, const char* server_addr, u16 serv
if (net > 0 && event.type == ENET_EVENT_TYPE_CONNECT) {
room_member_impl->nickname = nick;
room_member_impl->StartLoop();
room_member_impl->SendJoinRequest(nick, preferred_mac, password);
room_member_impl->SendJoinRequest(nick, console_id_hash, preferred_mac, password);
SendGameInfo(room_member_impl->current_game_info);
} else {
enet_peer_disconnect(room_member_impl->server, 0);

View file

@ -54,12 +54,13 @@ public:
LostConnection, ///< Connection closed
// Reasons why connection was rejected
NameCollision, ///< Somebody is already using this name
MacCollision, ///< Somebody is already using that mac-address
WrongVersion, ///< The room version is not the same as for this RoomMember
WrongPassword, ///< The password doesn't match the one from the Room
CouldNotConnect, ///< The room is not responding to a connection attempt
RoomIsFull ///< Room is already at the maximum number of players
NameCollision, ///< Somebody is already using this name
MacCollision, ///< Somebody is already using that mac-address
ConsoleIdCollision, ///< Somebody in the room has the same Console ID
WrongVersion, ///< The room version is not the same as for this RoomMember
WrongPassword, ///< The password doesn't match the one from the Room
CouldNotConnect, ///< The room is not responding to a connection attempt
RoomIsFull ///< Room is already at the maximum number of players
};
struct MemberInformation {
@ -116,11 +117,13 @@ public:
/**
* Attempts to join a room at the specified address and port, using the specified nickname.
* This may fail if the username is already taken.
* A console ID hash is passed in to check console ID conflicts.
* This may fail if the username or console ID is already taken.
*/
void Join(const std::string& nickname, const char* server_addr = "127.0.0.1",
const u16 server_port = DefaultRoomPort, const u16 client_port = 0,
const MacAddress& preferred_mac = NoPreferredMac, const std::string& password = "");
void Join(const std::string& nickname, const std::string& console_id_hash,
const char* server_addr = "127.0.0.1", const u16 server_port = DefaultRoomPort,
const u16 client_port = 0, const MacAddress& preferred_mac = NoPreferredMac,
const std::string& password = "");
/**
* Sends a WiFi packet to the room.