diff options
-rwxr-xr-x | scripts/VyattaMisc.pm | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/scripts/VyattaMisc.pm b/scripts/VyattaMisc.pm index 45bd7d4..3a083ec 100755 --- a/scripts/VyattaMisc.pm +++ b/scripts/VyattaMisc.pm @@ -231,4 +231,136 @@ sub isClusteringEnabled { } } +# $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); +} + return 1; |