From a021cc4c1ed05cd2609552eaf9da3923f4c6187e Mon Sep 17 00:00:00 2001 From: zonyitoo Date: Fri, 5 Mar 2021 16:43:50 +0800 Subject: [PATCH] check repeated salt after first successful decryption fixes #442 --- configs/iptables_mixed.sh | 82 +++++++++++++++++++ configs/iptables_tproxy.sh | 42 +++++----- crates/shadowsocks/src/relay/tcprelay/aead.rs | 49 +++++++---- 3 files changed, 134 insertions(+), 39 deletions(-) create mode 100644 configs/iptables_mixed.sh diff --git a/configs/iptables_mixed.sh b/configs/iptables_mixed.sh new file mode 100644 index 000000000000..5a5da660cae6 --- /dev/null +++ b/configs/iptables_mixed.sh @@ -0,0 +1,82 @@ +#!/bin/sh + +if [[ $EUID -ne 0 ]]; then + echo "This script must be run as root" 1>&2 + exit 1 +fi + +## TCP +# NAT PREROUTING +iptables -t nat -N shadowsocks-nat +# Skip LoopBack, Reserved +iptables -t nat -A shadowsocks-nat -d 0/8 -j RETURN +iptables -t nat -A shadowsocks-nat -d 127/8 -j RETURN +iptables -t nat -A shadowsocks-nat -d 10/8 -j RETURN +iptables -t nat -A shadowsocks-nat -d 169.254/16 -j RETURN +iptables -t nat -A shadowsocks-nat -d 172.16/12 -j RETURN +iptables -t nat -A shadowsocks-nat -d 192.168/16 -j RETURN +iptables -t nat -A shadowsocks-nat -d 224/4 -j RETURN +iptables -t nat -A shadowsocks-nat -d 240/4 -j RETURN +# Bypass CN IPs +iptables -t nat -A shadowsocks-nat -m set --match-set cn dst -j RETURN +# Bypass sslocal's outbound data +iptables -t nat -A shadowsocks-nat -m mark --mark 255 -j RETURN +# Redirect TCP to 60080 +iptables -t nat -A shadowsocks-nat -p tcp -j REDIRECT --to-ports 60080 +# Local TCP -> shadowsocks-nat +iptables -t nat -A OUTPUT -p tcp -j shadowsocks-nat +# LAN TCP -> shadowsocks-nat +iptables -t nat -A PREROUTING -p tcp -j shadowsocks-nat + +## UDP +# Strategy Route +ip rule add fwmark 1 table 233 +ip route add local 0.0.0.0/0 dev lo table 233 + +# TPROXY for LAN +iptables -t mangle -N shadowsocks-tproxy +# Skip LoopBack, Reserved +iptables -t mangle -A shadowsocks-tproxy -d 0/8 -j RETURN +iptables -t mangle -A shadowsocks-tproxy -d 127/8 -j RETURN +iptables -t mangle -A shadowsocks-tproxy -d 10/8 -j RETURN +iptables -t mangle -A shadowsocks-tproxy -d 169.254/16 -j RETURN +iptables -t mangle -A shadowsocks-tproxy -d 172.16/12 -j RETURN +iptables -t mangle -A shadowsocks-tproxy -d 192.168/16 -j RETURN +iptables -t mangle -A shadowsocks-tproxy -d 224/4 -j RETURN +iptables -t mangle -A shadowsocks-tproxy -d 240/4 -j RETURN +# Bypass CN IPs +iptables -t mangle -A shadowsocks-tproxy -m set --match-set cn dst -j RETURN +# Bypass sslocal's outbound data +iptables -t mangle -A shadowsocks-tproxy -m mark --mark 255 -j RETURN +# TPROXY UDP to 60080 +iptables -t mangle -A shadowsocks-tproxy -p udp -j TPROXY --on-port 60080 --tproxy-mark 1/1 +#iptables -t mangle -A shadowsocks-tproxy -p tcp -j TPROXY --on-port 60080 --tproxy-mark 1/1 +# Apply TPROXY to LAN +iptables -t mangle -A PREROUTING -p udp -j shadowsocks-tproxy + +# TPROXY for Local +iptables -t mangle -N shadowsocks-tproxy-mark +# Skip LoopBack, Reserved +iptables -t mangle -A shadowsocks-tproxy-mark -d 127/8 -j RETURN +iptables -t mangle -A shadowsocks-tproxy-mark -d 10/8 -j RETURN +iptables -t mangle -A shadowsocks-tproxy-mark -d 169.254/16 -j RETURN +iptables -t mangle -A shadowsocks-tproxy-mark -d 172.16/12 -j RETURN +iptables -t mangle -A shadowsocks-tproxy-mark -d 192.168/16 -j RETURN +iptables -t mangle -A shadowsocks-tproxy-mark -d 224/4 -j RETURN +iptables -t mangle -A shadowsocks-tproxy-mark -d 240/4 -j RETURN +# Bypass CN IPs +iptables -t mangle -A shadowsocks-tproxy-mark -m set --match-set cn dst -j RETURN +# Bypass sslocal's outbound data +iptables -t mangle -A shadowsocks-tproxy-mark -m mark --mark 255 -j RETURN +# Set MARK and reroute +iptables -t mangle -A shadowsocks-tproxy-mark -p udp -j MARK --set-xmark 1 +#iptables -t mangle -A shadowsocks-tproxy-mark -p tcp -j MARK --set-xmark 1 +# Apply TPROXY for Local +iptables -t mangle -A OUTPUT -p udp -j shadowsocks-tproxy-mark + +# DIVERT rules +# For optimizing TCP +# iptables -t mangle -N shadowsocks-divert +# iptables -t mangle -A shadowsocks-divert -j MARK --set-mark 1 +# iptables -t mangle -A shadowsocks-divert -j ACCEPT +# iptables -t mangle -I PREROUTING -p tcp -m socket -j shadowsocks-divert diff --git a/configs/iptables_tproxy.sh b/configs/iptables_tproxy.sh index 2e1889c2b2d2..1f6170130b8a 100644 --- a/configs/iptables_tproxy.sh +++ b/configs/iptables_tproxy.sh @@ -37,31 +37,31 @@ iptables -t mangle -A PREROUTING -j SS #ip6tables -t mangle -A PREROUTING -j SS # OUTPUT rules -iptables -t mangle -N SS-MASK -#ip6tables -t mangle -N SS-MASK +iptables -t mangle -N SS-MARK +#ip6tables -t mangle -N SS-MARK # Reserved addresses -iptables -t mangle -A SS-MASK -d 0/8 -j RETURN -iptables -t mangle -A SS-MASK -d 127/8 -j RETURN -iptables -t mangle -A SS-MASK -d 10/8 -j RETURN -iptables -t mangle -A SS-MASK -d 169.254/16 -j RETURN -iptables -t mangle -A SS-MASK -d 172.16/12 -j RETURN -iptables -t mangle -A SS-MASK -d 192.168/16 -j RETURN -iptables -t mangle -A SS-MASK -d 224/4 -j RETURN -iptables -t mangle -A SS-MASK -d 240/4 -j RETURN -#ip6tables -t mangle -A SS-MASK -d ::1/128 -j RETURN -#ip6tables -t mangle -A SS-MASK -d fc00::/7 -j RETURN -#ip6tables -t mangle -A SS-MASK -d fe80::/10 -j RETURN +iptables -t mangle -A SS-MARK -d 0/8 -j RETURN +iptables -t mangle -A SS-MARK -d 127/8 -j RETURN +iptables -t mangle -A SS-MARK -d 10/8 -j RETURN +iptables -t mangle -A SS-MARK -d 169.254/16 -j RETURN +iptables -t mangle -A SS-MARK -d 172.16/12 -j RETURN +iptables -t mangle -A SS-MARK -d 192.168/16 -j RETURN +iptables -t mangle -A SS-MARK -d 224/4 -j RETURN +iptables -t mangle -A SS-MARK -d 240/4 -j RETURN +#ip6tables -t mangle -A SS-MARK -d ::1/128 -j RETURN +#ip6tables -t mangle -A SS-MARK -d fc00::/7 -j RETURN +#ip6tables -t mangle -A SS-MARK -d fe80::/10 -j RETURN # Bypass sslocal with mask 0xff (255) -iptables -t mangle -A SS-MASK -j RETURN -m mark --mark 0xff -#ip6tables -t mangle -A SS-MASK -j RETURN -m mark --mark 0xff +iptables -t mangle -A SS-MARK -j RETURN -m mark --mark 0xff +#ip6tables -t mangle -A SS-MARK -j RETURN -m mark --mark 0xff # Reroute -iptables -t mangle -A SS-MASK -p udp -j MARK --set-mark 0x2333 -iptables -t mangle -A SS-MASK -p tcp -j MARK --set-mark 0x2333 -#ip6tables -t mangle -A SS-MASK -p udp -j MARK --set-mark 0x2333 -#ip6tables -t mangle -A SS-MASK -p tcp -j MARK --set-mark 0x2333 +iptables -t mangle -A SS-MARK -p udp -j MARK --set-mark 0x2333 +iptables -t mangle -A SS-MARK -p tcp -j MARK --set-mark 0x2333 +#ip6tables -t mangle -A SS-MARK -p udp -j MARK --set-mark 0x2333 +#ip6tables -t mangle -A SS-MARK -p tcp -j MARK --set-mark 0x2333 # Apply -iptables -t mangle -A OUTPUT -j SS-MASK -#ip6tables -t mangle -A OUTPUT -j SS-MASK +iptables -t mangle -A OUTPUT -j SS-MARK +#ip6tables -t mangle -A OUTPUT -j SS-MARK diff --git a/crates/shadowsocks/src/relay/tcprelay/aead.rs b/crates/shadowsocks/src/relay/tcprelay/aead.rs index 1296fbc58413..1b7757132e04 100644 --- a/crates/shadowsocks/src/relay/tcprelay/aead.rs +++ b/crates/shadowsocks/src/relay/tcprelay/aead.rs @@ -67,6 +67,7 @@ pub struct DecryptedReader { cipher: Option, buffer: BytesMut, method: CipherKind, + salt: Option, } impl DecryptedReader { @@ -79,6 +80,7 @@ impl DecryptedReader { cipher: None, buffer: BytesMut::with_capacity(method.salt_len()), method, + salt: None, } } else { DecryptedReader { @@ -86,6 +88,7 @@ impl DecryptedReader { cipher: Some(Cipher::new(method, key, &[])), buffer: BytesMut::with_capacity(2 + method.tag_len()), method, + salt: None, } } } @@ -105,7 +108,7 @@ impl DecryptedReader { match self.state { DecryptReadState::WaitSalt { ref key } => { let key = unsafe { &*(key.as_ref() as *const _) }; - ready!(self.poll_read_salt(cx, context, stream, key))?; + ready!(self.poll_read_salt(cx, stream, key))?; self.buffer.clear(); self.state = DecryptReadState::ReadLength; @@ -122,7 +125,7 @@ impl DecryptedReader { } }, DecryptReadState::ReadData { length } => { - ready!(self.poll_read_data(cx, stream, length))?; + ready!(self.poll_read_data(cx, context, stream, length))?; self.state = DecryptReadState::BufferedData { pos: 0 }; } @@ -146,13 +149,7 @@ impl DecryptedReader { } } - fn poll_read_salt( - &mut self, - cx: &mut task::Context<'_>, - context: &Context, - stream: &mut S, - key: &[u8], - ) -> Poll> + fn poll_read_salt(&mut self, cx: &mut task::Context<'_>, stream: &mut S, key: &[u8]) -> Poll> where S: AsyncRead + Unpin + ?Sized, { @@ -164,14 +161,10 @@ impl DecryptedReader { } let salt = &self.buffer[..salt_len]; - if context.check_nonce_and_set(&salt) { - use std::io::Error; - - trace!("detected repeated AEAD salt {:?}", ByteStr::new(&salt)); - - let err = Error::new(ErrorKind::Other, "detected repeated salt"); - return Err(err).into(); - } + // #442 Remember salt in filter after first successful decryption. + // + // If we check salt right here will allow attacker to flood our filter and eventually block all of our legitimate clients' requests. + self.salt = Some(Bytes::copy_from_slice(salt)); trace!("got AEAD salt {:?}", ByteStr::new(salt)); @@ -201,7 +194,13 @@ impl DecryptedReader { Ok(Some(length)).into() } - fn poll_read_data(&mut self, cx: &mut task::Context<'_>, stream: &mut S, size: usize) -> Poll> + fn poll_read_data( + &mut self, + cx: &mut task::Context<'_>, + context: &Context, + stream: &mut S, + size: usize, + ) -> Poll> where S: AsyncRead + Unpin + ?Sized, { @@ -219,6 +218,20 @@ impl DecryptedReader { return Err(io::Error::new(ErrorKind::Other, "invalid tag-in")).into(); } + // Check repeated salt after first successful decryption #442 + if self.salt.is_some() { + let salt = self.salt.take().unwrap(); + + if context.check_nonce_and_set(&salt) { + use std::io::Error; + + trace!("detected repeated AEAD salt {:?}", ByteStr::new(&salt)); + + let err = Error::new(ErrorKind::Other, "detected repeated salt"); + return Err(err).into(); + } + } + // Remote TAG self.buffer.truncate(size);