Allow port ranges in /etc/shorewall/tcfilters

git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@8323 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
This commit is contained in:
teastep 2008-03-21 17:08:55 +00:00
parent 19ea03b36d
commit 9b048e836e
4 changed files with 78 additions and 33 deletions

View File

@ -255,13 +255,14 @@ New Features in 4.1.6.
DEST PORT(S)
A comma-separated list of destination ports. May only
be given if the PROTO is tcp, udp, icmp or
sctp. Port ranges may not be used. Specify "-"
if any PORT should match.
sctp. Port ranges may be used, except with the PROTO is
icmp. Specify "-" if any PORT should match.
SOURCE PORT(S)
A comma-separated list of source port. May only be
given if the PROTO is tcp, udp or sctp. Port ranges
may not be used. Specify "-" if any PORT should match.
may be used unless the protocol is icmp. Specify "-" if
any PORT should match.
Entries in /etc/shorewall/tcfilters generate U32 tc filters which
may be displayed using the "shorewall show filters" ("shorewall-lite

View File

@ -43,6 +43,7 @@ our @EXPORT = qw( ALLIPv4
validate_host
validate_range
ip_range_explicit
expand_port_range
allipv4
rfc1918_neworks
resolve_proto
@ -355,4 +356,36 @@ sub validate_icmp( $ ) {
fatal_error "Invalid ICMP Type ($type)"
}
sub expand_port_range( $$ ) {
my ( $proto, $range ) = @_;
my ( $first, $last ) = split /:/, $range, 2;
if ( defined $last ) {
my @result;
( $first , $last ) = ( validate_port( $proto, $first ) , validate_port( $proto, $last ) );
while ( $first <= $last ) {
my $mask = 0xffff;
my $y = 2;
my $z = 1;
while ( ( $first % $y ) == 0 && ( $first + $y ) < $last ) {
$mask <<= 1;
$z = $y;
$y <<= 1;
}
push @result, sprintf( '%04x', $first ) , sprintf( '%04x' , $mask & 0xffff );
$first += $z;
}
fatal_error "Invalid port range ($range)" unless @result;
@result;
} else {
( sprintf( '%04x' , validate_port( $proto, $first ) ) , 'ffff' );
}
}
1;

View File

@ -591,47 +591,61 @@ sub process_tc_filter( $$$$$$ ) {
fatal_error "Only TCP, UDP and SCTP may specify SOURCE PORT"
unless $protonumber == TCP || $protonumber == UDP || $protonumber == SCTP;
for my $sport ( split_list $sportlist , 'port list' ) {
my $portnumber = in_hex4 validate_port( $protonumber , $sport );
emit( "\nrun_tc $rule\\" ,
" match u32 ${portnumber}0000 0xffff0000 at nexthdr+0\\" ,
" flowid $devref->{number}:$class" );
for my $sportrange ( split_list $sportlist , 'port list' ) {
my @sportlist = expand_port_range $protonumber , $sportrange;
while ( @sportlist ) {
my ( $sport, $smask ) = ( shift @sportlist, shift @sportlist );
emit( "\nrun_tc $rule\\" ,
" match u32 0x${sport}0000 0x${smask}0000 at nexthdr+0\\" ,
" flowid $devref->{number}:$class" );
}
}
} else {
fatal_error "Only TCP, UDP, SCTP and ICMP may specify DEST PORT"
unless $protonumber == TCP || $protonumber == UDP || $protonumber == SCTP || $protonumber == ICMP;
for my $port( split_list $portlist, 'port list' ) {
for my $portrange ( split_list $portlist, 'port list' ) {
if ( $protonumber == ICMP ) {
fatal_error "Only TCP, UDP and SCTP may specify SOURCE PORT" if $sportlist ne '-';
my ( $icmptype , $icmpcode ) = split '//', validate_icmp( $port );
my ( $icmptype , $icmpcode ) = split '//', validate_icmp( $portrange );
$icmptype = in_hex2 numeric_value $icmptype;
$icmpcode = in_hex2 numeric_value $icmpcode if defined $icmpcode;
my $rule1 = " match u8 $icmptype 0xff at nexthdr+0";
$rule1 .= "\\\n match u8 $icmpcode 0xff at nexthdr+1" if defined $icmpcode;
emit( "\nrun_tc ${rule}\\" ,
"$rule1\\" ,
" flowid $devref->{number}:$class" );
} else {
my $portnumber = in_hex8 validate_port( $protonumber , $port );
my $rule1 = "match u32 $portnumber 0x0000ffff at nexthdr+0";
if ( $sportlist eq '-' ) {
emit( "\nrun_tc ${rule}\\" ,
" $rule1\\" ,
" flowid $devref->{number}:$class" );
} else {
for my $sport ( split_list $sportlist , 'port list' ) {
my $portnumber = in_hex4 validate_port( $protonumber , $sport );
emit( "\nrun_tc ${rule}\\",
my @portlist = expand_port_range $protonumber , $portrange;
while ( @portlist ) {
my ( $port, $mask ) = ( shift @portlist, shift @portlist );
my $rule1 = "match u32 0x0000${port} 0x0000${mask} at nexthdr+0";
if ( $sportlist eq '-' ) {
emit( "\nrun_tc ${rule}\\" ,
" $rule1\\" ,
" match u32 ${portnumber}0000 0xffff0000 at nexthdr+0\\" ,
" flowid $devref->{number}:$class" );
}
} else {
for my $sportrange ( split_list $sportlist , 'port list' ) {
my @sportlist = expand_port_range $protonumber , $sportrange;
while ( @sportlist ) {
my ( $sport, $smask ) = ( shift @sportlist, shift @sportlist );
emit( "\nrun_tc ${rule}\\",
" $rule1\\" ,
" match u32 0x${sport}0000 0x${smask}0000 at nexthdr+0\\" ,
" flowid $devref->{number}:$class" );
}
}
}
}
}
}
}
}
}
}

View File

@ -1179,10 +1179,6 @@ ip link set ifb0 up</command></programlisting>
<para>ipsets are not supported</para>
</listitem>
<listitem>
<para>port ranges are not supported</para>
</listitem>
<listitem>
<para>DNS Names are not supported</para>
</listitem>
@ -1278,8 +1274,8 @@ eth0 192.168.1.0/24 206.124.146.179</programlisting></para>
<listitem>
<para>Comma-separated list of destination port names or numbers.
May only be specified if the protocol is TCP, UDP, SCTP or
ICMP.</para>
May only be specified if the protocol is TCP, UDP, SCTP or ICMP.
Port ranges are supported except for ICMP.</para>
</listitem>
</varlistentry>
@ -1288,7 +1284,8 @@ eth0 192.168.1.0/24 206.124.146.179</programlisting></para>
<listitem>
<para>Comma-separated list of source port names or numbers. May
only be specified if the protocol is TCP, UDP or SCTP.</para>
only be specified if the protocol is TCP, UDP or SCTP. Port ranges
are supported.</para>
</listitem>
</varlistentry>
</variablelist>