summaryrefslogtreecommitdiff
path: root/lib/Vyatta/Misc.pm
diff options
context:
space:
mode:
authorStephen Hemminger <stephen.hemminger@vyatta.com>2008-11-21 17:09:30 -0800
committerStephen Hemminger <stephen.hemminger@vyatta.com>2008-11-21 17:09:30 -0800
commit32cefc2d846f9946bf6e5b84cd914b5e2959dbfa (patch)
tree0bbb5d52e5621b84a897bd023ae51e15c9e72be9 /lib/Vyatta/Misc.pm
parent6d87be16190a658ac324488024a82961774f0ece (diff)
downloadvyatta-cfg-32cefc2d846f9946bf6e5b84cd914b5e2959dbfa.tar.gz
vyatta-cfg-32cefc2d846f9946bf6e5b84cd914b5e2959dbfa.zip
Convert VyattaConfig (et al) to Vyatta::Config
Use hierarchal directory structure
Diffstat (limited to 'lib/Vyatta/Misc.pm')
-rwxr-xr-xlib/Vyatta/Misc.pm486
1 files changed, 486 insertions, 0 deletions
diff --git a/lib/Vyatta/Misc.pm b/lib/Vyatta/Misc.pm
new file mode 100755
index 0000000..463f5d1
--- /dev/null
+++ b/lib/Vyatta/Misc.pm
@@ -0,0 +1,486 @@
+#!/usr/bin/perl
+
+# Module: VyattaMisc.pm
+#
+# Author: Marat <marat@vyatta.com>
+# Date: 2007
+# Description: Implements miscellaneous commands
+
+# **** License ****
+# 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.
+#
+# This code was originally developed by Vyatta, Inc.
+# Portions created by Vyatta are Copyright (C) 2006, 2007, 2008 Vyatta, Inc.
+# All Rights Reserved.
+# **** End License ****
+
+package Vyatta::Misc;
+require Exporter;
+@ISA = qw(Exporter);
+@EXPORT = qw(getNetAddIP isIpAddress is_ip_v4_or_v6);
+@EXPORT_OK = qw(getNetAddIP isIpAddress is_ip_v4_or_v6);
+
+
+use strict;
+
+use Vyatta::Config;
+
+sub get_sysfs_value {
+ my ($intf, $name) = @_;
+
+ open (my $statf, '<', "/sys/class/net/$intf/$name")
+ or die "Can't open statistics file /sys/class/net/$intf/$name";
+
+ my $value = <$statf>;
+ chomp $value if defined $value;
+ close $statf;
+ return $value;
+}
+
+# check if interace is configured to get an IP address using dhcp
+sub is_dhcp_enabled {
+ my ($intf, $outside_cli) = @_;
+
+ my $config = new Vyatta::Config;
+ if (!($outside_cli eq '')) {
+ $config->{_active_dir_base} = "/opt/vyatta/config/active/";
+ }
+
+ if ($intf =~ m/^eth/) {
+ if ($intf =~ m/(\w+)\.(\d+)/) {
+ $config->setLevel("interfaces ethernet $1 vif $2");
+ } else {
+ $config->setLevel("interfaces ethernet $intf");
+ }
+ } elsif ($intf =~ m/^br/) {
+ $config->setLevel("interfaces bridge $intf");
+ } elsif ($intf =~ m/^bond/) {
+ if ($intf =~ m/(\w+)\.(\d+)/) {
+ $config->setLevel("interfaces bonding $1 vif $2");
+ } else {
+ $config->setLevel("interfaces bonding $intf");
+ }
+ } else {
+ #
+ # add other interfaces that can be configured to use dhcp above
+ #
+ return 0;
+ }
+ my @addrs = $config->returnOrigValues("address");
+ foreach my $addr (@addrs) {
+ if (defined $addr && $addr eq "dhcp") {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+# return dhclient related files for interface
+sub generate_dhclient_intf_files {
+ my $intf = shift;
+ my $dhclient_dir = '/var/lib/dhcp3/';
+
+ $intf =~ s/\./_/g;
+ my $intf_config_file = $dhclient_dir . 'dhclient_' . $intf . '.conf';
+ my $intf_process_id_file = $dhclient_dir . 'dhclient_' . $intf . '.pid';
+ my $intf_leases_file = $dhclient_dir . 'dhclient_' . $intf . '.leases';
+ return ($intf_config_file, $intf_process_id_file, $intf_leases_file);
+
+}
+
+# getInterfacesIPadresses() returns IP addresses for the interface type passed to it
+# possible type of interfaces : 'broadcast', 'pointopoint', 'multicast', 'all'
+# the loopback IP address is never returned with any of the above parameters
+sub getInterfacesIPadresses {
+
+ my $interface_type = shift;
+ if (!($interface_type =~ m/broadcast|pointopoint|multicast|all/)) {
+ print STDERR "Invalid interface type specified to retrive IP addresses for\n";
+ return undef;
+ }
+ my @interfaces_on_system = `ifconfig -a | awk '\$2 ~ /Link/ {print \$1}'`;
+ chomp @interfaces_on_system;
+ my @intf_ips = ();
+ my $intf_ips_index = 0;
+ foreach my $intf_system (@interfaces_on_system) {
+ if (!($intf_system eq 'lo')) {
+ my $is_intf_interface_type = 0;
+ if (!($interface_type eq 'all')) {
+ $is_intf_interface_type =
+ `ip link show $intf_system 2>/dev/null | grep -i $interface_type | wc -l`;
+ } else {
+ $is_intf_interface_type = 1;
+ }
+ if ($is_intf_interface_type > 0) {
+ $intf_ips[$intf_ips_index] =
+ `ip addr show $intf_system 2>/dev/null | grep inet | grep -v inet6 | awk '{print \$2}'`;
+ if (!($intf_ips[$intf_ips_index] eq '')){
+ $intf_ips_index++;
+ }
+ }
+ }
+ }
+ chomp @intf_ips;
+ return (@intf_ips);
+
+}
+
+
+sub getNetAddrIP {
+ my ($interface);
+ ($interface) = @_;
+
+ if ($interface eq '') {
+ print STDERR "Error: No interface specified.\n";
+ return undef;
+ }
+
+ my $ifconfig_out = `ifconfig $interface`;
+ $ifconfig_out =~ /inet addr:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/;
+ my $ip = $1;
+ if ($ip eq '') {
+ print STDERR "Error: Unable to determine IP address for interface \'$interface\'.\n";
+ return undef;
+ }
+
+ $ifconfig_out =~ /Mask:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/;
+ my $netmask = $1;
+ if ($netmask eq '') {
+ print STDERR "Error: Unable to determine netmask for interface \'$interface\'.\n";
+ return undef;
+ }
+
+ use NetAddr::IP; # This library is available via libnetaddr-ip-perl.deb
+ my $naip = new NetAddr::IP($ip, $netmask);
+ return $naip;
+}
+
+sub is_ip_v4_or_v6 {
+ my $addr = shift;
+
+ my $ip = NetAddr::IP->new($addr);
+ if (defined $ip && $ip->version() == 4) {
+ #
+ # the call to IP->new() will accept 1.1 and consider
+ # it to be 1.1.0.0, so add a check to force all
+ # 4 octets to be defined
+ #
+ if ($addr !~ /\d+\.\d+\.\d+\.\d+/) {
+ return undef;
+ }
+ return 4;
+ }
+ $ip = NetAddr::IP->new6($addr);
+ if (defined $ip && $ip->version() == 6) {
+ return 6;
+ }
+
+ return undef;
+}
+
+sub isIpAddress {
+ my $ip = shift;
+
+ $_ = $ip;
+ if ( ! /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) {
+ return 0;
+ }
+ else {
+ my @ips = split /\./, $ip;
+ my $octet = 0;
+ my $counter = 0;
+
+ foreach $octet (@ips) {
+ if (($octet < 0) || ($octet > 255)) { return 0; }
+ if (($counter == 0) && ($octet < 1)) { return 0; }
+ $counter++;
+ }
+ }
+
+ return 1;
+}
+
+sub isClusterIP {
+ my ($vc, $ip) = @_;
+
+ if (!(defined($ip))) {
+ return 0;
+ }
+
+ my @cluster_groups = $vc->listNodes('cluster group');
+ foreach my $cluster_group (@cluster_groups) {
+ my @services = $vc->returnValues("cluster group $cluster_group service");
+ foreach my $service (@services) {
+ if ($ip eq $service) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+sub remove_ip_prefix {
+ my @addr_nets = @_;
+
+ s/\/\d+$// for @addr_nets;
+ return @addr_nets;
+}
+
+sub is_ip_in_list {
+ my ($ip, @list) = @_;
+
+ if (!defined($ip) || scalar(@list) == 0) {
+ return 0;
+ }
+
+ @list = remove_ip_prefix(@list);
+ my %list_hash = map { $_ => 1 } @list;
+ if (defined($list_hash{$ip})) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+sub get_eth_ip_addrs {
+ my ($vc, $eth_path) = @_;
+
+ my @addrs = ();
+ my @virt_addrs = ();
+
+ $vc->setLevel("interfaces ethernet $eth_path");
+ @addrs = $vc->returnValues("address");
+
+ #
+ # check for VIPs
+ #
+ $vc->setLevel("interfaces ethernet $eth_path vrrp vrrp-group");
+ my @vrrp_groups = $vc->listNodes();
+ foreach my $group (@vrrp_groups) {
+ $vc->setLevel("interfaces ethernet $eth_path vrrp vrrp-group $group");
+ @virt_addrs = $vc->returnValues("virtual-address");
+ }
+ return (@addrs, @virt_addrs);
+}
+
+sub get_tun_ip_addrs {
+ my ($vc, $tun_path) = @_;
+
+ my @addrs = ();
+ my @virt_addrs = ();
+
+ $vc->setLevel("interfaces tunnel $tun_path");
+ @addrs = $vc->returnValues("address");
+
+ #
+ # check for VIPs
+ #
+ $vc->setLevel("interfaces tunnel $tun_path vrrp vrrp-group");
+ my @vrrp_groups = $vc->listNodes();
+ foreach my $group (@vrrp_groups) {
+ $vc->setLevel("interfaces tunnel $tun_path vrrp vrrp-group $group");
+ @virt_addrs = $vc->returnValues("virtual-address");
+ }
+ return (@addrs, @virt_addrs);
+}
+
+sub get_serial_ip_addrs {
+ #
+ # Todo when serial is added
+ #
+}
+
+sub isIPinInterfaces {
+ my ($vc, $ip_addr, @interfaces) = @_;
+
+ if (!(defined($ip_addr))) {
+ return 0;
+ }
+
+ foreach my $intf (@interfaces) {
+ # regular ethernet
+ if ($intf =~ m/^eth\d+$/) {
+ my @addresses = get_eth_ip_addrs($vc, $intf);
+ if (is_ip_in_list($ip_addr, @addresses)) {
+ return 1;
+ }
+ }
+ # ethernet vlan
+ if ($intf =~ m/^eth(\d+).(\d+)$/) {
+ my $eth = "eth$1";
+ my $vif = $2;
+ my @addresses = get_eth_ip_addrs($vc, "$eth vif $vif");
+ if (is_ip_in_list($ip_addr, @addresses)) {
+ return 1;
+ }
+ }
+ # tunnel
+ if ($intf =~ m/^tun\d+$/) {
+ my @addresses = get_tun_ip_addrs($vc, $intf);
+ if (is_ip_in_list($ip_addr, @addresses)) {
+ return 1;
+ }
+ }
+ # serial
+ if ($intf =~ m/^wan(\d+).(\d+)$/) {
+ my @addresses = get_serial_ip_addrs($vc, $intf);
+ if (is_ip_in_list($ip_addr, @addresses)) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+sub isClusteringEnabled {
+ my ($vc) = @_;
+
+ if ($vc->exists('cluster')) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+# $str: string representing a port number
+# returns ($success, $err)
+# $success: 1 if success. otherwise undef
+# $err: error message if failure. otherwise undef
+sub isValidPortNumber {
+ my $str = shift;
+ return (undef, "\"$str\" is not a valid port number")
+ if (!($str =~ /^\d+$/));
+ return (undef, "invalid port \"$str\" (must be between 1 and 65535)")
+ if ($str < 1 || $str > 65535);
+ return (1, undef);
+}
+
+# $str: string representing a port range
+# $sep: separator for range
+# returns ($success, $err)
+# $success: 1 if success. otherwise undef
+# $err: error message if failure. otherwise undef
+sub isValidPortRange {
+ my $str = shift;
+ my $sep = shift;
+ return (undef, "\"$str\" is not a valid port range")
+ if (!($str =~ /^(\d+)$sep(\d+)$/));
+ my ($start, $end) = ($1, $2);
+ my ($success, $err) = isValidPortNumber($start);
+ return (undef, $err) if (!defined($success));
+ ($success, $err) = isValidPortNumber($end);
+ return (undef, $err) if (!defined($success));
+ return (undef, "invalid port range ($end is not greater than $start)")
+ if ($end <= $start);
+ return (1, undef);
+}
+
+my %port_name_hash_tcp = ();
+my %port_name_hash_udp = ();
+sub buildPortNameHash {
+ open(IF, "</etc/services") or return 0;
+ while (<IF>) {
+ s/#.*$//;
+ my $is_tcp = /\d\/tcp\s/;
+ my @names = grep (!/\//, (split /\s/));
+ foreach my $name (@names) {
+ if ($is_tcp) {
+ $port_name_hash_tcp{$name} = 1;
+ } else {
+ $port_name_hash_udp{$name} = 1;
+ }
+ }
+ }
+ close IF;
+ return 1;
+}
+
+# $str: string representing a port name
+# $proto: protocol to check
+# returns ($success, $err)
+# $success: 1 if success. otherwise undef
+# $err: error message if failure. otherwise undef
+sub isValidPortName {
+ my $str = shift;
+ my $proto = shift;
+ return (undef, "\"\" is not a valid port name for protocol \"$proto\"")
+ if ($str eq '');
+ buildPortNameHash() if ((keys %port_name_hash_tcp) == 0);
+ return (1, undef) if ($proto eq 'tcp' && defined($port_name_hash_tcp{$str}));
+ return (1, undef) if ($proto eq '6' && defined($port_name_hash_tcp{$str}));
+ return (1, undef) if ($proto eq 'udp' && defined($port_name_hash_udp{$str}));
+ return (1, undef) if ($proto eq '17' && defined($port_name_hash_udp{$str}));
+ return (undef, "\"$str\" is not a valid port name for protocol \"$proto\"");
+}
+
+sub getPortRuleString {
+ my $port_str = shift;
+ my $can_use_port = shift;
+ my $prefix = shift;
+ my $proto = shift;
+ my $negate = '';
+ if ($port_str =~ /^!(.*)$/) {
+ $port_str = $1;
+ $negate = '! ';
+ }
+ $port_str =~ s/-/:/g;
+
+ my $num_ports = 0;
+ my @port_specs = split /,/, $port_str;
+ foreach my $port_spec (@port_specs) {
+ my ($success, $err) = (undef, undef);
+ if ($port_spec =~ /:/) {
+ ($success, $err) = isValidPortRange($port_spec, ':');
+ if (defined($success)) {
+ $num_ports += 2;
+ next;
+ } else {
+ return (undef, $err);
+ }
+ }
+ if ($port_spec =~ /^\d/) {
+ ($success, $err) = isValidPortNumber($port_spec);
+ if (defined($success)) {
+ $num_ports += 1;
+ next;
+ } else {
+ return (undef, $err);
+ }
+ }
+ ($success, $err) = isValidPortName($port_spec, $proto);
+ if (defined($success)) {
+ $num_ports += 1;
+ next;
+ } else {
+ return (undef, $err);
+ }
+ }
+
+ my $rule_str = '';
+ if (($num_ports > 0) && (!$can_use_port)) {
+ return (undef, "ports can only be specified when protocol is \"tcp\" "
+ . "or \"udp\" (currently \"$proto\")");
+ }
+ if ($num_ports > 15) {
+ return (undef, "source/destination port specification only supports "
+ . "up to 15 ports (port range counts as 2)");
+ }
+ if ($num_ports > 1) {
+ $rule_str = " -m multiport --${prefix}ports ${negate}${port_str}";
+ } elsif ($num_ports > 0) {
+ $rule_str = " --${prefix}port ${negate}${port_str}";
+ }
+
+ return ($rule_str, undef);
+}
+
+1;