diff options
Diffstat (limited to 'bin/drakids')
-rw-r--r-- | bin/drakids | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/bin/drakids b/bin/drakids new file mode 100644 index 0000000..50cc786 --- /dev/null +++ b/bin/drakids @@ -0,0 +1,337 @@ +#!/usr/bin/perl + +use strict; +use lib qw(/usr/lib/libDrakX); +# i18n: IMPORTANT: to get correct namespace (drakx-net instead of libDrakX) +BEGIN { unshift @::textdomains, 'drakx-net' } +use common; +use standalone; + +use Socket; +use mygtk2 qw(gtknew); +use ugtk2 qw(:dialogs); +use POSIX qw(strftime); +use dbus_object; +use network::ifw; + +use Gtk2::SimpleList; + +use ugtk2 qw(:create :helpers :wrappers); + +my $loglist = create_attack_list(); +$loglist->get_selection->set_mode('single'); + +my $blacklist = create_attack_list(); +$blacklist->get_selection->set_mode('multiple'); + +my $whitelist = Gtk2::SimpleList->new(addr => 'hidden', + N("Allowed addresses") => 'text', + ); +$whitelist->get_selection->set_mode('multiple'); +$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 $i_m_ifw2 = member("--ifw2", @ARGV); +my $services_log = create_service_list('status'); +my $allowed_services = create_service_list(); +my $blocked_services = create_service_list(); + +my $title = N("Interactive Firewall"); +my $icon = "drakfirewall"; + +$ugtk2::wm_icon = $icon; +my $w = ugtk2->new($title); + +my $ifw; +eval { + my $bus = dbus_object::system_bus(); + dbus_object::set_gtk2_watch_helper($bus); + network::ifw::init($bus, sub { + my ($_con, $msg) = @_; + my $member = $msg->get_member; + 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); + } elsif ($member eq 'Clear') { + clear_lists(); + } elsif ($member eq 'Init') { + handle_init(); + } elsif ($member eq 'ManageRequest') { + $w->{window}->present; + } + }); + $ifw = network::ifw->new($bus); +}; + +if ($@) { + err_dialog(N("Interactive Firewall"), N("Unable to contact daemon")); + $w->exit(1); +} + +init_lists(); + +gtkadd($w->{window}, + gtknew('VBox', spacing => 5, children => [ + $::isEmbedded ? () : (0, Gtk2::Banner->new($icon, $title)), + 1, gtknew('Notebook', children => [ + if_($i_m_ifw2, + gtknew('Label', text => N("Log")), + gtknew('VBox', spacing => 5, children => [ + 1, gtknew('ScrolledWindow', width => 600, height => 260, child => $services_log), + 0, gtknew('HButtonBox', layout => 'edge', children_loose => [ + gtknew('Button', text => N("Allow"), clicked => sub {}), + gtknew('Button', text => N("Block"), clicked => sub {}), + gtknew('Button', text => N("Close"), clicked => sub { Gtk2->main_quit }) + ]), + ]), + gtknew('Label', text => N("Allowed services")), + gtknew('VBox', spacing => 5, children => [ + 1, gtknew('ScrolledWindow', width => 600, height => 260, child => $allowed_services), + 0, gtknew('HButtonBox', layout => 'edge', children_loose => [ + gtknew('Button', text => N("Remove"), clicked => sub {}), + gtknew('Button', text => N("Block"), clicked => sub {}), + gtknew('Button', text => N("Close"), clicked => sub { Gtk2->main_quit }) + ]), + ]), + gtknew('Label', text => N("Blocked services")), + gtknew('VBox', spacing => 5, children => [ + 1, gtknew('ScrolledWindow', width => 600, height => 260, child => $blocked_services), + 0, gtknew('HButtonBox', layout => 'edge', children_loose => [ + gtknew('Button', text => N("Remove"), clicked => sub {}), + gtknew('Button', text => N("Allow"), clicked => sub {}), + gtknew('Button', text => N("Close"), clicked => sub { Gtk2->main_quit }) + ]), + ]), + ), + gtknew('Label', text => N("Log")), + gtknew('VBox', spacing => 5, children => [ + 1, gtknew('ScrolledWindow', width => 600, height => 260, child => $loglist), + 0, gtknew('HButtonBox', layout => 'edge', children_loose => [ + gtknew('Button', text => N("Clear logs"), clicked => \&clear_log), + gtknew('Button', text => N("Blacklist"), clicked => sub { blacklist(get_selected_log_seq()) }), + gtknew('Button', text => N("Whitelist"), clicked => sub { whitelist(get_selected_log()) }), + gtknew('Button', text => N("Close"), clicked => sub { Gtk2->main_quit }) + ]), + ]), + gtknew('Label', text => N("Blacklist")), + gtknew('VBox', spacing => 5, children => [ + 1, gtknew('ScrolledWindow', width => 600, height => 260, child => $blacklist), + 0, gtknew('HButtonBox', layout => 'edge', children_loose => [ + gtknew('Button', text => N("Remove from blacklist"), clicked => sub { unblacklist(get_selected_blacklist()) }), + gtknew('Button', text => N("Move to whitelist"), clicked => sub { + my @addr = get_selected_blacklist(); + unblacklist(@addr); + whitelist(@addr); + }), + gtknew('Button', text => N("Close"), clicked => sub { Gtk2->main_quit }) + ]), + ]), + gtknew('Label', text => N("Whitelist")), + gtknew('VBox', spacing => 5, children => [ + 1, gtknew('ScrolledWindow', width => 600, height => 260, child => $whitelist), + 0, gtknew('HButtonBox', layout => 'edge', children_loose => [ + gtknew('Button', text => N("Remove from whitelist"), clicked => sub { unwhitelist(get_selected_whitelist()) }), + gtknew('Button', text => N("Close"), clicked => sub { Gtk2->main_quit }) + ]), + ]), + ]), + ]), +); +$w->show; +Gtk2->main; + +$w->exit(0); + +sub sort_by_column { + my ($column, $model) = @_; + my $col_id = $column->get_sort_column_id; + my ($old_id, $old_order) = $model->get_sort_column_id; + $model->set_sort_column_id($col_id, $old_id == $col_id && $old_order ne 'descending' ? 'ascending' : 'descending'); +} + +sub handle_init() { + $ifw->attach_object; + init_lists(); +} + +sub list_remove_addr { + my ($list, @addr) = @_; + #- workaround buggy Gtk2::SimpleList array abstraction, it destroys references + @$list = map { member($_->[0], @addr) ? () : [ @$_ ] } @$list; +} + +#- may throw an exception +sub init_blacklist() { + my @packets = $ifw->get_blacklist; + while (my @blacklist = splice(@packets, 0, 8)) { + handle_blacklist(@blacklist); + } +} + +sub clear_blacklist() { + @{$blacklist->{data}} = (); +} + +sub handle_blacklist { + attack_list_add($blacklist, network::ifw::attack_to_hash(\@_)); +} + +sub get_selected_blacklist() { + uniq(map { $blacklist->{data}[$_][0] } $blacklist->get_selected_indices); +} + +sub blacklist { + my @seq = @_; + eval { $ifw->set_blacklist_verdict($_, 1) foreach @seq }; + $@ and err_dialog(N("Interactive Firewall"), N("Unable to contact daemon")); +} + +sub unblacklist { + my @addr = @_; + eval { $ifw->unblacklist($_) foreach @addr }; + if (!$@) { + list_remove_addr($blacklist->{data}, @addr); + } else { + err_dialog(N("Interactive Firewall"), N("Unable to contact daemon")); + } +} + +#- may throw an exception +sub init_whitelist() { + handle_whitelist($_) foreach $ifw->get_whitelist; +} + +sub clear_whitelist() { + @{$whitelist->{data}} = (); +} + +sub handle_whitelist { + my ($addr) = @_; + push @{$whitelist->{data}}, [ $addr, network::ifw::resolve_address(network::ifw::get_ip_address($addr)) ]; +} + +sub get_selected_whitelist() { + uniq(map { $whitelist->{data}[$_][0] } $whitelist->get_selected_indices); +} + +sub whitelist { + my @addr = @_; + eval { $ifw->whitelist($_) foreach @addr }; + $@ and err_dialog(N("Interactive Firewall"), N("Unable to contact daemon")); +} + +sub unwhitelist { + my @addr = @_; + eval { $ifw->unwhitelist($_) foreach @addr }; + if (!$@) { + list_remove_addr($whitelist->{data}, @addr); + } else { + err_dialog(N("Interactive Firewall"), N("Unable to contact daemon")); + } +} + +sub init_lists() { + eval { + init_loglist(); + init_blacklist(); + init_whitelist(); + }; + $@ 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', + seq => 'hidden', + timestamp => 'hidden', + N("Date") => 'text', + N("Remote host") => 'text', + N("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->{seq}, + $attack->{timestamp}, + $attack->{date}, + $attack->{hostname}, + $attack->{type}, + $attack->{service}, + $attack->{indev}, + $attack->{protocol}, + ]; +} + +sub create_service_list { + my ($o_status) = @_; + my $service_list = Gtk2::SimpleList->new( + N("Application") => 'text', + N("Service") => 'text', + if_($o_status, N("Status") => 'text'), + ); + N_("Allowed"); + N_("Blocked"); + $service_list->set_headers_clickable(1); + foreach (0, 1, if_($o_status, 2)) { + $service_list->get_column($_)->signal_connect('clicked', \&sort_by_column, $service_list->get_model); + } + $service_list; +} + +#- 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 get_selected_log_seq() { + uniq(map { $loglist->{data}[$_][1] } $loglist->get_selected_indices); +} +sub get_selected_log() { + uniq(map { $loglist->{data}[$_][0] } $loglist->get_selected_indices); +} + +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")); + } +} |