custom openvpn script, changed iptable to include a load balanced table

This commit is contained in:
mantaohuang 2020-04-05 21:46:57 -04:00
parent 5957bc66f3
commit a0427f3c95
4 changed files with 80 additions and 17 deletions

View File

@ -1,5 +1,5 @@
#!/bin/sh #!/bin/sh
# set -e
# Flush the tables. This may cut the system's internet. # Flush the tables. This may cut the system's internet.
iptables -F iptables -F
iptables -X iptables -X
@ -19,25 +19,43 @@ iptables -A OUTPUT -j ACCEPT -o tun+
#iptables -A OUTPUT -j ACCEPT -o tun+ #iptables -A OUTPUT -j ACCEPT -o tun+
iptables -t mangle -A OUTPUT -m owner --gid-owner openvpn -j MARK --set-mark 11 iptables -t mangle -A OUTPUT -m owner --gid-owner openvpn -j MARK --set-mark 11
iptables -t mangle -A OUTPUT -j MARK --set-mark 12
iptables -t nat -A POSTROUTING -m owner --gid-owner openvpn -o enp1s0 -j MASQUERADE iptables -t nat -A POSTROUTING -m owner --gid-owner openvpn -o enp1s0 -j MASQUERADE
echo ip route echo ip route
ip route flush all ip route flush all
ip rule flush ip rule flush
ip rule add from all lookup main pref 32766 ip rule add from all lookup main pref 32766
ip rule add from all lookup default pref 32767 ip rule add from all lookup default pref 32767
echo add fwmark
ip rule add fwmark 11 table novpn pref 100
echo add to novpn table echo "create route table if it does not exist"
if [ $(cat /etc/iproute2/rt_tables | grep novpn | wc -l) -eq 0 ]; then
echo "11 novpn" >> /etc/iproute2/rt_tables
fi
if [ $(cat /etc/iproute2/rt_tables | grep balanced | wc -l) -eq 0 ]; then
echo "10 balanced" >> /etc/iproute2/rt_tables
fi
echo "add to novpn table"
ip route flush table novpn ip route flush table novpn
ip route add 192.168.122.0/24 dev enp1s0 # src 192.168.122.128 ip route add 192.168.122.0/24 dev enp1s0
#ip route add 192.168.122.0/24 dev enp1s0 table novpn
ip route add default via 192.168.122.1 dev enp1s0 table novpn ip route add default via 192.168.122.1 dev enp1s0 table novpn
echo add to default table
echo "add to balanced table"
ip route flush table balanced
ip route add default via 192.168.122.1 dev enp1s0 table balanced
echo "add to default table"
# need to add a default route for the routing code to trigger the fwmark rule at all, else there's a direct "Network is unreachable" with no packet generated. # need to add a default route for the routing code to trigger the fwmark rule at all, else there's a direct "Network is unreachable" with no packet generated.
ip route add default via 192.168.122.254 dev enp1s0 # not exist ip route add default via 192.168.122.254 dev enp1s0
echo rp_filter
echo "disable rp_filter"
for i in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > $i; done for i in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > $i; done
echo "add ip rule fwmark"
ip rule add fwmark 12 table balanced pref 98
ip rule add fwmark 11 table novpn pref 99
# We should permit replies to traffic we've sent out. # We should permit replies to traffic we've sent out.
iptables -A INPUT -j ACCEPT -m state --state ESTABLISHED iptables -A INPUT -j ACCEPT -m state --state ESTABLISHED

View File

@ -17,8 +17,8 @@ class OManager:
os.makedirs(folder_path) os.makedirs(folder_path)
if not name: if not name:
name = f"openvpn-{self.idx}" name = f"openvpn-{self.idx}"
op = Openvpn(cfg_fp, interface, folder_path, op = Openvpn(cfg_fp, self.idx, folder_path,
f"{self.base_port + self.idx}", name=name, f"{self.base_port + self.idx}", "script.sh.template", name=name,
additional_cfg=additional_cfg) additional_cfg=additional_cfg)
self.ops.append(op) self.ops.append(op)
self.idx += 1 self.idx += 1

View File

