summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStig Thormodsrud <stig@vyatta.com>2007-11-27 10:37:15 -0800
committerStig Thormodsrud <stig@vyatta.com>2007-11-27 10:37:15 -0800
commitfae7c4099efc2f247ed9eb4a52f3839bcedf987a (patch)
tree07c0a7c5a20c5d86c0cfbdfa2801a261c2741194
parent65b95aa0fd0210501bd828299f561925269b6321 (diff)
downloadvyatta-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.am1
-rw-r--r--debian/control3
-rw-r--r--debian/vyatta-cfg.postinst.in8
-rw-r--r--scripts/vyatta-interfaces.pl339
-rw-r--r--templates/interfaces/ethernet/node.tag/address/node.def7
-rw-r--r--templates/interfaces/ethernet/node.tag/vif/node.tag/address/node.def9
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 $(../../@).$(../@) "