Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

vpngen.py 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. import glob
  2. import json
  3. import os
  4. import os.path
  5. import re
  6. import shutil
  7. from enum import Enum
  8. from subprocess import call
  9. class VpnGenError(Enum):
  10. Success = 0,
  11. VpnAlreadyExists = 1,
  12. VpnDoesNotExists = 2,
  13. ClientAlreadyExists = 3,
  14. ClientDoesNotExists = 4
  15. class VpnGen:
  16. default_config_base_dir = ""
  17. default_config_file = ""
  18. default_client_config_file = ""
  19. ovpn_config_path = ""
  20. def __init__(self, default_config_path, ovpn_config_path):
  21. self.default_config_base_dir = os.path.abspath(default_config_path)
  22. self.default_config_file = "%s.conf" % self.default_config_base_dir
  23. self.default_client_config_file = "%s%sclients%sclient.conf" % (self.default_config_base_dir, os.sep, os.sep)
  24. self.ovpn_config_path = os.path.abspath(ovpn_config_path)
  25. def f7(self, seq):
  26. seen = set()
  27. seen_add = seen.add
  28. return [x for x in seq if not (x in seen or seen_add(x))]
  29. def get_vpn_vars(self):
  30. with open(self.default_config_file, "r") as f:
  31. default_config = f.read()
  32. variables = re.findall('\$\{([^}]+)}', default_config)
  33. variables += ["KEY_COUNTRY", "KEY_PROVINCE", "KEY_CITY", "KEY_ORG", "KEY_EMAIL"]
  34. variables = self.f7(variables)
  35. return variables
  36. def get_client_vars(self, vpn_name):
  37. default_client_config_path = self.get_client_default_config_path(vpn_name)
  38. if not os.path.exists(default_client_config_path):
  39. return None
  40. with open(default_client_config_path, "r") as f:
  41. default_config = f.read()
  42. variables = re.findall('\$\{([^}]+)}', default_config)
  43. variables = self.f7(variables)
  44. vpn_variables = self.get_vpn_vars()
  45. real_variables = []
  46. for var in variables:
  47. if var not in vpn_variables and var != "client":
  48. real_variables.append(var)
  49. return real_variables
  50. def get_base_dir(self, vpn_name):
  51. return "%s%s%s%s" % (self.ovpn_config_path, os.sep, vpn_name, os.sep)
  52. def get_config_path(self, vpn_name):
  53. return "%s%s%s.conf" % (self.ovpn_config_path, os.sep, vpn_name)
  54. def get_vpn_variables_path(self, vpn_name):
  55. base_dir = self.get_base_dir(vpn_name)
  56. return "%svpngen.json" % base_dir
  57. def get_easy_rsa_dir(self, vpn_name):
  58. base_dir = self.get_base_dir(vpn_name)
  59. return "%seasy-rsa%s" % (base_dir, os.sep)
  60. def get_easy_rsa_key_dir(self, vpn_name):
  61. easyrsadir = self.get_easy_rsa_dir(vpn_name)
  62. return "%skeys%s" % (easyrsadir, os.sep)
  63. def get_pkitool_path(self, vpn_name):
  64. easyrsadir = self.get_easy_rsa_dir(vpn_name)
  65. return "%spkitool" % easyrsadir
  66. def get_client_default_config_path(self, vpn_name):
  67. base_dir = self.get_base_dir(vpn_name)
  68. return "%s%sclients%sclient.conf" % (base_dir, os.sep, os.sep)
  69. def get_client_dir(self, vpn_name, client_name):
  70. base_dir = self.get_base_dir(vpn_name)
  71. return "%sclients%s%s-%s%s" % (base_dir, os.sep, client_name, vpn_name, os.sep)
  72. def get_client_config_path(self, vpn_name, client_name):
  73. client_dir = self.get_client_dir(vpn_name, client_name)
  74. return "%s%s-%s.conf" % (client_dir, client_name, vpn_name)
  75. def get_client_variables_path(self, vpn_name, client_name):
  76. client_dir = self.get_client_dir(vpn_name, client_name)
  77. return "%svpngen.json" % client_dir
  78. def get_client_generated_files_paths(self, vpn_name, client_name):
  79. keys_dir = self.get_easy_rsa_key_dir(vpn_name,)
  80. return [
  81. "%s%s.crt" % (keys_dir, client_name),
  82. "%s%s.key" % (keys_dir, client_name)
  83. ]
  84. def get_client_tarball_path(self, vpn_name, client_name):
  85. base_dir = self.get_base_dir(vpn_name)
  86. return "%sclients%s%s-%s.tar.bz2" % (base_dir, os.sep, client_name, vpn_name)
  87. def get_server_needed_files_paths(self, vpn_name):
  88. keys_dir = self.get_easy_rsa_key_dir(vpn_name)
  89. return [
  90. "%sca.crt" % keys_dir,
  91. "%sta.key" % keys_dir
  92. ]
  93. def get_client_misc_files_paths(self, vpn_name):
  94. base_dir = self.get_base_dir(vpn_name)
  95. return glob.glob("%smisc-files%s*" % (base_dir, os.sep))
  96. def get_all_needed_files_paths(self, vpn_name, client_name):
  97. return self.get_client_generated_files_paths(vpn_name, client_name) +\
  98. self.get_server_needed_files_paths(vpn_name) +\
  99. self.get_client_misc_files_paths(vpn_name)
  100. def get_server_variables(self, vpn_name):
  101. with open(self.get_vpn_variables_path(vpn_name), "r") as f:
  102. return json.load(f)['variables']
  103. def get_client_variables(self, vpn_name, client_name):
  104. with open(self.get_client_variables_path(vpn_name, client_name), "r") as f:
  105. return json.load(f)['variables']
  106. def setup_vars(self, vpn_name, variables):
  107. easyrsadir = self.get_easy_rsa_dir(vpn_name)
  108. os.environ["KEY_COUNTRY"] = variables['KEY_COUNTRY']
  109. os.environ["KEY_PROVINCE"] = variables['KEY_PROVINCE']
  110. os.environ["KEY_CITY"] = variables['KEY_CITY']
  111. os.environ["KEY_ORG"] = variables['KEY_ORG']
  112. os.environ["KEY_OU"] = variables['KEY_ORG']
  113. os.environ["KEY_CN"] = variables['KEY_ORG']
  114. os.environ["KEY_NAME"] = variables['KEY_ORG']
  115. os.environ["KEY_EMAIL"] = variables['KEY_EMAIL']
  116. os.environ["KEY_SIZE"] = variables['KEY_SIZE']
  117. os.environ["CA_EXPIRE"] = variables['CA_EXPIRE']
  118. os.environ["KEY_EXPIRE"] = variables['KEY_EXPIRE']
  119. os.environ["EASY_RSA"] = easyrsadir
  120. os.environ["OPENSSL"] = "openssl"
  121. os.environ["PKCS11TOOL"] = "pkcs11-tool"
  122. os.environ["GREP"] = "grep"
  123. os.environ["KEY_CONFIG"] = "%s%s" % (easyrsadir, "openssl.cnf")
  124. os.environ["KEY_DIR"] = "%s%s" % (easyrsadir, "keys")
  125. os.environ["PKCS11_MODULE_PATH"] = "dummy"
  126. os.environ["PKCS11_PIN"] = "dummy"
  127. def create_vpn(self, vpn_name, variables):
  128. base_dir = self.get_base_dir(vpn_name)
  129. conf_file = self.get_config_path(vpn_name)
  130. conf_vpngen_file = self.get_vpn_variables_path(vpn_name)
  131. if os.path.exists(base_dir) or os.path.exists(conf_file):
  132. return VpnGenError.VpnAlreadyExists
  133. with open(self.default_config_file, "r") as f:
  134. default_config = f.read()
  135. variables['name'] = vpn_name
  136. for variable in variables:
  137. default_config = default_config.replace("${%s}" % variable, variables[variable])
  138. os.makedirs(base_dir)
  139. with open(conf_file, "w") as f:
  140. f.write(default_config)
  141. os.rmdir(base_dir)
  142. shutil.copytree(self.default_config_base_dir, base_dir)
  143. curdir = os.curdir
  144. easyrsadir = self.get_easy_rsa_dir(vpn_name)
  145. pkitool = self.get_pkitool_path(vpn_name)
  146. os.chdir(easyrsadir)
  147. self.setup_vars(vpn_name, variables)
  148. call([".%sclean-all" % os.sep])
  149. call([pkitool, "--initca", "-batch"])
  150. call([pkitool, "--server", "server", "-batch"])
  151. call([".%sbuild-dh" % os.sep])
  152. call(["openssl", "ca", "-gencrl",
  153. "-keyfile", "keys%sca.key" % os.sep,
  154. "-cert", "keys%sca.crt" % os.sep,
  155. "-out", "keys%scrl.pem" % os.sep,
  156. "-config", "openssl.cnf"])
  157. del os.environ["KEY_OU"]
  158. del os.environ["KEY_CN"]
  159. del os.environ["KEY_NAME"]
  160. call(["openvpn", "--genkey", "--secret", "keys%sta.key" % os.sep])
  161. with open(conf_vpngen_file, "w") as f:
  162. json.dump({'variables': variables}, f, indent=4, separators=(',', ': '))
  163. os.chdir(curdir)
  164. return VpnGenError.Success
  165. def remove_vpn(self, vpn_name):
  166. base_dir = self.get_base_dir(vpn_name)
  167. conf_file = self.get_config_path(vpn_name)
  168. if not os.path.exists(base_dir) and not os.path.exists(conf_file):
  169. return VpnGenError.VpnDoesNotExists
  170. os.remove(conf_file)
  171. shutil.rmtree(base_dir)
  172. return VpnGenError.Success
  173. def create_client(self, vpn_name, client_name, variables):
  174. base_dir = self.get_base_dir(vpn_name)
  175. if not os.path.exists(base_dir):
  176. return VpnGenError.VpnDoesNotExists
  177. client_dir = self.get_client_dir(vpn_name, client_name)
  178. if os.path.exists(client_dir):
  179. return VpnGenError.ClientAlreadyExists
  180. curdir = os.curdir
  181. easyrsadir = self.get_easy_rsa_dir(vpn_name)
  182. pkitool = self.get_pkitool_path(vpn_name)
  183. os.chdir(easyrsadir)
  184. self.setup_vars(vpn_name, variables)
  185. os.environ["KEY_CN"] = client_name
  186. os.environ["KEY_NAME"] = client_name
  187. call([pkitool, client_name])
  188. os.chdir(curdir)
  189. os.makedirs(client_dir)
  190. return self.rebuild_client(vpn_name, client_name, variables)
  191. def remove_client(self, vpn_name, client_name):
  192. base_dir = self.get_base_dir(vpn_name)
  193. if not os.path.exists(base_dir):
  194. return VpnGenError.VpnDoesNotExists
  195. client_dir = self.get_client_dir(vpn_name, client_name)
  196. if not os.path.exists(client_dir):
  197. return VpnGenError.ClientDoesNotExists
  198. return VpnGenError.Success
  199. def rebuild_client(self, vpn_name, client_name, variables):
  200. client_dir = self.get_client_dir(vpn_name, client_name)
  201. client_conf_file = self.get_client_config_path(vpn_name, client_name)
  202. client_default_config_path = self.get_client_default_config_path(vpn_name)
  203. with open(client_default_config_path, "r") as f:
  204. client_default_config = f.read()
  205. for variable in variables:
  206. client_default_config = client_default_config.replace("${%s}" % variable, variables[variable])
  207. files_names = glob.glob("%s%s*" % (client_dir, os.sep))
  208. for file_name in files_names:
  209. os.remove(file_name)
  210. with open(client_conf_file, "w") as f:
  211. f.write(client_default_config)
  212. files_paths = self.get_all_needed_files_paths(vpn_name, client_name)
  213. for file_path in files_paths:
  214. split = os.path.splitext(file_path)
  215. dest = "%s%s-%s%s" % (client_dir, os.path.basename(split[0]), vpn_name, split[1])
  216. shutil.copy(file_path, dest)
  217. split = os.path.splitext(client_conf_file)
  218. client_ovpn_file = "%s.ovpn" % split[0]
  219. shutil.copy(client_conf_file, client_ovpn_file)
  220. files_names = glob.glob("%s%s*" % (client_dir, os.sep))
  221. files_names = list(map(lambda file_path: os.path.basename(file_path), files_names))
  222. call(["tar", "cfj", self.get_client_tarball_path(vpn_name, client_name),
  223. "-C", client_dir] + files_names)
  224. client_variables = {}
  225. for variable in self.get_client_vars(vpn_name):
  226. client_variables[variable] = variables[variable]
  227. with open(self.get_client_variables_path(vpn_name, client_name), "w") as f:
  228. json.dump({'variables': client_variables}, f, indent=4, separators=(',', ': '))
  229. return VpnGenError.Success