File Coverage

blib/lib/Metabrik/Network/Linux/Iptables.pm
Criterion Covered Total %
statement 9 425 2.1
branch 0 284 0.0
condition 0 129 0.0
subroutine 3 59 5.0
pod 2 54 3.7
total 14 951 1.4


line stmt bran cond sub pod time code
1             #
2             # $Id$
3             #
4             # network::linux::iptables Brik
5             #
6             package Metabrik::Network::Linux::Iptables;
7 1     1   792 use strict;
  1         2  
  1         34  
8 1     1   8 use warnings;
  1         2  
  1         27  
9              
10 1     1   5 use base qw(Metabrik::Shell::Command Metabrik::System::Package);
  1         2  
  1         4950  
11              
12             sub brik_properties {
13             return {
14 0     0 1   revision => '$Revision$',
15             tags => [ qw(unstable fw firewall filter block filtering nat) ],
16             author => 'GomoR ',
17             license => 'http://opensource.org/licenses/BSD-3-Clause',
18             attributes => {
19             datadir => [ qw(datadir) ],
20             device => [ qw(device) ],
21             table => [ qw(nat|filter|mangle|$name) ],
22             chain => [ qw(INPUT|OUTPUT|FORWARD|PREROUTING|POSTROUTING|MASQUERADE|DNAT|$name) ],
23             target => [ qw(ACCEPT|REJECT|DROP|RETURN|REDIRECT|$name) ],
24             protocol => [ qw(udp|tcp|all) ],
25             source => [ qw(source) ],
26             destination => [ qw(destination) ],
27             test_only => [ qw(0|1) ],
28             input => [ qw(file) ],
29             output => [ qw(file) ],
30             },
31             attributes_default => {
32             table => 'filter',
33             chain => 'INPUT',
34             target => 'REJECT',
35             protocol => '',
36             source => '',
37             destination => '',
38             test_only => 0,
39             input => 'current.txt',
40             output => 'current.txt',
41             },
42             commands => {
43             install => [ ], # Inherited
44             command => [ qw(command) ],
45             show_nat => [ ],
46             show_filter => [ ],
47             save => [ qw(file table|OPTIONAL) ],
48             save_nat => [ qw(file) ],
49             save_filter => [ qw(file) ],
50             restore => [ qw(file table|OPTIONAL) ],
51             restore_nat => [ qw(file) ],
52             restore_filter => [ qw(file) ],
53             flush => [ qw(table|$table_list chain) ],
54             flush_nat => [ qw(chain|OPTIONAL) ],
55             flush_nat_prerouting => [ ],
56             flush_nat_input => [ ],
57             flush_nat_output => [ ],
58             flush_nat_postrouting => [ ],
59             flush_filter => [ qw(chain|OPTIONAL) ],
60             flush_filter_input => [ ],
61             flush_filter_forward => [ ],
62             flush_filter_output => [ ],
63             set_policy => [ qw(table target) ],
64             set_policy_input => [ qw(target) ],
65             set_policy_output => [ qw(target) ],
66             set_policy_forward => [ qw(target) ],
67             add => [ qw(table chain target rule) ],
68             add_nat => [ qw(chain target rule) ],
69             add_nat_output => [ qw(target rule) ],
70             add_nat_output_return => [ qw(rule) ],
71             add_nat_output_redirect => [ qw(rule) ],
72             add_nat_output_dnat => [ qw(rule) ],
73             add_nat_postrouting => [ qw(target rule) ],
74             add_nat_postrouting_masquerade => [ qw(rule) ],
75             add_nat_postrouting_dnat => [ qw(rule) ],
76             add_filter => [ qw(chain target rule) ],
77             add_filter_output => [ qw(target rule) ],
78             add_filter_output_accept => [ qw(rule) ],
79             add_filter_output_reject => [ qw(rule) ],
80             del => [ qw(table chain target rule) ],
81             del_nat => [ qw(chain target rule) ],
82             del_nat_output => [ qw(target rule) ],
83             del_nat_output_return => [ qw(rule) ],
84             del_nat_output_redirect => [ qw(rule) ],
85             del_nat_output_dnat => [ qw(rule) ],
86             check => [ qw(table chain target rule) ],
87             check_nat => [ qw(chain target rule) ],
88             check_nat_output => [ qw(target rule) ],
89             check_nat_output_return => [ qw(rule) ],
90             check_nat_output_redirect => [ qw(rule) ],
91             check_nat_output_dnat => [ qw(rule) ],
92             start_redirect_target_to => [ qw(host_port dest_host_port protocol|OPTIONAL) ],
93             start_redirect_target_tcp_to => [ qw(host_port dest_host_port) ],
94             start_redirect_target_udp_to => [ qw(host_port dest_host_port) ],
95             stop_redirect_target_to => [ qw(host_port dest_host_port protocol|OPTIONAL) ],
96             stop_redirect_target_tcp_to => [ qw(host_port dest_host_port) ],
97             stop_redirect_target_udp_to => [ qw(host_port dest_host_port) ],
98             },
99             require_modules => {
100             'Metabrik::File::Text' => [ ],
101             },
102             require_binaries => {
103             iptables => [ ],
104             },
105             need_packages => {
106             ubuntu => [ qw(iptables) ],
107             debian => [ qw(iptables) ],
108             kali => [ qw(iptables) ],
109             },
110             };
111             }
112              
113             sub brik_use_properties {
114 0     0 1   my $self = shift;
115              
116             return {
117 0   0       attributes_default => {
118             device => defined($self->global) && $self->global->device || 'eth0',
119             },
120             };
121             }
122              
123             sub command {
124 0     0 0   my $self = shift;
125 0           my ($command) = @_;
126              
127 0 0         $self->brik_help_run_undef_arg('command', $command) or return;
128              
129 0           my $cmd = "iptables $command";
130              
131 0           $self->log->verbose("command: cmd[$cmd]");
132              
133 0 0         if ($self->test_only) {
134 0           return 1;
135             }
136              
137 0           $self->ignore_error(0);
138              
139 0 0         my $r = $self->sudo_execute($cmd) or return;
140 0 0         if ($r == 256) {
141 0           return 0;
142             }
143              
144 0           return 1;
145             }
146              
147             sub show_nat {
148 0     0 0   my $self = shift;
149              
150 0           my $cmd = '-S -t nat';
151              
152 0           return $self->command($cmd);
153             }
154              
155             sub show_filter {
156 0     0 0   my $self = shift;
157              
158 0           my $cmd = '-S -t filter';
159              
160 0           return $self->command($cmd);
161             }
162              
163             sub save {
164 0     0 0   my $self = shift;
165 0           my ($output, $table) = @_;
166              
167 0   0       $output ||= $self->output;
168 0 0         $self->brik_help_run_undef_arg('save', $output) or return;
169              
170 0           my $datadir = $self->datadir;
171             # If it does not start with a /, we put it in datadir
172 0 0         if ($output !~ m{^/}) {
173 0           $output = $datadir.'/'.$output;
174             }
175              
176 0           my $cmd = 'iptables-save -c';
177 0 0         if (defined($table)) {
178 0           $cmd = "iptables-save -c -t $table";
179             }
180              
181 0           $self->log->verbose("save: cmd[$cmd]");
182              
183 0 0         if ($self->test_only) {
184 0           return 1;
185             }
186              
187 0           my $preve = $self->ignore_error;
188 0           my $prevc = $self->capture_stderr;
189 0           $self->ignore_error(0);
190 0           $self->capture_stderr(0);
191 0           my $r = $self->sudo_capture($cmd);
192 0 0         if (! defined($r)) {
193 0           $self->ignore_error($preve);
194 0           $self->ignore_error($prevc);
195 0           return;
196             }
197 0           $self->ignore_error($preve);
198 0           $self->ignore_error($prevc);
199              
200 0 0         my $ft = Metabrik::File::Text->new_from_brik_init($self) or return;
201 0           $ft->append(0);
202 0           $ft->overwrite(1);
203 0 0         $ft->write($r, $output) or return;
204              
205 0           return $output;
206             }
207              
208             sub save_nat {
209 0     0 0   my $self = shift;
210 0           my ($output) = @_;
211              
212 0   0       $output ||= $self->output;
213 0 0         $self->brik_help_run_undef_arg('save_nat', $output) or return;
214              
215 0           return $self->save($output, 'nat');
216             }
217              
218             sub save_filter {
219 0     0 0   my $self = shift;
220 0           my ($output) = @_;
221              
222 0   0       $output ||= $self->output;
223 0 0         $self->brik_help_run_undef_arg('save_filter', $output) or return;
224              
225 0           return $self->save($output, 'filter');
226             }
227              
228             sub restore {
229 0     0 0   my $self = shift;
230 0           my ($input, $table) = @_;
231              
232 0   0       $input ||= $self->input;
233 0 0         $self->brik_help_run_undef_arg('restore', $input) or return;
234              
235 0           my $datadir = $self->datadir;
236 0 0         if ($input !~ m{^/}) {
237 0           $input = $datadir.'/'.$input;
238             }
239 0 0         $self->brik_help_run_file_not_found('restore', $input) or return;
240              
241 0           my $cmd = "cat \"$input\" | iptables-restore -c";
242 0 0         if (defined($table)) {
243 0           $cmd = "iptables-restore -c -T $table < \"$input\"";
244             }
245              
246 0           $self->log->verbose("restore: cmd[$cmd]");
247              
248 0 0         if ($self->test_only) {
249 0           return 1;
250             }
251              
252 0           my $preve = $self->ignore_error;
253 0           my $prevc = $self->capture_stderr;
254 0           $self->ignore_error(0);
255 0           $self->capture_stderr(0);
256 0           my $r = $self->sudo_capture($cmd);
257 0 0         if (! defined($r)) {
258 0           $self->ignore_error($preve);
259 0           $self->ignore_error($prevc);
260 0           return;
261             }
262 0           $self->ignore_error($preve);
263 0           $self->ignore_error($prevc);
264              
265 0           return $input;
266             }
267              
268             sub restore_nat {
269 0     0 0   my $self = shift;
270 0           my ($input) = @_;
271              
272 0   0       $input ||= $self->input;
273 0 0         $self->brik_help_run_undef_arg('restore_nat', $input) or return;
274              
275 0           my $datadir = $self->datadir;
276 0 0         if ($input !~ m{^/}) {
277 0           $input = $datadir.'/'.$input;
278             }
279 0 0         $self->brik_help_run_file_not_found('restore_nat', $input) or return;
280              
281 0           return $self->restore($input, 'nat');
282             }
283              
284             sub restore_filter {
285 0     0 0   my $self = shift;
286 0           my ($input) = @_;
287              
288 0   0       $input ||= $self->input;
289 0 0         $self->brik_help_run_undef_arg('restore_filter', $input) or return;
290              
291 0           my $datadir = $self->datadir;
292 0 0         if ($input !~ m{^/}) {
293 0           $input = $datadir.'/'.$input;
294             }
295 0 0         $self->brik_help_run_file_not_found('restore_filter', $input) or return;
296              
297 0           return $self->restore($input, 'filter');
298             }
299              
300             sub flush {
301 0     0 0   my $self = shift;
302 0           my ($table, $chain) = @_;
303              
304 0 0         if (! defined($table)) {
305 0           $table = [ qw(nat filter) ];
306             }
307 0 0         my $ref = $self->brik_help_run_invalid_arg('flush', $table, 'ARRAY', 'SCALAR')
308             or return;
309              
310 0           my $cmd = "-t $table -F";
311              
312 0 0         if ($ref eq 'ARRAY') {
313 0           for my $this (@$table) {
314 0           $self->flush($this, $chain);
315             }
316 0           return 1;
317             }
318             else {
319 0 0         if (defined($chain)) {
320 0           $cmd = "-t $table -F $chain";
321             }
322             }
323              
324 0           return $self->command($cmd);
325             }
326              
327             sub flush_nat {
328 0     0 0   my $self = shift;
329 0           my ($chain) = @_;
330              
331 0           return $self->flush('nat', $chain);
332             }
333              
334             sub flush_nat_prerouting {
335 0     0 0   my $self = shift;
336              
337 0           return $self->flush_nat('PREROUTING');
338             }
339              
340             sub flush_nat_input {
341 0     0 0   my $self = shift;
342              
343 0           return $self->flush_nat('INPUT');
344             }
345              
346             sub flush_nat_output {
347 0     0 0   my $self = shift;
348              
349 0           return $self->flush_nat('OUTPUT');
350             }
351              
352             sub flush_nat_postrouting {
353 0     0 0   my $self = shift;
354              
355 0           return $self->flush_nat('POSTROUTING');
356             }
357              
358             sub flush_filter {
359 0     0 0   my $self = shift;
360 0           my ($chain) = @_;
361              
362 0           return $self->flush('filter', $chain);
363             }
364              
365             sub flush_filter_input {
366 0     0 0   my $self = shift;
367              
368 0           return $self->flush_filter('INPUT');
369             }
370              
371             sub flush_filter_forward {
372 0     0 0   my $self = shift;
373              
374 0           return $self->flush_filter('FORWARD');
375             }
376              
377             sub flush_filter_output {
378 0     0 0   my $self = shift;
379              
380 0           return $self->flush_filter('OUTPUT');
381             }
382              
383             sub set_policy {
384 0     0 0   my $self = shift;
385 0           my ($table, $target) = @_;
386              
387 0 0         $self->brik_help_run_undef_arg('set_policy', $table) or return;
388 0 0         $self->brik_help_run_undef_arg('set_policy', $target) or return;
389              
390 0           my $cmd = "-P $table $target";
391              
392 0           return $self->command($cmd);
393             }
394              
395             sub set_policy_input {
396 0     0 0   my $self = shift;
397 0           my ($target) = @_;
398              
399 0 0         $self->brik_help_run_undef_arg('set_policy_input', $target) or return;
400              
401 0           return $self->set_policy('input', $target);
402             }
403              
404             sub set_policy_output {
405 0     0 0   my $self = shift;
406 0           my ($target) = @_;
407              
408 0 0         $self->brik_help_run_undef_arg('set_policy_output', $target) or return;
409              
410 0           return $self->set_policy('output', $target);
411             }
412              
413             sub set_policy_forward {
414 0     0 0   my $self = shift;
415 0           my ($target) = @_;
416              
417 0 0         $self->brik_help_run_undef_arg('set_policy_forward', $target) or return;
418              
419 0           return $self->set_policy('forward', $target);
420             }
421              
422             sub _action {
423 0     0     my $self = shift;
424 0           my ($action, $table, $chain, $target, $rule) = @_;
425              
426 0   0       my $source = $rule->{source} || $self->source;
427 0   0       my $destination = $rule->{destination} || $self->destination;
428 0   0       my $protocol = $rule->{protocol} || $self->protocol;
429 0   0       my $dport = $rule->{dest_port} || '';
430 0   0       my $sport = $rule->{src_port} || '';
431 0   0       my $to_ports = $rule->{to_ports} || '';
432 0   0       my $state = $rule->{state} || '';
433 0   0       my $uid = $rule->{uid} || '';
434 0   0       my $to_destination = $rule->{to_destination} || '';
435 0   0       my $custom = $rule->{custom} || '';
436              
437 0           my $cmd = "-t $table $action $chain -j $target";
438 0 0         if (length($source)) {
439 0           $cmd .= " -s $source";
440             }
441 0 0         if (length($destination)) {
442 0           $cmd .= " -d $destination";
443             }
444 0 0         if (length($protocol)) {
445 0           $cmd .= " -p $protocol";
446             }
447 0 0         if (length($dport)) {
448 0           $cmd .= " --dport $dport";
449             }
450 0 0         if (length($sport)) {
451 0           $cmd .= " --sport $dport";
452             }
453 0 0         if (length($to_ports)) {
454 0           $cmd .= " --to-ports $to_ports";
455             }
456 0 0         if (length($state)) {
457 0           $cmd .= " -m state --state $state";
458             }
459 0 0         if (length($uid)) {
460 0           $cmd .= " -m owner --uid $uid";
461             }
462 0 0         if (length($to_destination)) {
463 0           $cmd .= " --to-destination $to_destination";
464             }
465 0 0         if (length($custom)) {
466 0           $cmd .= " $custom";
467             }
468              
469 0           return $cmd;
470             }
471              
472             sub add {
473 0     0 0   my $self = shift;
474 0           my ($table, $chain, $target, $rule) = @_;
475              
476 0   0       $table ||= $self->table;
477 0   0       $chain ||= $self->chain;
478 0   0       $target ||= $self->target;
479 0 0         $self->brik_help_run_undef_arg('add', $table) or return;
480 0 0         $self->brik_help_run_undef_arg('add', $chain) or return;
481 0 0         $self->brik_help_run_undef_arg('add', $target) or return;
482 0 0         $self->brik_help_run_undef_arg('add', $rule) or return;
483 0 0         $self->brik_help_run_invalid_arg('add', $rule, 'HASH') or return;
484              
485 0           my $cmd = $self->_action('-A', $table, $chain, $target, $rule);
486              
487 0           return $self->command($cmd);
488             }
489              
490             sub add_nat {
491 0     0 0   my $self = shift;
492 0           my ($chain, $target, $rule) = @_;
493              
494 0   0       $chain ||= $self->chain;
495 0   0       $target ||= $self->target;
496 0 0         $self->brik_help_run_undef_arg('add_nat', $chain) or return;
497 0 0         $self->brik_help_run_undef_arg('add_nat', $target) or return;
498 0 0         $self->brik_help_run_undef_arg('add_nat', $rule) or return;
499 0 0         $self->brik_help_run_invalid_arg('add_nat', $rule, 'HASH') or return;
500              
501 0           return $self->add('nat', $chain, $target, $rule);
502             }
503              
504             sub add_nat_output {
505 0     0 0   my $self = shift;
506 0           my ($target, $rule) = @_;
507              
508 0   0       $target ||= $self->target;
509 0 0         $self->brik_help_run_undef_arg('add_nat_output', $target) or return;
510 0 0         $self->brik_help_run_undef_arg('add_nat_output', $rule) or return;
511 0 0         $self->brik_help_run_invalid_arg('add_nat_output', $rule, 'HASH') or return;
512              
513 0           return $self->add_nat('OUTPUT', $target, $rule);
514             }
515              
516             sub add_nat_output_return {
517 0     0 0   my $self = shift;
518 0           my ($rule) = @_;
519              
520 0 0         $self->brik_help_run_undef_arg('add_nat_output_return', $rule) or return;
521 0 0         $self->brik_help_run_invalid_arg('add_nat_output_return', $rule, 'HASH') or return;
522              
523 0           return $self->add_nat_output('RETURN', $rule);
524             }
525              
526             sub add_nat_output_redirect {
527 0     0 0   my $self = shift;
528 0           my ($rule) = @_;
529              
530 0 0         $self->brik_help_run_undef_arg('add_nat_output_redirect', $rule) or return;
531 0 0         $self->brik_help_run_invalid_arg('add_nat_output_redirect', $rule, 'HASH') or return;
532              
533 0           return $self->add_nat_output('REDIRECT', $rule);
534             }
535              
536             sub add_nat_output_dnat {
537 0     0 0   my $self = shift;
538 0           my ($rule) = @_;
539              
540 0 0         $self->brik_help_run_undef_arg('add_nat_output_dnat', $rule) or return;
541 0 0         $self->brik_help_run_invalid_arg('add_nat_output_dnat', $rule, 'HASH') or return;
542              
543 0           return $self->add_nat_output('DNAT', $rule);
544             }
545              
546             sub add_nat_postrouting {
547 0     0 0   my $self = shift;
548 0           my ($target, $rule) = @_;
549              
550 0   0       $target ||= $self->target;
551 0 0         $self->brik_help_run_undef_arg('add_nat_postrouting', $target) or return;
552 0 0         $self->brik_help_run_undef_arg('add_nat_postrouting', $rule) or return;
553 0 0         $self->brik_help_run_invalid_arg('add_nat_postrouting', $rule, 'HASH') or return;
554              
555 0           return $self->add_nat('POSTROUTING', $target, $rule);
556             }
557              
558             # Example: iptables -A POSTROUTING -t nat -j MASQUERADE -s 192.168.1.0/24
559             sub add_nat_postrouting_masquerade {
560 0     0 0   my $self = shift;
561 0           my ($rule) = @_;
562              
563 0 0         $self->brik_help_run_undef_arg('add_nat_postrouting_masquerade', $rule) or return;
564 0 0         $self->brik_help_run_invalid_arg('add_nat_postrouting_masquerade', $rule, 'HASH') or return;
565              
566 0           return $self->add_nat_postrouting('MASQUERADE', $rule);
567             }
568              
569             sub add_nat_postrouting_dnat {
570 0     0 0   my $self = shift;
571 0           my ($rule) = @_;
572              
573 0 0         $self->brik_help_run_undef_arg('add_nat_postrouting_dnat', $rule) or return;
574 0 0         $self->brik_help_run_invalid_arg('add_nat_postrouting_dnat', $rule, 'HASH') or return;
575              
576 0           return $self->add_nat_postrouting('DNAT', $rule);
577             }
578              
579             sub add_filter {
580 0     0 0   my $self = shift;
581 0           my ($chain, $target, $rule) = @_;
582              
583 0   0       $chain ||= $self->chain;
584 0   0       $target ||= $self->target;
585 0 0         $self->brik_help_run_undef_arg('add_filter', $chain) or return;
586 0 0         $self->brik_help_run_undef_arg('add_filter', $target) or return;
587 0 0         $self->brik_help_run_undef_arg('add_filter', $rule) or return;
588 0 0         $self->brik_help_run_invalid_arg('add_filter', $rule, 'HASH') or return;
589              
590 0           return $self->add('filter', $chain, $target, $rule);
591             }
592              
593             sub add_filter_output {
594 0     0 0   my $self = shift;
595 0           my ($target, $rule) = @_;
596              
597 0   0       $target ||= $self->target;
598 0 0         $self->brik_help_run_undef_arg('add_filter_output', $target) or return;
599 0 0         $self->brik_help_run_undef_arg('add_filter_output', $rule) or return;
600 0 0         $self->brik_help_run_invalid_arg('add_filter_output', $rule, 'HASH') or return;
601              
602 0           return $self->add_filter('OUTPUT', $target, $rule);
603             }
604              
605             sub add_filter_output_accept {
606 0     0 0   my $self = shift;
607 0           my ($rule) = @_;
608              
609 0 0         $self->brik_help_run_undef_arg('add_filter_output_accept', $rule) or return;
610 0 0         $self->brik_help_run_invalid_arg('add_filter_output_accept', $rule, 'HASH') or return;
611              
612 0           return $self->add_filter_output('ACCEPT', $rule);
613             }
614              
615             sub add_filter_output_reject {
616 0     0 0   my $self = shift;
617 0           my ($rule) = @_;
618              
619 0 0         $self->brik_help_run_undef_arg('add_filter_output_reject', $rule) or return;
620 0 0         $self->brik_help_run_invalid_arg('add_filter_output_reject', $rule, 'HASH') or return;
621              
622 0           return $self->add_filter_output('REJECT', $rule);
623             }
624              
625             sub del {
626 0     0 0   my $self = shift;
627 0           my ($table, $chain, $target, $rule) = @_;
628              
629 0   0       $table ||= $self->table;
630 0   0       $chain ||= $self->chain;
631 0   0       $target ||= $self->target;
632 0 0         $self->brik_help_run_undef_arg('del', $table) or return;
633 0 0         $self->brik_help_run_undef_arg('del', $chain) or return;
634 0 0         $self->brik_help_run_undef_arg('del', $target) or return;
635 0 0         $self->brik_help_run_undef_arg('del', $rule) or return;
636 0 0         $self->brik_help_run_invalid_arg('del', $rule, 'HASH') or return;
637              
638 0           my $cmd = $self->_action('-D', $table, $chain, $target, $rule);
639              
640 0           return $self->command($cmd);
641             }
642              
643             sub del_nat {
644 0     0 0   my $self = shift;
645 0           my ($chain, $target, $rule) = @_;
646              
647 0   0       $chain ||= $self->chain;
648 0   0       $target ||= $self->target;
649 0 0         $self->brik_help_run_undef_arg('del_nat', $chain) or return;
650 0 0         $self->brik_help_run_undef_arg('del_nat', $target) or return;
651 0 0         $self->brik_help_run_undef_arg('del_nat', $rule) or return;
652 0 0         $self->brik_help_run_invalid_arg('del_nat', $rule, 'HASH') or return;
653              
654 0           return $self->del('nat', $chain, $target, $rule);
655             }
656              
657             sub del_nat_output {
658 0     0 0   my $self = shift;
659 0           my ($target, $rule) = @_;
660              
661 0   0       $target ||= $self->target;
662 0 0         $self->brik_help_run_undef_arg('del_nat_output', $target) or return;
663 0 0         $self->brik_help_run_undef_arg('del_nat_output', $rule) or return;
664 0 0         $self->brik_help_run_invalid_arg('del_nat_output', $rule, 'HASH') or return;
665              
666 0           return $self->del_nat('OUTPUT', $target, $rule);
667             }
668              
669             sub del_nat_output_return {
670 0     0 0   my $self = shift;
671 0           my ($rule) = @_;
672              
673 0 0         $self->brik_help_run_undef_arg('del_nat_output_return', $rule) or return;
674 0 0         $self->brik_help_run_invalid_arg('del_nat_output_return', $rule, 'HASH') or return;
675              
676 0           return $self->del_nat_output('RETURN', $rule);
677             }
678              
679             sub del_nat_output_redirect {
680 0     0 0   my $self = shift;
681 0           my ($rule) = @_;
682              
683 0 0         $self->brik_help_run_undef_arg('del_nat_output_return', $rule) or return;
684 0 0         $self->brik_help_run_invalid_arg('del_nat_output_return', $rule, 'HASH') or return;
685              
686 0           return $self->del_nat_output('REDIRECT', $rule);
687             }
688              
689             sub del_nat_output_dnat {
690 0     0 0   my $self = shift;
691 0           my ($rule) = @_;
692              
693 0 0         $self->brik_help_run_undef_arg('del_nat_output_return', $rule) or return;
694 0 0         $self->brik_help_run_invalid_arg('del_nat_output_return', $rule, 'HASH') or return;
695              
696 0           return $self->del_nat_output('DNAT', $rule);
697             }
698              
699             sub check {
700 0     0 0   my $self = shift;
701 0           my ($table, $chain, $target, $rule) = @_;
702              
703 0   0       $table ||= $self->table;
704 0   0       $chain ||= $self->chain;
705 0   0       $target ||= $self->target;
706 0 0         $self->brik_help_run_undef_arg('check', $table) or return;
707 0 0         $self->brik_help_run_undef_arg('check', $chain) or return;
708 0 0         $self->brik_help_run_undef_arg('check', $target) or return;
709 0 0         $self->brik_help_run_undef_arg('check', $rule) or return;
710 0 0         $self->brik_help_run_invalid_arg('check', $rule, 'HASH') or return;
711              
712 0           my $cmd = $self->_action('-C', $table, $chain, $target, $rule);
713              
714 0           return $self->command($cmd);
715             }
716              
717             sub check_nat {
718 0     0 0   my $self = shift;
719 0           my ($chain, $target, $rule) = @_;
720              
721 0   0       $chain ||= $self->chain;
722 0   0       $target ||= $self->target;
723 0 0         $self->brik_help_run_undef_arg('check_nat', $chain) or return;
724 0 0         $self->brik_help_run_undef_arg('check_nat', $target) or return;
725 0 0         $self->brik_help_run_undef_arg('check_nat', $rule) or return;
726 0 0         $self->brik_help_run_invalid_arg('check_nat', $rule, 'HASH') or return;
727              
728 0           return $self->check('nat', $chain, $target, $rule);
729             }
730              
731             sub check_nat_output {
732 0     0 0   my $self = shift;
733 0           my ($target, $rule) = @_;
734              
735 0   0       $target ||= $self->target;
736 0 0         $self->brik_help_run_undef_arg('check_nat_output', $target) or return;
737 0 0         $self->brik_help_run_undef_arg('check_nat_output', $rule) or return;
738 0 0         $self->brik_help_run_invalid_arg('check_nat_output', $rule, 'HASH') or return;
739              
740 0           return $self->check_nat('OUTPUT', $target, $rule);
741             }
742              
743             sub check_nat_output_return {
744 0     0 0   my $self = shift;
745 0           my ($rule) = @_;
746              
747 0 0         $self->brik_help_run_undef_arg('check_nat_output_return', $rule) or return;
748 0 0         $self->brik_help_run_invalid_arg('check_nat_output_return', $rule, 'HASH') or return;
749              
750 0           return $self->check_nat_output('RETURN', $rule);
751             }
752              
753             sub check_nat_output_redirect {
754 0     0 0   my $self = shift;
755 0           my ($rule) = @_;
756              
757 0 0         $self->brik_help_run_undef_arg('check_nat_output_return', $rule) or return;
758 0 0         $self->brik_help_run_invalid_arg('check_nat_output_return', $rule, 'HASH') or return;
759              
760 0           return $self->check_nat_output('REDIRECT', $rule);
761             }
762              
763             sub check_nat_output_dnat {
764 0     0 0   my $self = shift;
765 0           my ($rule) = @_;
766              
767 0 0         $self->brik_help_run_undef_arg('check_nat_output_return', $rule) or return;
768 0 0         $self->brik_help_run_invalid_arg('check_nat_output_return', $rule, 'HASH') or return;
769              
770 0           return $self->check_nat_output('DNAT', $rule);
771             }
772              
773             sub _redirect_target_to {
774 0     0     my $self = shift;
775 0           my ($action, $target_host_port, $dest_host_port, $protocol) = @_;
776              
777 0 0         if ($target_host_port =~ m{^\d+$}) {
778 0           $target_host_port = ":$target_host_port";
779             }
780 0 0         if ($dest_host_port =~ m{^\d+$}) {
781 0           $dest_host_port = ":$dest_host_port";
782             }
783              
784 0           my ($target_host, $target_port) = split(/:/, $target_host_port);
785 0   0       $target_host ||= '';
786 0   0       $target_port ||= '';
787              
788 0           my ($dest_host, $dest_port) = split(/:/, $dest_host_port);
789 0   0       $dest_host ||= '';
790 0   0       $dest_port ||= '';
791              
792 0           my $method_return = '';
793 0           my $method_dnat = '';
794 0 0         if ($action eq 'start') {
795 0           $method_return = 'add_nat_output_return';
796 0           $method_dnat = 'add_nat_output_dnat';
797             }
798             else {
799 0           $method_return = 'del_nat_output_return';
800 0           $method_dnat = 'del_nat_output_dnat';
801             }
802              
803             # Add only if it does not exist yet
804 0 0 0       if ($action eq 'start' && ! $self->check_nat_output_return({ state => 'ESTABLISHED' })) {
805 0 0         $self->$method_return({ state => 'ESTABLISHED' }) or return;
806             }
807              
808             # Use only specified protocol
809 0 0         if ($protocol) {
810 0           my $rule = {
811             destination => $target_host,
812             dest_port => $target_port,
813             to_destination => "$dest_host:$dest_port",
814             protocol => $protocol,
815             };
816 0 0 0       if ($action eq 'start' && ! $self->check_nat_output_dnat($rule)) {
    0          
817 0 0         $self->$method_dnat($rule) or return;
818             }
819             elsif ($action eq 'stop') {
820 0 0         $self->$method_dnat($rule) or return;
821             }
822             }
823             # Or use both tcp and udp
824             else {
825 0           my $rule_tcp = {
826             destination => $target_host,
827             dest_port => $target_port,
828             to_destination => "$dest_host:$dest_port",
829             protocol => 'tcp',
830             };
831 0           my $rule_udp = {
832             destination => $target_host,
833             dest_port => $target_port,
834             to_destination => "$dest_host:$dest_port",
835             protocol => 'udp',
836             };
837 0 0 0       if ($action eq 'start' && ! $self->check_nat_output_dnat($rule_tcp)) {
    0          
838 0 0         $self->$method_dnat($rule_tcp) or return;
839             }
840             elsif ($action eq 'stop') {
841 0 0         $self->$method_dnat($rule_tcp) or return;
842             }
843 0 0 0       if ($action eq 'start' && ! $self->check_nat_output_dnat($rule_udp)) {
    0          
844 0 0         $self->$method_dnat($rule_udp) or return;
845             }
846             elsif ($action eq 'stop') {
847 0 0         $self->$method_dnat($rule_udp) or return;
848             }
849             }
850              
851 0           return 1;
852             }
853              
854             sub start_redirect_target_to {
855 0     0 0   my $self = shift;
856 0           my ($target_host_port, $dest_host_port, $protocol) = @_;
857              
858 0 0         $self->brik_help_run_undef_arg('start_redirect_target_to', $target_host_port) or return;
859 0 0         $self->brik_help_run_undef_arg('start_redirect_target_to', $dest_host_port) or return;
860              
861 0           return $self->_redirect_target_to('start', $target_host_port, $dest_host_port, $protocol);
862             }
863              
864             sub start_redirect_target_tcp_to {
865 0     0 0   my $self = shift;
866 0           my ($target_host_port, $dest_host_port) = @_;
867              
868 0 0         $self->brik_help_run_undef_arg('start_redirect_target_tcp_to', $target_host_port) or return;
869 0 0         $self->brik_help_run_undef_arg('start_redirect_target_tcp_to', $dest_host_port) or return;
870              
871 0           return $self->start_redirect_target_to($target_host_port, $dest_host_port, 'tcp');
872             }
873              
874             sub start_redirect_target_udp_to {
875 0     0 0   my $self = shift;
876 0           my ($target_host_port, $dest_host_port) = @_;
877              
878 0 0         $self->brik_help_run_undef_arg('start_redirect_target_udp_to', $target_host_port) or return;
879 0 0         $self->brik_help_run_undef_arg('start_redirect_target_udp_to', $dest_host_port) or return;
880              
881 0           return $self->start_redirect_target_to($target_host_port, $dest_host_port, 'udp');
882             }
883              
884             sub stop_redirect_target_to {
885 0     0 0   my $self = shift;
886 0           my ($target_host_port, $dest_host_port, $protocol) = @_;
887              
888 0 0         $self->brik_help_run_undef_arg('stop_redirect_target_to', $target_host_port) or return;
889 0 0         $self->brik_help_run_undef_arg('stop_redirect_target_to', $dest_host_port) or return;
890              
891 0           return $self->_redirect_target_to('stop', $target_host_port, $dest_host_port, $protocol);
892             }
893              
894             1;
895              
896             __END__