From 685b705e6628a105b6939c09c2046a7266f16c44 Mon Sep 17 00:00:00 2001 From: Pascal Rigaux Date: Wed, 25 Apr 2007 10:08:22 +0000 Subject: re-sync after the big svn loss --- bin/drakgw | 466 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 466 insertions(+) create mode 100755 bin/drakgw diff --git a/bin/drakgw b/bin/drakgw new file mode 100755 index 0000000..78f0b1c --- /dev/null +++ b/bin/drakgw @@ -0,0 +1,466 @@ +#!/usr/bin/perl + +# +# author Guillaume Cottenceau (gc@mandrakesoft.com) +# modified by Florin Grad (florin@mandrakesoft.com) +# wizardified by Olivier Blin (oblin@mandriva.com) +# +# Copyright 2000-2005 Mandriva +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +use strict; +use lib qw(/usr/lib/libDrakX); + +use standalone; #- warning, standalone must be loaded very first, for 'explanations' + +use common; +use detect_devices; +use interactive; +use network::network; +use network::ethernet; +use run_program; +use log; +use c; +use network::shorewall; +use network::dhcpd; +use network::squid; +use services; + +my $sysconf_network = "/etc/sysconfig/network"; +my $masq_file = "$::prefix/etc/shorewall/masq"; +my $cups_conf = "$::prefix/etc/cups/cupsd.conf"; + +my $in = 'interactive'->vnew('su'); + +my ($kernel_version) = c::kernel_version() =~ /(...)/; +unless ($kernel_version >= 2.4) { + $in->ask_warn(N("Error"), N("Sorry, we support only 2.4 and above kernels.")); + $in->exit(-1); +} + +my $net = {}; +network::network::read_net_conf($net); +my $modules_conf = modules::any_conf->read; +my %eth_intf = map { $_->[0] => join(': ', $_->[0], $_->[2]) } network::ethernet::get_eth_cards($modules_conf); + +my $shorewall = network::shorewall::read(); +my $choice; +my $gw_enabled; +my ($net_interface_name, $lan_interface_name, $lan_intf, $internal_domain_name); +my $use_dhcpd = 1; +my $use_caching_dns = 1; +my $use_caching_proxy = 1; + +my $resolv_conf = network::network::read_resolv_conf_raw(); +my $squid_conf = network::squid::read_squid_conf(); +my $dhcpd_conf = network::dhcpd::read_dhcpd_conf(); + +require wizards; +my $wiz = wizards->new( + { + defaultimage => "drakgw.png", + name => N("Internet Connection Sharing"), + pages => { + welcome => + { + name => N("You are about to configure your computer to share its Internet connection. +With that feature, other computers on your local network will be able to use this computer's Internet connection. + +Make sure you have configured your Network/Internet access using drakconnect before going any further. + +Note: you need a dedicated Network Adapter to set up a Local Area Network (LAN)."), + post => sub { + $gw_enabled = !$shorewall->{disabled} && grep { !/^#/ } cat_($masq_file); + return $gw_enabled ? "ask_reconfigure" : "choose_net_interface"; + }, + }, + + ask_reconfigure => + { + name => sub { + $gw_enabled ? + N("The setup of Internet Connection Sharing has already been done. +It's currently enabled. + +What would you like to do?") : + N("The setup of Internet connection sharing has already been done. +It's currently disabled. + +What would you like to do?"); #- FIXME : not used for now + }, + data => sub { + [ { type => "list", val => \$choice, list => [ ($gw_enabled ? N_("Disable") : N_("Enable")), N_("Reconfigure") ], format => \&translate } ]; + }, + post => sub { + if ($choice eq "Enable") { + #- FIXME, not used for now + #- gw_enable(); + return "end_enabled"; + } elsif ($choice eq "Disable") { + gw_disable(); + return "end_disabled"; + } elsif ($choice eq "Reconfigure") { + return "choose_net_interface"; + } + }, + }, + + choose_net_interface => + { + pre => sub { + $net_interface_name = $shorewall->{net_interface}; + }, + name => translate($network::shorewall::ask_shorewall_interface_label), + data => network::shorewall::shorewall_interface_choices(\$net_interface_name), + post => sub { + network::shorewall::set_net_interface($shorewall, $net_interface_name); + my $locals = @{$shorewall->{loc_interface}}; + if ($locals == 0) { + return "end_no_lan_interface"; + } elsif ($locals == 1) { + $lan_interface_name = $shorewall->{loc_interface}[0]; + return "one_lan_interface"; + } else { + return "choose_lan_interface"; + } + }, + }, + + one_lan_interface => + { + name => sub { + N("There is only one configured network adapter on your system: + +%s + +I am about to setup your Local Area Network with that adapter.", format_interfaces($lan_interface_name)); + }, + next => "lan_configure", + }, + + choose_lan_interface => + { + name => N("Please choose what network adapter will be connected to your Local Area Network."), + data => sub { + [ { type => "list", val => \$lan_interface_name, list => $shorewall->{loc_interface}, format => \&format_interfaces } ]; + }, + post => sub { + log::explanations("Choosing network device: $lan_interface_name"); + "lan_configure"; + }, + }, + + lan_configure => + { + pre => sub { + $lan_intf = $net->{ifcfg}{$lan_interface_name} ||= {}; + $lan_intf->{DEVICE} = $lan_interface_name; + $lan_intf->{ONBOOT} = 'yes'; + $lan_intf->{BOOTPROTO} = 'static'; + $lan_intf->{IPADDR} ||= "192.168.1.1"; + $lan_intf->{NETMASK} ||= "255.255.255.0"; + $internal_domain_name = $resolv_conf->{search}[0] ||= "homeland.net"; + }, + name => N("Local Area Network settings"), + data => sub { + [ + { label => N("Local IP address"), val => \$lan_intf->{IPADDR} }, + { label => N("Netmask"), val => \$lan_intf->{NETMASK} }, + { label => N("The internal domain name"), val => \$internal_domain_name }, + ]; + }, + complete => sub { + network::network::update_broadcast_and_network($lan_intf); + if (my $conflict = find { $_->{NETWORK} eq $lan_intf->{NETWORK} } grep { $_->{DEVICE} ne $lan_intf->{DEVICE} } values %{$net->{ifcfg}}) { + $in->ask_warn(N("Error"), N("Potential LAN address conflict found in current config of %s!\n", $conflict->{DEVICE})); + return 1; + } + 0; + }, + post => sub { + network::network::configure_network($net, $in, $modules_conf) unless $::testing; + return "dns"; + }, + }, + + dns => + { + pre => sub { + $dhcpd_conf->{domain_name_servers}[0] = $resolv_conf->{nameserver}[0] ||= $lan_intf->{IPADDR}; + }, + name => N("Domain Name Server (DNS) configuration"), + data => sub { + my @disable = (disabled => sub { $use_caching_dns }); + [ + { text => N("Use this gateway as domain name server"), val => \$use_caching_dns, type => 'bool' }, + { label => N("The DNS Server IP"), val => \$dhcpd_conf->{domain_name_servers}[0], @disable }, + ]; + }, + complete => sub { + !$use_caching_dns || $::testing and return 0; + #- install a caching name server if the specified DNS is the gateway + !$in->do_pkgs->ensure_is_installed('caching-nameserver', '/var/named/named.local'); + }, + post => sub { + services::set_status($_, $use_caching_dns) foreach qw(named caching-nameserver); + return "dhcpd"; + }, + }, + + dhcpd => + { + pre => sub { + #- not editable + $dhcpd_conf->{option_routers}[0] = $lan_intf->{IPADDR}; + $dhcpd_conf->{subnet_mask}[0] = $lan_intf->{NETMASK}; + $dhcpd_conf->{domain_name}[0] = $internal_domain_name; + #- editable + $dhcpd_conf->{dynamic_bootp}[0] ||= "16"; + $dhcpd_conf->{dynamic_bootp}[1] ||= "253"; + $dhcpd_conf->{default_lease_time}[0] ||= "21600"; + $dhcpd_conf->{max_lease_time}[0] ||= "43200"; + }, + name => N("DHCP Server Configuration. + +Here you can select different options for the DHCP server configuration. +If you do not know the meaning of an option, simply leave it as it is."), + data => sub { + my @advanced_disable = (advanced => 1, disabled => sub { !$use_dhcpd }); + [ + { text => N("Use automatic configuration (DHCP)"), val => \$use_dhcpd, type => 'bool' }, + { label => N("The DHCP start range"), val => \$dhcpd_conf->{dynamic_bootp}[0], @advanced_disable }, + { label => N("The DHCP end range"), val => \$dhcpd_conf->{dynamic_bootp}[1], @advanced_disable }, + { label => N("The default lease (in seconds)"), val => \$dhcpd_conf->{default_lease_time}[0], @advanced_disable }, + { label => N("The maximum lease (in seconds)"), val => \$dhcpd_conf->{max_lease_time}[0], @advanced_disable } + ]; + }, + complete => sub { + !$use_dhcpd || $::testing and return 0; + $in->do_pkgs->ensure_is_installed('dhcp-server', '/usr/sbin/dhcpd') or return 1; + 0; + }, + post => sub { + network::dhcpd::write_dhcpd_conf($dhcpd_conf, $lan_intf->{DEVICE}) if $use_dhcpd; + services::set_status("dhcpd", $use_dhcpd); + return "proxy"; + } + }, + + proxy => + { + pre => sub { + $squid_conf->{http_port}[0] ||= "3128"; + $squid_conf->{cache_size}[1] ||= "100"; + $squid_conf->{admin_mail}[0] ||= 'admin@mydomain.com'; + $squid_conf->{visible_hostname}[0] ||= 'myfirewall@mydomain.com'; + }, + name => N("Proxy caching server (SQUID)"), + data => sub { + my @disable = (advanced => 1, disabled => sub { !$use_caching_proxy }); + [ + { text => N("Use this gateway as proxy caching server"), val => \$use_caching_proxy, type => 'bool' }, + { label => N("Admin mail"), val => \$squid_conf->{admin_mail}[0], @disable }, + { label => N("Visible hostname"), val => \$squid_conf->{visible_hostname}[0], @disable }, + { label => N("Proxy port"), val => \$squid_conf->{http_port}[0], advanced => 1, @disable }, + { label => N("Cache size (MB)"), val => \$squid_conf->{cache_size}[1], advanced => 1, @disable }, + ]; + }, + complete => sub { + !$use_caching_proxy || $::testing and return 0; + $in->do_pkgs->ensure_is_installed('squid', '/usr/sbin/squid') or return 1; + 0; + }, + post => sub { + network::squid::write_squid_conf($squid_conf, $lan_intf, $internal_domain_name) if $use_caching_proxy; + services::set_status("squid", $use_caching_proxy); + if ($use_caching_proxy) { + set_proxy_port($squid_conf->{http_port}[0]); + } else { + delete_proxy_ports(); + } + -f $cups_conf ? "cups" : end_step(); + }, + }, + + cups => + { + name => N("Broadcast printer information"), + type => "yesorno", + default => "yes", + post => sub { + update_cups() unless $::testing; + end_step(); + }, + }, + + end_no_lan_interface => + { + name => N("No ethernet network adapter has been detected on your system. Please run the hardware configuration tool."), + end => 1, + }, + + end_enabled => + { + name => N("Internet Connection Sharing is now enabled."), + end => 1, + }, + + end_disabled => + { + name => N("Internet Connection Sharing is now disabled."), + end => 1, + }, + + end => + { + name => N("Everything has been configured. +You may now share Internet connection with other computers on your Local Area Network, using automatic network configuration (DHCP) and + a Transparent Proxy Cache server (SQUID)."), + end => 1, + }, + }, +}); +$wiz->safe_process($in); + + + +sub format_interfaces { + my ($interface) = @_; + $eth_intf{$interface} || $interface; +} + +sub end_step() { + gw_configure(); + log::l("[drakgw] Installation complete, exiting"); + "end"; +} + +sub delete_proxy_ports() { + my $r = $shorewall->{redirects}{tcp}; + my @ports = grep { $r->{$_} eq 'www' } keys %$r; + delete $r->{$_} foreach @ports; +} + +sub set_proxy_port { + my ($port) = @_; + $shorewall->{redirects}{tcp}{$port} = 'www'; +} + +sub gw_disable() { + my $_wait_disabl = $in->wait_message('', N("Disabling servers...")); + return if $::testing; + services::set_status($_, 0) foreach qw(dhcpd squid named); + delete_proxy_ports(); + network::shorewall::write($shorewall); + foreach ($network::dhcpd::dhcpd_conf_file, $network::squid::squid_conf_file, $masq_file) { + if (-f $_) { rename($_, "$_.drakgwdisable") or die "Could not rename $_ to $_.drakgwdisable" } + } + services::restart("shorewall"); +} + +sub gw_configure() { + #- test for potential conflict with previous firewall config + if (network::shorewall::check_iptables()) { + $in->ask_warn(N("Firewalling configuration detected!"), + N("Warning! An existing firewalling configuration has been detected. You may need some manual fixes after installation.")); + } + + $in->do_pkgs->ensure_is_installed('shorewall', '/sbin/shorewall') or $in->exit(-1); + + my $_wait_configuring = $in->wait_message(N("Configuring..."), + N("Configuring firewall...")); + + $shorewall->{disabled} = 0; + $shorewall->{masq_subnet} = "$lan_intf->{NETWORK}/$lan_intf->{NETMASK}"; + network::shorewall::write($shorewall); + + #- be sure that FORWARD_IPV4 is enabled in /etc/sysconfig/network + log::explanations("Enabling IPV4 forwarding"); + substInFile { s/^FORWARD_IPV4.*\n//; $_ .= "FORWARD_IPV4=true\n" if eof } $sysconf_network if !$::testing; + services::restart("network"); +} + +sub update_cups() { + #- Set up /etc/cups/cupsd.conf to make the broadcasting of the printer info + #- working correctly: + #- + #- 1. ServerName # because clients do necessarily + #- # know the server's name + #- + #- 2. BrowseAddress # broadcast printer info into + #- # the local network. + #- + #- 3. BrowseOrder Deny,Allow + #- BrowseDeny All + #- BrowseAllow # Only accept broadcast signals + #- # coming from local network + #- + #- 4. + #- Order Deny,Allow + #- Deny From All + #- Allow From # Allow only machines of local + #- # network to access the server + #- + #- These steps are only done when the CUPS package is installed. + + #- Modify the root location block in /etc/cups/cupsd.conf + + log::explanations("Updating CUPS configuration accordingly"); + + substInFile { + s/^ServerName[^:].*\n//; $_ .= "ServerName $lan_intf->{IPADDR}\n" if eof; + s/^BrowseAddress.*\n//; $_ .= "BrowseAddress $lan_intf->{BROADCAST}\n" if eof; + s/^BrowseOrder.*\n//; $_ .= "BrowseOrder Deny,Allow\n" if eof; + s/^BrowseDeny.*\n//; $_ .= "BrowseDeny All\n" if eof; + s/^BrowseAllow.*\n//; $_ .= "BrowseAllow \@IF($lan_interface_name)\n" if eof; + } $cups_conf; + + my @cups_conf_content = cat_($cups_conf); + my @root_location; my $root_location_start; my $root_location_end; + + # Cut out the root location block so that it can be treated seperately + # without affecting the rest of the file + if (any { m|^\s*| } @cups_conf_content) { + $root_location_start = -1; + $root_location_end = -1; + # Go through all the lines, bail out when start and end line found + for (my $i = 0; $i < @cups_conf_content && $root_location_end == -1; $i++) { + if ($cups_conf_content[$i] =~ m|^\s*<\s*Location\s+/\s*>|) { + $root_location_start = $i; + } elsif ($cups_conf_content[$i] =~ m|^\s*<\s*/Location\s*>| && $root_location_start != -1) { + $root_location_end = $i; + } + } + # Rip out the block and store it seperately + @root_location = splice(@cups_conf_content, $root_location_start, $root_location_end - $root_location_start + 1); + } else { + # If there is no root location block, create one + $root_location_start = @cups_conf_content; + @root_location = ("\n", "\n"); + } + + # Delete all former "Order", "Allow", and "Deny" lines from the root location block + s/^\s*Order.*//, s/^\s*Allow.*//, s/^\s*Deny.*// foreach @root_location; + + # Add the new "Order" and "Deny" lines, add an "Allow" line for the local network + splice(@root_location, -1, 0, $_) foreach "Order Deny,Allow\n", "Deny From All\n", "Allow From 127.0.0.1\n", + "Allow From \@IF($lan_interface_name)\n"; + + # Put the changed root location block back into the file + splice(@cups_conf_content, $root_location_start, 0, @root_location); + + output $cups_conf, @cups_conf_content; +} -- cgit v1.2.1