Przeglądaj źródła

added support ipset filters for iptables script

Roman Dmitriev 1 miesiąc temu
rodzic
commit
ed76039f5a
1 zmienionych plików z 97 dodań i 33 usunięć
  1. 97 33
      docs/iptables/sync_iptables.pl

+ 97 - 33
docs/iptables/sync_iptables.pl

@@ -137,7 +137,6 @@ my $ipset_removed = 0;
 # ============================================================================
 if ($gate->{user_acl}) {
 
-
     log_verbose($gate_ident."Sync user state at router $router_name [".$router_ip."] started.");
     db_log_verbose($dbh,$gate_ident."Sync user state at router $router_name [".$router_ip."] started.");
 
@@ -171,6 +170,7 @@ if ($gate->{user_acl}) {
     log_debug($gate_ident."Users status by ACL:".Dumper(\%users));
 
     my @filter_instances = get_records_sql($dbh,"SELECT * FROM filter_instances");
+    my @filter_ipsets = get_records_sql($dbh,"SELECT * FROM ipset_list");
     my @filterlist_ref = get_records_sql($dbh,"SELECT * FROM filter_list where filter_type=0");
 
     my %filters;
@@ -182,30 +182,42 @@ if ($gate->{user_acl}) {
     my $dyn_filters_index = $dyn_filters_base;
 
     foreach my $row (@filterlist_ref) {
-        if (is_ip($row->{dst})) {
-            $filters{$row->{id}}->{id}=$row->{id};
-            $filters{$row->{id}}->{proto}=$row->{proto};
-            $filters{$row->{id}}->{dst}=$row->{dst};
-            $filters{$row->{id}}->{dstport}=$row->{dstport};
-            $filters{$row->{id}}->{srcport}=$row->{srcport};
-            $filters{$row->{id}}->{dns_dst}=0;
-        } else {
-            my @dns_record=ResolveNames($row->{dst},undef);
-            my $resolved_ips = (scalar @dns_record>0);
-            next if (!$resolved_ips);
-            foreach my $resolved_ip (sort @dns_record) {
-                next if (!$resolved_ip);
-                $filters{$row->{id}}->{dns_dst}=1;
-                $filters{$dyn_filters_index}->{id}=$row->{id};
-                $filters{$dyn_filters_index}->{proto}=$row->{proto};
-                $filters{$dyn_filters_index}->{dst}=$resolved_ip;
-                $filters{$dyn_filters_index}->{dstport}=$row->{dstport};
-                $filters{$dyn_filters_index}->{srcport}=$row->{srcport};
-                $filters{$dyn_filters_index}->{dns_dst}=0;
-                push(@{$dyn_filters{$row->{id}}},$dyn_filters_index);
-                $dyn_filters_index++;
+        if ($row->{ipset_id}>0) {
+                $filters{$row->{id}}->{id}=$row->{id};
+                $filters{$row->{id}}->{proto}=$row->{proto};
+                $filters{$row->{id}}->{dst}=undef;
+                $filters{$row->{id}}->{ipset_id}=$row->{ipset_id};
+                $filters{$row->{id}}->{dstport}=$row->{dstport};
+                $filters{$row->{id}}->{srcport}=$row->{srcport};
+                $filters{$row->{id}}->{dns_dst}=0;
+            } else {
+            if (is_ip($row->{dst})) {
+                $filters{$row->{id}}->{id}=$row->{id};
+                $filters{$row->{id}}->{ipset_id}=undef;
+                $filters{$row->{id}}->{proto}=$row->{proto};
+                $filters{$row->{id}}->{dst}=$row->{dst};
+                $filters{$row->{id}}->{dstport}=$row->{dstport};
+                $filters{$row->{id}}->{srcport}=$row->{srcport};
+                $filters{$row->{id}}->{dns_dst}=0;
+            } else {
+                my @dns_record=ResolveNames($row->{dst},undef);
+                my $resolved_ips = (scalar @dns_record>0);
+                next if (!$resolved_ips);
+                foreach my $resolved_ip (sort @dns_record) {
+                    next if (!$resolved_ip);
+                    $filters{$row->{id}}->{dns_dst}=1;
+                    $filters{$dyn_filters_index}->{id}=$row->{id};
+                    $filters{$dyn_filters_index}->{proto}=$row->{proto};
+                    $filters{$dyn_filters_index}->{dst}=$resolved_ip;
+                    $filters{$dyn_filters_index}->{ipset_id}=undef;
+                    $filters{$dyn_filters_index}->{dstport}=$row->{dstport};
+                    $filters{$dyn_filters_index}->{srcport}=$row->{srcport};
+                    $filters{$dyn_filters_index}->{dns_dst}=0;
+                    push(@{$dyn_filters{$row->{id}}},$dyn_filters_index);
+                    $dyn_filters_index++;
+                    }
+                }
             }
-        }
     }
 
     log_debug($gate_ident."Filters status:". Dumper(\%filters));
@@ -259,7 +271,6 @@ if ($gate->{user_acl}) {
     my %cur_users;
     my %final_ipsets;  # Хранилище для финальных IPset данных
 
-
     # Создаем таблицу ipset если не существует
     log_verbose($gate_ident."Ensure ipset exists: ${IPTABLES_TABLE_NAME}_group_all");
     push(@cmd_ipset_list, "$IPSET_CMD create ${IPTABLES_TABLE_NAME}_group_all hash:net family inet hashsize 1024 maxelem 2655360");
@@ -305,6 +316,55 @@ if ($gate->{user_acl}) {
         }
     }
 
+    my %cur_ipset_members;
+    my %ipset_members;
+    my %ipset_list;
+
+    foreach my $ipset_row (@filter_ipsets) {
+        next if (!$ipset_row);
+        $ipset_list->{$ipset_row->{id}} = $ipset_row->{name};
+        my @filter_ipset_members = get_records_sql($dbh,"SELECT * FROM ipset_members WHERE ipset_id=?", $ipset_row->{id});
+        foreach my $ip_row (@filter_ipset_members) { $ipset_members{$ipset_row->{name}}{$ip_row->{ip}} = 1; }
+        log_verbose($gate_ident."Config ipset $ipset_row=>{name} has ".scalar(@address_list)." entries");
+    }
+
+    # filter ipsets
+    foreach my $ipset_row (@filter_ipsets) {
+        next if (!$ipset_row);
+        my $set_name = $IPTABLES_TABLE_NAME . '_' . $ipset_row->{name};
+        log_verbose($gate_ident."Ensure ipset exists: $set_name");
+        push(@cmd_ipset_list, "$IPSET_CMD create $set_name hash:net family inet hashsize 1024 maxelem 2655360");
+        my @address_list = get_ipset_members($set_name);
+        foreach my $ip (@address_list) { $cur_ipset_members{$ipset_row->{name}}{$ip} = 1; }
+        log_verbose($gate_ident."Current ipset $ipset_row=>{name} has ".scalar(@address_list)." entries");
+    }
+
+    # Добавляем новые IP в фильтры
+    foreach my $ipset_name (keys %ipset_members) {
+        my $set_name = $IPTABLES_TABLE_NAME . '_' . $ipset_name;
+        foreach my $ipset_member_ip (keys %{$ipset_members{$ipset_name}}) {
+            if (!exists($cur_ipset_members{$ipset_name}{$ipset_member_ip})) {
+                log_info($gate_ident."ADD ipset entry: $ipset_member_ip -> $ipset_name");
+                db_log_verbose($dbh, $gate_ident."Add user with ip: $ipset_member_ip to ipset $ipset_name");
+                push(@cmd_ipset_list, "$IPSET_CMD add $set_name $ipset_member_ip");
+                $ipset_added++;
+            }
+        }
+    }
+
+    # Удаляем старые IP из фильтров
+    foreach my $ipset_name (keys %cur_ipset_members) {
+        my $set_name = $IPTABLES_TABLE_NAME . '_' . $ipset_name;
+        foreach my $ipset_member_ip (keys %{$cur_ipset_members{$ipset_name}}) {
+            if (!exists($ipset_members{$ipset_name}{$ipset_member_ip})) {
+                log_info($gate_ident."REMOVE ipset entry: $ipset_member_ip <- $ipset_name");
+                db_log_verbose($dbh, $gate_ident."Remove user with ip: $ipset_member_ip from ipset $ipset_name");
+                push(@cmd_ipset_list, "$IPSET_CMD del $set_name $ipset_member_ip");
+                $ipset_removed++;
+            }
+        }
+    }
+
     log_verbose($gate_ident."IPset changes: $ipset_added added, $ipset_removed removed");
 
     # ============================================================================
@@ -401,14 +461,18 @@ if ($gate->{user_acl}) {
             my $src_rule = '-A '.$chain_name;
             my $dst_rule = '-A '.$chain_name;
 
-
-            if ($filters{$filter_id}->{dst} and $filters{$filter_id}->{dst} ne '0/0' and $filters{$filter_id}->{dst} !~ /\/\d{1,2}/) { $filters{$filter_id}->{dst} .='/32'; }
-            my $dst = $filters{$filter_id}->{dst};
-
-            if (defined $dst && $dst ne '' && $dst ne '0/0') {
-                $src_rule .= " -s $dst";
-                $dst_rule .= " -d $dst";
-            }
+            if (defined $filter->{ipset_id} && $filter->{ipset_id}>0 && $ipset_list{$filter->{ipset_id}}) {
+                my $set_name = $IPTABLES_TABLE_NAME . '_' . $ipset_list{$filter->{ipset_id}};
+                $src_rule .= " -m set --match-set $set_name src";
+                $dst_rule .= " -m set --match-set $set_name dst";
+                } else {
+                if ($filters{$filter_id}->{dst} and $filters{$filter_id}->{dst} ne '0/0' and $filters{$filter_id}->{dst} !~ /\/\d{1,2}/) { $filters{$filter_id}->{dst} .='/32'; }
+                my $dst = $filters{$filter_id}->{dst};
+                if (defined $dst && $dst ne '' && $dst ne '0/0') {
+                    $src_rule .= " -s $dst";
+                    $dst_rule .= " -d $dst";
+                    }
+                }
 
             if ($filters{$filter_id}->{proto} and ($filters{$filter_id}->{proto}!~/all/i)) {
                 $src_rule=$src_rule." -p ".$filters{$filter_id}->{proto};