1 | # -*- coding: utf-8 -*- |
---|
2 | ################################################################################# |
---|
3 | # @file ports_manager.py |
---|
4 | # @brief Add an remove iptables rules and get one |
---|
5 | # input free port. |
---|
6 | # @warning None |
---|
7 | # @note Use: IPTABLES to manage NAT ports. |
---|
8 | # AT to schedule ports allowance time. |
---|
9 | # @license GNU GPLv3+ |
---|
10 | # @author David Fuertes, EUPT, University of Zaragoza, |
---|
11 | # Opengnsys Api Rest support provided by Juan Carlos García, EUPT, University of Zaragoza. |
---|
12 | # @version 1.1.0 - First version |
---|
13 | # @date 2019-15-11 |
---|
14 | ################################################################################# |
---|
15 | import subprocess |
---|
16 | import re |
---|
17 | |
---|
18 | |
---|
19 | def get_origin_port(ip_origin, ip_remote, port_remote, maxtime): |
---|
20 | new_port = search_new_port() |
---|
21 | add_iptables_rules(ip_origin, ip_remote, new_port, port_remote) |
---|
22 | schedule_delete_rules(ip_origin, ip_remote, new_port, port_remote, maxtime) |
---|
23 | return new_port |
---|
24 | |
---|
25 | def search_new_port(): |
---|
26 | ports_in_use = get_ports_in_use() |
---|
27 | port = 11000 |
---|
28 | port_range = 4000 |
---|
29 | for i in range(port_range): |
---|
30 | if port in ports_in_use: |
---|
31 | port = port + 1 |
---|
32 | else: |
---|
33 | break |
---|
34 | |
---|
35 | return str(port) |
---|
36 | |
---|
37 | |
---|
38 | def add_iptables_rules(ip_origin, ip_remote, new_port, port_remote): |
---|
39 | rules = iptables_rules(ip_origin, ip_remote, new_port, port_remote, "A") |
---|
40 | for rule in rules: |
---|
41 | subprocess.run(rule, shell=True) |
---|
42 | |
---|
43 | |
---|
44 | def iptables_rules(ip_origin, ip_remote, new_port, port_remote, action): |
---|
45 | return ["sudo iptables -t nat -" + action + " PREROUTING -s " + ip_origin + " -p tcp --dport " + new_port + \ |
---|
46 | " -j DNAT --to-destination " + ip_remote + ":" + port_remote, |
---|
47 | "sudo iptables -t nat -" + action + " POSTROUTING -s " + ip_origin + \ |
---|
48 | " -p tcp -d " + ip_remote + " -j MASQUERADE", |
---|
49 | "sudo iptables -" + action + " FORWARD -s " + ip_origin + " -d " + ip_remote +" -p tcp -j ACCEPT"] |
---|
50 | |
---|
51 | |
---|
52 | def schedule_delete_rules(ip_origin, ip_remote, new_port, port_remote, maxtime): |
---|
53 | rules = iptables_rules(ip_origin, ip_remote, new_port, port_remote, "D") |
---|
54 | repeated_nat = check_repeat_nat_rules(ip_origin, ip_remote) |
---|
55 | repeated_forward = check_repeat_forward_rules(ip_origin, ip_remote) |
---|
56 | for i in range(repeated_nat['repeated_DNAT']): |
---|
57 | subprocess.run('echo ' + rules[0] + ' | sudo at now + ' + maxtime + ' hours', shell=True) |
---|
58 | for i in range(repeated_nat['repeated_MASQUERADE']): |
---|
59 | subprocess.run('echo ' + rules[1] + ' | sudo at now + ' + maxtime + ' hours', shell=True) |
---|
60 | for i in range(repeated_forward): |
---|
61 | subprocess.run('echo ' + rules[2] + ' | sudo at now + ' + maxtime + ' hours', shell=True) |
---|
62 | |
---|
63 | |
---|
64 | def check_repeat_nat_rules(ip_origin, ip_remote): |
---|
65 | iptables = subprocess.run('sudo iptables -t nat -L', shell=True, stdout=subprocess.PIPE).stdout.decode('utf-8') |
---|
66 | repeated_DNAT = 0 |
---|
67 | repeated_MASQUERADE = 0 |
---|
68 | for line in iptables.splitlines(): |
---|
69 | line_splited = re.sub(' +', ' ', line).split(' ') |
---|
70 | target = line_splited[0] |
---|
71 | if target == 'DNAT': |
---|
72 | source = line_splited[3] |
---|
73 | destiny= line_splited[-1].split(':')[1] |
---|
74 | if source == ip_origin and destiny == ip_remote: |
---|
75 | repeated_DNAT = repeated_DNAT + 1 |
---|
76 | |
---|
77 | |
---|
78 | if target == 'MASQUERADE': |
---|
79 | source = line_splited[3] |
---|
80 | destiny = line_splited[4] |
---|
81 | if source == ip_origin and destiny == ip_remote: |
---|
82 | repeated_MASQUERADE = repeated_MASQUERADE + 1 |
---|
83 | |
---|
84 | return {'repeated_DNAT':repeated_DNAT, 'repeated_MASQUERADE':repeated_MASQUERADE} |
---|
85 | |
---|
86 | def check_repeat_forward_rules(ip_origin, ip_remote): |
---|
87 | iptables = subprocess.run('sudo iptables -L', shell=True, stdout=subprocess.PIPE).stdout.decode('utf-8') |
---|
88 | repeated = 0 |
---|
89 | for line in iptables.splitlines(): |
---|
90 | line_splited = re.sub(' +', ' ', line).split(' ') |
---|
91 | if len(line_splited) > 5: |
---|
92 | source = line_splited[3] |
---|
93 | destiny = line_splited[4] |
---|
94 | if source == ip_origin and destiny == ip_remote: |
---|
95 | repeated = repeated + 1 |
---|
96 | |
---|
97 | return repeated |
---|
98 | |
---|
99 | def get_ports_in_use(): |
---|
100 | iptables = subprocess.run('sudo iptables -t nat -L', shell=True, stdout=subprocess.PIPE).stdout.decode('utf-8') |
---|
101 | ports = [] |
---|
102 | for line in iptables.splitlines(): |
---|
103 | line_splited = re.sub(' +', ' ', line).split(' ') |
---|
104 | target = line_splited[0] |
---|
105 | if target == 'DNAT': |
---|
106 | ports.append(int(line_splited[-2].split(':')[-1])) |
---|
107 | |
---|
108 | return ports |
---|