IPTables-Rule
view release on metacpan or search on metacpan
lib/IPTables/Rule.pm view on Meta::CPAN
my $max_length = 256;
if ( $arg ) {
if ( length($arg) > $max_length ) {
__errstr($self, 'comment too long (>'.$max_length.'): '.$arg);
return;
}
if ( $arg =~ m/[\"\']/ ) {
__errstr($self, 'quotes not permitted: '.$arg);
return;
}
$self->{comment} = $arg;
}
return $self->{comment};
}
*compile = \&generate;
sub generate {
my $self = shift;
# what is required?
unless ( $self->{chain} ) {
__errstr($self, 'Chain must be specified');
return;
}
# ports are only valid with protocol tcp and udp
if ( defined($self->{spt}) and $self->{proto} !~ m/\A(tcp|udp)\z/i ) {
__errstr($self, 'Protocol must be TCP or UDP when specifying source port');
return;
}
if ( defined($self->{dpt}) and $self->{proto} !~ m/\A(tcp|udp)\z/i ) {
__errstr($self, 'Protocol must be TCP or UDP when specifying destinatipn port');
return;
}
# cant use 'logprefix' unless the target is 'log'
if ( defined($self->{logprefix}) and $self->{target} !~ m/\Alog\z/i ) {
__errstr($self, 'Target must be LOG when specifying log prefix');
return;
}
# ipversion matches the source/dest addresses?
if ( $self->{ipver} eq '4' ) {
if ( $self->{src} ) {
# make sure it's ipv4
unless ( __is_valid_inet4($self->{src}) ) {
__errstr($self, 'IP Version is 4 but source is not valid IPv4');
return;
}
}
if ( $self->{dst} ) {
# make sure it's ipv4
unless ( __is_valid_inet4($self->{dst}) ) {
__errstr($self, 'IP Version is 4 but destination is not valid IPv4');
return;
}
}
} elsif ( $self->{ipver} eq '6' ) {
if ( $self->{src} ) {
# make sure it's ipv6
unless ( __is_valid_inet6($self->{src}) ) {
__errstr($self, 'IP Version is 6 but source is not valid IPv6');
return;
}
}
if ( $self->{dst} ) {
# make sure it's ipv6
unless ( __is_valid_inet6($self->{dst}) ) {
__errstr($self, 'IP Version is 6 but destination is not valid IPv6');
return;
}
}
} else {
# should never happen; the ipversion sub validates user input
__errstr($self, 'Code bug 0x01; Please report to developer.');
return;
}
# if icmp_type is set, protocol must be icmp or icmpv6
if ( defined($self->{icmp_type}) and $self->{proto} !~ m/\Aicmp(v6)?\z/i ) {
__errstr($self, 'icmp_type is set, but protocol is: '.$self->{proto});
return;
}
my $rule_prefix;
my $rule_criteria;
$rule_prefix = $self->{ip4binary} if $self->{ipver} eq '4';
$rule_prefix = $self->{ip6binary} if $self->{ipver} eq '6';
$rule_prefix .= ' -t '.$self->{table} if ( defined($self->{'table'}) );
$rule_prefix .= ' '.$self->{iptaction};
$rule_prefix .= ' '.$self->{chain};
# Source and Destination Addresses
if ( defined($self->{src}) ) {
if ( __is_valid_inet_host($self->{src}) or __is_valid_inet_cidr($self->{src}) ) {
$rule_criteria .= sprintf(' -s %s', $self->{src});
}
if ( __is_valid_inet_range($self->{src}) ) {
$rule_criteria .= sprintf(' -m iprange --src-range %s', $self->{'src'});
}
}
if ( defined($self->{dst}) ) {
if ( __is_valid_inet_host($self->{dst}) or __is_valid_inet_cidr($self->{dst}) ) {
$rule_criteria .= sprintf(' -d %s', $self->{dst});
}
if ( __is_valid_inet_range($self->{dst}) ) {
$rule_criteria .= sprintf(' -m iprange --dst-range %s', $self->{'dst'});
}
}
# this needs to be written out before we output the src/dst port (if they are present)
# otherwise iptables/ip6tables complains at the command.
$rule_criteria .= sprintf(' -p %s', $self->{proto}) if ( defined($self->{proto}) );
# Source and Destination Ports
if ( defined($self->{spt}) ) {
if ( $self->{spt} =~ m/\A\w+\z/ ) {
# just a single port
$rule_criteria .= sprintf(' --sport %s', $self->{'spt'});
}
if ( $self->{spt} =~ m/\A\w+(:\w+)+\z/ ) {
# port range
$rule_criteria .= sprintf(' --sport %s', $self->{'spt'});
}
if ( $self->{spt} =~ m/\A\w+(:\w+)+\z/ ) {
# multiport
$rule_criteria .= sprintf(' -m multiport --sports %s', $self->{'spt'});
}
lib/IPTables/Rule.pm view on Meta::CPAN
$rule_criteria .= sprintf(' -i %s', $self->{in}) if ( defined($self->{in}) );
$rule_criteria .= sprintf(' -o %s', $self->{out}) if ( defined($self->{out}) );
$rule_criteria .= sprintf(' -m mac --mac-source %s', $self->{mac}) if ( defined($self->{mac}) );
$rule_criteria .= sprintf(' -m conntrack --ctstate %s', $self->{state}) if ( defined($self->{state}) );
$rule_criteria .= sprintf(' --icmp-type %s', $self->{icmp_type}) if ( defined($self->{icmp_type}) );
$rule_criteria .= sprintf(' -m comment --comment "%s"', $self->{comment}) if ( defined($self->{comment}) );
$rule_criteria .= sprintf(' -m limit --limit %s', $self->{limit}) if ( defined($self->{limit}) );
$rule_criteria .= sprintf(' -j %s', $self->{'target'}) if ( defined($self->{'target'}) );
$rule_criteria .= sprintf(' --log-prefix "[%s] "', $self->{logprefix}) if ( defined($self->{logprefix}) );
# $ipt_rule .= sprintf(' -m statistic %s', $criteria{'statistic'}) if (defined($criteria{'statistic'}));
# $ipt_rule .= sprintf(' -m time %s', $criteria{'time'}) if (defined($criteria{'time'}));
my $full_cmd = $rule_prefix.$rule_criteria;
return $full_cmd;
}
###############################################################################
### INTERNAL HELPERS
# These are subs that are NOT expected to be used outside this module itself.
# They are for internal code reuse only.
# All sub named should be prefixed with double underslash (__) to indicate they
# are internal use only.
sub __is_valid_mac_address {
my ( $arg ) = @_;
chomp($arg);
return unless ( $arg );
if ( $arg =~ m/\A$qr_mac_addr\z/ ) {
return 1;
}
# fail by default
return;
}
sub __is_valid_inet4 {
my ( $arg ) = @_;
chomp($arg);
return unless ( $arg );
# ipv4 address?
return 1 if ( __is_inet4_host($arg) );
# ipv4 cidr?
return 1 if ( __is_inet4_cidr($arg) );
# ipv4 range?
return 1 if ( __is_inet4_range($arg) );
# fqdn?
return 1 if ( $arg =~ m/\A$qr_fqdn\z/ );
# fail by default
return;
}
sub __is_valid_inet6 {
my ( $arg ) = @_;
chomp($arg);
return unless ( $arg );
# ipv6 address?
return 1 if ( __is_inet6_host($arg) );
# ipv4 cidr?
return 1 if ( __is_inet6_cidr($arg) );
# ipv4 range?
return 1 if ( __is_inet6_range($arg) );
# fqdn?
return 1 if ( $arg =~ m/\A$qr_fqdn\z/ );
# fail by default
return;
}
sub __is_valid_inet_host {
my ( $arg ) = @_;
chomp($arg);
return unless ( $arg );
# ipv4 address?
return 1 if ( __is_inet4_host($arg) );
# ipv6 address?
return 1 if ( __is_inet6_host($arg) );
# fqdn?
return 1 if ( $arg =~ m/\A$qr_fqdn\z/ );
# fail by default
return;
}
sub __is_inet4_host {
my ( $arg ) = @_;
chomp($arg);
return unless ( $arg );
# ipv4 address?
return 1 if ( $arg =~ m/\A$qr_ip4_addr\z/ );
# fail by default
return;
}
sub __is_inet6_host {
my ( $arg ) = @_;
chomp($arg);
return unless ( $arg );
# ipv6 address?
return 1 if ( $arg =~ m/\A$qr_ip6_addr\z/ );
# fail by default
return;
}
sub __is_valid_inet_cidr {
my ( $arg ) = @_;
chomp($arg);
return unless ( $arg );
# ipv4 cidr?
return 1 if ( __is_inet4_cidr($arg) );
# ipv6 cidr?
return 1 if ( __is_inet6_cidr($arg) );
# fail by default
return;
}
sub __is_inet4_cidr {
my ( $arg ) = @_;
chomp($arg);
return unless ( $arg );
# ipv4 cidr?
if ( $arg =~ m/\A$qr_ip4_cidr\z/ ) {
# validate the cidr
my ($host, $cidr) = split(/\//, $arg);
return if ( $cidr < 0 );
return if ( $cidr > 32 );
return 1;
}
# fail by default
return;
}
sub __is_inet6_cidr {
my ( $arg ) = @_;
chomp($arg);
return unless ( $arg );
# ipv6 cidr?
if ( $arg =~ m/\A$qr_ip6_cidr\z/ ) {
# validate the cidr
my ($host, $cidr) = split(/\//, $arg);
return if ( $cidr < 0 );
return if ( $cidr > 128 );
return 1;
}
# fail by default
return;
}
sub __is_valid_inet_range {
my ( $arg ) = @_;
chomp($arg);
return unless ( $arg );
# ipv4 address range?
return 1 if ( __is_inet4_range($arg) );
# ipv6 address range?
return 1 if ( __is_inet6_range($arg) );
# fail by default
return;
}
sub __is_inet4_range {
my ( $arg ) = @_;
chomp($arg);
return unless ( $arg );
# ipv4 address range?
return 1 if (
$arg =~ m/\A$qr_ip4_addr\-$qr_ip4_addr\z/
);
# fail by default
return;
}
sub __is_inet6_range {
my ( $arg ) = @_;
chomp($arg);
return unless ( $arg );
# ipv6 address range?
return 1 if (
$arg =~ m/\A$qr_ip6_addr\-$qr_ip6_addr\z/
);
# fail by default
return;
}
sub __is_valid_inet_port {
my ( $arg ) = @_;
chomp($arg);
return unless ( $arg );
# just a numeric port?
if ( __is_a_number($arg) ) {
return if ( $arg < 0 );
return if ( $arg > 65535 );
return 1;
}
# just a named port?
if ( $arg =~ m/\A[a-z]+\z/i ) {
return 1;
}
# numeric port range?
if ( $arg =~ /\A\d+:\d+\z/ ) {
my ( $lower, $upper) = split(/:/, $arg, 2);
# recursive call to this sub to validate individal ports in multiport
return unless ( __is_valid_inet_port($lower) );
return unless ( __is_valid_inet_port($upper) );
# lower is higher than upper?
return if ( $upper < $lower );
return 1;
}
# named port range?
if ( $arg =~ /\A[a-z]+:[a-z]+\z/i ) {
my ( $lower, $upper) = split(/:/, $arg, 2);
# recursive call to this sub to validate individal ports in multiport
return unless ( __is_valid_inet_port($lower) );
return unless ( __is_valid_inet_port($upper) );
return 1;
}
# numeric multiport?
if ( $arg =~ /\A\d+(,\d+)+\z/ ) {
( run in 1.841 second using v1.01-cache-2.11-cpan-39bf76dae61 )