Skip to content

Commit cc097c8

Browse files
authored
Merge pull request #33 from Perflyst/patch-1
Python3 support and other updates
2 parents 76ae305 + b4d35cb commit cc097c8

File tree

4 files changed

+34
-7
lines changed

4 files changed

+34
-7
lines changed

.travis.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
language: python
22
python:
33
- "2.7"
4-
#- "3.6"
4+
- "3.7"
5+
- "3.8"
56
script: make test

hooks

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/python
1+
#!/usr/bin/env python3
22

33
"""Libvirt port-forwarding hook.
44
@@ -15,8 +15,7 @@ import re
1515
import subprocess
1616
import sys
1717

18-
# python 2.6 support
19-
if "check_output" not in dir( subprocess ):
18+
if "check_output" not in dir(subprocess):
2019
def f(*popenargs, **kwargs):
2120
if 'stdout' in kwargs:
2221
raise ValueError('stdout argument not allowed, it will be overridden.')
@@ -61,6 +60,10 @@ def json_minify(string, strip_space=True):
6160
# replace white space as defined in standard
6261
tmp = re.sub('[ \t\n\r]+', '', tmp)
6362
new_str.append(tmp)
63+
elif not strip_space:
64+
# Replace comments with white space so that the JSON parser reports
65+
# the correct column numbers on parsing errors.
66+
new_str.append(' ' * (match.start() - index))
6467

6568
index = match.end()
6669
val = match.group()
@@ -79,11 +82,19 @@ def json_minify(string, strip_space=True):
7982
in_single = True
8083
elif val == '*/' and in_multi and not (in_string or in_single):
8184
in_multi = False
85+
if not strip_space:
86+
new_str.append(' ' * len(val))
8287
elif val in '\r\n' and not (in_multi or in_string) and in_single:
8388
in_single = False
8489
elif not ((in_multi or in_single) or (val in ' \r\n\t' and strip_space)): # noqa
8590
new_str.append(val)
8691

92+
if not strip_space:
93+
if val in '\r\n':
94+
new_str.append(val)
95+
elif in_multi or in_single:
96+
new_str.append(' ' * len(val))
97+
8798
new_str.append(string[index:])
8899
return ''.join(new_str)
89100

@@ -156,6 +167,8 @@ def populate_chains(dnat_chain, snat_chain, fwd_chain, public_ip, private_ip, do
156167
subprocess.call([IPTABLES_BINARY, "-t", "nat", "-A", dnat_chain, "-p", protocol,
157168
"-d", public_ip, "--dport", str(public_port), "-j", "DNAT", "--to", dest] +
158169
(["-s", source_ip] if source_ip else []))
170+
subprocess.call([IPTABLES_BINARY, "-t", "nat", "-A", snat_chain, "-p", protocol,
171+
"-s", private_ip, "--dport", str(private_port), "-j", "SNAT", "--to-source", public_ip])
159172
subprocess.call([IPTABLES_BINARY, "-t", "nat", "-A", snat_chain, "-p", protocol,
160173
"-s", private_ip, "-d", private_ip, "--dport", str(public_port), "-j", "MASQUERADE"])
161174
interface = ["-o", domain["interface"]
@@ -172,6 +185,8 @@ def populate_chains(dnat_chain, snat_chain, fwd_chain, public_ip, private_ip, do
172185
private_ip, ports_range.replace(":", "-", 1))
173186
subprocess.call([IPTABLES_BINARY, "-t", "nat", "-A", dnat_chain, "-p", port_range["protocol"],
174187
"-d", public_ip, "--dport", ports_range, "-j", "DNAT", "--to", dest])
188+
subprocess.call([IPTABLES_BINARY, "-t", "nat", "-A", snat_chain, "-p", port_range["protocol"],
189+
"-s", private_ip, "--dport", str(private_port), "-j", "SNAT", "--to-source", public_ip])
175190
subprocess.call([IPTABLES_BINARY, "-t", "nat", "-A", snat_chain, "-p", port_range["protocol"],
176191
"-s", private_ip, "-d", private_ip, "--dport", ports_range, "-j", "MASQUERADE"])
177192
interface = ["-o", domain["interface"]
@@ -186,12 +201,16 @@ def insert_chains(action, dnat_chain, snat_chain, fwd_chain, public_ip, private_
186201
"OUTPUT", "-d", public_ip, "-j", dnat_chain])
187202
subprocess.call([IPTABLES_BINARY, "-t", "nat", action,
188203
"PREROUTING", "-d", public_ip, "-j", dnat_chain])
204+
# TODO: Find solution for connections from different private_ip to public_ip
205+
# maybe use private_ip_net as source instead
206+
# WORKAROUND: remove `"-s", private_ip, `
189207
subprocess.call([IPTABLES_BINARY, "-t", "nat", action, "POSTROUTING",
190208
"-s", private_ip, "-d", private_ip, "-j", snat_chain])
191209
subprocess.call([IPTABLES_BINARY, "-t", "filter", action,
192210
"FORWARD", "-d", private_ip, "-j", fwd_chain])
193211

194212
# the snat_chain doesn't work unless we turn off filtering bridged packets
213+
# https://wiki.libvirt.org/page/Net.bridge.bridge-nf-call_and_sysctl.conf
195214

196215

197216
def disable_bridge_filtering():

hooks.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
"cloud-admin": {
33
"interface": "virbr1", // you can use comments
44
"private_ip": "192.168.124.10", /* both styles */
5+
// source_ip is not the hosts public_ip
6+
// it is a remote IP which gets permission to access this port
57
"source_ip": "8.8.8.8",
68
"port_map": {
79
"tcp": [[1100, 3000], 443]
@@ -10,6 +12,7 @@
1012
"cloud-node1": {
1113
"private_ip": "192.168.126.2",
1214
"port_map": {
15+
// [[private_ip, public_ip]]
1316
"tcp": [[1101, 80],
1417
[1102, 443]]
1518
}

test_qemu.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
#!/usr/bin/python
1+
#!/usr/bin/env python3
22

33
import imp
4-
import json
54
import os
65
import socket
76
import sys
@@ -37,13 +36,15 @@ def capture_output(self, func):
3736
qemu.IPTABLES_BINARY = '/bin/echo'
3837
to = open(outfile, "w")
3938
os.dup2(to.fileno(), sys.stdout.fileno())
39+
to.close()
4040
func()
4141
finally:
4242
sys.stdout.flush()
4343
os.dup2(orig_out, sys.stdout.fileno())
4444
qemu.IPTABLES_BINARY = orig_binary
4545

46-
output = open(outfile).read()
46+
with open(outfile, 'r') as f:
47+
output = f.read()
4748
os.remove(outfile)
4849
return output
4950

@@ -62,12 +63,15 @@ def test_setup(self):
6263
-t nat -N SNAT-test
6364
-t filter -N FWD-test
6465
-t nat -A DNAT-test -p udp -d 192.168.1.1 --dport 53 -j DNAT --to 127.0.0.1:53
66+
-t nat -A SNAT-test -p udp -s 127.0.0.1 --dport 53 -j SNAT --to-source 192.168.1.1
6567
-t nat -A SNAT-test -p udp -s 127.0.0.1 -d 127.0.0.1 --dport 53 -j MASQUERADE
6668
-t filter -A FWD-test -p udp -d 127.0.0.1 --dport 53 -j ACCEPT -o virbr0
6769
-t nat -A DNAT-test -p tcp -d 192.168.1.1 --dport 80 -j DNAT --to 127.0.0.1:8080
70+
-t nat -A SNAT-test -p tcp -s 127.0.0.1 --dport 8080 -j SNAT --to-source 192.168.1.1
6871
-t nat -A SNAT-test -p tcp -s 127.0.0.1 -d 127.0.0.1 --dport 80 -j MASQUERADE
6972
-t filter -A FWD-test -p tcp -d 127.0.0.1 --dport 8080 -j ACCEPT -o virbr0
7073
-t nat -A DNAT-test -p tcp -d 192.168.1.1 --dport 443 -j DNAT --to 127.0.0.1:443
74+
-t nat -A SNAT-test -p tcp -s 127.0.0.1 --dport 443 -j SNAT --to-source 192.168.1.1
7175
-t nat -A SNAT-test -p tcp -s 127.0.0.1 -d 127.0.0.1 --dport 443 -j MASQUERADE
7276
-t filter -A FWD-test -p tcp -d 127.0.0.1 --dport 443 -j ACCEPT -o virbr0
7377
-t nat -I OUTPUT -d 192.168.1.1 -j DNAT-test

0 commit comments

Comments
 (0)