Merge pull request #24 from ivre/enh-log

Enhance logging in masscanned
This commit is contained in:
Pierre 2022-02-14 13:33:13 +01:00 committed by GitHub
commit 7590b02a2f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 748 additions and 72 deletions

View file

@ -290,12 +290,27 @@ tcpdump: pcap_loop: The interface disappeared
0 packets dropped by kernel
```
### Logging Policy
## Logging
* `ERR`: any error - will always be displayed.
* `WARN`, `-v`: responses sent by `masscanned`.
* `INFO`, `-vv`: packets not handled, packets ignored.
* `DEBUG`, `-vvv`: all packets received and sent by `masscanned`.
### Console Logger
**Verbs**:
* `init`
* `recv`
* `send`
* `drop`
#### ARP
```
$ts arp $verb $operation $client_mac $client_ip $masscanned_mac $masscanned_ip
```
#### Ethernet
```
$ts eth $verb $ethertype $client_mac $masscanned_mac
```
## To Do

View file

@ -29,20 +29,18 @@ pub fn repl<'a, 'b>(
arp_req: &'a ArpPacket,
masscanned: &Masscanned,
) -> Option<MutableArpPacket<'b>> {
masscanned.log.arp_recv(arp_req);
let mut arp_repl =
MutableArpPacket::owned(arp_req.packet().to_vec()).expect("error parsing ARP packet");
/* Build ARP answer depending of the type of request */
match arp_req.get_operation() {
ArpOperations::Request => {
masscanned.log.arp_recv(arp_req);
let ip = IpAddr::V4(arp_req.get_target_proto_addr());
/* Ignore ARP requests for IP addresses not handled by masscanned */
if let Some(ip_addr_list) = masscanned.ip_addresses {
if !ip_addr_list.contains(&ip) {
info!(
"Ignoring ARP request from {} for IP {}",
arp_req.get_sender_hw_addr(),
ip
);
masscanned.log.arp_drop(arp_req);
return None;
}
}
@ -53,17 +51,15 @@ pub fn repl<'a, 'b>(
arp_repl.set_target_hw_addr(arp_req.get_sender_hw_addr().to_owned());
arp_repl.set_target_proto_addr(arp_req.get_sender_proto_addr().to_owned());
arp_repl.set_sender_proto_addr(arp_req.get_target_proto_addr().to_owned());
warn!(
"ARP-Reply to {} for IP {}",
arp_req.get_sender_hw_addr(),
arp_repl.get_sender_proto_addr()
);
masscanned.log.arp_send(&arp_repl);
}
_ => {
info!("ARP Operation not handled: {:?}", arp_repl.get_operation());
masscanned.log.arp_drop(arp_req);
return None;
}
};
masscanned.log.arp_send(&arp_repl);
Some(arp_repl)
}
@ -76,6 +72,8 @@ mod tests {
use pnet::util::MacAddr;
use crate::logger::MetaLogger;
#[test]
fn test_arp_reply() {
let mut ips = HashSet::new();
@ -86,6 +84,7 @@ mod tests {
mac: MacAddr::from_str("00:11:22:33:44:55").expect("error parsing MAC address"),
iface: None,
ip_addresses: Some(&ips),
log: MetaLogger::new(),
};
let mut arp_req =
MutableArpPacket::owned([0; 28].to_vec()).expect("error constructing ARP request");

View file

@ -104,7 +104,10 @@ pub fn reply<'a, 'b>(
masscanned: &Masscanned,
mut client_info: &mut ClientInfo,
) -> Option<MutableEthernetPacket<'b>> {
debug!("receiving Ethernet packet: {:?}", eth_req);
/* Fill client information for this packet with MAC addresses (src and dst) */
client_info.mac.src = Some(eth_req.get_source());
client_info.mac.dst = Some(eth_req.get_destination());
masscanned.log.eth_recv(eth_req, &client_info);
let mut eth_repl;
/* First, check if the destination MAC address is one of those masscanned
* is authorized to answer to (avoid answering to packets addressed to
@ -113,16 +116,9 @@ pub fn reply<'a, 'b>(
if !get_authorized_eth_addr(&masscanned.mac, masscanned.ip_addresses)
.contains(&eth_req.get_destination())
{
info!(
"Ignoring Ethernet packet from {} to {}",
eth_req.get_source(),
eth_req.get_destination(),
);
masscanned.log.eth_drop(eth_req, &client_info);
return None;
}
/* Fill client information for this packet with MAC addresses (src and dst) */
client_info.mac.src = Some(eth_req.get_source());
client_info.mac.dst = Some(eth_req.get_destination());
/* Build next layer payload for answer depending on the incoming packet */
match eth_req.get_ethertype() {
/* Construct answer to ARP request */
@ -136,6 +132,7 @@ pub fn reply<'a, 'b>(
eth_repl.set_ethertype(EtherTypes::Arp);
eth_repl.set_payload(arp_repl.packet());
} else {
masscanned.log.eth_drop(eth_req, &client_info);
return None;
}
}
@ -145,6 +142,7 @@ pub fn reply<'a, 'b>(
p
} else {
warn!("error parsing IPv4 packet");
masscanned.log.eth_drop(eth_req, &client_info);
return None;
};
if let Some(mut ipv4_repl) =
@ -158,6 +156,7 @@ pub fn reply<'a, 'b>(
eth_repl.set_ethertype(EtherTypes::Ipv4);
eth_repl.set_payload(ipv4_repl.packet());
} else {
masscanned.log.eth_drop(eth_req, &client_info);
return None;
}
}
@ -172,18 +171,20 @@ pub fn reply<'a, 'b>(
eth_repl.set_ethertype(EtherTypes::Ipv6);
eth_repl.set_payload(ipv6_repl.packet());
} else {
masscanned.log.eth_drop(eth_req, &client_info);
return None;
}
}
/* Log & drop unknown network protocol */
_ => {
info!("Ethernet type not handled: {:?}", eth_req.get_ethertype());
masscanned.log.eth_drop(eth_req, &client_info);
return None;
}
};
eth_repl.set_source(masscanned.mac);
eth_repl.set_destination(eth_req.get_source());
debug!("sending Ethernet packet: {:?}", eth_repl);
masscanned.log.eth_send(&eth_repl, &client_info);
Some(eth_repl)
}
@ -193,6 +194,8 @@ mod tests {
use std::net::{Ipv4Addr, Ipv6Addr};
use std::str::FromStr;
use crate::logger::MetaLogger;
#[test]
fn test_eth_reply() {
/* test payload is IP(src="3.2.1.0", dst=".".join(str(b) for b in [0xaa, 0x99,
@ -212,6 +215,7 @@ mod tests {
mac: MacAddr::from_str("00:11:22:33:44:55").expect("error parsing MAC address"),
iface: None,
ip_addresses: Some(&ips),
log: MetaLogger::new(),
};
let mut eth_req = MutableEthernetPacket::owned(vec![
0;

View file

@ -39,24 +39,20 @@ pub fn repl<'a, 'b>(
masscanned: &Masscanned,
mut client_info: &mut ClientInfo,
) -> Option<MutableIpv4Packet<'b>> {
debug!("receiving IPv4 packet: {:?}", ip_req);
/* Fill client info with source and dest. IP addresses */
client_info.ip.src = Some(IpAddr::V4(ip_req.get_source()));
client_info.ip.dst = Some(IpAddr::V4(ip_req.get_destination()));
masscanned.log.ipv4_recv(&ip_req, &client_info);
/* If masscanned is configured with IP addresses, then
* check that the dest. IP address of the packet is one of
* those handled by masscanned - otherwise, drop the packet.
**/
if let Some(ip_addr_list) = masscanned.ip_addresses {
if !ip_addr_list.contains(&IpAddr::V4(ip_req.get_destination())) {
info!(
"Ignoring IP packet from {} for {}",
ip_req.get_source(),
ip_req.get_destination()
);
masscanned.log.ipv4_drop(&ip_req, &client_info);
return None;
}
}
/* Fill client info with source and dest. IP addresses */
client_info.ip.src = Some(IpAddr::V4(ip_req.get_source()));
client_info.ip.dst = Some(IpAddr::V4(ip_req.get_destination()));
/* Fill client info with transport layer procotol */
client_info.transport = Some(ip_req.get_next_level_protocol());
let mut ip_repl;
@ -77,6 +73,7 @@ pub fn repl<'a, 'b>(
ip_repl.set_payload(icmp_repl.packet());
ip_repl.set_next_level_protocol(IpNextHeaderProtocols::Icmp);
} else {
masscanned.log.ipv4_drop(&ip_req, &client_info);
return None;
}
}
@ -99,6 +96,7 @@ pub fn repl<'a, 'b>(
ip_repl.set_payload(tcp_repl.packet());
ip_repl.set_next_level_protocol(IpNextHeaderProtocols::Tcp);
} else {
masscanned.log.ipv4_drop(&ip_req, &client_info);
return None;
}
}
@ -123,15 +121,13 @@ pub fn repl<'a, 'b>(
ip_repl.set_payload(udp_repl.packet());
ip_repl.set_next_level_protocol(IpNextHeaderProtocols::Udp);
} else {
masscanned.log.ipv4_drop(&ip_req, &client_info);
return None;
}
}
/* Next layer protocol not handled (yet) - dropping packet */
_ => {
info!(
"IPv4 upper layer not handled: {:?}",
ip_req.get_next_level_protocol()
);
masscanned.log.ipv4_drop(&ip_req, &client_info);
return None;
}
};
@ -150,7 +146,7 @@ pub fn repl<'a, 'b>(
/* FIXME when dest. was a multicast IP address */
ip_repl.set_source(ip_req.get_destination());
ip_repl.set_destination(ip_req.get_source());
debug!("sending IPv4 packet: {:?}", ip_repl);
masscanned.log.ipv4_send(&ip_repl, &client_info);
Some(ip_repl)
}
@ -163,6 +159,8 @@ mod tests {
use pnet::util::MacAddr;
use crate::logger::MetaLogger;
#[test]
fn test_ipv4_reply() {
/* test payload is scapy> ICMP() */
@ -178,6 +176,7 @@ mod tests {
mac: MacAddr::from_str("00:11:22:33:44:55").expect("error parsing MAC address"),
iface: None,
ip_addresses: Some(&ips),
log: MetaLogger::new(),
};
let mut ip_req =
MutableIpv4Packet::owned(vec![0; Ipv4Packet::minimum_packet_size() + payload.len()])

View file

@ -14,7 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Masscanned. If not, see <http://www.gnu.org/licenses/>.
use log::*;
use std::net::IpAddr;
use pnet::packet::{
@ -35,7 +34,10 @@ pub fn repl<'a, 'b>(
masscanned: &Masscanned,
mut client_info: &mut ClientInfo,
) -> Option<MutableIpv6Packet<'b>> {
debug!("receiving IPv6 packet: {:?}", ip_req);
/* Fill client info with source and dest. IP address */
client_info.ip.src = Some(IpAddr::V6(ip_req.get_source()));
client_info.ip.dst = Some(IpAddr::V6(ip_req.get_destination()));
masscanned.log.ipv6_recv(ip_req, client_info);
let src = ip_req.get_source();
let mut dst = ip_req.get_destination();
/* If masscanned is configured with IP addresses, check that
@ -46,7 +48,7 @@ pub fn repl<'a, 'b>(
if !ip_addr_list.contains(&IpAddr::V6(dst))
&& ip_req.get_next_header() != IpNextHeaderProtocols::Icmpv6
{
info!("Ignoring IP packet from {} for {}", &src, &dst);
masscanned.log.ipv6_drop(ip_req, client_info);
return None;
}
}
@ -84,6 +86,7 @@ pub fn repl<'a, 'b>(
ip_repl.set_hop_limit(255);
};
} else {
masscanned.log.ipv6_drop(ip_req, client_info);
return None;
}
}
@ -108,6 +111,7 @@ pub fn repl<'a, 'b>(
ip_repl.set_payload_length(tcp_len as u16);
ip_repl.set_payload(&tcp_repl.packet());
} else {
masscanned.log.ipv6_drop(ip_req, client_info);
return None;
}
}
@ -132,15 +136,13 @@ pub fn repl<'a, 'b>(
ip_repl.set_payload_length(udp_len as u16);
ip_repl.set_payload(&udp_repl.packet());
} else {
masscanned.log.ipv6_drop(ip_req, client_info);
return None;
}
}
/* Other protocols are not handled (yet) - dropping */
_ => {
info!(
"IPv6 upper layer not handled: {:?}",
ip_req.get_next_header()
);
masscanned.log.ipv6_drop(ip_req, client_info);
return None;
}
};
@ -153,7 +155,7 @@ pub fn repl<'a, 'b>(
/* Set packet source and dest. */
ip_repl.set_source(dst);
ip_repl.set_destination(src);
debug!("sending IPv6 packet: {:?}", ip_repl);
masscanned.log.ipv6_send(&ip_repl, client_info);
Some(ip_repl)
}
@ -166,6 +168,8 @@ mod tests {
use pnet::util::MacAddr;
use crate::logger::MetaLogger;
#[test]
fn test_ipv6_reply() {
/* test payload is scapy> IPv6(src="7777:6666:5555:4444:3333:2222:1111:0000",
@ -187,6 +191,7 @@ mod tests {
mac: MacAddr::from_str("00:11:22:33:44:55").expect("error parsing MAC address"),
iface: None,
ip_addresses: Some(&ips),
log: MetaLogger::new(),
};
let mut ip_req =
MutableIpv6Packet::owned(vec![0; Ipv6Packet::minimum_packet_size() + payload.len()])

View file

@ -14,8 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Masscanned. If not, see <http://www.gnu.org/licenses/>.
use log::*;
use pnet::packet::{
icmp::{IcmpCode, IcmpPacket, IcmpTypes, MutableIcmpPacket},
Packet,
@ -26,16 +24,16 @@ use crate::Masscanned;
pub fn repl<'a, 'b>(
icmp_req: &'a IcmpPacket,
_masscanned: &Masscanned,
mut _client_info: &ClientInfo,
masscanned: &Masscanned,
client_info: &ClientInfo,
) -> Option<MutableIcmpPacket<'b>> {
debug!("receiving ICMPv4 packet: {:?}", icmp_req);
masscanned.log.icmpv4_recv(icmp_req, client_info);
let mut icmp_repl;
match icmp_req.get_icmp_type() {
IcmpTypes::EchoRequest => {
/* Check code of ICMP packet */
if icmp_req.get_icmp_code() != IcmpCode(0) {
info!("ICMP code not handled: {:?}", icmp_req.get_icmp_code());
masscanned.log.icmpv4_drop(icmp_req, client_info);
return None;
}
/* Compute answer length */
@ -53,13 +51,13 @@ pub fn repl<'a, 'b>(
* reply message."
**/
icmp_repl.set_payload(icmp_req.payload());
warn!("ICMP-Echo-Reply to ICMP-Echo-Request");
}
_ => {
masscanned.log.icmpv4_drop(icmp_req, client_info);
return None;
}
};
debug!("sending ICMPv4 packet: {:?}", icmp_repl);
masscanned.log.icmpv4_send(&icmp_repl, client_info);
Some(icmp_repl)
}
@ -70,6 +68,8 @@ mod tests {
use pnet::util::MacAddr;
use crate::logger::MetaLogger;
#[test]
fn test_icmpv4_reply() {
/* test payload is scapy> ICMP() */
@ -81,6 +81,7 @@ mod tests {
mac: MacAddr::from_str("00:11:22:33:44:55").expect("error parsing MAC address"),
iface: None,
ip_addresses: None,
log: MetaLogger::new(),
};
let mut icmp_req =
MutableIcmpPacket::owned(vec![0; IcmpPacket::minimum_packet_size() + payload.len()])

View file

@ -103,7 +103,7 @@ pub fn repl<'a, 'b>(
masscanned: &Masscanned,
client_info: &ClientInfo,
) -> (Option<MutableIcmpv6Packet<'b>>, Option<Ipv6Addr>) {
debug!("receiving ICMPv6 packet: {:?}", icmp_req);
masscanned.log.icmpv6_recv(icmp_req, client_info);
let mut dst_ip = None;
if icmp_req.get_icmpv6_code() != Icmpv6Codes::NoCode {
return (None, None);
@ -120,6 +120,7 @@ pub fn repl<'a, 'b>(
icmp_repl = MutableIcmpv6Packet::owned(nd_na_repl.packet().to_vec())
.expect("error constructing an ICMPv6 packet");
} else {
masscanned.log.icmpv6_drop(icmp_req, client_info);
return (None, None);
}
}
@ -136,17 +137,13 @@ pub fn repl<'a, 'b>(
icmp_repl = MutableIcmpv6Packet::owned(vec![0; Icmpv6Packet::packet_size(&echo_repl)])
.expect("error constructing an ICMPv6 packet");
icmp_repl.populate(&echo_repl);
warn!("ICMPv6-Echo-Reply to ICMPv6-Echo-Request");
}
_ => {
info!(
"ICMPv6 packet not handled: {:?}",
icmp_req.get_icmpv6_type()
);
masscanned.log.icmpv6_drop(icmp_req, client_info);
return (None, None);
}
};
debug!("sending ICMPv6 packet: {:?}", icmp_repl);
masscanned.log.icmpv6_send(&icmp_repl, client_info);
(Some(icmp_repl), dst_ip)
}
@ -160,6 +157,8 @@ mod tests {
use pnet::packet::icmpv6::ndp::{MutableNeighborSolicitPacket, NeighborSolicit};
use pnet::util::MacAddr;
use crate::logger::MetaLogger;
#[test]
fn test_nd_na_reply() {
let client_info = ClientInfo::new();
@ -174,6 +173,7 @@ mod tests {
mac: MacAddr::from_str("00:11:22:33:44:55").expect("error parsing MAC address"),
iface: None,
ip_addresses: Some(&ips),
log: MetaLogger::new(),
};
/* Legitimate solicitation */
let ndp_ns = NeighborSolicit {
@ -246,6 +246,7 @@ mod tests {
mac: MacAddr::from_str("00:11:22:33:44:55").expect("error parsing MAC address"),
iface: None,
ip_addresses: Some(&ips),
log: MetaLogger::new(),
};
let mut icmpv6_echo_req = MutableIcmpv6Packet::owned(vec![
0;

View file

@ -31,7 +31,7 @@ pub fn repl<'a, 'b>(
masscanned: &Masscanned,
mut client_info: &mut ClientInfo,
) -> Option<MutableTcpPacket<'b>> {
debug!("receiving TCP packet: {:?}", tcp_req);
masscanned.log.tcp_recv(tcp_req, client_info);
/* Fill client info with source and dest. TCP port */
client_info.port.src = Some(tcp_req.get_source());
client_info.port.dst = Some(tcp_req.get_destination());
@ -50,7 +50,7 @@ pub fn repl<'a, 'b>(
/* Compute syncookie */
if let Ok(cookie) = synackcookie::generate(&client_info, &masscanned.synack_key) {
if cookie != ackno {
info!("PSH-ACK ignored: synackcookie not valid");
masscanned.log.tcp_drop(tcp_req, client_info);
return None;
}
client_info.cookie = Some(cookie);
@ -76,10 +76,12 @@ pub fn repl<'a, 'b>(
/* Answer to ACK: nothing */
flags if flags == TcpFlags::ACK => {
/* answer here when server needs to speak first after handshake */
masscanned.log.tcp_drop(tcp_req, client_info);
return None;
}
/* Answer to RST: nothing */
flags if flags == TcpFlags::RST => {
masscanned.log.tcp_drop(tcp_req, client_info);
return None;
}
/* Answer to FIN,ACK with FIN,ACK */
@ -101,10 +103,9 @@ pub fn repl<'a, 'b>(
tcp_repl.set_sequence(
synackcookie::generate(&client_info, &masscanned.synack_key).unwrap(),
);
warn!("SYN-ACK to ACK on port {}", tcp_req.get_destination());
}
_ => {
info!("TCP flag not handled: {}", tcp_req.get_flags());
masscanned.log.tcp_drop(tcp_req, client_info);
return None;
}
}
@ -115,7 +116,7 @@ pub fn repl<'a, 'b>(
/* Set TCP headers */
tcp_repl.set_data_offset(5);
tcp_repl.set_window(65535);
debug!("sending TCP packet: {:?}", tcp_repl);
masscanned.log.tcp_send(&tcp_repl, client_info);
Some(tcp_repl)
}
@ -126,6 +127,8 @@ mod tests {
use pnet::util::MacAddr;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use crate::logger::MetaLogger;
#[test]
fn test_tcp_fin_ack() {
let masscanned = Masscanned {
@ -133,6 +136,7 @@ mod tests {
ip_addresses: None,
synack_key: [0x06a0a1d63f305e9b, 0xd4d4bcbb7304875f],
iface: None,
log: MetaLogger::new(),
};
/* reference */
let ip_src = IpAddr::V4(Ipv4Addr::new(27, 198, 143, 1));
@ -183,6 +187,7 @@ mod tests {
ip_addresses: None,
synack_key: [0x06a0a1d63f305e9b, 0xd4d4bcbb7304875f],
iface: None,
log: MetaLogger::new(),
};
/* reference */
let ip_src = IpAddr::V4(Ipv4Addr::new(27, 198, 143, 1));
@ -232,6 +237,7 @@ mod tests {
ip_addresses: None,
synack_key: [0x06a0a1d63f305e9b, 0xd4d4bcbb7304875f],
iface: None,
log: MetaLogger::new(),
};
/* reference */
let ip_src = IpAddr::V6(Ipv6Addr::new(234, 52, 183, 47, 184, 172, 64, 141));

View file

@ -14,8 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Masscanned. If not, see <http://www.gnu.org/licenses/>.
use log::*;
use pnet::packet::{
udp::{MutableUdpPacket, UdpPacket},
Packet,
@ -30,7 +28,7 @@ pub fn repl<'a, 'b>(
masscanned: &Masscanned,
mut client_info: &mut ClientInfo,
) -> Option<MutableUdpPacket<'b>> {
debug!("receiving UDP packet: {:?}", udp_req);
masscanned.log.udp_recv(udp_req, client_info);
/* Fill client info with source and dest. UDP port */
client_info.port.src = Some(udp_req.get_source());
client_info.port.dst = Some(udp_req.get_destination());
@ -43,12 +41,13 @@ pub fn repl<'a, 'b>(
.expect("error constructing a UDP packet");
udp_repl.set_length(udp_repl.packet().len() as u16);
} else {
masscanned.log.udp_drop(udp_req, client_info);
return None;
}
/* Set source and dest. port for response packet from client info */
/* Note: client info could have been modified by upper layers (e.g., STUN) */
udp_repl.set_source(client_info.port.dst.unwrap());
udp_repl.set_destination(client_info.port.src.unwrap());
debug!("sending UDP packet: {:?}", udp_repl);
masscanned.log.udp_send(&udp_repl, client_info);
Some(udp_repl)
}

308
src/logger/console.rs Normal file
View file

@ -0,0 +1,308 @@
// This file is part of masscanned.
// Copyright 2021 - The IVRE project
//
// Masscanned is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Masscanned is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Masscanned. If not, see <http://www.gnu.org/licenses/>.
use std::time::SystemTime;
use pnet::packet::{
arp::{ArpPacket, MutableArpPacket},
ethernet::{EthernetPacket, MutableEthernetPacket},
icmp::{IcmpPacket, MutableIcmpPacket},
icmpv6::{Icmpv6Packet, MutableIcmpv6Packet},
ipv4::{Ipv4Packet, MutableIpv4Packet},
ipv6::{Ipv6Packet, MutableIpv6Packet},
tcp::{MutableTcpPacket, TcpPacket},
udp::{MutableUdpPacket, UdpPacket},
};
use crate::client::ClientInfo;
use crate::logger::Logger;
pub struct ConsoleLogger {
arp: bool,
eth: bool,
ipv4: bool,
ipv6: bool,
icmpv4: bool,
icmpv6: bool,
tcp: bool,
udp: bool,
}
impl ConsoleLogger {
pub fn new() -> Self {
ConsoleLogger {
arp: true,
eth: true,
ipv4: true,
ipv6: true,
icmpv4: true,
icmpv6: true,
tcp: true,
udp: true,
}
}
fn prolog(&self, proto: &str, verb: &str, crlf: bool) {
let now = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap();
print!(
"{}.{}\t{}\t{}{}",
now.as_secs(),
now.subsec_millis(),
proto,
verb,
if crlf { "\n" } else { "\t" },
);
}
fn client_info(&self, c: &ClientInfo) {
print!(
"{}\t{}\t{}\t{}\t{}\t{}\t{}\t",
if let Some(m) = c.mac.src {
format!("{}", m)
} else {
"".to_string()
},
if let Some(m) = c.mac.dst {
format!("{}", m)
} else {
"".to_string()
},
if let Some(i) = c.ip.src {
format!("{}", i)
} else {
"".to_string()
},
if let Some(i) = c.ip.dst {
format!("{}", i)
} else {
"".to_string()
},
if let Some(t) = c.transport {
format!("{}", t)
} else {
"".to_string()
},
if let Some(p) = c.port.src {
format!("{}", p)
} else {
"".to_string()
},
if let Some(p) = c.port.dst {
format!("{}", p)
} else {
"".to_string()
},
);
}
}
impl Logger for ConsoleLogger {
fn init(&self) {
self.prolog("arp", "init", true);
self.prolog("eth", "init", true);
self.prolog("ipv4", "init", true);
self.prolog("ipv6", "init", true);
self.prolog("icmpv4", "init", true);
self.prolog("icmpv6", "init", true);
self.prolog("tcp", "init", true);
self.prolog("udp", "init", true);
}
/* ARP */
fn arp_enabled(&self) -> bool {
self.arp
}
fn arp_recv(&self, p: &ArpPacket) {
self.prolog("arp", "recv", false);
println!(
"{:}\t{:}\t{:}\t{:}\t{:?}",
p.get_sender_hw_addr(),
p.get_target_hw_addr(),
p.get_sender_proto_addr(),
p.get_target_proto_addr(),
p.get_operation(),
);
}
fn arp_drop(&self, p: &ArpPacket) {
self.prolog("arp", "drop", false);
println!(
"{:}\t{:}\t{:}\t{:}\t{:?}",
p.get_sender_hw_addr(),
p.get_target_hw_addr(),
p.get_sender_proto_addr(),
p.get_target_proto_addr(),
p.get_operation(),
);
}
fn arp_send(&self, p: &MutableArpPacket) {
self.prolog("arp", "send", false);
println!(
"{:}\t{:}\t{:}\t{:}\t{:?}",
p.get_target_hw_addr(),
p.get_sender_hw_addr(),
p.get_target_proto_addr(),
p.get_sender_proto_addr(),
p.get_operation(),
);
}
/* Ethernet */
fn eth_enabled(&self) -> bool {
self.eth
}
fn eth_recv(&self, p: &EthernetPacket, c: &ClientInfo) {
self.prolog("eth", "recv", false);
self.client_info(c);
println!("{:}", p.get_ethertype(),);
}
fn eth_drop(&self, p: &EthernetPacket, c: &ClientInfo) {
self.prolog("eth", "drop", false);
self.client_info(c);
println!("{:}", p.get_ethertype(),);
}
fn eth_send(&self, p: &MutableEthernetPacket, c: &ClientInfo) {
self.prolog("eth", "send", false);
self.client_info(c);
println!("{:}", p.get_ethertype(),);
}
/* IPv4 */
fn ipv4_enabled(&self) -> bool {
self.ipv4
}
fn ipv4_recv(&self, p: &Ipv4Packet, c: &ClientInfo) {
self.prolog("ipv4", "recv", false);
self.client_info(c);
println!("{:}", p.get_next_level_protocol(),);
}
fn ipv4_drop(&self, p: &Ipv4Packet, c: &ClientInfo) {
self.prolog("ipv4", "drop", false);
self.client_info(c);
println!("{:}", p.get_next_level_protocol(),);
}
fn ipv4_send(&self, p: &MutableIpv4Packet, c: &ClientInfo) {
self.prolog("ipv4", "send", false);
self.client_info(c);
println!("{:}", p.get_next_level_protocol(),);
}
/* IPv6 */
fn ipv6_enabled(&self) -> bool {
self.ipv6
}
fn ipv6_recv(&self, p: &Ipv6Packet, c: &ClientInfo) {
self.prolog("ipv6", "recv", false);
self.client_info(c);
println!("{:}", p.get_next_header(),);
}
fn ipv6_drop(&self, p: &Ipv6Packet, c: &ClientInfo) {
self.prolog("ipv6", "drop", false);
self.client_info(c);
println!("{:}", p.get_next_header(),);
}
fn ipv6_send(&self, p: &MutableIpv6Packet, c: &ClientInfo) {
self.prolog("ipv6", "send", false);
self.client_info(c);
println!("{:}", p.get_next_header(),);
}
/* ICMPv4 */
fn icmpv4_enabled(&self) -> bool {
self.icmpv4
}
fn icmpv4_recv(&self, p: &IcmpPacket, c: &ClientInfo) {
self.prolog("icmpv4", "recv", false);
self.client_info(c);
println!("{:?}\t{:?}", p.get_icmp_type(), p.get_icmp_code(),);
}
fn icmpv4_drop(&self, p: &IcmpPacket, c: &ClientInfo) {
self.prolog("icmpv4", "drop", false);
self.client_info(c);
println!("{:?}\t{:?}", p.get_icmp_type(), p.get_icmp_code(),);
}
fn icmpv4_send(&self, p: &MutableIcmpPacket, c: &ClientInfo) {
self.prolog("icmpv4", "send", false);
self.client_info(c);
println!("{:?}\t{:?}", p.get_icmp_type(), p.get_icmp_code(),);
}
/* ICMPv6 */
fn icmpv6_enabled(&self) -> bool {
self.icmpv6
}
fn icmpv6_recv(&self, p: &Icmpv6Packet, c: &ClientInfo) {
self.prolog("icmpv6", "recv", false);
self.client_info(c);
println!("{:?}\t{:?}", p.get_icmpv6_type(), p.get_icmpv6_code(),);
}
fn icmpv6_drop(&self, p: &Icmpv6Packet, c: &ClientInfo) {
self.prolog("icmpv6", "drop", false);
self.client_info(c);
println!("{:?}\t{:?}", p.get_icmpv6_type(), p.get_icmpv6_code(),);
}
fn icmpv6_send(&self, p: &MutableIcmpv6Packet, c: &ClientInfo) {
self.prolog("icmpv6", "send", false);
self.client_info(c);
println!("{:?}\t{:?}", p.get_icmpv6_type(), p.get_icmpv6_code(),);
}
/* TCP */
fn tcp_enabled(&self) -> bool {
self.tcp
}
fn tcp_recv(&self, p: &TcpPacket, c: &ClientInfo) {
self.prolog("tcp", "recv", false);
self.client_info(c);
println!(
"{:?}\t{:}\t{:}",
p.get_flags(),
p.get_sequence(),
p.get_acknowledgement(),
);
}
fn tcp_drop(&self, p: &TcpPacket, c: &ClientInfo) {
self.prolog("tcp", "drop", false);
self.client_info(c);
println!(
"{:?}\t{:}\t{:}",
p.get_flags(),
p.get_sequence(),
p.get_acknowledgement(),
);
}
fn tcp_send(&self, p: &MutableTcpPacket, c: &ClientInfo) {
self.prolog("tcp", "send", false);
self.client_info(c);
println!(
"{:?}\t{:}\t{:}",
p.get_flags(),
p.get_sequence(),
p.get_acknowledgement(),
);
}
/* UDP */
fn udp_enabled(&self) -> bool {
self.udp
}
fn udp_recv(&self, _p: &UdpPacket, c: &ClientInfo) {
self.prolog("udp", "recv", false);
self.client_info(c);
println!("");
}
fn udp_drop(&self, _p: &UdpPacket, c: &ClientInfo) {
self.prolog("udp", "drop", false);
self.client_info(c);
println!("");
}
fn udp_send(&self, _p: &MutableUdpPacket, c: &ClientInfo) {
self.prolog("udp", "send", false);
self.client_info(c);
println!("");
}
}

225
src/logger/meta.rs Normal file
View file

@ -0,0 +1,225 @@
// This file is part of masscanned.
// Copyright 2021 - The IVRE project
//
// Masscanned is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Masscanned is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Masscanned. If not, see <http://www.gnu.org/licenses/>.
use pnet::packet::{
arp::{ArpPacket, MutableArpPacket},
ethernet::{EthernetPacket, MutableEthernetPacket},
icmp::{IcmpPacket, MutableIcmpPacket},
icmpv6::{Icmpv6Packet, MutableIcmpv6Packet},
ipv4::{Ipv4Packet, MutableIpv4Packet},
ipv6::{Ipv6Packet, MutableIpv6Packet},
tcp::{MutableTcpPacket, TcpPacket},
udp::{MutableUdpPacket, UdpPacket},
};
use crate::client::ClientInfo;
use crate::logger::Logger;
pub struct MetaLogger {
loggers: Vec<Box<dyn Logger>>,
}
impl MetaLogger {
pub fn new() -> Self {
MetaLogger {
loggers: Vec::new(),
}
}
pub fn add(&mut self, log: Box<dyn Logger>) {
self.loggers.push(log);
}
pub fn init(&self) {
for l in &self.loggers {
l.init();
}
}
/* ARP */
pub fn arp_recv(&self, p: &ArpPacket) {
for l in &self.loggers {
if l.arp_enabled() {
l.arp_recv(p);
}
}
}
pub fn arp_drop(&self, p: &ArpPacket) {
for l in &self.loggers {
if l.arp_enabled() {
l.arp_drop(p);
}
}
}
pub fn arp_send(&self, p: &MutableArpPacket) {
for l in &self.loggers {
if l.arp_enabled() {
l.arp_send(p);
}
}
}
/* Ethernet */
pub fn eth_recv(&self, p: &EthernetPacket, c: &ClientInfo) {
for l in &self.loggers {
if l.eth_enabled() {
l.eth_recv(p, c);
}
}
}
pub fn eth_drop(&self, p: &EthernetPacket, c: &ClientInfo) {
for l in &self.loggers {
if l.eth_enabled() {
l.eth_drop(p, c);
}
}
}
pub fn eth_send(&self, p: &MutableEthernetPacket, c: &ClientInfo) {
for l in &self.loggers {
if l.eth_enabled() {
l.eth_send(p, c);
}
}
}
/* IPv4 */
pub fn ipv4_recv(&self, p: &Ipv4Packet, c: &ClientInfo) {
for l in &self.loggers {
if l.ipv4_enabled() {
l.ipv4_recv(p, c);
}
}
}
pub fn ipv4_drop(&self, p: &Ipv4Packet, c: &ClientInfo) {
for l in &self.loggers {
if l.ipv4_enabled() {
l.ipv4_drop(p, c);
}
}
}
pub fn ipv4_send(&self, p: &MutableIpv4Packet, c: &ClientInfo) {
for l in &self.loggers {
if l.ipv4_enabled() {
l.ipv4_send(p, c);
}
}
}
/* IPv6 */
pub fn ipv6_recv(&self, p: &Ipv6Packet, c: &ClientInfo) {
for l in &self.loggers {
if l.ipv6_enabled() {
l.ipv6_recv(p, c);
}
}
}
pub fn ipv6_drop(&self, p: &Ipv6Packet, c: &ClientInfo) {
for l in &self.loggers {
if l.ipv6_enabled() {
l.ipv6_drop(p, c);
}
}
}
pub fn ipv6_send(&self, p: &MutableIpv6Packet, c: &ClientInfo) {
for l in &self.loggers {
if l.ipv6_enabled() {
l.ipv6_send(p, c);
}
}
}
/* ICMPv4 */
pub fn icmpv4_recv(&self, p: &IcmpPacket, c: &ClientInfo) {
for l in &self.loggers {
if l.icmpv4_enabled() {
l.icmpv4_recv(p, c);
}
}
}
pub fn icmpv4_drop(&self, p: &IcmpPacket, c: &ClientInfo) {
for l in &self.loggers {
if l.icmpv4_enabled() {
l.icmpv4_drop(p, c);
}
}
}
pub fn icmpv4_send(&self, p: &MutableIcmpPacket, c: &ClientInfo) {
for l in &self.loggers {
if l.icmpv4_enabled() {
l.icmpv4_send(p, c);
}
}
}
/* ICMPv6 */
pub fn icmpv6_recv(&self, p: &Icmpv6Packet, c: &ClientInfo) {
for l in &self.loggers {
if l.icmpv6_enabled() {
l.icmpv6_recv(p, c);
}
}
}
pub fn icmpv6_drop(&self, p: &Icmpv6Packet, c: &ClientInfo) {
for l in &self.loggers {
if l.icmpv6_enabled() {
l.icmpv6_drop(p, c);
}
}
}
pub fn icmpv6_send(&self, p: &MutableIcmpv6Packet, c: &ClientInfo) {
for l in &self.loggers {
if l.icmpv6_enabled() {
l.icmpv6_send(p, c);
}
}
}
/* TCP */
pub fn tcp_recv(&self, p: &TcpPacket, c: &ClientInfo) {
for l in &self.loggers {
if l.tcp_enabled() {
l.tcp_recv(p, c);
}
}
}
pub fn tcp_drop(&self, p: &TcpPacket, c: &ClientInfo) {
for l in &self.loggers {
if l.tcp_enabled() {
l.tcp_drop(p, c);
}
}
}
pub fn tcp_send(&self, p: &MutableTcpPacket, c: &ClientInfo) {
for l in &self.loggers {
if l.tcp_enabled() {
l.tcp_send(p, c);
}
}
}
/* UDP */
pub fn udp_recv(&self, p: &UdpPacket, c: &ClientInfo) {
for l in &self.loggers {
if l.udp_enabled() {
l.udp_recv(p, c);
}
}
}
pub fn udp_drop(&self, p: &UdpPacket, c: &ClientInfo) {
for l in &self.loggers {
if l.udp_enabled() {
l.udp_drop(p, c);
}
}
}
pub fn udp_send(&self, p: &MutableUdpPacket, c: &ClientInfo) {
for l in &self.loggers {
if l.udp_enabled() {
l.udp_send(p, c);
}
}
}
}

95
src/logger/mod.rs Normal file
View file

@ -0,0 +1,95 @@
// This file is part of masscanned.
// Copyright 2021 - The IVRE project
//
// Masscanned is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Masscanned is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Masscanned. If not, see <http://www.gnu.org/licenses/>.
use pnet::packet::{
arp::{ArpPacket, MutableArpPacket},
ethernet::{EthernetPacket, MutableEthernetPacket},
icmp::{IcmpPacket, MutableIcmpPacket},
icmpv6::{Icmpv6Packet, MutableIcmpv6Packet},
ipv4::{Ipv4Packet, MutableIpv4Packet},
ipv6::{Ipv6Packet, MutableIpv6Packet},
tcp::{MutableTcpPacket, TcpPacket},
udp::{MutableUdpPacket, UdpPacket},
};
use crate::client::ClientInfo;
mod console;
mod meta;
pub use console::ConsoleLogger;
pub use meta::MetaLogger;
pub trait Logger {
fn init(&self);
/* list of notifications that a logger might or might not implement */
/* ARP */
fn arp_enabled(&self) -> bool {
true
}
fn arp_recv(&self, _p: &ArpPacket) {}
fn arp_drop(&self, _p: &ArpPacket) {}
fn arp_send(&self, _p: &MutableArpPacket) {}
/* Ethernet */
fn eth_enabled(&self) -> bool {
true
}
fn eth_recv(&self, _p: &EthernetPacket, _c: &ClientInfo) {}
fn eth_drop(&self, _p: &EthernetPacket, _c: &ClientInfo) {}
fn eth_send(&self, _p: &MutableEthernetPacket, _c: &ClientInfo) {}
/* IPv4 */
fn ipv4_enabled(&self) -> bool {
true
}
fn ipv4_recv(&self, _p: &Ipv4Packet, _c: &ClientInfo) {}
fn ipv4_drop(&self, _p: &Ipv4Packet, _c: &ClientInfo) {}
fn ipv4_send(&self, _p: &MutableIpv4Packet, _c: &ClientInfo) {}
/* IPv6 */
fn ipv6_enabled(&self) -> bool {
true
}
fn ipv6_recv(&self, _p: &Ipv6Packet, _c: &ClientInfo) {}
fn ipv6_drop(&self, _p: &Ipv6Packet, _c: &ClientInfo) {}
fn ipv6_send(&self, _p: &MutableIpv6Packet, _c: &ClientInfo) {}
/* ICMPv4 */
fn icmpv4_enabled(&self) -> bool {
true
}
fn icmpv4_recv(&self, _p: &IcmpPacket, _c: &ClientInfo) {}
fn icmpv4_drop(&self, _p: &IcmpPacket, _c: &ClientInfo) {}
fn icmpv4_send(&self, _p: &MutableIcmpPacket, _c: &ClientInfo) {}
/* ICMPv6 */
fn icmpv6_enabled(&self) -> bool {
true
}
fn icmpv6_recv(&self, _p: &Icmpv6Packet, _c: &ClientInfo) {}
fn icmpv6_drop(&self, _p: &Icmpv6Packet, _c: &ClientInfo) {}
fn icmpv6_send(&self, _p: &MutableIcmpv6Packet, _c: &ClientInfo) {}
/* TCP */
fn tcp_enabled(&self) -> bool {
true
}
fn tcp_recv(&self, _p: &TcpPacket, _c: &ClientInfo) {}
fn tcp_drop(&self, _p: &TcpPacket, _c: &ClientInfo) {}
fn tcp_send(&self, _p: &MutableTcpPacket, _c: &ClientInfo) {}
/* UDP */
fn udp_enabled(&self) -> bool {
true
}
fn udp_recv(&self, _p: &UdpPacket, _c: &ClientInfo) {}
fn udp_drop(&self, _p: &UdpPacket, _c: &ClientInfo) {}
fn udp_send(&self, _p: &MutableUdpPacket, _c: &ClientInfo) {}
}

View file

@ -35,12 +35,14 @@ use pnet::{
util::MacAddr,
};
use crate::logger::{ConsoleLogger, MetaLogger};
use crate::utils::IpAddrParser;
mod client;
mod layer_2;
mod layer_3;
mod layer_4;
mod logger;
mod proto;
mod smack;
mod synackcookie;
@ -55,6 +57,8 @@ pub struct Masscanned<'a> {
/* iface is an Option to make tests easier */
pub iface: Option<&'a NetworkInterface>,
pub ip_addresses: Option<&'a HashSet<IpAddr>>,
/* loggers */
pub log: MetaLogger,
}
/* Get the L2 network interface from its name */
@ -184,14 +188,17 @@ fn main() {
} else {
None
};
let masscanned = Masscanned {
let mut masscanned = Masscanned {
synack_key: [0, 0],
mac,
iface: Some(&iface),
ip_addresses,
log: MetaLogger::new(),
};
info!("interface......{}", masscanned.iface.unwrap().name);
info!("mac address....{}", masscanned.mac);
masscanned.log.add(Box::new(ConsoleLogger::new()));
masscanned.log.init();
let (mut tx, mut rx) = get_channel(masscanned.iface.unwrap());
loop {
/* check if network interface is still up */

View file

@ -165,6 +165,8 @@ mod tests {
use pnet::util::MacAddr;
use crate::logger::MetaLogger;
#[test]
fn test_proto_dispatch_stun() {
let mut client_info = ClientInfo::new();
@ -180,6 +182,7 @@ mod tests {
mac: MacAddr::from_str("00:11:22:33:44:55").expect("error parsing MAC address"),
iface: None,
ip_addresses: Some(&ips),
log: MetaLogger::new(),
};
/***** TEST STUN - MAGIC *****/
/* test payload is:
@ -239,6 +242,7 @@ mod tests {
mac: MacAddr::from_str("00:11:22:33:44:55").expect("error parsing MAC address"),
iface: None,
ip_addresses: Some(&ips),
log: MetaLogger::new(),
};
/***** TEST SSH *****/
let payloads = [
@ -278,6 +282,7 @@ mod tests {
mac: MacAddr::from_str("00:11:22:33:44:55").expect("error parsing MAC address"),
iface: None,
ip_addresses: Some(&ips),
log: MetaLogger::new(),
};
/***** TEST GHOST *****/
let payloads = [
@ -310,6 +315,7 @@ mod tests {
mac: MacAddr::from_str("00:11:22:33:44:55").expect("error parsing MAC address"),
iface: None,
ip_addresses: Some(&ips),
log: MetaLogger::new(),
};
/***** TEST COMPLETE REQUEST *****/
let payload = b"GET / HTTP/1.1\r\n\r\n";

View file

@ -413,6 +413,8 @@ mod tests {
use pnet::util::MacAddr;
use crate::logger::MetaLogger;
#[test]
fn test_proto_stun_ipv4() {
/* test payload is:
@ -439,6 +441,7 @@ mod tests {
mac: MacAddr::from_str("00:11:22:33:44:55").expect("error parsing MAC address"),
iface: None,
ip_addresses: Some(&ips),
log: MetaLogger::new(),
};
let payload_resp = if let Some(r) = repl(payload, &masscanned, &mut client_info) {
r
@ -498,6 +501,7 @@ mod tests {
mac: MacAddr::from_str("00:11:22:33:44:55").expect("error parsing MAC address"),
iface: None,
ip_addresses: Some(&ips),
log: MetaLogger::new(),
};
client_info.ip.src = Some(IpAddr::V6(test_ip_addr));
client_info.ip.dst = Some(IpAddr::V6(masscanned_ip_addr));
@ -549,6 +553,7 @@ mod tests {
mac: MacAddr::from_str("00:11:22:33:44:55").expect("error parsing MAC address"),
iface: None,
ip_addresses: Some(&ips),
log: MetaLogger::new(),
};
client_info.ip.src = Some(IpAddr::V4(test_ip_addr));
client_info.ip.dst = Some(IpAddr::V4(masscanned_ip_addr));
@ -598,6 +603,7 @@ mod tests {
mac: MacAddr::from_str("00:11:22:33:44:55").expect("error parsing MAC address"),
iface: None,
ip_addresses: Some(&ips),
log: MetaLogger::new(),
};
client_info.ip.src = Some(IpAddr::V4(test_ip_addr));
client_info.ip.dst = Some(IpAddr::V4(masscanned_ip_addr));