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 )