Compare commits

...

3 Commits

Author SHA1 Message Date
Avril 3267151615
Removed un-checked #[cold] from match arm branches.
2 years ago
Avril bfaff6067a
added connection acceptance filters
4 years ago
Avril 5c784482f6
ref lt
4 years ago

812
Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -1,6 +1,6 @@
[package]
name = "markov"
version = "0.9.0"
version = "0.9.1"
description = "Generate string of text from Markov chain fed by stdin"
authors = ["Avril <flanchan@cumallover.me>"]
edition = "2018"
@ -49,6 +49,7 @@ instant-init = []
opt-level = 3
lto = "fat"
codegen-units = 1
strip=true
[dependencies]
chain = {package = "markov", version = "1.1.0"}
@ -68,6 +69,7 @@ smallmap = "1.1.5"
lazy_static = "1.4.0"
once_cell = "1.4.1"
bzip2-sys = {version = "0.1.9", optional = true}
cidr = {version = "0.1.1", features = ["serde"]}
[build-dependencies]
rustc_version = "0.2"

@ -14,5 +14,6 @@ outbound = ''
backlog = 32
internal_backlog = 8
capacity = 4
timeout_ms = 5000
throttle_ms = 50
[mask]
default = 'Accept'

@ -165,7 +165,7 @@ impl BindError<std::convert::Infallible>
match self {
Self::Warp(w) => BindError::Warp(w),
Self::IO(w) => BindError::IO(w),
#[cold] _ => unreachable!(),
/*#[cold]*/ _ => unreachable!(),
}
}
}

@ -15,6 +15,7 @@ use tokio::{
time::Duration,
io::BufReader,
};
use ipfilt::IpFilter;
pub const DEFAULT_FILE_LOCATION: &'static str = "markov.toml";
@ -33,11 +34,14 @@ pub struct Config
pub filter: FilterConfig,
#[serde(default)]
pub writer: WriterConfig,
#[serde(default)]
pub mask: IpFilter,
}
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)]
pub struct FilterConfig
{
#[serde(default)]
inbound: String,
#[serde(default)]
outbound: String,
@ -123,6 +127,7 @@ impl Default for Config
filter: Default::default(),
feed_bounds: "2..".to_owned(),
writer: Default::default(),
mask: Default::default(),
}
}
}

@ -246,7 +246,7 @@ pub async fn host(from: ChainHandle<String>)
tokio::select!{
v = &mut child => {
match v {
#[cold] Ok(_) => {warn!("Child exited before we have? This should probably never happen.")},//Should never happen.
/*#[cold]*/ Ok(_) => {warn!("Child exited before we have? This should probably never happen.")},//Should never happen.
Err(e) => {error!("Child exited abnormally. Aborting: {}", e)}, //Child panic or cancel.
}
},
@ -302,7 +302,7 @@ pub async fn host(from: ChainHandle<String>)
//
// This probably shouldn't happen, as we `select!` for it up there and child never calls `close()` on `rx`.
// In any case, it means we should abort.
#[cold] error!("Failed to send buffer: {}", err);
/*#[cold]*/ error!("Failed to send buffer: {}", err);
break;
}
}

