1 |
#!/usr/bin/perl |
2 |
|
3 |
# |
4 |
# author Guillaume Cottenceau (gc@mandrakesoft.com) |
5 |
# modified by Florin Grad (florin@mandrakesoft.com) |
6 |
# wizardified by Olivier Blin (oblin@mandriva.com) |
7 |
# |
8 |
# Copyright 2000-2006 Mandriva |
9 |
# |
10 |
# This program is free software; you can redistribute it and/or modify |
11 |
# it under the terms of the GNU General Public License version 2, as |
12 |
# published by the Free Software Foundation. |
13 |
# |
14 |
# This program is distributed in the hope that it will be useful, |
15 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 |
# GNU General Public License for more details. |
18 |
# |
19 |
# You should have received a copy of the GNU General Public License |
20 |
# along with this program; if not, write to the Free Software |
21 |
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
22 |
# |
23 |
|
24 |
use strict; |
25 |
use lib qw(/usr/lib/libDrakX); |
26 |
|
27 |
# i18n: IMPORTANT: to get correct namespace (drakx-net instead of libDrakX) |
28 |
BEGIN { unshift @::textdomains, 'drakx-net' } |
29 |
use standalone; #- warning, standalone must be loaded very first, for 'explanations' |
30 |
|
31 |
use common; |
32 |
use detect_devices; |
33 |
use interactive; |
34 |
use network::network; |
35 |
use network::connection::ethernet; |
36 |
use run_program; |
37 |
use log; |
38 |
use c; |
39 |
use network::shorewall; |
40 |
use network::dhcpd; |
41 |
use network::squid; |
42 |
use services; |
43 |
|
44 |
my $sysconf_network = "/etc/sysconfig/network"; |
45 |
my $masq_file = "$::prefix/etc/shorewall/masq"; |
46 |
my $cups_conf = "$::prefix/etc/cups/cupsd.conf"; |
47 |
|
48 |
my $in = 'interactive'->vnew('su'); |
49 |
|
50 |
my $net = {}; |
51 |
network::network::read_net_conf($net); |
52 |
my $modules_conf = modules::any_conf->read; |
53 |
my %eth_intf = map { $_->[0] => join(': ', $_->[0], $_->[2]) } network::connection::ethernet::get_eth_cards($modules_conf); |
54 |
|
55 |
my $shorewall = network::shorewall::read(); |
56 |
my $choice; |
57 |
my $gw_enabled; |
58 |
my ($lan_interface_name, $lan_intf, $internal_domain_name); |
59 |
my $use_dhcpd = 1; |
60 |
my $use_caching_dns = 1; |
61 |
my $use_caching_proxy = 1; |
62 |
|
63 |
my $resolv_conf = network::network::read_resolv_conf_raw(); |
64 |
my $squid_conf = network::squid::read_squid_conf(); |
65 |
my $dhcpd_conf = network::dhcpd::read_dhcpd_conf(); |
66 |
|
67 |
require wizards; |
68 |
my $wiz = wizards->new( |
69 |
{ |
70 |
defaultimage => "drakgw", |
71 |
name => N("Internet Connection Sharing"), |
72 |
pages => { |
73 |
welcome => |
74 |
{ |
75 |
name => N("You are about to configure your computer to share its Internet connection. |
76 |
With that feature, other computers on your local network will be able to use this computer's Internet connection. |
77 |
|
78 |
Make sure you have configured your Network/Internet access using drakconnect before going any further. |
79 |
|
80 |
Note: you need a dedicated Network Adapter to set up a Local Area Network (LAN). Please disable Mageia Firewall for the network adapter connected to your LAN connection before proceeding."), |
81 |
post => sub { |
82 |
$gw_enabled = !$shorewall->{disabled} && grep { !/^#/ } cat_($masq_file); |
83 |
return $gw_enabled ? "ask_reconfigure" : "choose_net_interface"; |
84 |
}, |
85 |
}, |
86 |
|
87 |
ask_reconfigure => |
88 |
{ |
89 |
name => sub { |
90 |
$gw_enabled ? |
91 |
N("The setup of Internet Connection Sharing has already been done. |
92 |
It's currently enabled. |
93 |
|
94 |
What would you like to do?") : |
95 |
N("The setup of Internet connection sharing has already been done. |
96 |
It's currently disabled. |
97 |
|
98 |
What would you like to do?"); #- FIXME : not used for now |
99 |
}, |
100 |
data => sub { |
101 |
[ { type => "list", val => \$choice, list => [ ($gw_enabled ? N_("Disable") : N_("Enable")), N_("Reconfigure") ], format => \&translate } ]; |
102 |
}, |
103 |
post => sub { |
104 |
if ($choice eq "Enable") { |
105 |
#- FIXME, not used for now |
106 |
#- gw_enable(); |
107 |
return "end_enabled"; |
108 |
} elsif ($choice eq "Disable") { |
109 |
gw_disable(); |
110 |
return "end_disabled"; |
111 |
} elsif ($choice eq "Reconfigure") { |
112 |
return "choose_net_interface"; |
113 |
} |
114 |
}, |
115 |
}, |
116 |
|
117 |
choose_net_interface => |
118 |
{ |
119 |
pre => sub { |
120 |
$shorewall->{masq}{net_interface} = network::tools::get_default_gateway_interface($net); |
121 |
}, |
122 |
name => N("Please select the network interface directly connected to the internet."), |
123 |
data => [ { label => N("Net Device"), val => \$shorewall->{masq}{net_interface}, list => [ sort keys %{$net->{ifcfg}} ], format => sub { network::tools::get_interface_description($net, $_[0]) } } ], |
124 |
post => sub { |
125 |
network::shorewall::add_interface_to_net_zone($shorewall, $shorewall->{masq}{net_interface}); |
126 |
my $locals = @{$shorewall->{loc_zone}}; |
127 |
if ($locals == 0) { |
128 |
return "end_no_lan_interface"; |
129 |
} elsif ($locals == 1) { |
130 |
$lan_interface_name = $shorewall->{loc_zone}[0]; |
131 |
return "one_lan_interface"; |
132 |
} else { |
133 |
return "choose_lan_interface"; |
134 |
} |
135 |
}, |
136 |
}, |
137 |
|
138 |
one_lan_interface => |
139 |
{ |
140 |
name => sub { |
141 |
N("There is only one network adapter on your system configured for LAN connections: |
142 |
|
143 |
%s |
144 |
|
145 |
I am about to setup your Local Area Network with that adapter. |
146 |
|
147 |
If you have any other adapter connected to Local Area Network, |
148 |
disable the firewall protection on it using drakfirewall before |
149 |
configuring Internet Connection sharing.", format_interfaces($lan_interface_name)); |
150 |
}, |
151 |
next => "lan_configure", |
152 |
}, |
153 |
|
154 |
choose_lan_interface => |
155 |
{ |
156 |
name => N("Please choose what network adapter will be connected to your Local Area Network."), |
157 |
data => sub { |
158 |
[ { type => "list", val => \$lan_interface_name, list => $shorewall->{loc_zone}, format => \&format_interfaces } ]; |
159 |
}, |
160 |
post => sub { |
161 |
log::explanations("Choosing network device: $lan_interface_name"); |
162 |
"lan_configure"; |
163 |
}, |
164 |
}, |
165 |
|
166 |
lan_configure => |
167 |
{ |
168 |
pre => sub { |
169 |
$lan_intf = $net->{ifcfg}{$lan_interface_name} ||= {}; |
170 |
$lan_intf->{DEVICE} = $lan_interface_name; |
171 |
$lan_intf->{ONBOOT} = 'yes'; |
172 |
$lan_intf->{BOOTPROTO} = 'static'; |
173 |
$lan_intf->{IPADDR} ||= "192.168.1.1"; |
174 |
$lan_intf->{NETMASK} ||= "255.255.255.0"; |
175 |
$internal_domain_name = $resolv_conf->{search}[0] ||= "homeland.net"; |
176 |
}, |
177 |
name => N("Local Area Network settings"), |
178 |
data => sub { |
179 |
[ |
180 |
{ label => N("Local IP address"), val => \$lan_intf->{IPADDR} }, |
181 |
{ label => N("Netmask"), val => \$lan_intf->{NETMASK} }, |
182 |
{ label => N("The internal domain name"), val => \$internal_domain_name }, |
183 |
]; |
184 |
}, |
185 |
complete => sub { |
186 |
network::network::update_broadcast_and_network($lan_intf); |
187 |
if (my $conflict = find { $_->{NETWORK} eq $lan_intf->{NETWORK} } grep { $_->{DEVICE} ne $lan_intf->{DEVICE} } values %{$net->{ifcfg}}) { |
188 |
$in->ask_warn(N("Error"), N("Potential LAN address conflict found in current config of %s!\n", $conflict->{DEVICE})); |
189 |
return 1; |
190 |
} |
191 |
0; |
192 |
}, |
193 |
post => sub { |
194 |
network::network::configure_network($net, $in, $modules_conf) unless $::testing; |
195 |
return "dns"; |
196 |
}, |
197 |
}, |
198 |
|
199 |
dns => |
200 |
{ |
201 |
pre => sub { |
202 |
$dhcpd_conf->{domain_name_servers}[0] = $resolv_conf->{nameserver}[0] ||= $lan_intf->{IPADDR}; |
203 |
}, |
204 |
name => N("Domain Name Server (DNS) configuration"), |
205 |
data => sub { |
206 |
my @disable = (disabled => sub { $use_caching_dns }); |
207 |
[ |
208 |
{ text => N("Use this gateway as domain name server"), val => \$use_caching_dns, type => 'bool' }, |
209 |
{ label => N("The DNS Server IP"), val => \$dhcpd_conf->{domain_name_servers}[0], @disable }, |
210 |
]; |
211 |
}, |
212 |
complete => sub { |
213 |
!$use_caching_dns || $::testing and return 0; |
214 |
#- install a caching name server if the specified DNS is the gateway |
215 |
!$in->do_pkgs->ensure_is_installed('bind', '/usr/sbin/named'); |
216 |
}, |
217 |
post => sub { |
218 |
services::set_status($_, $use_caching_dns) foreach qw(named); |
219 |
return "dhcpd"; |
220 |
}, |
221 |
}, |
222 |
|
223 |
dhcpd => |
224 |
{ |
225 |
pre => sub { |
226 |
#- not editable |
227 |
$dhcpd_conf->{option_routers}[0] = $lan_intf->{IPADDR}; |
228 |
$dhcpd_conf->{subnet_mask}[0] = $lan_intf->{NETMASK}; |
229 |
$dhcpd_conf->{domain_name}[0] = $internal_domain_name; |
230 |
#- editable |
231 |
$dhcpd_conf->{dynamic_bootp}[0] ||= "16"; |
232 |
$dhcpd_conf->{dynamic_bootp}[1] ||= "253"; |
233 |
$dhcpd_conf->{default_lease_time}[0] ||= "21600"; |
234 |
$dhcpd_conf->{max_lease_time}[0] ||= "43200"; |
235 |
}, |
236 |
name => N("DHCP Server Configuration. |
237 |
|
238 |
Here you can select different options for the DHCP server configuration. |
239 |
If you do not know the meaning of an option, simply leave it as it is."), |
240 |
data => sub { |
241 |
my @advanced_disable = (advanced => 1, disabled => sub { !$use_dhcpd }); |
242 |
[ |
243 |
{ text => N("Use automatic configuration (DHCP)"), val => \$use_dhcpd, type => 'bool' }, |
244 |
{ label => N("The DHCP start range"), val => \$dhcpd_conf->{dynamic_bootp}[0], @advanced_disable }, |
245 |
{ label => N("The DHCP end range"), val => \$dhcpd_conf->{dynamic_bootp}[1], @advanced_disable }, |
246 |
{ label => N("The default lease (in seconds)"), val => \$dhcpd_conf->{default_lease_time}[0], @advanced_disable }, |
247 |
{ label => N("The maximum lease (in seconds)"), val => \$dhcpd_conf->{max_lease_time}[0], @advanced_disable } |
248 |
]; |
249 |
}, |
250 |
complete => sub { |
251 |
!$use_dhcpd || $::testing and return 0; |
252 |
$in->do_pkgs->ensure_is_installed('dhcp-server', '/usr/sbin/dhcpd') or return 1; |
253 |
0; |
254 |
}, |
255 |
post => sub { |
256 |
network::dhcpd::write_dhcpd_conf($dhcpd_conf, $lan_intf->{DEVICE}) if $use_dhcpd; |
257 |
services::set_status("dhcpd", $use_dhcpd); |
258 |
return "proxy"; |
259 |
} |
260 |
}, |
261 |
|
262 |
proxy => |
263 |
{ |
264 |
pre => sub { |
265 |
$squid_conf->{http_port}[0] ||= "3128"; |
266 |
$squid_conf->{cache_size}[1] ||= "100"; |
267 |
$squid_conf->{admin_mail}[0] ||= 'admin@mydomain.com'; |
268 |
$squid_conf->{visible_hostname}[0] ||= 'myfirewall@mydomain.com'; |
269 |
}, |
270 |
name => N("Proxy caching server (SQUID)"), |
271 |
data => sub { |
272 |
my @disable = (advanced => 1, disabled => sub { !$use_caching_proxy }); |
273 |
[ |
274 |
{ text => N("Use this gateway as proxy caching server"), val => \$use_caching_proxy, type => 'bool' }, |
275 |
{ label => N("Admin mail"), val => \$squid_conf->{admin_mail}[0], @disable }, |
276 |
{ label => N("Visible hostname"), val => \$squid_conf->{visible_hostname}[0], @disable }, |
277 |
{ label => N("Proxy port"), val => \$squid_conf->{http_port}[0], advanced => 1, @disable }, |
278 |
{ label => N("Cache size (MB)"), val => \$squid_conf->{cache_size}[1], advanced => 1, @disable }, |
279 |
]; |
280 |
}, |
281 |
complete => sub { |
282 |
!$use_caching_proxy || $::testing and return 0; |
283 |
$in->do_pkgs->ensure_is_installed('squid', '/usr/sbin/squid') or return 1; |
284 |
0; |
285 |
}, |
286 |
post => sub { |
287 |
network::squid::write_squid_conf($squid_conf, $lan_intf, $internal_domain_name) if $use_caching_proxy; |
288 |
services::set_status("squid", $use_caching_proxy); |
289 |
network::shorewall::set_redirected_ports($shorewall, 'tcp', $squid_conf->{http_port}[0], if_($use_caching_proxy, 'http')); |
290 |
@{$shorewall->{accept_local_users}{http}} = if_($use_caching_proxy, 'squid'); |
291 |
-f $cups_conf ? "cups" : end_step(); |
292 |
}, |
293 |
}, |
294 |
|
295 |
cups => |
296 |
{ |
297 |
name => N("Broadcast printer information"), |
298 |
type => "yesorno", |
299 |
default => "yes", |
300 |
post => sub { |
301 |
update_cups() unless $::testing; |
302 |
end_step(); |
303 |
}, |
304 |
}, |
305 |
|
306 |
end_no_lan_interface => |
307 |
{ |
308 |
name => N("No ethernet network adapter configured for LAN has been detected on your system. |
309 |
|
310 |
Please run the hardware configuration tool to configure it, and ensure that the Mageia firewall is not enabled for network adapter connected to your LAN network."), |
311 |
end => 1, |
312 |
}, |
313 |
|
314 |
end_enabled => |
315 |
{ |
316 |
name => N("Internet Connection Sharing is now enabled."), |
317 |
end => 1, |
318 |
}, |
319 |
|
320 |
end_disabled => |
321 |
{ |
322 |
name => N("Internet Connection Sharing is now disabled."), |
323 |
end => 1, |
324 |
}, |
325 |
|
326 |
end => |
327 |
{ |
328 |
name => N("Everything has been configured. |
329 |
You may now share Internet connection with other computers on your Local Area Network, using automatic network configuration (DHCP) and |
330 |
a Transparent Proxy Cache server (SQUID)."), |
331 |
end => 1, |
332 |
}, |
333 |
}, |
334 |
}); |
335 |
$wiz->safe_process($in); |
336 |
|
337 |
|
338 |
|
339 |
sub format_interfaces { |
340 |
my ($interface) = @_; |
341 |
$eth_intf{$interface} || $interface; |
342 |
} |
343 |
|
344 |
sub end_step() { |
345 |
gw_configure(); |
346 |
log::l("[drakgw] Installation complete, exiting"); |
347 |
"end"; |
348 |
} |
349 |
|
350 |
sub gw_disable() { |
351 |
my $_wait_disabl = $in->wait_message(N("Please wait"), N("Disabling servers...")); |
352 |
return if $::testing; |
353 |
services::set_status($_, 0) foreach qw(dhcpd squid named); |
354 |
network::shorewall::set_redirected_ports($shorewall, 'tcp', $squid_conf->{http_port}[0], ()); |
355 |
network::shorewall::write($shorewall); |
356 |
foreach ($network::dhcpd::dhcpd_conf_file, $network::squid::squid_conf_file, $masq_file) { |
357 |
if (-f $_) { rename($_, "$_.drakgwdisable") or die "Could not rename $_ to $_.drakgwdisable" } |
358 |
} |
359 |
services::restart("shorewall"); |
360 |
} |
361 |
|
362 |
sub gw_configure() { |
363 |
#- test for potential conflict with previous firewall config |
364 |
if (network::shorewall::check_iptables()) { |
365 |
$in->ask_warn(N("Firewalling configuration detected!"), |
366 |
N("Warning! An existing firewalling configuration has been detected. You may need some manual fixes after installation.")); |
367 |
} |
368 |
|
369 |
$in->do_pkgs->ensure_is_installed('shorewall', '/sbin/shorewall') or $in->exit(-1); |
370 |
|
371 |
my $_wait_configuring = $in->wait_message(N("Configuring..."), |
372 |
N("Configuring firewall...")); |
373 |
|
374 |
$shorewall->{disabled} = 0; |
375 |
$shorewall->{masq}{subnet} = $lan_intf->{NETWORK} . '/' . network::network::netmask_to_vlsm($lan_intf->{NETMASK}); |
376 |
network::shorewall::write($shorewall); |
377 |
|
378 |
#- be sure that FORWARD_IPV4 is enabled in /etc/sysconfig/network |
379 |
log::explanations("Enabling IPV4 forwarding"); |
380 |
substInFile { s/^FORWARD_IPV4.*\n//; $_ .= "FORWARD_IPV4=true\n" if eof } $sysconf_network if !$::testing; |
381 |
services::restart("network"); |
382 |
} |
383 |
|
384 |
sub update_cups() { |
385 |
#- Set up /etc/cups/cupsd.conf to make the broadcasting of the printer info |
386 |
#- working correctly: |
387 |
#- |
388 |
#- 1. ServerName <server's IP address> # because clients do necessarily |
389 |
#- # know the server's name |
390 |
#- |
391 |
#- 2. BrowseAddress <server's Broadcast IP> # broadcast printer info into |
392 |
#- # the local network. |
393 |
#- |
394 |
#- 3. BrowseOrder Deny,Allow |
395 |
#- BrowseDeny All |
396 |
#- BrowseAllow <IP mask for local net> # Only accept broadcast signals |
397 |
#- # coming from local network |
398 |
#- |
399 |
#- 4. <Location /> |
400 |
#- Order Deny,Allow |
401 |
#- Deny From All |
402 |
#- Allow From <IP mask for local net> # Allow only machines of local |
403 |
#- </Location> # network to access the server |
404 |
#- |
405 |
#- These steps are only done when the CUPS package is installed. |
406 |
|
407 |
#- Modify the root location block in /etc/cups/cupsd.conf |
408 |
|
409 |
log::explanations("Updating CUPS configuration accordingly"); |
410 |
|
411 |
substInFile { |
412 |
s/^ServerName[^:].*\n//; $_ .= "ServerName $lan_intf->{IPADDR}\n" if eof; |
413 |
s/^BrowseAddress.*\n//; $_ .= "BrowseAddress $lan_intf->{BROADCAST}\n" if eof; |
414 |
s/^BrowseOrder.*\n//; $_ .= "BrowseOrder Deny,Allow\n" if eof; |
415 |
s/^BrowseDeny.*\n//; $_ .= "BrowseDeny All\n" if eof; |
416 |
s/^BrowseAllow.*\n//; $_ .= "BrowseAllow \@IF($lan_interface_name)\n" if eof; |
417 |
} $cups_conf; |
418 |
|
419 |
my @cups_conf_content = cat_($cups_conf); |
420 |
my @root_location; my $root_location_start; my $root_location_end; |
421 |
|
422 |
# Cut out the root location block so that it can be treated seperately |
423 |
# without affecting the rest of the file |
424 |
if (any { m|^\s*<Location\s+/\s*>| } @cups_conf_content) { |
425 |
$root_location_start = -1; |
426 |
$root_location_end = -1; |
427 |
# Go through all the lines, bail out when start and end line found |
428 |
for (my $i = 0; $i < @cups_conf_content && $root_location_end == -1; $i++) { |
429 |
if ($cups_conf_content[$i] =~ m|^\s*<\s*Location\s+/\s*>|) { |
430 |
$root_location_start = $i; |
431 |
} elsif ($cups_conf_content[$i] =~ m|^\s*<\s*/Location\s*>| && $root_location_start != -1) { |
432 |
$root_location_end = $i; |
433 |
} |
434 |
} |
435 |
# Rip out the block and store it seperately |
436 |
@root_location = splice(@cups_conf_content, $root_location_start, $root_location_end - $root_location_start + 1); |
437 |
} else { |
438 |
# If there is no root location block, create one |
439 |
$root_location_start = @cups_conf_content; |
440 |
@root_location = ("<Location />\n", "</Location>\n"); |
441 |
} |
442 |
|
443 |
# Delete all former "Order", "Allow", and "Deny" lines from the root location block |
444 |
s/^\s*Order.*//, s/^\s*Allow.*//, s/^\s*Deny.*// foreach @root_location; |
445 |
|
446 |
# Add the new "Order" and "Deny" lines, add an "Allow" line for the local network |
447 |
splice(@root_location, -1, 0, $_) foreach "Order Deny,Allow\n", "Deny From All\n", "Allow From 127.0.0.1\n", |
448 |
"Allow From \@IF($lan_interface_name)\n"; |
449 |
|
450 |
# Put the changed root location block back into the file |
451 |
splice(@cups_conf_content, $root_location_start, 0, @root_location); |
452 |
|
453 |
output $cups_conf, @cups_conf_content; |
454 |
} |