diff options
Diffstat (limited to 'lib')
51 files changed, 15544 insertions, 0 deletions
diff --git a/lib/network/.perl_checker b/lib/network/.perl_checker new file mode 100644 index 0000000..2326e2f --- /dev/null +++ b/lib/network/.perl_checker @@ -0,0 +1 @@ +Basedir ../.. diff --git a/lib/network/adsl.pm b/lib/network/adsl.pm new file mode 100644 index 0000000..e2ac90d --- /dev/null +++ b/lib/network/adsl.pm @@ -0,0 +1,52 @@ +package network::adsl; # $Id: adsl.pm 219797 2007-05-25 15:39:46Z blino $ + +use common; +use run_program; +use network::tools; +use modules; + +sub adsl_probe_info { + my ($net) = @_; + my $pppoe_file = "$::prefix/etc/ppp/pppoe.conf"; + my $login; + foreach (qw(/etc/ppp/peers/ppp0 /etc/ppp/options /etc/ppp/options.adsl)) { + ($login) = map { if_(/^user\s+"([^"]+)"/, $1) } cat_("$::prefix/$_") if !$login && -r "$::prefix/$_"; + } + my %pppoe_conf = -f $pppoe_file && getVarsFromSh($pppoe_file); + $login = $pppoe_conf{USER} if !$login || $net->{adsl}{method} eq 'pppoe'; + my $passwd = network::tools::passwd_by_login($login); + if (!$net->{adsl}{vpi} && !$net->{adsl}{vci}) { + foreach (cat_("$::prefix/etc/ppp/peers/ppp0")) { + if (/^.*-vpi\s+(\d+)\s+-vci\s+(\d+)/ || /^plugin pppoatm.so (\d+)\.(\d+)$/) { + ($net->{adsl}{vpi}, $net->{adsl}{vci}) = ($1, $2); + last; + } + } + } + $pppoe_conf{DNS1} ||= ''; + $pppoe_conf{DNS2} ||= ''; + add2hash($net->{resolv}, { dnsServer2 => $pppoe_conf{DNS1}, dnsServer3 => $pppoe_conf{DNS2}, DOMAINNAME2 => '' }); + add2hash($net->{adsl}, { login => $login, passwd => $passwd }); +} + +sub adsl_conf_backend { + my ($in, $net) = @_; + + require network::connection::xdsl; + my $xdsl = network::connection::xdsl->new( + $net->{adsl}{method} eq "capi" ? + $net->{adsl}{capi_card} : + { driver => $net->{adsl}{driver}, ethernet_device => $net->{adsl}{ethernet_device} }); + $xdsl->{protocol} = $net->{adsl}{method}; + $xdsl->{access}{login} = $net->{adsl}{login}; + $xdsl->{access}{password} = $net->{adsl}{passwd}; + $xdsl->{access}{vpi} = $net->{adsl}{vpi}; + $xdsl->{access}{vci} = $net->{adsl}{vci}; + + $xdsl->install_packages($in); + $xdsl->unload_connection; + $xdsl->write_settings($net); + $xdsl->prepare_connection; +} + +1; diff --git a/lib/network/connection.pm b/lib/network/connection.pm new file mode 100644 index 0000000..837ab97 --- /dev/null +++ b/lib/network/connection.pm @@ -0,0 +1,350 @@ +package network::connection; + +use common; +use network::vpn; + +sub get_types { + sort { $a->get_metric <=> $b->get_metric } grep { $_->can('get_devices') } common::load_modules_from_base(__PACKAGE__); +} + +=item get_type_name() + +Get the connection type name, unstranslated + +=cut + +sub get_type_name() { N("Unknown connection type") } +sub get_type_description { + my ($class) = @_; + $class->get_type_name; +} + +=item get_type_icon() + +Get the connection type icon path + +=cut + +sub get_type_icon { + my ($self, $o_size) = @_; + my $size = $o_size || 24; + my $icon = eval { $self->_get_type_icon . '-' . $size }; + $icon || '/usr/share/mcc/themes/default/drakconnect-mdk'; +} + +=item get_devices(%options) + +Get the devices supported by this connection type +Options: +- automatic_only (no device requiring manual configuration should be returned) +- fast_only (no slow detection should be performed) + +=cut + +=item get_connections(%options) + +List connections that can be configured by the class +Options: see get_devices() + +=cut + +sub get_connections { + my ($class, %options) = @_; + map { $class->new($_) } $class->get_devices(%options); +} + +=item find_ifcfg_type($ifcfg) + +Returns the class matching the connection type of the ifcfg hash + +=cut + +sub find_ifcfg_type { + my ($_class, $ifcfg) = @_; + find { $_->can('handles_ifcfg') && $_->handles_ifcfg($ifcfg) } sort { $b->get_metric <=> $a->get_metric } get_types(); +} + +sub new { + my ($class, $device) = @_; + bless { + device => $device, + settings => {}, + networks => {}, + }, $class; +} + +sub get_description { + my ($self) = @_; + my $description = $self->{device}{description}; + $description =~ s/\|/ /g; + $description; +} + +sub get_label { + my ($self) = @_; + my $intf = $self->get_interface; + my $descr = $self->get_description; + $intf ? sprintf("%s (%s)", $descr, $intf) : $descr; +} + +sub get_driver { + my ($self) = @_; + $self->{device}{driver}; +} + +sub get_interface { + my ($_self) = @_; + die "unable to get interface"; +} + +sub get_metric { 60 } + +sub get_up_timeout { 10 } + +sub get_status { + my ($self) = @_; + require network::tools; + my ($_is_up, $gw_address) = network::tools::get_interface_status($self->get_interface); + $self->{status} = to_bool($gw_address); +} + +=item get_status_icon() + +Get status icon path (connected/disconnected/unconfigured) +The file may not exist + +=cut + +sub get_status_icon { + my ($self) = @_; + my $icon = $self->get_type_icon; + my $status = $self->get_interface ? $self->get_status ? "on" : "off" : "w"; + $icon . "-" . $status; +} + +sub get_ifcfg_bool { + my ($self, $field) = @_; + defined $self->{ifcfg}{$field} ? text2bool($self->{ifcfg}{$field}) : undef; +} + +sub get_selected_network { + my ($self) = @_; + exists $self->{networks}{$self->{network}} && $self->{networks}{$self->{network}}; +} + +sub selected_network_is_configured { + my ($self) = @_; + + my $network = $self->get_selected_network or return; + $self->network_is_configured($network); +} + +sub load_interface_settings { + my ($self) = @_; + require network::network; + my $file = network::network::get_ifcfg_file($self->get_interface); + $self->{ifcfg} = { getVarsFromSh($file) }; + $self->{vpn_list} = [ map { $_->get_configured_connections } network::vpn->list_types ]; + $self->{control}{onboot} = $self->get_ifcfg_bool('ONBOOT'); + $self->{control}{userctl} = $self->get_ifcfg_bool('USERCTL'); + $self->{control}{metric} = $self->{ifcfg}{METRIC}; + $self->{control}{mtu} = $self->{ifcfg}{MTU}; + $self->{control}{accounting} = $self->{ifcfg}{ACCOUNTING}; + $self->{control}{nm_controlled} = $self->{ifcfg}{NM_CONTROLLED}; + $self->{control}{uuid} = $self->{ifcfg}{UUID}; + $self->{control}{name} = $self->{ifcfg}{NAME}; + $self->{control}{last_connect} = $self->{ifcfg}{LAST_CONNECT}; +} + +#- override to return 1 if the connection network scan is slow +sub network_scan_is_slow { 0 } +#- override to return 1 if the hardware check is slow +sub check_hardware_is_slow { 0 } +#- override to return 1 if only one network is supported +sub has_unique_network { 0 } + +sub get_network_access_settings_label { N("Network access settings") } +sub get_access_settings_label { N("Access settings") } +sub get_address_settings_label { N("Address settings") } + +#- check that $self->can('get_providers') first +sub guess_provider_settings { + my ($self) = @_; + require lang; + my @providers_data = $self->get_providers; + my $locale_country = lang::c2name(ref($::o) && $::o->{locale}{country} || lang::read()->{country}); + my $separator = $providers_data[1]; + $self->{provider_name} ||= find { /^\Q$locale_country$separator\E/ } sort(keys %{$providers_data[0]}); +} + +sub set_provider { + my ($self) = @_; + if ($self->{provider_name} ne N("Unlisted - edit manually")) { + my @providers_data = $self->get_providers; + $self->{provider} = $providers_data[0]{$self->{provider_name}}; + $self->apply_provider_settings($net); + } +} + +sub apply_provider_settings { + my ($self, $net) = @_; + $self->guess_protocol($net) if $self->can('guess_protocol'); + $self->guess_access_settings('provider_only') if $self->can('guess_access_settings'); +} + +#- check that $self->can('get_providers') first +sub get_provider_settings { + my ($self) = @_; + my @providers_data = $self->get_providers; + [ + { + type => "list", val => \$self->{provider_name}, separator => $providers_data[1], + list => [ N("Unlisted - edit manually"), sort(keys %{$providers_data[0]}) ], sort => 0, + changed => sub { $self->set_provider }, + }, + ]; +} + +#- check that $self->can('get_protocols') first +sub get_protocol_settings { + my ($self) = @_; + my $protocols = $self->get_protocols; + [ + { + val => \$self->{protocol}, type => 'list', + list => [ sort { $protocols->{$a} cmp $protocols->{$b} } keys %$protocols ], + format => sub { $protocols->{$_[0]} }, + } + ]; +} + +sub guess_network_control_settings { + my ($self) = @_; + $self->{control}{vpn} = find { + $self->{ifcfg}{VPN_TYPE} eq $_->get_type && + $self->{ifcfg}{VPN_NAME} eq $_->get_name; + } @{$self->{vpn_list}}; +} + +sub get_network_control_settings { + my ($self) = @_; + [ + if_(@{$self->{vpn_list}}, + { label => N("VPN connection"), val => \$self->{control}{vpn}, + list => [ undef, @{$self->{vpn_list}} ], + format => sub { defined $_[0] ? $_[0]->get_label : N("None") } }), + ]; +} + +sub guess_control_settings { + my ($self) = @_; + $self->{control}{metric} ||= $self->get_metric; +} + +sub get_control_settings { + my ($self) = @_; + [ + { text => N("Allow users to manage the connection"), val => \$self->{control}{userctl}, type => "bool" }, + { text => N("Start the connection at boot"), val => \$self->{control}{onboot}, type => "bool" }, + { text => N("Enable traffic accounting"), val => \$self->{control}{accounting}, type => "bool" }, + { text => N("Allow interface to be controlled by Network Manager"), val => \$self->{control}{nm_controlled}, type => "bool" }, + { label => N("Metric"), val => \$self->{control}{metric}, advanced => 1 }, + { label => N("MTU"), val => \$self->{control}{mtu}, advanced => 1, + help => N("Maximum size of network message (MTU). If unsure, left blank.") }, + ]; +} + +sub build_ifcfg_settings { + my ($self, $o_options) = @_; + put_in_hash($o_options, { + DEVICE => $self->get_interface, + ONBOOT => bool2yesno($self->{control}{onboot}), + ACCOUNTING => bool2yesno($self->{control}{accounting}), + NM_CONTROLLED => bool2yesno($self->{control}{nm_controlled}), + USERCTL => bool2yesno($self->{control}{userctl}), + METRIC => $self->{control}{metric}, + MTU => $self->{control}{mtu}, + UUID => $self->{control}{uuid}, + NAME => $self->{control}{name}, + LAST_CONNECT => $self->{control}{last_connect}, + VPN_TYPE => defined $self->{control}{vpn} && $self->{control}{vpn}->get_type, + VPN_NAME => defined $self->{control}{vpn} && $self->{control}{vpn}->get_name, + #- FIXME: add MS_DNSx variables if DNS servers are specified + }); +} + +sub write_settings { + my ($self, $o_net, $_o_modules_conf) = @_; + require network::network; + my $file = network::network::get_ifcfg_file($self->get_interface); + network::network::write_interface_settings($self->build_ifcfg_settings, $file); + if ($self->{address}{hostname}) { + $o_net->{network}{HOSTNAME} = $self->{address}{hostname} if $o_net; + network::network::write_hostname($self->{address}{hostname}); + } + network::network::write_network_conf($o_net) if $o_net; + require network::shorewall; + network::shorewall::update_interfaces_list($self->get_interface); + network::network::reload_net_applet(); +} + +sub probed_networks { + my ($self) = @_; + $self->{probed_networks} = 1; +} + +sub connect { + my ($self) = @_; + require network::tools; + network::tools::start_interface($self->get_interface, 0); +} + +sub disconnect { + my ($self) = @_; + require network::tools; + network::tools::stop_interface($self->get_interface, 0); +} + +sub setup_thirdparty { + my ($self, $in) = @_; + my $driver = $self->get_driver; + # FIXME: weird return code + $driver && $self->can('get_thirdparty_settings') or return 1; + require network::thirdparty; + $self->{thirdparty} = network::thirdparty::apply_settings($in, ref $self, $self->get_thirdparty_settings, $driver); + $self->{device} = $self->{thirdparty}{device} if $self->{thirdparty} && $self->{thirdparty}{device}; + $self->{thirdparty}; +} + +sub prepare_device { + my ($self) = @_; + my $driver = $self->get_driver; + if ($driver) { + require modules; + eval { modules::load($driver) }; + } +} + +#- status messages can be sent using mdv-network-event +sub get_status_message { + my ($self, $status) = @_; + my $interface = $self->get_interface; + { + link_up => N("Link detected on interface %s", $interface), + link_down => N("Link beat lost on interface %s", $interface), + }->{$status}; +} + +=head2 Pure virtual private instance methods + +=over + +=item _get_type_icon + +Get the icon prefix for the connection type + +=back + +=cut + +1; diff --git a/lib/network/connection/.perl_checker b/lib/network/connection/.perl_checker new file mode 100644 index 0000000..80deab8 --- /dev/null +++ b/lib/network/connection/.perl_checker @@ -0,0 +1 @@ +Basedir ../../.. diff --git a/lib/network/connection/cable.pm b/lib/network/connection/cable.pm new file mode 100644 index 0000000..a81ae06 --- /dev/null +++ b/lib/network/connection/cable.pm @@ -0,0 +1,74 @@ +package network::connection::cable; + +use base qw(network::connection::ethernet); + +use strict; +use common; +use modules; +use detect_devices; + +sub get_type_name() { N("Cable") } +sub get_type_description() { N("Cable modem") } +sub _get_type_icon() { 'cablemodem' } +sub get_metric { 20 } + +sub handles_ifcfg { + my ($_class, $_ifcfg) = @_; + 0; +} + +my $bpalogin_file = '/etc/bpalogin.conf'; + +sub guess_protocol { + my ($self) = @_; + $self->{protocol} = 'dhcp'; +} + +sub guess_access_settings { + my ($self) = @_; + $self->{access}{use_bpalogin} = -e $::prefix . $bpalogin_file; + if ($self->{access}{use_bpalogin}) { + foreach (cat_($::prefix . $bpalogin_file)) { + /^username (.*)/ and $self->{access}{login} = $1; + /^password (.*)/ and $self->{access}{password} = $1; + } + } +} + +sub get_access_settings { + my ($self) = @_; + my %auth = ( + 0 => N("None"), + 1 => N("Use BPALogin (needed for Telstra)"), + ); + [ + { label => N("Authentication"), type => "list", val => \$self->{access}{use_bpalogin}, + list => [ sort keys %auth ], format => sub { $auth{$_[0]} } }, + { label => N("Account Login (user name)"), val => \$self->{access}{login}, + disabled => sub { !$self->{access}{use_bpalogin} } }, + { label => N("Account Password"), val => \$self->{access}{password}, hidden => 1, + disabled => sub { !$self->{access}{use_bpalogin} } }, + ]; +} + +sub write_settings { + my ($self, $o_net, $o_modules_conf) = @_; + if ($self->{access}{use_bpalogin}) { + substInFile { + s/username\s+.*\n/username $self->{access}{login}\n/; + s/password\s+.*\n/password $self->{access}{password}\n/; + } $::prefix . $bpalogin_file; + } + services::set_status("bpalogin", $self->{access}{use_bpalogin}); + $self->SUPER::write_settings($o_net, $o_modules_conf); +} + +sub install_packages { + my ($self, $in) = @_; + if ($self->{access}{use_bpalogin}) { + $in->do_pkgs->ensure_is_installed('bpalogin', '/usr/sbin/bpalogin') or return; + } + $self->SUPER::install_packages($in); +} + +1; diff --git a/lib/network/connection/cellular.pm b/lib/network/connection/cellular.pm new file mode 100644 index 0000000..5bb2259 --- /dev/null +++ b/lib/network/connection/cellular.pm @@ -0,0 +1,99 @@ +package network::connection::cellular; + +use base qw(network::connection::ppp); + +use strict; +use common; + +my $cellular_d = "/etc/sysconfig/network-scripts/cellular.d"; + +sub get_providers { + # manually-defined providers + require network::connection::providers::cellular; + # providers imported from mobile-broadband-provider-info + require network::connection::providers::cellular_extra; + # combine custom providers with m.b.p.i. imported ones, + # filtering out CDMA-only providers which we do not support for now + my %providers = ( + %network::connection::providers::cellular::data, + grep_each{!$::b->{cdma} } %network::connection::providers::cellular_extra::data + ); + (\%providers, '|'); +} + +sub get_cellular_settings_file { + my ($self) = @_; + my $network = $self->get_selected_network or return; + $::prefix . $cellular_d . '/' . $network->{name}; +} + +sub load_cellular_settings { + my ($self) = @_; + my $file = $self->get_cellular_settings_file or return; + -f $file && { getVarsFromSh($file) }; +} + +sub network_is_configured { + my ($self, $_network) = @_; + #- only one network is supported, assume it is configured if settings are available + defined($self->load_cellular_settings); +} + +sub write_cellular_settings { + my ($self) = @_; + my $file = $self->get_cellular_settings_file or return; + setVarsInShMode($file, 0600, { map { (uc($_) => $self->{access}{$_}) } qw(login password apn) }); +} + +sub guess_apn_from_chat { + my ($self) = @_; + my $chat = cat_($::prefix . $self->get_chat_file); + my $chat_apn = $chat =~ /\bAT\+CGDCONT=\d+,"IP","([^"]+)"/ && $1; +} + +sub guess_provider_settings { + my ($self) = @_; + my $settings = $self->load_cellular_settings; + my $apn = $settings && $settings->{APN} || $self->guess_apn_from_chat; + if ($apn) { + my @providers_data = $self->get_providers; + $self->{provider_name} ||= find { $providers_data[0]{$_}{apn} eq $apn } keys %{$providers_data[0]}; + return; + } + $self->SUPER::guess_provider_settings; +} + +sub guess_access_settings { + my ($self, $o_provider_only) = @_; + my $settings = !$o_provider_only && $self->load_cellular_settings || {}; + $self->{access}{$_} = $settings->{uc($_)} || $self->{provider}{$_} foreach qw(login password apn); +} + +sub get_access_settings { + my ($self) = @_; + [ + { label => N("Access Point Name"), val => \$self->{access}{apn} }, + @{$self->SUPER::get_access_settings}, + ]; +} + +sub set_ppp_settings { + my ($self) = @_; + $self->{access}{use_chat} = 1; + $self->{access}{dial_number} = !$self->{access}{no_dial} && "*99***$self->{access}{cid}#"; +} + +sub write_settings { + my ($self) = @_; + $self->write_cellular_settings; + $self->set_ppp_settings; + $self->SUPER::write_settings; +} + +sub apply_network_selection { + my ($self) = @_; + $self->set_ppp_settings; + $self->write_ppp_settings; +} + +1; diff --git a/lib/network/connection/cellular_bluetooth.pm b/lib/network/connection/cellular_bluetooth.pm new file mode 100644 index 0000000..5c99b63 --- /dev/null +++ b/lib/network/connection/cellular_bluetooth.pm @@ -0,0 +1,103 @@ +package network::connection::cellular_bluetooth; + +use base qw(network::connection::cellular); + +use strict; +use common; + +my $rfcomm_dev_prefix = "/dev/rfcomm"; + +sub get_type_name { N("Bluetooth") } +sub get_type_description { N("Bluetooth Dial Up Networking") } +sub _get_type_icon { 'bluetooth' } +sub get_devices { + my ($_class, %options) = @_; + ($options{fast_only} ? () : search_services('DUN')); +} + +sub get_metric { 45 } +sub get_interface { "ppp0" } + +sub get_packages { 'bluez', 'ppp' } + +sub get_rfcomm_device { + my ($self) = @_; + $self->{rfcomm_device} ||= find { ! -e ($rfcomm_dev_prefix . $_) } 0 .. 99; +} + +sub get_tty_device { + my ($self) = @_; + $rfcomm_dev_prefix . $self->get_rfcomm_device; +} + +# http://www.hingston.demon.co.uk/mike/nokia6680.html +# http://kapsi.fi/~mcfrisk/linux_gprs.html +# GPRS specific commands http://www.phonestar.com.my/s_at_10.html + +sub search_services { + my ($service_type) = @_; + my (@services); + my $service = {}; + my ($key, $value); + my $push_service = sub { push @services, $service if exists $service->{class} }; + my $use_key = sub { $key = $_[0]; undef $value }; + foreach (run_program::rooted_get_stdout($::prefix, 'sdptool', 'search', $service_type)) { + if (/^Searching for $service_type on (.+) \.\.\.$/) { + $push_service->(); + $service = { addr => $1 }; + } elsif (/^Service Name:\s+(.*)$/) { + $service->{name} = $1; + } elsif (/^Service Provider:\s+(.*)$/) { + $service->{name} = $1; + } elsif (/^\s*Channel:\s*(\d+)$/) { + $service->{channel} = $1; + } elsif (/^Service Class ID List/) { + $use_key->('class'); + } else { + $value = chomp_($_); + } + if ($key && $value) { + $service->{$key} = $value; + $use_key->(undef); + } + } + $push_service->(); + my %names; + foreach (@services) { + $names{$_->{addr}} ||= chomp_(run_program::rooted_get_stdout($::prefix, 'hcitool', 'name', $_->{addr})); + $_->{description} = $names{$_->{addr}}; + } + @services; +} + +sub set_ppp_settings { + my ($self) = @_; + + $self->{access}{cid} = 1; + $self->{access}{at_commands} = [ qq(AT+CGDCONT=$self->{access}{cid},"IP","$self->{access}{apn}") ]; + + $self->SUPER::set_ppp_settings; +} + +sub write_settings { + my ($self) = @_; + + my $dev = $self->get_rfcomm_device; + output("$::prefix/etc/bluetooth/rfcomm.conf", qq( +rfcomm$dev { + bind yes; + device $self->{device}{addr}; + channel $self->{device}{channel}; + comment "Dial-up networking"; +} +)); + + $self->SUPER::write_settings; +} + +sub prepare_connection { + my ($self) = @_; + run_program::rooted_get_stdout($::prefix, 'rfcomm', 'bind', $self->get_rfcomm_device); +} + +1; diff --git a/lib/network/connection/cellular_card.pm b/lib/network/connection/cellular_card.pm new file mode 100644 index 0000000..0fc3fbf --- /dev/null +++ b/lib/network/connection/cellular_card.pm @@ -0,0 +1,278 @@ +package network::connection::cellular_card; + +use base qw(network::connection::cellular); + +use strict; +use common; + +my $wrong_pin_error = N_("Wrong PIN number format: it should be 4 digits."); + +sub get_type_name() { N("GPRS/Edge/3G") } +sub _get_type_icon() { 'cellular' } +sub get_devices() { + require detect_devices; + my @maybe_usbserial_modules = ('usbserial_generic', 'unknown'); + my @serial = grep { $_->{description} =~ /GPRS|EDGE|3G|UMTS|H.DPA|CDMA/i } detect_devices::matching_driver('serial_cs', 'usbserial', @maybe_usbserial_modules); + member($_->{driver}, @maybe_usbserial_modules) and $_->{driver} = 'usbserial' foreach @serial; + #- cdc_acm can not be listed directly in network/cellular, it is already in network/isdn + @serial, detect_devices::probe_category('network/cellular'), detect_devices::matching_driver('cdc_acm'); +} +sub get_metric { 40 } + +sub get_packages { 'comgt', 'ppp' } + +sub handles_ifcfg { + my ($_class, $ifcfg) = @_; + exists $ifcfg->{CELLULAR_CID}; +} + +my @thirdparty_settings = ( + { + name => 'nozomi', + description => 'Option GlobeTrotter 3G/EDGE and FUSION+', + url => 'http://www.pharscape.org/', + kernel_module => 1, + }, + { + name => 'hso', + description => 'Option High Speed Mobile Devices', + url => 'http://www.pharscape.org/', + kernel_module => 1, + tools => { + package => 'hso-rezero', + test_file => '/usr/sbin/rezero', + }, + }, +); + +sub get_thirdparty_settings() { + \@thirdparty_settings; +} + +sub guess_hardware_settings { + my ($self) = @_; + $self->{hardware}{pin} ||= chomp_(cat_("/etc/sysconfig/network-scripts/pin-" . $self->get_interface)); +} + +sub get_interface { + my ($self) = @_; + $self->get_driver eq "hso" ? + "hso0" : + "ppp0"; +} + +sub get_tty_device { + my ($self) = @_; + + my $tty_interface = 0; + my %udev_env = map { if_(/^([^=]*)=(.*)$/, $1 => $2) } chomp_(run_program::get_stdout("udevadm info --query=property --path=$self->{device}{sysfs_device}")); + + if ($udev_env{USB_MODEM_INTERFACE}) { + my $dev_sys_path = $self->{device}->{sysfs_device}; + my $cfg = chomp_(cat_($dev_sys_path . "/bConfigurationValue")); + my $tty_usb = basename(glob_("$dev_sys_path/" . + $self->{device}->{pci_bus} . "-" . + ($self->{device}->{usb_port} + 1) . ":$cfg." . + $udev_env{USB_MODEM_INTERFACE} . "/ttyUSB*")); + if ($tty_usb) { + $tty_usb =~ s/ttyUSB//; + $tty_interface = $tty_usb; + } + } else { + # if no usb interface for tty port given, use first one + my @intfs = glob_("$self->{device}->{sysfs_device}/" . + $self->{device}->{pci_bus} . "-" . + ($self->{device}->{usb_port} + 1) . ":*"); + foreach (@intfs) { + my $tty_usb = basename(glob_("$_/tty*")); + if ($tty_usb) { + $tty_usb =~ s/tty[a-zA-Z]*//; + $tty_interface = $tty_usb; + last; + } + } + } + + $self->{device}{device} ? + "/dev/" . $self->{device}{device} : + $self->get_driver eq "nozomi" ? + "/dev/noz" . $tty_interface : + $self->get_driver eq "cdc_acm" ? + "/dev/ttyACM" . $tty_interface : + $self->get_driver eq "hso" ? + "/dev/ttyHS" . $tty_interface : + "/dev/ttyUSB" . $tty_interface; +} + +sub get_control_device { + my ($self) = @_; + my $tty_device = $self->get_tty_device; + if ($tty_device eq "/dev/ttyUSB0") { + for my $id (2, 1) { + my $usb_control_device = "/dev/ttyUSB" . $id; + return $usb_control_device if -e $usb_control_device; + } + } + $tty_device; +} + +sub network_scan_is_slow() { 1 } +sub check_hardware_is_slow() { 1 } +sub has_unique_network() { 1 } + +sub get_networks { + my ($self) = @_; + my $cmd = 'comgt -d ' . $self->get_control_device; + my ($network, $state) = `$cmd reg` =~ /^Registered on \w+ network: "(.*)",(\d+)$/m; + my ($strength) = `$cmd sig` =~ /^Signal Quality:\s+(\d+),\d+$/; + $self->probed_networks; + $self->{networks} = $network && { + $network => { + name => $network, + signal_strength => $strength * 5, + current => $state == 2, + } + }; +} + +sub get_hardware_settings { + my ($self) = @_; + [ { label => N("PIN number (4 digits). Leave empty if PIN is not required."), val => \$self->{hardware}{pin}, hidden => 1 } ]; +} + +sub check_hardware_settings { + my ($self) = @_; + if ($self->{hardware}{pin} !~ /(^$|^[0-9]{4}$)/) { + $self->{hardware}{error} = translate($wrong_pin_error); + return 0; + } + 1; +} + +sub get_peer_default_options { + my ($self) = @_; + $self->SUPER::get_peer_default_options, + "noccp", # disable CCP to avoid warning messages + "debug"; +} + +sub build_peer { + my ($self) = @_; + $self->SUPER::build_peer; + #- don't run comgt for now, it hangs on ttyUSB0 devices when run from pppd + #- $self->{access}{peer}->{init} = "comgt -d $dev < $pin_file" +} + +sub set_ppp_settings { + my ($self) = @_; + $self->{access}{no_dial} = $self->get_driver eq "hso"; + $self->{access}{cid} = 3; + + $self->{access}{at_commands} = [ + "AT+CPIN?", + # Set +CGEE to 2 + "AT+CMEE=2", + qq(AT+CGDCONT=$self->{access}{cid},"IP","$self->{access}{apn}"), + # Setup +CGEQREG (QoS, don't set it for now) + # qq(AT+CGEQREQ=3,3,64,384,0,0,2,0,"0E0","0E0",3,0,0), + # Attached to network, will return 1 + "AT+CGATT?", + if_($self->get_driver eq "hso", ""), + ]; + + $self->SUPER::set_ppp_settings; +} + +sub write_settings { + my ($self) = @_; + + my $interface = $self->get_interface; + my $pin_file = "/etc/sysconfig/network-scripts/pin-$interface"; + output_with_perm($pin_file, 0600, $self->{hardware}{pin} . "\n"); + + $self->SUPER::write_settings; +} + +sub prepare_device { + my ($self) = @_; + + my $driver = $self->get_driver; + require modules; + my $modules_conf = ref($::o) && $::o->{modules_conf} || modules::any_conf->read; + modules::load_and_configure($modules_conf, $driver, + if_($driver eq 'usbserial', join( + ' ', + "vendor=0x" . sprintf("%04x", $self->{device}{vendor}), + "product=0x" . sprintf("%04x", $self->{device}{id})))); + $modules_conf->write if !ref $::o; + sleep 2 if $driver eq 'usbserial'; +} + +sub check_device { + my ($self) = @_; + + my $dev = $self->get_tty_device; + if (! -e $dev) { + $self->{device}{error} = N("Unable to open device %s", $dev); + return; + } + + 1; +} + +sub check_hardware { + my ($self) = @_; + to_bool(run_program::rooted($::prefix, 'comgt', '>', '/dev/null', '-d', $self->get_control_device, 'PIN')); +} + +sub configure_hardware { + my ($self) = @_; + + my $device_ready = 0; + + require IPC::Open2; + require IO::Select; + require c; + use POSIX qw(:errno_h); + + my $pid = IPC::Open2::open2(my $cmd_out, my $cmd_in, 'comgt', '-d', $self->get_control_device); + common::nonblock($cmd_out); + my $selector = IO::Select->new($cmd_out); + my $already_entered_pin; + + while ($selector->can_read) { + local $_; + my $rv = sysread($cmd_out, $_, 512); + $rv == 0 and $selector->remove($cmd_out); + if (/^\s*\*\*\*SIM ERROR\*\*\*/m) { + $self->{hardware}{error} = N("Please check that your SIM card is inserted."); + last; + } elsif (/^Enter PIN number:/m) { + $self->{hardware}{pin} or last; + if ($already_entered_pin) { + $self->{hardware}{error} = translate($wrong_pin_error); + last; + } + $already_entered_pin = 1; + print $cmd_in $self->{hardware}{pin} . "\n"; + } elsif (/^ERROR entering PIN/m) { + $self->{hardware}{error} = N("You entered a wrong PIN code. +Entering the wrong PIN code multiple times may lock your SIM card!"); + last; + } elsif (/^Waiting for Registration/m) { + #- the card seems to be reset if comgt is killed right here, wait a bit + sleep 1; + #- don't wait the full scan + $device_ready = 1; + last; + } + } + kill 'TERM', $pid; + close($cmd_out); + close($cmd_in); + waitpid($pid, 0); + + $device_ready; +} + +1; diff --git a/lib/network/connection/dvb.pm b/lib/network/connection/dvb.pm new file mode 100644 index 0000000..c5f8ff6 --- /dev/null +++ b/lib/network/connection/dvb.pm @@ -0,0 +1,70 @@ +package network::connection::dvb; + +use base qw(network::connection::ethernet); + +use strict; +use common; +use modules; + +sub get_type_name() { N("DVB") } +sub get_type_description() { N("Satellite (DVB)") } +sub _get_type_icon() { 'dvb' } + +sub get_devices() { + require detect_devices; + detect_devices::probe_category("multimedia/dvb"); +} + +sub get_metric { 15 } + +sub handles_ifcfg { + my ($_class, $ifcfg) = @_; + exists $ifcfg->{DVB_ADAPTER_ID}; +} + +sub get_interface { + my ($self) = @_; + defined $self->{hardware}{adapter_id} && defined $self->{hardware}{network_demux} or return "dvb"; + 'dvb' . $self->{hardware}{adapter_id} . '_' . $self->{hardware}{network_demux}; +} + +sub get_dvb_device { + find { sysopen(undef, $_, c::O_RDWR() | c::O_NONBLOCK()) } glob("/dev/dvb/adapter*/net*"); +} + +sub load_interface_settings { + my ($self) = @_; + $self->guess_hardware_settings; #- so that matching interface settings can be loaded + $self->network::connection::load_interface_settings; + $self->{hardware}{adapter_id} = $self->{ifcfg}{DVB_ADAPTER_ID}; + $self->{hardware}{network_demux} = $self->{ifcfg}{DVB_NETWORK_DEMUX}; + $self->{hardware}{network_pid} = $self->{ifcfg}{DVB_NETWORK_PID}; +} + +sub guess_hardware_settings { + my ($self) = @_; + my $device = get_dvb_device() or return; + ($self->{hardware}{adapter_id}, $self->{hardware}{network_demux}) = $device =~ m,/dev/dvb/adapter(\d+)/net(\d+),; +} + +sub get_hardware_settings { + my ($self) = @_; + [ + { label => N("Adapter card"), val => \$self->{hardware}{adapter_id} }, + { label => N("Net demux"), val => \$self->{hardware}{network_demux} }, + { label => N("PID"), val => \$self->{hardware}{network_pid} }, + ]; +} + +sub build_ifcfg_settings { + my ($self) = @_; + my $settings = { + DVB_ADAPTER_ID => qq("$self->{hardware}{adapter_id}"), + DVB_NETWORK_DEMUX => qq("$self->{hardware}{network_demux}"), + DVB_NETWORK_PID => qq("$self->{hardware}{network_pid}"), + MII_NOT_SUPPORTED => "yes", + }; + $self->SUPER::build_ifcfg_settings($settings); +} + +1; diff --git a/lib/network/connection/ethernet.pm b/lib/network/connection/ethernet.pm new file mode 100644 index 0000000..7b76396 --- /dev/null +++ b/lib/network/connection/ethernet.pm @@ -0,0 +1,552 @@ +package network::connection::ethernet; # $Id: ethernet.pm 147431 2007-03-21 17:06:09Z blino $ + +use base qw(network::connection); + +use strict; +use common; +use network::tools; + +our @dhcp_clients = qw(dhclient dhcpcd pump dhcpxd); + +sub get_type_name() { N("Ethernet") } +sub get_type_description() { N("Wired (Ethernet)") } +sub _get_type_icon() { 'ethernet' } + +sub get_devices() { + #require list_modules; + #- FIXME: try to use list_modules::ethernet_categories() (but remove wireless stuff) + require detect_devices; + my @devices = detect_devices::probe_category('network/main|gigabit|pcmcia|tokenring|usb|firewire'); + my @lan = grep { detect_devices::is_lan_interface($_) && !detect_devices::is_wireless_interface($_) } detect_devices::get_all_net_devices(); + @devices, get_unlisted_devices(\@lan, \@devices); +} + +sub get_unlisted_devices { + my ($interfaces, $listed_devices) = @_; + my @unlisted_interfaces = sort(difference2($interfaces, [ map { device_to_interface($_) } @$listed_devices ])); + map { + my %device = %{interface_to_device($_) || +{ description => $_ }}; + $device{interface} = $_; + $device{description} = N("Virtual interface") if network::tools::is_virtual_interface($_); + \%device; + } @unlisted_interfaces; +} + +sub handles_ifcfg { + my ($_class, $ifcfg) = @_; + require detect_devices; + detect_devices::is_lan_interface($ifcfg->{DEVICE}); +} + +sub is_gigabit { + my ($self) = @_; + require list_modules; + member($self->get_driver, list_modules::category2modules('network/gigabit')); +} + +sub get_metric { + my ($self) = @_; + $self->is_gigabit ? 5 : 10; +} + +sub get_interface { + my ($self) = @_; + $self->{device}{interface} ||= device_to_interface($self->{device}); +} + +sub check_device { + my ($self) = @_; + if (!$self->get_interface) { + $self->{device}{error} = N("Unable to find network interface for selected device (using %s driver).", $self->get_driver); + return 0; + } + return 1; +} + +sub get_protocols() { + my $system_file = '/etc/sysconfig/drakx-net'; + my %global_settings = getVarsFromSh($system_file); + +{ + if_(!text2bool($global_settings{AUTOMATIC_ADDRESS}), static => N("Manual configuration")), + dhcp => N("Automatic IP (BOOTP/DHCP)"), + }; +} + +sub load_interface_settings { + my ($self) = @_; + + $self->network::connection::load_interface_settings; + $self->map_ifcfg2config_settings; +} + +sub map_ifcfg2config_settings { + my ($self) = @_; + $self->{protocol} = $self->{ifcfg}{BOOTPROTO}; + + $self->{address}{needhostname} = $self->get_ifcfg_bool('NEEDHOSTNAME'); + $self->{address}{peerdns} = $self->get_ifcfg_bool('PEERDNS'); + $self->{address}{peeryp} = $self->get_ifcfg_bool('PEERYP'); + $self->{address}{peerntpd} = $self->get_ifcfg_bool('PEERNTPD'); + + $self->{address}{dhcp_client} = $self->{ifcfg}{DHCP_CLIENT}; + $self->{address}{dhcp_hostname} = $self->{ifcfg}{DHCP_HOSTNAME}; + $self->{address}{dhcp_timeout} = $self->{ifcfg}{DHCP_TIMEOUT}; + $self->{address}{ip_address} = $self->{ifcfg}{IPADDR}; + $self->{address}{netmask} = $self->{ifcfg}{NETMASK}; + $self->{address}{gateway} = $self->{ifcfg}{GATEWAY}; + $self->{address}{dns1} = $self->{ifcfg}{DNS1} || $self->{ifcfg}{MS_DNS1}; + $self->{address}{dns2} = $self->{ifcfg}{DNS2} || $self->{ifcfg}{MS_DNS2}; + $self->{address}{domain} = $self->{ifcfg}{DOMAIN}; + + my $blacklist_ifplugd = $self->get_ifcfg_bool('MII_NOT_SUPPORTED'); + $self->{control}{use_ifplugd} = !$blacklist_ifplugd if defined $blacklist_ifplugd; + $self->{control}{ipv6_tunnel} = $self->get_ifcfg_bool('IPV6TO4INIT'); +} + +sub guess_protocol { + my ($self) = @_; + $self->{protocol} ||= 'dhcp'; +} + +sub guess_address_settings { + my ($self) = @_; + $self->{address}{dhcp_client} ||= find { -x "$::prefix/sbin/$_" } @dhcp_clients; + $self->{address}{peerdns} = 1 if !defined $self->{address}{peerdns}; + $self->{address}{peeryp} = 1 if !defined $self->{address}{peeryp}; + $self->supplement_address_settings; +} + +sub supplement_address_settings { + my ($self) = @_; + if ($self->{protocol} eq 'static' && network::network::is_ip($self->{address}{ip_address})) { + require network::network; + $self->{address}{netmask} ||= network::network::netmask($self->{address}{ip_address}); + # Bug #28033: don't guess default gateway and ns in static interfaces if + # user doesn't set one (otherwise we'll mess multi-interface systems) + # + #$self->{address}{gateway} ||= network::network::gateway($self->{address}{ip_address}); + #$self->{address}{dns1} ||= network::network::dns($self->{address}{ip_address}); + } +} + +sub get_address_settings_label { N("IP settings") } + +sub get_address_settings { + my ($self, $o_show_all) = @_; + my $auto_dns = sub { $self->{protocol} eq 'dhcp' && $self->{address}{peerdns} }; + my $not_static = sub { $self->{protocol} ne 'static' }; + my $not_dhcp = sub { $self->{protocol} ne 'dhcp' }; + [ + if_($self->{protocol} eq 'static' || $o_show_all, + { label => N("IP address"), val => \$self->{address}{ip_address}, disabled => $not_static, + focus_out => sub { + $self->supplement_address_settings if $self->can('supplement_address_settings'); + }, + help => N("Please enter the IP configuration for this machine. +Each item should be entered as an IP address in dotted-decimal +notation (for example, 1.2.3.4).") }, + { label => N("Netmask"), val => \$self->{address}{netmask}, disabled => $not_static }, + { label => N("Gateway"), val => \$self->{address}{gateway}, disabled => $not_static }, + ), + if_($self->{protocol} eq 'dhcp' || $o_show_all, + { text => N("Get DNS servers from DHCP"), val => \$self->{address}{peerdns}, type => "bool", disabled => $not_dhcp }, + ), + { label => N("DNS server 1"), val => \$self->{address}{dns1}, disabled => $auto_dns }, + { label => N("DNS server 2"), val => \$self->{address}{dns2}, disabled => $auto_dns }, + { label => N("Search domain"), val => \$self->{address}{domain}, disabled => $auto_dns, advanced => 1, + help => N("By default search domain will be set from the fully-qualified host name") }, + if_($self->{protocol} eq 'dhcp', + { label => N("DHCP client"), val => \$self->{address}{dhcp_client}, list => \@dhcp_clients, advanced => 1 }, + { label => N("DHCP timeout (in seconds)"), val => \$self->{address}{dhcp_timeout}, advanced => 1 }, + { text => N("Get YP servers from DHCP"), val => \$self->{address}{peeryp}, type => "bool", advanced => 1 }, + { text => N("Get NTPD servers from DHCP"), val => \$self->{address}{peerntpd}, type => "bool", advanced => 1 }, + { label => N("DHCP host name"), val => \$self->{address}{dhcp_hostname}, advanced => 1 }, + #- FIXME: install zcip if not checked + if_(0, { text => N("Do not fallback to Zeroconf (169.254.0.0 network)"), type => "bool", val => \$self->{address}{skip_zeroconf}, advanced => 1 }), + ), + ]; +} + +sub check_address_settings { + my ($self, $net) = @_; + + if ($self->{protocol} eq 'static') { + require network::network; + if (!network::network::is_ip($self->{address}{ip_address})) { + $self->{address}{error}{message} = N("IP address should be in format 1.2.3.4"); + $self->{address}{error}{field} = \$self->{address}{ip_address}; + return 0; + } + if (!network::network::is_ip($self->{address}{netmask})) { + $self->{address}{error}{message} = N("Netmask should be in format 255.255.224.0"); + $self->{address}{error}{field} = \$self->{address}{netmask}; + return 0; + } + if (network::network::is_ip_forbidden($self->{address}{ip_address})) { + $self->{address}{error}{message} = N("Warning: IP address %s is usually reserved!", $self->{address}{ip_address}); + $self->{address}{error}{field} = \$self->{address}{ip_address}; + return 0; + } + #- test if IP address is already used + if (my $conflict = find { text2bool($_->{ONBOOT}) && $_->{DEVICE} ne $self->get_interface && $_->{IPADDR} eq $self->{address}{ip_address} } values %{$net->{ifcfg}} ) { + # find out what connection we are conflicting with + my $conflict_device = $conflict->{DEVICE}; + + $self->{address}{error}{message} = N("%s is already used by a connection that starts on boot (%s). To use this address with this connection, first disable all other devices which use it, or configure them not to start at boot", $self->{address}{ip_address}, $conflict_device); + $self->{address}{error}{field} = \$self->{address}{ip_address}; + return 0; + } + } + + return 1; +} + +sub guess_hostname_settings { + my ($self) = @_; + $self->{address}{needhostname} = 0 if !defined $self->{address}{needhostname}; + if (!defined $self->{address}{hostname}) { + require network::network; + my $network = network::network::read_conf($::prefix . $network::network::network_file); + $self->{address}{hostname} = $network->{HOSTNAME}; + } +} + +# FIXME: add in drakroam/netcenter +sub get_hostname_settings { + my ($self) = @_; + my $auto_hostname = sub { $self->{protocol} eq 'dhcp' && $self->{address}{needhostname} }; + # configure the default hostname so the hostname setting should be more obvious to the users + $self->{address}{hostname} = 'localhost.localdomain' unless $self->{address}{hostname}; + [ + if_($self->{protocol} eq 'dhcp', + { text => N("Assign host name from DHCP server (or generate a unique one)"), val => \$self->{address}{needhostname}, type => "bool", + help => N("This will allow the server to attribute a name for this machine. If the server does not provides a valid host name, it will be generated automatically.")}, + ), + { label => N("Host name"), val => \$self->{address}{hostname}, disabled => $auto_hostname, + help => N("You should define a hostname for this machine, which will identify this PC. Note that this hostname will be shared among all network connections. If left blank, 'localhost.localdomain' will be used.")}, + ]; +} + +sub guess_control_settings { + my ($self) = @_; + + $self->network::connection::guess_control_settings($self); + + $self->{control}{onboot} = 1 if !defined $self->{control}{onboot}; + $self->{control}{use_ifplugd} = !is_ifplugd_blacklisted($self->get_driver) + if !defined $self->{control}{use_ifplugd}; +} + +sub get_control_settings { + my ($self) = @_; + [ + @{$self->network::connection::get_control_settings}, + { text => N("Network Hotplugging"), val => \$self->{control}{use_ifplugd}, type => "bool", + #- FIXME: force ifplugd if wireless roaming is enabled + disabled => sub { $self->{control}{force_ifplugd} }, advanced => 1, }, + #- FIXME: $need_network_restart = $ipv6_tunnel ^ text2bool($ethntf->{IPV6TO4INIT}); + { text => N("Enable IPv6 to IPv4 tunnel"), val => \$self->{control}{ipv6_tunnel}, type => "bool", advanced => 1 }, + ]; +} + +sub install_packages { + my ($self, $in) = @_; + if ($self->{protocol} eq 'dhcp') { + install_dhcp_client($in, $self->{address}{dhcp_client}) or return; + } + 1; +} + +sub build_ifcfg_settings { + my ($self, $o_options) = @_; + my $settings = put_in_hash($o_options, { + BOOTPROTO => $self->{protocol}, + IPADDR => $self->{address}{ip_address}, + GATEWAY => $self->{address}{gateway}, + NETMASK => $self->{address}{netmask}, + NEEDHOSTNAME => bool2yesno($self->{address}{needhostname}), + PEERYP => bool2yesno($self->{address}{peeryp}), + PEERDNS => bool2yesno($self->{address}{peerdns}), + RESOLV_MODS => bool2yesno(!$self->{address}{peerdns} && ($self->{address}{dns1} || $self->{address}{dns2})), + PEERNTPD => bool2yesno($self->{address}{peerntpd}), + DHCP_CLIENT => $self->{address}{dhcp_client}, + DHCP_HOSTNAME => $self->{address}{dhcp_hostname}, + DHCP_TIMEOUT => $self->{address}{dhcp_timeout}, + MII_NOT_SUPPORTED => bool2yesno(!$self->{control}{use_ifplugd}), + IPV6INIT => bool2yesno($self->{control}{ipv6_tunnel}), + IPV6TO4INIT => bool2yesno($self->{control}{ipv6_tunnel}), + DNS1 => $self->{address}{dns1}, + DNS2 => $self->{address}{dns2}, + DOMAIN => $self->{address}{domain}, + LINK_DETECTION_DELAY => $self->get_link_detection_delay, + }); + $self->network::connection::build_ifcfg_settings($settings); +} + +sub write_settings { + my ($self, $o_net, $o_modules_conf) = @_; + if ($o_modules_conf) { + $o_modules_conf->set_alias($self->get_interface, $self->get_driver); + if ($self->{device}{sysfs_device}) { + my $modalias = chomp_(cat_($self->{device}{sysfs_device} . "/modalias")); + $o_modules_conf->set_alias($modalias, $self->get_driver) if $modalias; + } + } + $self->SUPER::write_settings($o_net, $o_modules_conf); + # update udev configuration + update_udev_net_config(); +} + +sub get_status_message { + my ($self, $status) = @_; + my $interface = $self->get_interface; + { + link_up => N("Link beat detected on interface %s", $interface), + link_down => N("Link beat lost on interface %s", $interface), + map { ( + "$_->[0]_request" => N("Requesting a network address on interface %s (%s protocol)...", $interface, $_->[1]), + "$_->[0]_success" => N("Got a network address on interface %s (%s protocol)", $interface, $_->[1]), + "$_->[0]_failure" => N("Failed to get a network address on interface %s (%s protocol)", $interface, $_->[1]), + ) } ([ 'dhcp', 'DHCP' ], [ 'zcip', 'ZeroConf' ]), + }->{$status} || $self->network::connection::get_status_message($status); +} + +use c; +use detect_devices; +use common; +use run_program; + +sub install_dhcp_client { + my ($in, $client) = @_; + my %packages = ( + "dhclient" => "dhcp-client", + ); + #- use default dhcp client if none is provided + $client ||= $dhcp_clients[0]; + $client = $packages{$client} if exists $packages{$client}; + $in->do_pkgs->ensure_is_installed($client, undef, 1); +} + +my @hwaddr_fields = qw(pci_domain pci_bus pci_device pci_function); + +sub are_same_HwIDs { + my ($device1, $device2) = @_; + every { $device1->{$_} == $device2->{$_} } @hwaddr_fields; +} + +sub parse_hwaddr { + my ($hw_addr) = @_; + return if !$hw_addr; + my %device; + @device{@hwaddr_fields} = map { hex($_) } ($hw_addr =~ /([0-9a-f]+):([0-9a-f]+):([0-9a-f]+)\.([0-9a-f]+)/); + (every { defined $_ } keys %device) ? \%device : undef; +} + +sub mapIntfToDevice { + my ($interface) = @_; + my $hw_addr = c::getHwIDs($interface); + return {} if $hw_addr =~ /^usb/; + my $device = parse_hwaddr($hw_addr); + $device ? grep { are_same_HwIDs($_, $device) } detect_devices::probeall() : {}; +} + +sub device_matches_interface_HwIDs { + my ($device, $interface) = @_; + my $hw_addr = c::getHwIDs($interface); + $hw_addr =~ /^usb/ and return; + my ($device2) = parse_hwaddr($hw_addr); + return if !$device2; + are_same_HwIDs($device, $device2); +} + +sub get_interface_sysfs_path { + my ($interface) = @_; + $interface = network::tools::get_real_interface($interface); + my $dev_path = "/sys/class/net/$interface/device"; + my $bus = detect_devices::get_sysfs_field_from_link($dev_path, "subsystem"); + if ($bus eq 'ieee1394') { + my $child = first(glob("$dev_path/host_id/*-*")); + $dev_path = $child if $child; + } + $dev_path; +} + +sub get_interface_ids { + my ($interface) = @_; + detect_devices::get_ids_from_sysfs_device(get_interface_sysfs_path($interface)); +} + +sub device_matches_interface { + my ($device, $interface) = @_; + detect_devices::device_matches_sysfs_ids($device, get_interface_ids($interface)); +} + +sub device_to_interface { + my ($device) = @_; + my @all_interfaces = detect_devices::get_net_interfaces(); + my ($real, $other) = partition { network::tools::is_real_interface($_) } @all_interfaces; + find { + device_matches_interface_HwIDs($device, $_) || + device_matches_interface($device, $_); + } @$real, @$other; +} + +sub interface_to_device { + my ($interface) = @_; + my $sysfs_ids = get_interface_ids($interface); + find { detect_devices::device_matches_sysfs_ids($_, $sysfs_ids) } detect_devices::probeall(); +} + +sub interface_to_driver { + my ($interface) = @_; + my $dev_path = get_interface_sysfs_path($interface); + #- FIXME: use $bus and move in get_interface_sysfs_path if possible + my $child = -f "$dev_path/idVendor" && first(glob("$dev_path/*-*:*.*")); + $dev_path = $child if -f "$child/driver/module"; + detect_devices::get_sysfs_field_from_link($dev_path, 'driver/module'); +} + +# return list of [ intf_name, module, device_description ] tuples such as: +# [ "eth0", "3c59x", "3Com Corporation|3c905C-TX [Fast Etherlink]" ] +# +# this function try several method in order to get interface's driver and description in order to support both: +# - hotplug managed devices (USB, firewire) +# - special interfaces (IP aliasing, VLAN) +sub get_eth_cards { + my ($o_modules_conf) = @_; + + detect_devices::probeall_update_cache(); + my @all_cards = detect_devices::get_lan_interfaces(); + + my @devs = detect_devices::pcmcia_probe(); + my $saved_driver; + # compute device description and return (interface, driver, description) tuples: + return map { + my $interface = $_; + my $description; + # 1) get interface's driver through ETHTOOL ioctl: + my ($a, $detected_through_ethtool); + $a = c::getNetDriver($interface); + if ($a) { + $detected_through_ethtool = 1; + } elsif ($o_modules_conf) { + # 2) get interface's driver through module aliases: + $a = $o_modules_conf->get_alias($interface); + } + + # workaround buggy drivers that returns a bogus driver name for the GDRVINFO command of the ETHTOOL ioctl: + my %fixes = ( + "p80211_prism2_cs" => 'prism2_cs', + "p80211_prism2_pci" => 'prism2_pci', + "p80211_prism2_usb" => 'prism2_usb', + "ip1394" => "eth1394", + "DL2K" => "dl2k", + "orinoco" => undef, #- should be orinoco_{cs,nortel,pci,plx,tmd} + "hostap" => undef, #- should be hostap_{cs,pci,plx} + ); + if (exists $fixes{$a}) { + $a = $fixes{$a}; + $a or undef $detected_through_ethtool; + } + + # 3) try to match a PCMCIA device for device description: + if (my $b = find { $_->{device} eq $interface } @devs) { # PCMCIA case + $a = $b->{driver}; + $description = $b->{description}; + } else { + # 4) try to lookup a device by hardware address for device description: + # maybe should have we try sysfs first for robustness? + my @devices = mapIntfToDevice($interface); + ($description) = $devices[0]{description} if @devices; + } + # 5) try to match a device through sysfs for driver & device description: + # (eg: ipw2100 driver for intel centrino do not support ETHTOOL) + if (!$description || !$a) { + my $drv = interface_to_driver($interface); + $a = $drv if $drv && !$detected_through_ethtool; + my $card = interface_to_device($interface); + $description ||= $card->{description} if $card; + } + # 6) try to match a device by driver for device description: + # (eg: madwifi, ndiswrapper, ...) + if (!$description) { + my @cards = grep { $_->{driver} eq ($a || $saved_driver) } detect_devices::probeall(); + $description = $cards[0]{description} if @cards == 1; + } + $a and $saved_driver = $a; # handle multiple cards managed by the same driver + [ $interface, $saved_driver, if_($description, $description) ]; + } @all_cards; +} + +sub get_eth_cards_names { + my (@all_cards) = @_; + map { $_->[0] => join(': ', $_->[0], $_->[2]) } @all_cards; +} + +#- returns (link_type, mac_address) +sub get_eth_card_mac_address { + my ($intf) = @_; + #- don't look for 6 bytes addresses only because of various non-standard MAC addresses + `$::prefix/sbin/ip -o link show $intf 2>/dev/null` =~ m|.*link/(\S+)\s((?:[0-9a-f]{2}:?)+)\s|; +} + +#- write interfaces MAC address in iftab +sub update_iftab() { + #- skip aliases and vlan interfaces + foreach my $intf (grep { network::tools::is_real_interface($_) } detect_devices::get_lan_interfaces()) { + my ($link_type, $mac_address) = get_eth_card_mac_address($intf) or next; + #- do not write zeroed MAC addresses in iftab, it confuses ifrename + $mac_address =~ /^[0:]+$/ and next; + # ifrename supports alsa IEEE1394, EUI64 and IRDA + member($link_type, 'ether', 'ieee1394', 'irda', '[27]') or next; + substInFile { + s/^$intf\s+.*\n//; + s/^.*\s+$mac_address\n//; + $_ .= qq($intf mac $mac_address\n) if eof; + } "$::prefix/etc/iftab"; + } +} + +sub update_udev_net_config() { + my $lib = arch() =~ /x86_64/ ? "lib64" : "lib"; + my $net_name_helper = "/lib/udev/write_net_rules"; + my $udev_net_config = "$::prefix/etc/udev/rules.d/70-persistent-net.rules"; + my @old_config = cat_($udev_net_config); + #- skip aliases and vlan interfaces + foreach my $intf (grep { network::tools::is_real_interface($_) } detect_devices::get_lan_interfaces()) { + (undef, my $mac_address) = get_eth_card_mac_address($intf) or next; + #- do not write zeroed MAC addresses + $mac_address =~ /^[0:]+$/ and next; + #- skip already configured addresses + any { !/^\s*#/ && /"$mac_address"/ } @old_config and next; + my $type = cat_("/sys/class/net/$intf/type") =~ /^\d+$/; + local $ENV{MATCHIFTYPE} = $type if $type; + local $ENV{INTERFACE} = $intf; + local $ENV{MATCHADDR} = $mac_address; + local $ENV{COMMENT} = "Drakx-net rule for $intf ($mac_address)"; + run_program::rooted($::prefix, $net_name_helper, '>', '/dev/null', $mac_address); + } +} + +# automatic net aliases configuration +sub configure_eth_aliases { + my ($modules_conf) = @_; + foreach my $card (get_eth_cards($modules_conf)) { + $modules_conf->set_alias($card->[0], $card->[1]); + } + $::isStandalone and $modules_conf->write; + update_iftab(); + update_udev_net_config(); +} + +sub get_link_detection_delay { + my ($self) = @_; + member($self->get_driver, qw(b44 forcedeth r8169 skge sky2 tg3 via_velocity e1000e)) && 6; +} + +sub is_ifplugd_blacklisted { + my ($module) = @_; + !$module; +} + +1; diff --git a/lib/network/connection/isdn.pm b/lib/network/connection/isdn.pm new file mode 100644 index 0000000..1b8debc --- /dev/null +++ b/lib/network/connection/isdn.pm @@ -0,0 +1,230 @@ +package network::connection::isdn; + +use base qw(network::connection); + +use strict; +use common; + +sub get_type_name { N("ISDN") } +sub _get_type_icon { 'isdn' } + +sub get_devices { + require modules; + #- FIXME: module alias should be written when config is written only + @{detect_backend(modules::any_conf->read)}; +} +sub get_metric { 30 } + +sub get_up_timeout { 20 } + +use network::connection::isdn::consts; +use modules; +use run_program; +use log; +use network::tools; +use services; + +sub apply_config { + my ($in, $isdn) = @_; + + $isdn = find_capi_card($isdn) if $isdn->{driver} eq "capidrv"; + unload_connection($isdn); + install_packages($isdn, $in); + write_settings($isdn); + write_capi_conf($isdn) if $isdn->{driver} eq "capidrv"; + prepare_connection($isdn); +} + +sub write_settings { + my ($isdn) = @_; + + output_with_perm("$::prefix/etc/isdn/profile/link/myisp", 0600, + qq( +I4L_USERNAME="$isdn->{login}" +I4L_SYSNAME="" +I4L_LOCALMSN="$isdn->{phone_in}" +I4L_REMOTE_OUT="$isdn->{phone_out}" +I4L_DIALMODE="$isdn->{dialing_mode}" +I4L_IDLETIME="$isdn->{huptimeout}" +) . if_($isdn->{speed} =~ /128/, 'SLAVE="ippp1" +')); + output "$::prefix/etc/isdn/profile/card/mycard", + qq( +I4L_MODULE="$isdn->{driver}" +I4L_TYPE="$isdn->{type}" +I4L_IRQ="$isdn->{irq}" +I4L_MEMBASE="$isdn->{mem}" +I4L_PORT="$isdn->{io}" +I4L_IO0="$isdn->{io0}" +I4L_IO1="$isdn->{io1}" +I4L_ID="HiSax" +I4L_FIRMWARE="$isdn->{firmware}" +I4L_PROTOCOL="$isdn->{protocol}" +); + + output "$::prefix/etc/ppp/ioptions", + "lock +usepeerdns +defaultroute +"; + + network::tools::write_secret_backend($isdn->{login}, $isdn->{passwd}); + + 1; +} + +sub write_capi_conf { + my ($capi_card) = @_; + my $capi_conf; + my $firmware = $capi_card->{firmware} || '-'; + if ($capi_card->{driver} eq "fcclassic") { + $capi_conf = "fcclassic - - 0x300 5 - -\n# adjust IRQ and IO !! ^^^^^ ^^^\n"; + } elsif ($capi_card->{driver} eq "fcpnp") { + $capi_conf = "fcpnp - - 0x300 5 - -\n# adjust IRQ and IO !! ^^^^^ ^^^\n"; + } else { + $capi_conf = "$capi_card->{driver} $firmware - - - - -\n"; + } + + output("$::prefix/etc/capi.conf", $capi_conf); +} + +sub unload_connection { + my ($isdn) = @_; + require services; + services::stop("isdn4linux"); #- to be stopped before capi is loaded + if ($isdn->{driver} eq "capidrv") { + #- stop capi4linux before new config is written so that it can unload the driver + services::stop("capi4linux"); + } +} + +sub install_packages { + my ($isdn, $in) = @_; + + $in->do_pkgs->install( + 'isdn4k-utils', + $isdn->{driver} eq "capidrv" ? + (if_(!modules::module_is_available($isdn->{driver}), @{$isdn->{packages}}), + if_($isdn->{firmware} && ! -f "$::prefix/usr/lib/isdn/$isdn->{firmware}", "$isdn->{driver}-firmware")) + : + ('isdn4net', if_($isdn->{speed} =~ /128/, 'ibod')) + ); +} + +sub prepare_connection { + my ($isdn) = @_; + if ($isdn->{driver} eq "capidrv") { + services::enable('capi4linux'); + } else { + services::disable('capi4linux'); + } + services::enable('isdn4linux'); +} + +sub read_config { + my ($isdn) = @_; + + my %match = (I4L_USERNAME => 'login', + I4L_LOCALMSN => 'phone_in', + I4L_REMOTE_OUT => 'phone_out', + I4L_DIALMODE => 'dialing_mode', + I4L_IDLETIME => 'huptimeout', + I4L_MODULE => 'driver', + I4L_TYPE => 'type', + I4L_IRQ => 'irq', + I4L_MEMBASE => 'mem', + I4L_PORT => 'io', + I4L_IO0 => 'io0', + I4L_IO1 => 'io1', + I4L_FIRMWARE => 'firmware'); + foreach ('link/myisp', 'card/mycard') { + my %conf = getVarsFromSh("$::prefix/etc/isdn/profile/$_"); + foreach (keys %conf) { + $isdn->{$match{$_}} = $conf{$_} if $match{$_} && $conf{$_}; + } + } + + $isdn->{passwd} = network::tools::passwd_by_login($isdn->{login}); +} + +my $file = "$ENV{SHARE_PATH}/ldetect-lst/isdn.db"; +$file = "$::prefix$file" if !-e $file; + +sub get_info_providers_backend { + my ($isdn, $name) = @_; + $name eq N("Unlisted - edit manually") and return; + foreach (catMaybeCompressed($file)) { + chop; + my ($name_, $phone, $real, $dns1, $dns2) = split '=>'; + if ($name eq $name_) { + @$isdn{qw(user_name phone_out DOMAINNAME2 dnsServer3 dnsServer2)} = + ((split(/\|/, $name_))[2], $phone, $real, $dns1, $dns2); + } + } +} + +sub read_providers_backend() { map { /(.*?)=>/ } catMaybeCompressed($file) } + + +sub detect_backend { + my ($modules_conf) = @_; + my @isdn; + require detect_devices; + each_index { + my $c = $_; + my $isdn = { map { $_ => $c->{$_} } qw(description vendor id driver card_type type) }; + $isdn->{intf_id} = $::i; + $isdn->{$_} = sprintf("%0x", $isdn->{$_}) foreach 'vendor', 'id'; + $isdn->{card_type} = $c->{bus} eq 'USB' ? 'usb' : 'pci'; + $isdn->{description} =~ s/.*\|//; +# $c->{options} !~ /id=HiSax/ && $isdn->{driver} eq "hisax" and $c->{options} .= " id=HiSax"; + if ($c->{options} !~ /protocol=/ && $isdn->{protocol} =~ /\d/) { + $modules_conf->set_options($c->{driver}, $c->{options} . " protocol=" . $isdn->{protocol}); + } + $c->{options} =~ /protocol=(\d)/ and $isdn->{protocol} = $1; + push @isdn, $isdn; + } detect_devices::probe_category('network/isdn'); + \@isdn; +} + +sub get_cards_by_type { + my ($isdn_type) = @_; + grep { $_->{card} eq $isdn_type } @isdndata; +} + + +sub get_cards() { + my %buses = ( + isa => N("ISA / PCMCIA") . "/" . N("I do not know"), + pci => N("PCI"), + usb => N("USB"), + ); + # pmcia alias (we should really split up pcmcia from isa in isdn db): + $buses{pcmcia} = $buses{isa}; + + map { $buses{$_->{card}} . "|" . $_->{description} => $_ } @isdndata; +} + + +sub find_capi_card { + my ($isdn) = @_; + find { + hex($isdn->{vendor}) == $_->{vendor} && hex($isdn->{id}) == $_->{id}; + } @isdn_capi; +} + +sub get_capi_card { + my ($in, $isdn) = @_; + + my $capi_card = find_capi_card($isdn) or return; + + #- check if the capi driver is available + unless (modules::module_is_available($capi_card->{driver}) || ($capi_card->{packages} = $in->do_pkgs->check_kernel_module_packages($capi_card->{driver}))) { + log::explanations("a capi driver ($capi_card->{driver}) exists to replace $isdn->{driver}, but it is not installed and no packages provide it"); + return; + } + + $capi_card; +} + +1; diff --git a/lib/network/connection/isdn/consts.pm b/lib/network/connection/isdn/consts.pm new file mode 100644 index 0000000..a53ddbe --- /dev/null +++ b/lib/network/connection/isdn/consts.pm @@ -0,0 +1,460 @@ +package network::connection::isdn::consts; # $Id: consts.pm 54070 2006-08-07 17:34:38Z blino $ +use vars qw(@ISA @EXPORT); +@ISA = qw(Exporter); +@EXPORT = qw(@isdndata @isdn_capi); + +our @isdndata = + ( + { description => "Teles|16.0", #1 irq, mem, io + driver => 'hisax', + type => '1', + irq => '5', + mem => '0xd000', + io => '0xd80', + card => 'isa', + }, + { description => "Teles|8.0", #2 irq, mem + driver => 'hisax', + type => '2', + irq => '9', + mem => '0xd800', + card => 'isa', + }, + { description => "Teles|16.3 (ISA non PnP)", #3 irq, io + driver => 'hisax', + type => '3', + irq => '9', + io => '0xd80', + card => 'isa', + }, + { description => "Teles|16.3c (ISA PnP)", #14 irq, io + driver => 'hisax', + type => '14', + irq => '9', + io => '0xd80', + card => 'isa', + }, + { description => "Creatix/Teles|Generic (ISA PnP)", #4 irq, io0 (ISAC), io1 (HSCX) + driver => 'hisax', + type => '4', + irq => '5', + io0 => '0x0000', + io1 => '0x0000', + card => 'isa', + }, + { description => "Teles|generic", #21 no parameter + driver => 'hisax', + type => '21', + card => 'pci', + }, + { description => "Teles|16.3 (PCMCIA)", #8 irq, io + driver => 'hisax', + type => '8', + irq => '', + io => '0x', + card => 'isa', + }, + { description => "Teles|S0Box", #25 irq, io (of the used lpt port) + driver => 'hisax', + type => '25', + irq => '7', + io => '0x378', + card => 'isa', + }, + { description => "ELSA|PCC/PCF cards", #6 io or nothing for autodetect (the io is required only if you have n>1 ELSA|card) + driver => 'hisax', + type => '6', + io => "", + card => 'isa', + }, + { description => "ELSA|Quickstep 1000", #7 irq, io (from isapnp setup) + driver => 'hisax', + type => '7', + irq => '5', + io => '0x300', + card => 'isa', + }, + { description => "ELSA|Quickstep 1000", #18 no parameter + driver => 'hisax', + type => '18', + card => 'pci', + }, + { description => "ELSA|Quickstep 3000", #18 no parameter + driver => 'hisax', + type => '18', + card => 'pci', + }, + { description => "ELSA|generic (PCMCIA)", #10 irq, io (set with card manager) + driver => 'hisax', + type => '10', + irq => '', + io => '0x', + card => 'isa', + }, + { description => "ELSA|MicroLink (PCMCIA)", #10 irq, io (set with card manager) + driver => 'elsa_cs', + card => 'isa', + }, + { description => "ITK|ix1-micro Rev.2", #9 irq, io + driver => 'hisax', + type => '9', + irq => '9', + io => '0xd80', + card => 'isa', + }, + { description => "Eicon.Diehl|Diva (ISA PnP)", #11 irq, io + driver => 'hisax', + type => '11', + irq => '9', + io => '0x180', + card => 'isa', + }, + { description => "Eicon.Diehl|Diva 20", #11 no parameter + driver => 'hisax', + type => '11', + card => 'pci', + }, + { description => "Eicon.Diehl|Diva 20PRO", #11 no parameter + driver => 'hisax', + type => '11', + card => 'pci', + }, + { description => "Eicon.Diehl|Diva 20_U", #11 no parameter + driver => 'hisax', + type => '11', + card => 'pci', + }, + { description => "Eicon.Diehl|Diva 20PRO_U", #11 no parameter + driver => 'hisax', + type => '11', + card => 'pci', + }, + { description => "ASUS|COM ISDNLink", #12 irq, io (from isapnp setup) + driver => 'hisax', + type => '12', + irq => '5', + io => '0x200', + card => 'isa', + }, + { description => "ASUS|COM ISDNLink", + driver => 'hisax', + type => '35', + card => 'pci', + }, + { description => "DynaLink|Any", + driver => 'hisax', + type => '12', + card => 'pci', + }, + { description => "DynaLink|IS64PH, ASUSCOM", #36 + driver => 'hisax', + type => '36', + card => 'pci', + }, + { description => "HFC|2BS0 based cards", #13 irq, io + driver => 'hisax', + type => '13', + irq => '9', + io => '0xd80', + card => 'isa', + }, + { description => "HFC|2BDS0", #35 none + driver => 'hisax', + type => '35', + card => 'pci', + }, + { description => "HFC|2BDS0 S+, SP (PCMCIA)", #37 irq,io (pcmcia must be set with cardmgr) + driver => 'hisax', + type => '37', + card => 'isa', + }, + { description => "Sedlbauer|Speed Card", #15 irq, io + driver => 'hisax', + type => '15', + irq => '9', + io => '0xd80', + card => 'isa', + }, + { description => "Sedlbauer|PC/104", #15 irq, io + driver => 'hisax', + type => '15', + irq => '9', + io => '0xd80', + card => 'isa', + }, + { description => "Sedlbauer|Speed Card", #15 no parameter + driver => 'hisax', + type => '15', + card => 'pci', + }, + { description => "Sedlbauer|Speed Star (PCMCIA)", #22 irq, io (set with card manager) + driver => 'sedlbauer_cs', + card => 'isa', + }, + { description => "Sedlbauer|Speed Fax+ (ISA Pnp)", #28 irq, io (from isapnp setup) + driver => 'hisax', + type => '28', + irq => '9', + io => '0xd80', + card => 'isa', + firmware => '/usr/lib/isdn/ISAR.BIN', + }, + { description => "Sedlbauer|Speed Fax+", #28 no parameter + driver => 'hisax', + type => '28', + card => 'pci', + firmware => '/usr/lib/isdn/ISAR.BIN', + }, + { description => "USR|Sportster internal", #16 irq, io + driver => 'hisax', + type => '16', + irq => '9', + io => '0xd80', + card => 'isa', + }, + { description => "Generic|MIC card", #17 irq, io + driver => 'hisax', + type => '17', + irq => '9', + io => '0xd80', + card => 'isa', + }, + { description => "Compaq|ISDN S0 card", #19 irq, io0, io1, io (from isapnp setup io=IO2) + driver => 'hisax', + type => '19', + irq => '5', + io => '0x0000', + io0 => '0x0000', + io1 => '0x0000', + card => 'isa', + }, + { description => "Generic|NETjet card", #20 no parameter + driver => 'hisax', + type => '20', + card => 'pci', + }, + { description => "Dr. Neuhaus|Niccy (ISA PnP)", #24 irq, io0, io1 (from isapnp setup) + driver => 'hisax', + type => '24', + irq => '5', + io0 => '0x0000', + io1 => '0x0000', + card => 'isa', + }, + { description => "Dr. Neuhaus|Niccy", ##24 no parameter + driver => 'hisax', + type => '24', + card => 'pci', + }, + { description => "AVM|A1 (Fritz) (ISA non PnP)", #5 irq, io + driver => 'hisax', + type => '5', + irq => '10', + io => '0x300', + card => 'isa', + }, + { description => "AVM|ISA Pnp generic", #27 irq, io (from isapnp setup) + driver => 'hisax', + type => '27', + irq => '5', + io => '0x300', + card => 'isa', + }, + { description => "AVM|A1 (Fritz) (PCMCIA)", #26 irq, io (set with card manager) + driver => 'hisax', + type => '26', + irq => '', + card => 'isa', + }, + { description => "AVM|PCI (Fritz!)", #27 no parameter + driver => 'hisax', + type => '27', + card => 'pci', + }, + { description => "AVM|B1", + driver => 'b1pci', + card => 'pci', + }, + { description => "Siemens|I-Surf 1.0 (ISA Pnp)", #29 irq, io, memory (from isapnp setup) + driver => 'hisax', + type => '29', + irq => '9', + io => '0xd80', + mem => '0xd000', + card => 'isa', + }, + { description => "ACER|P10 (ISA Pnp)", #30 irq, io (from isapnp setup) + driver => 'hisax', + type => '30', + irq => '5', + io => '0x300', + card => 'isa', + }, + { description => "HST|Saphir (ISA Pnp)", #31 irq, io + driver => 'hisax', + type => '31', + irq => '5', + io => '0x300', + card => 'isa', + }, + { description => "Telekom|A4T", #32 none + driver => 'hisax', + type => '32', + card => 'pci', + }, + { description => "Scitel|Quadro", #33 subcontroller (4*S0, subctrl 1...4) + driver => 'hisax', + type => '33', + card => 'pci', + }, + { description => "Gazel|ISDN cards", #34 irq,io + driver => 'hisax', + type => '34', + irq => '5', + io => '0x300', + card => 'isa', + }, + { description => "Gazel|Gazel ISDN cards", #34 none + driver => 'hisax', + type => '34', + card => 'pci', + }, + { description => "Winbond|W6692 and Winbond based cards", #36 none + driver => 'hisax', + type => '36', + card => 'pci', + }, + { description => "BeWAN|R834", + driver => 'hisax_st5481', + type => '99', + card => 'usb', + }, + { description => "Gazel|128", + driver => 'hisax_st5481', + type => '99', + card => 'usb', + }, + ); + +#- cards than can be used with capi drivers +our @isdn_capi = + ( + { + vendor => 0x1131, + id => 0x5402, + description => 'AVM Audiovisuelles|Fritz DSL ISDN/DSL Adapter', + bus => 'PCI', + driver => 'fcdsl', + firmware => 'fdslbase.bin' + }, + { + vendor => 0x1244, + id => 0x0a00, + description => 'AVM Audiovisuelles|A1 ISDN Adapter [Fritz] CAPI', + bus => 'PCI', + driver => 'fcpci' + }, + { + vendor => 0x1244, + id => 0x0e00, + description => 'AVM Audiovisuelles|A1 ISDN Adapter [Fritz] CAPI', + bus => 'PCI', + driver => 'fcpci' + }, + { + vendor => 0x1244, + id => 0x0f00, + description => 'AVM Audiovisuelles|Fritz DSL ISDN/DSL Adapter', + bus => 'PCI', + driver => 'fcdsl', + firmware => 'fdslbase.bin' + }, + { + vendor => 0x1244, + id => 0x2700, + description => 'AVM Audiovisuelles|Fritz!Card DSL SL', + bus => 'PCI', + driver => 'fcdslsl', + firmware => 'fdssbase.bin' + }, + { + vendor => 0x1244, + id => 0x2900, + description => 'AVM Audiovisuelles|Fritz DSL Ver. 2.0', + bus => 'PCI', + driver => 'fcdsl2', + firmware => 'fds2base.bin' + }, + { + vendor => 0x057c, + id => 0x0c00, + description => 'AVM GmbH|FritzCard USB ISDN TA', + bus => 'USB', + driver => 'fcusb' + }, + { + vendor => 0x057c, + id => 0x1000, + description => 'AVM GmbH|FritzCard USB 2 Ver. 2.0 ISDN TA', + bus => 'USB', + driver => 'fcusb2', + firmware => 'fus2base.frm' + }, + { + vendor => 0x057c, + id => 0x1900, + description => 'AVM GmbH|FritzCard USB 2 Ver. 3.0 ISDN TA', + bus => 'USB', + driver => 'fcusb2', + firmware => 'fus3base.frm' + }, + { + vendor => 0x057c, + id => 0x2000, + description => 'AVM GmbH|Fritz X USB ISDN TA', + bus => 'USB', + driver => 'fxusb' + }, + { + vendor => 0x057c, + id => 0x2300, + description => 'AVM GmbH|FtitzCard USB DSL ISDN TA/ DSL Modem', + bus => 'USB', + driver => 'fcdslusb', + firmware => 'fdsubase.frm' + }, + { + vendor => 0x057c, + id => 0x2800, + description => 'AVM GmbH|Fritz X USB OEM ISDN TA', + bus => 'USB', + driver => 'fxusb_CZ' + }, + { + vendor => 0x057c, + id => 0x3000, + description => 'AVM GmbH|FtitzCard USB DSL SL USB', + bus => 'USB', + driver => 'fcdslusba', + firmware => 'fdlabase.frm' + }, + { + vendor => 0x057c, + id => 0x3500, + description => 'AVM GmbH|FtitzCard USB DSL SL USB Analog', + bus => 'USB', + driver => 'fcdslslusb', + firmware => 'fdlubase.frm', + }, + { + vendor => 0x057c, + id => 0x3600, + description => 'AVM FRITZ!Card DSL USB v2.0', + bus => 'USB', + driver => 'fcdslusb2', + firmware => 'fds2base.frm', + }, + ); + + +1; diff --git a/lib/network/connection/pots.pm b/lib/network/connection/pots.pm new file mode 100644 index 0000000..22299f6 --- /dev/null +++ b/lib/network/connection/pots.pm @@ -0,0 +1,133 @@ +package network::connection::pots; + +use base qw(network::connection::ppp); + +use strict; +use common; + +sub get_type_name { + #-PO: POTS means "Plain old telephone service" + N("POTS"); +} +sub get_type_description { + #-PO: POTS means "Plain old telephone service" + #-PO: remove it if it doesn't have an equivalent in your language + #-PO: for example, in French, it can be translated as "RTC" + N("Analog telephone modem (POTS)"); +} +sub _get_type_icon { 'potsmodem' } +sub get_metric { 50 } + +sub handles_ifcfg { + my ($_class, $ifcfg) = @_; + $ifcfg->{DEVICE} =~ /^ppp/ && exists $ifcfg->{MODEMPORT}; +} + +sub get_devices { + require detect_devices; + require modules; + #- FIXME: module alias should be written when config is written only + #detect_devices::getModem(modules::any_conf->read); + (); +} + +my @thirdparty_settings = ( + { + matching => qr/^Hcf:/, + description => 'HCF 56k Modem', + url => 'http://www.linuxant.com/drivers/hcf/', + name => 'hcfpcimodem', + kernel_module => { + test_file => 'hcfpciengine', + }, + tools => { + test_file => '/usr/sbin/hcfpciconfig', + }, + device => '/dev/ttySHCF0', + post => '/usr/sbin/hcfpciconfig --auto', + restart_service => 'hcfpci', + }, + + { + matching => qr/^Hsf:/, + description => 'HSF 56k Modem', + url => 'http://www.linuxant.com/drivers/hsf/', + name => 'hsfmodem', + kernel_module => { + test_file => 'hsfengine', + }, + tools => { + test_file => '/usr/sbin/hsfconfig', + }, + device => '/dev/ttySHSF0', + post => '/usr/sbin/hsfconfig --auto', + restart_service => 'hsf', + }, + + { + matching => qr/^LT:/, + description => 'LT WinModem', + url => 'http://www.heby.de/ltmodem/', + name => 'ltmodem', + kernel_module => 1, + tools => { + test_file => '/etc/devfs/conf.d/ltmodem.conf', + }, + device => '/dev/ttyS14', + links => [ + 'http://linmodems.technion.ac.il/Ltmodem.html', + 'http://linmodems.technion.ac.il/packages/ltmodem/', + ], + }, + + { + matching => [ list_modules::category2modules('network/slmodem') ], + description => 'Smartlink WinModem', + url => 'http://linmodems.technion.ac.il/resources.html#smartlink', + name => 'slmodem', + kernel_module => 1, + tools => { + test_file => '/usr/sbin/slmodemd', + }, + device => '/dev/ttySL0', + post => sub { + my ($driver) = @_; + addVarsInSh("$::prefix/etc/sysconfig/slmodemd", { SLMODEMD_MODULE => $driver }); + }, + restart_service => "slmodemd", + }, + + { + name => 'sm56', + description => 'Motorola SM56 WinModem', + url => 'http://www.motorola.com/softmodem/driver.htm#linux', + kernel_module => { + package => 'sm56', + }, + no_distro_package => 1, + device => '/dev/sm56', + }, +); + +sub get_thirdparty_settings { \@thirdparty_settings } + +sub get_providers { + my $db_path = "/usr/share/apps/kppp/Provider"; + #$in->do_pkgs->ensure_is_installed('kdenetwork-kppp-provider', $db_path); + my $separator = "|"; + my %providers; + foreach (all($::prefix . $db_path)) { + s!_! !g; + my $country = $_; + my $t_country = translate($country); + my $country_root = $::prefix . $db_path . '/' . $country; + foreach (grep { $_ ne '.directory' } all($country_root)) { + my $path = $country_root . $_; + s/%([0-9]{3})/chr(int($1))/eg; + $providers{$t_country . $separator . $_} = { path => $path }; + } + } + (\%providers, $separator); +} + +1; diff --git a/lib/network/connection/ppp.pm b/lib/network/connection/ppp.pm new file mode 100644 index 0000000..37fabb3 --- /dev/null +++ b/lib/network/connection/ppp.pm @@ -0,0 +1,150 @@ +package network::connection::ppp; + +use strict; +use common; + +use base qw(network::connection); + +my %authentication_methods = ( + script => N_("Script-based"), + pap => N_("PAP"), + terminal_ => N_("Terminal-based"), + chap => N_("CHAP"), + pap_chap => N_("PAP/CHAP"), +); + +my @kppp_authentication_methods = qw(script pap terminal chap pap_chap); +my @secrets_files = qw(pap-secrets chap-secrets); + +sub get_access_settings { + my ($self) = @_; + [ + { label => N("Account Login (user name)"), val => \$self->{access}{login} }, + { label => N("Account Password"), val => \$self->{access}{password}, hidden => 1 }, + ]; +} + +sub get_secret { + my ($_self, $login) = @_; + foreach (@secrets_files) { + my $file = "$::prefix/etc/ppp/$_"; + foreach (cat_($file)) { + my ($l, undef, $password) = split(' '); + if ($l && $password) { + s/^(['"]?)(.*)\1$/$2/ foreach $l, $password; + return $password if $l eq $login; + } + } + } +} + +sub write_secrets { + my ($self) = @_; + foreach (@secrets_files) { + my $file = "$::prefix/etc/ppp/$_"; + substInFile { + s/^'$self->{access}{login}'.*\n//; + $_ .= "\n'$self->{access}{login}' * '$self->{access}{password}' * \n" if eof; + } $file; + chmod 0600, $file; + } +} + +sub get_options { + #- options: PAPNAME PEERDNS +} + +sub get_tty_device { "/dev/modem" } + +sub get_up_timeout { 20 } + +sub build_ifcfg_settings { + my ($self) = @_; + my $modemport = $self->get_tty_device; + my $settings = put_in_hash($self->{settings}, { + if_($modemport, MODEMPORT => $modemport), + LINESPEED => "115200", + PERSIST => "yes", + DEFROUTE => "yes", + #- FIXME: move in network::connection::cellular or network::connection::cellular_card + if_($self->get_interface !~ /^hso/, DEBUG => "yes"), + if_($self->{access}{cid}, CELLULAR_CID => $self->{access}{cid}), + }); + $self->SUPER::build_ifcfg_settings($settings); +} + +sub build_chat { + my ($self) = @_; + #- optional: + #- auth_method: key of %authentication_methods + #- dial_number + #- login + #- password + #- at_commands: array ref of AT commands + (map { "ABORT $_" } "BUSY", "ERROR", "'NO CARRIER'", "'NO DIALTONE'", "'Invalid Login'", "'Login incorrect'", "VOICE", "'NO ANSWER'", "DELAYED", "'SIM PIN'"), + qq('' ATZ), + if_(ref $self->{access}{at_commands}, map { qq(OK-AT-OK '$_') } @{$self->{access}{at_commands}}), + if_($self->{access}{dial_number}, + qq(OK 'ATDT$self->{access}{dial_number}'), + qq(TIMEOUT 120), + qq(CONNECT ''), + if_(member($self->{access}{auth_method}, qw(script terminal)), + qq('ogin:--ogin:' '$self->{access}{login}'), + qq('ord:' '$self->{access}{password}')), + qq(TIMEOUT 5), + qq('~--' ''), + ); +} + +sub get_chat_file { + my ($self) = @_; + "/etc/sysconfig/network-scripts/chat-" . $self->get_interface; +} + +sub write_chat { + my ($self) = @_; + output_with_perm($::prefix . $self->get_chat_file, 0755, join("\n", $self->build_chat, '')); +} + +sub get_peer_default_options { + my ($_self) = @_; + qw(noauth defaultroute usepeerdns); +} + +sub build_peer { + my ($self) = @_; + #- options: + #- init + #- connect + #- pty + #- plugin + if ($self->{access}{use_chat}) { + my $chat_file = $self->get_chat_file; + $self->{access}{peer}{connect} ||= qq("/usr/sbin/chat -v -f $chat_file"); + } + $self->get_peer_default_options, + (map { if_($self->{access}{peer}{$_}, $_ . " " . $self->{access}{peer}{$_}) } qw(init connect pty plugin)), + if_($self->{access}{login}, qq(user "$self->{access}{login}")); +} + +sub write_peer { + my ($self) = @_; + my $interface = $self->get_interface; + my $peer_file = "/etc/ppp/peers/$interface"; + output_with_perm($::prefix . $peer_file, 0755, join("\n", $self->build_peer, '')); +} + +sub write_ppp_settings { + my ($self) = @_; + $self->write_secrets if $self->{access}{login}; + $self->write_chat if $self->{access}{use_chat}; + $self->write_peer; +} + +sub write_settings { + my ($self) = @_; + $self->write_ppp_settings; + $self->network::connection::write_settings; +} + +1; diff --git a/lib/network/connection/providers/cellular.pm b/lib/network/connection/providers/cellular.pm new file mode 100644 index 0000000..79f757c --- /dev/null +++ b/lib/network/connection/providers/cellular.pm @@ -0,0 +1,183 @@ +package network::connection::providers::cellular; + +use common; +use utf8; + +# http://www.reqwireless.com/apns.html +# http://wiki.mig33.com/mig33/show/apn +# http://www.unlocks.co.uk/gprs_settings.php +# http://www.opera.com/products/smartphone/docs/connect/ +# http://www.taniwha.org.uk/gprs.html +# https://rip.psg.com/~randy/gprs-ppp.html +# http://computer.cocus.co.il/Setup/V3X/MPT/Addons/GPRSope.inf + +our %data = ( + N("Brazil") . "|Vivo" => { + apn => "zap.vivo.com.br", + login => "vivo", + password => "vivo", + }, + N("Estonia") . "|Bravocom" => { + apn => "internet", + }, + N("Estonia") . "|Elisa" => { + apn => "internet", + }, + N("Estonia") . "|EMT" => { + apn => "internet.emt.ee", + }, + N("Estonia") . "|Simpel/POP!" => { + apn => "internet2.emt.ee", + }, + N("Estonia") . "|Tele2" => { + apn => "internet.tele2.ee", + }, + N("Estonia") . "|TeleYks" => { + apn => "internet", + }, + N("Estonia") . "|Zorro" => { + apn => "internet", + }, + # http://www.cubio.fi/fi/cubio_gsm/mms_ja_gprs_asetukset + N("Finland") . "|Cubio" => { + apn => "internet.cubio.net", + }, + # http://www.dnaoy.fi/Yksityisille/Matkaviestinta/Asiakaspalvelu/Documents/Ohjeet/asetukset_yleiset_wxp.pdf + N("Finland") . "|DNA" => { + apn => "internet", + }, + # http://matkaviestinta.elisa.fi/public/elisa.do?id=hen_liit_palvelut_gprs,ds_muut_0054.htm + # http://tuki.elisa.fi/asiakastuki/elisa.do?id=hen_as_matkaviest_ohjeet,as_help_page_0025.htm + # Official pages have inconsistent information on whether login and + # password are used. Presumably they are ignored, but we set them just to + # be sure. + N("Finland") . "|Elisa" => { + apn => "internet", + login => "rlnet", + password => "internet", + }, + # http://koti.mbnet.fi/simopot/asetukset/index.php?operaattori=globetel + N("Finland") . "|Globetel" => { + apn => "internet", + }, + # http://www.kolumbus.com/asiakaspalvelu_asetukset.html + # Redirects to Elisa automatic setup, presumably same settings apply. + N("Finland") . "|Kolumbus" => { + apn => "internet", + login => "rlnet", + password => "internet", + }, + # http://saunalahti.fi/tuki/gsm/vo/ohjeemail.php + N("Finland") . "|Saunalahti" => { + apn => "internet.saunalahti", + }, + # http://koti.mbnet.fi/simopot/asetukset/index.php?operaattori=sonera + N("Finland") . "|Sonera" => { + apn => "internet", + }, + # http://tdc.fi/publish.php?dogtag=songfi_at_ojl_int + N("Finland") . "|Song" => { + apn => "internet.song.fi", + login => "song@internet", + password => "songnet", + }, + # http://www.tele.fi/Asiakaspalvelu/Ohjeet/K%E4nnyk%E4ll%E4+nettiin+ja+tiedonsiirto/Asetukset/ + N("Finland") . "|Tele Finland" => { + apn => "internet", + }, + # http://www.gsm.aland.fi/tjanster/wap/wap.htm + N("Finland") . "|Ã…lands Mobiltelefon" => { + apn => "internet", + }, + N("France") . "|BouygTel" => { + apn => "ebouygtel.com", + }, + N("France") . "|BouygTel Pro" => { + apn => "a2bouygtel.com", + login => "a2b", + password => "acces", + }, + N("France") . "|BouygTel Pro GPRS" => { + apn => "b2bouygtel.com", + login => "B2B", + password => "NET", + }, + N("France") . "|Orange Web" => { + apn => "orange.fr", + login => "orange", + password => "orange", + }, + # http://www.actua-mobiles.com/p800/viewtopic.php?p=12184#12184 + # http://www.planete-se.net/index.php?showtopic=18184&st=0&p=186768&#entry186768 + N("France") . "|Orange WAP" => { + apn => "orange", + login => "orange", + password => "orange", + }, + N("France") . "|Orange Entreprises" => { + apn => "internet-entreprise", + login => "orange", + password => "orange", + }, + N("France") . "|SFR EeePC (Clé Internet 3G+)" => { + apn => "slsfr", + }, + N("France") . "|SFR WAP (Illimythics / Pass Surf)" => { + apn => "wapsfr", + }, + N("France") . "|SFR Web (Clé Internet / Data)" => { + apn => "websfr", + }, + N("Germany") . "|Vodafone Live! WAP" => { + apn => "wap.vodafone.de", + }, + N("Germany") . "|Vodafone Web" => { + apn => "web.vodafone.de", + }, + N("Italy") . "|TIM" => { + apn => "ibox.tim.it", + login => "tim", + password => "tim", + }, + N("Italy") . "|Vodafone" => { + apn => "web.omnitel.it", + login => "vodafone", + password => "vodafone", + }, + N("Italy") . "|Wind" => { + apn => "internet.wind.it", + login => "wind", + password => "wind", + }, + N("Italy") . "|Tre" => { + apn => "tre.it", + login => "tre", + password => "tre", + }, + N("Poland") . "|Era GSM" => { + apn => "erainternet", + login => "erainternet", + password => "erainternet", + }, + N("Poland") . "|Orange" => { + apn => "internet", + login => "internet", + password => "internet", + }, + N("Poland") . "|Play" => { + apn => "INTERNET", + }, + N("Poland") . "|Plus GSM" => { + apn => "internet", + }, + N("United Kingdom") . "|O2" => { + apn => "mobile.o2.co.uk", + login => "mobileweb", + password => "password", + }, + N("United States") . "|Cingular" => { + apn => "isp.cingular", + }, +); + +1; diff --git a/lib/network/connection/providers/cellular_extra.pm b/lib/network/connection/providers/cellular_extra.pm new file mode 100644 index 0000000..4039afa --- /dev/null +++ b/lib/network/connection/providers/cellular_extra.pm @@ -0,0 +1,2284 @@ +package network::connection::providers::cellular_extra; + +use common; +use utf8; + +# this list was imported from mobile-broadband-provider-info +# (http://svn.gnome.org/svn/mobile-broadband-provider-info/trunk) and converted +# to perl data using some black magick + +our %data = ( + N("United Arab Emirates") . "|Etisalat" => { + apn => "mnet", + login => "mnet", + password => "mnet", + dns => "194.170.1.6", + dns => "194.170.1.7", + }, + N("United Arab Emirates") . "|Etisalat 3G" => { + apn => "etisalat.ae", + login => "etisalat.ae", + password => "etisalat.ae", + }, + N("Albania") . "|Vodafone" => { + apn => "Twa", + }, + N("Angola") . "|Movinet" => { + cdma => 1, + login => "uname", + }, + N("Argentina") . "|Personal" => { + apn => "gprs.personal.com", + login => "gprs", + password => "adgj", + dns => "172.25.7.6", + dns => "172.25.7.7", + }, + N("Argentina") . "|CTI" => { + apn => "internet.ctimovil.com.ar", + login => "ctigprs", + dns => "170.51.255.100", + dns => "170.51.242.18", + }, + N("Argentina") . "|Movistar" => { + apn => "internet.gprs.unifon.com.ar", + login => "wap", + password => "wap", + }, + N("Angola") . "|Unitel" => { + apn => "internet.unitel.co.ao", + }, + N("Austria") . "|Max Max Online Mobil" => { + apn => "gprsinternet", + login => "GPRS", + dns => "213.162.64.1", + dns => "213.162.64.2", + }, + N("Austria") . "|Max Online" => { + apn => "gprsinternet", + login => "GPRS", + dns => "213.162.64.1", + dns => "213.162.64.2", + }, + N("Austria") . "|Max Online (Business)" => { + apn => "business.gprsinternet", + login => "GPRS", + dns => "213.162.64.1", + dns => "213.162.64.2", + }, + N("Austria") . "|Max Online (Metro)" => { + apn => "gprsmetro", + login => "GPRS", + dns => "213.162.64.1", + dns => "213.162.64.2", + }, + N("Austria") . "|Mobilkom/A1" => { + apn => "a1.net", + login => "ppp@a1plus.at", + password => "ppp", + dns => "194.48.139.254", + dns => "194.48.124.202", + }, + N("Austria") . "|Orange" => { + apn => "web.one.at", + login => "web", + password => "web", + dns => "194.24.128.100", + dns => "194.24.128.102", + }, + N("Austria") . "|Tele.ring" => { + apn => "web", + login => "web@telering.at", + password => "web", + dns => "212.95.31.167 ", + dns => "212.95.31.168", + }, + N("Austria") . "|Telering" => { + apn => "web", + login => "web@telering.at", + password => "web", + dns => "212.95.31.167 ", + dns => "212.95.31.168", + }, + N("Austria") . "|Drei" => { + apn => "drei.at", + }, + N("Austria") . "|Yesss" => { + apn => "web.yesss.at", + }, + N("Australia") . "|Exetel" => { + apn => "exetel1", + }, + N("Australia") . "|Optus" => { + apn => "internet", + dns => "202.139.83.3", + dns => "192.65.91.129", + }, + N("Australia") . "|Optus 3G" => { + apn => "CONNECT", + dns => "202.139.83.3", + dns => "192.65.91.129", + }, + N("Australia") . "|Telstra" => { + apn => "telstra.wap", + dns => "139.130.4.4", + dns => "203.50.2.71", + }, + N("Australia") . "|Telstra (3G data pack)" => { + apn => "telstra.datapack", + password => "Telstra", + dns => "139.130.4.4", + dns => "203.50.2.71", + }, + N("Australia") . "|Telstra (UMTS/HSDPA)" => { + apn => "telstra.internet", + dns => "139.130.4.4", + dns => "203.50.170.2", + }, + N("Australia") . "|Telstra (3G PC pack - pay by time)" => { + apn => "telstra.pcpack", + password => "Telstra", + dns => "139.130.4.4", + dns => "203.50.2.71", + }, + N("Australia") . "|Telstra (Next G card)" => { + dns => "139.130.4.4", + dns => "203.50.2.71", + }, + N("Australia") . "|Three" => { + apn => "3netaccess", + login => "a", + password => "a", + dns => "202.124.68.130", + dns => "202.124.76.66", + }, + N("Australia") . "|Three Prepaid" => { + apn => "3services", + login => "a", + password => "a", + dns => "202.124.68.130", + dns => "202.124.76.66", + }, + N("Australia") . "|Virgin Mobile" => { + apn => "VirginInternet", + login => "guest", + password => "guest", + dns => "61.88.88.88", + }, + N("Australia") . "|Vodafone" => { + apn => "vfinternet.au", + dns => "192.189.54.33", + dns => "210.80.58.3", + }, + N("Azerbaijan") . "|Azercell" => { + apn => "internet", + }, + N("Azerbaijan") . "|Bakcell" => { + apn => "mms", + }, + N("Bosnia and Herzegovina") . "|BH GSM" => { + apn => "mms.bhmobile.ba", + }, + N("Bahamas") . "|Batelco" => { + apn => "internet.btcbahamas.com", + }, + N("Bangladesh") . "|AKTel" => { + apn => "atmmms", + dns => "192.168.023.007", + }, + N("Bangladesh") . "|Banglalink" => { + apn => "blweb", + }, + N("Bangladesh") . "|Grameen Phone" => { + apn => "gpinternet", + dns => "202.56.4.120", + dns => "202.56.4.121", + }, + N("Barbados") . "|Digicel" => { + apn => "isp.digicelbarbados.com", + }, + N("Belgium") . "|Mobistar (business)" => { + apn => "web.pro.be", + login => "mobistar", + password => "mobistar", + dns => "212.65.63.10", + dns => "212.65.63.145", + }, + N("Belgium") . "|Orange" => { + apn => "orangeinternet", + }, + N("Belgium") . "|Proximus Inter" => { + apn => "internet.proximus.be", + dns => "195.238.2.21", + dns => "195.238.2.22", + }, + N("Belgium") . "|Proximus Intra" => { + apn => "intraprox.be", + dns => "195.238.2.21", + dns => "195.238.2.22", + }, + N("Belgium") . "|Base" => { + apn => "gprs.base.be", + login => "base", + password => "base", + }, + N("Belgium") . "|Mobistar (personal)" => { + apn => "internet.be", + login => "mobistar", + password => "mobistar", + dns => "212.65.63.10", + dns => "212.65.63.145", + }, + N("Bulgaria") . "|GloBul" => { + apn => "internet.globul.bg", + login => "globul", + dns => "192.168.88.11", + }, + N("Bulgaria") . "|M-Tel" => { + apn => "inet-gprs.mtel.bg", + login => "mtel", + password => "mtel", + dns => "213.226.7.34", + dns => "213.226.7.35", + }, + N("Bulgaria") . "|GloBul" => { + apn => "internet.globul.bg", + login => "globul", + password => "[none]", + dns => "192.168.88.11", + }, + N("Brazil") . "|Claro" => { + apn => "claro.com.br", + login => "claro", + password => "claro", + }, + N("Brazil") . "|Oi" => { + apn => "gprs.oi.com.br", + password => "oioioi", + }, + N("Brazil") . "|TIM" => { + apn => "tim.br", + login => "tim", + password => "tim", + dns => "10.223.246.102", + dns => "10.223.246.103", + }, + N("Brazil") . "|Oi (WAP)" => { + apn => "wapgprs.oi.com.br", + login => "oiwap", + password => "oioioi", + }, + N("Brazil") . "|Velox" => { + apn => "wap.telcel.com", + login => "iesgprs", + password => "iesgprs2002", + dns => "66.36.250.14", + }, + N("Brazil") . "|Vivo" => { + apn => "zap.vivo.com.br", + login => "vivo", + password => "vivo", + }, + N("Belarus") . "|VELCOM" => { + apn => "wap.velcom.by", + login => "wap", + password => "wap", + }, + N("Belarus") . "|VELCOM (Simple GPRS)" => { + apn => "web.velcom.by", + login => "web", + password => "web", + dns => "212.98.162.154", + dns => "193.232.248.2", + }, + N("Belarus") . "|VELCOM (Web Plus)" => { + apn => "plus.velcom.by", + login => "plus", + password => "plus", + }, + N("Belarus") . "|VELCOM (Privet)" => { + apn => "privet.velcom.by", + login => "privet", + password => "privet", + }, + N("Belarus") . "|MTS" => { + apn => "internet.mts.by", + login => "mts", + password => "mts", + }, + N("Botswana") . "|Mascom Wireless" => { + apn => "internet.mascom", + }, + N("Canada") . "|Microcell Fido" => { + apn => "internet.fido.ca", + login => "fido", + password => "fido", + dns => "204.92.15.211", + dns => "207.181.101.4", + }, + N("Canada") . "|Rogers AT&T" => { + apn => "internet.com", + login => "wapuser1", + password => "wap", + dns => "207.181.101.4", + dns => "207.181.101.5", + }, + N("Congo (Kinshasa)") . "|Vodafone" => { + apn => "vodanet", + login => "vodalive", + dns => "172.24.97.1", + }, + N("Congo (Brazzaville)") . "|Vodafone" => { + apn => "vodanet", + login => "vodalive", + dns => "172.24.97.1", + }, + N("Switzerland") . "|Orange" => { + apn => "mobileoffice3g", + dns => "213.55.128.1 ", + dns => "213.55.128.2", + }, + N("Switzerland") . "|Sunrise" => { + apn => "internet", + login => "internet", + password => "internet", + dns => "212.35.35.35", + dns => "212.35.35.5", + }, + N("Switzerland") . "|Swisscom" => { + apn => "gprs.swisscom.ch", + login => "gprs", + password => "gprs", + dns => "164.128.36.34", + dns => "164.128.76.39", + }, + N("Cote d'Ivoire") . "|internet" => { + apn => "172.16.100.5", + }, + N("Chile") . "|Claro Chile" => { + apn => "bam.clarochile.cl", + login => "clarochile", + password => "clarochile", + }, + N("Chile") . "|Claro Chile - Prepago" => { + apn => "bap.clarochile.cl", + login => "clarochile", + password => "clarochile", + }, + N("Chile") . "|Claro Chile - WAP" => { + apn => "wap.clarochile.cl", + login => "clarochile", + password => "clarochile", + }, + N("Chile") . "|Entel PCS" => { + apn => "imovil.entelpcs.cl", + login => "entelpcs", + password => "entelpcs", + }, + N("Chile") . "|Entel PCS - WAP" => { + apn => "bam.entelpcs.cl", + login => "entelpcs", + password => "entelpcs", + }, + N("Chile") . "|Movistar" => { + apn => "web.tmovil.cl", + login => "web", + password => "web", + }, + N("Chile") . "|Movistar - WAP" => { + apn => "wap.tmovil.cl", + login => "wap", + password => "wap", + }, + N("Cameroon") . "|Orange" => { + apn => "orangecmgprs", + login => "orange", + password => "orange", + }, + N("Cameroon") . "|MTN" => { + apn => "INTERNET", + dns => "-", + }, + N("China") . "|China Mobile" => { + apn => "cmnet", + dns => "211.136.20.203 ", + dns => "211.136.20.203", + }, + N("China") . "|China Unicom" => { + apn => "none", + dns => "211.136.20.203 ", + dns => "211.136.20.203", + }, + N("Costa Rica") . "|IceCelular" => { + apn => "icecelular", + dns => "208.133.206.44 ", + dns => "208.133.206.44", + }, + N("Colombia") . "|Comcel" => { + apn => "internet.comcel.com.co", + login => "COMCELWEB", + password => "COMCELWEB", + }, + N("Colombia") . "|Tigo" => { + apn => "web.colombiamovil.com.co", + }, + N("Colombia") . "|Movistar" => { + apn => "internet.movistar.com.co", + login => "movistar", + password => "movistar", + }, + N("Czech Republic") . "|Cesky Mobil (postpaid)" => { + apn => "internet", + dns => "212.67.64.2", + dns => "217.77.161.131", + }, + N("Czech Republic") . "|Cesky Mobil (prepaid)" => { + apn => "Cinternet", + dns => "212.67.64.2", + dns => "217.77.161.131", + }, + N("Czech Republic") . "|EuroTel (Go)" => { + apn => "gointernet", + dns => "160.218.10.200 ", + dns => "160.218.43.200", + }, + N("Czech Republic") . "|Oscar (Post p.)" => { + apn => "internet", + login => "wap", + password => "wap", + dns => "217.77.161.130", + dns => "217.77.161.131", + }, + N("Czech Republic") . "|Oscar (Pre p.)" => { + apn => "internet", + dns => "217.77.161.130", + dns => "217.77.161.131", + }, + N("Czech Republic") . "|Paegas Internet" => { + apn => "internet.click.cz", + dns => "62.141.0.1", + dns => "62.141.0.2", + }, + N("Czech Republic") . "|Paegas Profil" => { + apn => "profil.click.cz", + dns => "62.141.0.1", + dns => "62.141.0.2", + }, + N("Czech Republic") . "|Radiomibil" => { + apn => "internet.click.cz", + }, + N("Czech Republic") . "|T-Mobil" => { + apn => "internet.t-mobile.cz", + dns => "62.141.0.1", + dns => "213.162.65.1", + }, + N("Czech Republic") . "|Eurotel (contract)" => { + apn => "internet", + dns => "160.218.10.200", + dns => "160.218.43.200", + }, + N("Czech Republic") . "|Eurotel (contract - open)" => { + apn => "internet.open", + dns => "160.218.10.200 ", + dns => "160.218.43.200", + }, + N("Czech Republic") . "|Vodafone (contract)" => { + apn => "internet", + dns => "217.77.161.130", + dns => "217.77.161.131", + }, + N("Czech Republic") . "|Telefonica (contract)" => { + apn => "internet", + dns => "160.218.10.200", + dns => "160.218.43.200", + }, + N("Czech Republic") . "|Vodafone (pre-pay)" => { + apn => "ointernet", + dns => "217.77.161.130", + dns => "217.77.161.131", + }, + N("Czech Republic") . "|Telefonica (Go)" => { + apn => "gointernet", + dns => "160.218.10.201", + dns => "194.228.2.1", + }, + N("Germany") . "|AldiTalk/MedionMobile" => { + apn => "internet.eplus.de", + login => "eplus", + password => "gprs", + dns => "212.23.97.2", + dns => "212.23.97.3", + }, + N("Germany") . "|E-Plus (pre-pay)" => { + apn => "internet.eplus.de", + login => "eplus", + password => "gprs", + dns => "212.23.97.2", + dns => "212.23.97.3", + }, + N("Germany") . "|E-Plus (contract)" => { + apn => "internet.eplus.de", + login => "eplus", + password => "gprs", + dns => "212.23.97.2", + dns => "212.23.97.3", + }, + N("Germany") . "|o2 (pay-by-MB)" => { + apn => "internet", + dns => "195.182.110.132 ", + dns => "62.134.11.4", + }, + N("Germany") . "|o2 (pay-by-time)" => { + apn => "surfo2", + dns => "195.182.110.132 ", + dns => "62.134.11.4", + }, + N("Germany") . "|o2 Viag Interkom" => { + apn => "internet", + dns => "195.182.110.132", + dns => "62.134.11.4", + }, + N("Germany") . "|T-mobile (D1)" => { + apn => "internet.t-d1.de", + password => "t-d1", + dns => "193.254.160.1 ", + dns => "193.254.160.130", + }, + N("Germany") . "|Vodafone (D2)" => { + apn => "web.vodafone.de", + login => "vodafone", + password => "vodafone", + dns => "139.7.30.125", + dns => "139.7.30.126", + }, + N("Germany") . "|Vodafone (D2) WebSessions" => { + apn => "event.vodafone.de", + login => "vodafone", + password => "vodafone", + dns => "139.7.30.125", + dns => "139.7.30.126", + }, + N("Germany") . "|FONIC" => { + apn => "pinternet.interkom.de", + }, + N("Denmark") . "|3 (BredbÃ¥nd)" => { + apn => "bredband.tre.dk", + }, + N("Denmark") . "|3 (BredbÃ¥nd Premium Kontant)" => { + apn => "net.tre.dk", + }, + N("Denmark") . "|3 (Mobil Abonnement)" => { + apn => "data.tre.dk", + }, + N("Denmark") . "|OiSTER" => { + apn => "bredband.oister.dk", + }, + N("Denmark") . "|ice.net (Nordisk Mobiltelefon)" => { + cdma => 1, + login => "cdma", + password => "cdma", + }, + N("Denmark") . "|Sonofon" => { + apn => "internet", + dns => "212.88.64.199", + dns => "212.88.64.14", + }, + N("Denmark") . "|TDC" => { + apn => "internet", + dns => "194.239.134.83", + dns => "193.162.153.164", + }, + N("Denmark") . "|Fullrate" => { + apn => "internet", + login => "Fullrate", + password => "Fullrate", + }, + N("Denmark") . "|Telia" => { + apn => "www.internet.mtelia.dk", + }, + N("Denmark") . "|BiBoB" => { + apn => "internet.bibob.dk", + }, + N("Dominican Republic") . "|Orange" => { + apn => "orangenet.com.do", + }, + N("Ecuador") . "|Porta 3G" => { + apn => "internet.porta.com.ec", + }, + N("Estonia") . "|EMT" => { + apn => "internet.emt.ee", + dns => "217.71.32.116", + dns => "217.71.32.115", + }, + N("Estonia") . "|Nordea" => { + apn => "internet.emt.ee", + }, + N("Estonia") . "|Radiolinja" => { + apn => "internet", + dns => "194.204.0.1", + }, + N("Estonia") . "|RLE" => { + apn => "internet", + }, + N("Estonia") . "|Tele2" => { + apn => "internet.tele2.ee", + login => "wap", + password => "wap", + }, + N("Egypt") . "|Click Vodafone" => { + apn => "internet.vodafone.net", + login => "internet", + password => "internet", + }, + N("Egypt") . "|Etisalat" => { + apn => "etisalat", + }, + N("Egypt") . "|MobiNil" => { + apn => "mobinilweb", + dns => "80.75.166.250", + dns => "163.121.163.201", + }, + N("Spain") . "|Amena" => { + apn => "internet", + login => "CLIENTE", + password => "AMENA", + dns => "213.143.32.20 ", + dns => "213.143.33.8", + }, + N("Spain") . "|Orange" => { + apn => "internet", + login => "CLIENTE", + password => "AMENA", + dns => "213.143.32.20 ", + dns => "213.143.33.8", + }, + N("Spain") . "|Simyo" => { + apn => "gprs-service.com", + }, + N("Spain") . "|Telefonica" => { + apn => "movistar.es", + login => "movistar", + password => "movistar", + dns => "194.179.1.100", + dns => "194.179.1.101", + }, + N("Spain") . "|Vodafone (Airtel)" => { + apn => "airtelnet.es", + login => "vodafone", + password => "vodafone", + dns => "212.73.32.3", + dns => "212.73.32.67", + }, + N("Spain") . "|Vodafone" => { + apn => "airtelnet.es", + login => "vodafone", + password => "vodafone", + dns => "196.207.32.69", + dns => "196.43.45.190", + }, + N("Spain") . "|Yoigo" => { + apn => "Internet", + }, + N("Spain") . "|Jazztel" => { + apn => "jazzinternet", + }, + N("Finland") . "|Dna" => { + apn => "internet", + dns => "217.78.192.22 ", + dns => "217.78.192.78", + }, + N("Finland") . "|Elisa" => { + apn => "internet", + }, + N("Finland") . "|Saunalahti" => { + apn => "internet.saunalahti", + }, + N("Finland") . "|Sonera" => { + apn => "internet", + dns => "192.89.123.230", + dns => "192.89.123.231", + }, + N("Finland") . "|Sonera prointernet" => { + apn => "prointernet", + dns => "192.89.123.230", + dns => "192.89.123.231", + }, + N("Fiji") . "|Vodafone" => { + apn => "vfinternet.fj", + }, + N("France") . "|Bouygues Telecom (B2Bouygtel)" => { + apn => "b2bouygtel.com", + dns => "62.201.129.99", + }, + N("France") . "|Bouygues Telecom" => { + apn => "ebouygtel.com", + dns => "62.201.129.99", + dns => "62.201.159.99", + }, + N("France") . "|France Telecom" => { + apn => "orange.fr.mnc001.mcc208.gprs", + login => "gprs", + }, + N("France") . "|Orange (contract)" => { + apn => "orange.fr", + login => "orange", + password => "orange", + dns => "194.51.3.56", + dns => "194.51.3.76", + }, + N("France") . "|Orange (business contract)" => { + apn => "internet-entreprise", + login => "orange", + password => "orange", + }, + N("France") . "|Orange (no contact)" => { + apn => "orange", + login => "orange", + password => "orange", + dns => "194.51.3.56 ", + dns => "194.51.3.76", + }, + N("France") . "|Orange MIB" => { + apn => "orange-mib", + login => "mportail", + password => "mib", + dns => "172.17.0.2 ", + dns => "172.17.0.4", + }, + N("France") . "|Orange Mobicarte" => { + apn => "orange", + login => "orange", + password => "orange", + }, + N("France") . "|Orange Internet Everywhere 3G" => { + apn => "orange.ie", + }, + N("France") . "|SFR" => { + apn => "websfr", + dns => "172.20.2.10", + dns => "172.20.2.39", + }, + N("France") . "|Transatel Telecom" => { + apn => "netgprs.com", + }, + N("France") . "|TEN" => { + apn => "ao.fr", + login => "orange", + password => "orange", + }, + N("France") . "|TEN (pay-by-MB)" => { + apn => "ofnew.fr", + login => "orange", + password => "orange", + }, + N("France") . "|Orange (business)" => { + apn => "internet-entreprise", + login => "orange", + password => "orange", + dns => "194.51.3.56", + dns => "194.51.3.76", + }, + N("France") . "|Orange (contract)" => { + apn => "orange.fr", + login => "orange", + password => "orange", + dns => "194.51.3.56", + dns => "194.51.3.76", + }, + N("United Kingdom") . "|airtel vodaphone" => { + apn => "airtel-ci-gprs.com", + }, + N("United Kingdom") . "|Jersey Telecom" => { + apn => "pepper", + login => "abc", + password => "abc", + dns => "212.9.0.135", + dns => "212.9.0.136", + }, + N("United Kingdom") . "|o2 (contract)" => { + apn => "mobile.o2.co.uk", + login => "o2web", + password => "password", + dns => "193.113.200.200", + dns => "193.113.200.201", + }, + N("United Kingdom") . "|o2 (pre-pay)" => { + apn => "payandgo.o2.co.uk", + login => "payandgo", + password => "payandgo", + }, + N("United Kingdom") . "|Orange (contract)" => { + apn => "orangeinternet", + login => "orange", + password => "orange", + dns => "193.35.133.10 ", + dns => "193.35.134.10", + }, + N("United Kingdom") . "|Orange JustTalk" => { + apn => "orangeinternet", + dns => "193.35.133.10", + dns => "193.35.134.10", + }, + N("United Kingdom") . "|T-Mobile" => { + apn => "general.t-mobile.uk", + login => "User", + password => "mms", + dns => "149.254.201.126", + dns => "149.254.192.126", + }, + N("United Kingdom") . "|Virgin Mobile" => { + apn => "vdata", + dns => "196.7.0.138", + dns => "196.7.142.132", + }, + N("United Kingdom") . "|Vodafone (contract)" => { + apn => "internet", + login => "web", + password => "web", + dns => "10.206.65.68", + dns => "10.203.65.68", + }, + N("United Kingdom") . "|Vodafone (pre-pay)" => { + apn => "pp.vodafone.co.uk", + login => "wap", + password => "wap", + dns => "172.29.1.11 ", + dns => "172.29.1.11", + }, + N("United Kingdom") . "|Vodafone (TopUp and Go)" => { + apn => "pp.internet", + }, + N("United Kingdom") . "|o2 (contract-faster)" => { + apn => "mobile.o2.co.uk", + login => "faster", + password => "password", + dns => "193.113.200.200", + dns => "193.113.200.201", + }, + N("United Kingdom") . "|3" => { + apn => "3internet", + }, + N("United Kingdom") . "|3 (handsets)" => { + apn => "three.co.uk", + }, + N("United Kingdom") . "|Orange (Pay and Go)" => { + apn => "orangewap", + login => "Multimedia", + password => "Orange", + dns => "158.43.192.1", + dns => "158.43.128.1", + }, + N("United Kingdom") . "|Orange (Pay Monthly)" => { + apn => "orangeinternet", + login => "orange", + password => "multimedia", + dns => "158.43.192.1", + dns => "158.43.128.1", + }, + N("Georgia") . "|Geocell" => { + apn => "Internet", + dns => "212.72.130.20", + dns => "212.72.152.001", + }, + N("Ghana") . "|Areeba" => { + apn => "internet.areeba.com.gh", + dns => "196.201.34.5", + dns => "213.137.131.3", + }, + N("Ghana") . "|ONETouch" => { + apn => "browse", + }, + N("Ghana") . "|Tigo" => { + apn => "web.tigo.com.gh", + login => "web", + password => 1, + }, + N("Ghana") . "|Zain" => { + apn => "internet", + }, + N("Greece") . "|Cosmote" => { + apn => "3g-internet", + dns => "195.167.65.194", + }, + N("Greece") . "|Telestet" => { + apn => "gnet.b-online.gr", + password => "24680", + dns => "212.152.79.19", + dns => "212.152.79.20", + }, + N("Greece") . "|Vodafone" => { + apn => "internet", + }, + N("Greece") . "|TIM" => { + apn => "gint.b-online.gr", + login => "web", + password => "web", + }, + N("Guatemala") . "|Comcel" => { + apn => "Wap.tigo.gt", + login => "Wap", + password => "Wap", + }, + N("Guatemala") . "|PCS Digital" => { + apn => "ideasalo", + }, + N("Guyana") . "|GT&T Cellink Plus" => { + apn => "wap.cellinkgy.com", + login => "test", + password => "test", + }, + N("Hong Kong") . "|CSL" => { + apn => "internet", + dns => "202.84.255.1", + dns => "203.116.254.150", + }, + N("Hong Kong") . "|New World" => { + apn => "internet", + }, + N("Hong Kong") . "|People" => { + apn => "internet", + }, + N("Hong Kong") . "|SmarTone" => { + apn => "internet", + dns => "202.140.96.51", + dns => "202.140.96.52", + }, + N("Hong Kong") . "|Sunday" => { + apn => "internet", + }, + N("Hong Kong") . "|Orange" => { + apn => "web.orangehk.com", + }, + N("Hong Kong") . "|Three" => { + apn => "mobile.three.com.hk", + }, + N("Honduras") . "|Tigo" => { + apn => "internet.tigo.hn", + }, + N("Croatia") . "|HTmobile" => { + apn => "www.htgprs.hr", + dns => "10.12.0.1", + }, + N("Croatia") . "|VIPNET" => { + apn => "gprs5.vipnet.hr", + login => "38591", + password => "38591", + dns => "195.29.159.15", + }, + N("Croatia") . "|VIPNET" => { + apn => "gprs0.vipnet.hr", + login => "38591", + password => "38591", + dns => "195.29.159.15", + }, + N("Croatia") . "|VIPNET" => { + apn => "3g.vip.hr", + login => "38591", + password => "38591", + dns => "212.91.97.3 ", + dns => "212.91.97.4", + }, + N("Hungary") . "|Pannon (átalánydÃjas)" => { + apn => "netx", + dns => "193.225.155.254 ", + dns => "194.149.0.157", + }, + N("Hungary") . "|Pannon (normál)" => { + apn => "net", + dns => "193.225.153.17", + dns => "195.56.172.113", + }, + N("Hungary") . "|T-Mobile" => { + apn => "internet", + dns => "212.51.115.1 ", + dns => "194.176.224.6", + }, + N("Hungary") . "|Pannon (tömörÃtett)" => { + apn => "snet", + dns => "193.225.153.17", + dns => "194.149.0.157", + }, + N("Hungary") . "|T-Mobile (mms)" => { + apn => "mms-westel", + login => "mms", + dns => "212.51.115.1", + dns => "194.176.224.3", + }, + N("Hungary") . "|Vodafone (elÅ‘f. norm.)" => { + apn => "standardnet.vodafone.net", + login => "vodawap", + password => "vodawap", + dns => "80.244.97.30", + dns => "80.244.96.1", + }, + N("Hungary") . "|Vodafone (elÅ‘f. töm.)" => { + apn => "internet.vodafone.net", + login => "vodawap", + password => "vodawap", + dns => "80.244.97.30", + dns => "80.244.96.1", + }, + N("Hungary") . "|Vodafone (felt. norm.)" => { + apn => "vitamax.snet.vodafone.net", + dns => "80.244.97.30", + dns => "80.244.96.1", + }, + N("Hungary") . "|Vodafone (felt. töm.)" => { + apn => "vitamax.internet.vodafone.net", + dns => "80.244.97.30", + dns => "80.244.96.1", + }, + N("Indonesia") . "|AXIS" => { + apn => "AXIS", + login => "axis", + password => "123456", + }, + N("Indonesia") . "|IM3" => { + apn => "www.imdosat-m3.net", + login => "gprs", + password => "im3", + dns => "202.155.46.66 ", + dns => "202.155.46.77", + }, + N("Indonesia") . "|Indosat" => { + apn => "satelindogprs.com", + dns => "202.152.162.250", + }, + N("Indonesia") . "|Telkomsel" => { + apn => "internet", + login => "wap", + password => "wap123", + dns => "202.152.0.2", + dns => "202.155.14.251", + }, + N("Indonesia") . "|Excelcomindo (XL)" => { + apn => "www.xlgprs.net", + login => "xlgprs", + password => "proxl", + dns => "202.152.254.245", + dns => "202.152.254.246", + }, + N("Indonesia") . "|Indosat (Matrix)" => { + apn => "satelindogprs.com indosatgprs", + dns => "202.155.46.66", + dns => "202.155.46.77", + }, + N("Ireland") . "|o2 (contract)" => { + apn => "open.internet", + login => "gprs", + password => "gprs", + dns => "62.40.32.33", + dns => "62.40.32.34", + }, + N("Ireland") . "|o2 (pre-pay)" => { + apn => "pp.internet", + login => "faster", + password => "web", + dns => "62.40.32.33", + dns => "62.40.32.34", + }, + N("Ireland") . "|Vodafone (HSDPA/GPRS/EDGE/UMTS)" => { + apn => "hs.vodafone.ie", + login => "vodafone", + password => "vodafone", + }, + N("Ireland") . "|Vodafone (GPRS/EDGE/UMTS) (old)" => { + apn => "isp.vodafone.ie", + login => "vodafone", + password => "vodafone", + }, + N("Ireland") . "|Meteor" => { + apn => "isp.mymeteor.ie", + login => "my", + password => "meteor", + }, + N("Ireland") . "|Vodafone (pre-pay)" => { + apn => "live.vodafone.com", + login => "vodafone", + password => "vodafone", + dns => "10.24.59.100", + }, + N("Ireland") . "|Three Ireland" => { + apn => "3ireland.ie", + dns => "172.31.140.69", + dns => "172.30.140.69", + }, + N("Israel") . "|CellCom" => { + apn => "etecsa", + login => "etecsa", + dns => "192.168.91.10", + dns => "192.168.91.4", + }, + N("Israel") . "|Orange" => { + apn => "orangeinternet", + dns => "158.43.192.1", + dns => "158.43.128.1", + }, + N("Israel") . "|Vodafone (MTC)" => { + apn => "apn01", + dns => "10.10.10.30", + }, + N("India") . "|Airtel" => { + apn => "airtelgprs.com", + dns => "202.56.230.5 ", + dns => "202.56.240.5", + }, + N("India") . "|BPL" => { + apn => "bplgprs.com", + login => "bplmobile", + dns => "202.169.145.34", + dns => "202.169.129.40", + }, + N("India") . "|BSNL" => { + apn => "celloneportal", + dns => "192.168.051.163", + }, + N("India") . "|BSNL Prepaid (West Bengal)" => { + apn => "www.e.pr", + dns => "218.248.240.208", + dns => "218.248.240.135", + }, + N("India") . "|Hutch (normal)" => { + apn => "www", + dns => "10.11.206.51", + dns => "10.11.206.50", + }, + N("India") . "|Hutch (Gujarat)" => { + apn => "web", + dns => "10.11.206.51", + dns => "10.11.206.50", + }, + N("India") . "|Idea Cellular" => { + apn => "internet", + dns => "10.4.42.15", + }, + N("India") . "|MTNL Delhi" => { + apn => "gprsmtnldel", + login => "mtnl", + password => "mtnl123", + }, + N("India") . "|MTNL Mumbai (pre-paid)" => { + apn => "gprsppsmum", + login => "mtnl", + password => "mtnl123", + }, + N("India") . "|MTNL Mumbai (post-paid)" => { + apn => "gprsmtnlmum", + login => "mtnl", + password => "mtnl123", + }, + N("India") . "|MTNL Mumbai (Plan 2)" => { + apn => "gprsmtnlmum", + login => "mtnl", + password => "mtnl123", + }, + N("India") . "|Orange" => { + apn => "portalnmms", + dns => "10.11.206.51", + dns => "10.11.206.50", + }, + N("India") . "|Spice telecom" => { + apn => "Simplyenjoy", + login => "Mobile number", + password => "spice", + }, + N("India") . "|Spice telecom (kar)" => { + apn => "simplydownload", + }, + N("India") . "|Tata Indicom (Plug2Surf)" => { + cdma => 1, + login => "internet", + password => "internet", + }, + N("India") . "|Telekomsel" => { + apn => "internet", + login => "wap", + password => "wap123", + }, + N("India") . "|Vodafone" => { + apn => "www", + login => "guest", + password => "guest", + }, + N("Iceland") . "|Islandssimi" => { + apn => "gprs.islandssimi.is", + dns => "213.176.128.51", + dns => "213.176.128.50", + }, + N("Iceland") . "|Nova" => { + apn => "internet.nova.is", + dns => "192.168.190.54", + dns => "192.168.190.55", + }, + N("Italy") . "|Vodafone" => { + apn => "web.omnitel.it", + }, + N("Italy") . "|TIM" => { + apn => "ibox.tim.it", + }, + N("Italy") . "|TIM (WAP)" => { + apn => "wap.tim.it", + login => "WAPTIM", + dns => "213.230.155.94 ", + dns => "213.230.130.222", + }, + N("Italy") . "|Wind" => { + apn => "internet.wind", + }, + N("Italy") . "|Wind (business)" => { + apn => "internet.wind.biz", + }, + N("Italy") . "|3 (ricaricabile)" => { + apn => "tre.it", + }, + N("Italy") . "|3 (abbonamento)" => { + apn => "datacard.tre.it", + }, + N("Italy") . "|Fastweb (SIM voce/dati)" => { + apn => "apn.fastweb.it", + }, + N("Italy") . "|Fastweb (SIM solo dati)" => { + apn => "datacard.fastweb.it", + }, + N("Jamaica") . "|Cable & Wireless" => { + apn => "wap", + }, + N("Jamaica") . "|Digicel" => { + apn => "web.digiceljamaica.com", + login => "wapuser", + password => "wap03jam", + dns => "208.131.176.126", + dns => "200.10.152.232", + }, + N("Japan") . "|Vodafone (J-Phone)" => { + apn => "vodafone", + login => "ai@vodafone", + password => "vodafone", + dns => "61.195.195.153", + dns => "61.195.194.26", + }, + N("Japan") . "|Softbank Mobile" => { + cdma => 1, + login => "ai@softbank", + password => "softbank", + }, + N("Japan") . "|e-mobile" => { + cdma => 1, + login => "em", + password => "em", + }, + N("Japan") . "|NTTdocomo" => { + cdma => 1, + }, + N("Japan") . "|au(KDDI)" => { + cdma => 1, + login => "au@au-win.ne.jp", + password => "au", + dns => "210.196.3.183", + dns => "210.141.112.163", + }, + N("Kenya") . "|Celtel" => { + apn => "ke.celtel.com", + }, + N("Kenya") . "|Safaricom" => { + apn => "web.safaricom.com", + login => "web", + password => "web", + }, + N("Kenya") . "|Econet" => { + apn => "internet.econet.co.ke", + }, + N("Kuwait") . "|Vodafone" => { + apn => "apn01", + dns => "10.10.10.30", + }, + N("Kuwait") . "|Wataniya" => { + apn => "action.wataniya.com", + }, + N("Kazakhstan") . "|Beeline" => { + apn => "internet.beeline.kz", + login => "@internet.beeline", + dns => "212.19.149.53 ", + dns => "194.226.128.1", + }, + N("Laos") . "|ETL" => { + apn => "etlnet", + dns => "192.168.4.130", + }, + N("Lebanon") . "|Cellis FTML" => { + apn => "internet.ftml.com.lb", + login => "plugged", + password => "plugged", + }, + N("Lebanon") . "|MTC Touch" => { + apn => "gprs.mtctouch.com.lb", + }, + N("Lebanon") . "|LibanCell" => { + apn => "isurf.libancell.com.lb", + }, + N("Saint Lucia") . "|Cable & Wireless" => { + apn => "internet", + dns => "-", + }, + N("Sri Lanka") . "|Airtel" => { + apn => "www.wap.airtel.lk", + }, + N("Sri Lanka") . "|Dialog GSM (Post-Paid)" => { + apn => "www.dialogsl.com", + }, + N("Sri Lanka") . "|Dialog GSM (Pre-Paid)" => { + apn => "ppinternet", + }, + N("Sri Lanka") . "|Hutch" => { + apn => "htwap", + }, + N("Sri Lanka") . "|Mobitel" => { + apn => "isp", + }, + N("Sri Lanka") . "|Tigo" => { + apn => "wap", + }, + N("Lithuania") . "|Bite" => { + apn => "banga", + login => "bite", + dns => "213.226.131.131", + dns => "193.219.88.36", + }, + N("Lithuania") . "|TELE2 GPRS" => { + apn => "internet.tele2.lt", + gateway => "130.244.196.90", + }, + N("Lithuania") . "|Omnitel (contract)" => { + apn => "gprs.omnitel.net", + dns => "194.176.32.129", + dns => "195.22.175.1", + }, + N("Lithuania") . "|Omnitel (no contract)" => { + apn => "gprs.startas.lt", + login => "omni", + password => "omni", + dns => "194.176.32.129", + dns => "195.22.175.1", + }, + N("Luxembourg") . "|LUXGSM" => { + apn => "webp.pt.lu", + dns => "194.154.192.101", + dns => "194.154.192.102", + }, + N("Luxembourg") . "|Tango" => { + apn => "internet", + login => "tango", + password => "tango", + }, + N("Luxembourg") . "|VOXmobile" => { + apn => "vox.lu", + }, + N("Latvia") . "|LMT" => { + apn => "internet.lmt.lv", + dns => "212.93.96.2", + dns => "212.93.96.4", + }, + N("Latvia") . "|Tele2" => { + apn => "internet.tele2.lv", + login => "gprs", + password => "internet", + }, + N("Morocco") . "|Maroc Telecom" => { + apn => "iam", + login => "wac", + password => "1987", + }, + N("Morocco") . "|Medi Telecom" => { + apn => "wap.meditel.ma", + login => "MEDIWAP", + password => "MEDIWAP", + }, + N("Moldova") . "|Moldcell" => { + apn => "internet", + login => "gprs", + password => "gprs", + }, + N("Moldova") . "|Eventis" => { + apn => "internet.md", + }, + N("Montenegro") . "|Mobtel Srbija" => { + apn => "internet", + login => "mobtel", + password => "gprs", + dns => "217.65.192.1", + dns => "217.65.192.52", + }, + N("Montenegro") . "|Promonte GSM" => { + apn => "gprs.promonte.com", + }, + N("Montenegro") . "|T-Mobile" => { + apn => "internet-postpaid", + login => "38167", + password => "38167", + }, + N("Montenegro") . "|Telekom Srbija (default)" => { + apn => "gprsinternet", + login => "mts", + password => "64", + dns => "195.178.38.3", + }, + N("Montenegro") . "|Telekom Srbija (via MMS)" => { + apn => "mms", + login => "mts", + password => "64", + dns => "195.178.38.3", + }, + N("Montenegro") . "|Telekom Srbija (via wap)" => { + apn => "gprswap", + login => "mts", + password => "64", + dns => "195.178.38.3", + }, + N("Mongolia") . "|MobiCom" => { + apn => "internet", + }, + N("Macao") . "|Macau Hutchison Telecom" => { + apn => "ctm-mobile", + }, + N("Macao") . "|Macau Hutchison Telecom (MMS)" => { + apn => "mms.hutchisonmacau.com", + login => "hutchison", + password => "1234", + }, + N("Macao") . "|CTM" => { + apn => "ctm-mobile", + }, + N("Macao") . "|Macau Hutchison Telecom (Internet)" => { + apn => "web.hutchisonmacau.com", + login => "hutchison", + password => "1234", + }, + N("Malta") . "|Go Mobile (Post-paid)" => { + apn => "gosurfing", + }, + N("Malta") . "|Go Mobile (Pre-paid)" => { + apn => "rtgsurfing", + }, + N("Malta") . "|Vodafone" => { + apn => "Internet", + login => "Internet", + password => "Internet", + }, + N("Mauritius") . "|Emtel" => { + apn => "WEB", + }, + N("Maldives") . "|Dhiraagu" => { + apn => "internet.dhimobile", + }, + N("Mexico") . "|TELCEL" => { + apn => "internet.itelcel.com", + login => "webgprs", + password => "webgprs2002", + dns => "148.233.151.245", + dns => "148.233.151.245", + }, + N("Mexico") . "|Iusacell" => { + cdma => 1, + }, + N("Malaysia") . "|DIGI" => { + apn => "diginet", + dns => "203.92.128.131", + dns => "203.92.128.132", + }, + N("Malaysia") . "|Maxis (contract)" => { + apn => "internet.gprs.maxis", + dns => "202.75.129.101", + dns => "10.216.4.21", + }, + N("Malaysia") . "|Maxis (pre-pay)" => { + apn => "net", + login => "maxis", + password => "net", + }, + N("Malaysia") . "|Timecel" => { + apn => "timenett.com.my", + dns => "203.121.16.85", + dns => "203.121.16.120", + }, + N("Malaysia") . "|TM Touch" => { + apn => "internet", + dns => "202.188.0.133", + }, + N("Malaysia") . "|Celcom" => { + apn => "celcom.net.my", + }, + N("Malaysia") . "|Maxis 3G (contract)" => { + apn => "unet", + login => "maxis", + password => "wap", + dns => "10.213.17.1", + dns => "10.213.17.2", + }, + N("Mozambique") . "|MCel" => { + apn => "isp.mcel.mz", + login => "guest", + password => "guest", + dns => "212.96.24.2", + dns => "212.96.24.1", + }, + N("Nigeria") . "|Zain" => { + apn => "wap", + login => "wap", + password => "wap", + }, + N("Nigeria") . "|MTN" => { + apn => "web.gprs.mtnnigeria.net", + login => "web", + password => "web", + }, + N("Nigeria") . "|Glo-Ng" => { + apn => "glosecure", + login => "gprs", + password => "gprs", + dns => "-", + }, + N("Nicaragua") . "|Alo Pcs" => { + apn => "internet.ideasalo.ni", + login => "internet", + password => "internet", + }, + N("Nicaragua") . "|Movistar" => { + apn => "internet.movistar.ni", + login => "internet", + password => "internet", + }, + N("Netherlands") . "|Hi" => { + apn => "portalmmm.nl", + }, + N("Netherlands") . "|KPN Mobile" => { + apn => "internet", + login => "KPN", + password => "gprs", + dns => "62.133.126.28", + dns => "62.133.126.29", + }, + N("Netherlands") . "|o2" => { + apn => "internet", + dns => "195.99.65.220", + dns => "195.99.66.220", + }, + N("Netherlands") . "|T-Mobile" => { + apn => "internet", + dns => "193.78.240.12", + dns => "193.79.242.39", + }, + N("Netherlands") . "|Telfort" => { + apn => "internet", + login => "telfortnl", + }, + N("Netherlands") . "|Vodafone" => { + apn => "live.vodafone.com", + login => "vodafone", + password => "vodafone", + }, + N("Netherlands") . "|Vodafone (business)" => { + apn => "office.vodafone.nl", + login => "vodafone", + password => "vodafone", + }, + N("Netherlands") . "|XS4ALL Mobiel Internet" => { + apn => "umts.xs4all.nl", + }, + N("Norway") . "|Netcom" => { + apn => "internet.netcom.no", + login => "netcom", + password => "netcom", + dns => "212.169.123.67 ", + dns => "212.45.188.254", + }, + N("Norway") . "|ice.net (Nordisk Mobiltelefon)" => { + cdma => 1, + login => "cdma", + password => "cdma", + }, + N("Norway") . "|Telenor" => { + apn => "internet", + dns => "212.17.131.3", + dns => "148.122.161.2", + }, + N("Norway") . "|TDC" => { + apn => "internet.no", + dns => "80.232.41.10", + dns => "80.232.41.20", + }, + N("Norway") . "|NetworkNorway" => { + apn => "internet", + }, + N("Norway") . "|OneCall" => { + apn => "internet", + }, + N("Norway") . "|Lebara" => { + apn => "internet", + }, + N("Norway") . "|Altibox" => { + apn => "internet", + }, + N("Norway") . "|SheTalks" => { + apn => "internet", + }, + N("Norway") . "|Telipol" => { + apn => "internet", + }, + N("Nepal") . "|Mero Mobile" => { + apn => "mero", + }, + N("New Zealand") . "|Vodafone" => { + apn => " live.vodafone.com", + dns => "202.20.93.10", + dns => "203.97.191.189", + }, + N("New Zealand") . "|Vodafone (restricted)" => { + apn => "www.vodafone.net.nz", + dns => "202.20.93.10", + dns => "203.97.191.189", + }, + N("New Zealand") . "|Vodafone (unrestricted)" => { + apn => "internet", + dns => "202.20.93.10", + dns => "203.97.191.189", + }, + N("Panama") . "|Cable and Wireless" => { + apn => "apn01.cwpanama.com.pa", + login => "xxx", + password => "xxx", + }, + N("Panama") . "|Movistar" => { + apn => "internet.movistar.pa", + login => "movistarpa", + password => "movistarpa", + }, + N("Oman") . "|Nawras" => { + apn => "isp.nawras.com.om", + }, + N("Peru") . "|Claro" => { + apn => "tim.pe", + login => "tim", + password => "tulibertad", + }, + N("Philippines") . "|Globe Telecom" => { + apn => "internet.globe.com.ph", + login => "globe", + password => "globe", + dns => "203.127.225.10", + dns => "203.127.225.11", + }, + N("Philippines") . "|Smart" => { + apn => "internet", + login => "witsductoor", + password => "banonoy", + dns => "202.57.96.3", + dns => "202.57.96.4", + }, + N("Philippines") . "|Sun Cellular" => { + apn => "minternet", + }, + N("Philippines") . "|Globe Telecoms (WAP)" => { + apn => "www.globe.com.ph", + login => "globe", + password => "globe", + dns => "203.127.225.10", + dns => "203.127.225.11", + }, + N("Pakistan") . "|Djuice" => { + apn => "172.18.19.11", + login => "telenor", + password => "telenor", + }, + N("Pakistan") . "|Mobilink GSM" => { + apn => "connect.mobilinkworld.com", + }, + N("Pakistan") . "|Mobilink GSM (jazz)" => { + apn => "jazzconnect.mobilinkworld.com", + }, + N("Pakistan") . "|Telenor" => { + apn => "internet", + login => "telenor", + password => "telenor", + }, + N("Pakistan") . "|Ufone" => { + apn => "ufone.internet", + login => "ufone", + password => "ufone", + }, + N("Pakistan") . "|ZONG" => { + apn => "zonginternet", + }, + N("Poland") . "|ERA" => { + apn => "erainternet", + login => "erainternet", + password => "erainternet", + dns => "213.158.194.1 ", + dns => "213.158.193.38", + }, + N("Poland") . "|Idea" => { + apn => "www.idea.pl", + login => "idea", + password => "idea", + dns => "194.9.223.79", + dns => "217.17.34.10", + }, + N("Poland") . "|Play Online" => { + apn => "Internet", + }, + N("Poland") . "|Polkomtel" => { + apn => "www.plusgsm.pl", + dns => "212.2.96.51 ", + dns => "212.2.96.52", + }, + N("Poland") . "|Heyah" => { + apn => "heyah.pl", + login => "heyah", + password => "heyah", + dns => "213.158.194.1", + dns => "213.158.193.38", + }, + N("Poland") . "|Orange" => { + apn => "internet", + login => "internet", + password => "internet", + dns => "194.9.223.79", + dns => "194.204.159.1", + }, + N("Poland") . "|iPlus" => { + apn => "www.plusgsm.pl", + dns => "212.2.96.51", + dns => "212.2.96.52", + }, + N("Portugal") . "|Kanguru" => { + apn => "myconnection", + dns => "62.169.67.172", + dns => "62.169.67.171", + }, + N("Portugal") . "|Kanguru (fixo)" => { + apn => "kangurufixo", + dns => "62.169.67.172", + dns => "62.169.67.171", + }, + N("Portugal") . "|Optimus" => { + apn => "internet", + dns => "194.79.69.129", + }, + N("Portugal") . "|TMN" => { + apn => "internet", + dns => "194.65.3.20", + dns => "194.65.3.21", + }, + N("Portugal") . "|Vodafone" => { + apn => "internet.vodafone.pt", + dns => "212.18.160.133", + dns => "212.18.160.134", + }, + N("Paraguay") . "|CTI" => { + apn => "internet.ctimovil.com.py", + login => "ctigprs", + password => "ctigprs999", + }, + N("Romania") . "|Orange" => { + apn => "internet", + dns => "172.22.7.21 ", + dns => "172.22.7.20", + }, + N("Romania") . "|Vodafone" => { + apn => "internet.vodafone.ro", + login => "internet.vodafone.ro", + password => "vodafone", + dns => "193.230.161.3", + dns => "193.230.161.4", + }, + N("Romania") . "|Zapp" => { + cdma => 1, + login => "zapp", + password => "zapp", + }, + N("Serbia") . "|Mobtel Srbija" => { + apn => "internet", + login => "mobtel", + password => "gprs", + dns => "217.65.192.1", + dns => "217.65.192.52", + }, + N("Serbia") . "|Telekom Srbija (default)" => { + apn => "gprsinternet", + login => "mts", + password => "64", + dns => "195.178.38.3", + }, + N("Serbia") . "|Telekom Srbija (via MMS)" => { + apn => "mms", + login => "mts", + password => "64", + dns => "195.178.38.3", + }, + N("Serbia") . "|Telekom Srbija (via wap)" => { + apn => "gprswap", + login => "mts", + password => "64", + dns => "195.178.38.3", + }, + N("Russian Federation") . "|BaikalWestCom" => { + apn => "inet.bwc.ru", + login => "bwc", + password => "bwc", + dns => "81.18.113.2", + dns => "81.18.112.50", + }, + N("Russian Federation") . "|Beeline" => { + apn => "internet.beeline.ru", + login => "beeline", + password => "beeline", + dns => "217.118.66.243", + dns => "217.118.66.244", + }, + N("Russian Federation") . "|Megafon (nw)" => { + apn => "internet.nw", + dns => "10.140.142.42 ", + dns => "10.140.142.45", + }, + N("Russian Federation") . "|МТС" => { + apn => "internet.mts.ru", + login => "mts", + password => "mts", + dns => "213.87.0.1", + dns => "213.87.1.1", + }, + N("Russian Federation") . "|PrimTelephone" => { + apn => "internet.primtel.ru", + }, + N("Russian Federation") . "|Megafon (ugsm)" => { + apn => "internet.ugsm", + dns => "83.149.32.2 ", + dns => "83.149.33.2", + }, + N("Russian Federation") . "|Megafon (usi)" => { + apn => "internet.usi.ru", + dns => "212.120.160.130 ", + dns => "212.120.160.130", + }, + N("Russian Federation") . "|Megafon (dv)" => { + apn => "internet.dv", + dns => "83.149.52.77", + dns => "194.186.112.18", + }, + N("Russian Federation") . "|Megafon (kvk)" => { + apn => "internet.kvk", + dns => "83.149.24.244 ", + dns => "62.183.50.230", + }, + N("Russian Federation") . "|Megafon (ltmsk)" => { + apn => "internet.ltmsk", + dns => "10.22.10.20 ", + dns => "10.22.10.21", + }, + N("Russian Federation") . "|Megafon (sib)" => { + apn => "internet.sib", + dns => "83.149.51.65 ", + dns => "83.149.50.65", + }, + N("Russian Federation") . "|Megafon (volga)" => { + apn => "internet.volga", + dns => "83.149.16.7 ", + dns => "195.128.128.1", + }, + N("Russian Federation") . "|Megafon (mc)" => { + apn => "internet.mc", + dns => "81.18.129.252 ", + dns => "217.150.34.1", + }, + N("Russian Federation") . "|NCC" => { + apn => "internet", + login => "ncc", + dns => "10.0.3.5 ", + dns => "10.0.3.2", + }, + N("Russian Federation") . "|NTC" => { + apn => "internet.ntc", + dns => "80.243.64.67 ", + dns => "80.243.68.34", + }, + N("Russian Federation") . "|Megafon (Moscow)" => { + apn => "internet", + login => "gdata", + password => "gdata", + }, + N("Russian Federation") . "|Enisey TeleCom" => { + apn => "internet.etk.ru", + login => "etk", + dns => "10.10.30.3", + dns => "10.10.30.4", + }, + N("Russian Federation") . "|Motiv" => { + apn => "inet.ycc.ru", + login => "motiv", + dns => "217.148.52.34", + dns => "217.148.52.3", + }, + N("Russian Federation") . "|Tatincom" => { + apn => "internet.tatincom.ru", + login => "tatincom", + password => "tatincom", + dns => "89.207.96.2", + dns => "89.207.97.18", + }, + N("Russian Federation") . "|Tele2" => { + apn => "wap.tele2.ru", + login => "gprs", + dns => "130.244.127.161", + dns => "130.244.127.169", + }, + N("Russian Federation") . "|Skylink (Moscow)" => { + cdma => 1, + login => "mobile@skylink.msk.ru", + password => "internet", + }, + N("Saudi Arabia") . "|Mobily" => { + apn => "web2", + }, + N("Saudi Arabia") . "|STC" => { + apn => "jawalnet.com.sa", + dns => "212.118.133.101", + dns => "212.118.133.102", + }, + N("Sweden") . "|3 (Mobiltelefon)" => { + apn => "data.tre.se", + }, + N("Sweden") . "|3 (Bredband)" => { + apn => "bredband.tre.se", + }, + N("Sweden") . "|3 (Bredband Kontantkort)" => { + apn => "net.tre.se", + }, + N("Sweden") . "|Glocalnet" => { + apn => "internet.glocalnet.se", + }, + N("Sweden") . "|Halebop" => { + apn => "halebop.telia.se", + }, + N("Sweden") . "|ice.net (Nordisk Mobiltelefon)" => { + cdma => 1, + login => "cdma", + password => "cdma", + }, + N("Sweden") . "|Tele2/Comviq" => { + apn => "internet.tele2.se", + }, + N("Sweden") . "|Telenor" => { + apn => "internet.telenor.se", + }, + N("Sweden") . "|Telia" => { + apn => "online.telia.se", + }, + N("Singapore") . "|M1" => { + apn => "sunsurf", + login => "65", + password => "user123", + dns => "202.79.64.21", + dns => "202.79.64.26", + }, + N("Singapore") . "|SingTel" => { + apn => "internet", + dns => "165.21.100.88", + dns => "165.21.83.88", + }, + N("Singapore") . "|Starhub" => { + apn => "shwap", + login => "star", + password => "hub", + dns => "203.116.1.78", + }, + N("Slovenia") . "|Mobitel (postpaid)" => { + apn => "internet", + login => "mobitel", + password => "internet", + dns => "213.229.248.161 ", + dns => "193.189.160.11", + }, + N("Slovenia") . "|Mobitel (prepaid)" => { + apn => "internetpro", + login => "mobitel", + password => "internet", + dns => "213.229.248.161 ", + dns => "193.189.160.11", + }, + N("Slovenia") . "|Simobil" => { + apn => "none", + dns => "121.30.86.130", + dns => "193.189.160.11", + }, + N("Slovakia") . "|T-Mobile (EuroTel)" => { + apn => "internet", + dns => "194.154.230.66 ", + dns => "194.154.230.74", + }, + N("Slovakia") . "|Globtel" => { + apn => "internet", + dns => "213.151.200.3", + dns => "195.12.140.130", + }, + N("Slovakia") . "|Orange" => { + apn => "internet", + login => "jusernejm", + password => "pasvord", + dns => "213.151.200.30 ", + dns => "213.151.208.161", + }, + N("Slovakia") . "|Eurotel" => { + apn => "internet", + dns => "194.154.230.64", + dns => "194.154.230.74", + }, + N("Senegal") . "|Tigo" => { + apn => "internet.tigo.hn", + dns => "200.85.0.104", + dns => "200.85.0.107", + }, + N("El Salvador") . "|movistar" => { + apn => "movistar.sv", + login => "movistarsv", + password => "movistarsv", + }, + N("Thailand") . "|AIS" => { + apn => "internet", + dns => "202.183.255.20", + dns => "202.183.255.21", + }, + N("Thailand") . "|DTAC" => { + apn => "www.dtac.co.th", + dns => "202.44.202.2", + dns => "203.44.144.33", + }, + N("Thailand") . "|True" => { + apn => "internet", + login => "true", + password => "true", + }, + N("Turkey") . "|Aria" => { + apn => "internet", + dns => "212.156.4.4", + dns => "212.156.4.20", + }, + N("Turkey") . "|Aycell" => { + apn => "aycell", + dns => "212.156.4.1", + dns => "212.156.4.4", + }, + N("Turkey") . "|Turkcell" => { + apn => "internet", + login => "gprs", + password => "gprs", + dns => "86.108.136.27", + dns => "86.108.136.26", + }, + N("Turkey") . "|Telsim (Post-paid)" => { + apn => "telsim", + login => "telsim", + password => "telsim", + dns => "212.65.128.20", + dns => "212.156.4.7", + }, + N("Turkey") . "|Telsim (pre-paid)" => { + apn => "prepaidgprs", + dns => "212.65.128.20", + dns => "212.156.4.7", + }, + N("Trinidad and Tobago") . "|Digicel" => { + apn => "wap.digiceltt.com", + login => "wap", + password => "wap", + }, + N("Trinidad and Tobago") . "|TSTT" => { + apn => "internet", + login => "wap", + password => "wap", + }, + N("Taiwan") . "|Chunghwa Telecom (emome)" => { + apn => "internet", + }, + N("Taiwan") . "|Far EasTone / KGT" => { + apn => "internet", + }, + N("Taiwan") . "|TW Mobile / TransAsia" => { + apn => "internet", + }, + N("Taiwan") . "|Vibo Telecom / Aurora" => { + apn => "vibo", + }, + N("Taiwan") . "|Asia Pacific Telecom (APBW)" => { + cdma => 1, + }, + N("Ukraine") . "|Jeans" => { + apn => "www.jeans.ua", + dns => "80.255.64.23", + dns => "80.255.64.24", + }, + N("Ukraine") . "|Djuice" => { + apn => "www.djuice.com.ua", + dns => "212.58.160.33", + dns => "212.58.160.34", + }, + N("Ukraine") . "|Mobi-GSM" => { + apn => "internet.urs", + dns => "213.186.192.254", + dns => "193.239.128.5", + }, + N("Ukraine") . "|Ace&Base" => { + apn => "www.ab.kyivstar.net", + login => "igprs", + password => "internet", + }, + N("Ukraine") . "|Life (standard)" => { + apn => "internet", + dns => "212.58.160.33", + dns => "212.58.160.34", + }, + N("Ukraine") . "|Beeline" => { + apn => "internet.beeline.ua", + }, + N("Ukraine") . "|Life (faster)" => { + apn => "speed", + dns => "212.58.160.33", + dns => "212.58.160.34", + }, + N("Ukraine") . "|Wellcome" => { + apn => "internet.urs", + dns => "213.186.192.254", + dns => "193.239.128.5", + }, + N("Ukraine") . "|Jeans (Hyper)" => { + apn => "hyper.net", + dns => "212.58.160.33", + dns => "212.58.160.34", + }, + N("Ukraine") . "|UMC (internet)" => { + apn => "internet", + login => "internet", + dns => "212.58.160.33", + dns => "212.58.160.34", + }, + N("Ukraine") . "|UMC (umc.ua)" => { + apn => "www.umc.ua", + dns => "80.255.64.23", + dns => "80.255.64.24", + }, + N("Ukraine") . "|Utel" => { + apn => "3g.utel.ua", + }, + N("Uganda") . "|MTN" => { + apn => "yellopix.mtn.co.ug", + dns => "212.88.97.20", + dns => "212.88.97.67", + }, + N("United States") . "|AT&T" => { + apn => "WAP.CINGULAR", + login => "WAP@CINGULARGPRS.COM", + password => "CINGULAR1", + }, + N("United States") . "|AT&T (Tethering)" => { + apn => "ISP.CINGULAR", + login => "ISP@CINGULARGPRS.COM", + password => "CINGULAR1", + }, + N("United States") . "|AT&T (Tethering with data acceleration)" => { + apn => "ISP.CINGULAR", + login => "ISPDA@CINGULARGPRS.COM", + password => "CINGULAR1", + }, + N("United States") . "|T-Mobile (Web)" => { + apn => "wap.voicestream.com", + }, + N("United States") . "|T-Mobile (Internet)" => { + apn => "internet2.voicestream.com", + }, + N("United States") . "|T-Mobile (Internet with VPN)" => { + apn => "internet3.voicestream.com", + }, + N("United States") . "|Sprint" => { + cdma => 1, + }, + N("United States") . "|Boost Mobile (Prepaid)" => { + cdma => 1, + }, + N("United States") . "|Verizon" => { + cdma => 1, + }, + N("United States") . "|US Cellular" => { + cdma => 1, + }, + N("United States") . "|Alltel" => { + cdma => 1, + }, + N("United States") . "|Leap Wireless" => { + cdma => 1, + }, + N("United States") . "|Cricket Communications" => { + cdma => 1, + }, + N("United States") . "|Jump Mobile (Prepaid)" => { + cdma => 1, + }, + N("United States") . "|MetroPCS" => { + cdma => 1, + }, + N("Uruguay") . "|Ancel" => { + apn => "gprs.ancel", + dns => "200.40.30.245 ", + dns => "200.40.220.245", + }, + N("Uruguay") . "|CTI" => { + apn => "internet.ctimovil.com.uy", + login => "ctiweb", + password => "ctiweb999", + }, + N("Uruguay") . "|Movistar" => { + apn => "webapn.movistar.com.uy", + login => "movistar", + password => "movistar", + }, + N("Uzbekistan") . "|Uzdunrobita" => { + apn => "net.urd.uz", + login => "user", + password => "pass", + }, + N("Saint Vincent and the Grenadines") . "|Digicel" => { + apn => "wap.digiceloecs.com", + login => "wapoecs", + password => "wap03oecs", + }, + N("Venezuela") . "|Digitel TIM" => { + apn => "gprsweb.digitel.ve", + dns => "57.67.127.195", + }, + N("South Africa") . "|Cell-c" => { + apn => "internet", + login => "Cellcis", + password => "Crap", + dns => "196.7.0.138", + dns => "196.7.142.132", + }, + N("South Africa") . "|MTN" => { + apn => "internet", + dns => "196.11.240.241", + dns => "209.212.97.1", + }, + N("South Africa") . "|Vodacom" => { + apn => "internet", + dns => "196.207.40.165", + dns => "196.43.46.190", + }, + N("South Africa") . "|Virgin Mobile" => { + apn => "vdata", + dns => "196.7.0.138", + dns => "196.7.142.132", + }, + N("South Africa") . "|Vodacom (unrestricted APN)" => { + apn => "unrestricted", + dns => "196.207.32.69", + dns => "196.43.45.190", + }, +); + +1; diff --git a/lib/network/connection/providers/xdsl.pm b/lib/network/connection/providers/xdsl.pm new file mode 100644 index 0000000..52b1b58 --- /dev/null +++ b/lib/network/connection/providers/xdsl.pm @@ -0,0 +1,1352 @@ +# -*- coding: utf-8 -*- +package network::connection::providers::xdsl; # $Id: xdsl.pm 59309 2006-09-01 12:08:15Z tv $ + +# This should probably be splitted out into ldetect-lst as some provider db + +use common; +use utf8; + +# Originally from : +# http://www.eagle-usb.org/article.php3?id_article=23 +# http://www.sagem.com/web-modems/download/support-fast1000-fr.htm +# http://perso.wanadoo.fr/michel-m/protocolesfai.htm +# Then other ISP found in : +# http://www.adslayuda.com/Comtrend500+file-16.html + +# the output is provided in html at http://faq.eagle-usb.org/wakka.php?wiki=ListConfigADSL +# this file should be put in /usr/share/eagle-usb/ for eagle-usb driver +# or in /usr/lib/libDrakX/network/ as part of the drakxtools + +our %data = ( + ## format chosen is the following : + # country|provider => { VPI, VCI_hexa, ... } all parameters + # country is automagically translated into LANG with N function + # provider is kept "as-is", not translated + # provider_id is used by eagleconfig to identify an ISP (I use ISO_3166-1) + # see http://en.wikipedia.org/wiki/ISO_3166-1 + # url_tech : technical URL providing info about ISP + # vpi : virtual path identifier + # vci : virtual channel identifier (in hexa below !!) + # Encapsulation: + # 1=PPPoE LLC, 2=PPPoE VCmux (never used ?) + # 3=RFC1483/2684 Routed IP LLC, + # 4=RFC1483/2684 Routed IP (IPoA VCmux) + # 5 RFC2364 PPPoA LLC, + # 6 RFC2364 PPPoA VCmux + # see http://faq.eagle-usb.org/wakka.php?wiki=AdslDescription + # dns are provided for when !usepeerdns in peers config file + # dnsServers : array ref with any valid DNS (order matters) + # DOMAINNAME2 : used for search key in /etc/resolv.conf + # method : PPPoA, pppoe, static or dhcp + # login_format : e.g. fti/login for France Telecom + # encryption : for pppd connection, when encryption is supported + # modem : model of modem provided by ISP or tested with ISP + # please forward updates to http://forum.eagle-usb.org + # try to order alphabetically by country (in English) / ISP (local language) + + N("Algeria") . "|Wanadoo" => + { + provider_id => 'DZ01', + vpi => 0, + vci => 23, + Encapsulation => 1, + method => 'pppoe', + dnsServers => [ qw(82.101.136.29 82.101.136.206) ], + }, + + N("Algeria") . "|Algerie Telecom (FAWRI)" => + { + provider_id => 'DZ02', + vpi => 0, + vci => 26, + Encapsulation => 1, + method => 'pppoe', + dnsServers => [ qw(61.88.88.88 205.252.144.228) ], + }, + + N("Argentina") . "|Speedy" => + { + provider_id => 'AR01', + vpi => 8, + vci => 23, + Encapsulation => 1, + method => 'pppoe', + dnsServers => [ qw(200.51.254.238 200.51.209.22) ], + }, + + N("Argentina") . "|Arnet" => + { + provider_id => 'AR02', + vpi => 8, + vci => 21, + Encapsulation => 1, + method => 'pppoe', + dnsServers => [ qw(200.45.191.35 200.45.191.40) ], + }, + + N("Austria") . "|" . N("Any") => + { + provider_id => 'AT00', + vpi => 8, + vci => 30, + Encapsulation => 6, + method => 'pppoa', + }, + + N("Austria") . "|AON" => + { + provider_id => 'AT01', + vpi => 1, + vci => 20, + Encapsulation => 6, + method => 'pppoa', + }, + + N("Austria") . "|Telstra" => + { + provider_id => 'AT02', + vpi => 8, + vci => 23, + Encapsulation => 1, + method => 'pppoe', + }, + + N("Australia") . "|Arachnet" => + { + provider_id => 'AU01', + url_tech => "http://www.ains.com.au/consumer/support/technical.htm", + vpi => 8, + vci => 23, + Encapsulation => 6, + method => 'pppoa', + }, + + N("Australia") . "|Speedstream On net" => + { + provider_id => 'AU02', + url_tech => "http://www.ains.com.au/consumer/support/technical.htm", + vpi => 8, + vci => 22, + Encapsulation => 6, + method => 'pppoa', + }, + + N("Australia") . "|Speedstream Off net" => + { + provider_id => 'AU03', + url_tech => "http://www.ains.com.au/consumer/support/technical.htm", + vpi => 8, + vci => 23, + Encapsulation => 1, + method => 'pppoe', + }, + + N("Belgium") . "|ADSL Office" => + { + provider_id => 'BE04', + vpi => 8, + vci => 23, + Encapsulation => 3, + method => 'pppoe', + }, + + N("Belgium") . "|Tiscali BE" => + { + provider_id => 'BE01', + vpi => 8, + vci => 23, + Encapsulation => 6, + method => 'pppoa', + dnsServers => [ qw(212.35.2.1 212.35.2.2 212.233.1.34 212.233.2.34) ], + DOMAINNAME2 => 'tiscali.be', + }, + + N("Belgium") . "|Belgacom" => + { + provider_id => 'BE03', + vpi => 8, + vci => 23, + Encapsulation => 6, + method => 'pppoa', + }, + + N("Belgium") . "|Turboline" => + { + provider_id => 'BE02', + vpi => 8, + vci => 23, + Encapsulation => 5, + method => 'pppoa', + }, + + N("Belgium") . "|Scarlet ADSL" => + { + provider_id => 'BE05', + vpi => 8, + vci => 20, + Encapsulation => 6, + method => 'pppoa', + }, + + N("Brazil") . "|Speedy/Telefonica" => + { + provider_id => 'BR01', + vpi => 8, + vci => 23, + Encapsulation => 1, + method => 'pppoe', + dnsServers => [ qw(200.204.0.10 200.204.0.138) ], + }, + + N("Brazil") . "|Velox/Telemar" => + { + provider_id => 'BR02', + vpi => 0, + vci => 21, + Encapsulation => 1, + method => 'pppoe', + }, + + N("Brazil") . "|Turbo/Brasil Telecom" => + { + provider_id => 'BR03', + vpi => 0, + vci => 23, + Encapsulation => 1, + method => 'pppoe', + }, + + N("Brazil") . "|Rio Grande do Sul (RS)" => + { + provider_id => 'BR04', + vpi => 1, + vci => 20, + Encapsulation => 1, + method => 'pppoe', + }, + + N("Bulgaria") . "|BTK ISDN" => + { + provider_id => 'BG02', + vpi => 1, + vci => 20, + Encapsulation => 1, + method => 'pppoe', + }, + + N("Bulgaria") . "|BTK POTS" => + { + provider_id => 'BG01', + vpi => 0, + vci => 23, + Encapsulation => 1, + method => 'pppoe', + }, + + N("China") . "|China Netcom|Beijing" => + { + provider_id => 'CN01', + vpi => 0, + vci => 23, + Encapsulation => 3, + method => 'pppoe', + }, + + N("China") . "|China Netcom|Changchun" => + { + provider_id => 'CN02', + vpi => 8, + vci => 23, + Encapsulation => 3, + method => 'pppoe', + }, + + N("China") . "|China Netcom|Harbin" => + { + provider_id => 'CN03', + vpi => 8, + vci => 23, + Encapsulation => 3, + method => 'pppoe', + }, + + N("China") . "|China Netcom|Jilin" => + { + provider_id => 'CN04', + vpi => 0, + vci => 27, + Encapsulation => 3, + method => 'pppoe', + }, + + N("China") . "|China Netcom|Lanzhou" => + { + provider_id => 'CN05', + vpi => 0, + vci => 20, + Encapsulation => 3, + method => 'pppoe', + }, + + N("China") . "|China Netcom|Tianjin" => + { + provider_id => 'CN06', + vpi => 0, + vci => 23, + Encapsulation => 3, + method => 'pppoe', + }, + + N("China") . "|China Netcom|Xi'an" => + { + provider_id => 'CN07', + vpi => 8, + vci => 23, + Encapsulation => 3, + method => 'pppoe', + }, + + N("China") . "|China Telecom|Chongqing" => + { + provider_id => 'CN08', + vpi => 0, + vci => 23, + Encapsulation => 3, + method => 'pppoe', + }, + + N("China") . "|China Telecom|Fujian" => + { + provider_id => 'CN09', + vpi => 0, + vci => 0xc8, + Encapsulation => 3, + method => 'pppoe', + }, + + N("China") . "|China Telecom|Guangxi" => + { + provider_id => 'CN10', + vpi => 0, + vci => 23, + Encapsulation => 3, + method => 'pppoe', + }, + + N("China") . "|China Telecom|Guangzhou" => + { + provider_id => 'CN11', + vpi => 8, + vci => 20, + Encapsulation => 3, + method => 'pppoe', + }, + + N("China") . "|China Telecom|Hangzhou" => + { + provider_id => 'CN12', + vpi => 0, + vci => 20, + Encapsulation => 3, + method => 'pppoe', + }, + + N("China") . "|China Netcom|Hunan" => + { + provider_id => 'CN13', + vpi => 0, + vci => 23, + Encapsulation => 3, + method => 'pppoe', + }, + + N("China") . "|China Telecom|Nanjing" => + { + provider_id => 'CN14', + vpi => 8, + vci => 23, + Encapsulation => 3, + method => 'pppoe', + }, + + N("China") . "|China Telecom|Shanghai" => + { + provider_id => 'CN15', + vpi => 8, + vci => 51, + Encapsulation => 3, + method => 'pppoe', + }, + + N("China") . "|China Telecom|Shenzhen" => + { + provider_id => 'CN16', + vpi => 8, + vci => 23, + Encapsulation => 3, + method => 'pppoe', + }, + + N("China") . "|China Telecom|Urumqi" => + { + provider_id => 'CN17', + vpi => 0, + vci => 20, + Encapsulation => 3, + method => 'pppoe', + }, + + N("China") . "|China Telecom|Wuhan" => + { + provider_id => 'CN18', + vpi => 0, + vci => 20, + Encapsulation => 3, + method => 'pppoe', + }, + + N("China") . "|China Telecom|Yunnan" => + { + provider_id => 'CN19', + vpi => 0, + vci => 23, + Encapsulation => 3, + method => 'pppoe', + }, + + N("China") . "|China Telecom|Zhuhai" => + { + provider_id => 'CN20', + vpi => 0, + vci => 23, + Encapsulation => 3, + method => 'pppoe', + }, + + N("Czech Republic") . "|Cesky Telecom PPPoA" => + { + provider_id => 'CZ01', + url_tech => 'http://www.telecom.cz/domacnosti/internet/pristupove_sluzby/broadband/vse_o_kz_a_moznostech_instalace.php', + vpi => 8, + vci => 30, + Encapsulation => 6, + method => 'pppoa', + }, + + N("Czech Republic") . "|Cesky Telecom PPPoE" => + { + provider_id => 'CZ02', + url_tech => 'http://www.telecom.cz/zakaznicka_podpora/dokumenty_ke_stazeni/internet_expres.php', + vpi => 8, + vci => 30, + Encapsulation => 1, + method => 'pppoe', + }, + + N("Denmark") . "|" . N("Any") => + { + provider_id => 'DK01', + vpi => 0, + vci => 65, + Encapsulation => 3, + method => 'pppoe', + }, + + N("Denmark") . "|Cybercity" => + { + provider_id => 'DK02', + vpi => 0, + vci => 23, + Encapsulation => 6, + method => 'pppoa', + }, + + N("Denmark") . "|Tiscali" => + { + provider_id => 'DK03', + vpi => 0, + vci => 23, + Encapsulation => 6, + method => 'pppoa', + }, + + N("Egypt") . "|Raya Telecom" => + { + provider_id => 'EG01', + vpi => 8, + vci => 50, + method => 'pppoa', + Encapsulation => 6, + dnsServers => [ qw(62.240.110.197 62.240.110.198) ], + }, + + N("Finland") . "|Sonera" => + { + provider_id => 'FI01', + vpi => 0, + vci => 64, + Encapsulation => 3, + method => 'pppoe', + }, + + N("France") . "|Free non dégroupé 512/128 & 1024/128" => + { + provider_id => 'FR01', + vpi => 8, + vci => 23, + Encapsulation => 6, + CMVep => 'FR', + dnsServers => [ qw(213.228.0.23 212.27.32.176) ], + method => 'pppoa', + DOMAINNAME2 => 'free.fr', + }, + + N("France") . "|Free non dégroupé ADSL Max" => + { + provider_id => 'FR11', + vpi => 8, + vci => 23, + Encapsulation => 6, + CMVep => 'FR04', + dnsServers => [ qw(213.228.0.23 212.27.32.176) ], + method => 'pppoa', + DOMAINNAME2 => 'free.fr', + }, + + N("France") . "|Free dégroupé 1024/256 (mini)" => + { + provider_id => 'FR04', + vpi => 8, + vci => 24, + Encapsulation => 4, + CMVep => 'FR04', + dnsServers => [ qw(213.228.0.23 212.27.32.176 213.228.0.68 212.27.32.176 212.27.32.177 212.27.39.2 212.27.39.1) ], + method => 'dhcp', + DOMAINNAME2 => 'free.fr', + }, + + N("France") . "|n9uf tel9com 512 & dégroupé 1024" => + { + provider_id => 'FR05', + vpi => 8, + vci => 23, + Encapsulation => 6, + CMVep => 'FR', + dnsServers => [ qw(212.30.93.108 212.203.124.146 62.62.156.12 62.62.156.13) ], + method => 'pppoa', + }, + + N("France") . "|Cegetel non dégroupé 512 IP/ADSL et dégroupé" => + { + provider_id => 'FR08', + vpi => 8, + vci => 23, + Encapsulation => 6, + CMVep => 'FR', + dnsServers => [ qw(212.94.174.85 212.94.174.86) ], + method => 'pppoa', + login_format => 'login@cegetel.net', + }, + + N("France") . "|Cegetel ADSL Max 8 Mb" => + { + provider_id => 'FR10', + vpi => 8, + vci => 23, + Encapsulation => 6, + CMVep => 'FR10', + dnsServers => [ qw(212.94.174.85 212.94.174.86) ], + method => 'pppoa', + login_format => 'login@cegetel.net', + }, + + N("France") . "|Club-Internet" => + { + provider_id => 'FR06', + vpi => 8, + vci => 23, + Encapsulation => 6, + CMVep => 'FR', + dnsServers => [ qw(194.117.200.10 194.117.200.15) ], + method => 'pppoa', + DOMAINNAME2 => 'club-internet.fr', + }, + + N("France") . "|Orange" => + { + provider_id => 'FR09', + vpi => 8, + vci => 23, + Encapsulation => 6, + CMVep => 'FR', + dnsServers => [ qw(80.10.246.2 80.10.246.129) ], + method => 'pppoa', + login_format => 'fti/login', + DOMAINNAME2 => 'orange.fr', + }, + + N("France") . "|Télé2" => + { + provider_id => 'FR02', + vpi => 8, + vci => 23, + Encapsulation => 6, + CMVep => 'FR', + dnsServers => [ qw(212.151.136.242 130.244.127.162 212.151.136.246) ], + method => 'pppoa', + }, + + N("France") . "|Tiscali.fr 128k" => + { + provider_id => 'FR03', + vpi => 8, + vci => 23, + Encapsulation => 5, + CMVep => 'FR', + dnsServers => [ qw(213.36.80.1 213.36.80.2) ], + method => 'pppoa', + }, + + N("France") . "|Tiscali.fr 512k" => + { + provider_id => 'FR07', + vpi => 8, + vci => 23, + Encapsulation => 6, + CMVep => 'FR', + dnsServers => [ qw(213.36.80.1 213.36.80.2) ], + method => 'pppoa', + }, + + N("Germany") . "|Deutsche Telekom (DT)" => + { + provider_id => 'DE01', + vpi => 1, + vci => 20, + Encapsulation => 1, + method => 'pppoe', + }, + + N("Germany") . "|1&1" => + { + provider_id => 'DE02', + vpi => 1, + vci => 20, + Encapsulation => 1, + dnsServers => [ qw(195.20.224.234 194.25.2.129) ], + method => 'pppoe', + }, + + N("Germany") . "|Alice DSL" => + { + provider_id => 'DE03', + vpi => 1, + vci => 20, + Encapsulation => 1, + dnsServers => [ qw(213.191.73.65 213.191.74.20) ], + method => 'pppoe', + }, + + N("Greece") . "|" . N("Any") => + { + provider_id => 'GR01', + vpi => 8, + vci => 23, + Encapsulation => 6, + method => 'pppoa', + }, + + N("Hungary") . "|Matav" => + { + provider_id => 'HU01', + vpi => 1, + vci => 20, + Encapsulation => 1, + method => 'pppoe', + }, + + N("Ireland") . "|" . N("Any") => + { + provider_id => 'IE01', + vpi => 8, + vci => 23, + Encapsulation => 1, + method => 'pppoe', + }, + + N("Israel") . "|Barak 013" => + { + provider_id => 'IL03', + vpi => 8, + vci => 48, + Encapsulation => 6, + dnsServers => [ qw(212.150.49.10 206.49.94.234 212.150.48.169) ], + method => 'pppoa' + }, + + N("Israel") . "|Bezeq 014" => + { + provider_id => 'IL04', + vpi => 8, + vci => 48, + Encapsulation => 6, + dnsServers => [ qw(192.115.106.10 192.115.106.11 192.115.106.35) ], + method => 'pppoa' + }, + + N("Israel") . "|Bezeq" => + { + provider_id => 'IL01', + vpi => 8, + vci => 30, + Encapsulation => 6, + dnsServers => [ qw(192.115.106.10 192.115.106.11 192.115.106.35) ], + method => 'pppoa', + }, + + N("Israel") . "|BGU" => + { + provider_id => 'IL06', + vpi => 8, + vci => 48, + Encapsulation => 6, + dnsServers => [ qw(132.72.140.46 132.72.140.45) ], + method => 'pppoa' + }, + + N("Israel") . "|HaifaU" => + { + provider_id => 'IL07', + vpi => 8, + vci => 48, + Encapsulation => 6, + dnsServers => [ qw(132.74.1.3 132.74.1.5) ], + method => 'pppoa' + }, + + N("Israel") . "|HUJI" => + { + provider_id => 'IL08', + vpi => 8, + vci => 48, + Encapsulation => 6, + dnsServers => [ qw(128.139.6.1 128.139.4.3) ], + method => 'pppoa' + }, + + N("Israel") . "|Kavey Zahave 012" => + { + provider_id => 'IL02', + vpi => 8, + vci => 48, + Encapsulation => 6, + dnsServers => [ qw(212.117.129.3 212.117.128.6) ], + method => 'pppoa' + }, + + N("Israel") . "|Netvision 017" => + { + provider_id => 'IL01', + vpi => 8, + vci => 48, + Encapsulation => 6, + dnsServers => [ qw(212.143.212.143 194.90.1.5) ], + method => 'pppoa' + }, + + N("Israel") . "|Smile 015" => + { + provider_id => 'IL05', + vpi => 8, + vci => 48, + Encapsulation => 6, + dnsServers => [ qw(192.116.202.222 213.8.172.83) ], + method => 'pppoa' + }, + + N("Israel") . "|TAU" => + { + provider_id => 'IL09', + vpi => 8, + vci => 48, + Encapsulation => 6, + dnsServers => [ qw(132.66.32.10 132.66.16.2) ], + method => 'pppoa' + }, + + N("Israel") . "|Technion" => + { + provider_id => 'IL10', + vpi => 8, + vci => 48, + Encapsulation => 6, + dnsServers => [ qw(132.68.1.2 132.68.1.9) ], + method => 'pppoa' + }, + + N("India") . "|" . N("Any") => + { + provider_id => 'IN01', + vpi => 0, + vci => 20, + Encapsulation => 6, + method => 'pppoa', + }, + + N("Iceland") . "|Islandssimi" => + { + provider_id => 'IS01', + vpi => 0, + vci => 23, + Encapsulation => 6, + method => 'pppoa', + }, + + N("Iceland") . "|Landssimi" => + { + provider_id => 'IS02', + vpi => 8, + vci => 30, + Encapsulation => 6, + method => 'pppoa', + }, + + N("Italy") . "|Telecom Italia" => + { + provider_id => 'IT01', + vpi => 8, + vci => 23, + Encapsulation => 6, + CMVep => 'IT', + dnsServers => [ qw(195.20.224.234 194.25.2.129) ], + method => 'pppoa', + }, + + N("Italy") . "|Telecom Italia/Office Users (ADSL Smart X)" => + { + provider_id => 'IT02', + vpi => 8, + vci => 23, + Encapsulation => 3, + CMVep => 'IT', + method => 'static', + }, + + N("Italy") . "|Tiscali.it, Alice" => + { + provider_id => 'IT03', + vpi => 8, + vci => 23, + Encapsulation => 6, + CMVep => 'IT', + dnsServers => [ qw(195.20.224.234 194.25.2.129) ], + method => 'pppoa', + }, + + N("Italy") . "|Libero.it" => + { + provider_id => 'IT04', + url_tech => 'http://internet.libero.it/assistenza/adsl/installazione_ass.phtml', + vpi => 8, + vci => 23, + Encapsulation => 6, + CMVep => 'IT', + dnsServers => [ qw(193.70.192.25 193.70.152.25) ], + method => 'pppoa', + }, + + N("Sri Lanka") . "|Srilanka Telecom" => + { + provider_id => 'LK01', + url_tech => 'http://www.sltnet.lk', + vpi => 8, + vci => 23, + Encapsulation => 6, + dnsServers => [ qw(203.115.0.1 203.115.0.18) ], + method => 'pppoa', + encryption => 1, + }, + + N("Lithuania") . "|Lietuvos Telekomas" => + { + provider_id => 'LT01', + vpi => 8, + vci => 23, + Encapsulation => 1, + method => 'pppoe', + }, + + N("Mauritius") . "|wanadoo.mu" => + { + provider_id => 'MU01', + vpi => 8, + vci => 23, + Encapsulation => 6, + dnsServers => [ qw(202.123.2.6 202.123.2.11) ], + method => 'pppoa', + }, + + N("Mauritius") . "|Telecom Plus (Mauritius Telecom)" => + { + provider_id => 'MU02', + url_tech => 'http://www.telecomplus.net', + vpi => 8, + vci => 23, + Encapsulation => 6, + dnsServers => [ qw(202.123.1.6 202.123.1.11) ], + method => 'pppoa', + }, + + N("Morocco") . "|Maroc Telecom" => + { + provider_id => 'MA01', + vpi => 8, + vci => 23, + Encapsulation => 6, + dnsServers => [ qw(212.217.0.1 212.217.0.12) ], + method => 'pppoa', + }, + + N("Netherlands") . "|KPN" => + { + provider_id => 'NL01', + vpi => 8, + vci => 30, + Encapsulation => 6, + method => 'pppoa', + }, + + N("Netherlands") . "|Eager Telecom" => + { + provider_id => 'NL02', + vpi => 0, + vci => 21, + Encapsulation => 3, + method => 'pppoe', + }, + + N("Netherlands") . "|Tiscali" => + { + provider_id => 'NL03', + vpi => 0, + vci => 22, + Encapsulation => 1, + method => 'pppoe', + }, + + N("Netherlands") . "|Versatel" => + { + provider_id => 'NL04', + vpi => 0, + vci => 20, + Encapsulation => 3, + method => 'pppoe', + }, + + N("Norway") . "|Bluecom" => + { + provider_id => 'NO01', + method => 'dhcp', + }, + + N("Norway") . "|Firstmile" => + { + provider_id => 'NO02', + method => 'dhcp', + }, + + N("Norway") . "|NextGenTel" => + { + provider_id => 'NO03', + method => 'dhcp', + }, + + N("Norway") . "|SSC" => + { + provider_id => 'NO04', + method => 'dhcp', + }, + + N("Norway") . "|Tele2" => + { + provider_id => 'NO05', + method => 'dhcp', + }, + + N("Norway") . "|Telenor ADSL" => + { + provider_id => 'NO06', + method => 'PPPoE', + }, + + N("Norway") . "|Tiscali" => + { + provider_id => 'NO07', + vpi => 8, + vci => 35, + method => 'dhcp', + }, + + N("Pakistan") . "|Micronet BroadBand" => + { + provider_id => 'PK01', + vpi => 1, + vci => 20, + Encapsulation => 3, + dnsServers => [ qw(203.82.48.3 203.82.48.4) ], + method => 'pppoe', + encryption => 1, + }, + + N("Poland") . "|Telekomunikacja Polska (TPSA/neostrada)" => + { + provider_id => 'PL01', + vpi => 0, + vci => 23, + Encapsulation => 6, + dnsServers => [ qw(194.204.152.34 217.98.63.164) ], + method => 'pppoa', + }, + + N("Poland") . "|Netia neostrada" => + { + provider_id => 'PL02', + url_tech => 'http://www.netia.pl/?o=d&s=210', + vpi => 8, + vci => 23, + Encapsulation => 1, + dnsServers => [ qw(195.114.181.130 195.114.161.61) ], + method => 'pppoe', + }, + + N("Portugal") . "|PT" => + { + provider_id => 'PT01', + vpi => 0, + vci => 23, + Encapsulation => 1, + method => 'pppoe', + }, + + N("Russia") . "|MTU-Intel" => + { + provider_id => 'RU01', + url_tech => 'http://stream.ru/s-requirements', + vpi => 1, + vci => 32, + Encapsulation => 1, + dnsServers => [ qw(212.188.4.10 195.34.32.116) ], + method => 'pppoe', + }, + + N("Singapore") . "|Singnet" => + { + provider_id => 'SG01', + vpi => 0, + vci => 64, + method => 'pppoa', + Encapsulation => 6, + }, + + N("Senegal") . "|Sonatel Multimedia Sentoo" => + { + provider_id => 'SN01', + vpi => 0, + vci => 35, + Encapsulation => 6, + method => 'pppoa', + DOMAINNAME2 => 'sentoo.sn', + }, + + N("Slovenia") . "|SiOL" => + { + provider_id => 'SL01', + vpi => 1, + vci => 20, + method => 'pppoe', + Encapsulation => 1, + dnsServers => [ qw(193.189.160.11 193.189.160.12) ], + DOMAINNAME2 => 'siol.net', + }, + + N("Spain") . "|Telefónica IP dinámica" => + { + provider_id => 'ES01', + vpi => 8, + vci => 20, + Encapsulation => 1, + CMVep => 'ES', + dnsServers => [ qw(80.58.32.33 80.58.0.97) ], + method => 'pppoe', + login_format => 'adslppp@telefonicanetpa / adslppp', + }, + + N("Spain") . "|Telefónica ip fija" => + { + provider_id => 'ES02', + vpi => 8, + vci => 20, + Encapsulation => 3, + CMVep => 'ES', + dnsServers => [ qw(80.58.32.33 80.58.0.97) ], + method => 'static', + login_format => 'adslppp@telefonicanetpa / adslppp', + }, + + N("Spain") . "|Wanadoo/Eresmas Retevision" => + { + provider_id => 'ES03', + vpi => 8, + vci => 23, + Encapsulation => 6, + CMVep => 'ES', + dnsServers => [ qw(80.58.0.33 80.58.32.97) ], + method => 'pppoa', + login_format => 'rtxxxxx@wanadooadsl', + encryption => 1, + }, + + N("Spain") . "|Wanadoo PPPoE" => + { + provider_id => 'ES04', + vpi => 8, + vci => 20, + Encapsulation => 1, + CMVep => 'ES', + method => 'pppoe', + }, + + N("Spain") . "|Wanadoo ip fija" => + { + provider_id => 'ES05', + vpi => 8, + vci => 20, + Encapsulation => 3, + CMVep => 'ES', + method => 'static', + }, + + N("Spain") . "|Tiscali" => + { + provider_id => 'ES06', + vpi => 1, + vci => 20, + Encapsulation => 6, + CMVep => 'ES', + method => 'pppoa', + login_format => 'login@tiscali.es', + }, + + N("Spain") . "|Arrakis" => + { + provider_id => 'ES07', + vpi => 0, + vci => 23, + Encapsulation => 6, + CMVep => 'ES', + method => 'pppoa', + }, + + N("Spain") . "|Auna" => + { + provider_id => 'ES08', + vpi => 0, + vci => 23, + Encapsulation => 6, + CMVep => 'ES', + method => 'pppoa', + }, + + N("Spain") . "|Communitel" => + { + provider_id => 'ES09', + vpi => 0, + vci => 21, + Encapsulation => 6, + CMVep => 'ES', + method => 'pppoa', + }, + + N("Spain") . "|Euskatel" => + { + provider_id => 'ES10', + vpi => 8, + vci => 20, + Encapsulation => 1, + CMVep => 'ES', + method => 'pppoe', + }, + + N("Spain") . "|Uni2" => + { + provider_id => 'ES11', + vpi => 1, + vci => 21, + Encapsulation => 6, + CMVep => 'ES', + method => 'pppoa', + }, + + N("Spain") . "|Ya.com PPPoE" => + { + provider_id => 'ES12', + vpi => 8, + vci => 20, + Encapsulation => 1, + CMVep => 'ES', + method => 'pppoe', + login_format => 'adXXXXXXXXX@yacomadsl', + }, + + N("Spain") . "|Ya.com static" => + { + provider_id => 'ES13', + vpi => 8, + vci => 20, + Encapsulation => 3, + CMVep => 'ES', + method => 'static', + login_format => 'adXXXXXXXXX@yacomadsl', + }, + + N("Spain") . "|Arsys" => + { + provider_id => 'ES14', + vpi => 1, + vci => 21, + Encapsulation => 1, + CMVep => 'ES', + dnsServers => [ qw(217.76.128.4 217.76.129.4) ], + method => 'pppoe', + login_format => 'login@arsystel', + }, + + N("Spain") . "|Terra" => + { + provider_id => 'ES15', + vpi => 8, + vci => 20, + Encapsulation => 1, + CMVep => 'ES', + dnsServers => [ qw(213.4.132.1 213.4.141.1) ], + method => 'pppoe', + login_format => 'login@terraadsl', + }, + + N("Spain") . "|Jazztel" => + { + provider_id => 'ES16', + vpi => 8, + vci => 23, + Encapsulation => 6, + CMVep => 'ES', + dnsServers => [ qw(62.14.63.145 62.14.2.1) ], + method => 'pppoa', + login_format => 'username@adsl', + encryption => 1, + }, + + N("Sweden") . "|Telia" => + { + provider_id => 'SE01', + vpi => 8, + vci => 23, + Encapsulation => 3, + method => 'pppoe', + }, + + N("Switzerland") . "|" . N("Any") => + { + provider_id => 'CH01', + vpi => 8, + vci => 23, + Encapsulation => 3, + method => 'pppoe', + }, + + N("Switzerland") . "|BlueWin / Swisscom" => + { + provider_id => 'CH02', + vpi => 8, + vci => 23, + Encapsulation => 5, + dnsServers => [ qw(195.186.4.108 195.186.4.109) ], + method => 'pppoa', + }, + + N("Switzerland") . "|VTX Datacomm (ex-Tiscali)" => + { + provider_id => 'CH03', + vpi => 8, + vci => 23, + Encapsulation => 1, + method => 'pppoa', + }, + + N("Thailand") . "|Asianet" => + { + provider_id => 'TH01', + vpi => 0, + vci => 64, + Encapsulation => 1, + dnsServers => [ qw(203.144.225.242 203.144.225.72 203.144.223.66) ], + method => 'pppoe', + }, + + N("Tunisia") . "|Planet.tn" => + { + provider_id => 'TU01', + url_tech => 'http://www.planet.tn/', + vpi => 0, + vci => 23, + Encapsulation => 5, + dnsServers => [ qw(193.95.93.77 193.95.66.10) ], + method => 'pppoe', + }, + + N("Turkey") . "|TTnet" => + { + provider_id => 'TR01', + url_tech => 'http://www.ttnet.net.tr', + vpi => 8, + vci => 23, + Encapsulation => 1, + dnsServers => [ qw(195.175.37.14 195.175.37.69) ], + method => 'pppoe', + encryption => 1, + login_format => 'login@ttnet', + }, + + N("United Arab Emirates") . "|Etisalat" => + { + provider_id => 'AE01', + vpi => 0, + vci => 32, + Encapsulation => 5, + dnsServers => [ qw(213.42.20.20 195.229.241.222) ], + method => 'pppoa', + }, + + N("United Kingdom") . "|Tiscali UK " => + { + provider_id => 'UK01', + vpi => 0, + vci => 26, + Encapsulation => 6, + dnsServers => [ qw(212.74.112.66 212.74.112.67) ], + method => 'pppoa', + }, + + N("United Kingdom") . "|British Telecom " => + { + provider_id => 'UK02', + vpi => 0, + vci => 26, + Encapsulation => 6, + dnsServers => [ qw(194.74.65.69 194.72.9.38) ], + method => 'pppoa', + }, + + ); + +1; diff --git a/lib/network/connection/wireless.pm b/lib/network/connection/wireless.pm new file mode 100644 index 0000000..e036f6c --- /dev/null +++ b/lib/network/connection/wireless.pm @@ -0,0 +1,1132 @@ +package network::connection::wireless; + +use base qw(network::connection::ethernet); + +use strict; +use common; +use log; +use network::network; + +#- class attributes: +#- network: ID of the selected network + +sub get_type_name() { N("Wireless") } +sub get_type_description() { N("Wireless (Wi-Fi)") } +sub _get_type_icon() { 'wireless' } +sub get_devices { + my ($_class, %options) = @_; + require detect_devices; + my @devices = detect_devices::probe_category('network/wireless'); + my @wireless = grep { detect_devices::is_wireless_interface($_) } detect_devices::get_lan_interfaces(); + my @all_devices = (@devices, network::connection::ethernet::get_unlisted_devices(\@wireless, \@devices)); + foreach (@all_devices) { + my $interface = $_->{interface} || network::connection::ethernet::device_to_interface($_) or next; + my $driver = network::connection::ethernet::interface_to_driver($interface) or next; + $_->{driver} = $driver if $driver; + } + @all_devices, + if_(!$options{automatic_only}, { + driver => 'ndiswrapper', + description => N("Use a Windows driver (with ndiswrapper)"), + }); +} + +sub handles_ifcfg { + my ($_class, $ifcfg) = @_; + require detect_devices; + detect_devices::is_wireless_interface($ifcfg->{DEVICE}) || exists $ifcfg->{WIRELESS_MODE}; +} + +sub get_metric { 35 } + +#- http://www.linux-wireless.org/Install-HOWTO/WL/WEP-Key-HOWTO.txt +my $wpa_supplicant_max_wep_key_len = 32; + +our %wireless_enc_modes = ( + none => N_("None"), + open => N_("Open WEP"), + restricted => N_("Restricted WEP"), + 'wpa-psk' => N_("WPA/WPA2 Pre-Shared Key"), + 'wpa-eap' => N_("WPA/WPA2 Enterprise"), +); +#define the eap related variables we handle +#0 means we preserve value if found +#1 means we save without quotes +#2 save with quotes +my %eap_vars = ( + ssid => 2, + scan_ssid => 1, + identity => 2, + password => 2, + key_mgmt => 1, + eap => 1, + pairwise => 1, + group => 1, + proto => 1, + ca_cert => 2, + client_cert => 2, + phase2 => 2, + anonymous_identity => 2, + subject_match => 2, + disabled => 0, + id_str => 0, + bssid => 0, + priority => 0, + auth_alg => 0, + eapol_flags => 0, + proactive_key_caching => 0, + peerkey => 0, + ca_path => 0, + private_key => 0, + private_key_passwd => 0, + dh_file => 0, + altsubject_match => 0, + phase1 => 0, + fragment_size => 0, + eap_workaround => 0, +); + +my @thirdparty_settings = ( + { + name => 'zd1201', + description => 'ZyDAS ZD1201', + url => 'http://linux-lc100020.sourceforge.net/', + firmware => { + test_file => 'zd1201*.fw', + }, + }, + + (map { + { + name => "ipw${_}", + description => "Intel(R) PRO/Wireless ${_}", + url => "http://ipw${_}.sourceforge.net/", + firmware => { + url => "http://ipw${_}.sourceforge.net/firmware.php", + test_file => "ipw$_-*.fw", + }, + }; + } (2100, 2200)), + + { + name => "ipw3945", + description => "Intel(R) PRO/Wireless 3945", + url => "http://ipw3945.sourceforge.net/", + firmware => { + package => "ipw3945-ucode", + test_file => "ipw3945.ucode", + }, + tools => { + package => "ipw3945d", + test_file => '/usr/sbin/ipw3945d', + }, + }, + + (map { + my ($version, $ucode_api, $ucode_version) = @$_; + $ucode_version ||= $version; + { + name => "iwl${version}", + description => "Intel(R) PRO/Wireless ${version}", + url => "http://intellinuxwireless.org/", + firmware => { + package => "iwlwifi-${version}-ucode", + test_file => "iwlwifi-${ucode_version}${ucode_api}.ucode", + }, + sleep => 1, + }; + } ([ 3945, '-1' ], [ 4965, '-1' ], [ 'agn', '-1', 5000 ])), + + { + name => 'p54pci', + description => 'PCI adaptors based on the Intersil Prism54 chip series', + url => 'http://wireless.kernel.org/en/users/Drivers/p54', + firmware => { + url => 'http://wireless.kernel.org/en/users/Drivers/p54#firmware', + test_file => "isl3886pci", + }, + }, + + { + name => 'p54usb', + description => 'USB adaptors based on the Intersil Prism54 chip series', + url => 'http://wireless.kernel.org/en/users/Drivers/p54', + firmware => { + url => 'http://wireless.kernel.org/en/users/Drivers/p54#firmware', + test_file => "isl388*usb", + }, + }, + + { + name => 'atmel', + matching => [ qw(at76_usb atmel_cs atmel_pci) ], + description => 'Atmel at76c50x cards', + url => 'http://thekelleys.org.uk/atmel/', + firmware => { + test_file => 'atmel_at76c50*', + }, + links => 'http://at76c503a.berlios.de/', + }, + + { + name => 'madwifi', + matching => 'ath_pci', + description => 'Multiband Atheros Driver for WiFi', + url => 'http://madwifi.org/', + kernel_module => 1, + tools => { + optional => 1, + test_file => '/usr/bin/athstats', + }, + }, + + { + name => 'prism2', + matching => qr/^prism2_/, + description => 'Prism2 based cards', + tools => { + package => 'prism2-utils', + test_file => '/sbin/wlanctl-ng', + }, + }, + + { + name => 'zd1211', + matching => 'zd1211rw', + description => 'ZD1211 chip', + firmware => { + url => 'http://sourceforge.net/projects/zd1211/', + test_file => 'zd1211/zd1211_*', + }, + }, + + { + name => 'bcm43xx', + description => 'Broadcom bcm43xx wireless chips', + url => 'http://bcm43xx.berlios.de/', + firmware => { + test_file => 'bcm43xx_microcode*.fw', + no_package => 1, + extract => { + name => 'bcm43xx-fwcutter', + test_file => '/usr/bin/bcm43xx-fwcutter', + windows_source => 'bcmwl5.sys', + default_source => 'bcmwl5.sys', + run => sub { + my ($file) = @_; + run_program::rooted($::prefix, '/usr/bin/bcm43xx-fwcutter', + '-w', $network::thirdparty::firmware_directory, $file); + }, + }, + }, + }, + + (map { + +{ + name => $_, + description => "Broadcom $_ wireless chips", + url => 'http://wireless.kernel.org/en/users/Drivers/b43', + firmware => { + test_file => $_ . "/ucode*.fw", + no_package => 1, + extract => { + name => 'b43-fwcutter', + test_file => '/usr/bin/b43-fwcutter', + windows_source => 'bcmwl5.sys', + default_source => 'bcmwl5.sys', + run => sub { + my ($file) = @_; + run_program::rooted($::prefix, '/usr/bin/b43-fwcutter', + '-w', $network::thirdparty::firmware_directory, $file); + }, + }, + }, + }; + } qw(b43 b43legacy)), + + { + name => 'broadcom-wl', + matching => 'wl', + description => 'Broadcom Hybrid', + url => 'http://www.broadcom.com/support/802.11/linux_sta.php', + kernel_module => 1, + }, + + { + name => 'acx100', + matching => [ qw(acx_pci acx_usb) ], + description => 'ACX100/ACX111/TNETW1450', + firmware => { + url => 'http://acx100.sourceforge.net/wiki/Firmware', + test_file => 'tiacx1*', + no_distro_package => 1, + }, + }, + + { + name => 'ndiswrapper', + description => 'Wireless device using ndiswrapper (windows drivers)', + tools => { + test_file => '/usr/sbin/ndiswrapper', + }, + firmware => { + user_install => sub { + my ($settings, $in) = @_; + require network::ndiswrapper; + $settings->{device} = network::ndiswrapper::select_device($in) or return; + network::ndiswrapper::setup_device($in, $settings->{device}); + $settings->{device}{driver} = $settings->{name}; + }, + url => 'http://ndiswrapper.sourceforge.net/mediawiki/index.php/List', + component_name => N_("Windows driver"), + no_package => 1, + }, + no_module_reload => 1, + }, + + { + name => 'rt61', + matching => 'rt61pci', + description => 'Ralink RT61 802.11abg WLAN', + firmware => { + url => 'http://rt2x00.serialmonkey.com/', + test_file => 'rt2661.bin', + }, + }, + + { + name => 'rt73', + matching => 'rt73usb', + description => 'Ralink RT73 802.11abg WLAN', + firmware => { + url => 'http://rt2x00.serialmonkey.com/', + test_file => 'rt73.bin', + }, + }, + + (map { + +{ + name => "rt${_}", + matching => qr/^rt${_}(sta|)$/, + description => 'Ralink RT${_} WiFi', + kernel_module => 1, + firmware => { + url => 'http://www.ralinktech.com/', + test_file => "rt${_}.bin", + }, + }; + } (2860, 2870, 3090)), + + { + name => 'rtl8187se', + matching => 'r8180', + description => 'Realtek RTL8180 / RTL8185 WiFi', + kernel_module => 1, + }, +); + +sub get_packages { 'wireless-tools' } + +sub get_thirdparty_settings() { + \@thirdparty_settings; +} + +sub setup_thirdparty { + my ($self, $in) = @_; + require network::rfswitch; + network::rfswitch::configure(); + if ($self->get_driver eq 'ndiswrapper') { + require network::ndiswrapper; + my @devices = map { network::ndiswrapper::present_devices($_) } network::ndiswrapper::installed_drivers(); + return {} if member($self->{device}, @devices) && network::ndiswrapper::find_interface($self->{device}); + } + my $thirdparty = $self->SUPER::setup_thirdparty($in); + my $driver = $self->get_driver; + if ($self->{thirdparty} && $driver eq 'ipw3945' && !$self->rf_killed && !$self->SUPER::check_device) { + log::explanations("Reloading module $driver"); + eval { modules::unload($driver) }; + eval { modules::load($driver) }; + } + $thirdparty; +} + +sub rf_killed { + my ($self) = @_; + if ($self->{device}{sysfs_device}) { + my $rf_kill_path = $self->{device}{sysfs_device} . "/rf_kill"; + if (-e $rf_kill_path) { + my $rf_kill = chomp_(cat_($rf_kill_path)); + #- for ipw drivers, 0 means no RF kill switch + return $rf_kill != 0; + } + } + undef; +} + +sub check_device { + my ($self) = @_; + if ($self->rf_killed) { + $self->{device}{error} = N("Your wireless card is disabled, please enable the wireless switch (RF kill switch) first."); + return 0; + } + return $self->SUPER::check_device; +} + +sub load_interface_settings { + my ($self) = @_; + $self->network::connection::load_interface_settings; + $self->{hide_passwords} = 1; + # override ifcfg with network-specific settings if available + my $network = $self->get_selected_network; + $self->{ifcfg}= $network ? + get_network_ifcfg($network->{ap}) || get_network_ifcfg($network->{essid}) : + $self->{ifcfg}; + + $self->SUPER::map_ifcfg2config_settings; +} + +sub get_networks { + my ($self, $o_net) = @_; + require network::monitor; + ($self->{networks}, $self->{control}{roaming}) = network::monitor::list_wireless($o_net && $o_net->{monitor}, $self->get_interface); + $self->probed_networks; + $self->{networks}; +} + +sub refresh_roaming_ids { + my ($self) = @_; + #- needed when switching from non-roaming to roaming + #- or after restarting wpa_supplicant + #- to get fresh wpa_supplicant network IDs + get_networks($self) if $self->{control}{roaming}; +} + +sub selected_network_is_configured { + my ($self) = @_; + $self->refresh_roaming_ids; + $self->SUPER::selected_network_is_configured; +} + +sub guess_network { + my ($_self) = @_; + #- FIXME: try to find the AP matching $self->{ifcfg}{WIRELESS_ESSID}; +} + +sub get_network_ifcfg { + my ($ssid) = @_; + require network::network; + my $file = $::prefix . $network::network::wireless_d . '/' . $ssid; + -f $file && { getVarsFromSh($file) }; +} + +sub guess_network_access_settings { + my ($self) = @_; + + my $network = $self->get_selected_network; + my $ifcfg = $self->{ifcfg}; + $ifcfg ||= {}; + + $self->{access}{network}{bssid} = $network && $network->{hidden} && $network->{ap}; + $self->{access}{network}{essid} = $network && $network->{essid} || $ifcfg->{WIRELESS_ESSID} || !$network && "any"; + ($self->{access}{network}{key}, my $restricted, $self->{access}{network}{force_ascii_key}) = + get_wep_key_from_iwconfig($ifcfg->{WIRELESS_ENC_KEY}); + + $self->{access}{network}{encryption} = + $network && $network->{flags} =~ /eap/i ? + 'wpa-eap' : + $network && $network->{flags} =~ /wpa/i ? + 'wpa-psk' : + $network && $network->{flags} =~ /wep/i || $self->{access}{network}{key} ? + $ifcfg->{WIRELESS_ENC_MODE} || ($restricted ? 'restricted' : 'open') : + 'none'; + + undef $self->{ifcfg}{WIRELESS_IWPRIV} if is_old_rt2x00($self->get_driver) && $self->{ifcfg}{WIRELESS_IWPRIV} =~ /WPAPSK/; + + my $system_file = '/etc/sysconfig/drakx-net'; + my %global_settings = getVarsFromSh($system_file); + $self->{control}{roaming} = + (exists $self->{ifcfg}{WIRELESS_WPA_DRIVER} || text2bool($global_settings{ROAMING})) + && !is_old_rt2x00($self->get_driver); + + $self->{access}{network}{mode} = + $network && $network->{mode} || + $ifcfg->{WIRELESS_MODE} || + 'Managed'; + + wpa_supplicant_load_eap_settings($self->{access}{network}) if $self->need_wpa_supplicant; +} + +sub get_network_access_settings_label { N("Wireless settings") } + +sub get_network_access_settings { + my ($self) = @_; + [ + { label => N("Operating Mode"), val => \$self->{access}{network}{mode}, + list => [ N_("Ad-hoc"), N_("Managed"), N_("Master"), N_("Repeater"), N_("Secondary"), N_("Auto") ], + format => \&translate, + }, + { label => N("Network name (ESSID)"), val => \$self->{access}{network}{essid}, + disabled => sub { my $network = $self->get_selected_network; $network && $network->{essid} } }, + { label => N("Encryption mode"), val => \$self->{access}{network}{encryption}, list => [ keys %wireless_enc_modes ], + sort => 1, format => sub { translate($wireless_enc_modes{$_[0]}) } }, + { label => N("Encryption key"), val => \$self->{access}{network}{key}, + hidden => sub { $self->{hide_passwords} }, + disabled => sub { member($self->{access}{network}{encryption}, qw(none wpa-eap)) } }, + { text => N("Hide password"), + type => "bool", val => \$self->{hide_passwords} }, + { text => N("Force using this key as ASCII string (e.g. for Livebox)"), + type => "bool", val => \$self->{access}{network}{force_ascii_key}, + disabled => sub { + #- only for WEP keys looking like hexadecimal + !member($self->{access}{network}{encryption}, qw(open restricted)) || + !get_hex_key($self->{access}{network}{key}); + } }, + { label => N("EAP Login/Username"), val => \$self->{access}{network}{eap_identity}, + disabled => sub { $self->{access}{network}{encryption} ne 'wpa-eap' }, + help => N("The login or username. Format is plain text. If you +need to specify domain then try the untested syntax + DOMAIN\\username") }, + { label => N("EAP Password"), val => \$self->{access}{network}{eap_password}, + hidden => sub { $self->{hide_passwords} }, + disabled => sub { $self->{access}{network}{encryption} ne 'wpa-eap' }, + help => N(" Password: A string. +Note that this is not the same thing as a psk. +____________________________________________________ +RELATED ADDITIONAL INFORMATION: +In the Advanced Page, you can select which EAP mode +is used for authentication. For the eap mode setting + Auto Detect: implies all possible modes are tried. + +If Auto Detect fails, try the PEAP TTLS combo bofore others +Note: + The settings MD5, MSCHAPV2, OTP and GTC imply +automatically PEAP and TTLS modes. + TLS mode is completely certificate based and may ignore +the username and password values specified here.") }, + { label => N("EAP client certificate"), val => \$self->{access}{network}{eap_client_cert}, + disabled => sub { $self->{access}{network}{encryption} ne 'wpa-eap' }, + help => N("The complete path and filename of client certificate. This is +only used for EAP certificate based authentication. It could be +considered as the alternative to username/password combo. + Note: other related settings are shown on the Advanced page.") }, + { label => N("Network ID"), val => \$self->{ifcfg}{WIRELESS_NWID}, advanced => 1 }, + { label => N("Operating frequency"), val => \$self->{ifcfg}{WIRELESS_FREQ}, advanced => 1 }, + { label => N("Sensitivity threshold"), val => \$self->{ifcfg}{WIRELESS_SENS}, advanced => 1 }, + { label => N("Bitrate (in b/s)"), val => \$self->{ifcfg}{WIRELESS_RATE}, advanced => 1 }, + { label => N("RTS/CTS"), val => \$self->{ifcfg}{WIRELESS_RTS}, advanced => 1, + help => N("RTS/CTS adds a handshake before each packet transmission to make sure that the +channel is clear. This adds overhead, but increase performance in case of hidden +nodes or large number of active nodes. This parameter sets the size of the +smallest packet for which the node sends RTS, a value equal to the maximum +packet size disable the scheme. You may also set this parameter to auto, fixed +or off.") + }, + { label => N("Fragmentation"), val => \$self->{ifcfg}{WIRELESS_FRAG}, advanced => 1 }, + { label => N("iwconfig command extra arguments"), val => \$self->{ifcfg}{WIRELESS_IWCONFIG}, advanced => 1, + help => N("Here, one can configure some extra wireless parameters such as: +ap, channel, commit, enc, power, retry, sens, txpower (nick is already set as the hostname). + +See iwconfig(8) man page for further information."), + }, + { label => + #-PO: split the "xyz command extra argument" translated string into two lines if it's bigger than the english one + N("iwspy command extra arguments"), val => \$self->{ifcfg}{WIRELESS_IWSPY}, advanced => 1, + help => N("iwspy is used to set a list of addresses in a wireless network +interface and to read back quality of link information for each of those. + +This information is the same as the one available in /proc/net/wireless : +quality of the link, signal strength and noise level. + +See iwpspy(8) man page for further information."), + }, + { label => N("iwpriv command extra arguments"), val => \$self->{ifcfg}{WIRELESS_IWPRIV}, advanced => 1, + disabled => sub { $self->need_rt2x00_iwpriv }, + help => N("iwpriv enable to set up optionals (private) parameters of a wireless network +interface. + +iwpriv deals with parameters and setting specific to each driver (as opposed to +iwconfig which deals with generic ones). + +In theory, the documentation of each device driver should indicate how to use +those interface specific commands and their effect. + +See iwpriv(8) man page for further information."), + }, + { label => N("EAP Protocol"), val => \$self->{access}{network}{forceeap}, + list => [ N_("Auto Detect"), N_("WPA2"), N_("WPA") ], + sort => 1, format => \&translate, advanced => 1, + help => N("Auto Detect is recommended as it first tries WPA version 2 with +a fallback to WPA version 1") }, + { label => N("EAP Mode"), val => \$self->{access}{network}{eap_eap}, + list => [ N_("Auto Detect"), N_("PEAP"), N_("TTLS"), N_("TLS"), N_("MSCHAPV2"), N_("MD5"), N_("OTP"), N_("GTC"), N_("LEAP") , N_("PEAP TTLS"), N_("TTLS TLS") ], + sort => 1, format => \&translate, advanced => 1, }, + { label => N("EAP key_mgmt"), val => \$self->{access}{network}{eap_key_mgmt}, advanced => 1, + disabled => sub { $self->{access}{network}{encryption} ne 'wpa-eap' }, + help => N("list of accepted authenticated key management protocols. +possible values are WPA-EAP, IEEE8021X, NONE") }, + { label => N("EAP outer identity"), val => \$self->{access}{network}{eap_anonymous_identity}, advanced => 1, + disabled => sub { $self->{access}{network}{encryption} ne 'wpa-eap' }, + help => N("Anonymous identity string for EAP: to be used as the +unencrypted identity with EAP types that support different +tunnelled identity, e.g., TTLS") }, + { label => N("EAP phase2"), val => \$self->{access}{network}{eap_phase2}, advanced => 1, + disabled => sub { $self->{access}{network}{encryption} ne 'wpa-eap' } , + help => N("Inner authentication with TLS tunnel parameters. +input is string with field-value pairs, Examples: +auth=MSCHAPV2 for PEAP or +autheap=MSCHAPV2 autheap=MD5 for TTLS") }, + { label => N("EAP CA certificate"), val => \$self->{access}{network}{eap_ca_cert}, advanced => 1, + disabled => sub { $self->{access}{network}{encryption} ne 'wpa-eap' }, + help => N("Full file path to CA certificate file (PEM/DER). This file +can have one or more trusted CA certificates. If ca_cert are not +included, server certificate will not be verified. If possible, +a trusted CA certificate should always be configured +when using TLS or TTLS or PEAP.") }, + { label => N("EAP certificate subject match"), val => \$self->{access}{network}{eap_subject_match}, advanced => 1, + disabled => sub { $self->{access}{network}{encryption} ne 'wpa-eap' }, + help => N(" Substring to be matched against the subject of +the authentication server certificate. If this string is set, +the server certificate is only accepted if it contains this +string in the subject. The subject string is in following format: +/C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as\@example.com") }, + { label => N("Extra directives"), val => \$self->{access}{network}{extra}, advanced => 1, + help => N("Here one can pass extra settings to wpa_supplicant +The expected format is a string field=value pair. Multiple values +maybe specified, separating each value with the # character. +Note: directives are passed unchecked and may cause the wpa +negotiation to fail silently. Supported directives are preserved +across editing. +Supported directives are : + disabled, id_str, bssid, priority, auth_alg, eapol_flags, + proactive_key_caching, peerkey, ca_path, private_key, + private_key_passwd, dh_file, altsubject_match, phase1, + fragment_size and eap_workaround, pairwise, group + Others such as key_mgmt, eap maybe used to force + special settings different from the U.I settings.") }, + ]; +} + +sub check_network_access_settings { + my ($self) = @_; + + if (!member($self->{access}{network}{encryption}, qw(none wpa-eap)) && !$self->{access}{network}{key}) { + $self->{network_access}{error}{message} = N("An encryption key is required."); + $self->{network_access}{error}{field} = \$self->{access}{network}{key}; + return 0; + } + + if ($self->{access}{network}{encryption} eq 'wpa-psk' && + !convert_psk_key_for_wpa_supplicant($self->{access}{network}{key})) { + $self->{network_access}{error}{message} = N("The pre-shared key should have between 8 and 63 ASCII characters, or 64 hexadecimal characters."); + $self->{network_access}{error}{field} = \$self->{access}{network}{key}; + return 0; + } + if (member($self->{access}{network}{encryption}, qw(open restricted)) && + !convert_wep_key_for_wpa_supplicant($self->{access}{network}{key}, $self->{access}{network}{force_ascii_key})) { + $self->{network_access}{error}{message} = N("The WEP key should have at most %d ASCII characters or %d hexadecimal characters.", + $wpa_supplicant_max_wep_key_len, $wpa_supplicant_max_wep_key_len * 2); + $self->{network_access}{error}{field} = \$self->{access}{network}{key}; + return 0; + } + + if ($self->{ifcfg}{WIRELESS_FREQ} && $self->{ifcfg}{WIRELESS_FREQ} !~ /[0-9.]*[kGM]/) { + $self->{network_access}{error}{message} = N("Freq should have the suffix k, M or G (for example, \"2.46G\" for 2.46 GHz frequency), or add enough '0' (zeroes)."); + $self->{network_access}{error}{field} = \$self->{ifcfg}{WIRELESS_FREQ}; + return 0; + } + + if ($self->{ifcfg}{WIRELESS_RATE} && $self->{ifcfg}{WIRELESS_RATE} !~ /[0-9.]*[kGM]/) { + $self->{network_access}{error}{message} = N("Rate should have the suffix k, M or G (for example, \"11M\" for 11M), or add enough '0' (zeroes)."); + $self->{network_access}{error}{field} = \$self->{ifcfg}{WIRELESS_RATE}; + return 0; + } + + return 1; +} + +sub get_control_settings { + my ($self) = @_; + [ + @{$self->SUPER::get_control_settings}, + { text => N("Allow access point roaming"), val => \$self->{control}{roaming}, type => "bool", + disabled => sub { is_wpa_supplicant_blacklisted($self->get_driver) } }, + ]; +} + +sub need_wpa_supplicant { + my ($self) = @_; + ($self->{control}{roaming} || $self->{access}{network}{encryption} =~ /^wpa-/) && !is_old_rt2x00($self->get_driver); +} + +sub install_packages { + my ($self, $in) = @_; + if ($self->need_wpa_supplicant) { + $in->do_pkgs->ensure_is_installed('wpa_supplicant', '/usr/sbin/wpa_supplicant') or return; + $in->do_pkgs->ensure_is_installed('mandi', '/usr/sbin/mandi'); + } + $self->SUPER::install_packages($in); +} + + +sub build_ifcfg_settings { + my ($self) = @_; + + # if we are not using WEP, the key is always ASCII (#52128) + $self->{access}{network}{force_ascii_key} = 1 unless member($self->{access}{network}{encryption}, qw(open restricted)); + + my $settings = { + WIRELESS_MODE => $self->{access}{network}{mode}, + if_($self->need_wpa_supplicant, + WIRELESS_WPA_DRIVER => wpa_supplicant_get_driver($self->get_driver), + WIRELESS_WPA_REASSOCIATE => bool2yesno($self->need_wpa_supplicant_reassociate), + MII_NOT_SUPPORTED => 'no', + ), + WIRELESS_ESSID => $self->{access}{network}{essid}, + if_($self->{access}{network}{encryption} ne 'none', + WIRELESS_ENC_KEY => convert_wep_key_for_iwconfig($self->{access}{network}{key}, $self->{access}{network}{force_ascii_key})), + if_(member($self->{access}{network}{encryption}, qw(open restricted)), + WIRELESS_ENC_MODE => $self->{access}{network}{encryption}), + if_($self->need_rt2x00_iwpriv, + #- use iwpriv for WPA with rt2400/rt2500 drivers, they don't plan to support wpa_supplicant + WIRELESS_IWPRIV => qq(set AuthMode=WPAPSK +set EncrypType=TKIP +set SSID=$self->{access}{network}{essid} +set WPAPSK="$self->{access}{network}{key}" +set TxRate=0)), + (map { $_ => $self->{ifcfg}{$_} } + qw(WIRELESS_NWID WIRELESS_FREQ WIRELESS_SENS WIRELESS_RATE WIRELESS_RTS WIRELESS_FRAG WIRELESS_IWCONFIG WIRELESS_IWSPY), if_(!$self->need_rt2x00_iwpriv, 'WIRELESS_IWPRIV')), + }; + $self->SUPER::build_ifcfg_settings($settings); +} + +sub add_network_to_wpa_supplicant { + my ($self) = @_; + if ($self->{access}{network}{encryption} eq 'wpa-eap') { + wpa_supplicant_add_eap_network($self->{access}{network}); + } else { + wpa_supplicant_add_network($self->{access}{network}); + } + #- this should be handled by the monitoring daemon instead + run_program::run('/usr/sbin/wpa_cli', 'reconfigure'); +} + +sub write_settings { + my ($self, $o_net, $o_modules_conf) = @_; + + my $network = $self->get_selected_network; + network::network::write_wireless_conf($_, $self->build_ifcfg_settings) foreach + grep { $_ } ($network ? $network->{ap} : ()), $self->{access}{network}{essid}; + + $self->add_network_to_wpa_supplicant if $self->need_wpa_supplicant; + + wlan_ng_configure($self->{access}{network}{essid}, $self->{access}{network}{key}, $self->get_interface, $self->get_driver) if $self->{thirdparty}{name} eq 'prism2'; + + $self->SUPER::write_settings($o_net, $o_modules_conf); +} + +sub apply_network_selection { + my ($self) = @_; + require network::network; + my $file = network::network::get_ifcfg_file($self->get_interface); + network::network::write_interface_settings($self->build_ifcfg_settings, $file); + + $self->add_network_to_wpa_supplicant if $self->need_wpa_supplicant; +} + +sub network_is_configured { + my ($self, $network) = @_; + if ($self->{control}{roaming}) { + return defined $network->{id}; + } else { + my $wireless_ifcfg = get_network_ifcfg($network->{ap}) || defined $network->{essid} && get_network_ifcfg($network->{essid}); + return $wireless_ifcfg; + } +} + +sub connect { + my ($self, $_in, $net) = @_; + + $self->SUPER::connect; + + if ($self->{control}{roaming}) { + my $network_id; + foreach (0 .. 1) { + $self->refresh_roaming_ids if $_; + my $network = $self->get_selected_network; + $network_id = $network->{id} if $network && defined $network->{id}; + } + if (defined $network_id) { + if ($net->{monitor}) { + log::explanations("selecting wpa_supplicant network $network_id through network monitor"); + eval { $net->{monitor}->select_network($network_id) }; + return !$@; + } else { + run_program::run('/usr/sbin/wpa_cli', 'select_network', $network_id); + } + } + } +} + +sub get_status_message { + my ($self, $status) = @_; + my $interface = $self->get_interface; + my ($current_essid, $current_ap) = get_access_point($interface); + my $network = $current_essid || $current_ap && "[$current_ap]"; + { + link_up => N("Associated to wireless network \"%s\" on interface %s", $network, $interface), + link_down => N("Lost association to wireless network on interface %s", $interface), + }->{$status} || $self->SUPER::get_status_message($status); +} + + + +my $wpa_supplicant_conf = "/etc/wpa_supplicant.conf"; + +sub get_access_point { + my ($intf) = @_; + (chomp_(`/sbin/iwgetid -r $intf 2>/dev/null`), lc(chomp_(`/sbin/iwgetid -r -a $intf 2>/dev/null`))); +} + +sub is_old_rt2x00 { + my ($module) = @_; + member($module, qw(rt2400 rt2500 rt2570 rt61 rt73)); +} + +sub is_wpa_supplicant_blacklisted { + my ($module) = @_; + is_old_rt2x00($module); +} + +sub need_wpa_supplicant_reassociate { + my ($self) = @_; + $self->get_driver eq 'rt61pci'; +} + +sub need_rt2x00_iwpriv { + my ($self) = @_; + is_old_rt2x00($self->get_driver) && $self->{access}{network}{encryption} eq 'wpa-psk'; +} + +sub get_hex_key { + my ($key) = @_; + #- odd number or non-hexa characters, consider the key as ASCII and prepend "s:" + if ($key =~ /^([[:xdigit:]]{4}[\:-]?)+[[:xdigit:]]{2,}$/) { + $key =~ s/[\:-]//g; + return lc($key); + } +} + +sub convert_wep_key_for_iwconfig { + my ($real_key, $force_ascii) = @_; + !$force_ascii && get_hex_key($real_key) || "s:$real_key"; +} + +sub convert_wep_key_for_wpa_supplicant { + my ($key, $force_ascii) = @_; + if (my $hex_key = !$force_ascii && get_hex_key($key)) { + return length($hex_key) <= $wpa_supplicant_max_wep_key_len * 2 && $hex_key; + } else { + return length($key) <= $wpa_supplicant_max_wep_key_len && qq("$key"); + } +} + +sub get_wep_key_from_iwconfig { + my ($key) = @_; + my ($mode, $real_key) = $key =~ /^(?:(open|restricted)\s+)?(.*)$/; + my $is_ascii = $real_key =~ s/^s://; + my $force_ascii = to_bool($is_ascii && get_hex_key($real_key)); + ($real_key, $mode eq 'restricted', $force_ascii); +} + +sub convert_psk_key_for_wpa_supplicant { + my ($key) = @_; + my $l = length($key); + $l == 64 ? + get_hex_key($key) : + $l >= 8 && $l <= 63 ? + qq("$key") : + undef; +} + +#- FIXME: to be improved (quotes, comments) +sub wlan_ng_update_vars { + my ($file, $vars) = @_; + substInFile { + while (my ($key, $value) = each(%$vars)) { + s/^#?\Q$key\E=(?:"[^#]*"|[^#\s]*)(\s*#.*)?/$key=$value$1/ and delete $vars->{$key}; + } + $_ .= join('', map { "$_=$vars->{$_}\n" } keys %$vars) if eof; + } $file; +} + +sub wlan_ng_configure { + my ($essid, $key, $device, $module) = @_; + my $wlan_conf_file = "$::prefix/etc/wlan/wlan.conf"; + my @wlan_devices = split(/ /, (cat_($wlan_conf_file) =~ /^WLAN_DEVICES="(.*)"/m)[0]); + push @wlan_devices, $device unless member($device, @wlan_devices); + #- enable device and make it use the choosen ESSID + wlan_ng_update_vars($wlan_conf_file, + { + WLAN_DEVICES => qq("@wlan_devices"), + "SSID_$device" => qq("$essid"), + "ENABLE_$device" => "y" + }); + + my $wlan_ssid_file = "$::prefix/etc/wlan/wlancfg-$essid"; + #- copy default settings for this ESSID if config file does not exist + -f $wlan_ssid_file or cp_f("$::prefix/etc/wlan/wlancfg-DEFAULT", $wlan_ssid_file); + + #- enable/disable encryption + wlan_ng_update_vars($wlan_ssid_file, + { + (map { $_ => $key ? "true" : "false" } qw(lnxreq_hostWEPEncrypt lnxreq_hostWEPDecrypt dot11PrivacyInvoked dot11ExcludeUnencrypted)), + AuthType => $key ? qq("sharedkey") : qq("opensystem"), + if_($key, + dot11WEPDefaultKeyID => 0, + dot11WEPDefaultKey0 => qq("$key") + ) + }); + #- hide settings for non-root users + chmod 0600, $wlan_conf_file; + chmod 0600, $wlan_ssid_file; + + #- apply settings on wlan interface + require services; + services::restart($module eq 'prism2_cs' ? 'pcmcia' : 'wlan'); +} + +sub wpa_supplicant_get_driver { + my ($module) = @_; + $module =~ /^hostap_/ ? "hostap" : + $module eq "prism54" ? "prism54" : + $module =~ /^ath_/ ? "madwifi" : + $module =~ /^at76c50|atmel_/ ? "atmel" : + "wext"; +} + +sub wpa_supplicant_add_network { + my ($ui_input) = @_; + my $conf = wpa_supplicant_read_conf(); + + # use shorter variables + my $essid = $ui_input->{essid}; + my $bssid = $ui_input->{bssid}; + my $enc_mode = $ui_input->{encryption}; + my $key = $ui_input->{key}; + my $force_ascii = $ui_input->{force_ascii_key}; + my $mode = $ui_input->{mode}; + + my $network = { + ssid => qq("$essid"), + scan_ssid => to_bool($bssid), #- hidden or non-broadcasted SSIDs + if_($bssid, bssid => $bssid), + if_($enc_mode ne 'none', priority => 1), + }; + + if ($enc_mode eq 'wpa-psk') { + $network->{psk} = convert_psk_key_for_wpa_supplicant($key); + } else { + $network->{key_mgmt} = 'NONE'; + $network->{mode} = to_bool($mode eq 'Ad-hoc'); + if (member($enc_mode, qw(open restricted))) { + put_in_hash($network, { + wep_key0 => convert_wep_key_for_wpa_supplicant($key, $force_ascii), + wep_tx_keyidx => 0, + auth_alg => $enc_mode eq 'restricted' ? 'SHARED' : 'OPEN', + }); + } + } + + #- handle extra variables as final overides + handle_extra_params($network, $ui_input->{extra}); + + @$conf = difference2($conf, [ wpa_supplicant_find_similar($conf, $network) ]); + push @$conf, $network; + wpa_supplicant_write_conf($conf); +} + +sub wpa_supplicant_find_similar { + my ($conf, $network) = @_; + grep { + my $current = $_; + any { exists $network->{$_} && $network->{$_} eq $current->{$_} } qw(ssid bssid); + } @$conf; +} + +sub wpa_supplicant_read_conf() { + my @conf; + my $network; + foreach (cat_($::prefix . $wpa_supplicant_conf)) { + if ($network) { + #- in a "network = {}" block + # value is either the string with "quotes" - or a full-length string + if (/^\s*(\w+)=\s*(?|([^"].*)|("[^"]*")).*$/) { + $network->{$1} = $2; + } elsif (/^\}/) { + #- end of network block + push @conf, $network; + undef $network; + } + } elsif (/^\s*network={/) { + #- beginning of a new network block + $network = {}; + } + } + \@conf; +} + +sub wpa_supplicant_write_conf { + my ($conf) = @_; + my $buf; + my @conf = @$conf; + my $network; + foreach (cat_($::prefix . $wpa_supplicant_conf)) { + if ($network) { + #- in a "network = {}" block + if (/^\s*(\w+)=(.*)$/) { + push @{$network->{entries}}, { key => $1, value => $2 }; + member($1, qw(ssid bssid)) and $network->{$1} = $2; + } elsif (/^\}/) { + #- end of network block, write it + $buf .= "network={$network->{comment}\n"; + + my $new_network = first(wpa_supplicant_find_similar(\@conf, $network)); + foreach (@{$network->{entries}}) { + my $key = $_->{key}; + if ($new_network) { + #- do not write entry if not provided in the new network + exists $new_network->{$key} or next; + #- update value from the new network + $_->{value} = delete $new_network->{$key}; + } + $buf .= " "; + $buf .= "$key=$_->{value}" if $key; + $buf .= "$_->{comment}\n"; + } + if ($new_network) { + #- write new keys + while (my ($key, $value) = each(%$new_network)) { + $buf .= " $key=$value\n"; + } + } + $buf .= "}\n"; + $new_network and @conf = grep { $_ != $new_network } @conf; + undef $network; + } else { + #- unrecognized, keep it anyway + push @{$network->{entries}}, { comment => $_ }; + } + } else { + if (/^\s*network={/) { + #- beginning of a new network block + $network = {}; + } else { + #- keep other options, comments + $buf .= $_; + } + } + } + + #- write remaining networks + foreach (@conf) { + $buf .= "\nnetwork={\n"; + while (my ($key, $value) = each(%$_)) { + $buf .= " $key=$value\n"; + } + $buf .= "}\n"; + } + + output($::prefix . $wpa_supplicant_conf, $buf); + #- hide keys for non-root users + chmod 0600, $::prefix . $wpa_supplicant_conf; +} + +sub wpa_supplicant_load_eap_settings { + my ($network) = @_; + my $quoted_essid = qq("$network->{essid}"); + my $conf = wpa_supplicant_read_conf(); + foreach my $old_net (@$conf) { + if ($old_net->{ssid} eq $network->{essid} || $old_net->{ssid} eq $quoted_essid) { + $network->{extra} = ''; + foreach my $eap_var (keys %eap_vars) { + next if $eap_var eq 'ssid'; + my $ui_var = join('_', "eap", $eap_var); + if (defined $old_net->{$eap_var}) { + if ($eap_vars{$eap_var} == 0) { + if ($network->{extra} eq "") { + $network->{extra} = "$eap_var=$old_net->{$eap_var}"; + } else { + $network->{extra} = join('#', $network->{extra}, "$eap_var=$old_net->{$eap_var}"); + } + } else { + $network->{$ui_var} = $old_net->{$eap_var}; + #- remove quotes on selected variables + $network->{$ui_var} = $1 if $eap_vars{$eap_var} == 2 && $network->{$ui_var} =~ /^"(.*)"$/; + if ($eap_var eq "proto") { + $network->{forceeap} = 'WPA2' if $old_net->{$eap_var} eq "RSN"; + $network->{forceeap} = 'WPA' if $old_net->{$eap_var} eq "WPA"; + } + } + } + } + last; + } + } +} + +sub handle_extra_params { + my ($network, $extra) = @_; + #- handle extra variables as final overides + if (defined $extra && $extra ne "") { + #- FIXME: should split it on what the # sign? + foreach my $extra_var (split('#', $extra)) { + my ($key, $val) = split('=', $extra_var, 2); + $network->{$key} = $val; + } + } +} +sub wpa_supplicant_add_eap_network { + my ($ui_input) = @_; + + #- expect all variables for us to be prefixed with eap_ + my $conf = wpa_supplicant_read_conf(); + my $default_eap_cfg = { + pairwise => 'CCMP TKIP', + group => 'CCMP TKIP', + proto => 'RSN WPA', + key_mgmt => 'WPA-EAP IEEE8021X NONE', + scan_ssid => 1, + }; + if ($ui_input->{forceeap} eq 'WPA') { + #- WPA only + $default_eap_cfg->{pairwise} = 'TKIP'; + $default_eap_cfg->{group} = 'TKIP'; + $default_eap_cfg->{proto} = 'WPA'; + } elsif ($ui_input->{forceeap} eq 'WPA2') { + #- WPA2 only + $default_eap_cfg->{pairwise} = 'CCMP TKIP'; + $default_eap_cfg->{group} = 'CCMP TKIP'; + $default_eap_cfg->{proto} = 'RSN'; + } + my $network = { ssid => qq("$ui_input->{essid}") }; + #- set the values + foreach my $eap_var (keys %eap_vars) { + my $key = join('_', "eap", $eap_var); + if (!defined $ui_input->{$key} || $ui_input->{$key} =~ /auto detect/i) { + $network->{$eap_var} = $default_eap_cfg->{$eap_var} if $default_eap_cfg->{$eap_var}; + } else { + #- do not define if blank, the save routine will delete entry from file + next if !$ui_input->{$key}; + $network->{$eap_var} = $eap_vars{$eap_var} == 2 ? qq("$ui_input->{$key}") : $ui_input->{$key}; + } + } + #- handle extra variables as final overides + handle_extra_params($network, $ui_input->{extra}); + + $network->{mode} = to_bool($ui_input->{mode} eq 'Ad-hoc'); + + @$conf = difference2($conf, [ wpa_supplicant_find_similar($conf, $network) ]); + push @$conf, $network; + wpa_supplicant_write_conf($conf); +} +1; diff --git a/lib/network/connection/xdsl.pm b/lib/network/connection/xdsl.pm new file mode 100644 index 0000000..e55dd24 --- /dev/null +++ b/lib/network/connection/xdsl.pm @@ -0,0 +1,412 @@ +package network::connection::xdsl; + +use base qw(network::connection::ppp); + +use strict; +use common; + +sub get_type_name() { N("DSL") } +sub _get_type_icon() { 'xdsl' } + +sub get_devices() { + require detect_devices; + require network::connection::isdn; + require network::connection::ethernet; + my @usb_devices = detect_devices::get_xdsl_usb_devices(); + $_->{xdsl_type} = 'usb' foreach @usb_devices; + my @capi_devices = grep { $_->{driver} =~ /dsl/i } map { network::connection::isdn::find_capi_card($_) } network::connection::isdn->get_devices; + $_->{xdsl_type} = 'capi' foreach @capi_devices; + my @ethernet_devices = network::connection::ethernet::get_devices(); + $_->{xdsl_type} = 'ethernet' foreach @ethernet_devices; + @usb_devices, @capi_devices, @ethernet_devices; +} + +sub get_metric { 25 } +sub get_interface() { "ppp0" } + +sub get_up_timeout { 20 } + +my @non_ppp_protocols = qw(static dhcp); +sub uses_ppp { + my ($self) = @_; + !member($self->{protocol}, @non_ppp_protocols); +} + +sub uses_atm_arp { + my ($self) = @_; + $self->{device}{xdsl_type} eq 'usb' && !$self->uses_ppp; +} +sub get_atm_arp_interface { "atm0" } + +sub uses_atm_bridging { + my ($self) = @_; + $self->{device}{xdsl_type} eq 'usb' && member($self->{protocol}, qw(pppoe)); +} +sub get_atm_bridging_interface { "nas0" } + +sub get_pppoe_interface { + my ($self) = @_; + $self->uses_atm_bridging + ? $self->get_atm_bridging_interface + : $self->network::connection::ethernet::get_interface; +} + +my %protocol_settings = ( + pppoa => { + plugin => sub { + my ($self) = @_; + "pppoatm.so " . join('.', $self->{access}{peer}{vpi}, $self->{access}{peer}{vci}); + }, + }, + pppoe => { + pty => sub { + my ($self) = @_; + my $pppoe_interface = $self->get_pppoe_interface; + qq("pppoe -m 1412 -I $pppoe_interface"); + }, + options => [ + qw(default-asyncmap noaccomp nobsdcomp novjccomp nodeflate), + "mru 1492", + "mtu 1492", + "lcp-echo-interval 20", + "lcp-echo-failure 3", + ], + }, + pptp => { + pty => qq("/usr/sbin/pptp 10.0.0.138 --nolaunchpppd"), + options => [ qw(noipdefault) ], + }, + capi => { + plugin => "capiplugin.so avmadsl", + options => [ + qw(ipcp-accept-remote ipcp-accept-local sync noipx), + "connect /bin/true", + "lcp-echo-interval 5", + "lcp-echo-failure 3", + "lcp-max-configure 50", + "lcp-max-terminate 2", + "mru 1492", + "mtu 1492" + ], + }, +); + +my @thirdparty_settings = ( + { + matching => 'speedtch', + description => N_("Alcatel speedtouch USB modem"), + url => "http://www.speedtouch.com/supuser.htm", + name => 'speedtouch', + firmware => + { + package => 'speedtouch-firmware', + test_file => 'speedtch-*.bin*', + extract => { + name => 'speedtouch-firmware-extractor', + test_file => '/usr/sbin/firmware-extractor', + windows_source => 'alcaudsl.sys', + floppy_source => 'mgmt*.o', + default_source => '/usr/share/speedtouch/mgmt.o', + run => sub { + my ($file) = @_; + run_program::raw({ root => $::prefix, chdir => $network::thirdparty::firmware_directory }, + '/usr/sbin/firmware-extractor', $file); + }, + }, + }, + links => 'http://linux-usb.sourceforge.net/SpeedTouch/mandrake/index.html', + ppp => { + options => [ qw(noaccomp sync) ], + }, + }, + + { + name => 'eciadsl', + explanations => N_("The ECI Hi-Focus modem cannot be supported due to binary driver distribution problem. + +You can find a driver on http://eciadsl.flashtux.org/"), + no_distro_package => 1, + tools => { + test_file => '/usr/sbin/pppoeci', + }, + ppp => { + options => [ + qw(noipdefault noaccomp sync), + "linkname eciadsl", + "lcp-echo-interval 0", + ], + protocols => { + pppoe => { + pty => sub { + my ($self) = @_; + qq("/usr/bin/pppoeci -v 1 -vpi $self->{access}{peer}{vpi} -vci $self->{access}{peer}{vci}"); + }, + }, + }, + }, + }, + + { + matching => 'ueagle_atm', + description => 'Eagle chipset (from Analog Devices), e.g. Sagem F@st 800/840/908', + url => 'http://www.eagle-usb.org/', + name => 'ueagle', + firmware => { + test_file => 'ueagle-atm/eagle*.fw', + }, + links => 'http://atm.eagle-usb.org/wakka.php?wiki=UeagleAtmDoc', + }, + + { + matching => qr/^unicorn_.*_atm$/, + description => 'Bewan Adsl (Unicorn)', + url => 'http://www.bewan.com/bewan/users/downloads/', + name => 'unicorn', + kernel_module => 1, + tools => { + optional => 1, + test_file => '/usr/bin/bewan_adsl_status', + }, + sleep => 10, + ppp => { + options => [ + qw(default-asyncmap hide-password noaccomp nobsdcomp nodeflate novjccomp sync), + "lcp-echo-interval 20", + "lcp-echo-failure 3", + ], + }, + }, + + { + name => 'cxacru', + firmware => { + test_file => 'cxacru-fw.bin', + no_distro_package => 1, + explanations => N_("Modems using Conexant AccessRunner chipsets cannot be supported due to binary firmware distribution problem."), + url => 'http://accessrunner.sourceforge.net/firmware.shtml', + }, + } +); + +sub get_thirdparty_settings() { + \@thirdparty_settings; +} + +sub get_providers { + my ($self) = @_; + require network::connection::providers::xdsl; + if_($self->{device}{xdsl_type} ne 'capi', \%network::connection::providers::xdsl::data, '|'); +} + +sub get_protocols { + my ($self) = @_; + $self->{device}{xdsl_type} eq 'capi' ? + { + capi => N("DSL over CAPI"), + } : + { + dhcp => N("Dynamic Host Configuration Protocol (DHCP)"), + static => N("Manual TCP/IP configuration"), + pptp => N("Point to Point Tunneling Protocol (PPTP)"), + pppoe => N("PPP over Ethernet (PPPoE)"), + pppoa => N("PPP over ATM (PPPoA)"), + }; +} + +sub guess_protocol { + my ($self, $net) = @_; + $self->{protocol} = $self->{provider} && $self->{provider}{method}; + if ($self->{device}{xdsl_type} eq 'capi') { + $self->{protocol} = 'capi'; + } elsif ($self->{device}{xdsl_type} eq 'ethernet') { + require network::connection::ethernet; + my $interface = $self->network::connection::ethernet::get_interface; + if (my $ifcfg = $net->{ifcfg}{$interface}) { + $self->{protocol} = $ifcfg->{BOOTPROTO} if member($ifcfg->{BOOTPROTO}, @non_ppp_protocols); + $self->{protocol} ||= 'dhcp'; + #- pppoa shouldn't be selected by default for ethernet devices, fallback on pppoe + $self->{protocol} = 'pppoe' if $self->{protocol} eq 'pppoa'; + } + } +} + +sub guess_access_settings { + my ($self) = @_; + require network::adsl; + my $probe = {}; + network::adsl::adsl_probe_info($probe); + $self->{access}{login} = $probe->{adsl}{login}; + $self->{access}{password} = $probe->{adsl}{passwd}; + $self->{access}{peer}{$_} = $probe->{adsl}{$_} foreach qw(vpi vci); + if ($self->{provider}) { + $self->{access}{peer}{$_} = hex($self->{provider}{$_}) foreach qw(vpi vci); + } +} + +sub get_access_settings { + my ($self) = @_; + + [ + @{$self->network::connection::ppp::get_access_settings}, + if_(member($self->{protocol}, qw(pppoa pppoe)), + { label => N("Virtual Path ID (VPI):"), val => \$self->{access}{peer}{vpi}, advanced => 1 }, + { label => N("Virtual Circuit ID (VCI):"), val => \$self->{access}{peer}{vci}, advanced => 1 } + ), + ]; +} + +sub get_peer_default_options { + my ($self) = @_; + $self->network::connection::ppp::get_peer_default_options, + qw(lock persist nopcomp noccp novj), + "kdebug 1", + "holdoff 4", + "maxfail 5"; +} + +sub build_peer { + my ($self) = @_; + my $may_call = sub { ref $_[0] eq 'CODE' ? $_[0]->($self) : $_[0] }; + my @ppp_fields = qw(plugin pty); + my @ppp_options; + if ($self->{thirdparty}) { + foreach my $settings (grep { $_ } $self->{thirdparty}{ppp}{protocols}{$self->{protocol}}, $self->{thirdparty}{ppp}) { + @ppp_options = @{$settings->{options}} if $settings->{options}; + foreach (@ppp_fields) { + $self->{access}{peer}{$_} ||= $may_call->($settings->{$_}) if defined $settings->{$_}; + } + } + } + if (my $generic_settings = $protocol_settings{$self->{protocol}}) { + @ppp_options = @{$generic_settings->{options} || []} if !@ppp_options; + foreach (@ppp_fields) { + $self->{access}{peer}{$_} ||= $may_call->($generic_settings->{$_}) if defined $generic_settings->{$_}; + } + } + + @ppp_options, #- write them before pty/plugin stuff + $self->network::connection::ppp::build_peer; +} + +sub write_settings { + my ($self, $net) = @_; + + if ($self->{device}{xdsl_type} eq 'ethernet' && $self->{protocol} eq 'pppoe') { + my $interface = $self->network::connection::ethernet::get_interface; + $net->{ifcfg}{$interface} = { + DEVICE => $interface, + BOOTPROTO => 'none', + NETMASK => '255.255.255.0', + NETWORK => '10.0.0.0', + BROADCAST => '10.0.0.255', + MII_NOT_SUPPORTED => 'yes', + ONBOOT => 'yes', + }; + } + + if ($self->{protocol} eq 'capi') { + require network::connection::isdn; + network::connection::isdn::write_capi_conf($self->{device}); + } + + #- TODO: add "options ueagle-atm cmv_file= $net->{adsl}{cmv}.bin" in /etc/modprobe.d/ueagle-atm + # if ($self->get_driver eq 'ueagle-atm') { ... } + + if ($self->uses_ppp) { + $self->network::connection::ppp::write_settings; + } else { + $self->network::connection::write_settings; + } +} + +sub build_ifcfg_settings { + my ($self) = @_; + my $settings = { + if_($self->uses_ppp, TYPE => 'ADSL'), + }; + if ($self->uses_atm_arp) { + #- use ATMARP with the atm0 interface + put_in_hash($settings, { + DEVICE => $self->get_atm_arp_interface, + ATM_ADDR => join('.', @{$self->{access}{peer}}{qw(vpi vci)}), + MII_NOT_SUPPORTED => "yes", + }); + } + if ($self->uses_atm_bridging) { + put_in_hash($settings, { + ATM_DEVICE => $self->get_atm_bridging_interface, + ATM_ADDR => join('.', @{$self->{access}{peer}}{qw(vpi vci)}), + }); + } + $self->network::connection::build_ifcfg_settings($settings); +} + +sub unload_connection { + my ($self) = @_; + require network::connection::isdn; + network::connection::isdn::unload_connection($self->{device}) if $self->{protocol} eq 'capi'; +} + +sub install_packages { + my ($self, $in) = @_; + my $per_type_packages = { + pppoa => [ qw(ppp-pppoatm) ], + pppoe => [ qw(rp-pppoe) ], + pptp => [ qw(pptp-linux) ], + capi => [ qw(ppp) ], + }; + my @packages = @{$per_type_packages->{$self->{protocol}} || []}; + push @packages, 'linux-atm' if $self->uses_atm_arp || $self->uses_atm_bridging; + if (@packages && !$in->do_pkgs->install(@packages)) { + $in->ask_warn(N("Error"), N("Could not install the packages (%s)!", @packages)); + return; + } + if ($self->{protocol} eq 'capi') { + require network::connection::isdn; + network::connection::isdn::install_packages($self->{device}, $in); + $in->do_pkgs->ensure_is_installed_if_available("drdsl", "/usr/sbin/drdsl"); + } + 1; +} + +sub prepare_connection { + my ($self) = @_; + + if ($::isInstall) { + #- load modules that are not automatically loaded during install + my @modules = qw(ppp_synctty ppp_async ppp_generic n_hdlc); #- required for pppoe/pptp connections + push @modules, 'pppoatm' if $self->{protocol} eq 'pppoa'; + foreach (@modules) { + eval { modules::load($_) } or log::l("failed to load $_ module: $@"); + } + } + + if ($self->{protocol} eq 'capi') { + require network::connection::isdn; + network::connection::isdn::prepare_connection($self->{device}); + require run_program; + run_program::rooted($::prefix, "/usr/sbin/drdsl"); + } + + 1; +} + +sub connect { + my ($self) = @_; + if ($self->{device}{xdsl_type} eq 'ethernet') { + require network::tools; + network::tools::start_interface($self->network::connection::ethernet::get_interface, 0); + } + $self->network::connection::connect; +} + +sub disconnect { + my ($self) = @_; + $self->network::connection::disconnect; + if ($self->{device}{xdsl_type} eq 'ethernet') { + require network::tools; + network::tools::stop_interface($self->network::connection::ethernet::get_interface, 0); + } +} + +1; diff --git a/lib/network/connection_manager.pm b/lib/network/connection_manager.pm new file mode 100644 index 0000000..3efb2c1 --- /dev/null +++ b/lib/network/connection_manager.pm @@ -0,0 +1,506 @@ +package network::connection_manager; + +use strict; + +use common; +use run_program; +use detect_devices; +use interactive; +use mygtk2; +use ugtk2 qw(:create :helpers :wrappers); +use Gtk2::SimpleList; +use network::signal_strength; +use network::network; +use network::tools; +use network::connection; +use modules; +use locale; # for cmp + +sub create_pixbufs() { + { + state => { map { $_ => gtkcreate_pixbuf($_) } qw(connected disconnected refresh) }, + link_level => { map { + $_ => gtkcreate_pixbuf('wifi-' . sprintf('%03d', $_))->scale_simple(24, 24, 'hyper'); + } qw(20 40 60 80 100) }, + encryption => { map { + $_ => gtkcreate_pixbuf("encryption-$_-24"); + } qw(open weak strong) }, + }; +} + +sub new { + my ($class, $in, $net, $w, $pixbufs) = @_; + bless { + in => $in, net => $net, gui => { w => $w, pixbufs => $pixbufs }, + }, $class; +} + +sub set_connection { + my ($cmanager, $connection) = @_; + $cmanager->{connection} = $connection; + $cmanager->{wait_message_timeout} = 20*1000 if ref($connection) eq 'network::connection::wireless'; +} + +sub check_setup { + my ($cmanager) = @_; + $cmanager->{connection}{passed_setup} = + (!$cmanager->{connection}->can("check_device") || + $cmanager->{connection}->check_device) && + (!$cmanager->{connection}->can("check_hardware") || + !$cmanager->{connection}->check_hardware_is_slow && $cmanager->{connection}->check_hardware) + if !defined $cmanager->{connection}{passed_setup}; + $cmanager->{connection}{passed_setup}; +} + +sub setup_connection { + my ($cmanager) = @_; + + $cmanager->load_settings; + + my @packages = $cmanager->{connection}->can('get_packages') ? $cmanager->{connection}->get_packages : (); + if (@packages && !$cmanager->{in}->do_pkgs->install(@packages)) { + $cmanager->{in}->ask_warn(N("Error"), N("Could not install the packages (%s)!", join(', ', @packages))); + return; + } + $cmanager->{connection}->prepare_device; + $cmanager->{connection}->setup_thirdparty($cmanager->{in}) or return; + if ($cmanager->{connection}->can("check_device") && !$cmanager->{connection}->check_device) { + $cmanager->{in}->ask_warn(N("Error"), $cmanager->{connection}{device}{error}); + return; + } + my $device_ready = 1; + if ($cmanager->{connection}->can('check_hardware')) { + #- FIXME: change message to "Checking device..." in cooker + my $_wait = $cmanager->{in}->wait_message(N("Please wait"), N("Configuring device...")); + $device_ready = $cmanager->{connection}->check_hardware; + } + if ($cmanager->{connection}->can('get_hardware_settings') && !$device_ready) { + $cmanager->{in}->ask_from_({ + title => N("Network settings"), + messages => N("Please enter settings for network"), + auto_window_size => 1, + }, $cmanager->{connection}->get_hardware_settings) or return; + if ($cmanager->{connection}->can("check_hardware_settings") && !$cmanager->{connection}->check_hardware_settings) { + $cmanager->{in}->ask_warn(N("Error"), $cmanager->{connection}->{hardware}{error}); + return; + } + } + if ($cmanager->{connection}->can('configure_hardware') && !$device_ready) { + my $wait = $cmanager->{in}->wait_message(N("Please wait"), N("Configuring device...")); + if (!$cmanager->{connection}->configure_hardware) { + undef $wait; + $cmanager->{in}->ask_warn(N("Error"), $cmanager->{connection}{hardware}{error}) if $cmanager->{connection}{hardware}{error}; + return; + } + } + $cmanager->write_settings; + $cmanager->{connection}{passed_setup} = 1; +} + +sub load_settings { + my ($cmanager) = @_; + + $cmanager->{connection}->load_interface_settings; + $cmanager->{connection}->guess_hardware_settings if $cmanager->{connection}->can('guess_hardware_settings'); + $cmanager->{connection}->guess_network_access_settings if $cmanager->{connection}->can('guess_network_access_settings'); + if ($cmanager->{connection}->can('get_providers')) { + $cmanager->{connection}->guess_provider_settings; + $cmanager->{connection}->set_provider; + } + $cmanager->{connection}->guess_protocol($cmanager->{net}) if $cmanager->{connection}->can('guess_protocol'); + $cmanager->{connection}->guess_access_settings if $cmanager->{connection}->can('guess_access_settings'); + $cmanager->{connection}->guess_address_settings if $cmanager->{connection}->can('guess_address_settings'); + $cmanager->{connection}->guess_hostname_settings if $cmanager->{connection}->can('guess_hostname_settings'); + $cmanager->{connection}->guess_network_control_settings if $cmanager->{connection}->can('guess_network_control_settings'); + $cmanager->{connection}->guess_control_settings; +} + +sub write_settings { + my ($cmanager) = @_; + + my $modules_conf = modules::any_conf->read; + $cmanager->{connection}->write_settings($cmanager->{net}, $modules_conf); + $modules_conf->write; +} + +sub configure_connection { + my ($cmanager) = @_; + + if (!$cmanager->check_setup) { + $cmanager->setup_connection or return; + $cmanager->update_networks if $cmanager->{connection}->can('get_networks'); + $cmanager->update_on_status_change; + return; + } + + $cmanager->load_settings; + my $system_file = '/etc/sysconfig/drakx-net'; + my %global_settings = getVarsFromSh($system_file); + + my $error; + do { + undef $error; + $cmanager->{in}->ask_from_({ + title => N("Network settings"), + messages => N("Please enter settings for network"), + icon => $cmanager->{connection}->get_type_icon(48), + banner_title => $cmanager->{connection}->get_description, + }, + [ + $cmanager->{connection}->can('get_network_access_settings') ? ( + { label => $cmanager->{connection}->get_network_access_settings_label, title => 1, advanced => 1 }, + @{$cmanager->{connection}->get_network_access_settings}, + ) : (), + $cmanager->{connection}->can('get_providers') ? ( + @{$cmanager->{connection}->get_provider_settings($cmanager->{net})} + ) : (), + $cmanager->{connection}->can('get_protocols') ? ( + @{$cmanager->{connection}->get_protocol_settings}, + ) : (), + $cmanager->{connection}->can('get_access_settings') ? ( + { label => $cmanager->{connection}->get_access_settings_label, title => 1, advanced => 1 }, + @{$cmanager->{connection}->get_access_settings} + ) : (), + $cmanager->{connection}->can('get_address_settings') && !text2bool($global_settings{AUTOMATIC_ADDRESS}) ? ( + { label => $cmanager->{connection}->get_address_settings_label, title => 1, advanced => 1 }, + @{$cmanager->{connection}->get_address_settings('show_all')} + ) : (), + $cmanager->{connection}->can('get_network_control_settings') ? ( + @{$cmanager->{connection}->get_network_control_settings} + ) : (), + $cmanager->{connection}->can('get_control_settings') ? ( + @{$cmanager->{connection}->get_control_settings} + ) : (), + ], + ) or return; + if ($cmanager->{connection}->can('check_network_access_settings') && !$cmanager->{connection}->check_network_access_settings) { + $cmanager->{in}->ask_warn(N("Error"), $cmanager->{connection}{network_access}{error}{message}); + $error = 1; + } + if ($cmanager->{connection}->can('check_address_settings') && !$cmanager->{connection}->check_address_settings($cmanager->{net})) { + $cmanager->{in}->ask_warn(N("Error"), $cmanager->{connection}{address}{error}{message}); + $error = 1; + } + } while $error; + + $cmanager->{connection}->install_packages($cmanager->{in}) if $cmanager->{connection}->can('install_packages'); + $cmanager->{connection}->unload_connection if $cmanager->{connection}->can('unload_connection'); + + $cmanager->write_settings; + + 1; +} + +sub start_connection { + my ($cmanager) = @_; + + $cmanager->{connection} or return; + if ($cmanager->{connection}->can('get_networks')) { + $cmanager->{connection}{network} && + ($cmanager->{connection}->selected_network_is_configured || + $cmanager->configure_connection) + or return; + } + + gtkset_mousecursor_wait($cmanager->{gui}{w}{window}->window); + my $wait = $cmanager->{in}->wait_message(N("Please wait"), N("Connecting...")); + if ($cmanager->{connection}->can('apply_network_selection')) { + $cmanager->load_settings; + $cmanager->{connection}->apply_network_selection($cmanager); + } + $cmanager->{connection}->prepare_connection if $cmanager->{connection}->can('prepare_connection'); + $cmanager->{connection}->disconnect; + $cmanager->{connection}->connect($cmanager->{in}, $cmanager->{net}); + gtkset_mousecursor_normal($cmanager->{gui}{w}{window}->window); + + $cmanager->update_on_status_change; + if ($cmanager->{wait_message_timeout}) { + $cmanager->{wait_message} = $wait; + Glib::Timeout->add($cmanager->{wait_message_timeout}, + sub { + if ($cmanager->{wait_message}) { + undef $cmanager->{wait_message}; + $cmanager->{in}->ask_warn(N("Error"), N("Connection failed.")) + if !$cmanager->{connection}->get_status; + } + undef; + }); + }; +} + +sub stop_connection { + my ($cmanager) = @_; + + gtkset_mousecursor_wait($cmanager->{gui}{w}{window}->window); + my $_wait = $cmanager->{in}->wait_message(N("Please wait"), N("Disconnecting...")); + $cmanager->{connection}->disconnect; + gtkset_mousecursor_normal($cmanager->{gui}{w}{window}->window); + + $cmanager->update_on_status_change; +} + +sub monitor_connection { + my ($cmanager) = @_; + my $interface = $cmanager->{connection} && $cmanager->{connection}->get_interface or return; + run_program::raw({ detach => 1 }, '/usr/bin/net_monitor', '--defaultintf', $interface); +} + +sub toggle_would_disconnect { + my ($cmanager) = @_; + + my $network = $cmanager->{connection} && $cmanager->{connection}->get_selected_network; + $cmanager->{connection} && $cmanager->{connection}->get_status && + (!$network || keys(%{$cmanager->{connection}{networks}}) <= 1 || $network->{current}); +} + +sub toggle_connection { + my ($cmanager) = @_; + + if ($cmanager->toggle_would_disconnect) { + $cmanager->stop_connection; + } else { + $cmanager->start_connection; + } +} + +sub create_networks_list { + my ($cmanager) = @_; + + if ($cmanager->{gui}{show_unique_network}) { + $cmanager->{gui}{networks_list} = gtknew('HBox', spacing => 20); + return; + } + + $cmanager->{gui}{networks_list} = Gtk2::SimpleList->new( + "AP" => "hidden", + '' => "pixbuf", + N("SSID") => "text", + N("Signal strength") => "pixbuf", + N("Encryption") => "pixbuf", + N("Operating Mode") => "text", + ); + $cmanager->{gui}{networks_list}->get_selection->set_mode('single'); + $cmanager->{gui}{networks_list}->get_selection->signal_connect('changed' => sub { $cmanager->select_network }); + + $cmanager->{gui}{networks_list}->signal_connect('query-tooltip' => sub { + my ($widget, $x, $y, $kbd_tip, $tooltip) = @_; + (undef, undef, my $model, my $path, my $iter) = $widget->get_tooltip_context($x, $y, $kbd_tip) or return; + my $ap = $model->get($iter, 0); + my $network = $cmanager->{connection}{networks}{$ap}; + $tooltip->set_text(sprintf("%2.2f%% %s\n", $network->{signal_strength}, $network->{flags})); + $widget->set_tooltip_row($tooltip, $path); + 1; + }); + $cmanager->{gui}{networks_list}->set_has_tooltip(1); + $cmanager->{gui}{networks_list}->get_column(1)->set_sort_column_id(1); + $cmanager->{gui}{networks_list}->get_model->set_sort_func (1, sub { + my ($sortable, $iter_left, $iter_right) = @_; + my $s1 = $sortable->get($iter_left, 2); + my $s2 = $sortable->get($iter_right, 2); + return $s1 cmp $s2; + }); + $cmanager->{gui}{networks_list}->get_column(2)->set_sort_column_id(2); + $cmanager->{gui}{networks_list}->get_model->set_sort_func (2, sub { + my ($sortable, $iter_left, $iter_right) = @_; + my $s1 = $cmanager->{connection}{networks}{$sortable->get($iter_left, 0)}->{signal_strength}; + my $s2 = $cmanager->{connection}{networks}{$sortable->get($iter_right, 0)}->{signal_strength}; + return $s1 <=> $s2; + }); + $cmanager->{gui}{networks_list}->get_column(3)->set_sort_column_id(3); + $cmanager->{gui}{networks_list}->get_model->set_sort_func (3, sub { + my ($sortable, $iter_left, $iter_right) = @_; + my $s1 = $cmanager->{connection}{networks}{$sortable->get($iter_left, 0)}->{flags}; + my $s2 = $cmanager->{connection}{networks}{$sortable->get($iter_right, 0)}->{flags}; + #FIXME Should define an explicit order OPEN < WEP < WPA + return $s1 cmp $s2; + }); + $cmanager->{gui}{networks_list}->set_enable_search(1); + $cmanager->{gui}{networks_list}->set_search_column(1); + $cmanager->{gui}{networks_list}->set_search_equal_func(sub { + my ($model, $column, $key, $iter, $data) = @_; + return $model->get($iter, 2) !~ /^\Q$key/i; + }); + # Sort by signal level by default + $cmanager->{gui}{networks_list}->get_model->set_sort_column_id(2, 'descending'); +} + +sub select_network { + my ($cmanager) = @_; + + if ($cmanager->{connection}) { + my ($selected) = $cmanager->{gui}{networks_list}->get_selected_indices; + $cmanager->{connection}{network} = defined $selected && $cmanager->{gui}{networks_list}{data}[$selected][0]; + } + $cmanager->update_on_status_change; +} + +sub filter_networks { + my ($connection) = @_; + $_->{configured} = $connection->network_is_configured($_) foreach values %{$connection->{networks}}; + sort { + $b->{current} <=> $a->{current} || $b->{configured} <=> $a->{configured} || $b->{signal_strength} <=> $a->{signal_strength} || $a->{name} cmp $b->{name}; + } values %{$connection->{networks}}; +} + +sub update_networks { + my ($cmanager) = @_; + + @{$cmanager->{gui}{networks_list}{data}} = (); + + if ($cmanager->{connection}) { + $cmanager->check_setup || $cmanager->setup_connection or return; + + my $wait = $cmanager->{connection}->network_scan_is_slow && $cmanager->{in}->wait_message(N("Please wait"), N("Scanning for networks...")); + $cmanager->{connection}{networks} = $cmanager->{connection}->get_networks($cmanager->{net}); + $cmanager->{connection}{network} ||= find { $cmanager->{connection}{networks}{$_}{current} } keys %{$cmanager->{connection}{networks}}; + + my $routes = network::tools::get_routes(); + my $interface = $cmanager->{connection}->get_interface; + my $connected = exists $routes->{$interface}{network}; + + my @networks = filter_networks($cmanager->{connection}); + foreach my $network (@networks) { + my $ap = $network->{ap}; + my $connected_pixbuf = $network->{current} ? $connected ? $cmanager->{gui}{pixbufs}{state}{connected} : $cmanager->{gui}{pixbufs}{state}{refresh} : undef; + my $network_name = !$network->{essid} && exists $cmanager->{net}{wireless}{$ap} && $cmanager->{net}{wireless}{$ap}{WIRELESS_ESSID} || $network->{name}; + my $strength_pixbuf = network::signal_strength::get_strength_icon($network); + + if ($cmanager->{gui}{show_unique_network}) { + gtkset($cmanager->{gui}{networks_list}, children => [ + 1, $network_name, + 0, Gtk2::Image->new_from_pixbuf($strength_pixbuf), + ]); + $cmanager->{connection}{network} = $network_name; + } else { + push @{$cmanager->{gui}{networks_list}{data}}, [ + $ap || $network->{name}, + $connected_pixbuf, + $network_name, + $strength_pixbuf, + $cmanager->{gui}{pixbufs}{encryption}{$network->{flags} =~ /WPA/i ? 'strong' : $network->{flags} =~ /WEP/i ? 'weak' : 'open'}, + $network->{mode}, + ]; + } + } + + if ($cmanager->{connection}{network} && !$cmanager->{gui}{show_unique_network}) { + my $index = eval { find_index { $_->[0] eq $cmanager->{connection}{network} } @{$cmanager->{gui}{networks_list}{data}} }; + $cmanager->{gui}{networks_list}->select($index) if defined $index; + } + + undef $wait; + } + + $cmanager->update_on_status_change; +} + +sub update_on_status_change { + my ($cmanager) = @_; + + if ($cmanager->{gui}{buttons}{connect_toggle}) { + my $disconnect = $cmanager->toggle_would_disconnect; + $cmanager->{gui}{buttons}{connect_toggle}->set_label($disconnect ? N("Disconnect") : N("Connect")); + gtkset($cmanager->{gui}{buttons}{connect_toggle}, image => gtknew('Image', file => $disconnect ? 'stop-16' : 'activate-16')) + if $cmanager->{gui}{buttons}{connect_toggle}->get_image; + $cmanager->{gui}{buttons}{connect_toggle}->set_sensitive( + $cmanager->{connection} && ( + !$cmanager->{connection}->can('get_networks') || + $cmanager->{connection}->get_status || #- always allow to disconnect if connected + $cmanager->{connection}{network} + )); + } + + $cmanager->{gui}{buttons}{connect_start}->set_sensitive($cmanager->{connection} && (!$cmanager->{connection}->get_status || $cmanager->{connection}{network})) + if $cmanager->{gui}{buttons}{connect_start}; + $cmanager->{gui}{buttons}{connect_stop}->set_sensitive($cmanager->{connection} && $cmanager->{connection}->get_status) + if $cmanager->{gui}{buttons}{connect_stop}; + + my $allow_configure; + if ($cmanager->{connection}) { + my $may_have_network = + !$cmanager->{connection}->can('get_networks') || + $cmanager->{connection}{network}; + $allow_configure = $may_have_network || !$cmanager->check_setup; + } + + $cmanager->{gui}{buttons}{configure}->set_sensitive($allow_configure) + if $cmanager->{gui}{buttons}{configure}; + + my $has_interface = to_bool($cmanager->{connection} && $cmanager->{connection}->get_interface); + $cmanager->{gui}{buttons}{refresh}->set_sensitive($has_interface) + if $cmanager->{gui}{buttons}{refresh}; + $cmanager->{gui}{buttons}{monitor}->set_sensitive($has_interface) + if $cmanager->{gui}{buttons}{monitor}; + + if ($cmanager->{gui}{status_image} && $cmanager->{connection}) { + my $icon = $cmanager->{connection}->get_status_icon; + ugtk2::_find_imgfile($icon) or $icon = $cmanager->{connection}->get_type_icon; + gtkset($cmanager->{gui}{status_image}, file => $icon); + } +} + +sub _get_network_event_message { + my ($connections, $member, @args) = @_; + #- FIXME: the hostname.d script and s2u use a different D-Bus interface + if ($member eq 'hostname') { + my ($hostname) = @args; + N("Hostname changed to \"%s\"", $hostname); + } elsif ($member eq 'status') { + my ($status, $interface) = @args; + my $event_connection = find { $_->get_interface eq $interface } @$connections; + $event_connection && $event_connection->get_status_message($status); + } +} + +sub setup_dbus_handlers { + my ($cmanagers, $connections, $on_network_event, $dbus) = @_; + #- FIXME: use network::monitor? + $dbus->{connection}->add_filter( + sub { + my ($_con, $msg) = @_; + if ($msg->get_interface eq 'org.mageia.network') { + my $member = $msg->get_member; + my $message = _get_network_event_message($connections, $member, $msg->get_args_list); + $on_network_event->($message) if $on_network_event && $message; + if ($member eq 'status') { + my ($status, $interface) = $msg->get_args_list; + print "got connection status event: $status $interface\n"; + my $cmanager = find { $_->{connection}->get_interface eq $interface } @$cmanagers + or return; + #- FIXME: factorize in update_on_status_change() and check why update_networks() calls update_on_status_change() + if ($cmanager->{connection}->can('get_networks') && !$cmanager->{connection}->network_scan_is_slow) { + $cmanager->update_networks; + } else { + $cmanager->network::connection_manager::update_on_status_change; + } + if ($cmanager->{wait_message}) { + if ($status eq 'interface_up') { + undef $cmanager->{wait_message}; + } elsif ($status =~ /_failure$/) { + undef $cmanager->{wait_message}; + $cmanager->{in}->ask_warn(N("Error"), join("\n", N("Connection failed."), if_($message, $message))); + } + } + } + } + if ($msg->get_interface eq 'org.mageia.monitoring.wireless' && $msg->get_member eq 'Event') { + my ($event, $interface) = $msg->get_args_list; + print "got wireless event: $event $interface\n"; + # eugeni: wpa_supplicant seems to issue 'Authentication..timed out messages' even if they + # are not fatal (#54002). We should either handle them with more care, or just ignore them altogether +# my $cmanager = find { $_->{connection}->get_interface eq $interface } @$cmanagers; +# if ($cmanager && $cmanager->{wait_message}) { +# # CTRL-EVENT-CONNECTED does not have to be handled, further status will be handled by interface status code +# if ($event =~ /Authentication with (.+?) timed out/) { +# undef $cmanager->{wait_message}; +# $cmanager->{in}->ask_warn(N("Error"), N("Connection failed.")); +# } +# } + } + }); + $dbus->{connection}->add_match("type='signal',interface='org.mageia.network'"); + $dbus->{connection}->add_match("type='signal',interface='org.mageia.monitoring.wireless'"); + dbus_object::set_gtk2_watch_helper($dbus); +} + +1; diff --git a/lib/network/dhcpd.pm b/lib/network/dhcpd.pm new file mode 100644 index 0000000..8cf30d5 --- /dev/null +++ b/lib/network/dhcpd.pm @@ -0,0 +1,50 @@ +package network::dhcpd; + +use strict; +use common; + +my $sysconf_dhcpd = "$::prefix/etc/sysconfig/dhcpd"; +my $dhcpd_conf_file = "$::prefix/etc/dhcpd.conf"; +my $update_dhcp = "/usr/sbin/update_dhcp.pl"; + +sub read_dhcpd_conf { + my ($o_file) = @_; + my $s = cat_($o_file || $dhcpd_conf_file); + { option_routers => [ $s =~ /^\s*option routers\s+(\S+);/mg ], + subnet_mask => [ if_($s =~ /^\s*option subnet-mask\s+(.*);/mg, split(' ', $1)) ], + domain_name => [ if_($s =~ /^\s*option domain-name\s+"(.*)";/mg, split(' ', $1)) ], + domain_name_servers => [ if_($s =~ /^\s*option domain-name-servers\s+(.*);/m, split(' ', $1)) ], + dynamic_bootp => [ if_($s =~ /^\s*range dynamic-bootp\s+\S+\.(\d+)\s+\S+\.(\d+)\s*;/m, split(' ', $1)) ], + default_lease_time => [ if_($s =~ /^\s*default-lease-time\s+(.*);/m, split(' ', $1)) ], + max_lease_time => [ if_($s =~ /^\s*max-lease-time\s+(.*);/m, split(' ', $1)) ] }; +} + +sub write_dhcpd_conf { + my ($dhcpd_conf, $device) = @_; + + my ($lan) = $dhcpd_conf->{option_routers}[0] =~ /^(.*)\.\d+$/; + log::explanations("Configuring a DHCP server on $lan.0"); + + renamef($dhcpd_conf_file, "$dhcpd_conf_file.old"); + output($dhcpd_conf_file, qq(subnet $lan.0 netmask $dhcpd_conf->{subnet_mask}[0] { + # default gateway + option routers $dhcpd_conf->{option_routers}[0]; + option subnet-mask $dhcpd_conf->{subnet_mask}[0]; + + option domain-name "$dhcpd_conf->{domain_name}[0]"; + option domain-name-servers $dhcpd_conf->{domain_name_servers}[0]; + + range dynamic-bootp $lan.$dhcpd_conf->{dynamic_bootp}[0] $lan.$dhcpd_conf->{dynamic_bootp}[1]; + default-lease-time $dhcpd_conf->{default_lease_time}[0]; + max-lease-time $dhcpd_conf->{max_lease_time}[0]; +} +)); + + #- put the interface for the dhcp server in the sysconfig-dhcp config, for the /etc/init.d script of dhcpd + log::explanations("Update network interfaces list for dhcpd server"); + substInFile { s/^INTERFACES\n//; $_ .= qq(INTERFACES="$device"\n) if eof } $sysconf_dhcpd if !$::testing; + run_program::rooted($::prefix, $update_dhcp); +} + + +1; diff --git a/lib/network/drakconnect.pm b/lib/network/drakconnect.pm new file mode 100644 index 0000000..4f68ff0 --- /dev/null +++ b/lib/network/drakconnect.pm @@ -0,0 +1,26 @@ +package network::drakconnect; + +use common; +use network::network; + +sub apply { + my ($in, $net, $modules_conf) = @_; + network::network::configure_network($net, $in, $modules_conf); +} + +sub get_intf_ip { + my ($net, $interface) = @_; + my ($ip, $state, $mask); + if (-x "/sbin/ifconfig") { + local $_ = `LC_ALL=C LANGUAGE=C /sbin/ifconfig $interface`; + $ip = /inet addr:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/mso ? $1 : N("No IP"); + $mask = /Mask:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/mso ? $1 : N("No Mask"); + $state = /inet/ ? N("up") : N("down"); + } else { + $ip = $net->{ifcfg}{$interface}{IPADDR}; + $state = "n/a"; + } + ($ip, $state, $mask); +} + +1; diff --git a/lib/network/drakconnect/.perl_checker b/lib/network/drakconnect/.perl_checker new file mode 100644 index 0000000..80deab8 --- /dev/null +++ b/lib/network/drakconnect/.perl_checker @@ -0,0 +1 @@ +Basedir ../../.. diff --git a/lib/network/drakconnect/delete.pm b/lib/network/drakconnect/delete.pm new file mode 100644 index 0000000..b8d0689 --- /dev/null +++ b/lib/network/drakconnect/delete.pm @@ -0,0 +1,68 @@ +package network::drakconnect::delete; + +use common; +use wizards; +use interactive; +use network::connection::ethernet; + +sub del_intf { + my ($in, $net, $modules_conf) = @_; + my ($intf2delete, $failure); + if (!keys %{$net->{ifcfg}}) { + $in->ask_warn(N("Error"), N("No ethernet network adapter has been detected on your system. Please run the hardware configuration tool.")); + return; + } + my @all_cards = network::connection::ethernet::get_eth_cards($modules_conf); + my %names = network::connection::ethernet::get_eth_cards_names(@all_cards); + + my $wiz = wizards->new( + { + defaultimage => "drakconnect", + name => N("Remove a network interface"), + pages => { + welcome => { + no_back => 1, + name => N("Select the network interface to remove:"), + data => [ { label => N("Net Device"), val => \$intf2delete, allow_empty_list => 1, + list => [ keys %{$net->{ifcfg}} ], + format => sub { + my $type = network::tools::get_interface_type($net->{ifcfg}{$_[0]}); + $names{$_[0]} || ($type ? "$type ($_[0])" : $_[0]); + } + } + ], + post => sub { + !$::testing and eval { + if (member($intf2delete, qw(adsl modem))) { + eval { rm_rf("/etc/ppp/peers/ppp0") }; + eval { rm_rf("/etc/sysconfig/network-scripts/ifcfg-ppp0") }; + } + if ($intf2delete eq 'adsl') { + eval { rm_rf("/etc/sysconfig/network-scripts/ifcfg-sagem") }; + } elsif ($intf2delete eq 'isdn') { + eval { rm_rf("/etc/sysconfig/network-scripts/ifcfg-ippp0") }; + } else { + system("ifdown $intf2delete"); + eval { rm_rf("/etc/sysconfig/network-scripts/$intf2delete") }; + eval { rm_rf("/etc/sysconfig/network-scripts/ifcfg-$intf2delete") }; + } + }; + $failure = $@; + network::network::reload_net_applet(); + return "end"; + }, + }, + end => { + name => sub { + $failure ? + N("An error occurred while deleting the \"%s\" network interface:\n\n%s", $intf2delete, $failure) + : N("Congratulations, the \"%s\" network interface has been successfully deleted", $intf2delete); + }, + end => 1, + }, + }, + }); + $wiz->safe_process($in); +} + +1; diff --git a/lib/network/drakconnect/edit.pm b/lib/network/drakconnect/edit.pm new file mode 100644 index 0000000..4e1983b --- /dev/null +++ b/lib/network/drakconnect/edit.pm @@ -0,0 +1,525 @@ +package network::drakconnect::edit; + +use ugtk2 qw(:create :dialogs :helpers :wrappers); +use mygtk2 qw(gtknew); +use common; +use detect_devices; +use run_program; +use network::drakconnect; +use network::adsl; +use network::connection::ethernet; +use network::connection::isdn; +use network::modem; +use network::network; + +sub manage { + my ($in, $net, $modules_conf) = @_; + + my $p = {}; + my ($interface_menu, $selected, $apply_button); + my $window = ugtk2->new('Manage Connection'); + unless ($::isEmbedded) { + $window->{rwindow}->set_position('center'); + $window->{rwindow}->set_title(N("Manage connections")); # translation availlable in mcc domain => we need merging + } + + my $notebook = Gtk2::Notebook->new; + $notebook->set_property('show-tabs', 0); + $notebook->set_property('show-border', 0); + + my @all_cards = network::connection::ethernet::get_eth_cards($modules_conf); + my %names = network::connection::ethernet::get_eth_cards_names(@all_cards); + foreach (keys %names) { + my $dev = detect_devices::is_lan_interface($_) ? $names{$_} : $_; + $p->{$dev} = { + name => $_ , + intf => $net->{ifcfg}{$_} + }; + } + while (my ($device, $interface) = each %{$net->{ifcfg}}) { + exists $names{$device} and next; + my $type = network::tools::get_interface_type($interface); + $p->{"$type ($device)"} = { + name => $device, + intf => $interface + }; + } + + $window->{rwindow}->add(gtkpack_(Gtk2::VBox->new, + 0, gtkpack__(Gtk2::HBox->new, + gtknew('Label', text => N("Device: "), alignment => [ 0, 0 ]), + $interface_menu = gtksignal_connect(Gtk2::ComboBox->new_text, + changed => sub { + $selected = $interface_menu->get_text; + $notebook->set_current_page($p->{$selected}{gui}{index}); + }, + ), + ), + 1, $notebook, + 0, create_okcancel(my $oc = + { + cancel_clicked => sub { $window->destroy; Gtk2->main_quit }, + ok_clicked => sub { + if ($apply_button->get_property('sensitive')) { + save($in, $net, $modules_conf, $p, $apply_button); + } + $window->destroy; + Gtk2->main_quit; + }, + }, + undef, undef, '', + [ N("Help"), sub { run_program::raw({ detach => 1 }, 'drakhelp', '--id', 'internet-connection') } ], + [ N("Apply"), sub { save($in, $net, $modules_conf, $p, $apply_button) }, 0, 1 ], + ), + ), + ); + $apply_button = $oc->{buttons}{N("Apply")}; + + each_index { + my ($name, $interface) = ($_, $p->{$_}{name}); + $p->{$name}{gui}{index} = $::i; + $p->{$name}{intf} ||= { DEVICE => $interface }; + build_tree($in, $net, $p->{$name}{intf}, $name); + build_notebook($net, \@all_cards, $p->{$name}{intf}, $p->{$name}{gui}, $apply_button, $name, $interface); + $notebook->append_page(gtkpack(Gtk2::VBox->new(0,0), $p->{$name}{gui}{notebook})); + } (sort keys %$p); + + $interface_menu->set_popdown_strings(sort keys %$p); + $interface_menu->set_active(0); + $apply_button->set_sensitive(0); + + $window->{rwindow}->show_all; + $window->main; +} + +sub build_tree { + my ($in, $net, $intf, $interface) = @_; + + if ($interface eq 'adsl') { + $intf->{pages} = { 'TCP/IP' => 1, 'DHCP' => 1, 'Account' => 1, 'Options' => 1, 'Information' => 1 }; + network::adsl::adsl_probe_info($net); + $intf->{save} = sub { + $net->{type} = 'adsl'; + network::adsl::adsl_conf_backend($in, $net); + }; + } + elsif ($interface eq 'modem') { + $intf->{pages} = { 'TCP/IP' => 1, 'Account' => 1, 'Modem' => 1, 'Options' => 1 }; + put_in_hash($intf, network::modem::ppp_read_conf()); + $intf->{save} = sub { network::modem::ppp_configure($net, $in, $intf) }; + } + elsif ($interface eq 'isdn') { + $intf->{pages} = { 'TCP/IP' => 1, 'Account' => 1, 'Modem' => 1, 'Options' => 1 }; + network::connection::isdn::read_config($intf); + $intf->{save} = sub { network::connection::isdn::apply_config($in, $intf) }; + } + else { + #- ethernet is default + $intf->{pages} = { 'TCP/IP' => 1, 'DHCP' => 1, if_(network::tools::get_interface_type($intf) eq "wifi", 'Wireless' => 1), 'Options' => 1, 'Information' => 1 }; + } +} + +sub build_notebook { + my ($net, $all_cards, $intf, $gui, $apply_button, $interface, $interface_name) = @_; + + my $apply = sub { $apply_button->set_sensitive(1) }; + my $is_ethernet = detect_devices::is_lan_interface($interface); + + my $size_group = Gtk2::SizeGroup->new('horizontal'); + + if ($intf->{pages}{'TCP/IP'}) { + gtkpack__($gui->{sheet}{'TCP/IP'} = gtkset_border_width(Gtk2::VBox->new(0,10), 5), + gtknew('Title2', label => N("IP configuration")), + if_($is_ethernet, + gtkpack(Gtk2::HBox->new(1,0), + gtknew('Label_Left', text => N("Protocol")), + $gui->{intf}{BOOTPROTO} = gtksignal_connect(Gtk2::ComboBox->new_text, changed => sub { + return if !$_[0]->realized; + my $proto = $gui->{intf}{BOOTPROTO}; + my $protocol = $intf->{BOOTPROTO} = { reverse %{$proto->{protocols}} }->{$proto->get_text}; + + foreach ($gui->{intf}{IPADDR}, $gui->{intf}{NETMASK}, $gui->{network}{GATEWAY}) { + $_->set_sensitive(to_bool($protocol eq "static")); + } + $gui->{sheet}{DHCP}->set_sensitive($intf->{BOOTPROTO} eq 'dhcp'); + $apply->(); + }, + ), + ), + ), + gtkpack(Gtk2::HBox->new(1,0), + gtknew('Label_Left', text => N("IP address")), + gtksignal_connect($gui->{intf}{IPADDR} = Gtk2::Entry->new, + key_press_event => $apply), + ), + gtkpack(Gtk2::HBox->new(1,0), + gtknew('Label_Left', text => N("Netmask")), + gtksignal_connect($gui->{intf}{NETMASK} = Gtk2::Entry->new, + key_press_event => $apply), + ), + if_($is_ethernet, + gtkpack(Gtk2::HBox->new(1,0), + gtknew('Label_Left', text => N("Gateway")), + gtksignal_connect($gui->{network}{GATEWAY} = Gtk2::Entry->new, + key_press_event => $apply), + ), + ), + gtknew('Title2', label => N("DNS servers")), + gtknew('Label_Left', text => join(', ', grep { $_ } $intf->{dns1} || $net->{resolv}{dnsServer}, + $intf->{dns2} || $net->{resolv}{dnsServer2}, + $intf->{dns3} || $net->{resolv}{dnsServer3}), + ), + gtkpack(Gtk2::HBox->new(1,0), + gtknew('Label_Left', text => N("Search Domain")), + my $w2 = gtknew('Label_Left', text => $intf->{domain} || $net->{resolv}{DOMAINNAME} || 'none'), + ), + ); + $size_group->add_widget($_) foreach $w2, $gui->{intf}{BOOTPROTO}, $gui->{intf}{IPADDR}, $gui->{intf}{NETMASK}, $gui->{network}{GATEWAY}; + + if ($is_ethernet) { + my $proto = $gui->{intf}{BOOTPROTO}; + $proto->{protocols} = { none => N("none"), static => N("static"), dhcp => N("DHCP") }; + $proto->set_popdown_strings(values %{$proto->{protocols}}); + $proto->set_text($proto->{protocols}{$intf->{BOOTPROTO} || 'none'}); + if ($intf->{BOOTPROTO} ne 'static') { + $_->set_sensitive(0) foreach $gui->{intf}{IPADDR}, $gui->{intf}{NETMASK}, $gui->{network}{GATEWAY}; + } + } else { + $_->set_sensitive(0) foreach $gui->{intf}{IPADDR}, $gui->{intf}{NETMASK}, $gui->{network}{GATEWAY}; + delete $gui->{intf}{BOOTPROTO}; + } + !$intf->{IPADDR} and ($intf->{IPADDR}, $gui->{active}, $intf->{NETMASK}) = network::drakconnect::get_intf_ip($net, $interface_name); + $gui->{network}{$_}->set_text($net->{network}{$_}) foreach keys %{$gui->{network}}; + } + + if ($intf->{pages}{DHCP}) { + gtkpack(gtkset_border_width($gui->{sheet}{DHCP} = Gtk2::HBox->new(0,10), 5), + gtkpack__(gtkset_border_width(Gtk2::VBox->new(0,10), 5), + gtkpack__(Gtk2::HBox->new(1,0), + gtknew('Label_Left', text => N("DHCP client")), + gtksignal_connect($gui->{intf}{DHCP_CLIENT} = Gtk2::ComboBox->new_with_strings(\@network::connection::ethernet::dhcp_clients, + $intf->{DHCP_CLIENT} || $network::connection::ethernet::dhcp_clients[0]), + changed => $apply)), + gtksignal_connect($gui->{intf_bool}{NEEDHOSTNAME} = Gtk2::CheckButton->new(N("Assign host name from DHCP server (or generate a unique one)")), toggled => $apply), + gtkpack__(Gtk2::HBox->new(1,0), + gtknew('Label_Left', text => N("DHCP host name")), + gtksignal_connect($gui->{intf}{DHCP_HOSTNAME} = Gtk2::Entry->new, + key_press_event => $apply)), + gtkpack__(Gtk2::HBox->new(1,0), + gtknew('Label_Left', text => N("DHCP timeout (in seconds)")), + gtksignal_connect($gui->{intf}{DHCP_TIMEOUT} = Gtk2::Entry->new, + key_press_event => $apply)), + gtksignal_connect($gui->{intf_bool}{PEERDNS} = Gtk2::CheckButton->new(N("Get DNS servers from DHCP")), toggled => $apply), + gtksignal_connect($gui->{intf_bool}{PEERYP} = Gtk2::CheckButton->new(N("Get YP servers from DHCP")), toggled => $apply), + gtksignal_connect($gui->{intf_bool}{PEERNTPD} = Gtk2::CheckButton->new(N("Get NTPD servers from DHCP")), toggled => $apply), + ), + ); + foreach (qw(NEEDHOSTNAME PEERDNS)) { #- default these settings to yes + defined $intf->{$_} or $intf->{$_} = "yes"; + } + $gui->{intf}{$_}->set_text($intf->{$_}) foreach qw(DHCP_HOSTNAME DHCP_TIMEOUT); + $gui->{intf_bool}{$_}->set_active(text2bool($intf->{$_})) foreach qw(NEEDHOSTNAME PEERDNS PEERYP PEERNTPD); + $gui->{intf}{DHCP_CLIENT}->set_text($intf->{DHCP_CLIENT}); + $gui->{sheet}{DHCP}->set_sensitive($intf->{BOOTPROTO} eq 'dhcp'); + } + my $size_group2 = Gtk2::SizeGroup->new('horizontal'); + $size_group2->add_widget($_) foreach $gui->{intf}{DHCP_HOSTNAME}, $gui->{intf}{DHCP_TIMEOUT}, $gui->{intf}{DHCP_CLIENT}; + + if ($intf->{pages}{Wireless}) { + gtkpack(gtkset_border_width($gui->{sheet}{Wireless} = Gtk2::HBox->new(0,10), 5), + gtkpack_(Gtk2::VBox->new(0,0), + map { (0, gtkpack_(Gtk2::VBox->new(0,0), + 1, Gtk2::Label->new($_->[0]), + 0, gtksignal_connect($gui->{intf}{$_->[1]} = Gtk2::Entry->new, + key_press_event => $apply), + )); + } ([ N("Operating Mode"), "WIRELESS_MODE" ], + [ N("Network name (ESSID)"), "WIRELESS_ESSID" ], + [ N("Network ID"), "WIRELESS_NWID" ], + [ N("Operating frequency"), "WIRELESS_FREQ" ], + [ N("Sensitivity threshold"), "WIRELESS_SENS" ], + [ N("Bitrate (in b/s)"), "WIRELESS_RATE" ] + ), + ), + Gtk2::VSeparator->new, + gtkpack_(Gtk2::VBox->new(0,0), + map { (0, gtkpack_(Gtk2::VBox->new(0,0), + 1, Gtk2::Label->new($_->[0]), + 0, gtksignal_connect($gui->{intf}{$_->[1]} = Gtk2::Entry->new, + key_press_event => $apply), + )); + } ([ N("Encryption key"), 'WIRELESS_ENC_KEY' ], + [ N("RTS/CTS"), 'WIRELESS_RTS' ], + [ N("Fragmentation"), 'WIRELESS_FRAG' ], + [ N("iwconfig command extra arguments"), 'WIRELESS_IWCONFIG' ], + [ N("iwspy command extra arguments"), 'WIRELESS_IWSPY' ], + [ N("iwpriv command extra arguments"), 'WIRELESS_IWPRIV' ], + ), + ), + ); + } + + if ($intf->{pages}{Options}) { + gtkpack__(gtkset_border_width($gui->{sheet}{Options} = Gtk2::VBox->new(0,10), 5), + $gui->{intf_bool}{ONBOOT} = gtksignal_connect(Gtk2::CheckButton->new(N("Start at boot")), + toggled => $apply), + if_($is_ethernet, + map { ($gui->{intf_bool}{$_->[0]} = gtksignal_connect(Gtk2::CheckButton->new($_->[1]), + toggled => $apply)); + } ( + [ "MII_NOT_SUPPORTED", N("Network Hotplugging") ], + ), + ), + if_($interface eq 'isdn', + gtkpack(Gtk2::HBox->new(0,0), + gtkpack__(Gtk2::VBox->new(0,0), + Gtk2::Label->new(N("Dialing mode")), + my @dialing_mode_radio = gtkradio(("auto") x 2, "manual"), + ), + Gtk2::VSeparator->new, + gtkpack__(Gtk2::VBox->new(0,0), + Gtk2::Label->new(N("Connection speed")), + my @speed_radio = gtkradio(("64 Kb/s") x 2, "128 Kb/s"), + ), + ), + gtkpack__(Gtk2::HBox->new(0,5), + Gtk2::Label->new(N("Connection timeout (in sec)")), + gtksignal_connect($gui->{intf}{huptimeout} = Gtk2::Entry->new, + key_press_event => $apply), + ), + ), + gtkpack__(Gtk2::HBox->new(0,1), + gtknew('Label_Left', text => N("Metric")), + gtksignal_connect(gtkset_text($gui->{intf}{METRIC} = Gtk2::Entry->new, $intf->{METRIC}), + key_press_event => $apply)), + + ); + $dialing_mode_radio[0]->signal_connect(toggled => sub { $gui->{intf_radio}{dialing_mode} = 'auto'; $apply->() }); + $dialing_mode_radio[1]->signal_connect(toggled => sub { $gui->{intf_radio}{dialing_mode} = 'static'; $apply->() }); + $speed_radio[0]->signal_connect(toggled => sub { $gui->{intf_radio}{speed} = '64'; $apply->() }); + $speed_radio[1]->signal_connect(toggled => sub { $gui->{intf_radio}{speed} = '128'; $apply->() }); + $gui->{intf_bool}{ONBOOT}->set_active($intf->{ONBOOT} eq 'yes' ? 1 : 0); + $gui->{intf_bool}{MII_NOT_SUPPORTED}->set_active($intf->{MII_NOT_SUPPORTED} eq 'no' ? 1 : 0); + } + + if ($intf->{pages}{Account}) { + if ($interface_name =~ /^speedtouch|sagem$/) { + $gui->{description} = $interface_name eq 'speedtouch' ? 'Alcatel|USB ADSL Modem (Speed Touch)' : 'Analog Devices Inc.|USB ADSL modem'; + } + gtkpack_(gtkset_border_width($gui->{sheet}{Account} = Gtk2::VBox->new(0,10), 5), + if_($interface eq 'modem', + 0, gtkpack(Gtk2::VBox->new(1,0), + gtkpack__(Gtk2::HBox->new, Gtk2::Label->new(N("Authentication"))), + gtkpack__(Gtk2::HBox->new, $gui->{intf}{auth} = gtksignal_connect(Gtk2::ComboBox->new_text, + changed => $apply)), + )), + map { (0, gtkpack(Gtk2::VBox->new(1,0), + gtkpack__(Gtk2::HBox->new, Gtk2::Label->new($_->[0])), + gtkpack__(Gtk2::HBox->new, $gui->{intf}{$_->[1]} = gtksignal_connect(Gtk2::Entry->new, + key_press_event => $apply)), + ), + ); + } ([ N("Account Login (user name)"), 'login' ], + [ N("Account Password"), 'passwd' ], + if_($interface =~ /^(isdn|modem)$/, [ N("Provider phone number"), $1 eq 'modem' ? 'phone' : 'phone_out' ]), + ), + ); + + if ($interface eq 'modem') { + my %auth_methods = map_index { $::i => $_ } N("PAP"), N("Terminal-based"), N("Script-based"), N("CHAP"), N("PAP/CHAP"); + $gui->{intf}{auth}->set_popdown_strings(sort values %auth_methods); + $gui->{intf}{auth}->set_text($auth_methods{$intf->{Authentication}}); + } + $gui->{intf}{passwd}->set_visibility(0); + } + + if ($intf->{pages}{Modem}) { + gtkpack(gtkset_border_width($gui->{sheet}{Modem} = Gtk2::HBox->new(0,10), 5), + if_($interface eq 'modem', + gtkpack__(Gtk2::VBox->new(0,5), + (map { (gtkpack(Gtk2::VBox->new(1,0), + gtkpack__(Gtk2::HBox->new, Gtk2::Label->new($_->[0])), + gtkpack__(Gtk2::HBox->new, $gui->{intf}{$_->[1]} = gtksignal_connect(Gtk2::ComboBox->new_text, + changed => $apply)), + ), + ); + } ([ N("Flow control"), 'FlowControl' ], + [ N("Line termination"), 'Enter' ], + [ N("Connection speed"), 'Speed' ], + )), + # gtkpack(Gtk2::VBox->new(0,0), # no relative kppp option found :-( + # Gtk2::Label->new(N("Dialing mode")), + # gtkradio('', N("Tone dialing"), N("Pulse dialing")), + # ), + ), + Gtk2::VSeparator->new, + gtkpack__(Gtk2::VBox->new(0,10), + gtkpack__(Gtk2::HBox->new(0,5), + Gtk2::Label->new(N("Modem timeout")), + $gui->{intf}{Timeout} = gtksignal_connect(Gtk2::SpinButton->new(Gtk2::Adjustment->new($intf->{Timeout}, 0, 120, 1, 5, 0), 0, 0), + value_changed => $apply), + ), + gtksignal_connect($gui->{intf_bool}{UseLockFile} = Gtk2::CheckButton->new(N("Use lock file")), + toggled => $apply), + gtkpack__(Gtk2::HBox->new, gtksignal_connect($gui->{intf_bool}{WaitForDialTone} = Gtk2::CheckButton->new(N("Wait for dialup tone before dialing")), + toggled => $apply)), + gtkpack__(Gtk2::HBox->new(0,5), + Gtk2::Label->new(N("Busy wait")), + $gui->{intf}{BusyWait} = gtksignal_connect(Gtk2::SpinButton->new(Gtk2::Adjustment->new($intf->{BusyWait}, 0, 120, 1, 5, 0), 0, 0), + value_changed => $apply), + ), + gtkpack__(Gtk2::HBox->new(0,5), + Gtk2::Label->new(N("Modem sound")), + gtkpack__(Gtk2::VBox->new(0,5), my @volume_radio = gtkradio('', N("Enable"), N("Disable"))), + ), + ), + ), + if_($interface eq 'isdn', + gtkpack_(Gtk2::VBox->new(0,0), + map { (0, gtkpack(Gtk2::VBox->new(1,0), + gtkpack__(Gtk2::HBox->new, Gtk2::Label->new($_->[0])), + gtkpack__(Gtk2::HBox->new, $gui->{intf}{$_->[1]} = gtksignal_connect(Gtk2::Entry->new, + key_press_event => $apply)), + ), + ); + } ([ N("Card IRQ"), 'irq' ], + [ N("Card mem (DMA)"), 'mem' ], + [ N("Card IO"), 'io' ], + [ N("Card IO_0"), 'io0' ], + ), + ), + Gtk2::VSeparator->new, + gtkpack__(Gtk2::VBox->new(0,0), + Gtk2::Label->new(N("Protocol")), + my @protocol_radio = gtkradio('', N("European protocol (EDSS1)"), + N("Protocol for the rest of the world\nNo D-Channel (leased lines)")), + ), + ), + ); + $protocol_radio[0]->signal_connect(toggled => sub { $gui->{intf_radio}{protocol} = 2; $apply->() }); + $protocol_radio[1]->signal_connect(toggled => sub { $gui->{intf_radio}{protocol} = 3; $apply->() }); + $volume_radio[0]->signal_connect(toggled => sub { $gui->{intf_radio}{Volume} = 1; $apply->() }); + $volume_radio[1]->signal_connect(toggled => sub { $gui->{intf_radio}{Volume} = 0; $apply->() }); + $gui->{intf}{FlowControl}->set_popdown_strings('Hardware [CRTSCTS]', 'Software [XON/XOFF]', 'None'); + $gui->{intf}{Enter}->set_popdown_strings('CR', 'CF', 'CR/LF'); + $gui->{intf}{Speed}->set_popdown_strings('2400', '9600', '19200', '38400', '57600', '115200'); + } + + if ($intf->{pages}{Information}) { + my ($info) = $gui->{description} ? + find { $_->{description} eq $gui->{description} } detect_devices::probeall : network::connection::ethernet::mapIntfToDevice($interface_name); + my @intfs = grep { $interface_name eq $_->[0] } @$all_cards; + if (is_empty_hash_ref($info) && @intfs == 1) { + my $driver = $intfs[0][1]; + my @cards = grep { $_->{driver} eq $driver } detect_devices::probeall(); + @cards == 1 and $info = $cards[0]; + } + + gtkpack(gtkset_border_width($gui->{sheet}{Information} = Gtk2::VBox->new(0,10), 5), + gtktext_insert(Gtk2::TextView->new, + join('', + map { $_->[0] . ": \x{200e}" . $_->[1] . "\n" } ( + [ N("Vendor"), split('\|', $info->{description}) ], + [ N("Description"), reverse split('\|', $info->{description}) ], + [ N("Media class"), $info->{media_type} || '-' ], + [ N("Module name"), $info->{driver} || '-' ], + [ N("Mac Address"), c::get_hw_address($interface_name) || '-' ], + [ N("Bus"), $info->{bus} || '-' ], + [ N("Location on the bus"), $info->{pci_bus} || '-' ], + ) + ) + ), + ); + } + + foreach (keys %{$gui->{intf}}) { + next if ref($gui->{intf}{$_}) !~ /Gtk2::(ComboBox|Entry)/; + # skip unset fields: + next if !$intf->{$_}; + # special case b/c of translation: + next if member($_, qw(BOOTPROTO )); + if ($_ eq "FlowControl") { + # kppp is writing translated strings :-( (eg: s/Software/Logiciel/): + # (let's hope that all translations use 'CRTSCTS' and 'XON/OFF' as substring) + $gui->{intf}{$_}->set_text('Hardware [CRTSCTS]') if $intf->{$_} =~ /CRTSCTS/; + $gui->{intf}{$_}->set_text('Software [XON/XOFF]') if $intf->{$_} =~ m!XON/XOFF!; + } else { + $gui->{intf}{$_}->set_text($intf->{$_}); + } + } + + $gui->{notebook} = Gtk2::Notebook->new; + populate_notebook($gui->{notebook}, $gui); +} + +sub populate_notebook { + my ($notebook, $gui) = @_; + foreach ('TCP/IP', 'DHCP', 'Account', 'Wireless', 'Modem', 'Options', 'Information') { + !$gui->{sheet}{$_} and next; + $notebook->append_page($gui->{sheet}{$_}, Gtk2::Label->new(translate($_))); + } +} + +sub save { + my ($in, $net, $modules_conf, $p, $apply_button) = @_; + + my $dialog = _create_dialog(N("Please wait")); + gtkpack($dialog->vbox, + gtkshow(Gtk2::Label->new(N("Please Wait... Applying the configuration")))); + $dialog->show_all; + gtkset_mousecursor_wait(); + + Glib::Timeout->add(200, sub { + gtkflush(); + delete $net->{network}{GATEWAY}; + foreach (keys %$p) { + save_notebook($in, $net, $p->{$_}{intf}, $p->{$_}{gui}) or return; + $p->{$_}{intf}{save} and $p->{$_}{intf}{save}->(); + } + network::drakconnect::apply($in, $net, $modules_conf); + system("/etc/rc.d/init.d/network restart"); + $dialog->response(0); + }); + $dialog->run; + + $apply_button->set_sensitive(0); + gtkset_mousecursor_normal(); + $dialog->destroy; +} + +sub save_notebook { + my ($in, $net, $intf, $gui) = @_; + + if ($gui->{network}{GATEWAY}->is_sensitive && $gui->{network}{GATEWAY}->get_text) { + $net->{network}{GATEWAY} = $gui->{network}{GATEWAY}->get_text; + } + $gui->{intf}{$_} and $intf->{$_} = $gui->{intf}{$_}->get_text foreach keys %{$gui->{intf}}; + $gui->{intf_radio}{$_} and $intf->{$_} = $gui->{intf_radio}{$_} foreach keys %{$gui->{intf_radio}}; + $intf->{$_} = bool2yesno($gui->{intf_bool}{$_}->get_active) foreach keys %{$gui->{intf_bool}}; + $gui->{intf_bool}{MII_NOT_SUPPORTED} and $intf->{MII_NOT_SUPPORTED} = bool2yesno(!$gui->{intf_bool}{MII_NOT_SUPPORTED}->get_active); + + if (my $proto = $gui->{intf}{BOOTPROTO}) { + $intf->{BOOTPROTO} = { reverse %{$proto->{protocols}} }->{$proto->get_text}; + } + if ($intf->{BOOTPROTO} eq 'static') { + if (!is_ip($intf->{IPADDR})) { + $in->ask_warn(N("Error"), N("IP address should be in format 1.2.3.4")); + return 0; + } + if (!is_ip($intf->{NETMASK})) { + $in->ask_warn(N("Error"), N("Netmask should be in format 255.255.224.0")); + return 0; + } + } + + delete $intf->{IPADDR} if $intf->{IPADDR} eq N("No IP"); + delete $intf->{NETMASK} if $intf->{NETMASK} eq N("No Mask"); + + if ($net->{network}{GATEWAY} && !is_ip($net->{network}{GATEWAY})) { + $in->ask_warn(N("Error"), N("Gateway address should be in format 1.2.3.4")); + return 0; + } + 1; +} + +1; diff --git a/lib/network/drakconnect/global.pm b/lib/network/drakconnect/global.pm new file mode 100644 index 0000000..59da73c --- /dev/null +++ b/lib/network/drakconnect/global.pm @@ -0,0 +1,107 @@ +package network::drakconnect::global; + +use ugtk2 qw(:create :dialogs :helpers :wrappers); +use mygtk2 qw(gtknew); +use common; +use network::drakconnect; +use network::test; + +my $net_test; +sub update_network_status { + my ($int_state) = @_; + unless ($net_test) { + $net_test = network::test->new; + $net_test->start; + } + if ($net_test->is_done) { + my $isconnected = $net_test->is_connected; + $int_state->set($isconnected ? N("Connected") : N("Not connected")); + $net_test->start; + } + 1; +} + +sub configure_net { + my ($in, $net, $modules_conf) = @_; + my $int_state; + my $int_label = Gtk2::WrappedLabel->new($net->{type} eq 'lan' ? N("Gateway:") : N("Interface:")); + my $int_name = Gtk2::Label->new($net->{type} eq 'lan' ? $net->{network}{GATEWAY} : $net->{net_interface}); + + my $dialog = ugtk2->new(N("Internet connection configuration")); + my $exit_dialogsub = sub { Gtk2->main_quit }; + if (!$net->{type}) { + $in->ask_warn( + N("Warning"), + N("You do not have any configured Internet connection. +Run the \"%s\" assistant from the Mageia Control Center", N("Set up a new network interface (LAN, ISDN, ADSL, ...)"))); + return; + } + unless ($::isEmbedded) { + $dialog->{rwindow}->set_position('center'); + $dialog->{rwindow}->set_size_request(-1, -1); + $dialog->{rwindow}->set_icon(gtkcreate_pixbuf("drakconnect")); + } + $dialog->{rwindow}->signal_connect(delete_event => $exit_dialogsub); + + my $param_vbox = Gtk2::VBox->new(0,0); + my $i = 0; + + my @conf_data = ( + [ N("Host name (optional)"), \$net->{network}{HOSTNAME} ], + [ N("First DNS Server (optional)"), \$net->{resolv}{dnsServer} ], + [ N("Second DNS Server (optional)"), \$net->{resolv}{dnsServer2} ], + [ N("Third DNS server (optional)"), \$net->{resolv}{dnsServer3} ], + ); + my @infos; + gtkpack($param_vbox, + create_packtable({}, + map { + my $c; + if (defined $_->[2]) { + $c = Gtk2::Combo->new; + $c->set_popdown_strings(@{$_->[2]}); + $infos[2*$i+1] = $c->entry; + } else { + $c = $infos[2*$i+1] = Gtk2::Entry->new; + } + $infos[2*$i+1]->set_text(${$_->[1]}); + $i++; + [ Gtk2::WrappedLabel->new($_->[0]), $c ]; + } @conf_data + ) + ); + + $dialog->{rwindow}->add(gtkpack_(Gtk2::VBox->new, + 0, Gtk2::Label->new(N("Internet Connection Configuration")), + 1, gtkadd(gtkcreate_frame(N("Internet access")), + gtkset_border_width(create_packtable({ col_spacings => 5, row_spacings => 5, homogenous => 1 }, + [ Gtk2::WrappedLabel->new(N("Connection type: ")), + Gtk2::WrappedLabel->new(translate($net->{type})) ], + [ $int_label, $int_name ], + [ Gtk2::WrappedLabel->new(N("Status:")), + $int_state = Gtk2::WrappedLabel->new(N("Testing your connection...")) ] + ), + 5), + ), + 1, gtkadd(gtkcreate_frame(N("Parameters")), gtkset_border_width($param_vbox, 5)), + 0, gtkpack(create_hbox('edge'), + gtksignal_connect(Gtk2::Button->new(N("Cancel")), clicked => $exit_dialogsub), + gtksignal_connect(Gtk2::Button->new(N("Ok")), clicked => sub { + foreach my $i (0..$#conf_data) { + ${$conf_data[$i][1]} = $infos[2*$i+1]->get_text; + } + network::drakconnect::apply($in, $net, $modules_conf); + $exit_dialogsub->(); + }), + ), + ), + ); + + $dialog->{rwindow}->show_all; + my $update = sub { update_network_status($int_state) }; + $update->(); + Glib::Timeout->add(2000, $update); + $dialog->main; +} + +1; diff --git a/lib/network/drakfirewall.pm b/lib/network/drakfirewall.pm new file mode 100644 index 0000000..f22ecfe --- /dev/null +++ b/lib/network/drakfirewall.pm @@ -0,0 +1,370 @@ +package network::drakfirewall; # $Id: drakfirewall.pm 268043 2010-04-30 13:29:37Z blino $ + +use strict; +use diagnostics; + +use network::shorewall; +use common; +use network::nfs; +use network::network; + +my @all_servers = +( + { + name => N_("Web Server"), + pkg => 'apache apache-mod_perl boa lighttpd thttpd', + ports => '80/tcp 443/tcp', + }, + { + name => N_("Domain Name Server"), + pkg => 'bind dnsmasq mydsn', + ports => '53/tcp 53/udp', + }, + { + name => N_("SSH server"), + pkg => 'openssh-server', + ports => '22/tcp', + }, + { + name => N_("FTP server"), + pkg => 'ftp-server-krb5 wu-ftpd proftpd pure-ftpd', + ports => '20/tcp 21/tcp', + }, + { + name => N_("DHCP Server"), + pkg => 'dhcp-server udhcpd', + ports => '67/udp 68/udp', + hide => 1, + }, + { + name => N_("Mail Server"), + pkg => 'sendmail postfix qmail exim', + ports => '25/tcp', + }, + { + name => N_("POP and IMAP Server"), + pkg => 'imap courier-imap-pop', + ports => '109/tcp 110/tcp 143/tcp', + }, + { + name => N_("Telnet server"), + pkg => 'telnet-server-krb5', + ports => '23/tcp', + hide => 1, + }, + { + name => N_("NFS Server"), + pkg => 'nfs-utils nfs-utils-clients', + ports => '111/tcp 111/udp 2049/tcp 2049/udp ' . network::nfs::list_nfs_ports(), + hide => 1, + prepare => sub { network::nfs::write_nfs_ports(network::nfs::read_nfs_ports()); }, + restart => 'nfs-common nfs-server', + }, + { + name => N_("Windows Files Sharing (SMB)"), + pkg => 'samba-server', + ports => '137/tcp 137/udp 138/tcp 138/udp 139/tcp 139/udp 445/tcp 445/udp 1024:1100/tcp 1024:1100/udp', + hide => 1, + }, + { + name => N_("Bacula backup"), + pkg => 'bacula-fd bacula-sd bacula-dir-common', + ports => '9101:9103/tcp', + hide => 1, + }, + { + name => N_("Syslog network logging"), + pkg => 'rsyslog syslog-ng', + ports => '514/udp', + hide => 1, + }, + { + name => N_("CUPS server"), + pkg => 'cups', + ports => '631/tcp 631/udp', + hide => 1, + }, + { + name => N_("MySQL server"), + pkg => 'mysql', + ports => '3306/tcp 3306/udp', + hide => 1, + }, + { + name => N_("PostgreSQL server"), + pkg => 'postgresql8.2 postgresql8.3', + ports => '5432/tcp 5432/udp', + hide => 1, + }, + { + name => N_("Echo request (ping)"), + ports => '8/icmp', + force_default_selection => 0, + }, + { + name => N_("Network services autodiscovery (zeroconf and slp)"), + ports => '5353/udp 427/udp', + pkg => 'avahi cups openslp', + }, + { + name => N_("BitTorrent"), + ports => '6881:6999/tcp', + hide => 1, + pkg => 'bittorrent deluge ktorrent transmission vuze rtorrent ctorrent', + }, + { + name => N_("Windows Mobile device synchronization"), + pkg => 'synce-hal', + ports => '990/tcp 999/tcp 5678/tcp 5679/udp 26675/tcp', + hide => 1, + }, +); + +my @ifw_rules = ( + { + name => N_("Port scan detection"), + ifw_rule => 'psd', + }, +); + +# global network configuration +my $net = {}; +network::network::read_net_conf($net); + +sub port2server { + my ($port) = @_; + find { + any { $port eq $_ } split(' ', $_->{ports}); + } @all_servers; +} + +sub check_ports_syntax { + my ($ports) = @_; + foreach (split ' ', $ports) { + my ($nb, $range, $nb2) = m!^(\d+)(:(\d+))?/(tcp|udp|icmp)$! or return $_; + foreach my $port ($nb, if_($range, $nb2)) { + 1 <= $port && $port <= 65535 or return $_; + } + $nb < $nb2 or return $_ if $range; + } + ''; +} + +sub to_ports { + my ($servers, $unlisted) = @_; + join(' ', (map { $_->{ports} } @$servers), if_($unlisted, $unlisted)); +} + +sub from_ports { + my ($ports) = @_; + + my @l; + my @unlisted; + foreach (split ' ', $ports) { + if (my $s = port2server($_)) { + push @l, $s; + } else { + push @unlisted, $_; + } + } + [ uniq(@l) ], join(' ', @unlisted); +} + +sub default_from_pkgs { + my ($do_pkgs) = @_; + my @pkgs = $do_pkgs->are_installed(map { split ' ', $_->{pkg} } @all_servers); + [ grep { + my $s = $_; + exists $s->{force_default_selection} ? + $s->{force_default_selection} : + any { member($_, @pkgs) } split(' ', $s->{pkg}); + } @all_servers ]; +} + +sub default_ports { + my ($do_pkgs) = @_; + to_ports(default_from_pkgs($do_pkgs), ''); +} + +sub get_ports() { + my $shorewall = network::shorewall::read() or return; + $shorewall->{ports}; +} + +sub set_ports { + my ($do_pkgs, $disabled, $ports, $log_net_drop, $o_in) = @_; + + if (!$disabled || -x "$::prefix/sbin/shorewall") { + $do_pkgs->ensure_binary_is_installed('shorewall', 'shorewall', $::isInstall) or return; + my $shorewall = network::shorewall::read(!$disabled && $o_in); + if (!$shorewall) { + log::l("unable to read shorewall configuration, skipping installation"); + return; + } + + $shorewall->{disabled} = $disabled; + $shorewall->{ports} = $ports; + $shorewall->{log_net_drop} = $log_net_drop; + log::l($disabled ? "disabling shorewall" : "configuring shorewall to allow ports: $ports"); + network::shorewall::write($shorewall, $o_in); + } +} + +sub get_conf { + my ($in, $disabled, $o_ports) = @_; + + my $possible_servers = default_from_pkgs($in->do_pkgs); + $_->{hide} = 0 foreach @$possible_servers; + + if ($o_ports) { + $disabled, from_ports($o_ports); + } elsif (my $shorewall = network::shorewall::read()) { + $shorewall->{disabled}, from_ports($shorewall->{ports}), $shorewall->{log_net_drop}; + } else { + $in->ask_okcancel(N("Firewall configuration"), N("drakfirewall configurator + +This configures a personal firewall for this Mageia machine."), 1) or return; + + $in->ask_okcancel(N("Firewall configuration"), N("drakfirewall configurator + +Make sure you have configured your Network/Internet access with +drakconnect before going any further."), 1) or return; + + $disabled, $possible_servers, ''; + } +} + +sub choose_allowed_services { + my ($in, $disabled, $servers, $unlisted, $log_net_drop) = @_; + + $_->{on} = 0 foreach @all_servers; + $_->{on} = 1 foreach @$servers; + my @l = grep { $_->{on} || !$_->{hide} } @all_servers; + + $in->ask_from_({ + title => N("Firewall"), + icon => $network::shorewall::firewall_icon, + if_(!$::isEmbedded, banner_title => N("Firewall")), + advanced_messages => N("You can enter miscellaneous ports. +Valid examples are: 139/tcp 139/udp 600:610/tcp 600:610/udp. +Have a look at /etc/services for information."), + callbacks => { + complete => sub { + if (my $invalid_port = check_ports_syntax($unlisted)) { + $in->ask_warn('', N("Invalid port given: %s. +The proper format is \"port/tcp\" or \"port/udp\", +where port is between 1 and 65535. + +You can also give a range of ports (eg: 24300:24350/udp)", $invalid_port)); + return 1; + } + }, + } }, + [ + { label => N("Which services would you like to allow the Internet to connect to?"), title => 1 }, + if_($net->{PROFILE} && network::network::netprofile_count() > 0, { label => N("Those settings will be saved for the network profile <b>%s</b>", $net->{PROFILE}) }), + { text => N("Everything (no firewall)"), val => \$disabled, type => 'bool' }, + (map { { text => translate($_->{name}), val => \$_->{on}, type => 'bool', disabled => sub { $disabled } } } @l), + { label => N("Other ports"), val => \$unlisted, advanced => 1, disabled => sub { $disabled } }, + { text => N("Log firewall messages in system logs"), val => \$log_net_drop, type => 'bool', advanced => 1, disabled => sub { $disabled } }, + ]) or return; + + $disabled, [ grep { $_->{on} } @l ], $unlisted, $log_net_drop; +} + +sub set_ifw { + my ($do_pkgs, $enabled, $rules, $ports) = @_; + if ($enabled) { + $do_pkgs->ensure_is_installed('mandi-ifw', '/etc/ifw/start', $::isInstall) or return; + + my $ports_by_proto = network::shorewall::ports_by_proto($ports); + output_with_perm("$::prefix/etc/ifw/rules", 0644, + (map { "source /etc/ifw/rules.d/$_\n" } @$rules), + map { + my $proto = $_; + map { + my $multiport = /:/ && " -m multiport"; + "iptables -A Ifw -m state --state NEW -p $proto$multiport --dport $_ -j IFWLOG --log-prefix NEW\n"; + } @{$ports_by_proto->{$proto}}; + } intersection([ qw(tcp udp) ], [ keys %$ports_by_proto ]), + ); + } + + substInFile { + undef $_ if $_ eq "INCLUDE /etc/ifw/rules", "iptables -I INPUT 2 -j Ifw"; + } "$::prefix/etc/shorewall/start"; + network::shorewall::set_in_file('start', $enabled, "INCLUDE /etc/ifw/start", "INCLUDE /etc/ifw/rules", "iptables -I INPUT 1 -j Ifw"); + network::shorewall::set_in_file('stop', $enabled, "iptables -D INPUT -j Ifw", "INCLUDE /etc/ifw/stop"); +} + +sub choose_watched_services { + my ($in, $servers, $unlisted) = @_; + + my @l = (@ifw_rules, @$servers, map { { ports => $_ } } split(' ', $unlisted)); + my $enabled = 1; + $_->{ifw} = 1 foreach @l; + + $in->ask_from_({ + icon => $network::shorewall::firewall_icon, + if_(!$::isEmbedded, banner_title => N("Interactive Firewall")), + messages => + N("You can be warned when someone accesses to a service or tries to intrude into your computer. +Please select which network activities should be watched."), + title => N("Interactive Firewall"), + }, + [ + { text => N("Use Interactive Firewall"), val => \$enabled, type => 'bool' }, + map { { + text => (exists $_->{name} ? translate($_->{name}) : $_->{ports}), + val => \$_->{ifw}, + type => 'bool', disabled => sub { !$enabled }, + } } @l, + ]) or return; + my ($rules, $ports) = partition { exists $_->{ifw_rule} } grep { $_->{ifw} } @l; + set_ifw($in->do_pkgs, $enabled, [ map { $_->{ifw_rule} } @$rules ], to_ports($ports)); + + # return something to say that we are done ok + $rules, $ports; +} + +sub main { + my ($in, $disabled) = @_; + + ($disabled, my $servers, my $unlisted, my $log_net_drop) = get_conf($in, $disabled) or return; + + ($disabled, $servers, $unlisted, $log_net_drop) = choose_allowed_services($in, $disabled, $servers, $unlisted, $log_net_drop) or return; + + my $system_file = '/etc/sysconfig/drakx-net'; + my %global_settings = getVarsFromSh($system_file); + + if (!$disabled && (!defined($global_settings{IFW}) || text2bool($global_settings{IFW}))) { + choose_watched_services($in, $servers, $unlisted) or return; + } + + # preparing services when required + foreach (@$servers) { + exists $_->{prepare} and $_->{prepare}(); + } + + my $ports = to_ports($servers, $unlisted); + + set_ports($in->do_pkgs, $disabled, $ports, $log_net_drop, $in) or return; + + # restart mandi + require services; + services::is_service_running("mandi") and services::restart("mandi"); + + # restarting services if needed + foreach my $service (@$servers) { + if ($service->{restart}) { + services::is_service_running($_) and services::restart($_) foreach split(' ', $service->{restart}); + } + } + + # clearing pending ifw notifications in net_applet + system('killall -s SIGUSR1 net_applet'); + + ($disabled, $ports); +} + +1; diff --git a/lib/network/drakroam.pm b/lib/network/drakroam.pm new file mode 100755 index 0000000..9ff8189 --- /dev/null +++ b/lib/network/drakroam.pm @@ -0,0 +1,136 @@ +package network::drakroam; + +# drakroam: wireless network roaming GUI +# Austin Acton, 2004 <austin@mandriva.org> +# Olivier Blin, 2005-2006 <oblin@mandriva.com> +# Licensed under the GPL + +use strict; + +use common; +use interactive; +use mygtk2; +use ugtk2 qw(:create :helpers :wrappers); +use network::connection; +use network::connection_manager; +use network::connection::wireless; +use network::connection::cellular_card; + +sub update_connections_list { + my ($droam) = @_; + + $droam->{gui}{model}->set($droam->{gui}{model}->append, 0, $droam->{gui}{empty_pixbuf} , 1, N("No device found")) unless @{$droam->{all_connections}}; + $droam->{gui}{model}->set($droam->{gui}{model}->append, + 0, gtknew('Pixbuf', file => $_->get_type_icon)->scale_simple($droam->{gui}{pixbuf_size}, $droam->{gui}{pixbuf_size}, 'hyper'), + 1, $_->get_description) foreach @{$droam->{all_connections}}; + my $index = $droam->{connection} ? + eval { find_index { $_ == $droam->{connection} } @{$droam->{all_connections}} } + : 0; + $droam->{gui}{connections_combo}->set_active($index) if defined $index; +} + +sub get_connection { + my ($droam) = @_; + + @{$droam->{all_connections}} or return; + my $index = $droam->{gui}{connections_combo}->get_active; + defined $index && $droam->{all_connections}[$index]; +} + +sub select_connection { + my ($droam) = @_; + + $droam->set_connection(get_connection($droam)); + $droam->check_setup || $droam->setup_connection if $droam->{connection}; + update_on_connection_change($droam); +} + +sub update_on_connection_change { + my ($droam) = @_; + return if !($droam->{connection} && $droam->check_setup); + $droam->{gui}{buttons}{refresh}->set_sensitive(to_bool($droam->{connection})) + if $droam->{gui}{buttons}{refresh}; + $droam->update_networks; +} + +sub create_drakroam_gui { + my ($droam, $dbus, $title, $icon) = @_; + + $droam->{gui}{model} = Gtk2::ListStore->new('Gtk2::Gdk::Pixbuf', 'Glib::String'); + $droam->{gui}{connections_combo} = Gtk2::ComboBox->new($droam->{gui}{model}); + my $pix_r = Gtk2::CellRendererPixbuf->new; + $droam->{gui}{connections_combo}->pack_start($pix_r, 0,); + $droam->{gui}{connections_combo}->add_attribute($pix_r, pixbuf => 0); + my $text_r = Gtk2::CellRendererText->new; + $droam->{gui}{connections_combo}->pack_start($text_r, 1); + $droam->{gui}{connections_combo}->add_attribute($text_r, text => 1); + + $droam->{gui}{pixbuf_size} = 32; + $droam->{gui}{empty_pixbuf} = Gtk2::Gdk::Pixbuf->new('rgb', 1, 8, $droam->{gui}{pixbuf_size}, $droam->{gui}{pixbuf_size}); + $droam->{gui}{empty_pixbuf}->fill(0); + + my $status_bar = Gtk2::Statusbar->new; + my $status_bar_cid = $status_bar->get_context_id("Network event"); + $droam->{on_network_event} = sub { + my ($message) = @_; + my $m_id = $status_bar->push($status_bar_cid, $message); + Glib::Timeout->add(20000, sub { $status_bar->remove($status_bar_cid, $m_id); 0 }); + }; + + (undef, my $rootwin_height) = gtkroot()->get_size(); + my $scrolled_height = $rootwin_height > 480 ? 300 : 225; + gtkadd($droam->{gui}{w}{window}, + gtknew('VBox', spacing => 5, children => [ + $::isEmbedded ? () : (0, Gtk2::Banner->new($icon, $title)), + 0, gtknew('HBox', children_tight => [ gtknew('Label_Left', text => N("Device: "), alignment => [ 0.5, 0.5 ]), + gtksignal_connect($droam->{gui}{connections_combo}, changed => sub { select_connection($droam) }) ]), + 1, gtknew('ScrolledWindow', width => 500, height => $scrolled_height, child => $droam->{gui}{networks_list}), + 0, gtknew('HButtonBox', layout => 'edge', children_loose => [ + $droam->{gui}{buttons}{configure} = gtknew('Button', text => N("Configure"), clicked => sub { $droam->configure_connection }), + $droam->{gui}{buttons}{connect_start} = gtknew('Button', text => N("Connect"), relief => 'half', clicked => sub { $droam->start_connection }), + $droam->{gui}{buttons}{connect_stop} = gtknew('Button', text => N("Disconnect"), relief => 'half', clicked => sub { $droam->stop_connection }), + $droam->{gui}{buttons}{refresh} = gtknew('Button', text => N("Refresh"), clicked => sub { $droam->update_networks }), + gtknew('Button', text => N("Quit"), clicked => sub { Gtk2->main_quit }) + ]), + 0, $status_bar, + ]), + ); +} + +sub main { + my ($in, $net, $dbus, $o_interface, $o_ap) = @_; + + my $title = N("Wireless connection"); + my $icon = '/usr/share/mcc/themes/default/drakroam-mdk.png'; + + $ugtk2::wm_icon = $icon; + my $w = ugtk2->new($title); + #- so that transient_for is defined, for wait messages and popups to be centered + $::main_window = $w->{real_window}; + + my $pixbufs = network::connection_manager::create_pixbufs(); + my $droam = network::connection_manager->new($in, $net, $w, $pixbufs); + $droam->create_networks_list; + create_drakroam_gui($droam, $dbus, $title, $icon); + + $droam->{gui}{w}->show; + + my @connection_types = qw(network::connection::wireless network::connection::cellular_card); + @{$droam->{all_connections}} = map { $_->get_connections(automatic_only => 1) } @connection_types; + my $connection = $o_interface && find { $_->get_interface eq $o_interface } @{$droam->{all_connections}}; + $connection ||= find { !$_->network_scan_is_slow } @{$droam->{all_connections}}; + $droam->set_connection($connection) if $connection; + update_connections_list($droam); + update_on_connection_change($droam); + + network::connection_manager::setup_dbus_handlers([ $droam ], $droam->{all_connections}, $droam->{on_network_event}, $dbus) if $dbus; + + if ($o_ap && $droam->{connection}) { + $droam->{connection}{network} = $o_ap; + $droam->start_connection; + } + + $droam->{gui}{w}->main; +} + +1; diff --git a/lib/network/drakvpn.pm b/lib/network/drakvpn.pm new file mode 100644 index 0000000..c68127d --- /dev/null +++ b/lib/network/drakvpn.pm @@ -0,0 +1,120 @@ +package network::drakvpn; + +=head1 NAME + +network::drakvpn - Interactive VPN configuration + +=head1 SYNOPSIS + + use interactive; + use network::drakvpn; + + my $in = 'interactive'->vnew('su'); + network::drakvpn::create_connection($in); + +=cut + +use strict; +use common; + +use network::vpn; + +sub create_connection { + my ($in) = @_; + my $vpn_type; + my $vpn_connection; + my $new_name; + require wizards; + my $wiz = wizards->new({ + defaultimage => "drakvpn", + name => N("VPN configuration"), + pages => { + welcome => { + if_(!$::isInstall, no_back => 1), + name => N("Choose the VPN type"), + data => [ { + val => \$vpn_type, type => 'list', + list => [ sort { $a->get_description cmp $b->get_description } network::vpn::list_types ], + format => sub { $_[0] && $_[0]->get_description }, + allow_empty_list => 1, + } ], + complete => sub { + $vpn_type or return 1; + my @packages = $vpn_type->get_packages; + if (@packages && !$in->do_pkgs->install(@packages)) { + $in->ask_warn(N("Error"), N("Could not install the packages (%s)!", join(', ', @packages))); + return 1; + } + if ($vpn_type->can('prepare')) { + my $wait = $in->wait_message(N("Please wait"), N("Initializing tools and detecting devices for %s...", $vpn_type->get_type)); + if (!$vpn_type->prepare) { + undef $wait; + $in->ask_warn(N("Error"), N("Unable to initialize %s connection type!", $vpn_type->get_type)); + return 1; + } + } + }, + next => "vpn_name", + }, + vpn_name => { + name => N("Please select an existing VPN connection or enter a new name."), + data => sub { [ + { label => N("VPN connection"), val => \$vpn_connection, type => 'list', + list => [ $vpn_type->get_configured_connections, '' ], + format => sub { $_[0] ? $_[0]{name} : N("Configure a new connection...") }, + gtk => { use_boxradio => 1 } }, + { label => N("New name"), val => \$new_name, disabled => sub { $vpn_connection } }, + ] }, + complete => sub { + if (!$vpn_connection && !$new_name) { + $in->ask_warn(N("Warning"), N("You must select an existing connection or enter a new name.")); + 1; + } + }, + post => sub { + $vpn_connection ||= $vpn_type->new($new_name); + $vpn_connection->read_config; + $vpn_connection->can('get_key_settings') ? "vpn_key_settings" : "vpn_settings"; + }, + }, + vpn_key_settings => { + name => N("Please enter the required key(s)"), + data => sub { $vpn_connection->get_key_settings }, + next => "vpn_settings", + }, + vpn_settings => { + name => N("Please enter the settings of your VPN connection"), + data => sub { $vpn_connection->get_settings }, + post => sub { + $vpn_connection->write_config; + "connect"; + }, + }, + connect => { + name => N("Do you want to start the connection now?"), + type => "yesorno", + post => sub { + my ($connect) = @_; + if ($connect) { + $vpn_connection->is_started and $vpn_connection->stop; + $vpn_connection->start($in) or $in->ask_warn(N("Warning"), N("Connection failed.")); + } + require network::network; + network::network::reload_net_applet(); + "end"; + }, + }, + end => { + name => N("The VPN connection is now configured. + +This VPN connection can be automatically started together with a network connection. +It can be done by reconfiguring the network connection and selecting this VPN connection. +"), + end => 1, + }, + }, + }); + $wiz->process($in); +} + +1; diff --git a/lib/network/ifw.pm b/lib/network/ifw.pm new file mode 100644 index 0000000..2509b93 --- /dev/null +++ b/lib/network/ifw.pm @@ -0,0 +1,160 @@ +package network::ifw; + +use Socket; +use common; + +our @ISA = qw(dbus_object); + +sub init { + my ($bus, $filter) = @_; + my $con = $bus->{connection}; + $con->add_filter($filter); + $con->add_match("type='signal',interface='org.mageia.monitoring.ifw'"); +} + +sub new { + my ($type, $bus) = @_; + require dbus_object; + my $o = dbus_object::new($type, + $bus, + "org.mageia.monitoring", + "/org/mageia/monitoring/ifw", + "org.mageia.monitoring.ifw"); + $o; +} + +sub set_blacklist_verdict { + my ($o, $seq, $blacklist) = @_; + $o->call_method('SetBlacklistVerdict', Net::DBus::dbus_uint32($seq), Net::DBus::dbus_uint32($blacklist)); +} + +sub unblacklist { + my ($o, $addr) = @_; + $o->call_method('UnBlacklist', Net::DBus::dbus_uint32($addr)); +} + +sub whitelist { + my ($o, $addr) = @_; + $o->call_method('Whitelist', Net::DBus::dbus_uint32($addr)); +} + +sub unwhitelist { + my ($o, $addr) = @_; + $o->call_method('UnWhitelist', Net::DBus::dbus_uint32($addr)); +} + +sub get_interactive { + my ($o) = @_; + $o->call_method('GetMode'); +} + +sub set_interactive { + my ($o, $mode) = @_; + $o->call_method('SetMode', Net::DBus::dbus_uint32($mode)); +} + +sub get_reports { + my ($o, $o_include_processed) = @_; + $o->call_method('GetReports', Net::DBus::dbus_uint32(to_bool($o_include_processed))); +} + +sub get_blacklist { + my ($o) = @_; + $o->call_method('GetBlacklist'); +} + +sub get_whitelist { + my ($o) = @_; + $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; + # "%c" has strange effects on utf-8 locales + #c::strftime("%c", localtime($timestamp)); + c::strftime("%Y-%m-%d %H:%M:%S", localtime($timestamp)); +} + +sub get_service { + my ($port) = @_; + getservbyport($port, undef) || $port; +} + +sub get_protocol { + my ($protocol) = @_; + getprotobynumber($protocol) || $protocol; +} + +sub get_ip_address { + my ($addr) = @_; + inet_ntoa(pack('L', $addr)); +} + +sub resolve_address { + my ($ip_addr) = @_; + #- try to resolve address, timeout after 2 seconds + my $hostname; + eval { + local $SIG{ALRM} = sub { die "ALARM" }; + alarm 2; + $hostname = gethostbyaddr(inet_aton($ip_addr), AF_INET); + alarm 0; + }; + $hostname || $ip_addr; +} + +sub attack_to_hash { + my ($args) = @_; + my $attack = { mapn { $_[0] => $_[1] } [ 'timestamp', 'indev', 'prefix', 'sensor', 'protocol', 'addr', 'port', 'icmp_type', 'seq', 'processed' ], $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") + : $attack->{prefix} eq 'NEW' ? N("New connection") + : N(qq("%s" attack), $attack->{prefix}); + $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}) + : $attack->{prefix} eq "NEW" ? N("%s is connecting on the %s service.", $attack->{hostname}, $attack->{service}) + : N(qq(A "%s" attack has been attempted by %s), $attack->{prefix}, $attack->{hostname}); + $attack; +} + +sub parse_listen_message { + my ($args) = @_; + my $listen = { mapn { $_[0] => $_[1] } [ 'program', 'port' ], $args }; + $listen->{port} = unpack('S', pack('n', $listen->{port})); + $listen->{service} = get_service($listen->{port}); + $listen->{message} = N("The \"%s\" application is trying to make a service (%s) available to the network.", + $listen->{program}, + $listen->{service} ne $listen->{port} ? $listen->{service} : + #-PO: this should be kept lowercase since the expression is meant to be used between brackets + N("port %d", $listen->{port}), + ); + $listen; +} + +1; diff --git a/lib/network/invictus.pm b/lib/network/invictus.pm new file mode 100644 index 0000000..91806d5 --- /dev/null +++ b/lib/network/invictus.pm @@ -0,0 +1,30 @@ +package network::invictus; + +use MDK::Common; + +my $ucarp_d = "/etc/ucarp.d"; +my $ct_sync_config = "/etc/sysconfig/ct_sync"; + +sub read_config { + my ($invictus) = @_; + foreach (all($::prefix . $ucarp_d)) { + $invictus->{ucarp}{$_} = +{ getVarsFromSh($::prefix . $ucarp_d . '/' . $_) }; + } + $invictus->{ct_sync} = +{ getVarsFromSh($::prefix . $ct_sync_config) }; + $invictus->{ct_sync}{CMARKBIT} ||= 30; +} + +sub write_config { + my ($invictus) = @_; + mkdir_p($::prefix . $ucarp_d); + foreach (keys %{$invictus->{ucarp}}) { + $invictus->{ucarp}{$_}{UPSCRIPT} ||= '/usr/share/invictus-firewall/ucarp-up.sh'; + $invictus->{ucarp}{$_}{DOWNSCRIPT} ||= '/usr/share/invictus-firewall/ucarp-down.sh'; + setVarsInShMode($::prefix . $ucarp_d . '/' . $_, 0600, $invictus->{ucarp}{$_}, + qw(INTERFACE SRCIP VIRTIP VHID PASSWORD TAKEOVER UPSCRIPT DOWNSCRIPT)); + } + setVarsInSh($::prefix . $ct_sync_config, $invictus->{ct_sync}, + qw(ENABLE INTERFACE CMARKBIT)); +} + +1; diff --git a/lib/network/ipsec.pm b/lib/network/ipsec.pm new file mode 100644 index 0000000..846b07a --- /dev/null +++ b/lib/network/ipsec.pm @@ -0,0 +1,619 @@ +package network::ipsec; + + + +use detect_devices; +use run_program; +use common; +use log; + +#- debugg functions ---------- +sub recreate_ipsec_conf { + my ($ipsec) = @_; + foreach my $key1 (ikeys %$ipsec) { + if (! $ipsec->{$key1}{command}) { + print "$ipsec->{$key1}\n"; + } else { + print $ipsec->{$key1}{command} . " " . + $ipsec->{$key1}{src_range} . " " . + $ipsec->{$key1}{dst_range} . " " . + $ipsec->{$key1}{upperspec} . " " . + $ipsec->{$key1}{flag} . " " . + $ipsec->{$key1}{direction} . " " . + $ipsec->{$key1}{ipsec} . "\n\t" . + $ipsec->{$key1}{protocol} . "/" . + $ipsec->{$key1}{mode} . "/" . + $ipsec->{$key1}{src_dest} . "/" . + $ipsec->{$key1}{level} . ";\n"; + } + } +} + +sub recreate_racoon_conf { + my ($racoon) = @_; + my $in_a_section = "n"; + my $in_a_proposal_section = "n"; + foreach my $key1 (ikeys %$racoon) { + if ($in_a_proposal_section eq "y") { + print "\t}\n}\n$racoon->{$key1}\n" if ! $racoon->{$key1}{1}; + } elsif ($in_a_section eq "y") { + print "}\n$racoon->{$key1}\n" if ! $racoon->{$key1}{1}; + } else { + print "$racoon->{$key1}\n" if ! $racoon->{$key1}{1}; + } + $in_a_section = "n"; + $in_a_proposal_section = "n"; + foreach my $key2 (ikeys %{$racoon->{$key1}}) { + if ($racoon->{$key1}{$key2}[0] =~ /^path/) { + print "$racoon->{$key1}{$key2}[0] $racoon->{$key1}{$key2}[1] $racoon->{$key1}{$key2}[2];\n"; + } elsif ($racoon->{$key1}{$key2}[0] =~ /^remote/) { + $in_a_section = "y"; + $in_a_proposal_section = "n"; + print "$racoon->{$key1}{$key2}[0] $racoon->{$key1}{$key2}[1] {\n"; + } elsif ($racoon->{$key1}{$key2}[0] =~ /^sainfo/) { + $in_a_section = "y"; + $in_a_proposal_section = "n"; + if ($racoon->{$key1}{$key2}[2] && $racoon->{$key1}{$key2}[5]) { + print "$racoon->{$key1}{$key2}[0] $racoon->{$key1}{$key2}[1] $racoon->{$key1}{$key2}[2] $racoon->{$key1}{$key2}[3] $racoon->{$key1}{$key2}[4] $racoon->{$key1}{$key2}[5] $racoon->{$key1}{$key2}[6] {\n"; + } else { + print "$racoon->{$key1}{$key2}[0] anonymous {\n"; + } + } elsif ($racoon->{$key1}{$key2}[0] =~ /^proposal /) { + $in_a_proposal_section = "y"; + print "\t$racoon->{$key1}{$key2}[0] {\n"; + } elsif ($in_a_section eq "y" && $racoon->{$key1}{$key2}[0] =~ /^certificate_type/) { + print "\t$racoon->{$key1}{$key2}[0] $racoon->{$key1}{$key2}[1] $racoon->{$key1}{$key2}[2] $racoon->{$key1}{$key2}[3];\n"; + } elsif ($in_a_section eq "y" && $racoon->{$key1}{$key2}[0] =~ /^#/) { + print "\t$racoon->{$key1}{$key2}[0] $racoon->{$key1}{$key2}[1]\n"; + } elsif ($in_a_section eq "y") { + print "\t$racoon->{$key1}{$key2}[0] $racoon->{$key1}{$key2}[1];\n"; + } elsif ($in_a_proposal_section eq "y" && $racoon->{$key1}{$key2}[0] =~ /^#/) { + print "\t\t$racoon->{$key1}{$key2}[0] $racoon->{$key1}{$key2}[1]\n"; + } elsif ($in_a_proposal_section eq "y") { + print "\t\t$racoon->{$key1}{$key2}[0] $racoon->{$key1}{$key2}[1];\n"; + } + } + } + +print "}\n"; +} + +sub recreate_ipsec_conf1_k24 { + my ($ipsec) = @_; + foreach my $key1 (ikeys %$ipsec) { + print "$key1-->$ipsec->{$key1}\n" if ! $ipsec->{$key1}{1}; + foreach my $key2 (ikeys %{$ipsec->{$key1}}) { + if ($ipsec->{$key1}{$key2}[0] =~ m/^#/) { + print "\t$key2-->$ipsec->{$key1}{$key2}[0]\n"; + } elsif ($ipsec->{$key1}{$key2}[0] =~ m/(conn|config|version)/) { + print "$key1-->$key2-->$ipsec->{$key1}{$key2}[0] $ipsec->{$key1}{$key2}[1]\n"; + } else { + print "\t$key2-->$ipsec->{$key1}{$key2}[0]=$ipsec->{$key1}{$key2}[1]\n"; + } + } + } +} +#- end of debug functions -------- + +sub sys { system(@_) == 0 or log::l("[drakvpn] Warning, sys failed for $_[0]") } + +sub start_daemons () { + return if $::testing; + log::explanations("Starting daemons"); + if (-e "/etc/rc.d/init.d/ipsec") { + system("/etc/rc.d/init.d/ipsec status >/dev/null") == 0 and sys("/etc/rc.d/init.d/ipsec stop"); + sys("/etc/rc.d/init.d/$_ start >/dev/null"), sys("/sbin/chkconfig --level 345 $_ on") foreach 'ipsec'; + } else { + + } + sys("/etc/rc.d/init.d/$_ start >/dev/null"), sys("/sbin/chkconfig --level 345 $_ on") foreach 'shorewall'; +} + +sub stop_daemons () { + return if $::testing; + log::explanations("Stopping daemons"); + if (-e "/etc/rc.d/init.d/ipsec") { + foreach (qw(ipsec)) { + system("/etc/rc.d/init.d/$_ status >/dev/null 2>/dev/null") == 0 and sys("/etc/rc.d/init.d/$_ stop"); + } + sys("/sbin/chkconfig --level 345 $_ off") && -e "/etc/rc.d/init.d/$_" foreach 'ipsec'; + } + system("/etc/rc.d/init.d/shorewall status >/dev/null 2>/dev/null") == 0 and sys("/etc/rc.d/init.d/shorewall stop >/dev/null"); + +} + +sub set_config_file { + my ($file, @l) = @_; + + my $done; + substInFile { + if (!$done && (/^#LAST LINE/ || eof)) { + $_ = join('', map { join("\t", @$_) . "\n" } @l) . $_; + $done = 1; + } else { + $_ = '' if /^[^#]/; + } + } "$::prefix/$file"; +} + +sub get_config_file { + my ($file) = @_; + map { [ split ' ' ] } grep { !/^#/ } cat_("$::prefix/$file"); +} + + +#------------------------------------------------------------------- +#---------------------- configure racoon_conf ----------------------- +#------------------------------------------------------------------- + +sub read_racoon_conf { + my ($racoon_conf) = @_; + my %conf; + my $nb = 0; #total number + my $i = 0; #nb within a section + my $in_a_section = "n"; + my @line1; + my $line = ""; + local $_; + open(my $LIST, "< $racoon_conf"); + while (<$LIST>) { + chomp($_); + $line = $_; + $in_a_section = "n" if $line =~ /}/ && $line !~ /^#/; + $line =~ s/^\s+|\s*;|\s*{//g if $line !~ /^#/; + $line =~ /(.*)#(.*)/ if $line !~ /^#/; #- define before and after comment +# print "--line-->$line\n"; + my $data_part = $1; + my $comment_part = "#" . $2; + if ($data_part) { + $data_part =~ s/,//g; +# print "@@".$data_part."->".$comment_part."\n"; + @line1 = split /\s+/,$data_part; + @line1 = (@line1, $comment_part) if $comment_part; + } else { + @line1 = split /\s+/,$line; + } + if (!$line && $in_a_section eq "n") { + $nb++; + put_in_hash(\%conf, { $nb => $line }); + $in_a_section = "n"; + } elsif (!$line && $in_a_section eq "y") { + put_in_hash($conf{$nb} ||= {}, { $i => [ '' ] }); + $i++; + } elsif ($line =~ /^path/) { + $i=1; + $nb++; + put_in_hash($conf{$nb} ||= {}, { $i => [@line1] }); + $in_a_section = "n"; + $i++; + } elsif ($line =~ /^#|^{|^}/) { + if ($in_a_section eq "y") { + put_in_hash($conf{$nb} ||= {}, { $i => [$line] }); + $i++; + } else { + $nb++; + put_in_hash(\%conf, { $nb => $line }); + $in_a_section = "n"; + } + } elsif ($line =~ /^sainfo|^remote|^listen|^timer|^padding/ && $in_a_section eq "n") { + $i=1; + $nb++; + put_in_hash($conf{$nb} ||= {}, { $i => [@line1] }); + $in_a_section = "y"; + $i++; + } elsif ($line eq "proposal" && $in_a_section eq "y") { + $i=1; + $nb++; + put_in_hash($conf{$nb} ||= {}, { $i => [@line1] }); + $in_a_section = "y"; + $i++; + } else { + put_in_hash($conf{$nb} ||= {}, { $i => [@line1] }); + $i++; + } + } + +\%conf; +} + +sub display_racoon_conf { + my ($racoon) = @_; + my $display = ""; + my $prefix_to_simple_line = ""; + foreach my $key1 (ikeys %$racoon) { + if (!$racoon->{$key1}{1}) { + $display .= $prefix_to_simple_line . $racoon->{$key1} . "\n"; + $prefix_to_simple_line = ""; + } else { + foreach my $key2 (ikeys %{$racoon->{$key1}}) { + my $t = $racoon->{$key1}{1}[0]; + my $f = $racoon->{$key1}{$key2}[0]; + my $list_length = scalar @{$racoon->{$key1}{$key2}}; + my $line = ""; + + if ($racoon->{$key1}{$key2}[0] eq "sainfo" && !$racoon->{$key1}{$key2}[2]) { + $line = "sainfo anonymous"; + } else { + for (my $i = 0; $i <= $list_length-1; $i++) { + + my $c = $racoon->{$key1}{$key2}[$i]; + my $n = $racoon->{$key1}{$key2}[$i+1]; + + if ($c =~ /^path|^log|^timer|^listen|^padding|^remote|^proposal|^sainfo/) { + $line .= "$c "; + } elsif ($i == $list_length-2 && $n =~ /^#/) { + $line .= "$c; "; + } elsif ($i == $list_length-1) { + if ($f =~ /^#|^$|^timer|^listen|^padding|^remote|^proposal\s+|^sainfo/) { + $line .= $c; + } elsif ($c =~ /^#/) { + $line .= "\t$c"; + } else { + $line .= "$c;"; + } + } else { + $line .= "$c "; + } + } + } + + if ($f =~ /^timer|^listen|^padding|^remote|^sainfo/) { + $line .= " {"; + $prefix_to_simple_line = ""; + } elsif ($f eq "proposal") { + $line = "\t" . $line . " {"; + } elsif ($t eq "proposal") { + $line = "\t\t" . $line if $line ne "proposal"; + $prefix_to_simple_line = "\t"; + } else { + $line = "\t" . $line if $t !~ /^path|^log/; + $prefix_to_simple_line = ""; + } + $display .= "$line\n"; + } + } + } + +$display; + +} + +sub write_racoon_conf { + my ($racoon_conf, $racoon) = @_; + my $display = ""; + my $prefix_to_simple_line = ""; + foreach my $key1 (ikeys %$racoon) { + if (!$racoon->{$key1}{1}) { + $display .= $prefix_to_simple_line . $racoon->{$key1} . "\n"; + $prefix_to_simple_line = ""; + } else { + foreach my $key2 (ikeys %{$racoon->{$key1}}) { + my $t = $racoon->{$key1}{1}[0]; + my $f = $racoon->{$key1}{$key2}[0]; + my $list_length = scalar @{$racoon->{$key1}{$key2}}; + my $line = ""; + + if ($racoon->{$key1}{$key2}[0] eq "sainfo" && !$racoon->{$key1}{$key2}[2]) { + $line = "sainfo anonymous"; + } else { + for (my $i = 0; $i <= $list_length-1; $i++) { + + my $c = $racoon->{$key1}{$key2}[$i]; + my $n = $racoon->{$key1}{$key2}[$i+1]; + + if ($c =~ /^path|^log|^timer|^listen|^padding|^remote|^proposal|^sainfo/) { + $line .= "$c "; + } elsif ($i == $list_length-2 && $n =~ /^#/) { + $line .= "$c; "; + } elsif ($i == $list_length-1) { + if ($f =~ /^#|^$|^timer|^listen|^padding|^remote|^proposal\s+|^sainfo/) { + $line .= $c; + } elsif ($c =~ /^#/) { + $line .= "\t$c"; + } else { + $line .= "$c;"; + } + } else { + $line .= "$c "; + } + } + } + + if ($f =~ /^timer|^listen|^padding|^remote|^sainfo/) { + $line .= " {"; + $prefix_to_simple_line = ""; + } elsif ($f eq "proposal") { + $line = "\t" . $line . " {"; + } elsif ($t eq "proposal") { + $line = "\t\t" . $line if $line ne "proposal"; + $prefix_to_simple_line = "\t"; + } else { + $line = "\t" . $line if $t !~ /^path|^log/; + $prefix_to_simple_line = ""; + } + $display .= "$line\n"; + } + } + } + +open(my $ADD, "> $racoon_conf") or die "Can not open the $racoon_conf file for writing"; + print $ADD "$display\n"; + +} + +sub get_section_names_racoon_conf { + my ($racoon) = @_; + my @section_names; + + foreach my $key1 (ikeys %$racoon) { + if (!$racoon->{$key1}{1}) { + next; + } else { + my $list_length = scalar @{$racoon->{$key1}{1}}; + my $section_title = ""; + my $separator = ""; + for (my $i = 0; $i <= $list_length-1; $i++) { + my $s = $racoon->{$key1}{1}[$i]; + if ($s !~ /^#|^proposal/) { + $section_title .= $separator . $s; + $separator = " "; + } + } + push(@section_names, $section_title) if $section_title ne ""; + } + } + + @section_names; + +} + +sub add_section_racoon_conf { + my ($new_section, $racoon) = @_; + put_in_hash($racoon, { max(keys %$racoon) + 1 => '' }); + put_in_hash($racoon, { max(keys %$racoon) + 1 => $new_section }); + put_in_hash($racoon, { max(keys %$racoon) + 1 => '}' }) if $new_section->{1}[0] !~ /^path|^remote/; + put_in_hash($racoon, { max(keys %$racoon) + 1 => '' }) if $new_section->{1}[0] =~ /^proposal/; + put_in_hash($racoon, { max(keys %$racoon) + 1 => '}' }) if $new_section->{1}[0] =~ /^proposal/; +} + +sub matched_section_key_number_racoon_conf { + my ($section_name, $racoon) = @_; + foreach my $key1 (ikeys %$racoon) { + if (!$racoon->{$key1}{1}) { + next; + } else { + my $list_length = scalar @{$racoon->{$key1}{1}}; + my $section_title = ""; + my $separator = ""; + for (my $i = 0; $i <= $list_length-1; $i++) { + my $s = $racoon->{$key1}{1}[$i]; + if ($s !~ /^#|^proposal/) { + $section_title .= $separator . $s; + $separator = " "; + } + } + if ($section_title eq $section_name) { + return $key1; + } + } + } + +} + +sub already_existing_section_racoon_conf { + my ($section_name, $racoon, $racoon_conf) = @_; + if (-e $racoon_conf) { + foreach my $key1 (ikeys %$racoon) { + if (!$racoon->{$key1}{1}) { + next; + } elsif (find { + my $list_length = scalar @{$racoon->{$key1}{1}}; + my $section_title = ""; + my $separator = ""; + for (my $i = 0; $i <= $list_length-1; $i++) { + my $s = $racoon->{$key1}{1}[$i]; + if ($s !~ /^#|^proposal/) { + $section_title .= $separator . $s; + $separator = " "; + } + } + + $section_title eq $section_name; + + } ikeys %{$racoon->{$key1}}) { + + return "already existing"; + } + } + } + +} + +sub remove_section_racoon_conf { + my ($section_name, $racoon, $k) = @_; + if ($section_name =~ /^remote/) { + + delete $racoon->{$k} if $k > 1 && !$racoon->{$k-1}; + my $closing_curly_bracket = 0; + while ($closing_curly_bracket < 2) { + print "-->$k\n"; + $closing_curly_bracket++ if $racoon->{$k} eq "}"; + delete $racoon->{$k}; + $k++; + } + + } elsif ($section_name =~ /^path/) { + + delete $racoon->{$k}; + delete $racoon->{$k+1} if $racoon->{$k+1}{1} eq ""; + + } else { + + delete $racoon->{$k}; + delete $racoon->{$k+1} if $racoon->{$k+1}{1} eq ""; + delete $racoon->{$k+2} if $racoon->{$k+2}{1} eq ""; #- remove assoc } + + } + +} + +#------------------------------------------------------------------- +#---------------------- configure ipsec_conf ----------------------- +#------------------------------------------------------------------- + +sub read_ipsec_conf { + my ($ipsec_conf) = @_; + my %conf; + my $nb = 0; #total number + my $i = 0; #nb within a connexion + my $in_a_conn = "n"; + my $line = ""; + my @line1; + local $_; + my @mylist; + my $myline = ""; + open(my $LIST, "< $ipsec_conf"); #or die "Can not open the $ipsec_conf file for reading"; + while (<$LIST>) { + chomp($_); + $myline = $_; + $myline =~ s/^\s+//; + $myline =~ s/;$//; + if ($myline =~ /^spdadd/) { + @mylist = split /\s+/,$myline; + $in_a_conn = "y"; + $nb++; + next; + } elsif ($in_a_conn eq "y") { + @mylist = (@mylist, split '\s+|/',$myline); + put_in_hash(\%conf, { $nb => { command => $mylist[0], + src_range => $mylist[1], + dst_range => $mylist[2], + upperspec => $mylist[3], + flag => $mylist[4], + direction => $mylist[5], + ipsec => $mylist[6], + protocol => $mylist[7], + mode => $mylist[8], + src_dest => $mylist[9], + level => $mylist[10] } }); + $in_a_conn = "n"; + } else { + $nb++; + put_in_hash(\%conf, { $nb => $myline }); + } + } + + \%conf; +} + +sub write_ipsec_conf { + my ($ipsec_conf, $ipsec) = @_; + my $display = ""; + foreach my $key1 (ikeys %$ipsec) { + if (! $ipsec->{$key1}{command}) { + $display .= "$ipsec->{$key1}\n"; + } else { + $display .= $ipsec->{$key1}{command} . " " . + $ipsec->{$key1}{src_range} . " " . + $ipsec->{$key1}{dst_range} . " " . + $ipsec->{$key1}{upperspec} . " " . + $ipsec->{$key1}{flag} . " " . + $ipsec->{$key1}{direction} . " " . + $ipsec->{$key1}{ipsec} . "\n\t" . + $ipsec->{$key1}{protocol} . "/" . + $ipsec->{$key1}{mode} . "/" . + $ipsec->{$key1}{src_dest} . "/" . + $ipsec->{$key1}{level} . ";\n"; + } + } + open(my $ADD, "> $ipsec_conf") or die "Can not open the $ipsec_conf file for writing"; + print $ADD $display; +} + +sub display_ipsec_conf { + my ($ipsec) = @_; + my $display = ""; + + foreach my $key1 (ikeys %$ipsec) { + if (! $ipsec->{$key1}{command}) { + $display .= "$ipsec->{$key1}\n"; + } else { + $display .= $ipsec->{$key1}{command} . " " . + $ipsec->{$key1}{src_range} . " " . + $ipsec->{$key1}{dst_range} . " " . + $ipsec->{$key1}{upperspec} . " " . + $ipsec->{$key1}{flag} . " " . + $ipsec->{$key1}{direction} . " " . + $ipsec->{$key1}{ipsec} . "\n\t" . + $ipsec->{$key1}{protocol} . "/" . + $ipsec->{$key1}{mode} . "/" . + $ipsec->{$key1}{src_dest} . "/" . + $ipsec->{$key1}{level} . ";\n"; + } + } + + $display; + +} + +sub get_section_names_ipsec_conf { + my ($ipsec) = @_; + my @section_names; + + foreach my $key1 (ikeys %$ipsec) { + if ($ipsec->{$key1}{command} =~ m/(^spdadd)/) { + push(@section_names, "$ipsec->{$key1}{src_range} $ipsec->{$key1}{dst_range}"); + } + } + + @section_names; + +} + +sub remove_section_ipsec_conf { + my ($section_name, $ipsec) = @_; + foreach my $key1 (ikeys %$ipsec) { + if (find { + my $s = "$ipsec->{$key1}{src_range} $ipsec->{$key1}{dst_range}"; + $s !~ /^#/ && $ipsec->{$key1}{src_range} && $section_name eq $s; + } ikeys %{$ipsec->{$key1}}) { + delete $ipsec->{$key1-1}; + delete $ipsec->{$key1}; + } + } +} + +sub add_section_ipsec_conf { + my ($new_section, $ipsec) = @_; + put_in_hash($ipsec, { max(keys %$ipsec) + 1 => '' }); + put_in_hash($ipsec, { max(keys %$ipsec) + 1 => $new_section }); +} + +sub already_existing_section_ipsec_conf { + my ($section_name, $ipsec) = @_; + foreach my $key1 (ikeys %$ipsec) { + if (find { + my $s = "$ipsec->{$key1}{src_range} $ipsec->{$key1}{dst_range}"; + $s !~ /^#/ && $ipsec->{$key1}{src_range} && + $section_name eq $s; + } ikeys %{$ipsec->{$key1}}) { + return "already existing"; + } + } + return "no"; +} + +#- returns the hash key number of $section_name +sub matched_section_key_number_ipsec_conf { + my ($section_name, $ipsec) = @_; + foreach my $key1 (ikeys %$ipsec) { + if (find { + my $s = "$ipsec->{$key1}{src_range} $ipsec->{$key1}{dst_range}"; + $s !~ /^#/ && $ipsec->{$key1}{src_range} && + $section_name eq $s; + } ikeys %{$ipsec->{$key1}}) { + return $key1; + } + } +} +1 diff --git a/lib/network/modem.pm b/lib/network/modem.pm new file mode 100644 index 0000000..b7fbc85 --- /dev/null +++ b/lib/network/modem.pm @@ -0,0 +1,218 @@ +package network::modem; # $Id: modem.pm 243081 2008-06-25 15:44:25Z blino $ + +use strict; +use common; +use any; +use modules; +use detect_devices; +use network::network; +use network::tools; + +sub get_user_home() { + my $home; + if ($ENV{USER} ne "root") { + #- kdesu case + my $user = find { $_->[0] eq $ENV{USER} } list_passwd(); + $home = $user->[7] if $user; + } + $home ||= $ENV{HOME}; #- consolehelper case + $home; +} + +sub ppp_read_conf() { + my $modem = {}; + my %l = getVarsFromSh(get_user_home() . "/.kde/share/config/kppprc"); + add2hash(\%l, { getVarsFromSh("$::prefix/usr/share/config/kppprc") }); + $l{Authentication} = 4 if $l{Authentication} !~ /\d/; + $modem->{$_} ||= $l{$_} foreach qw(Authentication Gateway IPAddr SubnetMask); + $modem->{connection} ||= $l{Name}; + $modem->{domain} ||= $l{Domain}; + ($modem->{dns1}, $modem->{dns2}) = split(',', $l{DNS}); + + foreach (cat_("/etc/sysconfig/network-scripts/chat-ppp0")) { + /.*ATDT([\d#*]*)/ and $modem->{phone} ||= $1; + } + foreach (cat_("/etc/sysconfig/network-scripts/ifcfg-ppp0")) { + /NAME=(['"]?)(.*)\1/ and $modem->{login} ||= $2; + /^METRIC=(.*)/ and $modem->{METRIC} = $1; + } + $modem->{login} ||= $l{Username}; + $modem->{passwd} = network::tools::passwd_by_login($modem->{login}); + $modem->{$_} ||= '' foreach qw(connection phone login passwd auth domain dns1 dns2); + $modem->{auto_gateway} ||= defined $modem->{Gateway} && $modem->{Gateway} ne '0.0.0.0' ? N("Manual") : N("Automatic"); + $modem->{auto_ip} ||= defined $modem->{IPAddr} && $modem->{IPAddr} ne '0.0.0.0' ? N("Manual") : N("Automatic"); + $modem->{auto_dns} ||= $modem->{dns1} || $modem->{dns2} ? N("Manual") : N("Automatic"); + $modem->{device} ||= '/dev/modem'; + $modem; +} + +#-----modem conf +sub ppp_configure { + my ($net, $in, $modem) = @_; + $in->do_pkgs->install('ppp') if !$::testing; + $in->do_pkgs->install('kppp') if !$::testing && $in->do_pkgs->is_installed('kdebase4-runtime'); + + if ($modem->{device} ne "/dev/modem") { + my $dev = $modem->{device}; + $dev =~ s!^/dev/!!; + devices::symlink_now_and_register({ device => $dev }, 'modem'); + } + + my %toreplace = map { $_ => $modem->{$_} } qw(Authentication AutoName connection dns1 dns2 domain IPAddr login passwd phone SubnetMask); + $toreplace{phone} =~ s/[^\d#*]//g; + if ($modem->{auto_dns} ne N("Automatic")) { + $toreplace{dnsserver} = join ',', map { $modem->{$_} } "dns1", "dns2"; + $toreplace{dnsserver} .= $toreplace{dnsserver} && ','; + } + + #- using peerdns or dns1,dns2 avoid writing a /etc/resolv.conf file. + $toreplace{peerdns} = "yes"; + + $toreplace{connection} ||= 'DialupConnection'; + $toreplace{domain} ||= 'localdomain'; + $toreplace{papname} = $toreplace{login} if member($modem->{Authentication}, 1, 3, 4); + + # handle static/dynamic settings: + if ($modem->{auto_ip} eq N("Automatic")) { + $toreplace{$_} = '0.0.0.0' foreach qw(IPAddr SubnetMask); + } else { + $toreplace{$_} = $modem->{$_} foreach qw(IPAddr SubnetMask); + } + $toreplace{Gateway} = $modem->{auto_gateway} eq N("Automatic") ? '0.0.0.0' : $modem->{Gateway}; + + $toreplace{METRIC} = defined($modem->{METRIC}) ? $modem->{METRIC} : network::tools::get_default_metric("modem"); + + $net->{ifcfg}{ppp0} = { + DEVICE => "ppp0", + ONBOOT => "no", + USERCTL => "no", + MODEMPORT => "/dev/modem", + LINESPEED => "115200", + PERSIST => "yes", + DEFABORT => "yes", + DEBUG => "yes", + INITSTRING => "ATZ", + DEFROUTE => "yes", + HARDFLOWCTL => "yes", + ESCAPECHARS => "no", + PPPOPTIONS => "", + PAPNAME => $toreplace{papname}, + REMIP => "", + NETMASK => "", + IPADDR => "", + MRU => "", + MTU => "", + DISCONNECTTIMEOUT => "5", + RETRYTIMEOUT => "60", + BOOTPROTO => "none", + PEERDNS => $toreplace{peerdns}, + METRIC => $toreplace{METRIC}, + if_($modem->{auto_dns} ne N("Automatic"), + map { qq(DNS$_=$toreplace{"dns$_"}\n) } grep { $toreplace{"dns$_"} } 1..2), + }; + + #- build chat-ppp0. + my @chat = <<END; +'ABORT' 'BUSY' +'ABORT' 'ERROR' +'ABORT' 'NO CARRIER' +'ABORT' 'NO DIALTONE' +'ABORT' 'Invalid Login' +'ABORT' 'Login incorrect' +'' 'ATZ' +END + if ($modem->{special_command}) { + push @chat, <<END; +'OK' '$modem->{special_command}' +END + } + push @chat, <<END; +'OK' 'ATDT$toreplace{phone}' +'TIMEOUT' '120' +'CONNECT' '' +END + if (member($modem->{Authentication}, 0, 2)) { + push @chat, <<END; +'ogin:--ogin:' '$toreplace{login}' +'ord:' '$toreplace{passwd}' +END + } + push @chat, <<END; +'TIMEOUT' '5' +'~--' '' +END + my $chat_file = "$::prefix/etc/sysconfig/network-scripts/chat-ppp0"; + output_with_perm($chat_file, 0600, @chat); + + network::tools::write_secret_backend($toreplace{login}, $toreplace{passwd}); + + #- install kppprc file according to used configuration. + mkdir_p("$::prefix/usr/share/config"); + + $toreplace{$_->[0]} = $modem->{$_->[0]} || $_->[1] foreach [ 'Timeout', 60 ], [ 'UseLockFile', 1 ], [ 'Enter', 'CR' ], [ 'Volume', 0 ], + [ 'BusyWait', 0 ], [ 'FlowControl', 'CRTSCTS' ], [ 'Speed', 115200 ]; + output($modem->{kppprc} || "$::prefix/usr/share/config/kppprc", common::to_utf8(<<END)); +# KDE Config File + +[Account0] +ExDNSDisabled=0 +AutoName=$toreplace{AutoName} +ScriptArguments= +AccountingEnabled=0 +DialString=ATDT +Phonenumber=$toreplace{phone} +IPAddr=$toreplace{IPAddr} +Domain=$toreplace{domain} +Name=$toreplace{connection} +VolumeAccountingEnabled=0 +pppdArguments= +Password=$toreplace{passwd} +BeforeDisconnect= +Command= +ScriptCommands= +Authentication=$toreplace{Authentication} +DNS=$toreplace{dnsserver} +SubnetMask=$toreplace{SubnetMask} +AccountingFile= +DefaultRoute=1 +Username=$toreplace{login} +Gateway=$toreplace{Gateway} +StorePassword=1 +DisconnectCommand= + +[Modem] +BusyWait=$toreplace{BusyWait} +Enter=$toreplace{Enter} +FlowControl=$toreplace{FlowControl} +Volume=$toreplace{Volume} +Timeout=$toreplace{Timeout} +UseCDLine=0 +UseLockFile=$toreplace{UseLockFile} +Device=/dev/modem +Speed=$toreplace{Speed} + +[Graph] +InBytes=0,0,255 +Text=0,0,0 +Background=255,255,255 +Enabled=true +OutBytes=255,0,0 + +[General] +QuitOnDisconnect=0 +ShowLogWindow=0 +DisconnectOnXServerExit=1 +DefaultAccount=$toreplace{connection} +iconifyOnConnect=1 +Hint_QuickHelp=0 +AutomaticRedial=0 +PPPDebug=0 +NumberOfAccounts=1 +ShowClock=1 +DockIntoPanel=0 +pppdTimeout=30 +END + network::network::proxy_configure($::o->{miscellaneous}); +} + +1; diff --git a/lib/network/monitor.pm b/lib/network/monitor.pm new file mode 100644 index 0000000..1182de4 --- /dev/null +++ b/lib/network/monitor.pm @@ -0,0 +1,136 @@ +package network::monitor; + +use common; +use dbus_object; + +our @ISA = qw(dbus_object); + +my $monitor_service = "org.mageia.monitoring"; +my $monitor_path = "/org/mageia/monitoring/wireless"; +my $monitor_interface = "org.mageia.monitoring.wireless"; + +sub new { + my ($type, $bus) = @_; + dbus_object::new($type, $bus, $monitor_service, $monitor_path, $monitor_interface); +} + +sub list_wireless { + my ($monitor, $o_intf) = @_; + my ($results, $list, %networks); + my $has_roaming; + #- first try to use mandi + eval { + $results = $monitor->call_method('ScanResults'); + $list = $monitor->call_method('ListNetworks'); + $has_roaming = 1; + } if $monitor; + #- try wpa_cli if we're root + if (!$has_roaming && !$>) { + $results = `/usr/sbin/wpa_cli scan_results 2>/dev/null`; + $list = `/usr/sbin/wpa_cli list_networks 2>/dev/null`; + $_ =~ s/^Selected interface (.*)\n//g foreach $results, $list; + } + if ($results && $list) { + #- bssid / frequency / signal level / flags / ssid + while ($results =~ /^((?:[0-9a-f]{2}:){5}[0-9a-f]{2})\t(\d+)\t(\d+)\t(.*?)\t(.*)$/mg) { + my ($ap, $frequency, $signal_strength, $flags, $essid) = ($1, $2, $3, $4, $5); + $networks{$ap}{ap} ||= $ap; + #- wpa_supplicant may list the network two times, use ||= + $networks{$ap}{frequency} ||= $frequency; + $networks{$ap}{signal_strength} ||= $signal_strength; + my $adhoc = $flags =~ s/\[ibss\]//i; + $networks{$ap}{mode} ||= $adhoc ? "Ad-Hoc" : "Managed"; + $networks{$ap}{flags} ||= $flags; + $networks{$ap}{essid} ||= $essid; + } + if (any { $_->{signal_strength} > 100 } values %networks) { + #- signal level is really too high in wpa_supplicant + #- this should be standardized at some point + $_->{signal_strength} = int($_->{signal_strength}/3.5) + foreach values %networks; + } + + #- network id / ssid / bssid / flags + while ($list =~ /^(\d+)\t(.*?)\t(.*?)\t(.*)$/mg) { + foreach my $net (uniq(if_($networks{$3}, $networks{$3}), grep { $_->{essid} eq $2 } values(%networks))) { + $net->{ap} = $3 if $3 ne 'any'; + $net->{id} = $1; + $net->{essid} ||= $2; + $net->{current} = to_bool($4 eq '[CURRENT]'); + } + } + } else { + #- else use iwlist + require network::connection::wireless; + my ($current_essid, $current_ap) = network::connection::wireless::get_access_point($o_intf); + if ($o_intf && !$> && !`/sbin/ip link show $o_intf up`) { + system("/sbin/ip link set $o_intf up"); + } + my @list = `/sbin/iwlist $o_intf scanning 2>/dev/null`; + my $net = {}; + my $quality_match = qr/Quality[:=](\S*)/; + my $eval_quality = sub { + my ($qual) = @_; + $qual =~ s!/0+$!/255!; #- prism54 reports quality with division by zero + $qual =~ m!/! ? eval($qual)*100 : $qual; + }; + my ($has_key, $has_wpa, $has_eap); + foreach (@list) { + if ((/^\s*$/ || /Cell/) && exists $net->{ap}) { + $net->{current} = to_bool($net->{ap} ? $net->{ap} eq $current_ap : $net->{essid} && $net->{essid} eq $current_essid); + $net->{flags} = $has_wpa ? '[WPA]' : $has_key ? '[WEP]' : ''; + $net->{flags} .= '[EAP]' if $has_eap; + $networks{$net->{ap}} = $net; + $net = {}; + $has_key = $has_wpa = $has_eap = undef; + } + /Address: (.*)/ and $net->{ap} = lc($1); + /ESSID:"(.*?)"/ and $net->{essid} = $1; + /Mode:(\S*)/ and $net->{mode} = $1; + $net->{mode} = 'Managed' if $net->{mode} eq 'Master'; + $_ =~ $quality_match and $net->{signal_strength} = $eval_quality->($1); + m|Signal level[:=]([0-9]+/[0-9]+)| and $net->{signal_level} = $eval_quality->($1); + /key:(\S*)\s/ && $1 eq 'on' and $has_key = 1; + /Extra:wpa_ie=|IE:.*WPA/ and $has_wpa = 1; + /Authentication Suites \(\d+\) :.*\b802\.1x\b/ and $has_eap = 1; + } + my $incorrect_quality = + (every { $_->{signal_strength} == 100 } values %networks) && + (any { $_->{signal_strength} != $_->{signal_level} } values %networks); + foreach (values %networks) { + my $level = delete $_->{signal_level}; + $_->{signal_strength} ||= $level; + $_->{signal_strength} = $level if $incorrect_quality; + } + if ($current_ap && exists $networks{$current_ap}) { + foreach (`/sbin/iwconfig $o_intf 2>/dev/null`) { + my $quality = $_ =~ $quality_match && $eval_quality->($1); + $networks{$current_ap}{signal_strength} = $quality if $quality; + } + } + } + + foreach (values %networks) { + $_->{hidden} = member($_->{essid}, '', '<hidden>'); + $_->{essid} eq '<hidden>' and undef $_->{essid}; + $_->{name} = $_->{essid} || "[$_->{ap}]"; + } + (\%networks, $has_roaming); +} + +sub select_network { + my ($o, $id) = @_; + my $method = 'SelectNetwork'; + if ($o) { + $o->call_method($method, Net::DBus::dbus_uint32($id)); + } else { + require run_program; + run_program::run("dbus-send", "--system", "--type=method_call", + "--dest=" . $monitor_service, + $monitor_path, + $monitor_interface . '.' . $method, + 'uint32:' . $id); + } +} + +1; diff --git a/lib/network/ndiswrapper.pm b/lib/network/ndiswrapper.pm new file mode 100644 index 0000000..22af6d6 --- /dev/null +++ b/lib/network/ndiswrapper.pm @@ -0,0 +1,160 @@ +package network::ndiswrapper; + +use strict; +use common; +use modules; +use detect_devices; + +#- using bsd_glob() since glob("/DONT_EXIST") return "/DONT_EXIST" instead of () (and we don't want this) +use File::Glob ':glob'; + +my $ndiswrapper_root = "/etc/ndiswrapper"; + +sub installed_drivers() { + grep { -d $::prefix . "$ndiswrapper_root/$_" } all($::prefix . $ndiswrapper_root); +} + +sub present_devices { + my ($driver) = @_; + my @supported_devices; + foreach (all($::prefix . "$ndiswrapper_root/$driver")) { + my ($ids) = /^([0-9A-F]{4}:[0-9A-F]{4})\.[0-9A-F]\.conf$/; + $ids and push @supported_devices, $ids; + } + grep { member(uc(sprintf("%04x:%04x", $_->{vendor}, $_->{id})), @supported_devices) } detect_devices::probeall(); +} + +sub get_devices { + my ($in, $driver) = @_; + my @devices = present_devices($driver); + @devices or $in->ask_warn(N("Error"), N("No device supporting the %s ndiswrapper driver is present!", $driver)); + @devices; +} + +sub ask_driver { + my ($in) = @_; + if (my $inf_file = $in->ask_fileW({ title => N("Please select the correct driver"), message => N("Please select the Windows driver description (.inf) file, or corresponding driver file (.dll or .o files). Note that only drivers up to Windows XP are supported."), directory => $::prefix . "/media" })) { + my $driver = basename(lc($inf_file)); + $driver =~ s/\.inf$//; + + #- first uninstall the driver if present, may solve issues if it is corrupted + require run_program; + -d $::prefix . "$ndiswrapper_root/$driver" and run_program::rooted($::prefix, 'ndiswrapper', '-e', $driver); + + unless (run_program::rooted($::prefix, 'ndiswrapper', '-i', $inf_file)) { + $in->ask_warn(N("Error"), N("Unable to install the %s ndiswrapper driver!", $driver)); + return undef; + } + + return $driver; + } + undef; +} + +sub find_matching_devices { + my ($device) = @_; + my $net_path = '/sys/class/net'; + my @devices; + + my $is_driver_listed = sub { my ($driver) = @_; any { member($driver, @{$_->{drivers}}) } @devices }; + + require network::connection::ethernet; + foreach my $interface (all($net_path)) { + if (network::connection::ethernet::device_matches_interface($device, $interface)) { + my $driver = network::connection::ethernet::interface_to_driver($interface); + push @devices, { interface => $interface, drivers => [ $driver ] } if $driver; + } + } + + #- find drivers with no net interface + my $sysfs_driver = $device->{sysfs_device} && basename(readlink($device->{sysfs_device} . "/driver/module")); + if ($sysfs_driver) { + my @sysfs_drivers = $sysfs_driver; + if ($sysfs_drivers[0] eq 'ssb') { + push @sysfs_drivers, map { basename(readlink($_)) } bsd_glob($device->{sysfs_device} . "/ssb*/driver/module"); + } + @sysfs_drivers = grep { !$is_driver_listed->($_) } @sysfs_drivers; + push @devices, { interface => undef, drivers => \@sysfs_drivers } if @sysfs_drivers; + } + + #- add original driver + push @devices, { interface => undef, drivers => [ $device->{driver} ] } + if !$is_driver_listed->($device->{driver}) && any { $_ eq $device->{driver} } modules::loaded_modules(); + + @devices; +} + +sub find_conflicting_devices { + my ($device) = @_; + grep { !member("ndiswrapper", @{$_->{drivers}}) } find_matching_devices($device); +} + +sub find_interface { + my ($device) = @_; + my $dev = find { member("ndiswrapper", @{$_->{drivers}}) } find_matching_devices($device); + $dev->{interface}; +} + +sub setup_device { + my ($in, $device) = @_; + + my @conflicts = find_conflicting_devices($device); + if (@conflicts) { + $in->ask_yesorno(N("Warning"), N("The selected device has already been configured with the %s driver. +Do you really want to use a ndiswrapper driver?", $conflicts[0]->{drivers}[0])) or return; + #- stop old interfaces + network::tools::stop_interface($_->{interface}, 0) foreach grep { defined $_->{interface} } @conflicts; + #- unload old modules before trying to load ndiswrapper + #- (sorted according to /proc/modules to handle deps nicely) + my @drivers = intersection([ modules::loaded_modules() ], [ map { @{$_->{drivers}} } @conflicts ]); + eval { modules::unload($_) } foreach @drivers; + } + + #- unload ndiswrapper first so that the newly installed .inf files will be read + eval { modules::unload("ndiswrapper") }; + eval { modules::load("ndiswrapper") }; + + if ($@) { + $in->ask_warn(N("Error"), N("Unable to load the ndiswrapper module!")); + return; + } + + my $interface = find_interface($device); + unless ($interface) { + $in->ask_warn(N("Error"), N("Unable to find the ndiswrapper interface!")); + return; + } + + $interface; +} + +sub select_device { + my ($in) = @_; + my $driver; + my @drivers = installed_drivers(); + if (@drivers) { + $driver ||= first(@drivers); + $in->ask_from('', N("Choose an ndiswrapper driver"), [ + { type => "list", val => \$driver, allow_empty_list => 1, + list => [ undef, @drivers ], + format => sub { defined $_[0] ? N("Use the ndiswrapper driver %s", $_[0]) : N("Install a new driver") } } + ]) or return; + } + $driver ||= ask_driver($in) or return; + + my @devices = get_devices($in, $driver) or return; + my $device; + if (@devices == 1) { + #- only one device matches installed driver + $device = $devices[0]; + } else { + $in->ask_from('', N("Select a device:"), [ + { type => "list", val => \$device, allow_empty_list => 1, + list => [ present_devices($driver) ], + format => sub { $_[0]{description} } } + ]) or return; + } + return $device; +} + +1; diff --git a/lib/network/net_applet/ifw.pm b/lib/network/net_applet/ifw.pm new file mode 100644 index 0000000..22fc432 --- /dev/null +++ b/lib/network/net_applet/ifw.pm @@ -0,0 +1,227 @@ +package network::net_applet::ifw; + +use common; +use network::ifw; +use ugtk2 qw(:create :helpers :wrappers :dialogs); +use mygtk2 qw(gtknew gtkset); + +sub init() { + network::ifw::init($network::net_applet::dbus, sub { + my ($_con, $msg) = @_; + my $member = $msg->get_member; + if ($member eq 'Attack') { + handle_ifw_message($msg->get_args_list); + } elsif ($member eq 'Listen') { + handle_ifw_listen($msg->get_args_list); + } elsif ($member eq 'Init') { + create(); + } elsif ($member eq 'AlertAck') { + $network::net_applet::ifw_alert = 0; + } + }); + create(); +} + +sub create() { + if ($network::net_applet::ifw) { + $network::net_applet::ifw->attach_object; + main::checkNetworkForce(); + } else { + $network::net_applet::ifw = eval { network::ifw->new($network::net_applet::dbus) }; + } +} + +sub enable_ifw_alert() { + unless ($network::net_applet::ifw_alert) { + $network::net_applet::ifw_alert = 1; + network::net_applet::update_tray_icon(); + Glib::Timeout->add(1000, sub { + network::net_applet::update_tray_icon(); + $network::net_applet::ifw_alert; + }); + } +} + +sub disable_ifw_alert() { + eval { $network::net_applet::ifw->send_alert_ack }; + $network::net_applet::ifw_alert = 0; + network::net_applet::update_tray_icon(); +} + +sub get_unprocessed_ifw_messages() { + my @packets = eval { $network::net_applet::ifw->get_reports }; + while (my @ifw_message = splice(@packets, 0, 10)) { + handle_ifw_message(@ifw_message); + } +} + +sub set_verdict { + my ($attack, $apply_verdict) = @_; + eval { $apply_verdict->($attack) }; + $@ and err_dialog(N("Interactive Firewall"), N("Unable to contact daemon")); +} + +sub apply_verdict_blacklist { + my ($attack) = @_; + $network::net_applet::ifw->set_blacklist_verdict($attack->{seq}, 1); +} + +sub apply_verdict_ignore { + my ($attack) = @_; + $network::net_applet::ifw->set_blacklist_verdict($attack->{seq}, 0); +} + +sub apply_verdict_whitelist { + my ($attack) = @_; + $network::net_applet::ifw->whitelist($attack->{addr}); + apply_verdict_ignore($attack); +} + +sub handle_ifw_message { + my $message = network::ifw::attack_to_hash(\@_); + unless ($message->{msg}) { + print "unhandled attack type, skipping\n"; + return; + } + my $is_attack = $message->{prefix} ne 'NEW'; + enable_ifw_alert() if $is_attack; + $network::net_applet::notification_queue->add({ + title => N("Interactive Firewall"), + pixbuf => $network::net_applet::pixbufs{firewall}, + message => $message->{msg}, + timeout => sub { + set_verdict($message, \&apply_verdict_ignore); + }, + if_($is_attack, + urgency => 'critical', + actions => [ { + action => 'clicked', + label => #-PO: "Process" is a verb + N("Process attack"), + callback => sub { + disable_ifw_alert(); + ask_attack_verdict($message); + }, + } ], + ), + }); +} + +sub ask_attack_verdict { + my ($attack) = @_; + + my $w = ugtk2->new(N("Interactive Firewall: intrusion detected"), + icon => "drakfirewall"); + my ($blacklist, $whitelist, $ignore, $auto); + + my $update_automatic_mode = sub { $auto->get_active and $network::net_applet::interactive_cb->set_active(1) }; + my $set_verdict = sub { + my ($verdict) = @_; + set_verdict($attack, $verdict); + $network::net_applet::notification_queue->process_next; + }; + 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, $attack->{msg}, + 0, N("What do you want to do with this attacker?") + ]) + ]), + gtksignal_connect(gtkadd(Gtk2::Expander->new(N("Attack details")), + gtknew('HBox', children => [ + 0, gtknew('Label', text => " "), + 1, gtknew('VBox', children_loose => [ + 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})), + N("Attacker IP address: %s", $attack->{ip_addr}), + if_($attack->{hostname} ne $attack->{ip_addr}, N("Attacker hostname: %s", $attack->{hostname})), + ( + $attack->{service} ne $attack->{port} ? + N("Service attacked: %s", $attack->{service}) : + N("Port attacked: %s", $attack->{port}), + ), + if_($attack->{icmp_type}, N("Type of ICMP attack: %s", $attack->{icmp_type})) + ]), + ])), + activate => sub { $_[0]->get_expanded and $w->shrink_topwindow } + ), + $auto = gtknew('CheckButton', text => N("Always blacklist (do not ask again)"), toggled => sub { + $whitelist->set_sensitive(!$_[0]->get_active); + $ignore->set_sensitive(!$_[0]->get_active); + }), + gtknew('HButtonBox', layout => 'edge', children_loose => [ + $blacklist = gtknew('Button', text => N("Blacklist"), clicked => sub { + $w->destroy; + $update_automatic_mode->(); + $set_verdict->(\&apply_verdict_blacklist); + }), + $whitelist = gtknew('Button', text => N("Whitelist"), clicked => sub { + $w->destroy; + $update_automatic_mode->(); + $set_verdict->(\&apply_verdict_whitelist); + }), + $ignore = gtknew('Button', text => N("Ignore"), clicked => sub { + $w->destroy; + $set_verdict->(\&apply_verdict_ignore); + }), + ]), + ])); + eval { $auto->set_active(!$network::net_applet::ifw->get_interactive) }; + $blacklist->grab_focus; + gtksignal_connect($w->{window}, delete_event => sub { + $set_verdict->(\&apply_verdict_ignore); + }); + $w->{window}->show_all; +} + +sub handle_ifw_listen { + my $listen = network::ifw::parse_listen_message(\@_); + enable_ifw_alert(); + $network::net_applet::notification_queue->add({ + title => N("Interactive Firewall: new service"), + pixbuf => $network::net_applet::pixbufs{firewall}, + message => $listen->{message}, + actions => [ { + action => 'clicked', + label => #-PO: "Process" is a verb + N("Process connection"), + callback => sub { + disable_ifw_alert(); + ask_listen_verdict($listen); + }, + } ], + }); +} + +sub ask_listen_verdict { + my ($listen) = @_; + + my $w = ugtk2->new(N("Interactive Firewall: new service"), icon => "drakfirewall"); + my $set_verdict = sub { + $network::net_applet::notification_queue->process_next; + }; + gtkadd($w->{window}, + gtknew('VBox', spacing => 5, children_loose => [ + gtknew('HBox', children => [ + 0, Gtk2::Image->new_from_stock('gtk-dialog-warning', 'dialog'), + 1, gtknew('VBox', children => [ + 0, $listen->{message}, + 0, N("Do you want to open this service?"), + ]) + ]), + gtknew('CheckButton', text => N("Remember this answer"), toggled => sub {}), + gtknew('HButtonBox', layout => 'edge', children_loose => [ + gtknew('Button', text => N("Allow"), clicked => sub { $w->destroy; $set_verdict->(1) }), + gtknew('Button', text => N("Block"), clicked => sub { $w->destroy; $set_verdict->(0) }), + ]), + ])); + gtksignal_connect($w->{window}, delete_event => sub { $set_verdict->() }); + $w->{window}->show_all; +} + +1; diff --git a/lib/network/netcenter.pm b/lib/network/netcenter.pm new file mode 100755 index 0000000..10d156d --- /dev/null +++ b/lib/network/netcenter.pm @@ -0,0 +1,215 @@ +#!/usr/bin/perl +# Olivier Blin, 2007 <oblin@mandriva.com> +# Licensed under the GPL + +package network::netcenter; + +use strict; +use common; +use mygtk2; +use ugtk2 qw(:create :helpers :wrappers); +use network::connection; +use network::connection_manager; +use network::tools; +use network::network; +use run_program; + +sub build_cmanager { + my ($in, $net, $w, $pixbufs, $connection) = @_; + + my $cmanager = network::connection_manager->new($in, $net, $w, $pixbufs); + $cmanager->set_connection($connection); + $cmanager->{gui}{show_unique_network} = $cmanager->{connection}->has_unique_network; + + if ($connection->can('get_networks')) { + $cmanager->create_networks_list; + #- do not check if it is slow (either scan or device check) or unavailable + $cmanager->update_networks + if !$connection->network_scan_is_slow && $cmanager->check_setup; + } + $cmanager; +} + +sub build_cmanager_box { + my ($cmanager, $is_first) = @_; + + my $head = gtknew('HBox', children => [ + 0, $cmanager->{gui}{status_image} = gtknew('Image'), + 0, gtknew('Label', padding => [ 5, 0 ]), + 1, gtknew('VBox', children_tight => [ + gtknew('HBox', children => [ + 1, gtknew('Label', alignment => [ 0, 0 ], text_markup => '<b>' . $cmanager->{connection}->get_type_description . '</b>'), + 0, gtknew('Label', padding => [ 2, 0 ]), + 0, $cmanager->{gui}{labels}{interface} = gtknew('Label', alignment => [ 0, 0 ], text_markup => $cmanager->{connection}->get_interface ? '<b>' . $cmanager->{connection}->get_interface . '</b>' : ""), + ]), + gtknew('Label', ellipsize => 'end', alignment => [ 0, 0 ], text_markup => $cmanager->{connection}->get_description), + ]), + ]); + my $content = gtknew('HBox', children => [ + 0, gtknew('Label', padding => [ 5, 0 ]), + 1, gtknew('VBox', spacing => 5, children_tight => [ + ($cmanager->{connection}->can('get_networks') ? ( + $cmanager->{gui}{show_unique_network} ? ( + $cmanager->{gui}{networks_list}, + ): ( + gtknew('Label', text => N("Please select your network:"), alignment => [ 0, 0 ]), + gtknew('ScrolledWindow', height => 160, child => $cmanager->{gui}{networks_list}) + ), + ) : ()), + gtknew('HBox', children => [ + 1, gtknew('HButtonBox', spacing => 6, layout => 'start', children_loose => [ + $cmanager->{gui}{buttons}{monitor} = + gtknew('Button', text => N("_: This is a verb\nMonitor"), + image => gtknew('Image', file => 'monitor-16'), + clicked => sub { $cmanager->monitor_connection }), + $cmanager->{gui}{buttons}{configure} = + gtknew('Button', text => N("Configure"), + image => gtknew('Image', file => 'configure-16'), + clicked => sub { $cmanager->configure_connection }), + ($cmanager->{connection}->can('get_networks') ? + ($cmanager->{gui}{buttons}{refresh} = + gtknew('Button', text => N("Refresh"), + image => gtknew('Image', file => 'refresh', size => 16), + clicked => sub { $cmanager->update_networks })) + : ()), + ]), + 0, $cmanager->{gui}{buttons}{connect_toggle} = + gtknew('Button', + image => gtknew('Image', file => 'activate-16'), + clicked => sub { $cmanager->toggle_connection }), + ]), + ]), + ]); + + my $expander = gtknew('Expander'); + my $on_expand = sub { + my ($expanded) = @_; + if ($expanded && $cmanager->{connection}->can('get_networks') && + !$cmanager->{connection}{probed_networks} && $expanded) { + gtkflush(); + $cmanager->update_networks; + } + }; + my $toggle_expand = sub { + my $was_expanded = $expander->get_expanded; + $was_expanded ? $content->hide : $content->show_all; + $on_expand->(!$was_expanded); + }; + $expander->signal_connect(activate => $toggle_expand); + my $eventbox = gtksignal_connect(Gtk2::EventBox->new, button_press_event => sub { + $_[1]->button == 1 or return; + $toggle_expand->(); + my $was_expanded = $expander->get_expanded; + $expander->set_expanded(!$was_expanded); + }); + my $box = gtknew('VBox', spacing => 5, children_tight => [ + (!$is_first ? Gtk2::HSeparator->new : ()), + gtknew('HBox', children => [ + 0, $expander, + 1, gtkadd($eventbox, $head), + ]), + $content, + ]); + $content->hide; + + $cmanager->update_on_status_change; + + $cmanager->{parent_box} = $box; +} + +sub get_connections() { + my @all_connections = map { $_->get_connections(automatic_only => 1, fast_only => 1) } network::connection::get_types; + @all_connections = grep { !network::tools::is_zeroconf_interface($_->get_interface) } @all_connections; + my ($sysfs, $no_sysfs) = partition { exists $_->{device}{sysfs_device} } @all_connections; + my ($real, $other) = partition { network::tools::is_real_interface($_->get_interface) } @$sysfs; + ( + (uniq_ { $_->{device}{sysfs_device} } @$real), + (uniq_ { $_->{device}{sysfs_device} } @$other), + (uniq_ { $_->{device}{interface} } @$no_sysfs), + ); +} + +sub advanced_settings { + my ($in, $net) = @_; + my $u = network::network::advanced_settings_read(); + my $old_crda = $net->{network}{CRDA_DOMAIN}; + if (network::network::advanced_choose($in, $net, $u)) { + network::network::advanced_settings_write($u); + # check if the CRDA changed + if ($old_crda ne $net->{network}{CRDA_DOMAIN}) { + # reconfiguring wireless domain + run_program::run("iw", "reg", "set", $net->{network}{CRDA_DOMAIN}); + } + network::network::write_network_conf($net); + } +} + +sub main { + my ($in, $net, $dbus) = @_; + + my $wait = $in->wait_message(N("Please wait"), N("Please wait")); + + my $title = N("Network Center"); + my $icon = '/usr/share/mcc/themes/default/drakroam-mdk.png'; + + $ugtk2::wm_icon = $icon; + my $w = ugtk2->new($title); + #- so that transient_for is defined, for wait messages and popups to be centered + $::main_window = $w->{real_window}; + + my @connections = get_connections(); + + my $pixbufs = network::connection_manager::create_pixbufs(); + my @cmanagers = map { build_cmanager($in, $net, $w, $pixbufs, $_) } @connections; + + (undef, my $rootwin_height) = gtkroot()->get_size; + my $scrolled_height = $rootwin_height > 480 ? 400 : 295; + my $managers_box; + gtkadd($w->{window}, + gtknew('VBox', spacing => 5, children => [ + $::isEmbedded ? () : (0, Gtk2::Banner->new($icon, $title)), + if_($net->{PROFILE} && network::network::netprofile_count() > 0, 0, gtknew('Label', text_markup => N("You are currently using the network profile <b>%s</b>", $net->{PROFILE})) ), + 1, gtknew('ScrolledWindow', width => 600, height => $scrolled_height, shadow_type => 'none', + child => $managers_box = gtknew('VBox', spacing => 5, children_tight => [ + map_index { build_cmanager_box($_, $::i == 0) } @cmanagers, + ])), + 0, gtknew('HButtonBox', spacing => 6, layout => 'end', children_loose => [ + gtknew('Button', text => N("Advanced settings"), clicked => sub { advanced_settings($in, $net) }), + gtknew('Button', text => N("Quit"), clicked => sub { Gtk2->main_quit }), + ]), + ]), + ); + + if ($dbus) { + $dbus->{connection}->add_filter(sub { + my ($_con, $msg) = @_; + if ($msg->get_interface eq 'org.mageia.network' && $msg->get_member eq 'status') { + my ($status, $interface) = $msg->get_args_list; + my $cmanager = find { $_->{connection}->get_interface eq $interface } @cmanagers; + if ($status eq "add") { + if (!$cmanager) { + detect_devices::probeall_update_cache(); + my $connection = find { $_->get_interface eq $interface } get_connections() + or return; + $cmanager = build_cmanager($in, $net, $w, $pixbufs, $connection); + push @connections, $connection; + push @cmanagers, $cmanager; + my $box = build_cmanager_box($cmanager, @connections == 0); + $managers_box ->add($box); + $box->show_all; + } + $cmanager->{parent_box}->show; + } + if ($status eq "remove") { + $cmanager->{parent_box}->hide if $cmanager; + } + } + }); + network::connection_manager::setup_dbus_handlers(\@cmanagers, \@connections, undef, $dbus); + } + + undef $wait; + $w->main; +} + +1; diff --git a/lib/network/netconnect.pm b/lib/network/netconnect.pm new file mode 100644 index 0000000..abe94c7 --- /dev/null +++ b/lib/network/netconnect.pm @@ -0,0 +1,867 @@ +package network::netconnect; # $Id: netconnect.pm 259351 2009-08-17 15:15:51Z tv $ + +use strict; +use common; +use log; +use detect_devices; +use list_modules; +use modules; +use mouse; +use services; +use network::network; +use network::tools; +use network::thirdparty; +use network::connection; + +sub detect { + my ($modules_conf, $auto_detect, $o_class) = @_; + my %l = ( + isdn => sub { + require network::connection::isdn; + $auto_detect->{isdn} = network::connection::isdn::detect_backend($modules_conf); + }, + modem => sub { + $auto_detect->{modem} = { map { $_->{description} || "$_->{MANUFACTURER}|$_->{DESCRIPTION} ($_->{device})" => $_ } detect_devices::getModem($modules_conf) }; + }, + ); + $l{$_}->() foreach $o_class || keys %l; + return; +} + +sub detect_timezone() { + my %tmz2country = ( + 'Europe/Paris' => N("France"), + 'Europe/Amsterdam' => N("Netherlands"), + 'Europe/Rome' => N("Italy"), + 'Europe/Brussels' => N("Belgium"), + 'America/New_York' => N("United States"), + 'Europe/London' => N("United Kingdom") + ); + my %tm_parse = MDK::Common::System::getVarsFromSh("$::prefix/etc/sysconfig/clock"); + my @country; + foreach (keys %tmz2country) { + if ($_ eq $tm_parse{ZONE}) { + unshift @country, $tmz2country{$_}; + } else { push @country, $tmz2country{$_} } + } + \@country; +} + +sub real_main { + my ($net, $in, $modules_conf) = @_; + #- network configuration should have been already read in $net at this point + my $mouse = $::o->{mouse} || {}; + my (@connections_list, $connection, $provider_settings, $protocol_settings, $access_settings, $control_settings); + my $connection_compat; + my ($hardware_settings, $network_access_settings, $address_settings, $hostname_settings); + my ($modem, $modem_name, $modem_dyn_dns, $modem_dyn_ip); + my ($up); + my ($isdn, $isdn_name, $isdn_type, %isdn_cards, @isdn_dial_methods); + my $my_isdn = join('', N("Manual choice"), " (", N("Internal ISDN card"), ")"); + my $success = 1; + my $has_internet = 1; + my $db_path = "/usr/share/apps/kppp/Provider"; + my (%countries, @isp, $country, $provider, $old_provider); + + my $system_file = '/etc/sysconfig/drakx-net'; + my %global_settings = getVarsFromSh($system_file); + + my $_w = N("Protocol for the rest of the world"); + my %isdn_protocols = ( + 2 => N("European protocol (EDSS1)"), + 3 => N("Protocol for the rest of the world\nNo D-Channel (leased lines)"), + ); + + $net->{autodetect} = {}; + + my %ppp_auth_methods = ( + 0 => N("Script-based"), + 1 => N("PAP"), + 2 => N("Terminal-based"), + 3 => N("CHAP"), + 4 => N("PAP/CHAP"), + ); + + my %steps_compat = ( + 'network::connection::isdn' => 'isdn', + 'network::connection::pots' => 'modem', + ); + + my $get_next = sub { + my ($step) = @_; + my @steps = ( + "select_connection" => sub { 0 }, + "configure_hardware" => sub { $connection->can('get_hardware_settings') }, + #- network is for example wireless/3G access point + "select_network" => sub { $connection->can('get_networks') }, + "configure_network_access" => sub { $connection->can('get_network_access_settings') }, + #- allow to select provider after network + "select_provider" => sub { $connection->can('get_providers') }, + #- protocol may depend on provider settings (xDSL) + "select_protocol" => sub { $connection->can('get_protocols') }, + #- peer settings may depend on provider and protocol (VPI/VCI for xDSL) + "configure_access" => sub { $connection->can('get_access_settings') }, + "configure_address" => sub { ($connection->can('get_address_settings') || $connection->can('get_hostname_settings')) && !text2bool($global_settings{AUTOMATIC_ADDRESS}) }, + "configure_control" => sub { $connection->can('get_control_settings') }, + "apply_connection" => sub { 1 }, + ); + my $can; + foreach (group_by2(@steps)) { + $can && $_->[1]->() and return $_->[0]; + $can ||= $_->[0] eq $step; + } + }; + + use locale; + set_l10n_sort(); + + require wizards; + my $wiz = wizards->new( + { + defaultimage => "drakconnect.png", + name => N("Network & Internet Configuration"), + pages => { + welcome => { + pre => sub { undef $net->{type} }, + if_(!$::isInstall, no_back => 1), + name => N("Choose the connection you want to configure") . if_($net->{PROFILE} && network::network::netprofile_count() > 0, "\n".N("Those settings will be saved for the network profile <b>%s</b>", $net->{PROFILE}) ), + if_(!$::isInstall, interactive_help_id => 'configureNetwork'), + data => [ { list => [ network::connection::get_types ], + type => 'list', val => \$net->{type}, format => sub { $_[0] && $_[0]->get_type_description }, + gtk => { use_scrolling => 1 } } ], + complete => sub { + my @packages = $net->{type}->can('get_packages') ? $net->{type}->get_packages : (); + if (@packages && !$in->do_pkgs->install(@packages)) { + $in->ask_warn(N("Error"), N("Could not install the packages (%s)!", join(', ', @packages))); + 1; + } + }, + post => sub { + if (exists $steps_compat{$net->{type}}) { + return $steps_compat{$net->{type}}; + } + @connections_list = $net->{type}->get_connections(automatic_only => text2bool($global_settings{AUTOMATIC_IFACE_CHOICE})); + @connections_list ? "select_connection" : "no_connection"; + }, + }, + + select_connection => { + name => sub { $net->{type}->get_type_name . "\n\n" . N("Select the network interface to configure:") }, + data => [ { val => \$connection, type => 'list', list => \@connections_list, + format => sub { $_[0] && N("%s: %s", $_[0]->get_interface, $_[0]->get_description) }, allow_empty_list => !text2bool($global_settings{AUTOMATIC_IFACE_CHOICE})} ], + complete => sub { + $connection->setup_thirdparty($in) or return 1; + $connection->prepare_device; + if ($connection->can("check_device") && !$connection->check_device) { + $in->ask_warn('', $connection->{device}{error}); + return 1; + } + return 0; + }, + post => sub { + $connection->load_interface_settings; + $get_next->("select_connection"); + }, + }, + + no_connection => { + name => sub { $net->{type}->get_type_name . "\n\n" . N("No device can be found for this connection type.") }, + end => 1, + }, + + configure_hardware => { + pre => sub { + $hardware_settings = $connection->get_hardware_settings; + $connection->guess_hardware_settings if $connection->can('guess_hardware_settings'); + }, + name => sub { $net->{type}->get_type_name . "\n\n" . N("Hardware Configuration") }, + data => sub { $hardware_settings }, + complete => sub { + if ($connection->can("check_hardware_settings") && !$connection->check_hardware_settings) { + $in->ask_warn('', $connection->{hardware}{error}); + return 1; + } + return 0 if !$connection->can('check_hardware') || $connection->check_hardware; + if ($connection->can('configure_hardware')) { + my $_w = $in->wait_message(N("Please wait"), N("Configuring device...")); + if (!$connection->configure_hardware) { + $in->ask_warn(N("Error"), $connection->{hardware}{error}) if $connection->{hardware}{error}; + return 1; + } + } + }, + post => sub { $get_next->("configure_hardware") }, + }, + + select_provider => { + pre => sub { + $provider_settings = $connection->get_provider_settings; + $connection->guess_provider_settings; + }, + name => sub { $net->{type}->get_type_name . "\n\n" . N("Please select your provider:") }, + data => sub { $provider_settings }, + post => sub { $get_next->("select_provider") }, + }, + + select_network => { + pre => sub { + my $_w = $in->wait_message(N("Please wait"), N("Scanning for networks...")); + $connection->get_networks($net); + }, + name => sub { $net->{type}->get_type_name . "\n\n" . N("Please select your network:") }, + data => sub { + [ { type => "list", val => \$connection->{network}, allow_empty_list => 1, + list => [ keys %{$connection->{networks}}, undef ], + format => sub { exists $connection->{networks}{$_[0]} ? + $connection->{networks}{$_[0]}{name} : + N("Unlisted - edit manually"); + } } ]; + }, + post => sub { + $get_next->("select_network"); + }, + }, + + configure_network_access => { + pre => sub { + $network_access_settings = $connection->get_network_access_settings; + $connection->guess_network_access_settings if $connection->can('guess_network_access_settings'); + }, + name => sub { $net->{type}->get_type_name . "\n\n" . $connection->get_network_access_settings_label }, + data => sub { $network_access_settings }, + complete => sub { + if ($connection->can('check_network_access_settings') && !$connection->check_network_access_settings) { + $in->ask_warn(N("Error"), $connection->{network_access}{error}{message}); + my $index = eval { find_index { $_->{val} eq $connection->{network_access}{error}{field} } @$network_access_settings }; + return 1, $index; + } + return 0; + }, + post => sub { $get_next->("configure_network_access") }, + }, + + select_protocol => { + pre => sub { + $protocol_settings = $connection->get_protocol_settings; + $connection->guess_protocol($net) if $connection->can('guess_protocol'); + }, + name => sub { $net->{type}->get_type_name . "\n\n" . N("Please select your connection protocol. +If you do not know it, keep the preselected protocol.") }, + data => sub { $protocol_settings }, + post => sub { $get_next->("select_protocol") }, + }, + + configure_access => { + pre => sub { + $access_settings = $connection->get_access_settings; + $connection->guess_access_settings if $connection->can('guess_access_settings'); + }, + name => sub { $net->{type}->get_type_name . "\n\n" . $connection->get_access_settings_label }, + data => sub { $access_settings }, + post => sub { $get_next->("configure_access") }, + }, + + configure_address => { + pre => sub { + $address_settings = $connection->can('get_address_settings') && $connection->get_address_settings; + $connection->guess_address_settings if $connection->can('guess_address_settings'); + $connection->guess_hostname_settings if $connection->can('guess_hostname_settings'); + $hostname_settings = $connection->can('get_hostname_settings') && $connection->get_hostname_settings; + }, + name => sub { $net->{type}->get_type_name . "\n\n" . $connection->get_address_settings_label }, + data => sub { [ @$address_settings, @$hostname_settings ] }, + complete => sub { + if ($connection->can('check_address_settings') && !$connection->check_address_settings($net)) { + $in->ask_warn(N("Error"), $connection->{address}{error}{message}); + my $index = eval { find_index { $_->{val} eq $connection->{address}{error}{field} } @$address_settings }; + return 1, $index; + } + return 0; + }, + post => sub { $get_next->("configure_address") }, + }, + + configure_control => { + pre => sub { + $control_settings = $connection->get_control_settings; + $connection->can('get_network_control_settings') and + push @$control_settings, @{$connection->get_network_control_settings}; + $connection->guess_control_settings if $connection->can('guess_control_settings'); + $connection->guess_network_control_settings if $connection->can('guess_network_control_settings'); + }, + name => sub { $net->{type}->get_type_name . "\n\n" . N("Connection control") }, + data => sub { $control_settings }, + post => sub { $get_next->("configure_control") }, + }, + + apply_connection => { + name => N("Do you want to start the connection now?"), + type => "yesorno", + complete => sub { + $connection->can('install_packages') && !$connection->install_packages($in); + }, + post => sub { + my ($answer) = @_; + my $_w = $in->wait_message(N("Please wait"), N("Testing your connection..."), 1); + $connection->unload_connection if $connection->can('unload_connection'); + $connection->write_settings($net, $modules_conf); + $connection->prepare_connection if $connection->can('prepare_connection'); + if ($answer) { + $connection->disconnect; + $connection->connect; + # TODO: we should have some graphical notification for these tests + #- FIXME: should use network::test for ppp (after future merge with network::connection) + #- or start interface synchronously + if (!$::isInstall) { + services::start('network-up'); + } else { + my $timeout = $connection->get_up_timeout; + while ($timeout--) { + my $status = $connection->get_status; + last if $status; + sleep 1; + } + } + $success = $connection->get_status(); + # try to resolve the network address for some time + my $timeout = 3; + while ($timeout--) { + $has_internet = network::tools::connected(); + last if $has_internet; + sleep 1; + } + } + "end"; #- handle disconnection in install? + }, + }, + + isdn_account => + { + pre => sub { + network::connection::isdn::get_info_providers_backend($isdn, $provider); + $isdn->{huptimeout} ||= 180; + }, + name => N("Connection Configuration") . "\n\n" . N("Please fill or check the field below"), + data => sub { + [ + { label => N("Your personal phone number"), val => \$isdn->{phone_in} }, + { label => N("Provider name (ex provider.net)"), val => \$net->{resolv}{DOMAINNAME2} }, + { label => N("Provider phone number"), val => \$isdn->{phone_out} }, + { label => N("Provider DNS 1 (optional)"), val => \$net->{resolv}{dnsServer2} }, + { label => N("Provider DNS 2 (optional)"), val => \$net->{resolv}{dnsServer3} }, + { label => N("Dialing mode"), list => ["auto", "manual"], val => \$isdn->{dialing_mode} }, + { label => N("Connection speed"), list => ["64 Kb/s", "128 Kb/s"], val => \$isdn->{speed} }, + { label => N("Connection timeout (in sec)"), val => \$isdn->{huptimeout} }, + { label => N("Account Login (user name)"), val => \$isdn->{login} }, + { label => N("Account Password"), val => \$isdn->{passwd}, hidden => 1 }, + { label => N("Card IRQ"), val => \$isdn->{irq}, advanced => 1 }, + { label => N("Card mem (DMA)"), val => \$isdn->{mem}, advanced => 1 }, + { label => N("Card IO"), val => \$isdn->{io}, advanced => 1 }, + { label => N("Card IO_0"), val => \$isdn->{io0}, advanced => 1 }, + { label => N("Card IO_1"), val => \$isdn->{io1}, advanced => 1 }, + ]; + }, + post => sub { + network::connection::isdn::apply_config($in, $isdn); + $net->{net_interface} = 'ippp0'; + "isdn_dial_on_boot"; + }, + }, + + isdn => + { + pre=> sub { + detect($modules_conf, $net->{autodetect}, 'isdn'); + %isdn_cards = map { $_->{description} => $_ } @{$net->{autodetect}{isdn}}; + }, + name => N("Select the network interface to configure:"), + data => sub { + [ { label => N("Net Device"), type => "list", val => \$isdn_name, allow_empty_list => 1, + list => [ $my_isdn, N("External ISDN modem"), keys %isdn_cards ] } ]; + }, + post => sub { + if ($isdn_name eq $my_isdn) { + return "isdn_ask"; + } elsif ($isdn_name eq N("External ISDN modem")) { + $net->{type} = 'isdn_external'; + return "modem"; + } + + # FIXME: some of these should be taken from isdn db + $isdn = { map { $_ => $isdn_cards{$isdn_name}{$_} } qw(description vendor id card_type driver type mem io io0 io1 irq firmware) }; + + if ($isdn->{id}) { + log::explanations("found isdn card : $isdn->{description}; vendor : $isdn->{vendor}; id : $isdn->{id}; driver : $isdn->{driver}\n"); + $isdn->{description} =~ s/\|/ -- /; + } + + network::connection::isdn::read_config($isdn); + $isdn->{driver} = $isdn_cards{$isdn_name}{driver}; #- do not let config overwrite default driver + + #- let the user choose hisax or capidrv if both are available + $isdn->{driver} ne "capidrv" && network::connection::isdn::get_capi_card($in, $isdn) and return "isdn_driver"; + return "isdn_protocol"; + }, + }, + + + isdn_ask => + { + pre => sub { + %isdn_cards = network::connection::isdn::get_cards(); + }, + name => N("Select a device!"), + data => sub { [ { label => N("Net Device"), val => \$isdn_name, type => 'list', separator => '|', list => [ keys %isdn_cards ], allow_empty_list => 1 } ] }, + pre2 => sub { + my ($label) = @_; + + #- ISDN card already detected + goto isdn_ask_step_3; + + isdn_ask_step_1: + my $e = $in->ask_from_list_(N("ISDN Configuration"), + $label . "\n" . N("What kind of card do you have?"), + [ N_("ISA / PCMCIA"), N_("PCI"), N_("USB"), N_("I do not know") ] + ) or return; + isdn_ask_step_1b: + if ($e =~ /PCI/) { + $isdn->{card_type} = 'pci'; + } elsif ($e =~ /USB/) { + $isdn->{card_type} = 'usb'; + } else { + $in->ask_from_list_(N("ISDN Configuration"), + N(" +If you have an ISA card, the values on the next screen should be right.\n +If you have a PCMCIA card, you have to know the \"irq\" and \"io\" of your card. +"), + [ N_("Continue"), N_("Abort") ]) eq 'Continue' or goto isdn_ask_step_1; + $isdn->{card_type} = 'isa'; + } + + isdn_ask_step_2: + $e = $in->ask_from_listf(N("ISDN Configuration"), + N("Which of the following is your ISDN card?"), + sub { $_[0]{description} }, + [ network::connection::isdn::get_cards_by_type($isdn->{card_type}) ]) or goto($isdn->{card_type} =~ /usb|pci/ ? 'isdn_ask_step_1' : 'isdn_ask_step_1b'); + $e->{$_} and $isdn->{$_} = $e->{$_} foreach qw(driver type mem io io0 io1 irq firmware); + + }, + post => sub { + $isdn = $isdn_cards{$isdn_name}; + return "isdn_protocol"; + } + }, + + + isdn_driver => + { + pre => sub { + $isdn_name = "capidrv"; + }, + name => N("A CAPI driver is available for this modem. This CAPI driver can offer more capabilities than the free driver (like sending faxes). Which driver do you want to use?"), + data => sub { [ + { label => N("Driver"), type => "list", val => \$isdn_name, + list => [ $isdn->{driver}, "capidrv" ] } + ] }, + post => sub { + $isdn->{driver} = $isdn_name; + return "isdn_protocol"; + } + }, + + + isdn_protocol => + { + name => N("ISDN Configuration") . "\n\n" . N("Which protocol do you want to use?"), + data => [ + { label => N("Protocol"), type => "list", val => \$isdn_type, + list => [ keys %isdn_protocols ], format => sub { $isdn_protocols{$_[0]} } } + ], + post => sub { + $isdn->{protocol} = $isdn_type; + return "isdn_db"; + } + }, + + + isdn_db => + { + name => N("ISDN Configuration") . "\n\n" . N("Select your provider.\nIf it is not listed, choose Unlisted."), + data => sub { + [ { label => N("Provider:"), type => "list", val => \$provider, separator => '|', + list => [ N("Unlisted - edit manually"), network::connection::isdn::read_providers_backend() ] } ]; + }, + next => "isdn_account", + }, + + + no_supported_winmodem => + { + name => N("Warning") . "\n\n" . N("Your modem is not supported by the system. +Take a look at http://www.linmodems.org"), + end => 1, + }, + + + modem => + { + pre => sub { + require network::modem; + detect($modules_conf, $net->{autodetect}, 'modem'); + $modem = {}; + if ($net->{type} eq 'isdn_external') { + #- FIXME: seems to be specific to ZyXEL Adapter Omni.net/TA 128/Elite 2846i + #- it does not even work with TA 128 modems + #- http://bugs.mandrakelinux.com/query.php?bug=1033 + $modem->{special_command} = 'AT&F&O2B40'; + } + }, + name => N("Select the modem to configure:"), + data => sub { + [ { label => N("Modem"), type => "list", val => \$modem_name, allow_empty_list => 1, + list => [ keys %{$net->{autodetect}{modem}}, N("Manual choice") ], } ]; + }, + complete => sub { + my $driver = $net->{autodetect}{modem}{$modem_name}{driver} or return 0; + #- some modem configuration programs modify modprobe.conf while we're loaded + #- so write it now and reload then + $modules_conf->write; + require network::connection::pots; + my $settings = network::thirdparty::apply_settings($in, 'pots', network::connection::pots::get_thirdparty_settings(), $driver); + $modem->{device} = $settings->{device} if $settings; + $modules_conf->read if $settings; + !$settings; + }, + post => sub { + return 'choose_serial_port' if $modem_name eq N("Manual choice"); + if (exists $net->{autodetect}{modem}{$modem_name}{device}) { + #- this is a serial probed modem + $modem->{device} = $net->{autodetect}{modem}{$modem_name}{device}; + } + if (exists $modem->{device}) { + return "ppp_provider"; + } else { + #- driver exists but device field hasn't been filled by network::thirdparty::setup_device + return "no_supported_winmodem"; + } + }, + }, + + + choose_serial_port => + { + pre => sub { + $modem->{device} ||= readlink "$::prefix/dev/modem"; + }, + name => N("Please choose which serial port your modem is connected to."), + if_(!$::isInstall, interactive_help_id => 'selectSerialPort'), + data => sub { + [ { val => \$modem->{device}, format => \&detect_devices::serialPort2text, type => "list", + list => [ grep { $_ ne $mouse->{device} } (detect_devices::serialPorts(), glob_("/dev/ttyUSB*"), grep { -e $_ } '/dev/modem', '/dev/ttySL0', '/dev/ttyS14',) ] } ]; + }, + post => sub { + return 'ppp_provider'; + }, + }, + + + ppp_provider => + { + pre => sub { + add2hash($modem, network::modem::ppp_read_conf()); + $in->do_pkgs->ensure_is_installed('kppp-provider', $db_path); + my $p_db_path = "$::prefix$db_path"; + @isp = map { + my $country = $_; + map { + s!$p_db_path/$country!!; + s/%([0-9]{3})/chr(int($1))/eg; + $countries{$country} ||= translate($country); + join('', $countries{$country}, $_); + } grep { !/.directory$/ } glob_("$p_db_path/$country/*"); + } map { s!$p_db_path/!!o; s!_! !g; $_ } glob_("$p_db_path/*") if !@isp; + $old_provider = $provider; + }, + name => N("Select your provider:"), + data => sub { + [ { label => N("Provider:"), type => "list", val => \$provider, separator => '/', + list => [ N("Unlisted - edit manually"), @isp ] } ]; + }, + post => sub { + if ($provider ne N("Unlisted - edit manually")) { + ($country, $provider) = split('/', $provider); + $country = { reverse %countries }->{$country}; + my %l = getVarsFromSh("$::prefix$db_path/$country/$provider"); + if (defined $old_provider && $old_provider ne $provider) { + $modem->{connection} = $l{Name}; + $modem->{phone} = $l{Phonenumber}; + $modem->{$_} = $l{$_} foreach qw(Authentication AutoName Domain Gateway IPAddr SubnetMask); + ($modem->{dns1}, $modem->{dns2}) = split(',', $l{DNS}); + } + } + return "ppp_account"; + }, + }, + + + ppp_account => + { + name => N("Dialup: account options"), + data => sub { + [ + { label => N("Connection name"), val => \$modem->{connection} }, + { label => N("Phone number"), val => \$modem->{phone} }, + { label => N("Login ID"), val => \$modem->{login} }, + { label => N("Password"), val => \$modem->{passwd}, hidden => 1 }, + { label => N("Authentication"), val => \$modem->{Authentication}, + list => [ sort keys %ppp_auth_methods ], format => sub { $ppp_auth_methods{$_[0]} } }, + ]; + }, + next => "ppp_ip", + }, + + + ppp_ip => + { + pre => sub { + $modem_dyn_ip = sub { $modem->{auto_ip} eq N("Automatic") }; + }, + name => N("Dialup: IP parameters"), + data => sub { + [ + { label => N("IP parameters"), type => "list", val => \$modem->{auto_ip}, list => [ N("Automatic"), N("Manual") ] }, + { label => N("IP address"), val => \$modem->{IPAddr}, disabled => $modem_dyn_ip }, + { label => N("Subnet mask"), val => \$modem->{SubnetMask}, disabled => $modem_dyn_ip }, + ]; + }, + next => "ppp_dns", + }, + + + ppp_dns => + { + pre => sub { + $modem_dyn_dns = sub { $modem->{auto_dns} eq N("Automatic") }; + }, + name => N("Dialup: DNS parameters"), + data => sub { + [ + { label => N("DNS"), type => "list", val => \$modem->{auto_dns}, list => [ N("Automatic"), N("Manual") ] }, + { label => N("Domain name"), val => \$modem->{domain}, disabled => $modem_dyn_dns }, + { label => N("First DNS Server (optional)"), val => \$modem->{dns1}, disabled => $modem_dyn_dns }, + { label => N("Second DNS Server (optional)"), val => \$modem->{dns2}, disabled => $modem_dyn_dns }, + { text => N("Set hostname from IP"), val => \$modem->{AutoName}, type => 'bool', disabled => $modem_dyn_dns }, + ]; + }, + next => "ppp_gateway", + }, + + + ppp_gateway => + { + name => N("Dialup: IP parameters"), + data => sub { + [ + { label => N("Gateway"), type => "list", val => \$modem->{auto_gateway}, list => [ N("Automatic"), N("Manual") ] }, + { label => N("Gateway IP address"), val => \$modem->{Gateway}, + disabled => sub { $modem->{auto_gateway} eq N("Automatic") } }, + ]; + }, + post => sub { + network::modem::ppp_configure($net, $in, $modem); + $net->{net_interface} = 'ppp0'; + "configure_control_compat"; + }, + }, + + + configure_control_compat => { + pre => sub { + $connection_compat = $net->{type}->new($connection || {}); + network::connection::guess_control_settings($connection_compat); + $control_settings = network::connection::get_control_settings($connection_compat); + }, + name => sub { N("Connection control") }, + data => sub { $control_settings }, + post => sub { + $net->{ifcfg}{$net->{net_interface}}{USERCTL} = bool2yesno($connection_compat->{control}{userctl}); + $net->{ifcfg}{$net->{net_interface}}{ONBOOT} = bool2yesno($connection_compat->{control}{onboot}); + network::network::configure_network($net, $in, $modules_conf); + "ask_connect_now"; + }, + }, + + isdn_dial_on_boot => + { + pre => sub { + $net->{ifcfg}{ippp0} ||= {}; # we want the ifcfg-ippp0 file to be written + $net->{ifcfg}{ippp0}{DEVICE} = "ippp0"; + @isdn_dial_methods = ({ name => N("Automatically at boot"), + ONBOOT => 1, DIAL_ON_IFUP => 1 }, + { name => N("By using Net Applet in the system tray"), + ONBOOT => 0, DIAL_ON_IFUP => 1 }, + { name => N("Manually (the interface would still be activated at boot)"), + ONBOOT => 1, DIAL_ON_IFUP => 0 }); + my $method = find { + $_->{ONBOOT} eq text2bool($net->{ifcfg}{ippp0}{ONBOOT}) && + $_->{DIAL_ON_IFUP} eq text2bool($net->{ifcfg}{ippp0}{DIAL_ON_IFUP}); + } @isdn_dial_methods; + #- use net_applet by default + $isdn->{dial_method} = $method->{name} || $isdn_dial_methods[1]{name}; + }, + name => N("How do you want to dial this connection?"), + data => sub { + [ { type => "list", val => \$isdn->{dial_method}, list => [ map { $_->{name} } @isdn_dial_methods ] } ]; + }, + post => sub { + my $method = find { $_->{name} eq $isdn->{dial_method} } @isdn_dial_methods; + $net->{ifcfg}{ippp0}{$_} = bool2yesno($method->{$_}) foreach qw(ONBOOT DIAL_ON_IFUP); + return "configure_control_compat"; + }, + }, + + ask_connect_now => + { + name => N("Do you want to try to connect to the Internet now?"), + type => "yesorno", + post => sub { + my ($a) = @_; + my $type = $net->{type}; + $up = 1; + if ($a) { + # local $::isWizard = 0; + my $_w = $in->wait_message(N("Please wait"), N("Testing your connection..."), 1); + network::tools::stop_net_interface($net, 0); + sleep 1; + network::tools::start_net_interface($net, 1); + my $s = 30; + $type =~ /modem/ and $s = 50; + $type =~ /isdn/ and $s = 20; + sleep $s; + $up = network::tools::connected(); + } + $success = $up; + return $a ? "disconnect" : "end"; + } + }, + + + disconnect => + { + name => sub { + $up ? N("The system is now connected to the Internet.") . + if_($::isInstall, N("For security reasons, it will be disconnected now.")) : + N("The system does not seem to be connected to the Internet. +Try to reconfigure your connection."); + }, + no_back => 1, + end => 1, + post => sub { + $::isInstall and network::tools::stop_net_interface($net, 0); + return "end"; + }, + }, + + + end => + { + name => sub { + if (!$success) { + return join("\n\n", N("Problems occurred during the network connectivity test."), + N("This can be caused by invalid network configuration, or problems with your modem or router."), + N("You might want to relaunch the configuration to verify the connection settings.")); + } + if (!$has_internet) { + return join("\n\n", N("Congratulations, the network configuration is finished."), N("However, the Internet connectivity test failed. You should test your connection manually, and verify your Internet modem or router."), + N("If your connection does not work, you might want to relaunch the configuration.")); + } + return join("\n\n", N("Congratulations, the network and Internet configuration are finished."), if_($::isStandalone && $in->isa('interactive::gtk'), + N("After this is done, we recommend that you restart your X environment to avoid any hostname-related problems."))); + }, + end => 1, + }, + }, + }); + $wiz->process($in); + + #- keeping the translations in case someone want to restore these texts + if_(0, + N("Alcatel speedtouch USB modem"), + N("Sagem USB modem"), + N("Bewan modem"), + N("Bewan modem"), + N("ECI Hi-Focus modem"), # this one needs eci agreement + N("LAN connection"), + N("Wireless connection"), + N("ADSL connection"), + N("Cable connection"), + N("ISDN connection"), + N("Modem connection"), + N("DVB connection"), + # keep b/c of translations in case they can be reused somewhere else: + N("(detected on port %s)", 'toto'), + #-PO: here, "(detected)" string will be appended to eg "ADSL connection" + N("(detected %s)", 'toto'), N("(detected)"), + N("Network Configuration"), + N("Zeroconf hostname resolution"), + N("If desired, enter a Zeroconf hostname. +This is the name your machine will use to advertise any of +its shared resources that are not managed by the network. +It is not necessary on most networks."), + N("Zeroconf Host name"), + N("Zeroconf host name must not contain a ."), + N("Because you are doing a network installation, your network is already configured. +Click on Ok to keep your configuration, or cancel to reconfigure your Internet & Network connection. +"), + N("The network needs to be restarted. Do you want to restart it?"), + N("A problem occurred while restarting the network: \n\n%s", 'foo'), + N("We are now going to configure the %s connection.\n\n\nPress \"%s\" to continue.", 'a', 'b'), + N("Configuration is complete, do you want to apply settings?"), + N("You have configured multiple ways to connect to the Internet.\nChoose the one you want to use.\n\n"), + N("Internet connection"), + N("Select the network interface to configure:"), + N("Configuring network device %s (driver %s)", '', ''), + N("The following protocols can be used to configure a LAN connection. Please choose the one you want to use."), + N("Please enter your host name. +Your host name should be a fully-qualified host name, +such as ``mybox.mylab.myco.com''. +You may also enter the IP address of the gateway if you have one."), + # better looking text (to be merged into texts since some languages (eg: ja) doesn't need it + N("Last but not least you can also type in your DNS server IP addresses."), + N("DNS server address should be in format 1.2.3.4"), + N("Gateway address should be in format 1.2.3.4"), + N("Gateway device"), + ); +} + +sub safe_main { + my ($net, $in, $modules_conf) = @_; + eval { real_main($net, $in, $modules_conf) }; + my $err = $@; + if ($err) { # && $in->isa('interactive::gtk') + $err =~ /wizcancel/ and $in->exit(0); + + local $::isEmbedded = 0; # to prevent sub window embedding + local $::isWizard = 0 if !$::isInstall; # to prevent sub window embedding + #err_dialog(N("Error"), N("An unexpected error has happened:\n%s", $err)); + $in->ask_warn(N("Error"), N("An unexpected error has happened:\n%s", $err)); + } +} + +1; + +=head1 network::netconnect::detect() + +=head2 example of usage + + use lib qw(/usr/lib/libDrakX); + use network::netconnect; + use modules; + use Data::Dumper; + + my %i; + my $modules_conf = modules::any_conf->read; + network::netconnect::detect($modules_conf, \%i); + print Dumper(\%i),"\n"; + +=cut diff --git a/lib/network/network.pm b/lib/network/network.pm new file mode 100644 index 0000000..565e438 --- /dev/null +++ b/lib/network/network.pm @@ -0,0 +1,832 @@ +package network::network; # $Id: network.pm 268044 2010-04-30 13:31:34Z blino $wir + +#-###################################################################################### +#- misc imports +#-###################################################################################### + +use strict; + +use lang; +use Socket; +use common; +use run_program; +use network::tools; +use vars qw(@ISA @EXPORT); +use log; + +our $network_file = "/etc/sysconfig/network"; +my $resolv_file = "/etc/resolv.conf"; +my $tmdns_file = "/etc/tmdns.conf"; +our $wireless_d = "/etc/sysconfig/network-scripts/wireless.d"; + +# list of CRDA domains +our @crda_domains = qw(AE AL AM AN AR AT AU AZ BA BE BG BH BL BN BO BR BY BZ CA CH CL CN CO CR CS CY CZ DE DK DO DZ EC EE EG ES FI FR GB GE GR GT HK HN HR HU ID IE IL IN IR IS IT JM JO JP KP KR KW KZ LB LI LK LT LU LV MA MC MK MO MT MX MY NL NO NP NZ OM PA PE PG PH PK PL PR PT QA RO RU SA SE SG SI SK SV SY TH TN TR TT TW UA US UY UZ VE VN YE ZA ZW); + +@ISA = qw(Exporter); +@EXPORT = qw(addDefaultRoute dns dnsServers gateway guessHostname is_ip is_ip_forbidden masked_ip netmask resolv); + +#- $net hash structure +#- autodetect +#- type +#- net_interface +#- PROFILE: selected netprofile +#- network (/etc/sysconfig/network) : NETWORKING FORWARD_IPV4 NETWORKING_IPV6 HOSTNAME GATEWAY GATEWAYDEV NISDOMAIN +#- NETWORKING : networking flag : string : "yes" by default +#- FORWARD_IPV4 : forward IP flag : string : "false" by default +#- HOSTNAME : hostname : string : "localhost.localdomain" by default +#- GATEWAY : gateway +#- GATEWAYDEV : gateway interface +#- NISDOMAIN : nis domain +#- NETWORKING_IPV6 : use IPv6, "yes" or "no" +#- IPV6_DEFAULTDEV +#- resolv (/etc/resolv.conf): dnsServer, dnsServer2, dnsServer3, DOMAINNAME, DOMAINNAME2, DOMAINNAME3 +#- dnsServer : dns server 1 +#- dnsServer2 : dns server 2 +#- dnsServer3 : dns server 3 : note that we uses the dns1 for the LAN, and the 2 others for the internet conx +#- DOMAINNAME : domainname : string : $net->{network}{HOSTNAME} =~ /\.(.*)/ by default +#- DOMAINNAME2 : well it's another domainname : have to look further why we used 2 +#- adsl: bus, Encapsulation, vpi, vci provider_id, method, login, passwd, ethernet_device, capi_card +#- cable: bpalogin, login, passwd +#- zeroconf: hostname +#- auth: LDAPDOMAIN WINDOMAIN +#- ifcfg (/etc/sysconfig/network-scripts/ifcfg-*): +#- key : device name +#- value : hash containing ifcfg file values, see write_interface_conf() for an exhaustive list +#- DHCP_HOSTNAME : If you have a dhcp and want to set the hostname +#- IPADDR : IP address +#- NETMASK : netmask +#- DEVICE : device name +#- BOOTPROTO : boot prototype : "bootp" or "dhcp" or "pump" or ... +#- IPV6INIT +#- IPV6TO4INIT +#- MS_DNS1 +#- MS_DNS2 +#- DOMAIN + +sub read_conf { + my ($file) = @_; + +{ getVarsFromSh($file) }; +} + +sub read_resolv_conf_raw { + my ($o_file) = @_; + my $s = cat_($o_file || $::prefix . $resolv_file); + { nameserver => [ $s =~ /^\s*nameserver\s+(\S+)/mg ], + search => [ if_($s =~ /^\s*search\s+(.*)/m, split(' ', $1)) ] }; +} + +sub read_resolv_conf { + my ($o_file) = @_; + my $resolv_conf = read_resolv_conf_raw($o_file); + +{ + (mapn { $_[0] => $_[1] } [ qw(dnsServer dnsServer2 dnsServer3) ], $resolv_conf->{nameserver}), + (mapn { $_[0] => $_[1] } [ qw(DOMAINNAME DOMAINNAME2 DOMAINNAME3) ], $resolv_conf->{search}), + }; +} + +sub read_interface_conf { + my ($file) = @_; + my %intf = getVarsFromSh($file); + + $intf{BOOTPROTO} ||= 'static'; + $intf{isPtp} = $intf{NETWORK} eq '255.255.255.255'; + $intf{isUp} = 1; + \%intf; +} + +sub read_zeroconf() { + cat_($::prefix . $tmdns_file) =~ /^\s*hostname\s*=\s*(\w+)/m && { ZEROCONF_HOSTNAME => $1 }; +} + +sub write_network_conf { + my ($net) = @_; + + if ($net->{network}{HOSTNAME} && $net->{network}{HOSTNAME} =~ /\.(.+\..+)$/) { + $net->{resolv}{DOMAINNAME} ||= $1; + } + $net->{network}{NETWORKING} = 'yes'; + + setVarsInSh($::prefix . $network_file, $net->{network}, qw(HOSTNAME NETWORKING GATEWAY GATEWAYDEV NISDOMAIN FORWARD_IPV4 NETWORKING_IPV6 IPV6_DEFAULTDEV CRDA_DOMAIN)); +} + +sub write_zeroconf { + my ($net, $in) = @_; + my $zhostname = $net->{zeroconf}{hostname}; + my $file = $::prefix . $tmdns_file; + + if ($zhostname) { + $in->do_pkgs->ensure_binary_is_installed('tmdns', 'tmdns', 'auto') if !$in->do_pkgs->is_installed('bind'); + $in->do_pkgs->ensure_binary_is_installed('zcip', 'zcip', 'auto'); + } + + #- write blank hostname even if disabled so that drakconnect does not assume zeroconf is enabled + eval { substInFile { s/^\s*(hostname)\s*=.*/$1 = $zhostname/ } $file } if $zhostname || -f $file; + + require services; + services::set_status('tmdns', $net->{zeroconf}{hostname}, $::isInstall); +} + +sub write_resolv_conf { + my ($net) = @_; + my $resolv = $net->{resolv}; + my $file = $::prefix . $resolv_file; + + my %new = ( + search => [ grep { $_ } uniq(@$resolv{'DOMAINNAME', 'DOMAINNAME2', 'DOMAINNAME3'}) ], + nameserver => [ grep { $_ } uniq(@$resolv{'dnsServer', 'dnsServer2', 'dnsServer3'}) ], + ); + + my (%prev, @unknown); + foreach (cat_($file)) { + s/\s+$//; + s/^[#\s]*//; + + if (my ($key, $val) = /^(search|nameserver)\s+(.*)$/) { + push @{$prev{$key}}, $val; + } elsif (/^ppp temp entry$/) { + } elsif (/\S/) { + push @unknown, $_; + } + } + unlink $file if -l $file; #- workaround situation when /etc/resolv.conf is an absolute link to /etc/ppp/resolv.conf or whatever + + if (@{$new{search}} || @{$new{nameserver}}) { + $prev{$_} = [ difference2($prev{$_} || [], $new{$_}) ] foreach keys %new; + + my @search = do { + my @new = if_(@{$new{search}}, "search " . join(' ', @{$new{search}}) . "\n"); + my @old = if_(@{$prev{search}}, "# search " . join(' ', @{$prev{search}}) . "\n"); + @new, @old; + }; + my @nameserver = do { + my @new = map { "nameserver $_\n" } @{$new{nameserver}}; + my @old = map { "# nameserver $_\n" } @{$prev{nameserver}}; + @new, @old; + }; + output_with_perm($file, 0644, @search, @nameserver, (map { "# $_\n" } @unknown), "\n# ppp temp entry\n"); + + #-res_init(); # reinit the resolver so DNS changes take affect + 1; + } else { + log::explanations("neither domain name nor dns server are configured"); + 0; + } +} + +sub update_broadcast_and_network { + my ($intf) = @_; + my @ip = split '\.', $intf->{IPADDR}; + my @mask = split '\.', $intf->{NETMASK}; + #- FIXME: NETWORK and BROADCAST are deprecated, see sysconfig.txt + $intf->{BROADCAST} = join('.', mapn { int($_[0]) | ((~int($_[1])) & 255) } \@ip, \@mask); + $intf->{NETWORK} = join('.', mapn { int($_[0]) & $_[1] } \@ip, \@mask); +} + +sub write_interface_settings { + my ($intf, $file) = @_; + setVarsInSh($file, $intf, qw(DEVICE BOOTPROTO IPADDR NETMASK NETWORK BROADCAST GATEWAY ONBOOT HWADDR METRIC MII_NOT_SUPPORTED TYPE USERCTL ATM_ADDR ATM_DEVICE ETHTOOL_OPTS VLAN MTU DNS1 DNS2 DOMAIN RESOLV_MODS LINK_DETECTION_DELAY), + qw(WIRELESS_MODE WIRELESS_ESSID WIRELESS_NWID WIRELESS_FREQ WIRELESS_SENS WIRELESS_RATE WIRELESS_ENC_KEY WIRELESS_ENC_MODE WIRELESS_RTS WIRELESS_FRAG WIRELESS_IWCONFIG WIRELESS_IWSPY WIRELESS_IWPRIV WIRELESS_WPA_DRIVER WIRELESS_WPA_REASSOCIATE CRDA_DOMAIN), + qw(DVB_ADAPTER_ID DVB_NETWORK_DEMUX DVB_NETWORK_PID), + qw(IPV6INIT IPV6TO4INIT), + qw(MRU REMIP PPPOPTIONS HARDFLOWCTL DEFABORT RETRYTIMEOUT PAPNAME LINESPEED MODEMPORT DEBUG ESCAPECHARS INITSTRING), + qw(DISCONNECTTIMEOUT PERSIST DEFROUTE), + qw(VPN_NAME VPN_TYPE), + qw(ACCOUNTING), + qw(NM_CONTROLLED), + qw(UUID NAME LAST_CONNECT), + qw(CELLULAR_CID), + if_($intf->{BOOTPROTO} eq "dhcp", qw(DHCP_CLIENT DHCP_HOSTNAME NEEDHOSTNAME PEERDNS PEERYP PEERNTPD DHCP_TIMEOUT)), + if_($intf->{DEVICE} =~ /^ippp\d+$/, qw(DIAL_ON_IFUP)) + ); + substInFile { s/^DEVICE='(`.*`)'/DEVICE=$1/g } $file; #- remove quotes if DEVICE is the result of a command + chmod $intf->{WIRELESS_ENC_KEY} ? 0700 : 0755, $file; #- hide WEP key for non-root users + log::explanations("written $intf->{DEVICE} interface configuration in $file"); +} + +sub get_ifcfg_file { + my ($name) = @_; + "$::prefix/etc/sysconfig/network-scripts/ifcfg-$name"; +} + +sub write_interface_conf { + my ($net, $name) = @_; + + my $file = get_ifcfg_file($name); + #- prefer ifcfg-XXX files + unlink("$::prefix/etc/sysconfig/network-scripts/$name"); + + my $intf = $net->{ifcfg}{$name}; + + require network::connection::ethernet; + my (undef, $mac_address) = network::connection::ethernet::get_eth_card_mac_address($intf->{DEVICE}); + $intf->{HWADDR} &&= $mac_address; #- set HWADDR to MAC address if required + + update_broadcast_and_network($intf); + + defined($intf->{METRIC}) or $intf->{METRIC} = network::tools::get_default_metric(network::tools::get_interface_type($intf)), + $intf->{BOOTPROTO} =~ s/dhcp.*/dhcp/; + + write_interface_settings($intf, $file); +} + +sub write_wireless_conf { + my ($ssid, $ifcfg) = @_; + my $wireless_file = $::prefix . $wireless_d . '/' . $ssid; + my %wireless_ifcfg = %$ifcfg; + # FIXME: be smarter to keep only DHCP/IP settings here + delete $wireless_ifcfg{$_} + foreach qw(DEVICE MII_NOT_SUPPORTED ONBOOT); + write_interface_settings(\%wireless_ifcfg, $wireless_file); +} + +sub add2hosts { + my ($hostname, @ips) = @_; + my ($sub_hostname) = $hostname =~ /(.*?)\./; + + my $file = "$::prefix/etc/hosts"; + + my @l; + push(@l, [$_, $hostname, if_($sub_hostname, $sub_hostname)]) foreach(@ips); + foreach (cat_($file)) { + # strip our own comments + next if ($_ =~ /# generated by drak.*/); + my ($ip, $aliases) = /^\s*(\S+)\s+(\S+.*)$/ or next; + my @hosts = difference2([ split /\s+/, $aliases ], [ $hostname, $sub_hostname ]); + if (@hosts) { + push (@l, [$ip, @hosts]); + } + }; + + log::explanations("writing host information to $file"); + output($file, "# generated by drakconnect\n"); + foreach (@l) { + append_to_file($file, join(" ", @{$_}) . "\n"); + } +} + +# The interface/gateway needs to be configured before this will work! +sub guessHostname { + my ($net, $intf_name) = @_; + + $net->{ifcfg}{$intf_name}{isUp} && dnsServers($net) or return 0; + $net->{network}{HOSTNAME} && $net->{resolv}{DOMAINNAME} and return 1; + + write_resolv_conf($net); + + my $name = gethostbyaddr(Socket::inet_aton($net->{ifcfg}{$intf_name}{IPADDR}), Socket::AF_INET()) or log::explanations("reverse name lookup failed"), return 0; + + log::explanations("reverse name lookup worked"); + + $net->{network}{HOSTNAME} ||= $name; + 1; +} + +sub addDefaultRoute { + my ($net) = @_; + c::addDefaultRoute($net->{network}{GATEWAY}) if $net->{network}{GATEWAY}; +} + +sub write_hostname { + my ($hostname) = @_; + + addVarsInSh($::prefix . $network_file, { HOSTNAME => $hostname }, qw(HOSTNAME)); + + add2hosts("localhost", "127.0.0.1"); + add2hosts($hostname, "127.0.0.1") if $hostname; + + unless ($::isInstall) { + my $rc = syscall_("sethostname", $hostname, length $hostname); + log::explanations($rc ? "set sethostname to $hostname" : "sethostname failed: $!"); + run_program::run("/usr/bin/run-parts", "--arg", $hostname, "/etc/sysconfig/network-scripts/hostname.d"); + } +} + +sub resolv($) { + my ($name) = @_; + is_ip($name) and return $name; + my $a = join(".", unpack "C4", (gethostbyname $name)[4]); + #-log::explanations("resolved $name in $a"); + $a; +} + +sub dnsServers { + my ($net) = @_; + #- FIXME: that's weird + my %used_dns; @used_dns{$net->{network}{dnsServer}, $net->{network}{dnsServer2}, $net->{network}{dnsServer3}} = (1, 2, 3); + sort { $used_dns{$a} <=> $used_dns{$b} } grep { $_ } keys %used_dns; +} + +sub findIntf { + my ($net, $device) = @_; + $net->{ifcfg}{$device}{DEVICE} = undef; + $net->{ifcfg}{$device}; +} + +my $ip_regexp = qr/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/; + +sub is_ip { + my ($ip) = @_; + my @fields = $ip =~ $ip_regexp or return; + every { 0 <= $_ && $_ <= 255 } @fields or return; + @fields; +} + +sub ip_compare { + my ($ip1, $ip2) = @_; + my (@ip1_fields) = $ip1 =~ $ip_regexp; + my (@ip2_fields) = $ip2 =~ $ip_regexp; + + every { $ip1_fields[$_] eq $ip2_fields[$_] } (0 .. 3); +} + +sub is_ip_forbidden { + my ($ip) = @_; + my @forbidden = ('127.0.0.1', '255.255.255.255'); + + any { ip_compare($ip, $_) } @forbidden; +} + +sub is_domain_name { + my ($name) = @_; + my @fields = split /\./, $name; + $name !~ /\.$/ && @fields > 0 && @fields == grep { /^[[:alnum:]](?:[\-[:alnum:]]{0,61}[[:alnum:]])?$/ } @fields; +} + +sub netmask { + my ($ip) = @_; + return "255.255.255.0" unless is_ip($ip); + $ip =~ $ip_regexp or warn "IP_regexp failed\n" and return "255.255.255.0"; + if ($1 >= 1 && $1 < 127) { + "255.0.0.0"; #-1.0.0.0 to 127.0.0.0 + } elsif ($1 >= 128 && $1 <= 191) { + "255.255.0.0"; #-128.0.0.0 to 191.255.0.0 + } elsif ($1 >= 192 && $1 <= 223) { + "255.255.255.0"; + } else { + "255.255.255.255"; #-experimental classes + } +} + +sub netmask_to_vlsm { + my ($netmask) = @_; + #- based on Network::IPv4Addr::ipv4_msk2cidr + my @bytes = split /\./, $netmask; + my $prefix = 0; + foreach (@bytes) { + my $bits = unpack("B*", pack("C", $_)); + $prefix += $bits =~ tr/1/1/; + } + return $prefix; +} + +sub masked_ip { + my ($ip) = @_; + my @ip = is_ip($ip) or return ''; + my @mask = netmask($ip) =~ $ip_regexp; + for (my $i = 0; $i < @ip; $i++) { + $ip[$i] &= int $mask[$i]; + } + join(".", @ip); +} + +sub dns { + my ($ip) = @_; + my @masked = masked_ip($ip) =~ $ip_regexp; + $masked[3] = 1; + join(".", @masked); + +} + +sub gateway { + my ($ip) = @_; + my @masked = masked_ip($ip) =~ $ip_regexp; + $masked[3] = 1; + join(".", @masked); +} + +sub netprofile_modules() { + my @m = split('\n', `/sbin/netprofile modules`); + my @modules = (); + + foreach my $module (@m) { + my @params = split('\t', $module); + my $vals = { + module => @params[0], + enabled => @params[1] eq '+' ? 1 : 0, + name => @params[2], + description => @params[3], + }; + push(@modules, $vals); + } + @modules; +} + +sub netprofile_module_enable { + my ($module) = @_; + system('/sbin/netprofile', 'module_enable', $module); + log::explanations(qq(Enabling netprofile module $module)); +} + +sub netprofile_module_disable { + my ($module) = @_; + system('/sbin/netprofile', 'module_disable', $module); + log::explanations(qq(Disabling netprofile module $module)); +} + +sub netprofile_set { + my ($net, $profile) = @_; + $net->{PROFILE} = $profile; + system('/sbin/netprofile', 'switch', $net->{PROFILE}); + log::explanations(qq(Switching to "$net->{PROFILE}" profile)); +} + +sub netprofile_delete { + my ($profile) = @_; + return if !$profile; + system('/sbin/netprofile', 'delete', $profile); + log::explanations(qq(Deleting "$profile" profile)); +} + +sub netprofile_list() { + map { if_(m!([^/]*)/$!, common::from_utf8($1)) } glob("$::prefix/etc/netprofile/profiles/*/"); +} + +sub netprofile_count() { + my @profiles = netprofile_list(); + return $#profiles; +} + +sub netprofile_read { + my ($net) = @_; + my $profile = cat_("$::prefix/etc/netprofile/current"); + chomp $profile if $profile; + $net->{PROFILE} = $profile || 'default'; +} + +sub advanced_settings_read { + my $modprobe = "$::prefix/etc/modprobe.conf"; + my $sysctl = "$::prefix/etc/sysctl.conf"; + my $msecconf = "$::prefix/etc/security/msec/security.conf"; + + my $ipv6_disabled = grep { /^options ipv6 disable=1$/ } cat_($modprobe); + my $disable_window_scaling = grep { /^net\.ipv4\.tcp_window_scaling\s*=\s*0$/ } cat_($sysctl); + my $disable_tcp_timestamps = grep { /^net\.ipv4\.tcp_timestamps\s*=\s*0$/ } cat_($sysctl); + my $log_martians = grep { /^net\.ipv4\.conf\.all\.log_martians\s*=\s*1$/ } cat_($sysctl); + my $disable_icmp = grep { /^net\.ipv4\.icmp_echo_ignore_all\s*=\s*1$/ } cat_($sysctl); + my $disable_icmp_broadcasts = grep { /^net\.ipv4\.icmp_echo_ignore_broadcasts\s*=\s*1$/ } cat_($sysctl); + my $disable_bogus_error_responses = grep { /^net\.ipv4\.icmp_ignore_bogus_error_responses\s*=\s*1$/ } cat_($sysctl); + my $msec = grep { /^BASE_LEVEL=/ } cat_($msecconf); + + { ipv6_disabled => $ipv6_disabled, disable_window_scaling => $disable_window_scaling, + disable_tcp_timestamps => $disable_tcp_timestamps, log_martians => $log_martians, + disable_icmp => $disable_icmp, disable_icmp_broadcasts => $disable_icmp_broadcasts, + disable_bogus_error_responses => $disable_bogus_error_responses, + msec => $msec, + } +} + +sub advanced_settings_write { + my ($u) = @_; + # ipv6 + substInFile { + /^(options ipv6 .*|install ipv6 .*|alias net-pf-10 off)/ and $_=""; + if (eof and $u->{ipv6_disabled}) { + $_ .= "options ipv6 disable=1\n"; + } + } "$::prefix/etc/modprobe.conf"; + # sysctl + substInFile { + # remove old entries + /^net\.ipv4\.(tcp_window_scaling|tcp_timestamps|conf\.all\.log_martians|icmp_echo_ignore_all|icmp_echo_ignore_broadcasts|icmp_ignore_bogus_error_responses).*/ and $_=""; + if (eof) { + # add new values + my $window_scaling = ($u->{disable_window_scaling}) ? "0" : "1"; + my $tcp_timestamps = ($u->{disable_tcp_timestamps}) ? "0" : "1"; + my $log_martians = ($u->{log_martians}) ? "1" : "0"; # this is inversed property + my $disable_icmp = ($u->{disable_icmp}) ? "1" : "0"; # this is inversed property + my $disable_icmp_broadcasts = ($u->{disable_icmp_broadcasts}) ? "1" : "0"; # this is inversed property + my $disable_bogus_error_responses = ($u->{disable_bogus_error_responses}) ? "1" : "0"; # this is inversed property + $_ .= "net.ipv4.tcp_window_scaling=$window_scaling\n"; + $_ .= "net.ipv4.tcp_timestamps=$tcp_timestamps\n"; + $_ .= "net.ipv4.conf.all.log_martians=$log_martians\n"; + $_ .= "net.ipv4.icmp_echo_ignore_all=$disable_icmp\n"; + $_ .= "net.ipv4.icmp_echo_ignore_broadcasts=$disable_icmp_broadcasts\n"; + $_ .= "net.ipv4.icmp_ignore_bogus_error_responses=$disable_bogus_error_responses\n"; + } + } "$::prefix/etc/sysctl.conf"; +} + +sub advanced_choose { + my ($in, $net, $u) = @_; + + my $use_http_for_https = $u->{https_proxy} eq $u->{http_proxy}; + $in->ask_from(N("Advanced network settings"), + N("Here you can configure advanced network settings. Please note that you have to reboot the machine for changes to take effect."), + [ + { label => N("Wireless regulatory domain"), val => \$net->{network}{CRDA_DOMAIN}, sort => 1, list => \@crda_domains }, + { label => "<b>".N("TCP/IP settings")."</b>"}, + { text => N("Disable IPv6"), val => \$u->{ipv6_disabled}, type => "bool" }, + { text => N("Disable TCP Window Scaling"), val => \$u->{disable_window_scaling}, type => "bool"}, + { text => N("Disable TCP Timestamps"), val => \$u->{disable_tcp_timestamps}, type => "bool"}, + { label => "<b>".N("Security settings (defined by MSEC policy)")."</b>"}, + { text => N("Disable ICMP echo"), val => \$u->{disable_icmp}, type => "bool", disabled => sub { $u->{msec} }}, + { text => N("Disable ICMP echo for broadcasting messages"), val => \$u->{disable_icmp_broadcasts}, type => "bool", disabled => sub { $u->{msec} }}, + { text => N("Disable invalid ICMP error responses"), val => \$u->{disable_bogus_error_responses}, type => "bool", disabled => sub { $u->{msec} }}, + { text => N("Log strange packets"), val => \$u->{log_martians}, type => "bool", disabled => sub { $u->{msec} }}, + ] + ) or return; + 1; +} + +sub miscellaneous_choose { + my ($in, $u) = @_; + + my $net = {}; + netprofile_read($net); + + my $use_http_for_https = $u->{https_proxy} eq $u->{http_proxy}; + $in->ask_from(N("Proxies configuration"), + N("Here you can set up your proxies configuration (eg: http://my_caching_server:8080)") . if_($net->{PROFILE} && netprofile_count() > 0, "\n".N("Those settings will be saved for the network profile <b>%s</b>", $net->{PROFILE})), + [ { label => N("HTTP proxy"), val => \$u->{http_proxy} }, + { text => N("Use HTTP proxy for HTTPS connections"), val => \$use_http_for_https, type => "bool" }, + { label => N("HTTPS proxy"), val => \$u->{https_proxy}, disabled => sub { $use_http_for_https } }, + { label => N("FTP proxy"), val => \$u->{ftp_proxy} }, + { label => N("No proxy for (comma separated list):"), val => \$u->{no_proxy} }, + ], + complete => sub { + $use_http_for_https and $u->{https_proxy} = $u->{http_proxy}; + $u->{no_proxy} =~ s/\s//g; + $u->{http_proxy} =~ m,^($|http://), or $in->ask_warn('', N("Proxy should be http://...")), return 1,0; + $u->{https_proxy} =~ m,^($|https?://), or $in->ask_warn('', N("Proxy should be http://... or https://...")), return 1,2; + $u->{ftp_proxy} =~ m,^($|ftp://|http://), or $in->ask_warn('', N("URL should begin with 'ftp:' or 'http:'")), return 1,3; + 0; + } + ) or return; + 1; +} + +sub proxy_configure_shell { + my ($proxy) = @_; + my $sh_file = "$::prefix/etc/profile.d/proxy.sh"; + setExportedVarsInSh($sh_file, $proxy, qw(http_proxy https_proxy ftp_proxy no_proxy)); + chmod 0755, $sh_file; + my $csh_file = "$::prefix/etc/profile.d/proxy.csh"; + setExportedVarsInCsh($csh_file, $proxy, qw(http_proxy https_proxy ftp_proxy no_proxy)); + chmod 0755, $csh_file; +} + +sub proxy_configure_kde { + my ($proxy) = @_; + + my $kde_config_dir = "$::prefix/usr/share/config"; + -d $kde_config_dir or return; + + my $kde_config_file = "$kde_config_dir/kioslaverc"; + update_gnomekderc($kde_config_file, + undef, + PersistentProxyConnection => "false" + ); + update_gnomekderc($kde_config_file, + "Proxy Settings", + AuthMode => 0, + ProxyType => $proxy->{http_proxy} || $proxy->{https_proxy} || $proxy->{ftp_proxy} ? 4 : 0, + ftpProxy => "ftp_proxy", + httpProxy => "http_proxy", + httpsProxy => "https_proxy", + NoProxyFor => "no_proxy", + ); +} + +#- (protocol, user, password, host, port) +my $http_proxy_match = qr,^(http)://(?:([^:\@]+)(?::([^:\@]+))?\@)?([^\:]+)(?::(\d+))?$,; +#- (protocol, host, port) +my $https_proxy_match = qr,^(https?)://(?:[^:\@]+(?::[^:\@]+)?\@)?([^\:]+)(?::(\d+))?$,; +#- (protocol, protocol, host, port) +my $ftp_proxy_match = qr,^(http|ftp)://(?:[^:\@]+(?::[^:\@]+)?\@)?([^\:]+)(?::(\d+))?$,; +my %proxy_default_port = ( + http => 80, + https => 443, + ftp => 21, +); + +sub proxy_configure_gnome { + my ($proxy) = @_; + + -d "$::prefix/etc/gconf/2/" or return; + + my $defaults_dir = "/etc/gconf/gconf.xml.local-defaults"; + my $p_defaults_dir = "$::prefix$defaults_dir"; + + my $use_alternate_proxy; + my $gconf_set = sub { + my ($key, $type, $value) = @_; + #- gconftool-2 is available since /etc/gconf/2/ exists + run_program::rooted($::prefix, 'gconftool-2', '>', '/dev/null', "--config-source=xml::$p_defaults_dir", "--direct", "--set", "--type=$type", if_($type eq "list", '--list-type', 'string'), $key, $value); + }; + + #- http proxy + if (my ($protocol, $user, $password, $host, $port) = $proxy->{http_proxy} =~ $http_proxy_match) { + $port ||= $proxy_default_port{$protocol} || $proxy_default_port{http}; + $gconf_set->("/system/http_proxy/use_http_proxy", "bool", 1); + $gconf_set->("/system/http_proxy/host", "string", $host); + $gconf_set->("/system/http_proxy/port", "int", $port); + $gconf_set->("/system/http_proxy/use_authentication", "bool", to_bool($user)); + $user and $gconf_set->("/system/http_proxy/authentication_user", "string", $user); + $password and $gconf_set->("/system/http_proxy/authentication_password", "string", $password); + } else { + $gconf_set->("/system/http_proxy/use_http_proxy", "bool", 0); + } + + #- https proxy + if (my ($protocol, $host, $port) = $proxy->{https_proxy} =~ $https_proxy_match) { + $port ||= $proxy_default_port{$protocol} || $proxy_default_port{https}; + $gconf_set->("/system/proxy/secure_host", "string", $host); + $gconf_set->("/system/proxy/secure_port", "int", $port); + $use_alternate_proxy = 1; + } else { + #- clear the ssl host so that it isn't used if the manual proxy is activated for ftp + $gconf_set->("/system/proxy/secure_host", "string", ""); + } + + #- ftp proxy + if (my ($protocol, $host, $port) = $proxy->{ftp_proxy} =~ $ftp_proxy_match) { + $port ||= $proxy_default_port{$protocol} || $proxy_default_port{ftp}; + $gconf_set->("/system/proxy/ftp_host", "string", $host); + $gconf_set->("/system/proxy/ftp_port", "int", $port); + $use_alternate_proxy = 1; + } else { + #- clear the ftp host so that it isn't used if the manual proxy is activated for ssl + $gconf_set->("/system/proxy/ftp_host", "string", ""); + } + + my $ignore_hosts = join(',', uniq(qw(localhost 127.0.0.0/8)), split(',', $proxy->{no_proxy})); + $gconf_set->("/system/http_proxy/ignore_hosts", "list", "[$ignore_hosts]"); + + #- set proxy mode to manual if either https or ftp is used + $gconf_set->("/system/proxy/mode", "string", $use_alternate_proxy ? "manual" : "none"); + + #- make gconf daemons reload their settings + system("killall -s HUP gconfd-2"); +} + +sub proxy_configure_mozilla_firefox { + my ($proxy) = @_; + + my $firefox_config_file = "$::prefix/etc/firefox.cfg"; + -f $firefox_config_file or return; + + my %prefs; + foreach (qw(http ssl ftp)) { + undef $prefs{"network.proxy.${_}"}; + undef $prefs{"network.proxy.${_}_port"}; + } + if (my ($protocol, undef, undef, $host, $port) = $proxy->{http_proxy} =~ $http_proxy_match) { + $prefs{"network.proxy.http"} = qq("$host"); + $prefs{"network.proxy.http_port"} = $port || $proxy_default_port{$protocol} || $proxy_default_port{http}; + } + if (my ($protocol, $host, $port) = $proxy->{https_proxy} =~ $https_proxy_match) { + $prefs{"network.proxy.ssl"} = qq("$host"); + $prefs{"network.proxy.ssl_port"} = $port || $proxy_default_port{$protocol} || $proxy_default_port{https}; + } + if (my ($protocol, $host, $port) = $proxy->{ftp_proxy} =~ $ftp_proxy_match) { + $prefs{"network.proxy.ftp"} = qq("$host"); + $prefs{"network.proxy.ftp_port"} = $port || $proxy_default_port{$protocol} || $proxy_default_port{ftp}; + } + if ($proxy->{no_proxy}) { + $prefs{"network.proxy.no_proxies_on"} = qq("$proxy->{no_proxy}"); + } + $prefs{"network.proxy.type"} = any { defined $prefs{"network.proxy.${_}_port"} } qw(http ssl ftp); + + substInFile { + while (my ($key, $value) = each(%prefs)) { + if (/^defaultPref\("$key",/) { + $_ = defined $value && qq(defaultPref("$key", $value);\n); + delete $prefs{$key}; + } + } + $_ .= join('', map { if_(defined $prefs{$_}, qq(defaultPref("$_", $prefs{$_});\n)) } sort(keys %prefs)) if eof; + } $firefox_config_file; +} + +sub proxy_configure { + my ($proxy) = @_; + proxy_configure_shell($proxy); + proxy_configure_kde($proxy); + proxy_configure_gnome($proxy); + proxy_configure_mozilla_firefox($proxy); +} + +sub detect_crda_domain { + my $crda = { getVarsFromSh($::prefix . $network_file) }->{CRDA_DOMAIN}; + if (!$crda) { + my $locale = lang::read($>); + my $country = $locale->{country}; + if (grep($country, @crda_domains)) { + $crda = $country; + } else { + $crda = "US"; + } + } + $crda; +} + +sub read_net_conf { + my ($net) = @_; + add2hash($net->{network} ||= {}, read_conf($::prefix . $network_file)); + add2hash($net->{resolv} ||= {}, read_resolv_conf()); + add2hash($net->{zeroconf} ||= {}, read_zeroconf()); + + foreach (all("$::prefix/etc/sysconfig/network-scripts")) { + my ($device) = /^ifcfg-([A-Za-z0-9.:_-]+)$/; + next if $device =~ /.rpmnew$|.rpmsave$/; + if ($device && $device ne 'lo') { + my $intf = findIntf($net, $device); + add2hash($intf, { getVarsFromSh("$::prefix/etc/sysconfig/network-scripts/$_") }); + $intf->{DEVICE} ||= $device; + } + } + $net->{wireless} ||= {}; + foreach (all($::prefix . $wireless_d)) { + $net->{wireless}{$_} = { getVarsFromSh($::prefix . $wireless_d . '/' . $_) }; + } + # detect default CRDA_DOMAIN + $net->{network}{CRDA_DOMAIN} ||= detect_crda_domain(); + netprofile_read($net); + if (my $default_intf = network::tools::get_default_gateway_interface($net)) { + $net->{net_interface} = $default_intf; + $net->{type} = network::tools::get_interface_type($net->{ifcfg}{$default_intf}); + } +} + +#- FIXME: this is buggy, use network::tools::get_default_gateway_interface +sub probe_netcnx_type { + my ($net) = @_; + #- try to probe $netcnx->{type} which is used almost everywhere. + unless ($net->{type}) { + #- ugly hack to determine network type (avoid saying not configured in summary). + -e "$::prefix/etc/ppp/peers/adsl" and $net->{type} ||= 'adsl'; # enough ? + -e "$::prefix/etc/ppp/ioptions1B" || -e "$::prefix/etc/ppp/ioptions2B" and $net->{type} ||= 'isdn'; # enough ? + $net->{ifcfg}{ppp0} and $net->{type} ||= 'modem'; + $net->{ifcfg}{eth0} and $net->{type} ||= 'lan'; + } +} + +sub easy_dhcp { + my ($net, $modules_conf) = @_; + + return if text2bool($net->{network}{NETWORKING}); + + require modules; + require network::connection::ethernet; + modules::load_category($modules_conf, list_modules::ethernet_categories()); + my @all_dev = sort map { $_->[0] } network::connection::ethernet::get_eth_cards($modules_conf); + + my @ether_dev = grep { /^eth[0-9]+$/ && `LC_ALL= LANG= $::prefix/sbin/ip -o link show $_ 2>/dev/null` =~ m|\slink/ether\s| } @all_dev; + foreach my $dhcp_intf (@ether_dev) { + log::explanations("easy_dhcp: found $dhcp_intf"); + $net->{ifcfg}{$dhcp_intf} ||= {}; + put_in_hash($net->{ifcfg}{$dhcp_intf}, { + DEVICE => $dhcp_intf, + BOOTPROTO => 'dhcp', + NETMASK => '255.255.255.0', + ONBOOT => 'yes' + }); + } + + 1; +} + +sub reload_net_applet() { + #- make net_applet reload the configuration + my $pid = chomp_(`pidof -x net_applet`); + $pid and kill 1, $pid; +} + +sub configure_network { + my ($net, $in, $modules_conf) = @_; + if (!$::testing) { + require network::connection::ethernet; + network::connection::ethernet::configure_eth_aliases($modules_conf); + + write_network_conf($net); + write_resolv_conf($net); + write_hostname($net->{network}{HOSTNAME}) if $net->{network}{HOSTNAME}; + foreach (keys %{$net->{ifcfg}}) { + write_interface_conf($net, $_); + my $ssid = $net->{ifcfg}{$_}{WIRELESS_ESSID} or next; + write_wireless_conf($ssid, $net->{ifcfg}{$_}); + } + network::connection::ethernet::install_dhcp_client($in, $_->{DHCP_CLIENT}) foreach grep { $_->{BOOTPROTO} eq "dhcp" } values %{$net->{ifcfg}}; + write_zeroconf($net, $in); + + any { $_->{BOOTPROTO} =~ /^(pump|bootp)$/ } values %{$net->{ifcfg}} and $in->do_pkgs->install('pump'); + + require network::shorewall; + network::shorewall::update_interfaces_list(); + + } + + reload_net_applet(); +} + +1; diff --git a/lib/network/nfs.pm b/lib/network/nfs.pm new file mode 100644 index 0000000..93df7ab --- /dev/null +++ b/lib/network/nfs.pm @@ -0,0 +1,99 @@ +package network::nfs; + +use strict; +use common; + +sub read_nfs_ports { + my $statd_port = 4001; + my $statd_outgoing_port = undef; + my $lockd_tcp_port = 4002; + my $lockd_udp_port = 4002; + my $rpc_mountd_port = 4003; + my $rpc_rquotad_port = 4004; + if (-f "$::prefix/etc/sysconfig/nfs-common") { + foreach (cat_("$::prefix/etc/sysconfig/nfs-common")) { + $_ =~ /^STATD_OPTIONS=.*(--port|-p) (\d+).*$/ and $statd_port = $2; + $_ =~ /^STATD_OPTIONS=.*(--outgoing-port|-o) (\d+).*$/ and $statd_outgoing_port = $2; + $_ =~ /^LOCKD_TCPPORT=(\d+)/ and $lockd_tcp_port = $1; + $_ =~ /^LOCKD_UDPPORT=(\d+)/ and $lockd_udp_port = $1; + } + } + if (-f "$::prefix/etc/sysconfig/nfs-server") { + foreach (cat_("$::prefix/etc/sysconfig/nfs-server")) { + $_ =~ /^RPCMOUNTD_OPTIONS=.*(--port|-p) (\d+).*$/ and $rpc_mountd_port = $2; + $_ =~ /^RPCRQUOTAD_OPTIONS=.*(--port|-p) (\d+).*$/ and $rpc_rquotad_port = $2; + } + } + + my $ports = { statd_port => $statd_port, + lockd_tcp_port => $lockd_tcp_port, + lockd_udp_port => $lockd_udp_port, + rpc_mountd_port => $rpc_mountd_port, + rpc_rquotad_port => $rpc_rquotad_port, + }; + if (defined $statd_outgoing_port) { + $ports->{statd_outgoing_port} => $statd_outgoing_port, + } + $ports; +} + +sub list_nfs_ports { + my $ports = read_nfs_ports(); + + my $portlist = $ports->{lockd_tcp_port}. "/tcp " . $ports->{lockd_udp_port} . "/udp"; + if (defined $ports->{statd_outgoing_port} and $ports->{statd_outgoing_port} ne $ports->{statd_port}) { + $portlist .= " " . $ports->{statd_outgoing_port} . "/tcp " . $ports->{statd_outgoing_port} . "/udp"; + } + foreach (qw(statd_port rpc_mountd_port rpc_rquotad_port)) { + my $port = $ports->{$_}; + $portlist .= " $port/tcp $port/udp"; + } + # list of ports in shorewall format + $portlist; +} + +sub write_nfs_ports { + my ($ports) = @_; + # enabling fixed ports for NFS services + # nfs-common + my $lockd_options=""; + substInFile { + if ($ports->{statd_port}) { + my $port = $ports->{statd_port}; + s/^(STATD_OPTIONS)=$/$1="--port $port"/; + s/^(STATD_OPTIONS)="(.*)(--port \d+)(.*)"$/$1="$2--port $port$4"/; + s/^(STATD_OPTIONS)="(.*)(-p \d+)(.*)"$/$1="$2--port $port$4"/; + } + if ($ports->{lockd_tcp_port}) { + my $port = $ports->{lockd_tcp_port}; + s/^LOCKD_TCPPORT=.*/LOCKD_TCPPORT=$port/; + } + if ($ports->{lockd_udp_port}) { + my $port = $ports->{lockd_udp_port}; + s/^LOCKD_UDPPORT=.*/LOCKD_UDPPORT=$port/; + } + } "$::prefix/etc/sysconfig/nfs-common"; + # kernel-side configuration of nlockmgr + $lockd_options .= " nlm_tcpport=$ports->{lockd_tcp_port}" if $ports->{lockd_tcp_port}; + $lockd_options .= " nlm_udpport=$ports->{lockd_udp_port}" if $ports->{lockd_udp_port}; + if ($lockd_options ne "") { + output("$::prefix/etc/modprobe.d/lockd.drakx", "options lockd $lockd_options\n"); + } + # nfs-server + substInFile { + if ($ports->{rpc_mountd_port}) { + my $port = $ports->{rpc_mountd_port}; + s/^(RPCMOUNTD_OPTIONS)=$/$1="--port $port"/; + s/^(RPCMOUNTD_OPTIONS)="(.*)(--port \d+)(.*)"$/$1="$2--port $port$4"/; + s/^(RPCMOUNTD_OPTIONS)="(.*)(-p \d+)(.*)"$/$1="$2--port $port$4"/; + } + if ($ports->{rpc_rquotad_port}) { + my $port = $ports->{rpc_rquotad_port}; + s/^(RPCRQUOTAD_OPTIONS)=$/$1="--port $port"/; + s/^(RPCRQUOTAD_OPTIONS)="(.*)(--port \d+)(.*)"$/$1="$2--port $port$4"/; + s/^(RPCRQUOTAD_OPTIONS)="(.*)(-p \d+)(.*)"$/$1="$2--port $port$4"/; + } + } "$::prefix/etc/sysconfig/nfs-server"; +} + +1; diff --git a/lib/network/pxe.pm b/lib/network/pxe.pm new file mode 100644 index 0000000..2fecb8f --- /dev/null +++ b/lib/network/pxe.pm @@ -0,0 +1,286 @@ +package network::pxe; + +use common; +use network::tools; +use Xconfig::resolution_and_depth; + +our $tftp_root = "/var/lib/tftpboot"; +my $client_path = '/X86PC/linux'; +our $pxelinux_client_root = $tftp_root . $client_path; +our $pxelinux_images = $pxelinux_client_root . '/images'; +our $pxelinux_help_file = $pxelinux_client_root . '/help.txt'; +our $pxelinux_message_file = $pxelinux_client_root . '/messages'; +my $pxelinux_config_root = $pxelinux_client_root . '/pxelinux.cfg'; +our $pxelinux_config_file = $pxelinux_config_root . '/default'; +our $pxe_config_file = '/etc/pxe.conf'; + +my @global_pxelinux_settings = qw(PROMPT DEFAULT DISPLAY TIMEOUT F1); +my @append_settings = qw(initrd ramdisk_size vga display auto_install); +my @automatic_settings = qw(method interface network server directory); + +our %vga_bios_to_resolution = ( + 'normal' => "vga", + 'text' => "text", + '' => "automatic", + map { $_->{bios} => "$_->{X}x$_->{Y}" } grep { $_->{Depth} == 16 } Xconfig::resolution_and_depth::bios_vga_modes() + ); +our %vga_resolution_to_bios = reverse %vga_bios_to_resolution; + +sub read_pxelinux_help { + my ($help_file) = @_; + my %info; + foreach (cat_($help_file)) { + /^(\w+)\s*:\s*(.*)$/ and $info{$1} = $2; + } + \%info; +} + +sub read_pxelinux_conf { + my ($conf_file, $help_file) = @_; + my (%conf); + my $info = read_pxelinux_help($help_file); + my $entry = {}; + foreach (cat_($conf_file)) { + my $global = join('|', @global_pxelinux_settings); + if (/^($global)\s+(.*)/) { + $conf{lc($1)} = $2; + } elsif (/^label\s+(.*)/) { + $entry->{label} = $1; + } elsif (/^\s+LOCALBOOT\s+(\d+)/) { + $entry->{localboot} = $1; + } elsif (/^\s+KERNEL\s+(.*)/) { + $entry->{kernel} = $1; + } elsif (/^\s+APPEND\s+(.*)/) { + my @others; + foreach (split /\s+/, $1) { + my ($option, $value) = /^(.+?)(?:=(.*))?$/; + if (member($option, @append_settings)) { + $entry->{$option} = $value; + } elsif ($option eq 'automatic') { + foreach (split /,/, $value) { + my ($option, $value) = /^(.+?):(.+)$/; + $entry->{$option} = $value; + } + } else { + push @others, $_; + } + } + $entry->{others} = join(' ', @others); + } + if (exists $entry->{label} && (exists $entry->{localboot} || exists $entry->{kernel} && exists $entry->{initrd})) { + $entry->{info} = $info->{$entry->{label}}; + push @{$conf{entries}}, $entry; + $entry = {}; + } + } + \%conf; +} + + +sub list_pxelinux_labels { + my ($conf) = @_; + map { $_->{label} } @{$conf->{entries}}; +} + +sub write_pxelinux_conf { + my ($conf, $conf_file) = @_; + + output($conf_file, + join("\n", + "# DO NOT EDIT auto_generated by drakpxelinux.pl", + (map { $_ . ' ' . $conf->{lc($_)} } @global_pxelinux_settings), + '', + (map { + my $e = $_; + my $automatic = join(',', map { "$_:$e->{$_}" } grep { $e->{$_} } @automatic_settings); + ("label $e->{label}", + exists $e->{localboot} ? + " LOCALBOOT $e->{localboot}" : + (" KERNEL $e->{kernel}", + " APPEND " . join(' ', + (map { "$_=$e->{$_}" } grep { $e->{$_} } @append_settings), + if_($automatic, "automatic=$automatic"), + $e->{others})), + ''); + } @{$conf->{entries}}))); +} + +sub write_default_pxe_messages { + my ($net) = @_; + my $hostname = $net->{hostname} || chomp_(`hostname`); + output($pxelinux_message_file, <<EOF); + + Welcome to Mageia Linux PXE Server + Pxelinux + . .-----------------------------------. + /|\\ / Press F1 for available images \\ + /_|_\\ \\ Hosted by $hostname + \\ | / _ /'-----------------------------------' + \\|/ (') / + '. U / (O__ + . '. / (o_ (o_ (0_ //\\ + {o_ (o_ (o_ (o_ (o_ //\\ //\\ //\\ // ) + (')_ (`)_ (/)_ (/)_ (/)_ V_/_ V_/_ V_/_ V__/_ + --------------------------------------------------------- + + press F1 for help +EOF +} + +sub write_default_pxe_help() { + output($pxelinux_help_file, <<EOF); +Available images are: +--------------------- +local: local boot +EOF +} + +sub add_in_help { + my ($NAME, $INFO) = @_; + if (!any { /$NAME/ } cat_($pxelinux_help_file)) { + append_to_file($pxelinux_help_file, <<EOF); +$NAME : $INFO +EOF + + } else { + substInFile { + s/$NAME.*/$NAME : $INFO/; + } $pxelinux_help_file; + } +} + +sub change_label_in_help { + my ($NAMEOLD, $NEWNAME) = @_; + substInFile { + s/$NAMEOLD\s(.*)/$NEWNAME $1/; + } $pxelinux_help_file; +} + +# remove entry in help.txt +sub remove_in_help { + my ($NAME) = @_; + substInFile { + s/^$NAME\s:.*//x; + s/^\s*$//; + } $pxelinux_help_file; +} + +# adjust pxe confi with good value +sub write_pxe_conf { + my ($net, $interface) = @_; + if (!-f "$pxe_config_file.orig") { cp_af($pxe_config_file, "$pxe_config_file.orig") } + my $domainname = $net->{resolv}{domainname} || chomp_(`dnsdomainname`); + my $ip_address = network::tools::get_interface_ip_address($net, $interface); + + substInFile { + s/default_address.*/default_address=$ip_address/; + s/mtftp_address.*/mtftp_address=$ip_address/; + s/domain.*/domain=$domainname/; + } $pxe_config_file; +} + + +sub get_pxelinux_config_file_for_mac_address { + my ($mac_address) = @_; + #- 01 is the hardware type: Ethernet (ARP type 1) + $pxelinux_config_root . "/" . join('-', '01', split(/:/, $mac_address)); +} + +sub set_profile_for_mac_address { + my ($profile, $to_install, $mac_address) = @_; + if ($profile) { + symlinkf("profiles/" . ($to_install ? "install/" : "boot/") . $profile, get_pxelinux_config_file_for_mac_address($mac_address)); + } else { + unlink get_pxelinux_config_file_for_mac_address($mac_address); + } +} + +#- returns (profile_type, profile_name) +sub profile_from_file { + my ($file) = @_; + $file =~ m!(?:^|/)profiles/(\w+)/(.*)?$!; +} + +sub read_profiles() { + my %profiles_conf; + + foreach (all($pxelinux_config_root)) { + my $file = $pxelinux_config_root . '/' . $_; + if (-l $file && /^01(?:-([0-9a-z]{2}))+$/) { + #- per MAC address settings + #- the filename looks like 01-aa-bb-cc-dd-ee-ff + #- where AA:BB:CC:DD:EE:FF is the MAC address + my ($type, $name) = profile_from_file(readlink($file)); + tr/-/:/; + my $mac_address = substr($_, 3); + $profiles_conf{per_mac}{$mac_address} = { profile => $name, to_install => $type eq 'install' }; + } + } + + foreach my $type (qw(boot install)) { + my $root = $pxelinux_config_root . '/profiles/' . $type; + mkdir_p($root); + $profiles_conf{profiles}{$type}{$_} = 1 foreach all($root); + } + + \%profiles_conf; +} + +#- returns (pxelinux entries file, help file) +sub get_pxelinux_profile_path { + my ($profile, $type) = @_; + my $root = $pxelinux_config_root . '/profiles/' . $type; + "$root/$profile", "$root/help-$profile.txt"; +} + +sub list_profiles { + my ($profiles_conf) = @_; + sort(uniq(map { keys %{$profiles_conf->{profiles}{$_}} } qw(boot install))); +} + +sub profile_exists { + my ($profiles_conf, $profile) = @_; + member($profile, network::pxe::list_profiles($profiles_conf)); +} + +sub find_next_profile_name { + my ($profiles_conf, $prefix) = @_; + my $i; + /^$prefix(\d*)$/ && $1 >= $i and $i = $1 + 1 foreach network::pxe::list_profiles($profiles_conf); + "$prefix$i"; +} + +sub add_empty_profile { + my ($profiles_conf, $profile, $to_install) = @_; + $to_install and $profiles_conf->{profiles}{install}{$profile} = 1; + $profiles_conf->{profiles}{boot}{$profile} = 1; +} + +sub copy_profile_for_type { + my ($profile, $clone, $type) = @_; + my ($pxe, $help) = get_pxelinux_profile_path($profile, $type); + my ($clone_pxe, $clone_help) = get_pxelinux_profile_path($clone, $type); + -r $pxe and cp_f($pxe, $clone_pxe); + -r $help and cp_f($help, $clone_help); +} + +sub clone_profile { + my ($profiles_conf, $profile) = @_; + my $clone = find_next_profile_name($profiles_conf, $profile); + if (exists $profiles_conf->{profiles}{install}{$profile}) { + $profiles_conf->{profiles}{install}{$clone} = 1; + copy_profile_for_type($profile, $clone, 'install'); + } + $profiles_conf->{profiles}{boot}{$clone} = 1; + copy_profile_for_type($profile, $clone, 'boot'); +} + +sub remove_profile { + my ($profiles_conf, $profile) = @_; + foreach my $type (qw(boot install)) { + delete $profiles_conf->{profiles}{$type}{$profile}; + unlink(get_pxelinux_profile_path($profile, $type)); + } +} + +1; diff --git a/lib/network/rfswitch.pm b/lib/network/rfswitch.pm new file mode 100644 index 0000000..4617990 --- /dev/null +++ b/lib/network/rfswitch.pm @@ -0,0 +1,38 @@ +package network::rfswitch; + +use strict; +use MDK::Common; +use detect_devices; + +my $conf_file = "/etc/modprobe.d/rfswitch.conf"; + +my @settings = ( + { + match => sub { + # CL56, with buggy BIOS + detect_devices::dmidecode_category('BIOS')->{Vendor} eq 'COMPAL' && + detect_devices::dmidecode_category('System')->{'Product Name'} eq '<BAD INDEX>'; + }, + module => 'acerhk', + options => 'usedritek=1 autowlan=1 force_series=290', + install => 'echo 1 > /proc/driver/acerhk/wirelessled', + remove => 'echo 0 > /proc/driver/acerhk/wirelessled', + }, +); + +sub configure() { + my $setting = find { $_->{match}->() } @settings; + if ($setting) { + output_p($::prefix . $conf_file, + join("\n", + if_($setting->{options}, "options $setting->{module} $setting->{options}"), + if_($setting->{install}, "install $setting->{module} /sbin/modprobe --first-time --ignore-install $setting->{module} && $setting->{install}"), + if_($setting->{remove}, "remove $setting->{module} $setting->{remove}; /sbin/modprobe -r --ignore-remove $setting->{module}"), + "", + )); + require modules; + modules::set_preload_modules('rfswitch', $setting->{module}); + } +} + +1; diff --git a/lib/network/shorewall.pm b/lib/network/shorewall.pm new file mode 100644 index 0000000..46bafed --- /dev/null +++ b/lib/network/shorewall.pm @@ -0,0 +1,246 @@ +package network::shorewall; # $Id: shorewall.pm 254244 2009-03-18 22:54:32Z eugeni $ + +use detect_devices; +use network::network; +use run_program; +use common; +use log; + +my $shorewall_root = "/etc/shorewall"; +our $firewall_icon = $::isInstall ? 'banner-security' : '/usr/share/mcc/themes/default/firewall-mdk.png'; + +sub check_iptables() { + -f "$::prefix/etc/sysconfig/iptables" || + $::isStandalone && do { + system('modprobe iptable_nat'); + -x '/sbin/iptables' && listlength(`/sbin/iptables -t nat -nL`) > 8; + }; +} + +sub set_config_file { + my ($file, @l) = @_; + + my $done; + substInFile { + if (!$done && (/^#LAST LINE/ || eof)) { + $_ = join('', map { join("\t", @$_) . "\n" } @l) . $_; + $done = 1; + } else { + $_ = '' if /^[^#]/; + } + } "$::prefix${shorewall_root}/$file"; +} + +sub get_config_file { + my ($file) = @_; + map { [ split ' ' ] } grep { !/^#/ } cat_("$::prefix${shorewall_root}/$file"); +} + +sub set_in_file { + my ($file, $enabled, @list) = @_; + my $done; + substInFile { + foreach my $l (@list) { s|^$l\n|| } + if (!$done && $enabled && (/^#LAST LINE/ || eof)) { + $_ = join('', map { "$_\n" } @list) . $_; + $done = 1; + } + } "$::prefix/etc/shorewall/$file"; +} + +sub dev_to_shorewall { + my ($dev) = @_; + $dev =~ /^ippp/ && "ippp+" || + $dev =~ /^ppp/ && "ppp+" || + $dev; +} + +sub get_net_zone_interfaces { + my ($_net, $all_intf) = @_; + #- read shorewall configuration first + my @interfaces = map { $_->[1] } grep { $_->[0] eq 'net' } get_config_file('interfaces'); + #- else try to find the best interface available + @interfaces ? @interfaces : @{$all_intf || []}; +} + +sub get_zones { + my ($conf, $o_in) = @_; + my $net = {}; + network::network::read_net_conf($net); + #- find all interfaces but alias interfaces + my @all_intf = grep { !/:/ } uniq(keys(%{$net->{ifcfg}}), detect_devices::get_net_interfaces()); + my %net_zone = map { $_ => undef } @all_intf; + $net_zone{$_} = 1 foreach get_net_zone_interfaces($net, \@all_intf); + $o_in and $o_in->ask_from_({ + title => N("Firewall configuration"), + icon => $firewall_icon, + messages => N("Please select the interfaces that will be protected by the firewall. + +All interfaces directly connected to Internet should be selected, +while interfaces connected to a local network may be unselected. + +If you intend to use Mageia Internet Connection sharing, +unselect interfaces which will be connected to local network. + +Which interfaces should be protected? +"), + }, [ + map { + { text => network::tools::get_interface_description($net, $_), val => \$net_zone{$_}, type => 'bool' }; + } (sort keys %net_zone) ]); + ($conf->{net_zone}, $conf->{loc_zone}) = partition { $net_zone{$_} } keys %net_zone; +} + +sub add_interface_to_net_zone { + my ($conf, $interface) = @_; + if (!member($interface, @{$conf->{net_zone}})) { + push @{$conf->{net_zone}}, $interface; + @{$conf->{loc_zone}} = grep { $_ ne $interface } @{$conf->{loc_zone}}; + } +} + +sub read { + my ($o_in) = @_; + #- read old rules file if config is not moved to rules.drakx yet + my @rules = get_config_file(-f "$::prefix${shorewall_root}/rules.drakx" ? 'rules.drakx' : 'rules'); + my %conf = (disabled => !glob_("$::prefix/etc/rc3.d/S*shorewall"), + ports => join(' ', map { + my $e = $_; + map { "$_/$e->[3]" } split(',', $e->[4]); + } grep { $_->[0] eq 'ACCEPT' && $_->[1] eq 'net' } @rules), + ); + push @{$conf{accept_local_users}{$_->[4]}}, $_->[8] foreach grep { $_->[0] eq 'ACCEPT+' } @rules; + $conf{redirects}{$_->[3]}{$_->[4]} = $_->[2] foreach grep { $_->[0] eq 'REDIRECT' } @rules; + + if (my ($e) = get_config_file('masq')) { + ($conf{masq}{net_interface}, $conf{masq}{subnet}) = @$e; + } + + my @policy = get_config_file('policy'); + $conf{log_net_drop} = @policy ? (any { $_->[0] eq 'net' && $_->[1] eq 'all' && $_->[2] eq 'DROP' && $_->[3] } @policy) : 1; + + get_zones(\%conf, $o_in); + get_config_file('zones') && \%conf; +} + +sub ports_by_proto { + my ($ports) = @_; + my %ports_by_proto; + foreach (split ' ', $ports) { + m!^(\d+(?::\d+)?)/(udp|tcp|icmp)$! or die "bad port $_\n"; + push @{$ports_by_proto{$2}}, $1; + } + \%ports_by_proto; +} + +sub upgrade_to_shorewall3() { + #- the 'FW' option has been removed from shorewall.conf as of shorewall 3.0 + my $ipsecfile_ok; + substInFile { + undef $_ if /^\s*FW=/; + if ((/^\s*IPSECFILE=/ || eof) && !$ipsecfile_ok) { + $ipsecfile_ok = 1; + $_ = "IPSECFILE=zones\n"; + } + } "$::prefix${shorewall_root}/shorewall.conf"; +} + +sub write { + my ($conf, $o_in) = @_; + my $use_pptp = any { /^ppp/ && cat_("$::prefix/etc/ppp/peers/$_") =~ /pptp/ } @{$conf->{net_zone}}; + my $ports_by_proto = ports_by_proto($conf->{ports}); + my $has_loc_zone = to_bool(@{$conf->{loc_zone} || []}); + + my ($include_drakx, $other_rules) = partition { $_ eq "INCLUDE\trules.drakx\n" } grep { !/^#/ } cat_("$::prefix${shorewall_root}/rules"); + #- warn if the config is already in rules.drakx and additionnal rules are configured + if (!is_empty_array_ref($include_drakx) && !is_empty_array_ref($other_rules)) { + my %actions = ( + keep => N("Keep custom rules"), + drop => N("Drop custom rules"), + ); + my $action = 'keep'; + !$o_in || $o_in->ask_from_( + { + messages => N("Your firewall configuration has been manually edited and contains +rules that may conflict with the configuration that has just been set up. +What do you want to do?"), + title => N("Firewall"), + icon => 'banner-security', + }, + [ { val => \$action, type => 'list', list => [ 'keep', 'drop' ], format => sub { $actions{$_[0]} } } ]) or return; + #- reset the rules files if the user has chosen to drop modifications + undef $include_drakx if $action eq 'drop'; + } + + my $interface_settings = sub { + my ($zone, $interface) = @_; + [ $zone, $interface, 'detect', if_(detect_devices::is_bridge_interface($interface), 'routeback') ]; + }; + + set_config_file("zones", + [ 'net', 'ipv4' ], + if_($has_loc_zone, [ 'loc', 'ipv4' ]), + [ 'fw', 'firewall' ], + ); + set_config_file('interfaces', + (map { $interface_settings->('net', $_) } @{$conf->{net_zone}}), + (map { $interface_settings->('loc', $_) } @{$conf->{loc_zone} || []}), + ); + set_config_file('policy', + if_($has_loc_zone, [ 'loc', 'net', 'ACCEPT' ], [ 'loc', 'fw', 'ACCEPT' ], [ 'fw', 'loc', 'ACCEPT' ]), + [ 'fw', 'net', 'ACCEPT' ], + [ 'net', 'all', 'DROP', if_($conf->{log_net_drop}, 'info') ], + [ 'all', 'all', 'REJECT', 'info' ], + ); + if (is_empty_array_ref($include_drakx)) { + #- make sure the rules.drakx config is read, erasing user modifications + set_config_file('rules', [ 'INCLUDE', 'rules.drakx' ]); + } + output_with_perm("$::prefix${shorewall_root}/" . 'rules.drakx', 0600, map { join("\t", @$_) . "\n" } ( + if_($use_pptp, [ 'ACCEPT', 'fw', 'loc:10.0.0.138', 'tcp', '1723' ]), + if_($use_pptp, [ 'ACCEPT', 'fw', 'loc:10.0.0.138', 'gre' ]), + (map_each { [ 'ACCEPT', 'net', 'fw', $::a, join(',', @$::b), '-' ] } %$ports_by_proto), + (map_each { + if_($::b, map { [ 'ACCEPT+', 'fw', 'net', 'tcp', $::a, '-', '-', '-', $_ ] } @{$::b}); + } %{$conf->{accept_local_users}}), + (map { + my $proto = $_; + #- WARNING: won't redirect ports from the firewall system if a local zone exists + #- set redirect_fw_only to workaround + map_each { + map { [ 'REDIRECT', $_, $::b, $proto, $::a, '-' ] } 'fw', if_($has_loc_zone, 'loc'); + } %{$conf->{redirects}{$proto}}; + } keys %{$conf->{redirects}}), + )); + set_config_file('masq', if_(exists $conf->{masq}, [ $conf->{masq}{net_interface}, $conf->{masq}{subnet} ])); + + upgrade_to_shorewall3(); + + require services; + if ($conf->{disabled}) { + services::disable('shorewall', $::isInstall); + run_program::rooted($::prefix, '/sbin/shorewall', 'clear') unless $::isInstall; + } else { + services::enable('shorewall', $::isInstall); + } +} + +sub set_redirected_ports { + my ($conf, $proto, $dest, @ports) = @_; + if (@ports) { + $conf->{redirects}{$proto}{$_} = $dest foreach @ports; + } else { + my $r = $conf->{redirects}{$proto}; + @ports = grep { $r->{$_} eq $dest } keys %$r; + delete $r->{$_} foreach @ports; + } +} + +sub update_interfaces_list { + my ($o_intf) = @_; + $o_intf && member($o_intf, map { $_->[1] } get_config_file('interfaces')) and return; + my $shorewall = network::shorewall::read(); + $shorewall && !$shorewall->{disabled} and network::shorewall::write($shorewall); +} + +1; diff --git a/lib/network/signal_strength.pm b/lib/network/signal_strength.pm new file mode 100644 index 0000000..19e119c --- /dev/null +++ b/lib/network/signal_strength.pm @@ -0,0 +1,14 @@ +package network::signal_strength; + +use common; +use ugtk2; + +my %pixbufs; + +sub get_strength_icon { + my ($network) = @_; + my $approx = 20 + min(80, int($network->{signal_strength}/20)*20); + return $pixbufs{$approx} ||= ugtk2::gtkcreate_pixbuf('wifi-' . sprintf('%03d', $approx)); +} + +1; diff --git a/lib/network/squid.pm b/lib/network/squid.pm new file mode 100644 index 0000000..427bce3 --- /dev/null +++ b/lib/network/squid.pm @@ -0,0 +1,74 @@ +package network::squid; + +use strict; +use common; + +our $squid_conf_file = "$::prefix/etc/squid/squid.conf"; + +sub read_squid_conf { + my ($o_file) = @_; + my $s = cat_($o_file || $squid_conf_file); + { http_port => [ $s =~ /^\s*http_port\s+(?:\S+:)?(\d+)\b/mg ], + cache_size => [ if_($s =~ /^\s*cache_dir diskd\s+(.*)/mg, split(' ', $1)) ], + admin_mail => [ if_($s =~ /^\s*err_html_text\s+(.*)/mg, split(' ', $1)) ] }; +} + +sub write_squid_conf { + my ($squid_conf, $intf, $internal_domain_name) = @_; + + renamef($squid_conf_file, "$squid_conf_file.old"); + my $prefix = network::network::netmask_to_vlsm($intf->{NETMASK}); + output($squid_conf_file, qq( +http_port $squid_conf->{http_port}[0] transparent +hierarchy_stoplist cgi-bin ? +acl QUERY urlpath_regex cgi-bin \\? +no_cache deny QUERY +cache_dir diskd /var/spool/squid $squid_conf->{cache_size}[1] 16 256 +cache_store_log none +auth_param basic children 5 +auth_param basic realm Squid proxy-caching web server +auth_param basic credentialsttl 2 hours +refresh_pattern ^ftp: 1440 20% 10080 +refresh_pattern ^gopher: 1440 0% 1440 +refresh_pattern . 0 20% 4320 +half_closed_clients off +acl manager proto cache_object +acl localhost src 127.0.0.0/8 +acl to_localhost dst 127.0.0.0/8 +acl localnet src 10.0.0.0/8 # RFC1918 possible internal network +acl localnet src 172.16.0.0/12 # RFC1918 possible internal network +acl localnet src 192.168.0.0/16 # RFC1918 possible internal network +acl SSL_ports port 443 563 +acl Safe_ports port 80 # http +acl Safe_ports port 21 # ftp +acl Safe_ports port 443 563 # https, snews +acl Safe_ports port 70 # gopher +acl Safe_ports port 210 # wais +acl Safe_ports port 1025-65535 # unregistered ports +acl Safe_ports port 280 # http-mgmt +acl Safe_ports port 488 # gss-http +acl Safe_ports port 591 # filemaker +acl Safe_ports port 777 # multiling http +acl CONNECT method CONNECT +http_access allow manager localhost +http_access deny manager +http_access deny !Safe_ports +http_access deny CONNECT !SSL_ports +http_access deny to_localhost +acl mynetwork src $intf->{NETWORK}/$prefix +http_access allow mynetwork +http_access allow localnet +http_access allow localhost +http_reply_access allow all +icp_access allow all +visible_hostname $squid_conf->{visible_hostname}[0] +append_domain .$internal_domain_name +err_html_text $squid_conf->{admin_mail}[0] +deny_info ERR_CUSTOM_ACCESS_DENIED all +memory_pools off +coredump_dir /var/spool/squid +ie_refresh on +)) if !$::testing; +} + +1; diff --git a/lib/network/test.pm b/lib/network/test.pm new file mode 100644 index 0000000..0bd1231 --- /dev/null +++ b/lib/network/test.pm @@ -0,0 +1,161 @@ +package network::test; # $Id: test.pm 219797 2007-05-25 15:39:46Z blino $ + +use strict; +use common; +use run_program; +use Socket; + +sub new { + my ($class, $o_hostname) = @_; + bless { + hostname => $o_hostname || "www.mageia.org" + }, $class; +} + +#- launch synchronous test, will hang until the test finishes +sub test_synchronous { + my ($o) = @_; + ($o->{address}, $o->{ping}) = resolve_and_ping($o->{hostname}); + $o->{done} = 1; +} + +#- launch asynchronous test, will not hang +sub start { + my ($o) = @_; + $o->{done} = 0; + $o->{kid} = bg_command->new(sub { + my ($address, $ping) = resolve_and_ping($o->{hostname}); + print "$address|$ping\n"; + }); +} + +#- abort asynchronous test +sub abort { + my ($o) = @_; + if ($o->{kid}) { + kill -9, $o->{kid}{pid}; + undef $o->{kid}; + } +} + +#- returns a true value if the test is finished, usefull for asynchronous tests +sub is_done { + my ($o) = @_; + $o->update_status; + to_bool($o->{done}); +} + +#- return a true value if the connection works (hostname resolution and ping) +sub is_connected { + my ($o) = @_; + to_bool(defined($o->{hostname}) && defined($o->{ping})); +} + +#- get hostname used in test for resolution and ping +sub get_hostname { + my ($o) = @_; + $o->{hostname}; +} + +#- get resolved address (if any) of given hostname +sub get_address { + my ($o) = @_; + $o->{address}; +} + +#- get ping (if any) to given hostname +sub get_ping { + my ($o) = @_; + $o->{ping}; +} + +sub resolve_and_ping { + my ($hostname) = @_; + require Net::Ping; + require Time::HiRes; + my $p; + if ($>) { + $p = Net::Ping->new('tcp'); + # Try connecting to the www port instead of the echo port + $p->{port_num} = getservbyname('http', 'tcp'); + } else { + $p = Net::Ping->new('icmp'); + } + $p->hires; #- get ping as float + #- default timeout is 5 seconds + my ($ret, $ping, $address) = $p->ping($hostname, 5); + if ($ret) { + return $address, $ping; + } elsif (defined($ret)) { + return $address; + } +} + +sub update_status { + my ($o) = @_; + if ($o->{kid}) { + my $fd = $o->{kid}{fd}; + common::nonblock($fd); + local $| = 1; + if (defined(my $output = <$fd>)) { + ($o->{address}, $o->{ping}) = $output =~ /^([\d\.]+)\|([\d\.,]+)*$/; + $o->{done} = 1; + undef $o->{kid}; + } + } +} + +1; + +=head1 network::test + +=head2 Test synchronously + +resolve and get ping to hostname from command line if given, else to www.mageia.org + + use lib qw(/usr/lib/libDrakX); + use network::test; + + my $net_test = network::test->new($ARGV[0]); + $net_test->test_synchronous; + + my $is_connected = $net_test->is_connected; + my $hostname = $net_test->get_hostname; + my $address = $net_test->get_address; + my $ping = $net_test->get_ping; + + print "connected: $is_connected + host: $hostname + resolved host: $address + ping to host: $ping + "; + +=head2 Test asynchronously + +resolve and get ping to hostname from command line if given, else to Mageia + +prints a "." every 10 miliseconds during connection test + + use lib qw(/usr/lib/libDrakX); + use network::test; + + my $net_test = network::test->new($ARGV[0]); + $net_test->start; + + do { + print ".\n"; + select(undef, undef, undef, 0.01); + } while !$net_test->is_done; + + my $is_connected = $net_test->is_connected; + my $hostname = $net_test->get_hostname; + my $address = $net_test->get_address; + my $ping = $net_test->get_ping; + + print "connected: $is_connected + host: $hostname + resolved host: $address + ping to host: $ping + "; + +=cut diff --git a/lib/network/thirdparty.pm b/lib/network/thirdparty.pm new file mode 100644 index 0000000..8fd48ab --- /dev/null +++ b/lib/network/thirdparty.pm @@ -0,0 +1,385 @@ +package network::thirdparty; + +use strict; +use common; +use detect_devices; +use run_program; +use services; +use fs::get; +use fs; +use log; +use modules; +use list_modules; + +#- using bsd_glob() since glob("/DONT_EXIST") return "/DONT_EXIST" instead of () (and we don't want this) +use File::Glob ':glob'; + +#- network_settings is an hash of categories (rtc, dsl, wireless, ...) +#- each category is an hash of device settings + +#- a device settings element must have the following fields: +#- o matching: +#- specify if this settings element matches a driver +#- can be a regexp, array ref or Perl code (parameters: driver) +#- o description: +#- full name of the device +#- o name: name used by the packages + +#- the following fields are optional: +#- o url: +#- url where the user can find tools/drivers/firmwares for this device +#- o device: +#- device in /dev to be configured +#- o post: +#- command to be run after all packages are installed +#- can be a shell command or Perl code +#- o restart_service: +#- if exists but not 1, name of the service to be restarted +#- if 1, specify that the service named by the name field should be restarted +#- o tools: +#- hash of the tools settings +#- test_file field required +#- if package field doesn't exist, 'name' is used +#- o kernel_module: +#- if exists but not 1, hash of the module settings +#- if 1, kernel modules are needed and use the name field +#- (name-kernel or dkms-name) +#- o firmware: +#- hash of the firmware settings +#- test_file field required +#- if package field doesn't exist, 'name-firmware' is used + +#- hash of package settings structure: +#- o package: +#- name of the package to be installed for these device +#- o test_file: +#- file used to test if the package is installed +#- o prefix: +#- path of the files that are tested +#- o links: +#- useful links for this device +#- can be a single link or array ref +#- o user_install: +#- function to call if the package installation fails +#- o explanations: +#- additionnal text to display if the installation fails +#- o no_distro_package: +#- 1 if the package isn't available in the official distribution +# (because of missing distribution rights for example) + +our $firmware_directory = "/lib/firmware"; +our @thirdparty_types = qw(kernel_module tools firmware); + +sub device_get_packages { + my ($settings, $component, $o_default) = @_; + $settings->{$component} or return; + my $package; + if (ref $settings->{$component} eq 'HASH') { + $package = $settings->{$component}{package} || 1; + } else { + $package = $settings->{$component}; + } + $package == 1 ? $o_default || $settings->{name} : ref $package eq 'ARRAY' ? @$package : $package; +} + +sub device_get_option { + my ($settings, $option, $o_default) = @_; + $settings->{$option} or return; + my $value = $settings->{$option}; + $value == 1 ? $o_default || $settings->{name} : $value; +} + +sub component_get_option { + my ($settings, $component, $option) = @_; + ref $settings->{$component} eq 'HASH' && $settings->{$component}{$option} || $settings->{$option}; +} + +sub find_settings { + my ($settings_list, $driver) = @_; + find { + my $match = $_->{matching} || $_->{name}; + my $type = ref $match; + $type eq 'Regexp' && $driver =~ $match || + $type eq 'CODE' && $match->($driver) || + $type eq 'ARRAY' && member($driver, @$match) || + $driver eq $match; + } @$settings_list; +} + +sub device_run_command { + my ($settings, $driver, $component) = @_; + my $command = $settings->{$component} or return; + + if (ref $command eq 'CODE') { + $command->($driver); + } else { + log::explanations("Running $component command $command"); + run_program::rooted($::prefix, $command); + } +} + +sub warn_not_installed { + my ($in, @packages) = @_; + $in->ask_warn(N("Error"), N("Could not install the packages (%s)!", join(', ', @packages))); +} + +sub get_checked_element { + my ($settings, $driver, $component) = @_; + $component eq 'firmware' ? + get_firmware_path($settings) : + $component eq 'kernel_module' ? + $driver : + ref $settings->{$component} eq 'HASH' && $settings->{$component}{test_file}; +} + +sub warn_not_found { + my ($in, $settings, $driver, $component, @packages) = @_; + my %opt; + $opt{$_} = component_get_option($settings, $component, $_) foreach qw(url explanations no_distro_package no_package); + my $checked = get_checked_element($settings, $driver, $component); + my $component_name = ref $settings->{$component} eq 'HASH' && translate($settings->{$component}{component_name}) || $component; + $in->ask_warn(N("Error"), + join(" ", + ($opt{no_package} ? + N("Some components (%s) are required but aren't available for %s hardware.", $component_name, $settings->{name}) : + N("Some packages (%s) are required but aren't available.", join(', ', @packages))), + join("\n\n", + if_(!$opt{no_distro_package} && !$opt{no_package}, + #-PO: first argument is a list of Mageia distributions + #-PO: second argument is a package media name + N("These packages can be found in %s, or in the official %s package repository.", "non-free"), + ), + if_($checked, N("The following component is missing: %s", $checked)), + if_($opt{explanations}, translate($opt{explanations})), + if_($opt{url}, N("The required files can also be installed from this URL: +%s", $opt{url})), + ))); +} + +sub is_file_installed { + my ($settings, $component) = @_; + my $file = ref $settings->{$component} eq 'HASH' && $settings->{$component}{test_file}; + $file && -e "$::prefix$file"; +} + +sub is_module_installed { + my ($settings, $driver) = @_; + my $module = ref $settings->{kernel_module} eq 'HASH' && $settings->{kernel_module}{test_file} || $driver; + #- reload modules.dep so that newly added dkms modules are recognized + list_modules::load_default_moddeps(); + #- FIXME: modules::module_is_available() won't use the chroot modules.dep in installer + modules::module_is_available($module); +} + +sub get_firmware_path { + my ($settings) = @_; + my $wildcard = ref $settings->{firmware} eq 'HASH' && $settings->{firmware}{test_file} or return; + my $path = $settings->{firmware}{prefix} || $firmware_directory; + "$::prefix$path/$wildcard"; +} + +sub is_firmware_installed { + my ($settings) = @_; + my $pattern = get_firmware_path($settings) or return; + scalar bsd_glob($pattern, undef); +} + +sub extract_firmware { + my ($settings, $in) = @_; + my $choice; + $in->ask_from('', N("Firmware files are required for this device."), + [ { type => "list", val => \$choice, format => \&translate, + list => [ + if_(exists $settings->{firmware}{extract}{floppy_source}, N_("Use a floppy")), + if_(exists $settings->{firmware}{extract}{windows_source}, N_("Use my Windows partition")), + N_("Select file") + ] } ]) or return; + my ($h, $source); + if ($choice eq N_("Use a floppy")) { + $source = $settings->{firmware}{extract}{floppy_source}; + $h = find_file_on_floppy($in, $source); + } elsif ($choice eq N_("Use my Windows partition")) { + $source = $settings->{firmware}{extract}{windows_source}; + $h = find_file_on_windows_system($in, $source); + } else { + $source = $settings->{firmware}{extract}{default_source}; + $h = { file => $in->ask_file(N("Please select the firmware file (for example: %s)", basename($source)), dirname($source)) }; + } + if (!-e $h->{file}) { + log::explanations("Unable to find firmware file (tried to find $source."); + return; + } + + if ($settings->{firmware}{extract}{name}) { + $in->do_pkgs->ensure_is_installed($settings->{firmware}{extract}{name}, $settings->{firmware}{extract}{test_file}) or return; + } + $settings->{firmware}{extract}{run}->($h->{file}); + 1; +} + +sub find_file_on_windows_system { + my ($in, $file) = @_; + my $source; + require fsedit; + my $all_hds = fsedit::get_hds(); + fs::get_info_from_fstab($all_hds); + if (my $part = find { $_->{device_windobe} eq 'C' } fs::get::fstab($all_hds)) { + foreach (qw(windows/system winnt/system windows/system32/drivers winnt/system32/drivers)) { + -d $_ and $source = first(bsd_glob("$part->{mntpoint}/$_/$file", undef)) and last; + } + $source or $in->ask_warn(N("Error"), N("Unable to find \"%s\" on your Windows system!", $file)); + } else { + $in->ask_warn(N("Error"), N("No Windows system has been detected!")); + } + { file => $source }; +} + +sub find_file_on_floppy { + my ($in, $file) = @_; + my $floppy = detect_devices::floppy(); + my $mountpoint = '/media/floppy'; + my $h; + $in->ask_okcancel(N("Insert floppy"), + N("Insert a FAT formatted floppy in drive %s with %s in root directory and press %s", $floppy, $file, N("Next"))) or return; + if (eval { fs::mount::mount(devices::make($floppy), $mountpoint, 'vfat', 'readonly'); 1 }) { + log::explanations("Mounting floppy device $floppy in $mountpoint"); + $h = before_leaving { fs::mount::umount($mountpoint) }; + if ($h->{file} = first(bsd_glob("$mountpoint/$file", undef))) { + log::explanations("Found $h->{file} on floppy device"); + } else { + log::explanations("Unabled to find $file on floppy device"); + } + } else { + $in->ask_warn(N("Error"), N("Floppy access error, unable to mount device %s", $floppy)); + log::explanations("Unable to mount floppy device $floppy"); + } + $h; +} + +sub get_required_packages { + my ($type, $settings) = @_; + device_get_packages($settings, $type, if_($type eq 'firmware', "$settings->{name}-firmware")); +} + +sub check_installed { + my ($type, $settings, $driver) = @_; + $type eq 'kernel_module' ? + is_module_installed($settings, $driver) : + $type eq 'firmware' ? + is_firmware_installed($settings) : + is_file_installed($settings, $type); +} + +sub get_available_packages { + my ($type, $do_pkgs, @names) = @_; + if ($type eq 'kernel_module') { + return map { my $l = $do_pkgs->check_kernel_module_packages($_); $l ? @$l : () } @names; + } else { + return $do_pkgs->is_available(@names); + } +} + +sub user_install { + my ($type, $settings, $in) = @_; + if ($type eq 'firmware') { + ref $settings->{$type} eq 'HASH' or return; + if ($settings->{$type}{extract}) { + extract_firmware($settings, $in); + } else { + my $f = $settings->{$type}{user_install}; + $f && $f->($settings, $in); + } + } else { + my $f = ref $settings->{$type} eq 'HASH' && $settings->{$type}{user_install}; + $f && $f->($settings, $in); + } +} + +sub install_packages { + my ($in, $settings, $driver, $component, @packages) = @_; + + unless (@packages) { + log::explanations(qq(No $component package for module "$driver" is required, skipping)); + return 1; + } + + if (check_installed($component, $settings, $driver)) { + $settings->{old_status}{$component} = 1; + log::explanations(qq(Required $component package for module "$driver" is already installed, skipping)); + return 1; + } + + my $optional = ref $settings->{$component} eq 'HASH' && $settings->{$component}{optional}; + if (my @available = get_available_packages($component, $in->do_pkgs, @packages)) { + log::explanations("Installing thirdparty packages ($component) " . join(', ', @available)); + if ($in->do_pkgs->install(@available) && check_installed($component, $settings, $driver)) { + return 1; + } elsif (!$optional) { + warn_not_installed($in, @available); + } + } + return 1 if $optional; + log::explanations("Thirdparty package @packages ($component) is required but not available"); + + 0; +} + +sub install_components { + my ($in, $settings, $driver, @components) = @_; + + foreach my $component (@components) { + my @packages = get_required_packages($component, $settings); + if (!component_get_option($settings, $component, 'no_package')) { + install_packages($in, $settings, $driver, $component, @packages) and next; + } + + unless (user_install($component, $settings, $in)) { + warn_not_found($in, $settings, $driver, $component, @packages); + return; + } + } + + 1; +} + +sub apply_settings { + my ($in, $category, $settings_list, $driver) = @_; + + my $settings = find_settings($settings_list, $driver); + if ($settings) { + log::explanations(qq(Found settings for driver "$driver" in category "$category")); + + my $wait = $in->wait_message(N("Please wait"), N("Looking for required software and drivers...")); + + install_components($in, $settings, $driver, @thirdparty_types) or return; + + if (!$settings->{no_module_reload}) { + if (exists $settings->{firmware} && !$settings->{old_status}{firmware}) { + log::explanations("Reloading module $driver"); + eval { modules::unload($driver) }; + } else { + log::explanations("Loading module $driver"); + } + eval { modules::load($driver) }; + } + + undef $wait; + $wait = $in->wait_message(N("Please wait"), N("Please wait, running device configuration commands...")); + device_run_command($settings, $driver, 'post'); + + if (my $service = device_get_option($settings, 'restart_service')) { + log::explanations("Restarting service $service"); + services::restart_or_start($service); + } + + $settings->{sleep} and sleep $settings->{sleep}; + + log::explanations(qq(Settings for driver "$driver" applied)); + } else { + log::explanations(qq(No settings found for driver "$driver" in category "$category")); + } + + $settings || {}; +} + +1; diff --git a/lib/network/tools.pm b/lib/network/tools.pm new file mode 100644 index 0000000..60eeb8b --- /dev/null +++ b/lib/network/tools.pm @@ -0,0 +1,278 @@ +package network::tools; # $Id: tools.pm 253976 2009-03-13 10:57:55Z eugeni $ + +use strict; +use common; +use run_program; +use c; +use Socket; + +sub write_secret_backend { + my ($login, $password) = @_; + require network::connection::ppp; + network::connection::ppp::write_secrets({ access => { login => $login, password => $password } }); +} + +sub passwd_by_login { + my ($login) = @_; + require network::connection::ppp; + network::connection::ppp::get_secret(undef, $login); +} + +sub run_interface_command { + my ($command, $intf, $detach) = @_; + my @command = + !$> || system("/usr/sbin/usernetctl $intf report") == 0 ? + ($command, $intf, if_(!$::isInstall, "daemon")) : + common::wrap_command_for_root($command, $intf); + run_program::raw({ detach => $detach, root => $::prefix }, @command); +} + +sub start_interface { + my ($intf, $detach) = @_; + run_interface_command('/sbin/ifup', $intf, $detach); +} + +sub stop_interface { + my ($intf, $detach) = @_; + run_interface_command('/sbin/ifdown', $intf, $detach); +} + +sub start_net_interface { + my ($net, $detach) = @_; + start_interface($net->{net_interface}, $detach); +} + +sub stop_net_interface { + my ($net, $detach) = @_; + stop_interface($net->{net_interface}, $detach); +} + +sub connected() { gethostbyname("www.mageia.org") ? 1 : 0 } + +# request a ref on a bg_connect and a ref on a scalar +sub connected_bg__raw { + my ($kid_pipe, $status) = @_; + local $| = 1; + if (ref($kid_pipe) && ref($$kid_pipe)) { + my $fd = $$kid_pipe->{fd}; + common::nonblock($fd); + my $a = <$fd>; + $$status = $a if defined $a; + } else { $$kid_pipe = check_link_beat() } +} + +my $kid_pipe; +sub connected_bg { + my ($status) = @_; + connected_bg__raw(\$kid_pipe, $status); +} + +# test if connected; +# cmd = 0 : ask current status +# return : 0 : not connected; 1 : connected; -1 : no test ever done; -2 : test in progress +# cmd = 1 : start new connection test +# return : -2 +# cmd = 2 : cancel current test +# return : nothing +# cmd = 3 : return current status even if a test is in progress +my $kid_pipe_connect; +my $current_connection_status; + +sub test_connected { + local $| = 1; + my ($cmd) = @_; + + $current_connection_status = -1 if !defined $current_connection_status; + + if ($cmd == 0) { + connected_bg__raw(\$kid_pipe_connect, \$current_connection_status); + } elsif ($cmd == 1) { + if ($current_connection_status != -2) { + $current_connection_status = -2; + $kid_pipe_connect = check_link_beat(); + } + } elsif ($cmd == 2) { + if (defined($kid_pipe_connect)) { + kill -9, $kid_pipe_connect->{pid}; + undef $kid_pipe_connect; + } + } + return $current_connection_status; +} + +sub check_link_beat() { + bg_command->new(sub { + require Net::Ping; + my $p; + if ($>) { + $p = Net::Ping->new("tcp"); + # Try connecting to the www port instead of the echo port + $p->{port_num} = getservbyname("http", "tcp"); + } else { + $p = Net::Ping->new("icmp"); + } + print $p->ping("www.mageia.org") ? 1 : 0; + }); +} + +sub is_dynamic_ip { + my ($net) = @_; + any { $_->{BOOTPROTO} !~ /^(none|static|)$/ } values %{$net->{ifcfg}}; +} + +sub is_dynamic_host { + my ($net) = @_; + any { defined $_->{DHCP_HOSTNAME} } values %{$net->{ifcfg}}; +} + +#- returns interface whose IP address matchs given IP address, according to its network mask +sub find_matching_interface { + my ($net, $address) = @_; + my @ip = split '\.', $address; + find { + my @intf_ip = split '\.', $net->{ifcfg}{$_}{IPADDR} or return; + my @mask = split '\.', $net->{ifcfg}{$_}{NETMASK} or return; + every { $_ } mapn { ($_[0] & $_[2]) == ($_[1] & $_[2]) } \@intf_ip, \@ip, \@mask; + } sort keys %{$net->{ifcfg}}; +} + +#- returns the current gateway, with lowest metric +sub get_current_gateway_interface() { + my $routes = get_routes(); + first(sort { $routes->{$a}{metric} <=> $routes->{$b}{metric} } grep { + $routes->{$_}{network} eq '0.0.0.0' && $routes->{$_}{gateway}; + } keys %$routes); +} + +#- returns gateway interface if found +sub get_default_gateway_interface { + my ($net) = @_; + my @intfs = sort keys %{$net->{ifcfg}}; + get_current_gateway_interface() || + $net->{network}{GATEWAYDEV} || + $net->{network}{GATEWAY} && find_matching_interface($net, $net->{network}{GATEWAY}) || + (find { get_interface_type($net->{ifcfg}{$_}) eq 'adsl' } @intfs) || + (find { get_interface_type($net->{ifcfg}{$_}) eq 'isdn' && text2bool($net->{ifcfg}{$_}{DIAL_ON_IFUP}) } @intfs) || + (find { get_interface_type($net->{ifcfg}{$_}) eq 'modem' } @intfs) || + (find { get_interface_type($net->{ifcfg}{$_}) eq 'wifi' && $net->{ifcfg}{$_}{BOOTPROTO} eq 'dhcp' } @intfs) || + (find { get_interface_type($net->{ifcfg}{$_}) eq 'ethernet' && $net->{ifcfg}{$_}{BOOTPROTO} eq 'dhcp' } @intfs); +} + +#- remove suffix from virtual interfaces +sub get_real_interface { + my ($intf) = @_; + $intf =~ s/:\d+$//; + $intf; +} + +sub is_virtual_interface { + my ($intf) = @_; + $intf =~ /:\d+$/; +} + +sub is_vlan_interface { + my ($intf) = @_; + $intf =~ /\.\d+$/; +} + +sub is_real_interface { + my ($intf) = @_; + !is_virtual_interface($intf) && !is_vlan_interface($intf); +} + +sub is_zeroconf_interface { + my ($intf) = @_; + is_virtual_interface($intf) && get_interface_ip_address({}, $intf) =~ /^(127|169\.254)\./; +} + +sub get_interface_status { + my ($intf) = @_; + $intf = get_real_interface($intf); + my $routes = get_routes(); + return $routes->{$intf}{network}, $routes->{$intf}{network} eq '0.0.0.0' && $routes->{$intf}{gateway}; +} + +#- returns (gateway_interface, interface is up, gateway address, dns server address) +sub get_default_connection { + my ($net, $o_gw_intf) = @_; + my $gw_intf = $o_gw_intf || get_default_gateway_interface($net) or return; + $net->{resolv} = {}; + require network::network; + add2hash($net->{resolv}, network::network::read_resolv_conf()); + return $gw_intf, get_interface_status($gw_intf), $net->{resolv}{dnsServer}; +} + +sub has_network_connection() { + (undef, undef, my $gw_address) = get_default_connection({}); + to_bool($gw_address); +} + +sub get_interface_type { + my ($interface, $o_module) = @_; + require detect_devices; + member($interface->{TYPE}, "xDSL", "ADSL") && "adsl" || + $interface->{DEVICE} =~ /^ippp/ && "isdn" || + $interface->{DEVICE} =~ /^ppp/ && "modem" || + (detect_devices::is_wireless_interface($interface->{DEVICE}) || exists $interface->{WIRELESS_MODE}) && "wifi" || + detect_devices::is_lan_interface($interface->{DEVICE}) && + ($o_module && member($o_module, list_modules::category2modules('network/gigabit')) ? "ethernet_gigabit" : "ethernet") || + "unknown"; +} + +sub get_interface_description { + my ($net, $interface_name) = @_; + my $type = get_interface_type($net->{ifcfg}{$interface_name}); + #- FIXME: find interface description (from PCI/USB data) and translate + $type eq 'adsl' ? "DSL: $interface_name" : + $type eq 'isdn' ? "ISDN: $interface_name" : + $type eq 'modem' ? "Modem: $interface_name" : + $type eq 'wifi' ? "WiFi: $interface_name" : + member($type, qw(ethernet_gigabit ethernet)) ? "Ethernet: $interface_name" : + $interface_name; +} + +sub get_default_metric { + my ($type) = @_; + my @known_types = ("ethernet_gigabit", "ethernet", "adsl", "wifi", "isdn", "modem", "unknown"); + my $idx; + eval { $idx = find_index { $type eq $_ } @known_types }; + $idx = @known_types if $@; + $idx * 10; +} + +sub get_interface_ip_address { + my ($net, $interface) = @_; + `/sbin/ip addr show dev $interface` =~ /^\s*inet\s+([\d.]+).*\s+$interface$/m && $1 || + $net->{ifcfg}{$interface}{IPADDR}; +} + +sub get_interface_ptp_address { + my ($interface) = @_; + my ($flags, $_link, $addrs) = `/sbin/ip addr show dev $interface`; + $flags =~ /\bPOINTOPOINT\b/ or return; + my ($peer) = $addrs =~ /peer\s+([\d.]+)/; + return $peer if $peer; + my ($addr) = $addrs =~ /inet\s+([\d.]+)/; + return $addr if $addr; +} + +sub host_hex_to_dotted { + my ($address) = @_; + inet_ntoa(pack('N', unpack('L', pack('H8', $address)))); +} + +sub get_routes() { + my %routes; + foreach (cat_("/proc/net/route")) { + if (/^(\S+)\s+([0-9A-F]+)\s+([0-9A-F]+)\s+[0-9A-F]+\s+\d+\s+\d+\s+(\d+)\s+([0-9A-F]+)/) { + if (defined $3) { $routes{$1}{gateway} = hex($3) ? host_hex_to_dotted($3) : $routes{$1}{network} } + if (defined $2) { $routes{$1}{network} = host_hex_to_dotted($2) } + if (defined $4) { $routes{$1}{metric} = $4 } + } + } + $routes{$_}{gateway} ||= get_interface_ptp_address($_) foreach keys %routes; + #- TODO: handle IPv6 with /proc/net/ipv6_route + \%routes; +} + +1; diff --git a/lib/network/vpn.pm b/lib/network/vpn.pm new file mode 100644 index 0000000..4a5afbc --- /dev/null +++ b/lib/network/vpn.pm @@ -0,0 +1,191 @@ +package network::vpn; + +=head1 NAME + +network::vpn - VPN connection abstract class + +=cut + +use strict; +use common; + +my $vpn_d = "/etc/sysconfig/network-scripts/vpn.d"; + +=head1 CLASS METHODS + +=head2 Generic class methods + +=over + +=item list_types + +List supported VPN types + +=cut + +sub list_types { + common::load_modules_from_base(__PACKAGE__); +} + +=item get_configured_connections + +Return list of configured connections for this class + +=cut + +sub get_configured_connections { + my ($class) = @_; + map { if_(/^(.*).conf$/, $class->new($1)) } all($::prefix . $vpn_d . '/' . $class->get_type); +} + +=item new(NAME) + +Create a new VPN connection object named NAME + +=cut + +sub new { + my ($class, $name) = @_; + bless { + name => $name, + }, $class; +} + +=back + +=head2 Pure virtual class methods + +=over + +=item get_type + +Return VPN type (preferably one lowercase word) + +=item get_description + +Return description of the VPN type + +=item get_packages + +List package required for configuration + +=back + +=head1 INSTANCE METHODS + +=head2 Generic instance methods + +=over + +=item get_name + +Return name of the VPN connection + +=cut + +sub get_name { + my ($connection) = @_; + $connection->{name}; +} + +=item get_label + +Return label of the VPN connection + +=cut + +sub get_label { + my ($connection) = @_; + sprintf("%s (%s)", $connection->get_name, $connection->get_type); +} + +=item get_config_path + +Get configuration file path + +=cut + +sub get_config_path { + my ($connection) = @_; + $::prefix . $vpn_d . '/' . $connection->get_type . '/' . $connection->get_name . '.conf'; +} + +sub _run { + my ($connection, $action, @args) = @_; + my @command = ('vpn-' . $action, $connection->get_type, $connection->get_name, @args); + @command = common::wrap_command_for_root(@command) if $>; + require run_program; + run_program::rooted($::prefix, , @command); +} + +=item start($o_in) + +Start the VPN connection + +$o_in is an interactive object used to interact with the user, +used if some interactive username/passwords are required. +If not specified, there is no user interaction. + +=cut + +sub start { + my ($connection, $_o_in) = @_; + $connection->_run('start'); +} + +=item stop + +Stop the VPN connection + +=cut + +sub stop { + my ($connection) = @_; + $connection->_run('stop'); +} + +=item is_started + +Returns true if the VPN connection is started + +=cut + +sub is_started { + my ($connection) = @_; + my $pid = chomp_(cat_($::prefix . '/var/run/' . $connection->get_type . '-' . $connection->get_name . '.pid')); + $pid && -e '/proc/' . $pid; +} + +=back + +=head2 Pure virtual instance methods + +=over + +=item read_config + +Read configuration from the file returned by get_config_path() + +=item write_config + +Write configuration to the file returned by get_config_path() + +=item get_settings + +Return an array ref of interactive settings + +=back + +=head2 Optional instance methods + +=over + +=item prepare + +Run commands or services that are required for the VPN type + +=back + +=cut + +1; diff --git a/lib/network/vpn/openvpn.pm b/lib/network/vpn/openvpn.pm new file mode 100644 index 0000000..68e1b3f --- /dev/null +++ b/lib/network/vpn/openvpn.pm @@ -0,0 +1,409 @@ +package network::vpn::openvpn; + +use base qw(network::vpn); + +use strict; +use common; + +sub get_type { 'openvpn' } +sub get_description { "OpenVPN" } +sub get_packages { 'openvpn', if_(supports_pkcs11(), qw(openct opensc pcsc-lite)) } + +my $pkcs11_tokens; + +sub prepare { + require services; + if (supports_pkcs11()) { + #- don't fail if SmartCard daemons can't start, it's not mandatory + services::start_not_running_service($_) foreach qw(openct pcscd); + cache_pkcs11_tokens(); + } + 1; +} + +sub read_config { + my ($connection) = @_; + my ($pkcs11_slot, $pkcs11_id); + foreach (cat_($connection->get_config_path)) { + /^\s*proto\s+tcp/ and $connection->{tcp} = 1; + /^\s*dev\s+([[:alpha:]]+)(\d*)/ and ($connection->{dev_type}, $connection->{dev_number}) = ($1, $2); + if (/^\s*remote\s+(\S+)(?:\s+(\w+))?/) { + $connection->{gateway} = $1; + $connection->{port} = $2; + } + if (/^\s*tls-auth\s+(\S+)(?:\s+(\d+))?/) { + $connection->{'tls-auth'} = $1; + $connection->{key_direction} = $2; + } + foreach my $type (qw(ca cert key pkcs12 secret)) { + /^\s*$type\s+(.+)/ and $connection->{$type . '_file'} = $1; + } + /^\s*pkcs11-slot\s+(.+)/ and $pkcs11_slot = $1; + /^\s*pkcs11-id\s+(.+)/ and $pkcs11_id = $1; + /^\s*ns-cert-type\s+server/ and $connection->{check_server} = 1; + /^\s*auth-user-pass/ and $connection->{'auth-user-pass'} = 1; + if (/^\s*ifconfig\s+(\S+)\s+(\S+)/) { + $connection->{local_ip} = $1; + $connection->{remote_ip} = $2; + $connection->{addressing} = 'manual'; + } + /^\s*cipher\s+(.+)/ and $connection->{cipher} = $1; + /^\s*keysize\s+(.+)/ and $connection->{keysize} = $1; + } + if (exists $connection->{secret_file}) { + $connection->{type} = 'static'; + $connection->{key} = delete $connection->{secret_file}; + } else { + $connection->{type} = 'pki'; + $connection->{key} = delete $connection->{key_file}; + } + if (defined $pkcs11_slot && defined $pkcs11_id) { + my $tokens = $connection->get_pkcs11_tokens('no_cache'); + $connection->{pkcs11_object} = find { $_->{slot} eq $pkcs11_slot && $_->{id} eq $pkcs11_id } @{$tokens->{objects}}; + $connection->{pkcs11_object} ||= {}; + } +} + +sub write_config { + my ($connection) = @_; + my $file = $connection->get_config_path; + unless (-e $file) { + mkdir_p(dirname($file)); + cp_f("/usr/share/openvpn/sample-config-files/client.conf", $file); + } + + delete $connection->{keysize} if !$connection->{cipher}; + delete $connection->{ca_file} if $connection->{pkcs12_file}; + + if ($connection->{type} eq 'static') { + $connection->{secret_file} = delete $connection->{key}; + delete $connection->{ca_file}; + delete $connection->{cert_file}; + delete $connection->{key_file}; + } else { + $connection->{key_file} = delete $connection->{key}; + delete $connection->{secret_file}; + } + + my @config = $connection->build_config; + substInFile { + foreach my $conf (@config) { + if (/^;?$conf->{key}\b/) { + if ($conf->{comment}) { + $_ = ";$_" unless /^;/; + } else { + $_ = "$conf->{key} $conf->{value}\n"; + $conf->{comment} = 1; + } + last; + } + } + $_ .= join('', map { if_(!$_->{comment}, "$_->{key} $_->{value}\n") } @config) if eof; + } $file; +} + +sub get_key_settings { + my ($connection) = @_; + my %ciphers = get_ciphers(); + my @types = ( + pki => N("X509 Public Key Infrastructure"), + static => N("Static Key"), + ); + my $pkcs11_separator = '/'; + my $tokens = $connection->get_pkcs11_tokens; + my %types = @types; + [ + { + label => N("Type"), + val => \$connection->{type}, + list => first(list2kv(@types)), + format => sub { $types{$_[0]} }, + }, + (supports_pkcs11() ? { + label => "PKCS #11 token", + type => 'list', + list => [ undef, @{$tokens->{objects}} ], + format => sub { $_[0] ? join($pkcs11_separator, + $tokens->{slots}{$_[0]{slot}}{label} || $_[0]{slot}, + $_[0]{label} || $_[0]{id}) + : N("None") }, + val => \$connection->{pkcs11_object}, + separator => $pkcs11_separator, + allow_empty_list => 1, + disabled => sub { $connection->{type} ne 'pki' || $connection->{cert_file} || $connection->{key_file} || $connection->{pkcs12_file} }, + } : ()), + { + label => "PKCS #12", + type => 'file', + val => \$connection->{pkcs12_file}, + disabled => sub { $connection->{type} ne 'pki' || $connection->{cert_file} || $connection->{key_file} || $connection->{pkcs11_object} }, + }, + { + label => + #-PO: please don't translate the CA acronym + N("Certificate Authority (CA)"), + type => 'file', + val => \$connection->{ca_file}, + disabled => sub { $connection->{type} ne 'pki' || $connection->{pkcs12_file} }, + }, + { + label => N("Certificate"), + type => 'file', + val => \$connection->{cert_file}, + disabled => sub { $connection->{type} ne 'pki' || $connection->{pkcs11_object} || $connection->{pkcs12_file} }, + }, + { + label => N("Key"), + type => 'file', + val => \$connection->{key}, + disabled => sub { $connection->{type} eq 'pki' && ($connection->{pkcs11_object} || $connection->{pkcs12_file}) }, + }, + { + label => N("TLS control channel key"), + type => 'file', + val => \$connection->{'tls-auth'}, + disabled => sub { $connection->{type} ne 'pki' }, + advanced => 1, + }, + { + label => N("Key direction"), + type => 'list', + val => \$connection->{key_direction}, + list => [ undef, 0, 1 ], + format => sub { defined($_[0]) ? $_[0] : N("None") }, + advanced => 1, + }, + { + text => N("Authenticate using username and password"), + type => 'bool', + val => \$connection->{'auth-user-pass'}, + advanced => 1, + }, + { + text => N("Check server certificate"), + type => 'bool', + val => \$connection->{check_server}, + advanced => 1, + }, + { + label => N("Cipher algorithm"), + type => 'list', + val => \$connection->{cipher}, + list => [ '', keys %ciphers ], + format => sub { exists $ciphers{$_[0]} ? $ciphers{$_[0]} : N("Default") }, + advanced => 1, + }, + { + label => N("Size of cipher key"), + val => \$connection->{keysize}, + advanced => 1, + disabled => sub { !$connection->{cipher} || $connection->{cipher} eq 'none' }, + }, + ]; +} + +sub get_settings { + my ($connection) = @_; + my @addressing = ( + automatic => N("Get from server"), + manual => N("Manual configuration"), + ); + my %addressing = @addressing; + [ + { + label => N("Gateway"), + val => \$connection->{gateway}, + }, + { + label => N("Gateway port"), + val => \$connection->{port}, + advanced => 1, + }, + { + label => N("IP address"), + val => \$connection->{addressing}, + list => first(list2kv(@addressing)), + format => sub { $addressing{$_[0]} }, + }, + { + label => N("Local IP address"), + val => \$connection->{local_ip}, + disabled => sub { $connection->{addressing} ne 'manual' }, + }, + { + label => N("Remote IP address"), + val => \$connection->{remote_ip}, + disabled => sub { $connection->{addressing} ne 'manual' }, + }, + { + text => N("Use TCP protocol"), + type => 'bool', + val => \$connection->{tcp}, + advanced => 1, + }, + { + label => N("Virtual network device type"), + type => 'list', + list => [ 'tun', 'tap' ], + val => \$connection->{dev_type}, + advanced => 1, + }, + { + label => N("Virtual network device number (optional)"), + val => \$connection->{dev_number}, + advanced => 1, + }, + ]; +} + +my $lib = arch() =~ /x86_64/ ? "lib64" : "lib"; +my $openvpn_default_pkcs11_provider = find { -e $_ } ( + "/usr/local/$lib/libetpkcs11.so", + "/usr/$lib/opensc-pkcs11.so", +); + +my $supports_pkcs11; +sub supports_pkcs11 { + if (!defined $supports_pkcs11) { + require run_program; + $supports_pkcs11 = to_bool(run_program::rooted($::prefix, '/usr/sbin/openvpn', '--show-pkcs11-slots', '')); + } + $supports_pkcs11; +} + +sub get_pkcs11_tokens { + my ($_class, $o_no_cache) = @_; + cache_pkcs11_tokens() if !defined $pkcs11_tokens && !$o_no_cache; + $pkcs11_tokens; +} + +sub cache_pkcs11_tokens { + $pkcs11_tokens = { slots => {}, objects => [] }; + my $slot_id; + foreach (run_program::rooted_get_stdout($::prefix, '/usr/bin/pkcs11-tool', '--module', $openvpn_default_pkcs11_provider, '-L')) { + if (/^Slot\s+(\d+)\s+(.+)$/) { + $slot_id = $2 ne '(empty)' ? $1 : undef; + $pkcs11_tokens->{slots}{$slot_id}{name} = $2 if defined $slot_id; + } elsif (/^\s+token\s+label:\s+(.+)$/) { + $pkcs11_tokens->{slots}{$slot_id}{label} = $1 if defined $slot_id; + } elsif (/^\s+flags:\s*(.*)/) { + my @flags = split(/\s*,\s*/, $1); + if (defined $slot_id && !member("token present", @flags)) { + delete $pkcs11_tokens->{slots}{$slot_id}; + undef $slot_id; + } + } + } + foreach $slot_id (keys %{$pkcs11_tokens->{slots}}) { + my ($type, $label); + my @stdout; #- do rooted_get_stdout manually because pkcs11-tool may exit with non-zero code with proprietary modules + run_program::rooted($::prefix, '/usr/bin/pkcs11-tool', '>', \@stdout, '--module', $openvpn_default_pkcs11_provider, '-O', '--slot', $slot_id); + foreach (@stdout) { + if (/^(\S.*?)\s+Object/) { + $type = $1; + undef $label; + } elsif (/^\s+label:\s+(.+)$/) { + $label = $1; + } elsif (/^\s+ID:\s+(.+)$/ && $type eq 'Public Key') { + push @{$pkcs11_tokens->{objects}}, { id => $1, label => $label, slot => $slot_id }; + } + } + } +} + +sub build_config { + my ($connection) = @_; + ( + { key => 'client', comment => to_bool($connection->{secret_file}) }, + { key => 'proto', $connection->{tcp} ? (value => 'tcp') : (comment => 1) }, + { key => 'dev', value => $connection->{dev_type} . $connection->{dev_number} }, + { key => 'remote', value => join(' ', $connection->{gateway}, if_($connection->{port}, $connection->{port})) }, + (map { +{ key => $_, $connection->{$_ . '_file'} ? (value => $connection->{$_ . '_file'}) : (comment => 1) } } qw(ca cert key pkcs12 secret)), + { key => 'pkcs11-providers', $connection->{pkcs11_object} ? (value => $openvpn_default_pkcs11_provider) : (comment => 1) }, + { key => 'pkcs11-slot-type', $connection->{pkcs11_object} ? (value => 'id') : (comment => 1) }, + { key => 'pkcs11-slot', $connection->{pkcs11_object} ? (value => $connection->{pkcs11_object}{slot}) : (comment => 1) }, + { key => 'pkcs11-id-type', $connection->{pkcs11_object} ? (value => 'id') : (comment => 1) }, + { key => 'pkcs11-id', $connection->{pkcs11_object} ? (value => $connection->{pkcs11_object}{id}) : (comment => 1) }, + { key => 'tls-auth', $connection->{'tls-auth'} ? (value => join(' ', $connection->{'tls-auth'}, if_($connection->{key_direction}, $connection->{key_direction}))) : (comment => 1) }, + { key => 'ns-cert-type', $connection->{check_server} ? (value => 'server') : (comment => 1) }, + { key => 'auth-user-pass', comment => !$connection->{'auth-user-pass'} }, + { key => 'ifconfig', $connection->{addressing} eq 'manual' ? + (value => join(' ', $connection->{local_ip}, $connection->{remote_ip})) : (comment => 1) }, + { key => 'cipher', $connection->{cipher} ? (value => $connection->{cipher}) : (comment => 1) }, + { key => 'keysize', $connection->{keysize} ? (value => $connection->{keysize}) : (comment => 1) }, + ); +} + +sub get_ciphers() { + my @ciphers = chomp_(`/usr/sbin/openvpn --show-ciphers`); + #- drop header + shift @ciphers while $ciphers[0] =~ /^\S/; + none => N("None"), map { if_($_, first(split(' ', $_)), $_) } @ciphers; +} + +sub start { + my ($connection, $o_in) = @_; + $connection->read_config if keys %$connection <= 1; + my %interactive_passwords = if_($o_in, ( + if_($connection->{'auth-user-pass'}, 'Auth' => 1), + if_($connection->{pkcs11_object}, 'Token' => 1), + )); + my $port = 2222; + my $started = $connection->_run('start', + if_(%interactive_passwords, + '--management', "127.0.0.1", $port, + '--management-query-passwords', + )); + $started && (!%interactive_passwords || $connection->ask_passwords($o_in, $port, \%interactive_passwords)); +} + +sub ask_passwords { + my ($_connection, $in, $port, $interactive_passwords) = @_; + require Net::Telnet; + my $t = new Net::Telnet; + $t->open(host => "localhost", port => $port, errmode => "return"); + my $wait; + while (1) { + $wait ||= $in->wait_message(N("VPN connection"), N("Starting connection..")); + my ($_pre, $match) = $t->waitfor(string => ">PASSWORD:", string => ">NEED-OK:", errmode => "return", + #- don't quit if all interactive passwords have been entered + #- in case some passwords are incorrect + #- though, use a smaller timeout + timeout => (%$interactive_passwords ? 20 : 5)); + if (!defined $match) { + my $msg = $t->errmsg; + #- no more interactive password is required, success + $t->close, return 1 if $msg =~ /timed-out/ && !%$interactive_passwords; + $t->close, return; #- potential failure + } elsif ($match eq ">NEED-OK:") { + my ($type, $msg) = $t->getline =~ /'(.*)'.* MSG:/; + undef $wait; + my $ret = $in->ask_okcancel(N("VPN connection"), $type eq 'token-insertion-request' ? + N("Please insert your token") : + $msg); + $t->print(qq(needok "$type" ) . ($ret ? "ok" : "cancel")); + $t->close, return if !$ret; + } elsif ($match eq ">PASSWORD:") { + my ($full_type) = $t->getline =~ /'(.*)'/; + #- assume type is "Auth" if not token + my $type = $full_type =~ /\btoken$/ ? 'Token' : 'Auth'; + my ($username, $password); + undef $wait; + my $ret = $in->ask_from(N("VPN connection"), '', $type eq 'Token' ? [ + { label => N("PIN number"), val => \$password, hidden => 1 } + ] : [ + { label => N("Account Login (user name)"), val => \$username }, + { label => N("Account Password"), val => \$password, hidden => 1 }, + ]); + if ($ret) { + delete $interactive_passwords->{$type}; + $t->print(qq(username "$full_type" "$username")) if $username; + $t->print(qq(password "$full_type" "$password")); + } else { + $t->close, return; + } + } + } +} + +1; diff --git a/lib/network/vpn/vpnc.pm b/lib/network/vpn/vpnc.pm new file mode 100644 index 0000000..c7a87c7 --- /dev/null +++ b/lib/network/vpn/vpnc.pm @@ -0,0 +1,74 @@ +package network::vpn::vpnc; + +use base qw(network::vpn); + +use strict; +use common; + +sub get_type { 'vpnc' } +sub get_description { N("Cisco VPN Concentrator") } +sub get_packages { 'vpnc' } + +sub read_config { + my ($connection) = @_; + my @fields = group_by2(list_fields($connection)); + foreach (cat_($connection->get_config_path)) { + foreach my $field (@fields) { + # all strings start exactly one space after the keyword string + /^$field->[0] (.*)/ and ${$field->[1]{val}} = $1; + } + } +} + +sub write_config { + my ($connection) = @_; + output_with_perm($connection->get_config_path, 0600, map { + if_(${$_->[1]{val}}, $_->[0], ' ', ${$_->[1]{val}}, "\n"); + } group_by2(list_fields($connection))); +} + +sub get_settings { + my ($connection) = @_; + second(list2kv(list_fields($connection))); +} + +sub list_fields { + my ($connection) = @_; + ( + 'IPSec gateway' => { + label => N("Gateway"), + val => \$connection->{gateway}, + }, + 'IPSec ID' => { + label => N("Group name"), + val => \$connection->{id}, + }, + 'IPSec secret' => { + label => N("Group secret"), + val => \$connection->{secret}, + hidden => 1, + }, + 'Xauth username' => { + label => N("Username"), + val => \$connection->{username}, + }, + 'Xauth password' => { + label => N("Password"), + val => \$connection->{password}, + hidden => 1, + }, + 'NAT Traversal Mode' => { + label => N("NAT Mode"), + list => [ '', qw(natt none force-natt cisco-udp) ], + val => \$connection->{udp}, + advanced => 1, + }, + 'Cisco UDP Encapsulation Port' => { + label => N("Use specific UDP port"), + val => \$connection->{udp_port}, + advanced => 1, + }, + ); +} + +1; |