diff options
author | Stig Thormodsrud <stig@vyatta.com> | 2007-11-27 10:37:15 -0800 |
---|---|---|
committer | Stig Thormodsrud <stig@vyatta.com> | 2007-11-27 10:37:15 -0800 |
commit | fae7c4099efc2f247ed9eb4a52f3839bcedf987a (patch) | |
tree | 07c0a7c5a20c5d86c0cfbdfa2801a261c2741194 | |
parent | 65b95aa0fd0210501bd828299f561925269b6321 (diff) | |
download | vyatta-cfg-fae7c4099efc2f247ed9eb4a52f3839bcedf987a.tar.gz vyatta-cfg-fae7c4099efc2f247ed9eb4a52f3839bcedf987a.zip |
Fix 2497: check for duplicate ip address.
Also while we're add it, allow user to set an ipv6 address or get address from dhcp.
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | debian/control | 3 | ||||
-rw-r--r-- | debian/vyatta-cfg.postinst.in | 8 | ||||
-rw-r--r-- | scripts/vyatta-interfaces.pl | 339 | ||||
-rw-r--r-- | templates/interfaces/ethernet/node.tag/address/node.def | 7 | ||||
-rw-r--r-- | templates/interfaces/ethernet/node.tag/vif/node.tag/address/node.def | 9 |
6 files changed, 359 insertions, 8 deletions
diff --git a/Makefile.am b/Makefile.am index f048395..c757ac1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,6 +34,7 @@ sbin_SCRIPTS += scripts/vyatta-output-config.pl sbin_SCRIPTS += scripts/vyatta-save-config.pl sbin_SCRIPTS += scripts/vyatta-load-config.pl sbin_SCRIPTS += scripts/vyatta-cfg-notify +sbin_SCRIPTS += scripts/vyatta-interfaces.pl share_perl5_DATA = scripts/VyattaConfig.pm share_perl5_DATA += scripts/VyattaConfigDOMTree.pm diff --git a/debian/control b/debian/control index feb160c..10e1156 100644 --- a/debian/control +++ b/debian/control @@ -13,7 +13,8 @@ Depends: bash (>= 3.1), procps (>= 1:3.2.7-3), quagga, coreutils (>= 5.97-5.3), - vyatta-config-migrate + vyatta-config-migrate, + dhcp3-client Suggests: util-linux (>= 2.13-5), net-tools, ethtool, diff --git a/debian/vyatta-cfg.postinst.in b/debian/vyatta-cfg.postinst.in index 05daf3b..4690c18 100644 --- a/debian/vyatta-cfg.postinst.in +++ b/debian/vyatta-cfg.postinst.in @@ -6,3 +6,11 @@ sysconfdir=@sysconfdir@ update-rc.d vyatta-ofr defaults 90 >/dev/null # do we want to start vyatta-ofr here in postinst? +if [ "$sysconfdir" != "/etc" ]; then + # remove the config files and replace with blank ones + for conf in dhcp3/dhclient.conf + do + [ -f /etc/$conf ] && mv -f /etc/$conf /etc/$conf.vyatta-save + touch /etc/$conf + done +fi diff --git a/scripts/vyatta-interfaces.pl b/scripts/vyatta-interfaces.pl new file mode 100644 index 0000000..d7ba950 --- /dev/null +++ b/scripts/vyatta-interfaces.pl @@ -0,0 +1,339 @@ +#!/usr/bin/perl +# +# Module: vyatta-interfaces.pl +# +# **** License **** +# Version: VPL 1.0 +# +# The contents of this file are subject to the Vyatta Public License +# Version 1.0 ("License"); you may not use this file except in +# compliance with the License. You may obtain a copy of the License at +# http://www.vyatta.com/vpl +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# This code was originally developed by Vyatta, Inc. +# Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc. +# All Rights Reserved. +# +# Author: Stig Thormodsrud +# Date: November 2007 +# Description: Script to assign addresses to interfaces. +# +# **** End License **** +# + +use lib "/opt/vyatta/share/perl5/"; +use VyattaConfig; +use VyattaMisc; +use Getopt::Long; + +use NetAddr::IP; + +use strict; +use warnings; + +my $dhcp_daemon = '/sbin/dhclient'; +my $dhcp_conf = '/etc/dhcp3/dhclient.conf'; +my $dhcp_pid = '/var/run/dhclient.pid'; +my $dhcp_leases = '/var/lib/dhcp3/dhclient.leases'; + + +my ($eth_update, $eth_delete, $addr, $dev); +GetOptions("eth-addr-update=s" => \$eth_update, + "eth-addr-delete=s" => \$eth_delete, + "valid-addr=s" => \$addr, + "dev=s" => \$dev, +); + +if (defined $eth_update) { update_eth_addrs($eth_update, $dev); } +if (defined $eth_delete) { delete_eth_addrs($eth_delete, $dev); } +if (defined $addr) { is_valid_addr($addr, $dev); } + + +sub is_ip_duplicate { + my $ip = shift; + + # + # get a list of all ipv4 and ipv6 addresses + # + my @ipaddrs = `ip addr show | grep inet | cut -d" " -f6`; + chomp @ipaddrs; + my %ipaddrs_hash = map { $_ => 1 } @ipaddrs; + + if (defined $ipaddrs_hash{$ip}) { + return 1; + } else { + return 0; + } +} + +sub is_dhcp_running { + if (-f $dhcp_pid) { + my $pid = `cat $dhcp_pid`; + chomp $pid; + my $ps = `ps -p $pid -o comm=`; + + if (defined($ps) && $ps ne "") { + return 1; + } + } + return 0; +} + +sub dhcp_start_daemon { + my $cmd = "$dhcp_daemon -q -nw &"; + system($cmd); +} + +sub dhcp_stop_daemon { + if (is_dhcp_running()) { + my $pid = `cat $dhcp_pid`; + system("kill $pid"); + } + system("rm -f $dhcp_pid"); +} + +sub dhcp_restart_daemon { + if (is_dhcp_running()) { + dhcp_stop_daemon(); + } + dhcp_start_daemon(); +} + +sub dhcp_release_addr { + my $intf = shift; + my $cmd = "$dhcp_daemon -q -r $intf 2> /dev/null"; + system($cmd); +} + +sub dhcp_write_file { + my ($file, $data) = @_; + + open(my $fh, '>', $file) || die "Couldn't open $file - $!"; + print $fh $data; + close $fh; +} + +sub dhcp_conf_header { + my $output; + + my $date = `date`; + chomp $date; + $output = "#\n# autogenerated by vyatta-interfaces.pl on $date\n#\n"; + $output .= "request subnet-mask, broadcast-address, time-offset, routers,\n"; + $output .= "\tdomain-name, domain-name-servers, host-name,\n"; + $output .= "\tinterface-mtu;\n\n"; + return $output; +} + +sub dhcp_get_interfaces { + my @dhcp_intfs; + + my $config = new VyattaConfig; + + $config->setLevel("interfaces ethernet"); + my @eths = $config->listNodes(); + foreach my $eth (@eths) { + $config->setLevel("interfaces ethernet $eth"); + if ($config->exists("address")) { + my @addrs = $config->returnValues("address"); + foreach my $addr (@addrs) { + if (defined $addr && $addr eq "dhcp") { + push @dhcp_intfs, $eth; + } + } + } + $config->setLevel("interfaces ethernet $eth vif"); + my @vifs = $config->listNodes(); + foreach my $vif (@vifs) { + $config->setLevel("interfaces ethernet $eth vif $vif"); + my @addrs = $config->returnValues("address"); + foreach my $addr (@addrs) { + if (defined $addr && $addr eq "dhcp") { + push @dhcp_intfs, "$eth.$vif"; + } + } + } + } + return @dhcp_intfs; +} + +sub is_dhcp_enabled { + my $intf = shift; + + my $config = new VyattaConfig; + + if ($intf =~ m/(\w+)\.(\d)/) { + $config->setLevel("interfaces ethernet $1 vif $2"); + } else { + $config->setLevel("interfaces ethernet $intf"); + } + my @addrs = $config->returnOrigValues("address"); + foreach my $addr (@addrs) { + if (defined $addr && $addr eq "dhcp") { + return 1; + } + } + return 0; +} + +sub is_address_enabled { + my $intf = shift; + + my $config = new VyattaConfig; + + if ($intf =~ m/(\w+)\.(\d)/) { + $config->setLevel("interfaces ethernet $1 vif $2"); + } else { + $config->setLevel("interfaces ethernet $intf"); + } + my @addrs = $config->returnOrigValues("address"); + foreach my $addr (@addrs) { + if (defined $addr && $addr ne "dhcp") { + return 1; + } + } + return 0; +} + +sub dhcp_update_config { + my $output = dhcp_conf_header(); + + my $config = new VyattaConfig; + my $dhcp_instances = 0; + my @dhcp_intfs = dhcp_get_interfaces(); + foreach my $intf (@dhcp_intfs) { + $output .= "interface \"$intf\" {\n}\n\n"; + $dhcp_instances++; + } + + if ($dhcp_instances > 0) { + my $conf_file = $dhcp_conf; + dhcp_write_file($conf_file, $output); + dhcp_restart_daemon(); + } + return $dhcp_instances; +} + +sub update_dhcp_client { + my $dhcp_instances = dhcp_update_config(); + if ($dhcp_instances == 0) { + dhcp_stop_daemon(); + } +} + +sub is_ip_v4_or_v6 { + my $addr = shift; + + my $ip = NetAddr::IP->new($addr); + if (defined $ip && $ip->version() == 4) { + return 4; + } + $ip = NetAddr::IP->new6($addr); + if (defined $ip && $ip->version() == 6) { + return 6; + } + + return undef; +} + +sub update_eth_addrs { + my ($addr, $intf) = @_; + + if ($addr eq "dhcp") { + update_dhcp_client(); + return; + } + my $version = is_ip_v4_or_v6($addr); + if (!defined $version) { + exit 1; + } + + if ($version == 4) { + return system("ip addr add $addr broadcast + dev $intf"); + } + if ($version == 6) { + return system("ip -6 addr add $addr dev $intf"); + } + print "Error: Invalid address/prefix [$addr] for interface $intf\n"; + exit 1; +} + +sub delete_eth_addrs { + my ($addr, $intf) = @_; + + if ($addr eq "dhcp") { + dhcp_release_addr($intf); + update_dhcp_client(); + return; + } + my $version = is_ip_v4_or_v6($addr); + if (!defined $version) { + exit 1; + } + if ($version == 4) { + return system("ip addr del $addr dev $intf"); + } + if ($version == 6) { + return system("ip -6 addr del $addr dev $intf"); + } +} + +sub is_valid_addr { + my ($addr_net, $intf) = @_; + + if ($addr_net eq "dhcp") { + if (is_dhcp_enabled($intf)) { + print "Error: dhcp already configured for $intf\n"; + exit 1; + } + if (is_address_enabled($intf)) { + print "Error: remove static addresses before enabling dhcp for $intf\n"; + exit 1; + } + exit 0; + } + + my ($addr, $net); + if ($addr_net =~ m/^([0-9\.\:]+)\/(\d+)$/) { + $addr = $1; + $net = $2; + } else { + exit 1; + } + + my $version = is_ip_v4_or_v6($addr_net); + if (!defined $version) { + exit 1; + } + + if (is_dhcp_enabled($intf)) { + print "Error: remove dhcp before adding static addresses for $intf\n"; + exit 1; + } + if (is_ip_duplicate($addr_net)) { + print "Error: duplicate address/prefix [$addr_net]\n"; + exit 1; + } + + if ($version == 4) { + if ($net > 0 && $net <= 32) { + exit 0; + } + } + if ($version == 6) { + if ($net > 1 && $net <= 128) { + exit 0; + } + } + + exit 1; +} + +exit 0; + +# end of file diff --git a/templates/interfaces/ethernet/node.tag/address/node.def b/templates/interfaces/ethernet/node.tag/address/node.def index 83ce62f..9447c99 100644 --- a/templates/interfaces/ethernet/node.tag/address/node.def +++ b/templates/interfaces/ethernet/node.tag/address/node.def @@ -1,5 +1,6 @@ multi: -type: ipv4net +type: txt help: "Set IPv4 address and prefix for this interface" -update: "sudo ip addr add $(@) broadcast + dev $(../@)"; "Error setting address $(@) on dev $(../@)" -delete: "sudo ip addr del $(@) dev $(../@)"; "Error deleting address $(@) on dev $(../@)" +syntax: exec "/opt/vyatta/sbin/vyatta-interfaces.pl --valid-addr $(@) --dev $(../@)" +create: "sudo /opt/vyatta/sbin/vyatta-interfaces.pl --eth-addr-update $(@) --dev $(../@)"; "Error setting address $(@) on dev $(../@)" +delete: "sudo /opt/vyatta/sbin/vyatta-interfaces.pl --eth-addr-delete $(@) --dev $(../@)"; "Error deleting address $(@) on dev $(../@)" diff --git a/templates/interfaces/ethernet/node.tag/vif/node.tag/address/node.def b/templates/interfaces/ethernet/node.tag/vif/node.tag/address/node.def index 08bf3ea..a3c0b5c 100644 --- a/templates/interfaces/ethernet/node.tag/vif/node.tag/address/node.def +++ b/templates/interfaces/ethernet/node.tag/vif/node.tag/address/node.def @@ -1,5 +1,6 @@ multi: -type: ipv4net -help: "Set IPv4 address and prefix for this interface" -update: "sudo ip addr add $(@) dev $(../../@).$(../@)"; "Error setting address $(@) on dev $(../../@).$(../@)" -delete: "sudo ip addr del $(@) dev $(../../@).$(../@)"; "Error deleting address $(@) on dev $(../../@).$(../@)" +type: txt +help: "Set IPv4 address and prefix for this vif interface" +syntax: exec "/opt/vyatta/sbin/vyatta-interfaces.pl --valid-addr $(@) --dev $(../../@).$(../@) " +create: "sudo /opt/vyatta/sbin/vyatta-interfaces.pl --eth-addr-update $(@) --dev $(../../@).$(../@) "; "Error setting address $(@) on dev $(../../@) $(../@) " +delete: "sudo /opt/vyatta/sbin/vyatta-interfaces.pl --eth-addr-delete $(@) --dev $(../../@).$(../@) "; "Error deleting address $(@) on dev $(../../@).$(../@) " |