mirror of
https://github.com/ivre/masscanned.git
synced 2025-10-02 06:38:21 +00:00
Fix syn (#102)
* Add unit test for TCP SYN replies * Add functional test for TCP SYN+flag packets * Fix bug: prevent anwsers to SYN+flag first packets * Fix TCP behaviour to match Linux network stack * Update the documentation according to the new behaviour for TCP SYN packets
This commit is contained in:
parent
092a16631c
commit
c132c39ebf
3 changed files with 128 additions and 3 deletions
|
@ -217,7 +217,11 @@ code `0` and the same payload as the incoming packet, as specified by [RFC 792](
|
||||||
a supported protocol (Layer 5/6/7) has been detected,
|
a supported protocol (Layer 5/6/7) has been detected,
|
||||||
* if the received packet has flag `ACK`, it is ignored,
|
* if the received packet has flag `ACK`, it is ignored,
|
||||||
* if the received packet has flag `RST` or `FIN-ACK`, it is ignored,
|
* if the received packet has flag `RST` or `FIN-ACK`, it is ignored,
|
||||||
* if the received packet has flag `SYN`, then `masscanned` answers with a `SYN-ACK` packet, setting a **SYNACK-cookie** in the sequence number.
|
* if the received packet has flag `SYN`, then `masscanned` tries to imitate the behaviour
|
||||||
|
of a standard Linux stack - which is:
|
||||||
|
* if there are additional flags that are not among `PSH`, `URG`, `CWR`, `ECE`, then the `SYN` is ignored,
|
||||||
|
* if the flags `CWR` and`ECE` are simultaneously set, then the `SYN` is ignored,
|
||||||
|
* in any other case, `masscanned` answers with a `SYN-ACK` packet, setting a **SYNACK-cookie** in the sequence number.
|
||||||
|
|
||||||
#### UDP
|
#### UDP
|
||||||
|
|
||||||
|
|
|
@ -104,8 +104,14 @@ pub fn repl<'a, 'b>(
|
||||||
tcp_repl.set_acknowledgement(tcp_req.get_sequence().wrapping_add(1));
|
tcp_repl.set_acknowledgement(tcp_req.get_sequence().wrapping_add(1));
|
||||||
tcp_repl.set_sequence(tcp_req.get_acknowledgement());
|
tcp_repl.set_sequence(tcp_req.get_acknowledgement());
|
||||||
}
|
}
|
||||||
/* Answer to SYN */
|
/* Answer to SYN + P|U|C|E + !(C && E) to imitate Linux network stack */
|
||||||
flags if flags & TcpFlags::SYN == TcpFlags::SYN => {
|
flags
|
||||||
|
if (flags & TcpFlags::SYN) == TcpFlags::SYN &&
|
||||||
|
/* no other flag than S,P,U,C,E */
|
||||||
|
(flags & !(TcpFlags::SYN | TcpFlags::PSH | TcpFlags::URG | TcpFlags::CWR | TcpFlags::ECE)) == 0 &&
|
||||||
|
/* not C && E */
|
||||||
|
((flags & TcpFlags::CWR == 0) || (flags & TcpFlags::ECE == 0)) =>
|
||||||
|
{
|
||||||
tcp_repl = MutableTcpPacket::owned(vec![0; MutableTcpPacket::minimum_packet_size()])
|
tcp_repl = MutableTcpPacket::owned(vec![0; MutableTcpPacket::minimum_packet_size()])
|
||||||
.expect("error constructing a TCP packet");
|
.expect("error constructing a TCP packet");
|
||||||
tcp_repl.set_flags(TcpFlags::ACK);
|
tcp_repl.set_flags(TcpFlags::ACK);
|
||||||
|
@ -141,6 +147,97 @@ mod tests {
|
||||||
|
|
||||||
use crate::logger::MetaLogger;
|
use crate::logger::MetaLogger;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tcp_syn() {
|
||||||
|
let masscanned = Masscanned {
|
||||||
|
mac: MacAddr(0, 0, 0, 0, 0, 0),
|
||||||
|
self_ip_list: None,
|
||||||
|
remote_ip_deny_list: None,
|
||||||
|
synack_key: [0x06a0a1d63f305e9b, 0xd4d4bcbb7304875f],
|
||||||
|
iface: None,
|
||||||
|
log: MetaLogger::new(),
|
||||||
|
};
|
||||||
|
/* reference */
|
||||||
|
let ip_src = IpAddr::V4(Ipv4Addr::new(27, 198, 143, 1));
|
||||||
|
let ip_dst = IpAddr::V4(Ipv4Addr::new(90, 64, 122, 203));
|
||||||
|
let tcp_sport = 65500;
|
||||||
|
let tcp_dport = 80;
|
||||||
|
let seq = 1234567;
|
||||||
|
let ack = 0;
|
||||||
|
let mut client_info = ClientInfo {
|
||||||
|
mac: ClientInfoSrcDst {
|
||||||
|
src: None,
|
||||||
|
dst: None,
|
||||||
|
},
|
||||||
|
ip: ClientInfoSrcDst {
|
||||||
|
src: Some(ip_src),
|
||||||
|
dst: Some(ip_dst),
|
||||||
|
},
|
||||||
|
transport: None,
|
||||||
|
port: ClientInfoSrcDst {
|
||||||
|
src: Some(tcp_sport),
|
||||||
|
dst: Some(tcp_dport),
|
||||||
|
},
|
||||||
|
cookie: None,
|
||||||
|
};
|
||||||
|
/* flags OK - list is exhaustive */
|
||||||
|
/* aim at imitating a Linux network stack */
|
||||||
|
let flags_ok = [
|
||||||
|
TcpFlags::SYN,
|
||||||
|
TcpFlags::SYN | TcpFlags::PSH,
|
||||||
|
TcpFlags::SYN | TcpFlags::URG,
|
||||||
|
TcpFlags::SYN | TcpFlags::CWR,
|
||||||
|
TcpFlags::SYN | TcpFlags::ECE,
|
||||||
|
TcpFlags::SYN | TcpFlags::PSH | TcpFlags::URG,
|
||||||
|
TcpFlags::SYN | TcpFlags::PSH | TcpFlags::CWR,
|
||||||
|
TcpFlags::SYN | TcpFlags::PSH | TcpFlags::ECE,
|
||||||
|
TcpFlags::SYN | TcpFlags::PSH | TcpFlags::ECE,
|
||||||
|
TcpFlags::SYN | TcpFlags::URG | TcpFlags::CWR,
|
||||||
|
TcpFlags::SYN | TcpFlags::URG | TcpFlags::ECE,
|
||||||
|
TcpFlags::SYN | TcpFlags::PSH | TcpFlags::URG | TcpFlags::CWR,
|
||||||
|
TcpFlags::SYN | TcpFlags::PSH | TcpFlags::URG | TcpFlags::ECE,
|
||||||
|
];
|
||||||
|
for flags in flags_ok {
|
||||||
|
let mut tcp_req =
|
||||||
|
MutableTcpPacket::owned(vec![0; MutableTcpPacket::minimum_packet_size()]).unwrap();
|
||||||
|
tcp_req.set_source(tcp_sport);
|
||||||
|
tcp_req.set_destination(tcp_dport);
|
||||||
|
tcp_req.set_sequence(seq);
|
||||||
|
tcp_req.set_acknowledgement(ack);
|
||||||
|
tcp_req.set_flags(flags);
|
||||||
|
let some_tcp_repl = repl(&tcp_req.to_immutable(), &masscanned, &mut client_info);
|
||||||
|
if some_tcp_repl == None {
|
||||||
|
panic!("expected a reply, got none for flags: {:?}", flags);
|
||||||
|
}
|
||||||
|
let tcp_repl = some_tcp_repl.unwrap();
|
||||||
|
/* check reply flags */
|
||||||
|
assert!(tcp_repl.get_flags() == (TcpFlags::SYN | TcpFlags::ACK));
|
||||||
|
/* check reply seq and ack */
|
||||||
|
assert!(tcp_repl.get_acknowledgement() == seq.wrapping_add(1));
|
||||||
|
}
|
||||||
|
/* flags KO - list is *not* exhaustive */
|
||||||
|
let flags_ko = [
|
||||||
|
TcpFlags::SYN | TcpFlags::ACK,
|
||||||
|
TcpFlags::SYN | TcpFlags::FIN,
|
||||||
|
TcpFlags::SYN | TcpFlags::CWR | TcpFlags::ECE,
|
||||||
|
TcpFlags::SYN | TcpFlags::PSH | TcpFlags::URG | TcpFlags::CWR | TcpFlags::ECE,
|
||||||
|
TcpFlags::PSH,
|
||||||
|
];
|
||||||
|
for flags in flags_ko {
|
||||||
|
let mut tcp_req =
|
||||||
|
MutableTcpPacket::owned(vec![0; MutableTcpPacket::minimum_packet_size()]).unwrap();
|
||||||
|
tcp_req.set_source(tcp_sport);
|
||||||
|
tcp_req.set_destination(tcp_dport);
|
||||||
|
tcp_req.set_sequence(seq);
|
||||||
|
tcp_req.set_acknowledgement(ack);
|
||||||
|
tcp_req.set_flags(flags);
|
||||||
|
let some_tcp_repl = repl(&tcp_req.to_immutable(), &masscanned, &mut client_info);
|
||||||
|
if some_tcp_repl != None {
|
||||||
|
panic!("expected no reply, got one");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_tcp_fin_ack() {
|
fn test_tcp_fin_ack() {
|
||||||
let masscanned = Masscanned {
|
let masscanned = Masscanned {
|
||||||
|
|
|
@ -277,3 +277,27 @@ def test_ipv6_tcp_psh_ack():
|
||||||
assert TCP in ack, "expecting TCP, got %r" % ack.summary()
|
assert TCP in ack, "expecting TCP, got %r" % ack.summary()
|
||||||
ack = ack[TCP]
|
ack = ack[TCP]
|
||||||
assert ack.flags == "A", "expecting TCP A, got %r" % syn_ack.flags
|
assert ack.flags == "A", "expecting TCP A, got %r" % syn_ack.flags
|
||||||
|
|
||||||
|
|
||||||
|
@test
|
||||||
|
def test_tcp_syn_with_flags():
|
||||||
|
# send a SYN packet with other TCP flags, should not be answered
|
||||||
|
for flags in ["SA", "SR", "SF", "SPUCE"]:
|
||||||
|
seq_init = int(RandInt())
|
||||||
|
syn = (
|
||||||
|
Ether(dst=MAC_ADDR)
|
||||||
|
/ IP(dst=IPV4_ADDR)
|
||||||
|
/ TCP(flags=flags, dport=80, seq=seq_init)
|
||||||
|
)
|
||||||
|
syn_ack = srp1(syn, timeout=1)
|
||||||
|
assert syn_ack is None, "expecting no answer, got one"
|
||||||
|
# some should be accepted to imitate a Linux network stack
|
||||||
|
for flags in ["SP", "SU", "SC", "SE", "SPU", "SPC", "SPE", "SPUC", "SPUE"]:
|
||||||
|
seq_init = int(RandInt())
|
||||||
|
syn = (
|
||||||
|
Ether(dst=MAC_ADDR)
|
||||||
|
/ IP(dst=IPV4_ADDR)
|
||||||
|
/ TCP(flags=flags, dport=80, seq=seq_init)
|
||||||
|
)
|
||||||
|
syn_ack = srp1(syn, timeout=1)
|
||||||
|
assert syn_ack is not None, "expecting answer, got None"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue