--- a/rust/hedgewars-server/Cargo.toml Tue Dec 17 18:54:17 2019 +0300
+++ b/rust/hedgewars-server/Cargo.toml Thu Dec 19 23:13:58 2019 +0300
@@ -12,6 +12,7 @@
[dependencies]
getopts = "0.2.18"
rand = "0.6"
+chrono = "0.4"
mio = "0.6"
mio-extras = "2.0.5"
slab = "0.4"
--- a/rust/hedgewars-server/src/core/server.rs Tue Dec 17 18:54:17 2019 +0300
+++ b/rust/hedgewars-server/src/core/server.rs Thu Dec 19 23:13:58 2019 +0300
@@ -7,12 +7,11 @@
use crate::{protocol::messages::HwProtocolMessage::Greeting, utils};
use bitflags::*;
+use chrono::{offset, DateTime};
use log::*;
-use slab;
+use slab::Slab;
use std::{borrow::BorrowMut, collections::HashSet, iter, mem::replace, num::NonZeroU16};
-type Slab<T> = slab::Slab<T>;
-
#[derive(Debug)]
pub enum CreateRoomError {
InvalidName,
@@ -88,14 +87,58 @@
pub is_contributor: bool,
}
+struct Ipv4AddrRange {
+ min: [u8; 4],
+ max: [u8; 4],
+}
+
+impl Ipv4AddrRange {
+ fn contains(&self, addr: [u8; 4]) -> bool {
+ (0..4).all(|i| self.min[i] <= addr[i] && addr[i] <= self.max[i])
+ }
+}
+
+struct BanCollection {
+ ban_ips: Vec<Ipv4AddrRange>,
+ ban_timeouts: Vec<DateTime<offset::Utc>>,
+ ban_reasons: Vec<String>,
+}
+
+impl BanCollection {
+ fn new() -> Self {
+ Self {
+ ban_ips: vec![],
+ ban_timeouts: vec![],
+ ban_reasons: vec![],
+ }
+ }
+
+ fn find(&self, addr: [u8; 4]) -> Option<String> {
+ let time = offset::Utc::now();
+ self.ban_ips
+ .iter()
+ .enumerate()
+ .find(|(i, r)| r.contains(addr) && time < self.ban_timeouts[*i])
+ .map(|(i, _)| self.ban_reasons[i].clone())
+ }
+}
+
pub struct HwAnteroom {
pub clients: IndexSlab<HwAnteClient>,
+ bans: BanCollection,
}
impl HwAnteroom {
pub fn new(clients_limit: usize) -> Self {
let clients = IndexSlab::with_capacity(clients_limit);
- HwAnteroom { clients }
+ HwAnteroom {
+ clients,
+ bans: BanCollection::new(),
+ }
+ }
+
+ pub fn find_ip_ban(&self, addr: [u8; 4]) -> Option<String> {
+ self.bans.find(addr)
}
pub fn add_client(&mut self, client_id: ClientId, salt: String, is_local_admin: bool) {
--- a/rust/hedgewars-server/src/handlers.rs Tue Dec 17 18:54:17 2019 +0300
+++ b/rust/hedgewars-server/src/handlers.rs Thu Dec 19 23:13:58 2019 +0300
@@ -354,16 +354,25 @@
server: &mut HwServer,
client_id: ClientId,
response: &mut Response,
+ addr: [u8; 4],
is_local: bool,
) {
- let mut salt = [0u8; 18];
- thread_rng().fill_bytes(&mut salt);
+ let ban_reason = Some(addr)
+ .filter(|_| !is_local)
+ .and_then(|a| server.anteroom.find_ip_ban(a));
+ if let Some(reason) = ban_reason {
+ response.add(HwServerMessage::Bye(reason).send_self());
+ response.remove_client(client_id);
+ } else {
+ let mut salt = [0u8; 18];
+ thread_rng().fill_bytes(&mut salt);
- server
- .anteroom
- .add_client(client_id, encode(&salt), is_local);
+ server
+ .anteroom
+ .add_client(client_id, encode(&salt), is_local);
- response.add(HwServerMessage::Connected(utils::SERVER_VERSION).send_self());
+ response.add(HwServerMessage::Connected(utils::SERVER_VERSION).send_self());
+ }
}
pub fn handle_client_loss(server: &mut HwServer, client_id: ClientId, response: &mut Response) {
--- a/rust/hedgewars-server/src/server/database.rs Tue Dec 17 18:54:17 2019 +0300
+++ b/rust/hedgewars-server/src/server/database.rs Thu Dec 19 23:13:58 2019 +0300
@@ -7,8 +7,7 @@
const CHECK_ACCOUNT_EXISTS_QUERY: &str =
r"SELECT 1 FROM users WHERE users.name = :username LIMIT 1";
-const GET_ACCOUNT_QUERY: &str =
- r"SELECT CASE WHEN users.status = 1 THEN users.pass ELSE '' END,
+const GET_ACCOUNT_QUERY: &str = r"SELECT CASE WHEN users.status = 1 THEN users.pass ELSE '' END,
(SELECT COUNT(users_roles.rid) FROM users_roles WHERE users.uid = users_roles.uid AND users_roles.rid = 3),
(SELECT COUNT(users_roles.rid) FROM users_roles WHERE users.uid = users_roles.uid AND users_roles.rid = 13)
FROM users WHERE users.name = :username";
--- a/rust/hedgewars-server/src/server/network.rs Tue Dec 17 18:54:17 2019 +0300
+++ b/rust/hedgewars-server/src/server/network.rs Thu Dec 19 23:13:58 2019 +0300
@@ -523,13 +523,18 @@
response.add(Redirect(self.ssl.listener.local_addr().unwrap().port()).send_self())
}
- handlers::handle_client_accept(
- &mut self.server,
- client_id,
- &mut response,
- self.clients[client_id].peer_addr.ip().is_loopback(),
- );
- self.handle_response(response, poll);
+ if let IpAddr::V4(addr) = self.clients[client_id].peer_addr.ip() {
+ handlers::handle_client_accept(
+ &mut self.server,
+ client_id,
+ &mut response,
+ addr.octets(),
+ addr.is_loopback(),
+ );
+ self.handle_response(response, poll);
+ } else {
+ todo!("implement something")
+ }
}
pub fn accept_client(&mut self, poll: &Poll, server_token: mio::Token) -> io::Result<()> {