mirror of
https://gitlab.com/shorewall/code.git
synced 2024-12-16 03:10:39 +01:00
Re-implement optional interface handling
Signed-off-by: Tom Eastep <teastep@shorewall.net>
This commit is contained in:
parent
d94f2cc86d
commit
57c54af6ed
@ -2437,7 +2437,7 @@ sub do_length( $ ) {
|
|||||||
#
|
#
|
||||||
sub match_source_dev( $ ) {
|
sub match_source_dev( $ ) {
|
||||||
my $interface = shift;
|
my $interface = shift;
|
||||||
my $interfaceref = known_interface( $interface );
|
my $interfaceref = known_interface( $interface, 0 );
|
||||||
$interface = $interfaceref->{physical} if $interfaceref;
|
$interface = $interfaceref->{physical} if $interfaceref;
|
||||||
return '' if $interface eq '+';
|
return '' if $interface eq '+';
|
||||||
if ( $interfaceref && $interfaceref->{options}{port} ) {
|
if ( $interfaceref && $interfaceref->{options}{port} ) {
|
||||||
@ -2452,7 +2452,7 @@ sub match_source_dev( $ ) {
|
|||||||
#
|
#
|
||||||
sub match_dest_dev( $ ) {
|
sub match_dest_dev( $ ) {
|
||||||
my $interface = shift;
|
my $interface = shift;
|
||||||
my $interfaceref = known_interface( $interface );
|
my $interfaceref = known_interface( $interface, 0 );
|
||||||
$interface = $interfaceref->{physical} if $interfaceref;
|
$interface = $interfaceref->{physical} if $interfaceref;
|
||||||
return '' if $interface eq '+';
|
return '' if $interface eq '+';
|
||||||
if ( $interfaceref && $interfaceref->{options}{port} ) {
|
if ( $interfaceref && $interfaceref->{options}{port} ) {
|
||||||
@ -3251,7 +3251,7 @@ sub expand_rule( $$$$$$$$$$;$ )
|
|||||||
# Verify Interface, if any
|
# Verify Interface, if any
|
||||||
#
|
#
|
||||||
if ( $iiface ) {
|
if ( $iiface ) {
|
||||||
fatal_error "Unknown Interface ($iiface)" unless known_interface $iiface;
|
fatal_error "Unknown Interface ($iiface)" unless known_interface( $iiface, 0 );
|
||||||
|
|
||||||
if ( $restriction & POSTROUTE_RESTRICT ) {
|
if ( $restriction & POSTROUTE_RESTRICT ) {
|
||||||
#
|
#
|
||||||
@ -3341,7 +3341,7 @@ sub expand_rule( $$$$$$$$$$;$ )
|
|||||||
# Verify Destination Interface, if any
|
# Verify Destination Interface, if any
|
||||||
#
|
#
|
||||||
if ( $diface ) {
|
if ( $diface ) {
|
||||||
fatal_error "Unknown Interface ($diface)" unless known_interface $diface;
|
fatal_error "Unknown Interface ($diface)" unless known_interface( $diface, 0 );
|
||||||
|
|
||||||
if ( $restriction & PREROUTE_RESTRICT ) {
|
if ( $restriction & PREROUTE_RESTRICT ) {
|
||||||
#
|
#
|
||||||
|
@ -142,7 +142,7 @@ sub process_one_masq( )
|
|||||||
$rule .= "-m realm --realm $realm ";
|
$rule .= "-m realm --realm $realm ";
|
||||||
}
|
}
|
||||||
|
|
||||||
fatal_error "Unknown interface ($interface)" unless my $interfaceref = known_interface( $interface );
|
fatal_error "Unknown interface ($interface)" unless my $interfaceref = known_interface( $interface, 0 );
|
||||||
|
|
||||||
unless ( $interfaceref->{root} ) {
|
unless ( $interfaceref->{root} ) {
|
||||||
$rule .= match_dest_dev( $interface );
|
$rule .= match_dest_dev( $interface );
|
||||||
@ -314,7 +314,7 @@ sub do_one_nat( $$$$$ )
|
|||||||
my $rulein = '';
|
my $rulein = '';
|
||||||
my $ruleout = '';
|
my $ruleout = '';
|
||||||
|
|
||||||
fatal_error "Unknown interface ($interface)" unless my $interfaceref = known_interface( $interface );
|
fatal_error "Unknown interface ($interface)" unless my $interfaceref = known_interface( $interface, 0 );
|
||||||
|
|
||||||
unless ( $interfaceref->{root} ) {
|
unless ( $interfaceref->{root} ) {
|
||||||
$rulein = match_source_dev $interface;
|
$rulein = match_source_dev $interface;
|
||||||
@ -408,7 +408,7 @@ sub setup_netmap() {
|
|||||||
my $ruleout = '';
|
my $ruleout = '';
|
||||||
my $iface = $interface;
|
my $iface = $interface;
|
||||||
|
|
||||||
fatal_error "Unknown interface ($interface)" unless my $interfaceref = known_interface( $interface );
|
fatal_error "Unknown interface ($interface)" unless my $interfaceref = known_interface( $interface, 0 );
|
||||||
|
|
||||||
unless ( $interfaceref->{root} ) {
|
unless ( $interfaceref->{root} ) {
|
||||||
$rulein = match_source_dev( $interface );
|
$rulein = match_source_dev( $interface );
|
||||||
|
@ -35,7 +35,7 @@ use strict;
|
|||||||
our @ISA = qw(Exporter);
|
our @ISA = qw(Exporter);
|
||||||
our @EXPORT = qw( setup_providers @routemarked_interfaces handle_stickiness handle_optional_interfaces );
|
our @EXPORT = qw( setup_providers @routemarked_interfaces handle_stickiness handle_optional_interfaces );
|
||||||
our @EXPORT_OK = qw( initialize lookup_provider );
|
our @EXPORT_OK = qw( initialize lookup_provider );
|
||||||
our $VERSION = '4.4_11';
|
our $VERSION = '4.4_13';
|
||||||
|
|
||||||
use constant { LOCAL_TABLE => 255,
|
use constant { LOCAL_TABLE => 255,
|
||||||
MAIN_TABLE => 254,
|
MAIN_TABLE => 254,
|
||||||
@ -275,7 +275,7 @@ sub add_a_provider( ) {
|
|||||||
require_capability 'REALM_MATCH', "Configuring multiple providers through one interface", "s";
|
require_capability 'REALM_MATCH', "Configuring multiple providers through one interface", "s";
|
||||||
}
|
}
|
||||||
|
|
||||||
fatal_error "Unknown Interface ($interface)" unless known_interface $interface;
|
fatal_error "Unknown Interface ($interface)" unless known_interface( $interface, 1 );
|
||||||
fatal_error "A bridge port ($interface) may not be configured as a provider interface" if port_to_bridge $interface;
|
fatal_error "A bridge port ($interface) may not be configured as a provider interface" if port_to_bridge $interface;
|
||||||
|
|
||||||
my $physical = get_physical $interface;
|
my $physical = get_physical $interface;
|
||||||
@ -846,53 +846,100 @@ sub lookup_provider( $ ) {
|
|||||||
sub handle_optional_interfaces( $ ) {
|
sub handle_optional_interfaces( $ ) {
|
||||||
|
|
||||||
my $returnvalue = verify_required_interfaces( shift );
|
my $returnvalue = verify_required_interfaces( shift );
|
||||||
#
|
my $require = $config{REQUIRE_INTERFACE};
|
||||||
# find_interfaces_by_option1() does not return wildcard interfaces. If an interface is defined
|
my $wildcards = 0;
|
||||||
# as a wildcard in /etc/shorewall/interfaces, then only specific interfaces matching that
|
my $interfaces = find_interfaces_by_option1 'optional', $wildcards;
|
||||||
# wildcard are returned.
|
|
||||||
#
|
|
||||||
my $interfaces = find_interfaces_by_option1 'optional';
|
|
||||||
|
|
||||||
if ( $config{REQUIRE_INTERFACE} ) {
|
emit( 'HAVE_INTERFACE=', '' ) if $require;
|
||||||
emit( 'HAVE_INTERFACE=' );
|
|
||||||
emit( '' );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( @$interfaces ) {
|
if ( @$interfaces ) {
|
||||||
for my $interface ( @$interfaces ) {
|
#
|
||||||
|
# Clear the '_IS_USABLE' variables
|
||||||
|
#
|
||||||
|
emit( join( '_', 'SW', uc chain_base( get_physical( $_ ) ) , 'IS_USABLE=' ) ) for @$interfaces;
|
||||||
|
|
||||||
|
if ( $wildcards ) {
|
||||||
|
emit( '',
|
||||||
|
'interfaces=$($IP -' . $family . ' addr list | egrep \'^[[:digit:]]+\' | while read number interface rest; do echo ${interface%:}; done)',
|
||||||
|
'',
|
||||||
|
'for interface in $interfaces; do'
|
||||||
|
);
|
||||||
|
|
||||||
|
push_indent;
|
||||||
|
|
||||||
|
emit ( 'case "$interface" in'
|
||||||
|
);
|
||||||
|
|
||||||
|
push_indent;
|
||||||
|
} else {
|
||||||
|
emit '';
|
||||||
|
}
|
||||||
|
|
||||||
|
for my $interface ( grep $provider_interfaces{$_}, @$interfaces ) {
|
||||||
my $provider = $provider_interfaces{$interface};
|
my $provider = $provider_interfaces{$interface};
|
||||||
my $physical = get_physical $interface;
|
my $physical = get_physical $interface;
|
||||||
my $base = uc chain_base( $physical );
|
my $base = uc chain_base( $physical );
|
||||||
|
|
||||||
emit( '' );
|
|
||||||
|
|
||||||
if ( $provider ) {
|
|
||||||
#
|
|
||||||
# This interface is associated with a non-shared provider -- get the provider table entry
|
|
||||||
#
|
|
||||||
my $providerref = $providers{$provider};
|
my $providerref = $providers{$provider};
|
||||||
|
|
||||||
|
emit( "$physical)" ) if $wildcards;
|
||||||
|
|
||||||
|
push_indent;
|
||||||
|
|
||||||
if ( $providerref->{gatewaycase} eq 'detect' ) {
|
if ( $providerref->{gatewaycase} eq 'detect' ) {
|
||||||
emit qq(if interface_is_usable $physical && [ -n "$providerref->{gateway}" ]; then);
|
emit qq(if interface_is_usable $physical && [ -n "$providerref->{gateway}" ]; then);
|
||||||
} else {
|
} else {
|
||||||
emit qq(if interface_is_usable $physical; then);
|
emit qq(if interface_is_usable $physical; then);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
#
|
|
||||||
# Not a provider interface
|
|
||||||
#
|
|
||||||
emit qq(if interface_is_usable $physical; then);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit( ' HAVE_INTERFACE=Yes' ) if $config{REQUIRE_INTERFACE};
|
emit( ' HAVE_INTERFACE=Yes' ) if $require;
|
||||||
|
|
||||||
emit( " SW_${base}_IS_USABLE=Yes" ,
|
emit( " SW_${base}_IS_USABLE=Yes" ,
|
||||||
'else' ,
|
|
||||||
" SW_${base}_IS_USABLE=" ,
|
|
||||||
'fi' );
|
'fi' );
|
||||||
|
|
||||||
|
emit( ';;' ), pop_indent if $wildcards;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $config{REQUIRE_INTERFACE} ) {
|
for my $interface ( grep ! $provider_interfaces{$_}, @$interfaces ) {
|
||||||
|
my $physical = get_physical $interface;
|
||||||
|
my $base = uc chain_base( $physical );
|
||||||
|
my $case = $physical;
|
||||||
|
my $wild = $case =~ s/\+$/*/;
|
||||||
|
|
||||||
|
if ( $wildcards ) {
|
||||||
|
emit( "$case)" );
|
||||||
|
push_indent;
|
||||||
|
|
||||||
|
|
||||||
|
if ( $wild ) {
|
||||||
|
emit( qq(if [ -z "\$SW_${base}_IS_USABLE" ]; then) );
|
||||||
|
push_indent;
|
||||||
|
emit ( 'if interface_is_usable $interface; then' );
|
||||||
|
} else {
|
||||||
|
emit ( "if interface_is_usable $physical; then" );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
emit ( "if interface_is_usable $physical; then" );
|
||||||
|
}
|
||||||
|
|
||||||
|
emit ( ' HAVE_INTERFACE=Yes' ) if $require;
|
||||||
|
|
||||||
|
emit ( " SW_${base}_IS_USABLE=Yes" ,
|
||||||
|
'fi' );
|
||||||
|
|
||||||
|
if ( $wildcards ) {
|
||||||
|
pop_indent, emit( 'fi' ) if $wild;
|
||||||
|
emit( ';;' );
|
||||||
|
pop_indent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $wildcards ) {
|
||||||
|
emit( 'esac' );
|
||||||
|
pop_indent;
|
||||||
|
emit('done' );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $require ) {
|
||||||
emit( '',
|
emit( '',
|
||||||
'if [ -z "$HAVE_INTERFACE" ]; then' ,
|
'if [ -z "$HAVE_INTERFACE" ]; then' ,
|
||||||
' case "$COMMAND" in',
|
' case "$COMMAND" in',
|
||||||
|
@ -177,7 +177,7 @@ sub setup_ecn()
|
|||||||
|
|
||||||
my ($interface, $hosts ) = split_line 1, 2, 'ecn file entry';
|
my ($interface, $hosts ) = split_line 1, 2, 'ecn file entry';
|
||||||
|
|
||||||
fatal_error "Unknown interface ($interface)" unless known_interface $interface;
|
fatal_error "Unknown interface ($interface)" unless known_interface( $interface, 0 );
|
||||||
|
|
||||||
$interfaces{$interface} = 1;
|
$interfaces{$interface} = 1;
|
||||||
|
|
||||||
@ -328,7 +328,7 @@ sub process_routestopped() {
|
|||||||
|
|
||||||
my $interfaceref;
|
my $interfaceref;
|
||||||
|
|
||||||
fatal_error "Unknown interface ($interface)" unless $interfaceref = known_interface $interface;
|
fatal_error "Unknown interface ($interface)" unless $interfaceref = known_interface( $interface, 0 );
|
||||||
$hosts = ALLIP unless $hosts && $hosts ne '-';
|
$hosts = ALLIP unless $hosts && $hosts ne '-';
|
||||||
|
|
||||||
my $routeback = 0;
|
my $routeback = 0;
|
||||||
@ -769,7 +769,7 @@ sub setup_mac_lists( $ ) {
|
|||||||
my $targetref = $maclist_targets{$disposition};
|
my $targetref = $maclist_targets{$disposition};
|
||||||
|
|
||||||
fatal_error "Invalid DISPOSITION ($original_disposition)" if ! $targetref || ( ( $table eq 'mangle' ) && ! $targetref->{mangle} );
|
fatal_error "Invalid DISPOSITION ($original_disposition)" if ! $targetref || ( ( $table eq 'mangle' ) && ! $targetref->{mangle} );
|
||||||
fatal_error "Unknown Interface ($interface)" unless known_interface( $interface );
|
fatal_error "Unknown Interface ($interface)" unless known_interface( $interface, 0 );
|
||||||
fatal_error "No hosts on $interface have the maclist option specified" unless $maclist_interfaces{$interface};
|
fatal_error "No hosts on $interface have the maclist option specified" unless $maclist_interfaces{$interface};
|
||||||
|
|
||||||
my $chainref = $chain_table{$table}{( $ttl ? macrecent_target $interface : mac_chain $interface )};
|
my $chainref = $chain_table{$table}{( $ttl ? macrecent_target $interface : mac_chain $interface )};
|
||||||
|
@ -83,7 +83,7 @@ our @EXPORT = qw( NOTHING
|
|||||||
);
|
);
|
||||||
|
|
||||||
our @EXPORT_OK = qw( initialize );
|
our @EXPORT_OK = qw( initialize );
|
||||||
our $VERSION = '4.4_12';
|
our $VERSION = '4.4_13';
|
||||||
|
|
||||||
#
|
#
|
||||||
# IPSEC Option types
|
# IPSEC Option types
|
||||||
@ -1152,11 +1152,12 @@ sub map_physical( $$ ) {
|
|||||||
#
|
#
|
||||||
# Returns true if passed interface matches an entry in /etc/shorewall/interfaces
|
# Returns true if passed interface matches an entry in /etc/shorewall/interfaces
|
||||||
#
|
#
|
||||||
# If the passed name matches a wildcard, an entry for the name is added in %interfaces to speed up validation of other references to that name.
|
# If the passed name matches a wildcard and 'cache' is true, an entry for the name is added in
|
||||||
|
# %interfaces.
|
||||||
#
|
#
|
||||||
sub known_interface($)
|
sub known_interface($$)
|
||||||
{
|
{
|
||||||
my $interface = $_[0];
|
my ( $interface, $cache ) = @_;
|
||||||
my $interfaceref = $interfaces{$interface};
|
my $interfaceref = $interfaces{$interface};
|
||||||
|
|
||||||
return $interfaceref if $interfaceref;
|
return $interfaceref if $interfaceref;
|
||||||
@ -1165,18 +1166,19 @@ sub known_interface($)
|
|||||||
$interfaceref = $interfaces{$i};
|
$interfaceref = $interfaces{$i};
|
||||||
my $root = $interfaceref->{root};
|
my $root = $interfaceref->{root};
|
||||||
if ( $i ne $root && substr( $interface, 0, length $root ) eq $root ) {
|
if ( $i ne $root && substr( $interface, 0, length $root ) eq $root ) {
|
||||||
#
|
|
||||||
# Cache this result for future reference. We set the 'name' to the name of the entry that appears in /etc/shorewall/interfaces and we do not set the root;
|
|
||||||
#
|
|
||||||
my $physical = map_physical( $interface, $interfaceref );
|
my $physical = map_physical( $interface, $interfaceref );
|
||||||
|
|
||||||
return $interfaces{$interface} = { options => $interfaceref->{options},
|
my $copyref = { options => $interfaceref->{options},
|
||||||
bridge => $interfaceref->{bridge} ,
|
bridge => $interfaceref->{bridge} ,
|
||||||
name => $i ,
|
name => $i ,
|
||||||
number => $interfaceref->{number} ,
|
number => $interfaceref->{number} ,
|
||||||
physical => $physical,
|
physical => $physical ,
|
||||||
base => chain_base( $physical ),
|
base => chain_base( $physical ) ,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$interfaces{$interface} = $copyref if $cache;
|
||||||
|
|
||||||
|
return $copyref;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1228,7 +1230,7 @@ sub get_physical( $ ) {
|
|||||||
#
|
#
|
||||||
sub physical_name( $ ) {
|
sub physical_name( $ ) {
|
||||||
my $device = shift;
|
my $device = shift;
|
||||||
my $devref = known_interface $device;
|
my $devref = known_interface( $device, 0 );
|
||||||
|
|
||||||
$devref ? $devref->{physical} : $device;
|
$devref ? $devref->{physical} : $device;
|
||||||
}
|
}
|
||||||
@ -1287,24 +1289,31 @@ sub find_interfaces_by_option( $ ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
# Returns reference to array of interfaces with the passed option
|
# Returns reference to array of interfaces with the passed option. Unlike the preceding function, this one:
|
||||||
#
|
#
|
||||||
sub find_interfaces_by_option1( $ ) {
|
# - All entries in %interfaces are searched.
|
||||||
my $option = $_[0];
|
# - The second argument is used to return an indication of the presents of wildcard interfaces
|
||||||
|
#
|
||||||
|
sub find_interfaces_by_option1( $\$ ) {
|
||||||
|
my ( $option, $wildref) = @_;
|
||||||
my @ints = ();
|
my @ints = ();
|
||||||
|
my $wild = 0;
|
||||||
|
|
||||||
for my $interface ( keys %interfaces ) {
|
for my $interface ( sort { $interfaces{$a}->{number} <=> $interfaces{$b}->{number} }
|
||||||
|
keys %interfaces ) {
|
||||||
my $interfaceref = $interfaces{$interface};
|
my $interfaceref = $interfaces{$interface};
|
||||||
|
|
||||||
next unless defined $interfaceref->{physical};
|
next unless defined $interfaceref->{physical};
|
||||||
next if $interfaceref->{physical} =~ /\+/;
|
|
||||||
|
|
||||||
my $optionsref = $interfaceref->{options};
|
my $optionsref = $interfaceref->{options};
|
||||||
|
|
||||||
if ( $optionsref && defined $optionsref->{$option} ) {
|
if ( $optionsref && defined $optionsref->{$option} ) {
|
||||||
|
$wild ||= ( $interfaceref->{physical} =~ /\+$/ );
|
||||||
push @ints , $interface
|
push @ints , $interface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$$wildref = $wild;
|
||||||
\@ints;
|
\@ints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@ Changes in Shorewall 4.4.13
|
|||||||
|
|
||||||
4) Fix exclusion with CONTINUE/NONAT/ACCEPT+
|
4) Fix exclusion with CONTINUE/NONAT/ACCEPT+
|
||||||
|
|
||||||
|
5) Re-implement optional interface handling.
|
||||||
|
|
||||||
Changes in Shorewall 4.4.12
|
Changes in Shorewall 4.4.12
|
||||||
|
|
||||||
1) Fix IPv6 shorecap program.
|
1) Fix IPv6 shorecap program.
|
||||||
|
@ -42,6 +42,58 @@ VI. PROBLEMS CORRECTED AND NEW FEATURES IN PRIOR RELEASES
|
|||||||
who utilize a capabilities file should re-generate the file using
|
who utilize a capabilities file should re-generate the file using
|
||||||
this release.
|
this release.
|
||||||
|
|
||||||
|
7) Interface handling has been extensively modified in this release
|
||||||
|
to correct a number of problems with the earlier
|
||||||
|
implementation. Among those problems:
|
||||||
|
|
||||||
|
- Invalid shell variable names could be generated in the firewall
|
||||||
|
script. The generated firewall script uses shell variables to
|
||||||
|
track the availability of optional and required interfaces and
|
||||||
|
to record detected gateways, detected addresses, etc.
|
||||||
|
|
||||||
|
- The same shell variable name could be generated by two different
|
||||||
|
interface names.
|
||||||
|
|
||||||
|
- Entries in the interfaces file with a wildcard physical name
|
||||||
|
(physical name ends with "+") and with the 'optional' option were
|
||||||
|
handled strangely.
|
||||||
|
|
||||||
|
o If there were references to specific interfaces that matched
|
||||||
|
the wildcard, those entries were handled as if they had been
|
||||||
|
defined as optional in the interfaces file.
|
||||||
|
|
||||||
|
o If there were no references matching the wildcard, then the
|
||||||
|
'optional' option was effectively ignored.
|
||||||
|
|
||||||
|
The new implementation:
|
||||||
|
|
||||||
|
- Insures valid shell variable names.
|
||||||
|
|
||||||
|
- Insures that shell variable names are unique.
|
||||||
|
|
||||||
|
- Handles interface names appearing in the INTERFACE column of the
|
||||||
|
providers file as a special case for 'optional'. If the name
|
||||||
|
matches a wildcard entry in the interfaces file then the
|
||||||
|
usability of the specific interface is tracked individually.
|
||||||
|
|
||||||
|
- Handles the availabilty of other interfaces matching a wildcard
|
||||||
|
as a group; if there is one useable interface in the group then
|
||||||
|
the wildcard itself is considered usable.
|
||||||
|
|
||||||
|
The following example illustrates this use case:
|
||||||
|
|
||||||
|
/etc/shorewall/interfaces
|
||||||
|
|
||||||
|
net ppp+ - optional
|
||||||
|
|
||||||
|
/etc/shorewall/shorewall.conf
|
||||||
|
|
||||||
|
REQUIRE_INTERFACE=Yes
|
||||||
|
|
||||||
|
If there is any usable PPP interface then the firewall will be
|
||||||
|
allowed to start. Previously, the firewall would never be allowed
|
||||||
|
to start.
|
||||||
|
|
||||||
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
||||||
I I. K N O W N P R O B L E M S R E M A I N I N G
|
I I. K N O W N P R O B L E M S R E M A I N I N G
|
||||||
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
||||||
|
Loading…
Reference in New Issue
Block a user