From 2f3080a06b1d957d3e2a122a131a799512f81741 Mon Sep 17 00:00:00 2001 From: Olivier Blin Date: Wed, 24 Aug 2005 18:07:47 +0000 Subject: - net_applet: stop icon blink when an Interactive Firewall alert isn't processed - drakids: add log tab - drakids: allow to clear logs - net_applet: stop icon blinking when drakids is run or clear logs - net_applet: present drakids window on click on menu if drakids is already run - factorize packet reading to network::ifw::attack_to_hash --- perl-install/network/ifw.pm | 43 ++++++++++++- perl-install/standalone/drakids | 121 ++++++++++++++++++++++++++----------- perl-install/standalone/net_applet | 65 ++++++++++++-------- 3 files changed, 169 insertions(+), 60 deletions(-) diff --git a/perl-install/network/ifw.pm b/perl-install/network/ifw.pm index 5be73cc59..8550ddcc5 100644 --- a/perl-install/network/ifw.pm +++ b/perl-install/network/ifw.pm @@ -2,6 +2,7 @@ package network::ifw; use dbus_object; use Socket; +use common; our @ISA = qw(dbus_object); @@ -58,8 +59,9 @@ sub set_interactive { } sub get_reports { - my ($o) = @_; - $o->call_method('GetReports'); + my ($o, $o_include_processed) = @_; + $o->call_method('GetReports', + Net::DBus::Binding::Value->new(&Net::DBus::Binding::Message::TYPE_UINT32, to_bool($o_include_processed))); } sub get_blacklist { @@ -72,6 +74,21 @@ sub get_whitelist { $o->call_method('GetWhitelist'); } +sub clear_processed_reports { + my ($o) = @_; + $o->call_method('ClearProcessedReports'); +} + +sub send_alert_ack { + my ($o) = @_; + $o->call_method('SendAlertAck'); +} + +sub send_manage_request { + my ($o) = @_; + $o->call_method('SendManageRequest'); +} + sub format_date { my ($timestamp) = @_; require c; @@ -106,4 +123,26 @@ sub resolve_address { $hostname || $ip_addr; } +sub attack_to_hash { + my ($args) = @_; + my $attack = { mapn { $_[0] => $_[1] } [ 'timestamp', 'indev', 'prefix', 'sensor', 'protocol', 'addr', 'port', 'icmp_type', 'seq' ], $args }; + $attack->{port} = unpack('S', pack('n', $attack->{port})); + $attack->{date} = format_date($attack->{timestamp}); + $attack->{ip_addr} = get_ip_address($attack->{addr}); + $attack->{hostname} = resolve_address($attack->{ip_addr}); + $attack->{protocol} = get_protocol($attack->{protocol}); + $attack->{service} = get_service($attack->{port}); + $attack->{type} = + $attack->{prefix} eq 'SCAN' ? N("Port scanning") + : $attack->{prefix} eq 'SERV' ? N("Service attack") + : $attack->{prefix} eq 'PASS' ? N("Password cracking") + : undef; + $attack->{msg} = + $attack->{prefix} eq "SCAN" ? N("A port scanning attack has been attempted by %s.", $attack->{hostname}) + : $attack->{prefix} eq "SERV" ? N("The %s service has been attacked by %s.", $attack->{service}, $attack->{hostname}) + : $attack->{prefix} eq "PASS" ? N("A password cracking attack has been attempted by %s.", $attack->{hostname}) + : undef; + $attack; +} + 1; diff --git a/perl-install/standalone/drakids b/perl-install/standalone/drakids index 52763432e..ee8f6733c 100644 --- a/perl-install/standalone/drakids +++ b/perl-install/standalone/drakids @@ -16,23 +16,11 @@ use Gtk2::SimpleList; use ugtk2 qw(:create :helpers :wrappers); -my $blacklist = Gtk2::SimpleList->new(addr => 'hidden', - timestamp => 'hidden', - N("Date") => 'text', - N("Attacker") => 'text', - N("Attack type") => 'text', - N("Service") => 'text', - N("Network interface") => 'text', - N("Protocol") => 'text', - ); +my $loglist = create_attack_list(); +$loglist->get_selection->set_mode('single'); + +my $blacklist = create_attack_list(); $blacklist->get_selection->set_mode('multiple'); -$blacklist->set_headers_clickable(1); -foreach (0, 1, 2) { - $blacklist->get_column($_)->signal_connect('clicked', \&sort_by_column, $blacklist->get_model); - #- sort on timestamp if Date column is clicked - #- sort columns include hidden columns while list columns don't - $blacklist->get_column($_)->set_sort_column_id($_ == 0 ? 1 : $_ + 2); -} my $whitelist = Gtk2::SimpleList->new(addr => 'hidden', N("Allowed addresses") => 'text', @@ -42,10 +30,15 @@ $whitelist->set_headers_clickable(1); $whitelist->get_column(0)->signal_connect('clicked', \&sort_by_column, $whitelist->get_model); $whitelist->get_column(0)->set_sort_column_id(0); +my $w = ugtk2->new(N("Interactive Firewall"), + icon => "/usr/lib/libDrakX/icons/drakfirewall.png"); + my $ifw = network::ifw->new(dbus_object::system_bus(), sub { my ($_con, $msg) = @_; my $member = $msg->get_member; - if ($member eq 'Blacklist') { + if ($member eq 'Attack') { + handle_log($msg->get_args_list); + } elsif ($member eq 'Blacklist') { handle_blacklist($msg->get_args_list); } elsif ($member eq 'Whitelist') { handle_whitelist($msg->get_args_list); @@ -53,14 +46,22 @@ my $ifw = network::ifw->new(dbus_object::system_bus(), sub { clear_lists(); } elsif ($member eq 'Init') { handle_init(); + } elsif ($member eq 'ManageRequest') { + $w->{window}->present; } }); init_lists(); -$ugtk2::wm_icon = "/usr/lib/libDrakX/icons/drakfirewall.png"; -my $w = ugtk2->new(N("Interactive Firewall")); gtkadd($w->{window}, gtknew('Notebook', children => [ + gtknew('Label', text => N("Log")), + gtknew('VBox', spacing => 5, children => [ + 1, gtknew('ScrolledWindow', width => 600, height => 400, child => $loglist), + 0, gtknew('HButtonBox', layout => 'edge', children_loose => [ + gtknew('Button', text => N("Clear logs"), clicked => \&clear_log), + gtknew('Button', text => N("Quit"), clicked => sub { Gtk2->main_quit }) + ]), + ]), gtknew('Label', text => N("Blacklist")), gtknew('VBox', spacing => 5, children => [ 1, gtknew('ScrolledWindow', width => 600, height => 400, child => $blacklist), @@ -108,6 +109,7 @@ sub init_blacklist() { my @packets = $ifw->get_blacklist; while (my @blacklist = splice(@packets, 0, 8)) { handle_blacklist(@blacklist); + handle_log(@blacklist); } } @@ -116,20 +118,7 @@ sub clear_blacklist() { } sub handle_blacklist { - my ($timestamp, $indev, $prefix, $_sensor, $protocol, $addr, $port, $_icmp_type) = @_; - push @{$blacklist->{data}}, [ - $addr, - $timestamp, - network::ifw::format_date($timestamp), - network::ifw::resolve_address(network::ifw::get_ip_address($addr)), - $prefix eq 'SCAN' ? N("Port scanning") : - $prefix eq 'SERV' ? N("Service attack") : - $prefix eq 'PASS' ? N("Password cracking") : - '', - network::ifw::get_service($port), - $indev, - network::ifw::get_protocol($protocol), - ]; + attack_list_add($blacklist, network::ifw::attack_to_hash(\@_)); } sub get_selected_blacklist() { @@ -183,13 +172,77 @@ sub unwhitelist { sub init_lists() { eval { + init_loglist(); init_blacklist(); init_whitelist(); }; - $@ and err_dialog(N("Interactive Firewall"), N("Unable to contact daemon")); + $@ and print "$@\n", err_dialog(N("Interactive Firewall"), N("Unable to contact daemon")); } sub clear_lists() { + clear_loglist(); clear_blacklist(); clear_whitelist(); } + +sub create_attack_list() { + my $attacklist = Gtk2::SimpleList->new(addr => 'hidden', + timestamp => 'hidden', + N("Date") => 'text', + N("Attacker") => 'text', + N("Attack type") => 'text', + N("Service") => 'text', + N("Network interface") => 'text', + N("Protocol") => 'text', + ); + $attacklist->set_headers_clickable(1); + foreach (0, 1, 2) { + $attacklist->get_column($_)->signal_connect('clicked', \&sort_by_column, $attacklist->get_model); + #- sort on timestamp if Date column is clicked + #- sort columns include hidden columns while list columns don't + $attacklist->get_column($_)->set_sort_column_id($_ == 0 ? 1 : $_ + 2); + } + $attacklist; +} + +sub attack_list_add { + my ($attacklist, $attack) = @_; + push @{$attacklist->{data}}, [ + $attack->{addr}, + $attack->{timestamp}, + $attack->{date}, + $attack->{hostname}, + $attack->{type}, + $attack->{service}, + $attack->{indev}, + $attack->{protocol}, + ]; +} + +#- may throw an exception +sub init_loglist() { + my @packets = $ifw->get_reports(1); + while (my @attack = splice(@packets, 0, 10)) { + handle_log(@attack); + } +} + +sub clear_loglist() { + @{$loglist->{data}} = (); +} + +sub handle_log { + attack_list_add($loglist, network::ifw::attack_to_hash(\@_)); +} + +sub clear_log { + eval { + $ifw->clear_processed_reports; + $ifw->send_alert_ack; + }; + if (!$@) { + clear_loglist(); + } else { + err_dialog(N("Interactive Firewall"), N("Unable to contact daemon")); + } +} diff --git a/perl-install/standalone/net_applet b/perl-install/standalone/net_applet index 0cfb4a978..12437f921 100644 --- a/perl-install/standalone/net_applet +++ b/perl-install/standalone/net_applet @@ -33,6 +33,8 @@ my $watched_interface; my %pixbufs = ( + firewall => gtkcreate_pixbuf('/usr/lib/libDrakX/icons/drakfirewall.png'), + firewall_icon => gtkcreate_pixbuf('/usr/lib/libDrakX/icons/drakfirewall.png')->scale_simple(24, 24, 'hyper'), state => { map { $_ => gtkcreate_pixbuf($_) } qw(connected disconnected) }, link_level => { map { my $f = "./wifi-$_.png"; @@ -94,7 +96,7 @@ $eventbox->signal_connect(button_press_event => sub { $icon->show_all; -my ($dbus, $monitor, $ifw, $interactive_cb, @attacks_queue); +my ($dbus, $monitor, $ifw, $interactive_cb, @attacks_queue, $ifw_alert); eval { $dbus = dbus_object::system_bus() }; eval { $monitor = network::monitor->new($dbus) } if $dbus; eval { @@ -106,6 +108,8 @@ eval { } elsif ($member eq 'Init') { $ifw->attach_object; checkNetworkForce(); + } elsif ($member eq 'AlertAck') { + $ifw_alert = 0; } }); } if $dbus; @@ -114,11 +118,13 @@ $bubble = Gtk2::NotificationBubble->new; $bubble->attach($icon); $bubble->signal_connect(timeout => sub { #- on timeout, apply default policy - exists $attacks_queue[0]{handled} or set_blacklist_verdict($attacks_queue[0]{seq}, undef); + set_blacklist_verdict($attacks_queue[0]{seq}, undef); }); $bubble->signal_connect(clicked => sub { - $attacks_queue[0]{handled} = 1; $bubble->hide; + $ifw_alert = 0; + eval { $ifw->send_alert_ack }; + update_tray_icon(); ask_attack_verdict($attacks_queue[0]); }); @@ -157,7 +163,12 @@ sub run_drakroam() { run_program::raw({ detach => 1 }, '/usr/sbin/drakroam') unless is_running('drakroam'); } sub run_drakids() { - run_program::raw({ detach => 1 }, '/usr/sbin/drakids') unless is_running('drakids'); + $ifw_alert = 0; + if (is_running('drakids')) { + eval { $ifw->send_manage_request }; + } else { + run_program::raw({ detach => 1 }, '/usr/sbin/drakids'); + } } sub generate_wireless_menuitem { my ($net) = @_; @@ -234,14 +245,19 @@ sub go2State { } $menu->destroy; } - $menu = generate_menu($state_type, $interface); + $menu = generate_menu($interface); } } +sub update_tray_icon() { + !$ifw_alert || $img->get_storage_type ne 'pixbuf' ? + $img->set_from_pixbuf($pixbufs{state}{$current_state eq 'connected' ? 'connected' : 'disconnected'}) : + $img->set_from_stock('gtk-dialog-warning', 'small-toolbar'); +} sub generate_menu { - my ($state_type, $interface) = @_; + my ($interface) = @_; - $img->set_from_pixbuf($pixbufs{state}{$state_type eq 'connected' ? 'connected' : 'disconnected'}); - gtkset_tip(Gtk2::Tooltips->new, $eventbox, formatAlaTeX(common::sprintf_fixutf8(translate($tooltips{$state_type}), $interface))); + update_tray_icon(); + gtkset_tip(Gtk2::Tooltips->new, $eventbox, formatAlaTeX(common::sprintf_fixutf8(translate($tooltips{$current_state}), $interface))); my $menu = Gtk2::Menu->new; my $create_item = sub { @@ -271,15 +287,15 @@ sub generate_menu { my $interactive; eval { $interactive = $ifw->get_interactive }; - if ($state_type eq 'connected') { + if ($current_state eq 'connected') { $menu->append($create_item->($_)) foreach qw(downNetwork monitorNetwork); $menu->append($create_item->('monitorIFW')) if defined $interactive; - } elsif ($state_type eq 'disconnected') { + } elsif ($current_state eq 'disconnected') { $menu->append($create_item->('upNetwork')); } $menu->append($create_item->('confNetwork')); - if ($state_type ne 'notconfigured') { + if ($current_state ne 'notconfigured') { $menu->append($create_item->('wireless')) if $has_wireless; push @settings, $create_item->('chooseInterface'); } @@ -321,21 +337,13 @@ sub setAutoStart { sub get_unprocessed_attacks() { my @packets = eval { $ifw->get_reports }; - while (my @attack = splice(@packets, 0, 9)) { + while (my @attack = splice(@packets, 0, 10)) { handle_attack(@attack); } } sub handle_attack { - my $attack = { mapn { $_[0] => $_[1] } [ 'seq', 'timestamp', 'indev', 'prefix', 'sensor', 'protocol', 'addr', 'port', 'icmp_type' ], \@_ }; - $attack->{ip_addr} = network::ifw::get_ip_address($attack->{addr}); - $attack->{hostname} = network::ifw::resolve_address($attack->{ip_addr}); - $attack->{protocol} = network::ifw::get_protocol($attack->{protocol}); - $attack->{service} = network::ifw::get_service($attack->{port}); - $attack->{msg} = $attack->{prefix} eq "SCAN" ? N("A port scanning attack has been attempted by %s.", $attack->{hostname}) - : $attack->{prefix} eq "SERV" ? N("The %s service has been attacked by %s.", $attack->{service}, $attack->{hostname}) - : $attack->{prefix} eq "PASS" ? N("A password cracking attack has been attempted by %s.", $attack->{hostname}) - : undef; + my $attack = network::ifw::attack_to_hash(\@_); push @attacks_queue, $attack; @attacks_queue == 1 and notify_attack($attacks_queue[0]); } @@ -359,15 +367,24 @@ sub notify_attack { print "unhandled attack type, skipping\n"; return; } - $bubble->set(N("Interactive Firewall"), gtkcreate_img("/usr/lib/libDrakX/icons/drakfirewall.png"), $attack->{msg}); + unless ($ifw_alert) { + $ifw_alert = 1; + update_tray_icon(); + Glib::Timeout->add(1000, sub { + update_tray_icon(); + $ifw_alert; + }); + } + $bubble->set(N("Interactive Firewall"), Gtk2::Image->new_from_pixbuf($pixbufs{firewall}), $attack->{msg}); $bubble->show(5000); + } sub ask_attack_verdict { my ($attack) = @_; my $w = ugtk2->new(N("Interactive Firewall: intrusion detected"), - icon => "/usr/lib/libDrakX/icons/drakfirewall.png"); + icon => "/usr/lib/libDrakX/icons/drakfirewall.png"); my ($yes, $no, $auto); gtkadd($w->{window}, @@ -384,7 +401,7 @@ sub ask_attack_verdict { gtknew('HBox', children => [ 0, gtknew('Label', text => " "), 1, gtknew('VBox', children_loose => [ - N("Attack time: %s", network::ifw::format_date($attack->{timestamp})), + N("Attack time: %s", $attack->{date}), N("Network interface: %s", $attack->{indev}), N("Attack type: %s", $attack->{prefix}), if_($attack->{protocol}, N("Protocol: %s", $attack->{protocol})), -- cgit v1.2.1