@ -0,0 +1,181 @@
//! Filter accepts and denies based on cidr masks.
use super::*;
use cidr::{
Cidr,
IpCidr,
};
use std::{
net::{
IpAddr,
},
error,
fmt,
};
#[derive(Debug)]
pub struct IpFilterDeniedError(IpAddr, Option<IpCidr>);
impl warp::reject::Reject for IpFilterDeniedError{}
impl error::Error for IpFilterDeniedError{}
impl fmt::Display for IpFilterDeniedError
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "Denied {} due to ", self.0)?;
match &self.1 {
Some(cidr) => write!(f, "matching rule {}", cidr),
None => write!(f, "non-matching accept rule"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord, Serialize, Deserialize)]
pub enum Rule
{
Accept,
Deny,
}
impl Default for Rule
{
#[inline]
fn default() -> Self
{
Self::Deny
}
}
impl Rule
{
fn into_result<'a>(self, net: Option<&'a IpCidr>) -> Result<Option<&'a IpCidr>, Option<IpCidr>>
{
if let Self::Accept = self {
Ok(net)
} else {
Err(net.cloned())
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct IpFilter
{
/// The default fallback rule
pub default: Rule,
#[serde(default)]
accept: Vec<IpCidr>,
#[serde(default)]
deny: Vec<IpCidr>,
}
#[inline] fn find_in<'a>(needle: &IpAddr, haystack: &'a [IpCidr]) -> Option<&'a IpCidr>
{
for x in haystack.iter()
{
if x.contains(needle) {
return Some(x);
}
}
None
}
impl Default for IpFilter
{
#[inline]
fn default() -> Self
{
Self {
default: Rule::Deny,
accept: vec![cidr::Cidr::new_host([127,0,0,1].into())],
deny: Vec::default(),
}
}
}
impl IpFilter
{
/// Create a new CIDR filter with thie default rule.
///
/// Use `default()` to use with default rule.
pub fn new(fallback: Rule) -> Self
{
Self {
default: fallback,
accept: Vec::new(),
deny: Vec::new(),
}
}
/// Checks the rule for this IP, returns a result if it should accept or not.
///
/// If acceptance rule is met, return the CIDR match that caused the acceptance if applicable
///
/// If acceptance rule is not met, return in the error which CIDR match cause the deny if applicable
pub fn check(&self, ip: &IpAddr) -> Result<Option<&'_ IpCidr>, IpFilterDeniedError>
{
let accept = find_in(ip, &self.accept[..]);
let deny = find_in(ip, &self.deny[..]);
let (rule, cidr) = match (accept, deny) {
(None, Some(net)) => (Rule::Deny, Some(net)),
(Some(net), None) => (Rule::Accept, Some(net)),
(Some(ac), Some(den)) if ac != den => {
if ac.network_length() > den.network_length() {
(Rule::Accept, Some(ac))
} else {
(Rule::Deny, Some(den))
}
},
_ => (self.default, None)
};
rule.into_result(cidr)
.map_err(|cidr| IpFilterDeniedError(*ip, cidr))
}
pub fn accept_mask(&self) -> &[IpCidr]
{
&self.accept[..]
}
pub fn deny_mask(&self) -> &[IpCidr]
{
&self.deny[..]
}
pub fn accept_range(&mut self, items: impl IntoIterator<Item = IpCidr>)
{
self.accept.extend(items)
}
pub fn deny_range(&mut self, items: impl IntoIterator<Item = IpCidr>)
{
self.deny.extend(items)
}
pub fn accept_one(&mut self, item: IpCidr)
{
self.accept.push(item)
}
pub fn deny_one(&mut self, items: IpCidr)
{
self.deny.push(items)
}
/// Can any connection ever be accepted?
pub fn possible(&self) -> bool
{
//TODO: Test this
!(self.default == Rule::Deny && self.accept.len() == 0) &&
!(self.deny.iter().find(|x| x.network_length() == 0).is_some() && self.accept.len() == 0)
}
}
pub async fn recover(err: warp::Rejection) -> Result<impl warp::Reply, warp::Rejection>
{
if let Some(t) = err.find::<IpFilterDeniedError>() {
error!("Denying access to {} because of {:?} (403)", t.0, t.1);
Ok(warp::http::Response::builder()
.status(status!(403))
.body(format!("Access denied: {}", t)))
} else {
Err(err)
}
}

@ -1,5 +1,3 @@
#![feature(split_inclusive)]
#![allow(dead_code)]
#[macro_use] extern crate log;
@ -76,6 +74,7 @@ mod msg;
mod state;
use state::State;
mod save;
mod ipfilt;
mod forwarded_list;
use forwarded_list::XForwardedFor;
mod handle;
@ -172,11 +171,25 @@ async fn main() {
} else {
warp::filters::addr::remote().and_then(|x: Option<SocketAddr>| async move {x.map(|x| x.ip()).ok_or_else(|| warp::reject::not_found())}).boxed()
};
let ipfilter = warp::any()
.and(chain)
.and(client_ip)
.and_then(|state: State, host: IpAddr| {
async move {
state.config().mask.check(&host)
.map(|ci| {
trace!("Accepting from rule {:?}", ci);
host
})
.map(move |host| (state, host))
.map_err(warp::reject::custom)
}
}).untuple_one();
let push = warp::put()
.and(warp::path("put"))
.and(chain.clone())
.and(client_ip.clone())
.and(ipfilter.clone())
.and(warp::body::content_length_limit(state.config().max_content_length))
.and(warp::body::stream())
.and_then(|state: State, host: IpAddr, buf| {
@ -186,6 +199,8 @@ async fn main() {
.map_err(|_| warp::reject::not_found()) //(warp::reject::custom) //TODO: Recover rejection filter down below for custom error return
}
})
.recover(ipfilt::recover)
.with(warp::log("markov::put"));
@ -195,8 +210,8 @@ async fn main() {
let single = {
let msz = state.config().max_gen_size;
warp::post()
.and(ipfilter.clone())
.and(warp::path("single"))
.and(client_ip.clone())
.and(warp::path::param()
.map(move |sz: usize| {
if sz == 0 || (2..=msz).contains(&sz) {
@ -209,11 +224,13 @@ async fn main() {
.unify())
.and(warp::body::content_length_limit(state.config().max_content_length))
.and(warp::body::aggregate())
.map(|_, x, y, z| (x,y,z)).untuple_one()
.and_then(api::single)
.with(warp::log("markov::api::single"))
};
warp::path("api")
.and(single)
.recover(ipfilt::recover)
.recover(api::error::rejection)
};
}
@ -221,8 +238,7 @@ async fn main() {
let read = warp::get()
.and(chain.clone())
.and(client_ip.clone())
.and(ipfilter.clone())
.and(warp::path::param().map(|opt: usize| Some(opt))
.or(warp::path::end().map(|| Option::<usize>::None)).unify())
.and_then(|state: State, host: IpAddr, num: Option<usize>| {
@ -240,12 +256,12 @@ async fn main() {
}))))
}
})
.recover(ipfilt::recover)
.with(warp::log("markov::read"));
let sentance = warp::get()
.and(warp::path("sentance")) //TODO: sanitise::Sentance::new_iter the body line
.and(chain.clone())
.and(client_ip.clone())
.and(ipfilter.clone())
.and(warp::path::param().map(|opt: usize| Some(opt))
.or(warp::path::end().map(|| Option::<usize>::None)).unify())
.and_then(|state: State, host: IpAddr, num: Option<usize>| {
@ -263,6 +279,7 @@ async fn main() {
}))))
}
})
.recover(ipfilt::recover)
.with(warp::log("markov::read::sentance"));
let read = warp::path("get").and(read.or(sentance));