@ -11,6 +11,8 @@ import psutil
import subprocess import subprocess
from datetime import datetime from datetime import datetime
import humanize import humanize
from tornado.template import Template
import stat
def generate_config(in_fp, cfg): def generate_config(in_fp, cfg):
@ -39,9 +41,10 @@ RUNNING = "running"
class Openvpn: class Openvpn:
def __init__(self, cfg_fp, interface, folder_path, management_port, name=None, additional_cfg={}, loop=None): def __init__(self, cfg_fp, idx, folder_path, management_port, template_fp, name=None, additional_cfg={}, loop=None):
self.cfg_fp = cfg_fp self.cfg_fp = cfg_fp
self.interface = interface self.idx = idx
self.interface = f"tun{idx}"
self.folder_path = folder_path self.folder_path = folder_path
self.management_port = management_port self.management_port = management_port
self.PID = 0 self.PID = 0
@ -56,12 +59,33 @@ class Openvpn:
# TODO: update paths function # TODO: update paths function
self.io_stat_fp = os.path.join(self.folder_path, "io_stat.txt") self.io_stat_fp = os.path.join(self.folder_path, "io_stat.txt")
self.ping_stat_fp = os.path.join(self.folder_path, "ping_stat.txt") self.ping_stat_fp = os.path.join(self.folder_path, "ping_stat.txt")
self.template_fp = template_fp
if loop: if loop:
self.loop = loop self.loop = loop
else: else:
self.loop = asyncio.get_event_loop() self.loop = asyncio.get_event_loop()
def generate_script(self):
self.script_fp = os.path.join(self.folder_path, "cfg.txt")
with open(self.template_fp, "r") as template_f:
buf = template_f.read()
template = Template(buf)
script_log_fp = os.path.join(self.folder_path, "script_log.txt")
items = {
"script_log_fp": script_log_fp,
"route_table_name": f"vpn{self.idx}",
"route_table_id": f"{300+self.idx}",
"rule_pref": f"{100+self.idx}"
}
script = template.generate(**items)
with open(self.script_fp, "wb") as script_f:
script_f.write(script)
# mark executable
st = os.stat(self.script_fp)
os.chmod(self.script_fp, st.st_mode | stat.S_IEXEC)
return self.script_fp
def get_cfg(self): def get_cfg(self):
self.log_fp = os.path.join(self.folder_path, "log.txt") self.log_fp = os.path.join(self.folder_path, "log.txt")
cfg = { cfg = {
@ -85,9 +109,9 @@ class Openvpn:
if self.status == IDLE: if self.status == IDLE:
self.status = RUNNING self.status = RUNNING
config_fp = self.generate_config_file() config_fp = self.generate_config_file()
route_up_script = os.path.join(self.folder_path, "test.sh") script_fp = self.generate_script()
cmd = " ".join(["openvpn", "--config", config_fp, "--route-noexec", cmd = " ".join(["openvpn", "--config", config_fp, "--route-noexec",
"--route-up", route_up_script, "--script-security", "--route-up", script_fp, "--script-security",
"2", "--mute-replay-warnings"]) # TODO: remove --mute-replay-warnings "2", "--mute-replay-warnings"]) # TODO: remove --mute-replay-warnings
self.run_task.append(self.loop.create_task(self.run(cmd))) self.run_task.append(self.loop.create_task(self.run(cmd)))
self.run_task.append(self.loop.create_task(self.monitor_task())) self.run_task.append(self.loop.create_task(self.monitor_task()))
@ -233,6 +257,6 @@ class Openvpn:
if __name__ == "__main__": if __name__ == "__main__":
folder_fp = "/home/mantao/Desktop/t/" folder_fp = "/home/mantao/Desktop/t/"
cfg_fp = "/home/mantao/Desktop/t/TCP_Files/UK2-TCP.ovpn" cfg_fp = "/home/mantao/Desktop/t/TCP_Files/UK2-TCP.ovpn"
o1 = Openvpn(cfg_fp, "tun0", folder_fp, 8001, additional_cfg={ o1 = Openvpn(cfg_fp, 0, folder_fp, 8001, "script.sh.template", additional_cfg={
"auth-user-pass": "/home/mantao/Desktop/t/fast.txt"}) "auth-user-pass": "/home/mantao/Desktop/t/fast.txt"})
# o1.start() # o1.start()

21
script.sh.template Normal file
View File

@ -0,0 +1,21 @@
#!/bin/sh
echo ============================== >> {{script_log_fp}}
env >> {{script_log_fp}}
# create route table if it does not exist
if [ $(cat /etc/iproute2/rt_tables | grep {{route_table_name}} | wc -l) -eq 0 ]; then
echo "{{route_table_id}} {{route_table_name}}" >> /etc/iproute2/rt_tables
fi
# populate route table
ip route flush table {{route_table_name}}
ip route add ${route_vpn_gateway} dev ${dev} src ${ifconfig_local} table {{route_table_name}}
ip route add default via ${route_vpn_gateway} table {{route_table_name}}
# add vpn_gateway to main route table
ip route add ${route_vpn_gateway} dev ${dev} src ${ifconfig_local}
ip rule add from ${ifconfig_local} table {{route_table_name}} pref {{rule_pref}}
exit 0