#!/usr/bin/perl use strict; use lib qw(/usr/lib/libDrakX); use c; use common; use standalone; use Digest::MD5; use network::netconnect; use network::tools; use mygtk2 qw(gtknew); use network::activefw; use Gtk2::TrayIcon; use ugtk2 qw(:create :helpers :wrappers); my ($eventbox, $img); my ($current_state, $menu, $timeout); my $onstartupfile = "$ENV{HOME}/.net_applet"; add_icon_path("/usr/share/libDrakX/pixmaps/"); # Allow multiple instances, but only one per user: is_running('net_applet') and die "net_applet already running\n"; my $prog_name = "/usr/bin/net_applet"; my $current_md5 = md5file($prog_name); my %appletstate = ( connected => { colour => [ 'connected' ], changes => [ 'disconnected', 'error', 'busy' ], menu => [ 'downNetwork', 'confNetwork', 'monitorNetwork', 'refresh', 'help' ], tt => [ N_("Network is up on interface %s") ] }, disconnected => { colour => [ 'disconnected' ], changes => [ 'connected', 'error', 'busy' ], menu => [ 'upNetwork', 'confNetwork', 'refresh', 'help' ], tt => [ #-PO: keep the "Configure Network" substring synced with the "Configure Network" message below N_("Network is down on interface %s. Click on \"Configure Network\"") ] }, notconfigured => { colour => [ 'disconnected' ], changes => [ 'connected' ], menu => [ 'confNetwork', 'refresh', 'help' ], tt => [ N_("You do not have any configured Internet connection. Run the \"Add Connection\" assistant from the Mandrakelinux Control Center") ] } ); my %actions = ( 'upNetwork' => { name => sub { N("Connect %s", $_[0]) }, launch => \&network::tools::start_interface }, 'downNetwork' => { name => sub { N("Disconnect %s", $_[0]) }, launch => \&network::tools::stop_interface }, 'monitorNetwork' => { name => N("Monitor Network"), launch => sub { system("/usr/sbin/net_monitor --defaultintf $_[0] &") } }, 'confNetwork' => { name => N("Configure Network"), launch => sub { system("/usr/sbin/drakconnect --skip-wizard &") } }, 'refresh' => { name => N("Refresh"), launch => sub { checkNetwork() } }, 'help' => { name => N("Get Online Help"), launch => sub { system("drakhelp --id internet-connection &") } } ); gtkadd(my $icon = Gtk2::TrayIcon->new("Net_Applet"), gtkadd($eventbox = Gtk2::EventBox->new, gtkpack($img = Gtk2::Image->new) ) ); $eventbox->signal_connect(button_press_event => sub { if ($_[1]->button == 1) { is_running('net_monitor') or netMonitor(); } $_[1]->button == 3 && $menu and $menu->popup(undef, undef, undef, undef, $_[1]->button, $_[1]->time); }); my ($opt) = @ARGV; if ($opt eq '--force' || $opt eq '-f') { setAutoStart('TRUE') } shouldStart() or die "$onstartupfile should be set to TRUE or use net_applet --force"; my $activefw = activefw->new(sub { my ($con, $msg) = @_; handle_attack($msg->get_args_list) if $msg->get_interface eq "com.mandrakesoft.activefirewall" && $msg->get_path eq "/com/mandrakesoft/activefirewall" && $msg->get_member eq "Attack"; }); my $interactive_ids = $activefw->get_interactive; checkNetwork(); cronNetwork(); $icon->show_all; Gtk2->main; ugtk2::exit(0); sub is_running { my ($name) = @_; any { my ($ppid, $pid, $n) = /^\s*(\d+)\s+(\d+)\s+(.*)/; #- to run ps, perl may create some process with $name as name and 1 as ppid $ppid != 1 && $pid != $$ && $n eq $name; } `ps -o '%P %p %c' -u $ENV{USER}`; } sub shouldStart() { my %p = getVarsFromSh($onstartupfile); my $ret = $p{AUTOSTART} eq 'FALSE' ? 0 : 1; $ret; } sub md5file { my @md5; foreach my $file (@_) { open(my $FILE, $file) or do { print STDERR "Can not open '$file': $!"; push @md5, "" }; binmode($FILE); push @md5, Digest::MD5->new->addfile($FILE)->hexdigest; close($FILE); } return wantarray() ? @md5 : $md5[0]; } sub netMonitor() { system("/usr/sbin/net_monitor&"); checkNetwork(); } sub checkNetwork() { my $netcnx = {}; my $netc = {}; my $intf = {}; network::netconnect::read_net_conf($netcnx, $netc, $intf); my ($gw_intf, $is_up, $gw_address, $dns_server) = network::tools::get_internet_connection($netc, $intf); go2State($gw_address ? 'connected' : $gw_intf ? 'disconnected' : 'notconfigured', $gw_intf); my $new_md5 = md5file($prog_name); if ($new_md5 ne $current_md5) { exec($prog_name) } } sub getIP { my ($interface) = shift; my $ifconfig = '/sbin/ifconfig'; my @lines = `$ifconfig $interface`; my @ip = map { if_(/inet adr:([\d.]+)/, $1) } @lines; return wantarray() ? @ip : $ip[0]; } sub cronNetwork() { $timeout = Glib::Timeout->add(5*1000, sub { checkNetwork(); 1; }); } sub go2State { my ($state_type, $interface) = @_; if ($current_state ne $state_type) { $current_state = $state_type; $menu and $menu->destroy; $menu = setState($state_type, $interface); } } sub setState { my ($state_type, $interface) = @_; my $arr = $appletstate{$state_type}{menu}; my $tmp = gtkcreate_pixbuf($appletstate{$state_type}{colour}[0]); $img->set_from_pixbuf($tmp); gtkset_tip(Gtk2::Tooltips->new, $eventbox, formatAlaTeX(common::sprintf_fixutf8(translate($appletstate{$state_type}{tt}[0]), $interface))); my $menu = Gtk2::Menu->new; foreach (@$arr) { my $name = ref($actions{$_}{name}) eq 'CODE' ? $actions{$_}{name}->($interface) : $actions{$_}{name}; my $launch = $actions{$_}{launch}; $menu->append(gtksignal_connect(gtkshow(Gtk2::MenuItem->new_with_label($name)), activate => sub { $launch->($interface) })); } $menu->append(gtkshow(Gtk2::SeparatorMenuItem->new)); $menu->append(gtkshow(gtksignal_connect(gtkset_active(Gtk2::CheckMenuItem->new_with_label(N("Interactive intrusion detection")), $interactive_ids), toggled => sub { $activefw->set_interactive(to_bool($_[0]->get_active)) }))); $menu->append(gtkshow(gtksignal_connect(gtkset_active(Gtk2::CheckMenuItem->new_with_label(N("Always launch on startup")), shouldStart()), toggled => sub { setAutoStart(uc(bool2text($_[0]->get_active))) }))); $menu->append(gtksignal_connect(gtkshow(Gtk2::MenuItem->new_with_label(N("Quit"))), activate => sub { mainQuit() })); $menu; } sub mainQuit() { Glib::Source->remove($timeout) if $timeout; Gtk2->main_quit; } sub setAutoStart { my $state = shift; output_p $onstartupfile, qq(AUTOSTART=$state ); } sub handle_attack { my ($seq, $timestamp, $indev, $prefix, $sensor, $protocol, $addr, $port, $icmp_type) = @_; my $ip_addr = activefw::get_ip_address($addr); my $hostname = activefw::resolve_address($ip_addr); my $service = activefw::get_service($port); my $msg = $prefix eq "SCAN" ? N("A port scanning attack has been attempted by %s.", $hostname) : $prefix eq "SERV" ? N("The %s service has been attacked by %s.", $service , $hostname) : $prefix eq "PASS" ? N("A password cracking attack has been attempted by %s.", $hostname) : undef; unless ($msg) { print "unhandled attack type, skipping\n"; return; } $ugtk2::wm_icon = "/usr/lib/libDrakX/icons/drakfirewall.png"; my $w = ugtk2->new(N("Active Firewall : intrusion detected")); gtkadd($w->{window}, gtknew('VBox', spacing => 5, children_loose => [ gtknew('HBox', children => [ 0, Gtk2::Image->new_from_stock('gtk-dialog-warning', 'dialog'), 0, gtknew('Label', text => " "), 1, gtknew('VBox', children => [ 0, $msg, 0, N("Do you want to blacklist the attacker ?") ]) ]), gtknew('HBox', children_loose => [ gtknew('HButtonBox', layout => 'start', children_loose => [ gtknew('Button', text => N("No"), clicked => sub { $activefw->blacklist($seq, 0); Gtk2->main_quit }) ]), gtknew('HButtonBox', layout => 'end', children_loose => [ my $ok = gtknew('Button', text => N("Yes"), clicked => sub { $activefw->blacklist($seq, 1); Gtk2->main_quit }) ]) ]), gtkadd(Gtk2::Expander->new(N("Attack details")), gtknew('HBox', children => [ 0, gtknew('Label', text => " "), 1, gtknew('VBox', children_loose => [ N("Attack time: %s", activefw::format_date($timestamp)), N("Network interface: %s", $indev), N("Attack type: %s", $prefix), if_($protocol, N("Protocol: %s", $protocol)), N("Attacker IP address: %s", $ip_addr), if_($hostname ne $ip_addr, N("Attacker hostname: %s", $hostname)), if_($service, N("Service attacked: %s", $service)), if_($port, N("Port attacked: %s", $port)), if_($icmp_type, N("Type of ICMP attack: %s", $icmp_type)) ]) ])), ])); $ok->grab_focus; $w->main; }