@ -113,7 +113,11 @@ use std::any::{
impl<T: 'static> DynRange<T>
{
#[inline]
pub fn into_boxed(self) -> Box<dyn Any /*TODO: + Send + Sync */+ 'static>
{
self.into_inner()
}
fn into_inner(self) -> Box<dyn Any + 'static>
{
match self {
@ -157,7 +161,12 @@ impl<T: 'static> DynRange<T>
}
pub fn downcast<R: RangeBounds<T> + 'static>(self) -> Result<R, Self>
{
Box::new(self).downcast()
self.into_inner().downcast::<R>()
.map(|x| *x)
.map_err(|b| {
todo!("make this bullshit properly unboxable ehh...")
})
//Box::<(dyn std::any::Any + 'static)>::downcast(Box::new(self)).map_ok(|ok| *ok)
}
}

@ -13,7 +13,7 @@ use std::{
#[derive(Debug)]
pub struct SentanceError;
/// A sentance
/// A sentence
#[derive(Debug, PartialEq, Eq)]
#[repr(transparent)]
pub struct Sentance(str);

@ -68,7 +68,8 @@ impl Word
}
/// Create a new iterator over words from this sentance.
pub fn new_iter<'a>(from: &'a (impl AsRef<Sentance> +?Sized+'a)) -> impl Iterator<Item = &'a Self>
pub fn new_iter<'a, 'b>(from: &'a (impl AsRef<Sentance> +?Sized+'b)) -> impl Iterator<Item = &'a Self>
where 'b: 'a
{
let from = from.as_ref();
from.split_inclusive(is_word_boundary)

@ -28,7 +28,7 @@ pub async fn body(state: State, num: Option<usize>, mut output: mpsc::Sender<Str
output.send(filter.filter_owned(match sanitise::Sentance::new_iter(&string)
.max_by_key(|x| x.len()) {
Some(x) => x,
#[cold] None => return Ok(()),
/*#[cold]*/ None => return Ok(()),
}.to_owned())).await?;
}
Ok(())

Loading…
Cancel
Save