Skip to content

Commit

Permalink
Check earlier for consistent NAT tags.
Browse files Browse the repository at this point in the history
  • Loading branch information
hknutzen committed Mar 11, 2019
1 parent 3b14fc7 commit a2315d3
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 82 deletions.
9 changes: 5 additions & 4 deletions bin/export-netspoc
Expand Up @@ -818,7 +818,7 @@ sub setup_outer_owners {
# with previous version.
######################################################################
sub export_no_nat_set {
my ($nat_tag2multinat_def, $has_non_hidden) = @_;
my ($nat_tag2multinat_def, $nat_tag2nat_type) = @_;
progress("Export no-NAT-sets");
my %owner2domains;
my %all_nat_tags;
Expand Down Expand Up @@ -850,7 +850,7 @@ sub export_no_nat_set {
# Build union of all nat_sets of found NAT domains.
my $nat_sets = [ map { $_->{nat_set} } @nat_domains ];
my $combined = combine_nat_sets(
$nat_sets, $nat_tag2multinat_def, $has_non_hidden);
$nat_sets, $nat_tag2multinat_def, $nat_tag2nat_type);
delete @{$no_nat_set}{ keys %$combined };
}
create_dirs("owner/$owner_name");
Expand Down Expand Up @@ -1241,7 +1241,8 @@ link_topology();
mark_disabled();
set_zone();
setpath();
my ($natdomains, $nat_tag2multinat_def, $has_non_hidden) = distribute_nat_info();
my ($natdomains, $nat_tag2nat_type, $nat_tag2multinat_def) =
distribute_nat_info();
find_subnets_in_zone();

# Copy of %services with those services split, that have different 'user'.
Expand All @@ -1261,6 +1262,6 @@ export_assets();
my $owner2type2shash = export_services($normalized_services);
export_users_and_service_lists($owner2type2shash);
export_objects();
export_no_nat_set($nat_tag2multinat_def, $has_non_hidden);
export_no_nat_set($nat_tag2multinat_def, $nat_tag2nat_type);
copy_policy_file();
progress("Ready");
139 changes: 69 additions & 70 deletions lib/Netspoc/Compiler/Pass1.pm
Expand Up @@ -7860,20 +7860,39 @@ a common set of NAT tags (NAT set) is effective at every network.
=cut

#############################################################################
# Returns: Hash containing nat_tags declared to be non hidden at least
# once as keys.
sub generate_lookup_hash_for_non_hidden_nat_tags {
my %has_non_hidden;
# Comment: Check for equal type of NAT definitions.
# This is used for more efficient check of dynamic NAT rules,
# so we need to check only once for each pair of src / dst zone.
# Returns: A hash, mapping nat_tag to its type: static, dynamic or hidden.
sub get_lookup_hash_for_nat_type {
my %nat_tag2network;
my %nat_tag2nat_type;
for my $network (@networks) {
my $nat_hash = $network->{nat} or next;
for my $nat_tag (keys %$nat_hash) {
for my $nat_tag (sort keys %$nat_hash) {
my $nat_network = $nat_hash->{$nat_tag};
if (not $nat_network->{hidden}) {
$has_non_hidden{$nat_tag} = 1;
}
my $type =
$nat_network->{dynamic} ?
$nat_network->{hidden} ? 'hidden' : 'dynamic' : 'static';
if (my $other_net = $nat_tag2network{$nat_tag}) {
my $other_nat = $other_net->{nat}->{$nat_tag};
my $other_type =
$other_nat->{dynamic} ?
$other_nat->{hidden} ? 'hidden' : 'dynamic' : 'static';
if ($other_type ne $type) {
err_msg("All definitions of nat:$nat_tag must have",
" equal type.\n But found\n",
" - $other_type for $other_net->{name}\n",
" - $type for $network->{name}");
}
}
else {
$nat_tag2network{$nat_tag} = $network;
$nat_tag2nat_type{$nat_tag} = $type;
}
}
}
return \%has_non_hidden;
return \%nat_tag2nat_type;
}

# Mark invalid NAT transitions.
Expand Down Expand Up @@ -7914,10 +7933,6 @@ sub mark_invalid_nat_transitions {
# NAT definitions (several NAT definitions grouped at one
# network) as keys and arrays of NAT hashes containing the
# key NAT tag as values.
# $nat_definitions: Lookup hash with all NAT tags that are
# defined somewhere as keys. It is used to check, if all
# NAT definitions are bound and if all bound NAT tags are
# defined somewhere.
# Comments: Also checks consistency of multi NAT tags at one network. If
# non hidden NAT tags are grouped at one network, the same NAT
# tags must be used as group in all other occurrences to avoid
Expand All @@ -7928,21 +7943,19 @@ sub mark_invalid_nat_transitions {
# active at a time. As NAT:A can not be active (n2) and inactive
# (n1) in the same NAT domain, this restriction is needed.
sub generate_multinat_def_lookup {
my ($has_non_hidden) = @_;
my ($nat_tag2nat_type) = @_;
my %nat_tag2multinat_def;
my %nat_definitions;

for my $network (@networks) {
my $nat_hash = $network->{nat} or next;
# debug $network->{name}, " nat=", join(',', sort keys %$nat_hash);

NAT_TAG:
for my $nat_tag (sort keys %$nat_hash) {
$nat_definitions{$nat_tag} = 1;
if (my $previous_nat_hashes = $nat_tag2multinat_def{$nat_tag}) {

# Do not add same group twice.
if ($has_non_hidden->{$nat_tag}) {
if ($nat_tag2nat_type->{$nat_tag} ne 'hidden') {
for my $nat_hash2 (@$previous_nat_hashes) {
next NAT_TAG if keys_eq($nat_hash, $nat_hash2);
}
Expand Down Expand Up @@ -7981,7 +7994,7 @@ sub generate_multinat_def_lookup {
delete $nat_tag2multinat_def{$nat_tag};
}

return \%nat_tag2multinat_def, \%nat_definitions;
return \%nat_tag2multinat_def;
}

##############################################################################
Expand Down Expand Up @@ -8452,23 +8465,28 @@ sub check_multinat_errors {
#############################################################################
# Purpose: Check that every NAT tag is both bound and defined somewhere.
sub check_nat_definitions {
my ($nat_definitions, $natdomains) = @_;
my ($nat_tag2nat_type, $natdomains) = @_;
my %nat_definitions = %$nat_tag2nat_type;
for my $domain (@$natdomains) {
for my $router (@{ $domain->{routers} }) {
my $nat_tags = $router->{nat_tags}->{$domain};
for my $nat_tag (@$nat_tags) {
if ($nat_definitions->{$nat_tag}) {
$nat_definitions->{$nat_tag} = 'used';
if ($nat_definitions{$nat_tag}) {
$nat_definitions{$nat_tag} = 'used';
next;
}

# Prevent uninitialized value when checking NAT type later.
$nat_tag2nat_type->{$nat_tag} = 'static';

warn_msg(
"Ignoring useless nat:$nat_tag bound at $router->{name}");
}
}
}
for my $name (sort keys %$nat_definitions) {
$nat_definitions->{$name} eq 'used'
or warn_msg("nat:$name is defined, but not bound to any interface");
for my $name (sort keys %nat_definitions) {
$nat_definitions{$name} eq 'used' or
warn_msg("nat:$name is defined, but not bound to any interface");
}
}

Expand Down Expand Up @@ -8596,7 +8614,7 @@ sub distribute_nat_sets_to_interfaces {
# because hidden tag doesn't affect address calculation.
# Multiple hidden tags without real tag are ignored.
sub combine_nat_sets {
my ($nat_sets, $nat_tag2multinat_def, $has_non_hidden) = @_;
my ($nat_sets, $nat_tag2multinat_def, $nat_tag2nat_type) = @_;
return $nat_sets->[0] if @$nat_sets == 1;

# Collect single NAT tags and multi NAT hashes.
Expand Down Expand Up @@ -8643,8 +8661,8 @@ sub combine_nat_sets {
# Analyze active and inactive tags.
if (not $hash->{':none'}) {
my $real_tag;
for my $tag (%$hash) {
if ($has_non_hidden->{$tag}) {
for my $tag (keys %$hash) {
if ($nat_tag2nat_type->{$tag} ne 'hidden') {
if ($real_tag) {

# Ignore multiple real tags.
Expand Down Expand Up @@ -8685,20 +8703,20 @@ sub combine_nat_sets {
sub distribute_nat_info {
progress('Distributing NAT');
my $natdomains = find_nat_domains();
my $has_non_hidden = generate_lookup_hash_for_non_hidden_nat_tags();
my ($nat_tag2multinat_def, $nat_definitions)
= generate_multinat_def_lookup($has_non_hidden);
my $nat_tag2nat_type = get_lookup_hash_for_nat_type();
my ($nat_tag2multinat_def)
= generate_multinat_def_lookup($nat_tag2nat_type);
my $nat_errors =
distribute_nat_tags_to_nat_domains($nat_tag2multinat_def, $natdomains);
check_multinat_errors($nat_tag2multinat_def, $natdomains);
check_nat_definitions($nat_definitions, $natdomains);
check_nat_definitions($nat_tag2nat_type, $natdomains);
check_nat_network_location($natdomains) if not $nat_errors;
check_nat_compatibility();
check_interfaces_with_dynamic_nat();
distribute_nat_sets_to_interfaces($natdomains);
prepare_real_ip_nat_routers($nat_tag2multinat_def, $has_non_hidden);
prepare_real_ip_nat_routers($nat_tag2multinat_def, $nat_tag2nat_type);

return($natdomains, $nat_tag2multinat_def, $has_non_hidden);
return($natdomains, $nat_tag2nat_type, $nat_tag2multinat_def);
}

sub get_nat_network {
Expand Down Expand Up @@ -15005,15 +15023,12 @@ sub collect_path_interfaces {
# 2. Check host rule with dynamic NAT.
# 3. Check for partially applied hidden or dynamic NAT on path.
sub check_dynamic_nat_rules {
my ($natdomains) = @_;
my ($natdomains, $nat_tag2nat_type) = @_;
progress('Checking rules with hidden or dynamic NAT');

# Collect hidden or dynamic NAT tags that
# 1. are active inside nat_set,
# 2. are defined inside zone and remeber if NAT is hidden or not.
# 3. Check for equal type of NAT definitions.
# This is used for more efficient check of dynamic NAT rules,
# so we need to check only once for each pair of src / dst zone.
# 1. are active inside nat_set (i.e. NAT domain),
# 2. are defined inside zone.
my %nat_set2active_tags;
my %zone2dyn_nat;
{
Expand All @@ -15023,34 +15038,18 @@ sub check_dynamic_nat_rules {
my $href = $network->{nat} or next;
my $zone = $network->{zone};
for my $nat_tag (keys %$href) {
my $nat_network = $href->{$nat_tag};
if (my $other_net = $nat_type{$nat_tag}) {
my $other_nat = $other_net->{nat}->{$nat_tag};
my $other_type =
$other_nat->{dynamic} ?
$other_nat->{hidden} ? 'hidden' : 'dynamic' :
'static';
my $current_type =
$nat_network->{dynamic} ?
$nat_network->{hidden} ? 'hidden' : 'dynamic' :
'static';
if ($other_type ne $current_type) {
err_msg("All definitions of nat:$nat_tag must have",
" equal type.\n But found\n",
" - $other_type for $other_net->{name}\n",
" - $current_type for $network->{name}");
}
}
$nat_type{$nat_tag} = $network;

$nat_network->{dynamic} or next;
$is_dynamic_nat_tag{$nat_tag} = 1;
$zone2dyn_nat{$zone}->{$nat_tag} = $nat_network->{hidden} || 0;
# We already know, that type of $nat_tag is equal at
# all networks.
my $type = $nat_tag2nat_type->{$nat_tag};
next if $type eq 'static';
$zone2dyn_nat{$zone}->{$nat_tag} = 1;
}
}
for my $natdomain (@$natdomains) {
my $nat_set = $natdomain->{nat_set};
my @active = grep { $nat_set->{$_} } keys %is_dynamic_nat_tag;
my @active =
grep { $nat_tag2nat_type->{$_} ne 'static' } keys %$nat_set;
@{$nat_set2active_tags{$nat_set}}{@active} = @active;
}
}
Expand Down Expand Up @@ -17335,7 +17334,7 @@ sub print_iptables_acls {
}

sub prepare_real_ip_nat {
my ($router, $nat_tag2multinat_def, $has_non_hidden) = @_;
my ($router, $nat_tag2multinat_def, $nat_tag2nat_type) = @_;
my $hw_list = $router->{hardware};

my %effective2hw_list;
Expand All @@ -17349,7 +17348,7 @@ sub prepare_real_ip_nat {
# hidden addresses will be detected before this is used.
my $effective = {};
for my $nat_tag (@$bind_nat) {
$has_non_hidden->{$nat_tag} or next;
$nat_tag2nat_type->{$nat_tag} ne 'hidden' or next;
$effective->{$nat_tag} = 1;
}

Expand Down Expand Up @@ -17382,8 +17381,8 @@ sub prepare_real_ip_nat {
my $combine_nat = sub {
my ($list) = @_;
my $nat_sets = [ map { $_->{nat_set} } @$list ];
return
combine_nat_sets($nat_sets, $nat_tag2multinat_def, $has_non_hidden);
return combine_nat_sets($nat_sets,
$nat_tag2multinat_def, $nat_tag2nat_type);
};
my ($list1, $list2) = values %effective2hw_list;
my $combined1 = $combine_nat->($list1);
Expand All @@ -17393,10 +17392,10 @@ sub prepare_real_ip_nat {
}

sub prepare_real_ip_nat_routers {
my ($nat_tag2multinat_def, $has_non_hidden) = @_;
my ($nat_tag2multinat_def, $nat_tag2nat_type) = @_;
for my $router (@managed_routers, @routing_only_routers) {
$router->{acl_use_real_ip} or next;
prepare_real_ip_nat($router, $nat_tag2multinat_def, $has_non_hidden);
prepare_real_ip_nat($router, $nat_tag2multinat_def, $nat_tag2nat_type);
}
}

Expand Down Expand Up @@ -18787,7 +18786,7 @@ sub compile {
&mark_disabled();
&set_zone();
&setpath();
my ($natdomains) = distribute_nat_info();
my ($natdomains, $nat_tag2nat_type) = distribute_nat_info();
find_subnets_in_zone();

# Call after find_subnets_in_zone, where $zone->{networks} has
Expand Down Expand Up @@ -18816,7 +18815,7 @@ sub compile {
mark_managed_local();
},
sub {
check_dynamic_nat_rules($natdomains);
check_dynamic_nat_rules($natdomains, $nat_tag2nat_type);
});

concurrent(
Expand Down
8 changes: 4 additions & 4 deletions t/cut-netspoc.t
Expand Up @@ -351,7 +351,7 @@ $title = 'Area with NAT';
############################################################

$in = $topo . <<'END';
area:n2 = { border = interface:asa1.n2; nat:a2 = { ip = 10.9.9.9/32; dynamic; } }
area:n2 = { border = interface:asa1.n2; nat:a2 = { ip = 10.9.0.0/16; } }
service:test = {
user = network:n2;
permit src = user; dst = network:n1; prt = tcp;
Expand All @@ -368,7 +368,7 @@ router:asa1 = {
interface:n1 = { ip = 10.1.1.1; hardware = n1; bind_nat = a2; }
interface:n2 = { ip = 10.1.2.1; hardware = n2; }
}
area:n2 = { border = interface:asa1.n2; nat:a2 = { ip = 10.9.9.9/32; dynamic; } }
area:n2 = { border = interface:asa1.n2; nat:a2 = { ip = 10.9.0.0/16; } }
service:test = {
user = network:n2;
permit src = user; dst = network:n1; prt = tcp;
Expand Down Expand Up @@ -414,7 +414,7 @@ $title = 'Aggregate with NAT and owner';
$in = $topo . <<'END';
any:a2 = {
link = network:n2;
nat:a2 = { ip = 10.9.9.9/32; dynamic; }
nat:a2 = { ip = 10.9.0.0/16; }
owner = foo;
}
owner:foo = { admins = a@example.com; }
Expand All @@ -436,7 +436,7 @@ router:asa1 = {
}
any:a2 = {
link = network:n2;
nat:a2 = { ip = 10.9.9.9/32; dynamic; }
nat:a2 = { ip = 10.9.0.0/16; }
}
service:test = {
user = network:n2;
Expand Down
6 changes: 3 additions & 3 deletions t/group.t
Expand Up @@ -418,13 +418,13 @@ network:n1 = {
network:n2 = {
ip = 10.1.2.0/24;
nat:t1 = { ip = 10.9.2.0/24; }
nat:t2 = { ip = 10.9.2.0/24; }
host:h2 = { ip = 10.1.2.10; }
}
network:n3 = {
ip = 10.1.3.0/24;
nat:t1 = { hidden; }
nat:t3 = { hidden; }
host:h3 = { ip = 10.1.3.10; }
}
Expand All @@ -434,7 +434,7 @@ router:r1 = {
interface:n1 = { ip = 10.1.1.1; nat:t1 = { ip = 10.9.1.1; } hardware = n1; }
interface:n2 = { negotiated; hardware = n2; }
interface:n3 = { ip = 10.1.3.1; hardware = n3; }
interface:t1 = { unnumbered; hardware = t; bind_nat = t1; }
interface:t1 = { unnumbered; hardware = t; bind_nat = t1, t2, t3; }
}
network:t1 = { unnumbered; }
Expand Down

0 comments on commit a2315d3

Please sign in to comment.