def writeDefaultUpFile(): p = getPlatform() if p == platforms.LINUX or p == platforms.RPI: infoTrace("vpnproviders.py", "Writing default up script") up = open(getAddonPath(True, "up.sh"), 'w') up.write("#!/bin/bash\n") up.write("iptables -F\n") up.write("iptables -A INPUT -i tun0 -m state --state ESTABLISHED,RELATED -j ACCEPT\n") up.write("iptables -A INPUT -i tun0 -j DROP\n") up.close() command = "chmod +x " + getAddonPath(True, "up.sh") if useSudo(): command = "sudo " + command infoTrace("vpnproviders.py", "Fixing default up.sh " + command) os.system(command)
def getTemplateFile(vpn_provider): def_temp = getAddonPath(True, vpn_provider + "/TEMPLATE.txt") user_temp = getUserDataPath(vpn_provider + "/TEMPLATE.txt") if xbmcvfs.exists(user_temp): return user_temp else: return def_temp
def copyUserDefinedFiles(): # Copy everything in the user directory to the addon directory infoTrace("vpnproviders.py", "Copying user defined files from userdata directory") source_path = getUserDataPath((user_def_str) + "/") dest_path = getAddonPath(True, user_def_str + "/") # Get the list of connection profiles and another list of strings to abuse for the selection screen try: files = getUserDataList(user_def_str, "*") if len(files) == 0: errorTrace( "vpnproviders.py", "No User Defined files available to copy from " + source_path) return False for file in files: name = file[file.rfind(getSeparator()) + 1:] dest_file = dest_path + getSeparator() + name xbmcvfs.copy(file, dest_file) if not xbmcvfs.exists(dest_file): raise IOError('Failed to copy user def file ' + file + " to " + dest_file) return True except Exception as e: errorTrace( "vpnproviders.py", "Error copying files from " + source_path + " to " + dest_path) errorTrace("vpnproviders.py", str(e)) return False
def getLocationFiles(vpn_provider): # Return the locations files, add any user version to the end of the list locations = glob.glob(getAddonPath(True, vpn_provider + "/LOCATIONS*.txt")) user_locations = getUserDataPath(vpn_provider + "/LOCATIONS.txt") if xbmcvfs.exists(user_locations): locations.append(user_locations.replace(".txt", " User.txt")) return locations
def getBestPathWrapper(name): # This function will return the path to the user version of a given file # if it exists, otherwise it'll return the path the default add-on version # This is just about resetting the ovpn documents if neccesary filename = getUserDataPath(name) if not xbmcvfs.exists(filename): filename = getAddonPath(True, name) else: infoTrace("vpnprovider.py", "Using userdata override " + filename) if getPlatform() == platforms.WINDOWS: return filename.replace("\\", "\\\\") else: return filename
def populateSupportingFromGit(vpn_provider): # Copy all files from download to the directory that are not .ovpn, ignoring the metadata try: filelist = getDownloadList(vpn_provider, "*") debugTrace("Copying supporting files into addon directory for " + vpn_provider) for file in filelist: if not file.endswith(".ovpn") and not file.endswith("METADATA.txt"): name = os.path.basename(file) fullname = getAddonPath(True, vpn_provider + "/" + name) xbmcvfs.copy(file, fullname) if not xbmcvfs.exists(fullname): raise IOError('Failed to copy supporting file ' + file + " to " + fullname) return True except Exception as e: errorTrace("vpnproviders.py", "Can't copy " + file + " for VPN " + vpn_provider) errorTrace("vpnproviders.py", str(e)) return False
def copyUserDefinedFiles(): # Copy everything in the user directory to the addon directory infoTrace("vpnproviders.py", "Copying user defined files from userdata directory") source_path = getUserDataPath((user_def_str)+"/") dest_path = getAddonPath(True, user_def_str + "/") # Get the list of connection profiles and another list of strings to abuse for the selection screen try: files = getUserDataList(user_def_str, "*") if len(files) == 0: errorTrace("vpnproviders.py", "No User Defined files available to copy from " + source_path) return False for file in files: name = file[file.rfind(getSeparator())+1:] dest_file = dest_path + getSeparator() + name xbmcvfs.copy(file, dest_file) if not xbmcvfs.exists(dest_file): raise IOError('Failed to copy user def file ' + file + " to " + dest_file) return True except Exception as e: errorTrace("vpnproviders.py", "Error copying files from " + source_path + " to " + dest_path) errorTrace("vpnproviders.py", str(e)) return False
def generateOVPNFiles(vpn_provider, alternative_locations_name): # Generate the OVPN files for a VPN provider using the template and update with location info infoTrace( "vpnproviders.py", "Generating OVPN files for " + vpn_provider + " using list " + alternative_locations_name) # See if there's a port override going on addon = xbmcaddon.Addon("service.vpn.manager") if addon.getSetting("default_udp") == "true": portUDP = "" else: portUDP = addon.getSetting("alternative_udp_port") if addon.getSetting("default_tcp") == "true": portTCP = "" else: portTCP = addon.getSetting("alternative_tcp_port") # Get the logging level verb_value = addon.getSetting("openvpn_verb") if verb_value == "": verb_value = "1" addon.setSetting("openvpn_verb", verb_value) # Load ovpn template try: template_path = getTemplateFile(vpn_provider) debugTrace("Opening template file " + template_path) template_file = open(template_path, 'r') template = template_file.readlines() template_file.close() except Exception as e: errorTrace("vpnproviders.py", "Couldn't open the template file for " + vpn_provider) errorTrace("vpnproviders.py", str(e)) return False # Open a translate file try: debugTrace("Opening translate file for " + vpn_provider) translate_file = open( getAddonPath(True, vpn_provider + "/TRANSLATE.txt"), 'w') debugTrace("Opened translate file for " + vpn_provider) except Exception as e: errorTrace("vpnproviders.py", "Couldn't open the translate file for " + vpn_provider) errorTrace("vpnproviders.py", str(e)) return False if getPlatform() == platforms.WINDOWS and addon.getSetting( "block_outside_dns") == "true": template.append("block-outside-dns") if addon.getSetting("force_ping") == "true": template.append("ping #PINGSPEED") template.append("ping-exit #PINGEXIT") template.append("ping-timer-rem") if addon.getSetting("up_down_script") == "true": template.append("script-security 2") template.append(getUpParam(vpn_provider)) template.append(getDownParam(vpn_provider)) # Load locations file if not alternative_locations_name == "": if alternative_locations_name == "User": locations_name = getUserDataPath(vpn_provider + "/LOCATIONS.txt") else: locations_name = getAddonPath( True, vpn_provider + "/LOCATIONS " + alternative_locations_name + ".txt") else: locations_name = getAddonPath(True, vpn_provider + "/LOCATIONS.txt") try: debugTrace("Opening locations file for " + vpn_provider + "\n" + locations_name) locations_file = open(locations_name, 'r') debugTrace("Opened locations file for " + vpn_provider) locations = locations_file.readlines() locations_file.close() except Exception as e: errorTrace( "vpnproviders.py", "Couldn't open the locations file for " + vpn_provider + "\n" + locations_name) errorTrace("vpnproviders.py", str(e)) translate_file.close() return False # For each location, generate an OVPN file using the template for location in locations: try: location_values = location.split(",") geo = location_values[0] servers = location_values[1].split() proto = location_values[2] ports = (location_values[3].strip(' \t\n\r')).split() port = "" # Initialise the set of values that can be modified by the location file tuples ca_cert = "ca.crt" ta_key = "ta.key" crl_pem = "crl.pem" dh_parm = "dh.pem" user1 = "" user2 = "" user_key = getUserDataPathWrapper(vpn_provider + "/" + getKeyName(vpn_provider, geo)) user_cert = getUserDataPathWrapper(vpn_provider + "/" + getCertName(vpn_provider, geo)) user_pass = getUserDataPathWrapper( vpn_provider + "/" + getKeyPassName(vpn_provider, geo)) remove_flags = "" if proto == "udp": ping_speed = "5" ping_exit = "30" else: ping_speed = "10" ping_exit = "60" if len(location_values) > 4: # The final location value is a list of multiple x=y declarations. # These need to be parsed out and modified. modifier_tuples = (location_values[4].strip(' \t\n\r')).split() # Loop through all of the values splitting them into name value pairs for modifier in modifier_tuples: pair = modifier.split("=") if "#CERT" in pair[0]: ca_cert = pair[1].strip() if "#REMOVE" in pair[0]: remove_flags = pair[1].strip() if "#TLSKEY" in pair[0]: ta_key = pair[1].strip() if "#USERKEY" in pair[0]: user_key = pair[1].strip() if "#USERCERT" in pair[0]: user_cert = pair[1].strip() if "#USERPASS" in pair[0]: user_pass = pair[1].strip() if "#CRLVERIFY" in pair[0]: crl_pem = pair[1].strip() if "#DH" in pair[0]: dh_parm = pair[1].strip() if "#USER1" in pair[0]: user1 = pair[1].strip() if "#USER2" in pair[0]: user2 = pair[1].strip() if "#PINGSPEED" in pair[0]: ping_speed = pair[1].strip() if "#PINGEXIT" in pair[0]: ping_exit = pair[1].strip() if proto == "udp" and not portUDP == "": port = portUDP if proto == "tcp" and not portTCP == "": port = portTCP if port == "" and len(ports) == 1: port = ports[0] except Exception as e: errorTrace( "vpnproviders.py", "Location file for " + vpn_provider + " invalid on line\n" + location) errorTrace("vpnproviders.py", str(e)) translate_file.close() return False try: ovpn_file = open( getAddonPath(True, vpn_provider + "/" + geo + ".ovpn"), 'w') translate_location = geo if proto == "tcp": servprot = "tcp-client" else: servprot = proto # Do a replace on the tags in the template with data from the location file for line in template: output_line = line.strip(' \t\n\r') # Must check to see if there's a remove tag on the line before looking for other tags if "#REMOVE" in output_line: if output_line[output_line.index("#REMOVE") + 7] in remove_flags: # Remove the line if it's a flag this location doesn't care about output_line = "" else: # Delete the tag if this location doesn't want this line removed output_line = output_line.replace( "#REMOVE" + output_line[output_line.index("#REMOVE") + 7], "") output_line = output_line.replace("#PROTO", proto) output_line = output_line.replace("#SERVPROT", servprot) # If there are multiple servers then we'll need to duplicate the server # line (which starts with 'remote ') and fix the server. The rest of the # code will deal with the port which is the same for all lines (although # this assumption might not be true for all VPN providers...) if output_line.startswith("remote "): server_template = output_line server_lines = "" i = 0 for server in servers: if i == 0: translate_server = server if not server_lines == "": server_lines = server_lines + "\n" server_lines = server_lines + server_template.replace( "#SERVER", server) if port == "": server_lines = server_lines.replace( "#PORT", ports[i]) i = i + 1 if i > 1: translate_server = translate_server + " & " + str( i - 1) + " more" output_line = server_lines # There might be other places we use server and port, so still the do the replace output_line = output_line.replace("#SERVER", servers[0]) output_line = output_line.replace("#PORT", port) # Pass is always generated by the add-on so will be in the addon directory if "#PASS" in output_line: output_line = output_line.replace( "#PASS", getAddonPathWrapper(vpn_provider + "/" + "pass.txt")) # These flags are files that can be over ridden in the user data directory if "#CERT" in output_line: output_line = output_line.replace( "#CERT", getBestPathWrapper(vpn_provider + "/" + ca_cert)) if "#TLSKEY" in output_line: output_line = output_line.replace( "#TLSKEY", getBestPathWrapper(vpn_provider + "/" + ta_key)) if "#CRLVERIFY" in output_line: output_line = output_line.replace( "#CRLVERIFY", getBestPathWrapper(vpn_provider + "/" + crl_pem)) if "#DH" in output_line: output_line = output_line.replace( "#DH", getBestPathWrapper(vpn_provider + "/" + dh_parm)) # User files are managed by the add-on so will be in the user directory (set above) output_line = output_line.replace("#USERKEY", user_key) output_line = output_line.replace("#USERCERT", user_cert) output_line = output_line.replace("#USERPASS", user_pass) # Path is the add-on path, not the user directory if "#PATH" in output_line: output_line = output_line.replace( "#PATH", getAddonPathWrapper(vpn_provider + "/")) output_line = output_line.replace("#USER1", user1) output_line = output_line.replace("#USER2", user2) output_line = output_line.replace("#PINGSPEED", ping_speed) output_line = output_line.replace("#PINGEXIT", ping_exit) # Overwrite the verb value with the one in the settings if output_line.startswith("verb "): output_line = "verb " + verb_value # This is a little hack to remove a tag that doesn't work with TCP but is needed for UDP # Could do this with a #REMOVE, but doing it here is less error prone. if "explicit-exit-notify" in line and proto == "tcp": output_line = "" if not output_line == "": ovpn_file.write(output_line + "\n") ovpn_file.close() debugTrace("Wrote location " + geo + " " + proto) translate_file.write(translate_location + "," + translate_server + " (" + proto.upper() + ")\n") except Exception as e: errorTrace( "vpnproviders.py", "Can't write a location file for " + vpn_provider + " failed on line\n" + location) errorTrace("vpnproviders.py", str(e)) translate_file.close() return False # Write the location to server translation file translate_file.close() # Flag that the files have been generated writeGeneratedFile(vpn_provider) return True
def updateVPNFiles(vpn_provider): # If the OVPN files aren't generated then they need to be updated with location info infoTrace("vpnproviders.py", "Updating VPN profiles for " + vpn_provider) # Get the list of VPN profile files if isUserDefined(vpn_provider): ovpn_connections = getAddonList(vpn_provider, "*.ovpn") else: ovpn_connections = getDownloadList(vpn_provider, "*.ovpn") # See if there's a port override going on addon = xbmcaddon.Addon("service.vpn.manager") if addon.getSetting("default_udp") == "true": portUDP = "" else: portUDP = addon.getSetting("alternative_udp_port") if addon.getSetting("default_tcp") == "true": portTCP = "" else: portTCP = addon.getSetting("alternative_tcp_port") # Get the logging level verb_value = addon.getSetting("openvpn_verb") if verb_value == "": verb_value = "1" addon.setSetting("openvpn_verb", verb_value) # Open a translate file try: debugTrace("Opening translate file for " + vpn_provider) translate_file = open( getAddonPath(True, vpn_provider + "/TRANSLATE.txt"), 'w') debugTrace("Opened translate file for " + vpn_provider) except Exception as e: errorTrace("vpnproviders.py", "Couldn't open the translate file for " + vpn_provider) errorTrace("vpnproviders.py", str(e)) return False for connection in ovpn_connections: try: f = open(connection, 'r') debugTrace("Processing file " + connection) lines = f.readlines() f.close() if isUserDefined(vpn_provider): f = open(connection, 'w') else: f = open( getAddonPath( True, vpn_provider + "/" + os.path.basename(connection)), 'w') # Get the profile friendly name in case we need to generate key/cert names name = connection[connection.rfind(getSeparator()) + 1:connection.rfind(".ovpn")] translate_location = name translate_server = "" server_count = 0 found_up = False found_down = False found_script_sec = False found_block_dns = False found_ping = False proto = "udp" # Update the necessary values in the ovpn file for line in lines: line = line.strip(' \t\n\r') # Update path to pass.txt if not isUserDefined(vpn_provider) or addon.getSetting( "user_def_credentials") == "true": if line.startswith("auth-user-pass"): line = "auth-user-pass " + getAddonPathWrapper( vpn_provider + "/" + "pass.txt") # Update port numbers if line.startswith("remote "): server_count += 1 tokens = line.split() port = "" for newline in lines: if newline.startswith("proto "): if "tcp" in newline: proto = "tcp" if not portTCP == "": port = portTCP break if "udp" in newline: proto = "udp" if not portUDP == "": port = portUDP break if not port == "": line = "remote " + tokens[1] + " " + port + "\n" if translate_server == "": translate_server = tokens[1] # Update user cert and key if not isUserDefined(vpn_provider) and usesUserKeys( vpn_provider): if line.startswith("cert "): line = "cert " + getUserDataPathWrapper( vpn_provider + "/" + getCertName(vpn_provider, name)) if line.startswith("key "): line = "key " + getUserDataPathWrapper( vpn_provider + "/" + getKeyName(vpn_provider, name)) # Update key password (if there is one) if not isUserDefined(vpn_provider) or usesKeyPass( vpn_provider): if line.startswith("askpass"): line = "askpass " + getUserDataPathWrapper( vpn_provider + "/" + getKeyPass(vpn_provider)) # For user defined profile we need to replace any path tags with the addon dir path if isUserDefined(vpn_provider): line = line.replace("#PATH", getAddonPathWrapper(vpn_provider)) # Set the logging level if line.startswith("verb "): line = "verb " + verb_value if line.startswith("up "): found_up = True if line.startswith("down "): found_down = True if line.startswith("script-security "): found_script_sec = True if line.startswith("block-outside-dns"): found_block_dns = True if line.startswith("ping"): found_ping = True f.write(line + "\n") if not found_block_dns and getPlatform( ) == platforms.WINDOWS and addon.getSetting( "block_outside_dns") == "true": f.write("block-outside-dns\n") if addon.getSetting("up_down_script") == "true": if not found_script_sec: f.write("script-security 2\n") if not found_up: f.write(getUpParam(vpn_provider) + "\n") if not found_down: f.write(getDownParam(vpn_provider) + "\n") if not found_ping and addon.getSetting("force_ping") == "true": if proto == "tcp": f.write("ping 10\n") f.write("ping-exit 60\n") else: f.write("ping 5\n") f.write("ping-exit 30\n") f.write("ping-timer-rem\n") f.close() if server_count > 1: translate_server = translate_server + " & " + str( server_count - 1) + " more" translate_file.write(translate_location + "," + translate_server + " (" + proto.upper() + ")\n") except Exception as e: errorTrace("vpnproviders.py", "Failed to update ovpn file") errorTrace("vpnproviders.py", str(e)) translate_file.close() return False # Write the location to server translation file translate_file.close() # Flag that the files have been generated writeGeneratedFile(vpn_provider) return True
def cleanGeneratedFiles(): # Delete the GENERATED.txt file from all of the VPN provider directorys for provider in providers: filename = getAddonPath(True, provider + "/GENERATED.txt") if xbmcvfs.exists(filename) : xbmcvfs.delete(filename)
def cleanPassFiles(): # Delete the pass.txt file from all of the VPN provider directorys for provider in providers: filename = getAddonPath(True, provider + "/pass.txt") if xbmcvfs.exists(filename) : xbmcvfs.delete(filename)
def ovpnFilesAvailable(vpn_provider): if xbmcvfs.exists(getAddonPath(True, vpn_provider + "/GENERATED.txt")): return True return False
def ovpnGenerated(vpn_provider): if isUserDefined(vpn_provider): return True if xbmcvfs.exists(getAddonPath(True, vpn_provider + "/TEMPLATE.txt")): return True return False
def cleanPassFiles(): # Delete the pass.txt file from all of the VPN provider directorys for provider in providers: filename = getAddonPath(True, provider + "/pass.txt") if xbmcvfs.exists(filename): xbmcvfs.delete(filename)
def updateVPNFiles(vpn_provider): # If the OVPN files aren't generated then they need to be updated with location info infoTrace("vpnproviders.py", "Updating VPN profiles for " + vpn_provider) # Get the list of VPN profile files if isUserDefined(vpn_provider): ovpn_connections = getAddonList(vpn_provider, "*.ovpn") else: ovpn_connections = getDownloadList(vpn_provider, "*.ovpn") # See if there's a port override going on addon = xbmcaddon.Addon("service.vpn.manager") if addon.getSetting("default_udp") == "true": portUDP = "" else: portUDP = addon.getSetting("alternative_udp_port") if addon.getSetting("default_tcp") == "true": portTCP = "" else: portTCP = addon.getSetting("alternative_tcp_port") # Get the logging level verb_value = addon.getSetting("openvpn_verb") if verb_value == "": verb_value = "1" addon.setSetting("openvpn_verb", verb_value) # Open a translate file try: debugTrace("Opening translate file for " + vpn_provider) translate_file = open(getAddonPath(True, vpn_provider + "/TRANSLATE.txt"), 'w') debugTrace("Opened translate file for " + vpn_provider) except Exception as e: errorTrace("vpnproviders.py", "Couldn't open the translate file for " + vpn_provider) errorTrace("vpnproviders.py", str(e)) return False for connection in ovpn_connections: try: f = open(connection, 'r') debugTrace("Processing file " + connection) lines = f.readlines() f.close() if isUserDefined(vpn_provider): f = open(connection, 'w') else: f = open(getAddonPath(True, vpn_provider + "/" + os.path.basename(connection)), 'w') # Get the profile friendly name in case we need to generate key/cert names name = connection[connection.rfind(getSeparator())+1:connection.rfind(".ovpn")] translate_location = name translate_server = "" server_count = 0 found_up = False found_down = False found_script_sec = False found_block_dns = False found_ping = False found_verb = False proto = "udp" # Update the necessary values in the ovpn file for line in lines: line = line.strip(' \t\n\r') # Update path to pass.txt if not isUserDefined(vpn_provider) or addon.getSetting("user_def_credentials") == "true": if line.startswith("auth-user-pass"): line = "auth-user-pass " + getAddonPathWrapper(vpn_provider + "/" + "pass.txt") # Update port numbers if line.startswith("remote "): server_count += 1 tokens = line.split() port = "" for newline in lines: if newline.startswith("proto "): if "tcp" in newline: proto = "tcp" if not portTCP == "": port = portTCP break if "udp" in newline: proto = "udp" if not portUDP == "": port = portUDP break if not port == "": line = "remote " + tokens[1] + " " + port + "\n" if translate_server == "": translate_server = tokens[1] # Update user cert and key if not isUserDefined(vpn_provider) and usesUserKeys(vpn_provider): if line.startswith("cert "): line = "cert " + getUserDataPathWrapper(vpn_provider + "/" + getCertName(vpn_provider, name)) if line.startswith("key "): line = "key " + getUserDataPathWrapper(vpn_provider + "/" + getKeyName(vpn_provider, name)) # Update key password (if there is one) if not isUserDefined(vpn_provider) or usesKeyPass(vpn_provider): if line.startswith("askpass"): line = "askpass " + getUserDataPathWrapper(vpn_provider + "/" + getKeyPass(vpn_provider)) # For user defined profile we need to replace any path tags with the addon dir path if isUserDefined(vpn_provider): line = line.replace("#PATH", getAddonPathWrapper(vpn_provider)) # Set the logging level if line.startswith("verb "): line = "verb " + verb_value found_verb = True if line.startswith("up "): found_up = True if line.startswith("down "): found_down = True if line.startswith("script-security "): found_script_sec = True if line.startswith("block-outside-dns"): found_block_dns = True if line.startswith("ping"): found_ping = True f.write(line + "\n") if not found_block_dns and getPlatform() == platforms.WINDOWS and addon.getSetting("block_outside_dns") == "true": f.write("block-outside-dns\n") if addon.getSetting("up_down_script") == "true": if not found_script_sec: f.write("script-security 2\n") if not found_up: f.write(getUpParam(vpn_provider)+"\n") if not found_down: f.write(getDownParam(vpn_provider)+"\n") if not found_ping and addon.getSetting("force_ping") == "true": if proto == "tcp": f.write("ping 10\n") f.write("ping-exit 60\n") else: f.write("ping 5\n") f.write("ping-exit 30\n") f.write("ping-timer-rem\n") if not found_verb: f.write("verb " + verb_value + "\n") f.close() if server_count > 1: translate_server = translate_server + " & " + str(server_count - 1) + " more" translate_file.write(translate_location + "," + translate_server + " (" + proto.upper() + ")\n") except Exception as e: errorTrace("vpnproviders.py", "Failed to update ovpn file") errorTrace("vpnproviders.py", str(e)) translate_file.close() return False # Write the location to server translation file translate_file.close() # Flag that the files have been generated writeGeneratedFile(vpn_provider) return True
def getAddonList(vpn_provider, filter): # Return the list of ovpn files for a given provider (aka directory name...) path = getAddonPath(True, getVPNLocation(vpn_provider) + "/" + filter) debugTrace("Getting list of profiles in " + path) return sorted(glob.glob(path))
def getAddonPathWrapper(name): # Return the fully qualified add-on path and file name if getPlatform() == platforms.WINDOWS: return getAddonPath(True, name).replace("\\", "\\\\") else: return getAddonPath(True, name)
def cleanGeneratedFiles(): # Delete the GENERATED.txt file from all of the VPN provider directorys for provider in providers: filename = getAddonPath(True, provider + "/GENERATED.txt") if xbmcvfs.exists(filename): xbmcvfs.delete(filename)
def generateOVPNFiles(vpn_provider, alternative_locations_name): # Generate the OVPN files for a VPN provider using the template and update with location info infoTrace("vpnproviders.py", "Generating OVPN files for " + vpn_provider + " using list " + alternative_locations_name) # See if there's a port override going on addon = xbmcaddon.Addon("service.vpn.manager") if addon.getSetting("default_udp") == "true": portUDP = "" else: portUDP = addon.getSetting("alternative_udp_port") if addon.getSetting("default_tcp") == "true": portTCP = "" else: portTCP = addon.getSetting("alternative_tcp_port") # Get the logging level verb_value = addon.getSetting("openvpn_verb") if verb_value == "": verb_value = "1" addon.setSetting("openvpn_verb", verb_value) # Load ovpn template try: template_path = getTemplateFile(vpn_provider) debugTrace("Opening template file " + template_path) template_file = open(template_path, 'r') template = template_file.readlines() template_file.close() except Exception as e: errorTrace("vpnproviders.py", "Couldn't open the template file for " + vpn_provider) errorTrace("vpnproviders.py", str(e)) return False # Open a translate file try: debugTrace("Opening translate file for " + vpn_provider) translate_file = open(getAddonPath(True, vpn_provider + "/TRANSLATE.txt"), 'w') debugTrace("Opened translate file for " + vpn_provider) except Exception as e: errorTrace("vpnproviders.py", "Couldn't open the translate file for " + vpn_provider) errorTrace("vpnproviders.py", str(e)) return False if getPlatform() == platforms.WINDOWS and addon.getSetting("block_outside_dns") == "true": template.append("block-outside-dns") if addon.getSetting("force_ping") == "true": template.append("ping #PINGSPEED") template.append("ping-exit #PINGEXIT") template.append("ping-timer-rem") if addon.getSetting("up_down_script") == "true": template.append("script-security 2") template.append(getUpParam(vpn_provider)) template.append(getDownParam(vpn_provider)) # Load locations file if not alternative_locations_name == "": if alternative_locations_name == "User": locations_name = getUserDataPath(vpn_provider + "/LOCATIONS.txt") else: locations_name = getAddonPath(True, vpn_provider + "/LOCATIONS " + alternative_locations_name + ".txt") else: locations_name = getAddonPath(True, vpn_provider + "/LOCATIONS.txt") try: debugTrace("Opening locations file for " + vpn_provider + "\n" + locations_name) locations_file = open(locations_name, 'r') debugTrace("Opened locations file for " + vpn_provider) locations = locations_file.readlines() locations_file.close() except Exception as e: errorTrace("vpnproviders.py", "Couldn't open the locations file for " + vpn_provider + "\n" + locations_name) errorTrace("vpnproviders.py", str(e)) translate_file.close() return False # For each location, generate an OVPN file using the template for location in locations: try: location_values = location.split(",") geo = location_values[0] servers = location_values[1].split() proto = location_values[2] ports = (location_values[3].strip(' \t\n\r')).split() port = "" # Initialise the set of values that can be modified by the location file tuples ca_cert = "ca.crt" ta_key = "ta.key" crl_pem = "crl.pem" dh_parm = "dh.pem" user1 = "" user2 = "" user_key = getUserDataPathWrapper(vpn_provider + "/" + getKeyName(vpn_provider, geo)) user_cert = getUserDataPathWrapper(vpn_provider + "/" + getCertName(vpn_provider, geo)) user_pass = getUserDataPathWrapper(vpn_provider + "/" + getKeyPassName(vpn_provider, geo)) remove_flags = "" if proto == "udp": ping_speed = "5" ping_exit = "30" else: ping_speed = "10" ping_exit = "60" if len(location_values) > 4: # The final location value is a list of multiple x=y declarations. # These need to be parsed out and modified. modifier_tuples = (location_values[4].strip(' \t\n\r')).split() # Loop through all of the values splitting them into name value pairs for modifier in modifier_tuples: pair = modifier.split("=") if "#CERT" in pair[0]: ca_cert = pair[1].strip() if "#REMOVE" in pair[0]: remove_flags = pair[1].strip() if "#TLSKEY" in pair[0]: ta_key = pair[1].strip() if "#USERKEY" in pair[0]: user_key = pair[1].strip() if "#USERCERT" in pair[0]: user_cert = pair[1].strip() if "#USERPASS" in pair[0]: user_pass = pair[1].strip() if "#CRLVERIFY" in pair[0]: crl_pem = pair[1].strip() if "#DH" in pair[0]: dh_parm = pair[1].strip() if "#USER1" in pair[0]: user1 = pair[1].strip() if "#USER2" in pair[0]: user2 = pair[1].strip() if "#PINGSPEED" in pair[0]: ping_speed = pair[1].strip() if "#PINGEXIT" in pair[0]: ping_exit = pair[1].strip() if proto == "udp" and not portUDP == "": port = portUDP if proto == "tcp" and not portTCP == "": port = portTCP if port == "" and len(ports) == 1: port = ports[0] except Exception as e: errorTrace("vpnproviders.py", "Location file for " + vpn_provider + " invalid on line\n" + location) errorTrace("vpnproviders.py", str(e)) translate_file.close() return False try: ovpn_file = open(getAddonPath(True, vpn_provider + "/" + geo + ".ovpn"), 'w') translate_location = geo if proto == "tcp": servprot = "tcp-client" else: servprot = proto # Do a replace on the tags in the template with data from the location file for line in template: output_line = line.strip(' \t\n\r') # Must check to see if there's a remove tag on the line before looking for other tags if "#REMOVE" in output_line: if output_line[output_line.index("#REMOVE")+7] in remove_flags: # Remove the line if it's a flag this location doesn't care about output_line = "" else: # Delete the tag if this location doesn't want this line removed output_line = output_line.replace("#REMOVE" + output_line[output_line.index("#REMOVE")+7], "") output_line = output_line.replace("#PROTO", proto) output_line = output_line.replace("#SERVPROT", servprot) # If there are multiple servers then we'll need to duplicate the server # line (which starts with 'remote ') and fix the server. The rest of the # code will deal with the port which is the same for all lines (although # this assumption might not be true for all VPN providers...) if output_line.startswith("remote "): server_template = output_line server_lines = "" i = 0 for server in servers: if i == 0: translate_server = server if not server_lines == "" : server_lines = server_lines + "\n" server_lines = server_lines + server_template.replace("#SERVER", server) if port == "": server_lines = server_lines.replace("#PORT", ports[i]) i = i + 1 if i > 1: translate_server = translate_server + " & " + str(i - 1) + " more" output_line = server_lines # There might be other places we use server and port, so still the do the replace output_line = output_line.replace("#SERVER", servers[0]) output_line = output_line.replace("#PORT", port) # Pass is always generated by the add-on so will be in the addon directory if "#PASS" in output_line: output_line = output_line.replace("#PASS", getAddonPathWrapper(vpn_provider + "/" + "pass.txt")) # These flags are files that can be over ridden in the user data directory if "#CERT" in output_line: output_line = output_line.replace("#CERT", getBestPathWrapper(vpn_provider + "/" + ca_cert)) if "#TLSKEY" in output_line: output_line = output_line.replace("#TLSKEY", getBestPathWrapper(vpn_provider + "/" + ta_key)) if "#CRLVERIFY" in output_line: output_line = output_line.replace("#CRLVERIFY", getBestPathWrapper(vpn_provider + "/" + crl_pem)) if "#DH" in output_line: output_line = output_line.replace("#DH", getBestPathWrapper(vpn_provider + "/" + dh_parm)) # User files are managed by the add-on so will be in the user directory (set above) output_line = output_line.replace("#USERKEY", user_key) output_line = output_line.replace("#USERCERT", user_cert) output_line = output_line.replace("#USERPASS", user_pass) # Path is the add-on path, not the user directory if "#PATH" in output_line: output_line = output_line.replace("#PATH", getAddonPathWrapper(vpn_provider + "/")) output_line = output_line.replace("#USER1", user1) output_line = output_line.replace("#USER2", user2) output_line = output_line.replace("#PINGSPEED", ping_speed) output_line = output_line.replace("#PINGEXIT", ping_exit) # Overwrite the verb value with the one in the settings if output_line.startswith("verb "): output_line = "verb " + verb_value # This is a little hack to remove a tag that doesn't work with TCP but is needed for UDP # Could do this with a #REMOVE, but doing it here is less error prone. if "explicit-exit-notify" in line and proto == "tcp": output_line = "" if not output_line == "" : ovpn_file.write(output_line + "\n") ovpn_file.close() debugTrace("Wrote location " + geo + " " + proto) translate_file.write(translate_location + "," + translate_server + " (" + proto.upper() + ")\n") except Exception as e: errorTrace("vpnproviders.py", "Can't write a location file for " + vpn_provider + " failed on line\n" + location) errorTrace("vpnproviders.py", str(e)) translate_file.close() return False # Write the location to server translation file translate_file.close() # Flag that the files have been generated writeGeneratedFile(vpn_provider) return True
def writeGeneratedFile(vpn_provider): # Write a file to indicate successful generation of the ovpn files ovpn_file = open(getAddonPath(True, vpn_provider + "/GENERATED.txt"), 'w') ovpn_file.close()