#!/usr/bin/env perl #-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- # Network configurator. Designed to be architecture and distribution independent. # # Copyright (C) 2000-2001 Ximian, Inc. # # Authors: Hans Petter Jansson # Michael Vogt (Debian Support) # Arturo Espinosa # Grzegorz Golawski (PLD Support) # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Library General Public License as published # by the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # 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 Library General Public License for more details. # # You should have received a copy of the GNU Library General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Best viewed with 100 columns of width. # Configuration files affected: # # /etc/resolv.conf # /etc/host.conf # /etc/hosts # /etc/sysconfig/network # /etc/rc.config # /etc/smb.conf # Running programs affected: # # smbd # nmbd # ifconfig: check current interfaces and activate/deactivate. BEGIN { $SCRIPTSDIR = "@scriptsdir@"; if ($SCRIPTSDIR =~ /^@scriptsdir[@]/) { $SCRIPTSDIR = "."; $DOTIN = ".in"; } require "$SCRIPTSDIR/general.pl$DOTIN"; require "$SCRIPTSDIR/platform.pl$DOTIN"; require "$SCRIPTSDIR/util.pl$DOTIN"; require "$SCRIPTSDIR/file.pl$DOTIN"; require "$SCRIPTSDIR/xml.pl$DOTIN"; require "$SCRIPTSDIR/network.pl$DOTIN"; } # --- Tool information --- # $name = "network"; $version = "@VERSION@"; @platforms = ("redhat-5.2", "redhat-6.0", "redhat-6.1", "redhat-6.2", "redhat-7.0", "redhat-7.1", "redhat-7.2", "redhat-8.0", "redhat-9", "openna-1.0", "mandrake-7.1", "mandrake-7.2", "mandrake-9.0", "mandrake-9.1", "mandrake-9.2", "mandrake-10.0", "mandrake-10.1","mandrake-10.2", "mandriva-2006.0", "mandriva-2006.1", "mandriva-2007.0", "mandriva-2007.1", "yoper-2.2", "blackpanther-4.0", "debian-2.2", "debian-3.0", "debian-3.1", "debian-4.0", "debian-5.0", "debian-testing", "ubuntu-5.04", "ubuntu-5.10", "ubuntu-6.06", "ubuntu-6.10", "ubuntu-7.04", "ubuntu-7.10", "ubuntu-8.04", "ubuntu-8.10", "ubuntu-9.04", "ubuntu-9.10", "ubuntu-10.04", "ubuntu-10.10", "suse-7.0", "suse-9.0", "suse-9.1", "turbolinux-7.0", "fedora-1", "fedora-2", "fedora-3", "fedora-4", "fedora-5", "rpath", "pld-1.0", "pld-1.1", "pld-1.99", "conectiva-9", "conectiva-10", "vine-3.0", "vine-3.1", "ark", "slackware-9.1.0", "slackware-10.0.0", "slackware-10.1.0", "slackware-10.2.0", "slackware-11.0.0", "slackware-12.0.0", "slackware-12.1.0", "slackware-12.2.0", "slackware-13.0.0", "slackware-13.1.0", "slackware-13.37.0", "gentoo", "vlos-1.2", "freebsd-5", "freebsd-6"); $description =<<"end_of_description;"; Configures all network parameters and interfaces. end_of_description; $progress_max = 10; $profile_file = "profiles.xml"; # --- XML parsing --- # Scan XML from standard input to an internal tree. sub xml_parse { my ($tree, %hash, $elem); # Scan XML to tree. $tree = &gst_xml_scan (); # Walk the tree recursively and extract configuration parameters. # This is the top level - find and enter the "network" tag. while ($elem = shift @$tree) { if ($elem eq "network") { &xml_parse_network (shift @$tree, \%hash); } else { &gst_report ("xml_unexp_tag", $elem); shift @$tree; } } return(\%hash); } # ... sub push_unique { my ($arr, $val) = @_; my $i; foreach $i (@$arr) { return if $i eq $val; } push @$arr, $val; } sub xml_parse_network { my ($tree, $hash) = @_; my ($elem); my (@searchdomain, @nameserver, @order, %statichost, %interface, %dialing); shift @$tree; # Skip attributes. while ($elem = shift @$tree) { if ($elem eq "auto") { $$hash{"auto"} = &gst_xml_get_pcdata (shift @$tree); } elsif ($elem eq "hostname") { $$hash{"hostname"} = &gst_xml_get_pcdata (shift @$tree); } elsif ($elem eq "gateway") { $$hash{"gateway"} = &gst_xml_get_pcdata (shift @$tree); } elsif ($elem eq "gatewaydev") { $$hash{"gatewaydev"} = &gst_xml_get_pcdata (shift @$tree); } elsif ($elem eq "domain") { $$hash{"domain"} = &gst_xml_get_pcdata (shift @$tree); } elsif ($elem eq "workgroup") { $$hash{"workgroup"} = &gst_xml_get_pcdata (shift @$tree); } elsif ($elem eq "smbdesc") { $$hash{"smbdesc"} = &gst_xml_get_pcdata (shift @$tree); } elsif ($elem eq "name") { $$hash{"name"} = &gst_xml_get_pcdata (shift @$tree); } elsif ($elem eq "description") { $$hash{"description"} = &gst_xml_get_pcdata (shift @$tree); } elsif ($elem eq "winsserver") { $$hash{"winsserver"} = &gst_xml_get_pcdata (shift @$tree); } elsif ($elem eq "winsuse") { $$hash{"winsuse"} = &gst_xml_get_pcdata (shift @$tree); } elsif ($elem eq "smbuse") { $$hash{"smbuse"} = &gst_xml_get_pcdata (shift @$tree); } elsif ($elem eq "hostmatch") { $$hash{"hostmatch"} = &gst_xml_get_pcdata (shift @$tree); } elsif ($elem eq "nameserver") { &push_unique (\@nameserver, &gst_xml_get_pcdata (shift @$tree)); } elsif ($elem eq "searchdomain") { &push_unique (\@searchdomain, &gst_xml_get_pcdata (shift @$tree)); } elsif ($elem eq "order") { push (@order, &gst_xml_get_pcdata (shift @$tree)); } elsif ($elem eq "statichost") { &xml_parse_statichost (shift @$tree, \%statichost); } elsif ($elem eq "interface") { &gst_network_xml_parse_interface (shift @$tree, \%interface); } elsif ($elem eq "dialing") { &xml_parse_dialing (shift @$tree, \%dialing); } elsif ($elem eq "dialinstalled") { shift @$tree; } elsif ($elem eq "smbinstalled") { shift @$tree; } elsif ($elem eq "smartdhcpcd") { shift @$tree; } elsif ($elem eq "gwdevunsup") { shift @$tree; } elsif ($elem eq "wireless_device") { shift @$tree; } elsif ($elem eq "profiledb") { &xml_parse_profiledb (shift @$tree, $hash); } else { &gst_report ("xml_unexp_tag", $elem); shift @$tree; } } $$hash{"order"} = \@order unless $#order < 0; $$hash{"searchdomain"} = \@searchdomain unless $#searchdomain < 0; $$hash{"nameserver"} = \@nameserver unless $#nameserver < 0; $$hash{"statichost"} = \%statichost unless scalar keys %statichost == 0; $$hash{"interface"} = \%interface unless scalar keys %interface == 0; $$hash{"dialing"} = \%dialing unless scalar keys %dialing == 0; } # ... sub xml_parse_statichost { my ($tree, $statichost) = @_; my ($ip, @alias, $elem); shift @$tree; while ($elem = shift @$tree) { if ($elem eq "ip") { $ip = &gst_xml_get_pcdata (shift @$tree); } elsif ($elem eq "alias") { push(@alias, &gst_xml_get_pcdata (shift @$tree)); } else { &gst_report ("xml_unexp_tag", $elem); shift @$tree; } } # common regexp for IPv4 and IPv6 if ($ip =~ /([0-9a-fA-F\.:])+/) { $$statichost{$ip} = \@alias; } } sub xml_parse_dialing { my ($tree, $dialing) = @_; my (%hash, $name, $elem); shift @$tree; while ($elem = shift @$tree) { $hash{$elem} = &gst_xml_get_pcdata (shift @$tree); } $name = $hash{"name"}; $$dialing{$name} = \%hash; } # couple of functions for fixing profiles format sub fix_profile_modem_iface { my ($configuration, $section, $dialing) = @_; my ($s, $key, %h); foreach $s (keys %$dialing) { if ($s eq $section) { $h = $$dialing{$s}; foreach $key (keys %$h) { $$configuration{$key} = $$h{$key}; } } } } sub fix_profile_interface_format { my ($interface, $dialing) = @_; my (%configuration, $key, $section); return if (exists $$interface{"configuration"}); foreach $key (keys %$interface) { if ($key !~ /^(dev|enabled|hwaddr)$/) { if ($key eq 'wvsection') { &fix_profile_modem_iface (\%configuration, $$interface{$key}, $dialing); $configuration{"section"} = $$interface{$key}; } else { $dest_key = $key; $configuration{$key} = $$interface{$key}; } delete $$interface{$key}; } } $$interface{"type"} = &gst_network_get_interface_type ($$interface{"dev"}); if (%configuration) { $$interface{"configuration"} = \%configuration; } } sub fix_profile_format { my ($hash) = @_; my ($interfaces, $dialing, $iface); $interfaces = $$hash{"interface"}; $dialing = $$hash{"dialing"}; foreach $iface (keys %$interfaces) { &fix_profile_interface_format ($$interfaces{$iface}, $dialing); } } sub xml_parse_profile { my ($tree, $hash) = @_; my (%profile); &xml_parse_network ($tree, \%profile); # We've got to translate the old profiles format &fix_profile_format (\%profile); push @{$hash->{"profiledb"}{"profile"}}, \%profile; } sub xml_parse_profiledb { my ($tree, $hash) = @_; shift @$tree; # Skip attributes. while (@$tree) { if ($$tree[0] eq "profile") { &xml_parse_profile ($$tree[1], $hash); } else { &gst_report ("xml_unexp_tag", $$tree[0]); } shift @$tree; shift @$tree; } } # --- XML printing --- # sub xml_print_configuration { my ($h) = @_; my @scalar_keys = qw(auto hostname gateway gatewaydev gwdevunsup domain hostmatch workgroup smbdesc winsserver winsuse smbuse smartdhcpcd smbinstalled dialinstalled name); my @array_keys = qw(nameserver searchdomain order); # Hostname, domain, search domains, nameservers. &gst_xml_print_scalars ($h, @scalar_keys); &gst_xml_print_arrays ($h, @array_keys); &network_xml_print_statichost ($h); &xml_print_interfaces ($$h{"interface"}); } sub xml_print_profiledb { my ($h) = @_; &gst_xml_print_vspace (); &gst_xml_print_line ("\n"); &gst_xml_enter (); foreach $i (@{$$h{"profiledb"}{"profile"}}) { gst_xml_print_line ("\n"); gst_xml_enter (); &xml_print_configuration ($i); gst_xml_leave (); gst_xml_print_line ("\n"); } gst_xml_leave (); gst_xml_print_line ("\n"); } sub xml_print_interfaces { my ($h) = @_; my ($dev, $type); foreach $dev (keys %$h) { if ($$h{$dev}{"type"}) { $type = $$h{$dev}{"type"}; delete $$h{$dev}{"type"}; } else { $type = &gst_network_get_interface_type ($dev); } &gst_xml_print_vspace (); &gst_xml_print_line (""); &gst_xml_enter (); &gst_xml_print_hash ($$h{$dev}); &gst_xml_leave (); &gst_xml_print_line (""); } } sub xml_print { my ($h) = @_; &gst_xml_print_begin (); &xml_print_configuration ($h); &xml_print_profiledb ($h); &gst_xml_print_end (); } # Reading profiles sub read_profiledb { my ($hash) = @_; my ($path); my ($tree); $path = gst_file_get_data_path () . "/" . $main::tool->{"name"} . "/"; chmod (0755, $path); chmod (0644, $path . $profile_file); $tree = &gst_xml_scan ($path . $profile_file, $tool); if ($tree && scalar @$tree) { if ($$tree[0] eq 'profiledb') { xml_parse_profiledb ($$tree[1], $hash); } else { gst_report ('xml_unexp_tag', $$tree[0]); } } } # Writing profiles sub write_profiledb { my ($hash) = @_; my $profiledb = $hash->{'profiledb'}; my $path = &gst_file_get_data_path () . "/" . $main::tool->{'name'} . "/"; chmod (0755, $path); if ($profiledb) { # Write our profiles. my $fh = &gst_file_open_write_from_names ($path . $profile_file); if ($fh) { local *STDOUT = $fh; &xml_print_profiledb ($hash); close ($fh); delete $hash->{'profiledb'}; } } else { gst_file_remove ($path . $profile_file); } chmod (0644, $path . $profile_file); } # Top-level actions. sub get { my $hash; # network interface stuff $hash = &gst_network_conf_get (); &read_profiledb (\%$hash); &gst_network_ensure_loopback ($hash); &gst_report_end (); &xml_print ($hash); } sub set { my $hash; $hash = &xml_parse (); &write_profiledb ($hash); &gst_network_conf_set ($hash); &gst_report_end (); } sub set_profile { my ($tool, $profile_name) = @_; my ($hash, $profiles, $profile); &read_profiledb (\%$hash); $profiles = $$hash{"profiledb"}{"profile"}; foreach $profile (@$profiles) { if ($$profile{"name"} eq $profile_name) { &gst_network_conf_set ($profile); } } &gst_report_end (); } sub save_profiles { my $hash; $hash = &xml_parse (); &write_profiledb ($hash); &gst_report_end (); } # --- Filter config: XML in, XML out --- # sub filter { my $hash; $hash = &xml_parse (); &gst_report_end (); &xml_print ($hash); } sub enable_iface { my ($tool, $iface, $enabled) = @_; my (%dist_attrib, $iface_set); my %hash = ("configuration" => {"file" => $iface}); %dist_attrib = &gst_network_get_interface_replace_table (); $iface_set = $dist_attrib{"iface_set"}; &$iface_set (\%hash, undef, $enabled, 1); # small hack for ensuring that the interface is really down # when messing ifup/ifdown/ifconfig calls if ($enabled == 0) { gst_file_run ("ifconfig $iface down"); &drop_dhcp_connection ($iface); &drop_pppd_connection ($iface); } # Don't forget to do gst_end when the reports are over! &gst_report_end (); # XML output would come here, but this directive returns no XML. } sub enable_iface_with_config { my ($tool) = @_; my ($tree, $hash, $ret, $str); # Scan XML to tree. $tree = &gst_xml_scan (); if (shift @$tree eq "interface") { $hash = &gst_network_xml_parse_interface (shift @$tree); } $ret = &gst_network_enable_iface_with_config ($hash); &gst_report_end (); &gst_xml_print_begin ("enable-iface"); &gst_xml_print_pcdata ("success", ($ret == 0) ? "1" : "0"); &gst_xml_print_end ("enable-iface"); } sub list_ifaces { my ($tool) = @_; my ($ifaces, $iface, @arr); $ifaces = &gst_network_interfaces_get_info (); foreach $iface (keys %$ifaces) { push @arr, $$ifaces{$iface}; } &gst_report_end (); &gst_xml_print_begin ("network-ifaces"); &gst_xml_print_structure (\@arr, "interface"); &gst_xml_print_end ("network-ifaces"); } sub detect_modem { my ($tool) = @_; my ($device); $device = &gst_network_autodetect_modem (); &gst_report_end (); &gst_xml_print_begin ("network-modem-device"); &gst_xml_print_pcdata ("device", $device) if ($device ne undef); &gst_xml_print_end ("network-modem-device"); } sub detect_essids { my ($tool, $iface) = @_; my (@essids); $essids = &gst_network_detect_essids ($iface); &gst_report_end (); &gst_xml_print_begin ("essids"); &gst_xml_print_structure ($essids, "network"); &gst_xml_print_end ("essids"); } sub set_gateway { my ($tool, $iface, $address) = @_; &gst_network_route_set_default_gw ($iface, $address); &gst_report_end (); } # --- Main --- # # get, set and filter are special cases that don't need more parameters than a ref to their function. # Read general.pl.in:gst_run_directive to know about the format of this hash. $directives = { "get" => [ \&get, [], "" ], "set" => [ \&set, [], "" ], "filter" => [ \&filter, [], "" ], "list_ifaces" => [ \&list_ifaces, [], "List interfaces and active/inactive status." ], "save_profiles" => [ \&save_profiles, [], "Save the profiles list" ], "set_profile" => [ \&set_profile, [ "profile_name" ], "Set a profile as the default configuration" ], "enable_iface" => [ \&enable_iface, [ "interface", "enabled" ], "Immediatly enable or disable a given interface. " . "interface is the file tag value, enabled is 1 or 0." ], "enable_iface_with_config" => [ \&enable_iface_with_config, [], "Enable an interface with a given configuration" ], "detect_modem" => [ \&detect_modem, [], "Detects the modem device." ], "detect_essids" => [ \&detect_essids, [ "interface" ], "Detects active wireless networks" ], "set_gateway" => [ \&set_gateway, [ "interface", "address" ], "Sets the default gateway" ] }; $tool = &gst_init ($name, $version, $description, $directives, @ARGV); &gst_platform_ensure_supported ($tool, @platforms); &gst_run ($tool);