ip filter middleware (not rejecting yet)

This commit is contained in:
Brandon Thomas committed 2021-06-16 00:45:51 -04:00
1 parent b783fe5bcb
commit 8b95ea3abd
8 files changed
+103 -7

No files matched your search

Generated
+1
View File
@@ -3168,6 +3168,7 @@ dependencies = [
"actix-http",
"actix-multipart",
"actix-rt 2.2.0",
"actix-service",
"actix-utils 3.0.0",
"actix-web",
"anyhow",
+1
View File
@@ -86,6 +86,7 @@ actix-files= "0.5"
actix-http = "2.2.0"
actix-multipart = "0.3.0" # TODO: Ready for 0.4 upgrade
actix-rt = "2.2.0"
actix-service = "1.0.6"
actix-utils = "3.0.0"
actix-web = "3.3.2"
jwt = "0.13.0"
@@ -0,0 +1,84 @@
use std::pin::Pin;
use std::task::{Context, Poll};
use actix_service::{Service, Transform};
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error};
use futures::future::{ok, Ready};
use futures::Future;
use crate::threads::ip_banlist_set::IpBanlistSet;
use log::warn;
use log::info;
// There are two steps in middleware processing.
// 1. Middleware initialization, middleware factory gets called with
// next service in chain as parameter.
// 2. Middleware's call method gets called with normal request.
#[derive(Clone)] // NB: Clone is safe because IpBanlist is clone-safe (internal Arc)
pub struct IpFilter {
ip_banlist: IpBanlistSet,
}
impl IpFilter {
pub fn new(ip_banlist: IpBanlistSet) -> Self {
Self {
ip_banlist,
}
}
}
// Middleware factory is `Transform` trait from actix-service crate
// `S` - type of the next service
// `B` - type of response's body
impl<S, B> Transform<S> for IpFilter
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type InitError = ();
type Transform = IpFilterMiddleware<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
// NB: IpBanlist is clone-safe due to internal Arc.
ok(IpFilterMiddleware { service, ip_banlist: self.ip_banlist.clone() })
}
}
pub struct IpFilterMiddleware<S> {
service: S,
ip_banlist: IpBanlistSet,
}
impl<S, B> Service for IpFilterMiddleware<S>
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, req: ServiceRequest) -> Self::Future {
println!("Hi from start. You requested: {}", req.path());
info!("Checking IP. There are {} bans currently.", self.ip_banlist.num_bans().unwrap_or(0));
let fut = self.service.call(req);
Box::pin(async move {
let res = fut.await?;
println!("Hi from response");
Ok(res)
})
}
}
+1
View File
@@ -0,0 +1 @@
pub mod ip_filter_middleware;
+1
View File
@@ -1,2 +1,3 @@
pub mod endpoints;
pub mod middleware;
pub mod web_utils;
+5
View File
@@ -97,6 +97,7 @@ use sqlx::MySqlPool;
use sqlx::mysql::MySqlPoolOptions;
use std::sync::Arc;
use std::time::Duration;
use crate::http_server::middleware::ip_filter_middleware::IpFilter;
// TODO TODO TODO TODO
// TODO TODO TODO TODO
@@ -270,6 +271,9 @@ pub async fn serve(server_state: ServerState) -> AnyhowResult<()>
let log_format = "[%{HOSTNAME}e] %a \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\" %T";
HttpServer::new(move || {
// NB: Safe to clone due to internal arc
let ip_banlist = server_state_arc.ip_banlist.clone();
App::new()
.app_data(server_state_arc.clone())
.wrap(Cors::default()
@@ -310,6 +314,7 @@ pub async fn serve(server_state: ServerState) -> AnyhowResult<()>
.wrap(DefaultHeaders::new()
.header("X-Backend-Hostname", &hostname)
.header("X-Build-Sha", ""))
.wrap(IpFilter::new(ip_banlist))
// ==================== ACCOUNT CREATION / SESSION MANAGEMENT ====================
.service(
web::resource("/create_account")
+10
View File
@@ -36,4 +36,14 @@ impl IpBanlistSet {
},
}
}
pub fn num_bans(&self) -> AnyhowResult<usize> {
match self.ip_banlist.read() {
Err(_) => Err(anyhow!("Can't read lock")),
Ok(read) => {
let result = read.len();
Ok(result)
},
}
}
}
-7
View File
@@ -5,15 +5,8 @@ use log::info;
use log::warn;
use sqlx::MySqlPool;
use std::collections::HashSet;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::Duration;
use tokio::signal::ctrl_c;
use tokio::signal::unix::signal;
use tokio::signal::unix::{SignalKind, Signal};
use tokio::sync::oneshot::{Sender, Receiver};
use tokio::task::JoinHandle;
pub async fn poll_ip_bans(
ip_banlist_set: IpBanlistSet,