2024-12-02 00:06:53 +00:00
from lib import config as config_module
from lib import logging as logging_lib
from lib import utils
import os
import aiofiles . os
config = config_module . config
log = logging_lib . log
CLIENT_CONFIGS_LOCATION = " /etc/openvpn/client "
PARTNER_CONFIG_NAME = " clore_partner.conf "
def generate_openvpn_config (
local_ip = ' 10.1.0.2 ' ,
server_ip = ' 10.1.0.1 ' ,
server_hostname = ' example.com ' ,
udp_port = 1194 ,
vpn_secret_key = ' YOUR_VPN_SECRET_KEY '
) :
openvpn_config = f """ nobind
proto udp4
remote { server_hostname } { udp_port }
resolv - retry infinite
auth SHA256
cipher AES - 256 - CBC
dev { config . openvpn_forwarding_tun_device }
ifconfig { local_ip } { server_ip }
< secret >
- - - - - BEGIN OpenVPN Static key V1 - - - - -
{ vpn_secret_key }
- - - - - END OpenVPN Static key V1 - - - - -
< / secret >
fragment 1300
mssfix 1300
sndbuf 524288
rcvbuf 524288
user nobody
group nogroup
ping 15
ping - restart 45
ping - timer - rem
persist - tun
persist - key
verb 0 """
return openvpn_config
async def get_iptables_forward_rules ( ) :
code , stdout , stderr = await utils . async_run_command (
f " LC_ALL=C { ' sudo ' if config . run_iptables_with_sudo else ' ' } iptables -t nat -L PREROUTING -n -v --line-numbers "
)
rules = [ ]
if code == 0 :
collumns = [ ]
for idx , line in enumerate ( stdout . split ( ' \n ' ) ) :
if " num " in collumns and " target " in collumns and " in " in collumns :
items = line . split ( maxsplit = len ( collumns ) + 1 )
rule = { }
for idx , name in enumerate ( collumns ) :
rule [ name ] = items [ idx ]
rule [ " desc " ] = items [ len ( collumns ) + 1 ]
rules . append ( rule )
else :
collumns = line . split ( )
return rules
async def remove_iptables_rule ( rule_dict ) :
cmd = f " { ' sudo ' if config . run_iptables_with_sudo else ' ' } iptables "
if rule_dict . get ( ' target ' ) == ' DNAT ' :
cmd + = " -t nat "
cmd + = " -D PREROUTING "
if rule_dict . get ( ' prot ' ) and rule_dict [ ' prot ' ] != ' -- ' :
cmd + = f " -p { rule_dict [ ' prot ' ] } "
if rule_dict . get ( ' in ' ) and rule_dict [ ' in ' ] != ' * ' :
cmd + = f " -i { rule_dict [ ' in ' ] } "
if rule_dict . get ( ' out ' ) and rule_dict [ ' out ' ] != ' * ' :
cmd + = f " -o { rule_dict [ ' out ' ] } "
if rule_dict . get ( ' source ' ) and rule_dict [ ' source ' ] != ' 0.0.0.0/0 ' :
cmd + = f " -s { rule_dict [ ' source ' ] } "
if rule_dict . get ( ' destination ' ) and rule_dict [ ' destination ' ] != ' 0.0.0.0/0 ' :
cmd + = f " -d { rule_dict [ ' destination ' ] } "
if rule_dict . get ( ' target ' ) == ' DNAT ' :
if ' dports ' in rule_dict . get ( ' desc ' , ' ' ) :
port_info = rule_dict [ ' desc ' ] . split ( ' dports ' ) [ 1 ] . split ( ' ' ) [ 0 ]
if ' : ' in port_info :
cmd + = f " -m multiport --dports { port_info } "
else :
cmd + = f " --dport { port_info } "
if ' to: ' in rule_dict . get ( ' desc ' , ' ' ) :
dest_ip = rule_dict [ ' desc ' ] . split ( ' to: ' ) [ 1 ] . split ( ) [ 0 ]
cmd + = f " -j DNAT --to-destination { dest_ip } "
await utils . async_run_command ( cmd )
async def clore_partner_configure ( clore_partner_config ) :
try :
if clore_partner_config :
docker_restart_required = False
needed_openvpn_config = generate_openvpn_config (
local_ip = clore_partner_config [ " provider " ] ,
server_ip = clore_partner_config [ " forwarding " ] ,
server_hostname = clore_partner_config [ " openvpn_host " ] ,
udp_port = clore_partner_config [ " openvpn_port " ] ,
vpn_secret_key = clore_partner_config [ " secret " ]
)
2024-12-07 04:09:13 +00:00
saved_config = ' '
config_exists = await aiofiles . os . path . exists ( os . path . join ( CLIENT_CONFIGS_LOCATION , PARTNER_CONFIG_NAME ) )
if config_exists :
async with aiofiles . open ( os . path . join ( CLIENT_CONFIGS_LOCATION , PARTNER_CONFIG_NAME ) , mode = ' r ' ) as file :
saved_config = await file . read ( )
2024-12-02 00:06:53 +00:00
if saved_config != needed_openvpn_config :
async with aiofiles . open ( os . path . join ( CLIENT_CONFIGS_LOCATION , PARTNER_CONFIG_NAME ) , mode = ' w ' ) as file :
await file . write ( needed_openvpn_config )
is_active_code , is_active_stdout , is_active_stderr = await utils . async_run_command (
f " systemctl is-active openvpn-client@ { PARTNER_CONFIG_NAME . replace ( ' .conf ' , ' ' ) } "
)
if is_active_code == 0 and saved_config != needed_openvpn_config :
code , stdout , stderr = await utils . async_run_command (
f " systemctl restart openvpn-client@ { PARTNER_CONFIG_NAME . replace ( ' .conf ' , ' ' ) } "
)
docker_restart_required = False if code != 0 else True
elif is_active_code != 0 :
code , stdout , stderr = await utils . async_run_command (
f " systemctl start openvpn-client@ { PARTNER_CONFIG_NAME . replace ( ' .conf ' , ' ' ) } "
)
docker_restart_required = False if code != 0 else True
code , stdout , stderr = await utils . async_run_command (
f " { ' sudo ' if config . run_iptables_with_sudo else ' ' } ip route show table { str ( config . forwarding_ip_route_table_id ) } "
)
ip_route_configured = False
if code == 0 :
for line in stdout . split ( ' \n ' ) :
items = line . split ( ' ' )
if clore_partner_config [ " provider " ] in items and config . openvpn_forwarding_tun_device in items :
ip_route_configured = True
break
if not ip_route_configured :
code , stdout , stderr = await utils . async_run_command (
f " { ' sudo ' if config . run_iptables_with_sudo else ' ' } ip route add 0.0.0.0/0 dev { config . openvpn_forwarding_tun_device } src { clore_partner_config [ ' provider ' ] } table { config . forwarding_ip_route_table_id } && ip rule add from { clore_partner_config [ ' provider ' ] } table { config . forwarding_ip_route_table_id } "
)
ip_tables_configured = False
rules = await get_iptables_forward_rules ( )
for rule in rules :
try :
if rule [ " in " ] == config . openvpn_forwarding_tun_device and rule [ " target " ] . lower ( ) == " dnat " and f " { clore_partner_config [ ' ports ' ] [ 0 ] } : { clore_partner_config [ ' ports ' ] [ 1 ] } " in rule [ " desc " ] and f " to: { clore_partner_config [ ' provider ' ] } " in rule [ " desc " ] :
ip_tables_configured = True
elif rule [ " in " ] == config . openvpn_forwarding_tun_device and rule [ " target " ] . lower ( ) == " dnat " and " to:10. " in rule [ " desc " ] and " dports " in rule [ " desc " ] :
print ( " REMOVE RULE " , rule )
await remove_iptables_rule ( rule )
except Exception as ei :
log . error ( f " clore_partner_configure() | ei | { ei } " )
if ip_tables_configured == False :
code , stdout , stderr = await utils . async_run_command (
f " { ' sudo ' if config . run_iptables_with_sudo else ' ' } iptables -t nat -A PREROUTING -i { config . openvpn_forwarding_tun_device } -p tcp -m multiport --dports { clore_partner_config [ ' ports ' ] [ 0 ] } : { clore_partner_config [ ' ports ' ] [ 1 ] } -j DNAT --to-destination { clore_partner_config [ ' provider ' ] } && { ' sudo ' if config . run_iptables_with_sudo else ' ' } iptables -t nat -A PREROUTING -i { config . openvpn_forwarding_tun_device } -p udp -m multiport --dports { clore_partner_config [ ' ports ' ] [ 0 ] } : { clore_partner_config [ ' ports ' ] [ 1 ] } -j DNAT --to-destination { clore_partner_config [ ' provider ' ] } "
)
if docker_restart_required :
async with aiofiles . open ( config . restart_docker_flag_file , mode = ' w ' ) as file :
await file . write ( " " )
os . _exit ( 0 ) # We close clore hosting, because it's mandatory to restart docker after starting the up to date version of VPN, docker will be restarted on next start of clore hosting
else :
code , stdout , stderr = await utils . async_run_command (
f " systemctl stop openvpn-client@ { PARTNER_CONFIG_NAME . replace ( ' .conf ' , ' ' ) } "
)
return True
except Exception as e :
log . error ( f " FAIL | openvpn.clore_partner_configure | { e } " )
return False