restructured file architecture

This commit is contained in:
Giuliano Bellini s294739 2022-10-26 19:03:39 +02:00
parent c7667b5e0a
commit a21dedf034
5 changed files with 309 additions and 236 deletions

View file

@ -1,14 +1,17 @@
use std::os::macos::raw::stat;
use crate::{get_app_count_string, InfoTraffic, Sniffer, Status};
use iced::{ Svg, alignment, button, scrollable, executor, Alignment, Application, Button, Column, Command, Container, Element, Length, Row, Settings, Subscription, Text, Color, Radio, Scrollable, PickList, pick_list, Font, widget};
use std::sync::{Arc, Mutex, Condvar};
use std::time::Duration;
use pcap::Device;
use crate::info_address_port_pair::{AppProtocol, TransProtocol};
use crate::style::{Mode, FontSizeBody, FontSizeSubtitle, FontSizeTitle, icon_sun_moon};
use crate::gui_initial_page::initial_page;
use crate::gui_run_page::run_page;
use crate::style::{Mode, FONT_SIZE_BODY, FONT_SIZE_SUBTITLE, FONT_SIZE_TITLE, icon_sun_moon};
#[derive(Debug, Clone)]
pub(crate) enum Message {
pub enum Message {
Tick,
AdapterSelection(String),
IpVersionSelection(String),
@ -33,10 +36,12 @@ impl Application for Sniffer {
)
}
fn title(&self) -> String {
String::from("Sniffnet")
}
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::Tick => {}
@ -83,10 +88,10 @@ impl Application for Sniffer {
};
}
}
Command::none()
}
fn subscription(&self) -> Subscription<Message> {
match self.status_pair.0.lock().unwrap() {
_ => {
@ -95,227 +100,32 @@ impl Application for Sniffer {
}
}
fn view(&mut self) -> Element<Message> {
let button_start = Button::new(
&mut self.start,
Text::new("Run!").vertical_alignment(alignment::Vertical::Center).horizontal_alignment(alignment::Horizontal::Center),
)
.padding(10)
.height(Length::Units(80))
.width(Length::Units(160))
.style(self.style)
.on_press(Message::Start);
let status = *self.status_pair.0.lock().unwrap();
let mode = self.style;
let button_reset = Button::new(
&mut self.reset,
Text::new("Reset").horizontal_alignment(alignment::Horizontal::Center),
)
.padding(10)
.height(Length::Units(40))
.width(Length::Units(80))
.style(self.style)
.on_press(Message::Reset);
let button_style = Button::new(
&mut self.mode,
// icon(match self.style {
// Mode::Night => {font_awesome::SUN}
// Mode::Day => {font_awesome::MOON}
icon_sun_moon(self.style)
.horizontal_alignment(alignment::Horizontal::Center),
)
.padding(10)
.height(Length::Units(40))
.width(Length::Units(100))
.style(self.style)
.on_press(Message::Style);
let button_report = Button::new(
&mut self.report,
Text::new("Open network traffic report").horizontal_alignment(alignment::Horizontal::Center),
)
.padding(10)
.height(Length::Units(40))
.width(Length::Units(270))
.style(self.style)
.on_press(Message::OpenReport);
let logo = Svg::from_path("./resources/sniffnet_logo.svg", );
let header = Row::new()
.height(Length::FillPortion(3))
.align_items(Alignment::Center)
.push(Column::new().width(Length::FillPortion(1)))
.push(Column::new().width(Length::FillPortion(6)).push(logo))
.push(Row::new().width(Length::FillPortion(1)).align_items(Alignment::Center).push(button_style));
let mut dev_str_list = vec![];
for dev in Device::list().expect("Error retrieving device list\r\n") {
let mut dev_str = String::new();
match dev.desc {
None => {
dev_str.push_str(&format!("{}", dev.name));
}
Some(description) => {
dev_str.push_str(&format!("{}\n{}", dev.name, description));
}
let body = match status {
Status::Init => {
initial_page(self)
}
let num_addresses = dev.addresses.len();
match num_addresses {
0 => {},
1 => {dev_str.push_str("\nAddress:");},
_ => {dev_str.push_str("\nAddresses:");}
Status::Running => {
run_page(self)
}
Status::Pause => {Column::new()}
Status::Stop => {Column::new()}
};
let mut x = 0;
for addr in dev.addresses {
x += 1;
let address_string = addr.addr.to_string();
// if x == num_addresses {
// dev_str.push_str(&format!("{}", address_string));
// }
//else {
dev_str.push_str(&format!("\n {}", address_string));
//}
}
dev_str_list.push((dev.name, dev_str));
}
let col_adapter = Column::new()
.padding(20)
.spacing(10)
.height(Length::Fill)
.width(Length::FillPortion(4))
.push(Text::new("Select network adapter to inspect").size(FontSizeTitle))
.push(dev_str_list.iter().fold(
Scrollable::new(&mut self.scroll).style(self.style).padding(10).spacing(20).height(Length::FillPortion(8)),
|scroll, adapter| {
scroll.push(Radio::new(
&adapter.0,
&adapter.1,
Some(&self.device.clone().lock().unwrap().name),
|name| Message::AdapterSelection(name.to_string()),
).size(15).style(self.style))
},
));
let col_space = Column::new()
.padding(20)
.spacing(10)
.width(Length::FillPortion(1));
let filtri = self.filters.lock().unwrap();
let ip_active = &*filtri.ip;
let col_ip_radio = Column::new().spacing(10)
.push(Text::new("IP version").size(FontSizeSubtitle))
.push(Radio::new(
"ipv4",
"IPv4",
Some(ip_active),
|version| Message::IpVersionSelection(version.to_string())
).size(15).style(self.style))
.push(Radio::new(
"ipv6",
"IPv6",
Some(ip_active),
|version| Message::IpVersionSelection(version.to_string())
).size(15).style(self.style))
.push(Radio::new(
"no filter",
"both",
Some(ip_active),
|version| Message::IpVersionSelection(version.to_string())
).size(15).style(self.style));
let col_ip = Column::new()
.spacing(10)
.width(Length::FillPortion(1))
.push(col_ip_radio);
let transport_active = filtri.transport;
let col_transport_radio = Column::new().spacing(10)
.push(Text::new("Transport protocol").size(FontSizeSubtitle))
.push(Radio::new(
TransProtocol::TCP,
"TCP",
Some(transport_active),
|protocol| Message::TransportProtocolSelection(protocol)
).size(15).style(self.style))
.push(Radio::new(
TransProtocol::UDP,
"UDP",
Some(transport_active),
|protocol| Message::TransportProtocolSelection(protocol)
).size(15).style(self.style))
.push(Radio::new(
TransProtocol::Other,
"both",
Some(transport_active),
|protocol| Message::TransportProtocolSelection(protocol)
).size(15).style(self.style));
let col_transport = Column::new()
.align_items(Alignment::Center)
.spacing(10)
.width(Length::FillPortion(2))
.push(col_transport_radio)
.push(Row::new().height(Length::FillPortion(2)))
.push(button_start)
.push(Row::new().height(Length::FillPortion(1)));
let app_active = filtri.application;
let picklist_app = PickList::new(
&mut self.app,
&AppProtocol::ALL[..],
Some(app_active),
|protocol| Message::AppProtocolSelection(protocol),
Container::new(
Column::new()
.push(body)
)
.placeholder("Select application protocol")
.style(self.style);
let mut col_app = Column::new()
.width(Length::FillPortion(2))
.spacing(10)
.push(iced::Text::new("Application protocol").size(FontSizeSubtitle))
.push(picklist_app);
let filters = Column::new().width(Length::FillPortion(6)).padding(20).spacing(20)
.push(Row::new().push(Text::new("Select filters to be applied on network traffic").size(FontSizeTitle)))
.push(Row::new().height(Length::FillPortion(3)).push(col_ip).push(col_transport).push(col_app));
let sniffer = self.info_traffic.lock().unwrap();
let mut col_packets = Column::new()
.width(Length::FillPortion(1))
.align_items(Alignment::Center)
.spacing(20)
.push(iced::Text::new(std::env::current_dir().unwrap().to_str().unwrap()))
.push(iced::Text::new(sniffer.all_packets.to_string()));
if sniffer.tot_received_packets + sniffer.tot_sent_packets > 0 {
col_packets = col_packets
.push(iced::Text::new("Packets count per application protocol"))
.push(iced::Text::new(get_app_count_string(sniffer.app_protocols.clone(), sniffer.tot_received_packets + sniffer.tot_sent_packets)));
}
col_packets = col_packets.push(button_reset).push(button_report);
let mut body = Row::new().height(Length::FillPortion(9));
match *self.status_pair.0.lock().unwrap() {
Status::Init => {body = body
.push(col_adapter)
.push(col_space)
.push(filters);}
Status::Running => {body = body
.push(col_packets);}
Status::Pause => {}
Status::Stop => {}
}
Container::new(Column::new().push(header).push(body))
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y()
.style(self.style)
.style(mode)
.into()
}

178
src/gui_initial_page.rs Normal file
View file

@ -0,0 +1,178 @@
use iced::{alignment, Alignment, Button, Column, Length, PickList, Radio, Renderer, Row, Scrollable, Svg, Text};
use pcap::Device;
use crate::app::Message;
use crate::{AppProtocol, FONT_SIZE_SUBTITLE, FONT_SIZE_TITLE, icon_sun_moon, Sniffer, TransProtocol};
pub fn initial_page(sniffer: &mut Sniffer) -> Column<Message> {
let logo = Svg::from_path("./resources/sniffnet_logo.svg");
let button_style = Button::new(
&mut sniffer.mode,
icon_sun_moon(sniffer.style)
.horizontal_alignment(alignment::Horizontal::Center),
)
.padding(10)
.height(Length::Units(40))
.width(Length::Units(100))
.style(sniffer.style)
.on_press(Message::Style);
let header = Row::new()
.height(Length::FillPortion(3))
.align_items(Alignment::Center)
.push(Column::new().width(Length::FillPortion(1)))
.push(Column::new().width(Length::FillPortion(6)).push(logo))
.push(Row::new().width(Length::FillPortion(1)).align_items(Alignment::Center).push(button_style));
let button_start = Button::new(
&mut sniffer.start,
Text::new("Run!").vertical_alignment(alignment::Vertical::Center).horizontal_alignment(alignment::Horizontal::Center),
)
.padding(10)
.height(Length::Units(80))
.width(Length::Units(160))
.style(sniffer.style)
.on_press(Message::Start);
let mut dev_str_list = vec![];
for dev in Device::list().expect("Error retrieving device list\r\n") {
let mut dev_str = String::new();
match dev.desc {
None => {
dev_str.push_str(&format!("{}", dev.name));
}
Some(description) => {
dev_str.push_str(&format!("{}\n{}", dev.name, description));
}
}
let num_addresses = dev.addresses.len();
match num_addresses {
0 => {},
1 => {dev_str.push_str("\nAddress:");},
_ => {dev_str.push_str("\nAddresses:");}
}
let mut x = 0;
for addr in dev.addresses {
x += 1;
let address_string = addr.addr.to_string();
// if x == num_addresses {
// dev_str.push_str(&format!("{}", address_string));
// }
//else {
dev_str.push_str(&format!("\n {}", address_string));
//}
}
dev_str_list.push((dev.name, dev_str));
}
let col_adapter = Column::new()
.padding(20)
.spacing(10)
.height(Length::Fill)
.width(Length::FillPortion(4))
.push(Text::new("Select network adapter to inspect").size(FONT_SIZE_TITLE))
.push(dev_str_list.iter().fold(
Scrollable::new(&mut sniffer.scroll).style(sniffer.style).padding(10).spacing(20).height(Length::FillPortion(8)),
|scroll, adapter| {
scroll.push(Radio::new(
&adapter.0,
&adapter.1,
Some(&sniffer.device.clone().lock().unwrap().name),
|name| Message::AdapterSelection(name.to_string()),
).size(15).style(sniffer.style))
},
));
let col_space = Column::new()
.padding(20)
.spacing(10)
.width(Length::FillPortion(1));
let filtri = sniffer.filters.lock().unwrap();
let ip_active = &*filtri.ip;
let col_ip_radio = Column::new().spacing(10)
.push(Text::new("IP version").size(FONT_SIZE_SUBTITLE))
.push(Radio::new(
"ipv4",
"IPv4",
Some(ip_active),
|version| Message::IpVersionSelection(version.to_string())
).size(15).style(sniffer.style))
.push(Radio::new(
"ipv6",
"IPv6",
Some(ip_active),
|version| Message::IpVersionSelection(version.to_string())
).size(15).style(sniffer.style))
.push(Radio::new(
"no filter",
"both",
Some(ip_active),
|version| Message::IpVersionSelection(version.to_string())
).size(15).style(sniffer.style));
let col_ip = Column::new()
.spacing(10)
.width(Length::FillPortion(1))
.push(col_ip_radio);
let transport_active = filtri.transport;
let col_transport_radio = Column::new().spacing(10)
.push(Text::new("Transport protocol").size(FONT_SIZE_SUBTITLE))
.push(Radio::new(
TransProtocol::TCP,
"TCP",
Some(transport_active),
|protocol| Message::TransportProtocolSelection(protocol)
).size(15).style(sniffer.style))
.push(Radio::new(
TransProtocol::UDP,
"UDP",
Some(transport_active),
|protocol| Message::TransportProtocolSelection(protocol)
).size(15).style(sniffer.style))
.push(Radio::new(
TransProtocol::Other,
"both",
Some(transport_active),
|protocol| Message::TransportProtocolSelection(protocol)
).size(15).style(sniffer.style));
let col_transport = Column::new()
.align_items(Alignment::Center)
.spacing(10)
.width(Length::FillPortion(2))
.push(col_transport_radio)
.push(Row::new().height(Length::FillPortion(2)))
.push(button_start)
.push(Row::new().height(Length::FillPortion(1)));
let app_active = filtri.application;
let picklist_app = PickList::new(
&mut sniffer.app,
&AppProtocol::ALL[..],
Some(app_active),
|protocol| Message::AppProtocolSelection(protocol),
)
.placeholder("Select application protocol")
.style(sniffer.style);
let mut col_app = Column::new()
.width(Length::FillPortion(2))
.spacing(10)
.push(iced::Text::new("Application protocol").size(FONT_SIZE_SUBTITLE))
.push(picklist_app);
let filters = Column::new().width(Length::FillPortion(6)).padding(20).spacing(20)
.push(Row::new().push(Text::new("Select filters to be applied on network traffic").size(FONT_SIZE_TITLE)))
.push(Row::new().height(Length::FillPortion(3)).push(col_ip).push(col_transport).push(col_app));
let body = Row::new().height(Length::FillPortion(9))
.push(col_adapter)
.push(col_space)
.push(filters);
Column::new()
.push(header)
.push(body)
}

69
src/gui_run_page.rs Normal file
View file

@ -0,0 +1,69 @@
use iced::{alignment, Alignment, Button, Column, Length, Row, Svg, Text};
use crate::app::Message;
use crate::{get_app_count_string, icon_sun_moon, Sniffer};
pub fn run_page(sniffer: &mut Sniffer) -> Column<Message> {
let logo = Svg::from_path("./resources/sniffnet_logo.svg");
let button_style = Button::new(
&mut sniffer.mode,
icon_sun_moon(sniffer.style)
.horizontal_alignment(alignment::Horizontal::Center),
)
.padding(10)
.height(Length::Units(40))
.width(Length::Units(100))
.style(sniffer.style)
.on_press(Message::Style);
let header = Row::new()
.height(Length::FillPortion(3))
.align_items(Alignment::Center)
.push(Column::new().width(Length::FillPortion(1)))
.push(Column::new().width(Length::FillPortion(6)).push(logo))
.push(Row::new().width(Length::FillPortion(1)).align_items(Alignment::Center).push(button_style));
let button_reset = Button::new(
&mut sniffer.reset,
Text::new("Reset").horizontal_alignment(alignment::Horizontal::Center),
)
.padding(10)
.height(Length::Units(40))
.width(Length::Units(80))
.style(sniffer.style)
.on_press(Message::Reset);
let button_report = Button::new(
&mut sniffer.report,
Text::new("Open network traffic report").horizontal_alignment(alignment::Horizontal::Center),
)
.padding(10)
.height(Length::Units(40))
.width(Length::Units(270))
.style(sniffer.style)
.on_press(Message::OpenReport);
let sniffer_lock = sniffer.info_traffic.lock().unwrap();
let mut col_packets = Column::new()
.width(Length::FillPortion(1))
.align_items(Alignment::Center)
.spacing(20)
.push(iced::Text::new(std::env::current_dir().unwrap().to_str().unwrap()))
.push(iced::Text::new(sniffer_lock.all_packets.to_string()));
if sniffer_lock.tot_received_packets + sniffer_lock.tot_sent_packets > 0 {
col_packets = col_packets
.push(iced::Text::new("Packets count per application protocol"))
.push(iced::Text::new(get_app_count_string(sniffer_lock.app_protocols.clone(), sniffer_lock.tot_received_packets + sniffer_lock.tot_sent_packets)));
}
col_packets = col_packets.push(button_reset).push(button_report);
let body = Row::new().height(Length::FillPortion(9))
.push(col_packets);
Column::new()
.push(header)
.push(body)
}

View file

@ -6,6 +6,8 @@ mod thread_write_report_functions;
mod info_traffic;
mod style;
mod app;
mod gui_initial_page;
mod gui_run_page;
use std::fs::File;
use std::io::prelude::*;
@ -34,7 +36,7 @@ use iced::futures::FutureExt;
use iced_style::pane_grid::Line;
use indexmap::IndexMap;
use crate::info_traffic::InfoTraffic;
use style::{Mode, FontSizeBody, FontSizeSubtitle, FontSizeTitle, icon_sun_moon};
use style::{Mode, FONT_SIZE_BODY, FONT_SIZE_SUBTITLE, FONT_SIZE_TITLE, icon_sun_moon};
pub struct Filters {
@ -44,7 +46,7 @@ pub struct Filters {
}
struct Sniffer {
pub struct Sniffer {
info_traffic: Arc<Mutex<InfoTraffic>>,
device: Arc<Mutex<Device>>,
filters: Arc<Mutex<Filters>>,
@ -60,7 +62,7 @@ struct Sniffer {
/// This enum represents the sniffing process status.
#[derive(PartialEq, Eq)]
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum Status {
/// Sniffnet has just been launched/restarted
Init,
@ -129,7 +131,7 @@ pub fn main() {
style: Mode::Night
},
default_font: Some(include_bytes!("../fonts/CourierPrimeSans.ttf")),
default_text_size: FontSizeBody,
default_text_size: FONT_SIZE_BODY,
text_multithreading: false,
antialiasing: false,

View file

@ -3,19 +3,44 @@ use iced::container::{Style, StyleSheet};
use iced_style::scrollable::{Scrollbar, Scroller};
use crate::app::Message;
pub const ICONS: Font = Font::External {
name: "Icons",
bytes: include_bytes!("../fonts/icons.ttf"),
};
pub const COURIER_PRIME: Font = Font::External {
name: "CourierPrimeSans",
bytes: include_bytes!("../fonts/CourierPrimeSans.ttf"),
};
pub const COURIER_PRIME_ITALIC: Font = Font::External {
name: "CourierPrimeSans",
bytes: include_bytes!("../fonts/CourierPrimeSansItalic.ttf"),
};
pub const FONT_SIZE_BODY: u16 = 16;
pub const FONT_SIZE_SUBTITLE: u16 = 18;
pub const FONT_SIZE_TITLE: u16 = 22;
#[derive(Copy, Eq, PartialEq)]
pub enum Mode {
Night,
Day
}
impl Clone for Mode {
fn clone(&self) -> Self {
*self
}
}
impl StyleSheet for Mode {
fn style(&self) -> Style {
Style {
text_color: match self {
@ -31,9 +56,12 @@ impl StyleSheet for Mode {
border_color: Default::default()
}
}
}
impl pick_list::StyleSheet for Mode {
fn menu(&self) -> iced_style::menu::Style {
iced_style::menu::Style {
text_color: match self {
@ -103,6 +131,7 @@ impl pick_list::StyleSheet for Mode {
}
}
impl button::StyleSheet for Mode {
fn hovered(&self) -> iced_style::button::Style {
@ -181,8 +210,10 @@ impl iced_style::radio::StyleSheet for Mode {
text_color: None
}
}
}
impl iced_style::scrollable::StyleSheet for Mode {
fn active(&self) -> Scrollbar {
@ -229,10 +260,6 @@ impl iced_style::scrollable::StyleSheet for Mode {
}
pub const ICONS: Font = Font::External {
name: "Icons",
bytes: include_bytes!("../fonts/icons.ttf"),
};
pub fn icon(unicode: char) -> Text {
Text::new(unicode.to_string())
@ -242,6 +269,7 @@ pub fn icon(unicode: char) -> Text {
.size(20)
}
pub fn icon_sun_moon(style: Mode) -> Text {
match style {
Mode::Night => {
@ -259,18 +287,4 @@ pub fn icon_sun_moon(style: Mode) -> Text {
.size(20)
}
}
}
pub const CourierPrime: Font = Font::External {
name: "CourierPrimeSans",
bytes: include_bytes!("../fonts/CourierPrimeSans.ttf"),
};
pub const CourierPrimeItalic: Font = Font::External {
name: "CourierPrimeSans",
bytes: include_bytes!("../fonts/CourierPrimeSansItalic.ttf"),
};
pub const FontSizeBody: u16 = 16;
pub const FontSizeSubtitle: u16 = 18;
pub const FontSizeTitle: u16 = 22;
}