コード例 #1
0
ファイル: cmd_client.py プロジェクト: play-iot/iot-vpn
def __dns(vpn_opts: ClientOpts, nic: str, reason: str, new_nameservers: str,
          old_nameservers: str, debug: bool):
    logger.info(f'Discover DNS with {reason}::{nic}...')
    _reason = DHCPReason[reason]
    if not vpn_opts.is_vpn_nic(nic):
        logger.warn(f'NIC[{nic}] does not belong to VPN service')
        sys.exit(0)
    executor = VPNClientExecutor(
        vpn_opts, adhoc_task=True).require_install().probe(silent=True,
                                                           log_lvl=logger.INFO)
    current = executor.storage.get_current(info=True)
    if not current:
        current = executor.storage.find(executor.opts.nic_to_account(nic))
        if not current:
            logger.warn(f'Not found any VPN account')
            sys.exit(ErrorCode.VPN_ACCOUNT_NOT_FOUND)
    if executor.opts.nic_to_account(nic) != current.account:
        logger.warn(f'NIC[{nic}] does not meet current VPN account')
        sys.exit(ErrorCode.VPN_ACCOUNT_NOT_MATCH)
    if debug:
        now = datetime.now().isoformat()
        FileHelper.write_file(
            FileHelper.tmp_dir().joinpath('vpn_dns'),
            append=True,
            content=
            f"{now}::{reason}::{nic}::{new_nameservers}::{old_nameservers}\n")
    executor.device.dns_resolver.resolve(executor.vpn_service, _reason,
                                         current.hub, new_nameservers,
                                         old_nameservers)
コード例 #2
0
def __import(server_opts: ServerOpts, hub_password: str, vpn_opts: ToolOpts,
             group: str, certs_file: str, output_opts: OutputOpts):
    executor = VPNAuthExecutor(vpn_opts, server_opts, hub_password)
    data = JsonHelper.read(certs_file, strict=False)
    tmp_dir = FileHelper.tmp_dir('vpn_auth')
    command_file = FileHelper.touch(tmp_dir.joinpath('vpncmd.txt'))
    vpn_acc = {}
    for k, v in data.items():
        cert_file = tmp_dir.joinpath(f'{k}.cert')
        FileHelper.write_file(cert_file, v['cert_key'])
        commands = [
            f'CAAdd /{cert_file}',
            f'UserCreate {k} /GROUP:{group or "none"} /RealName:none /Note:none',
            f'UserSignedSet {k} /CN:{v["fqdn"]} /SERIAL:{v["serial_number"]}'
        ]
        vpn_acc[k] = {
            'vpn_server': server_opts.host,
            'vpn_port': server_opts.port,
            'vpn_hub': server_opts.hub,
            'vpn_account': server_opts.hub,
            'vpn_auth_type': 'cert',
            'vpn_user': k,
            'vpn_cert_key': v['cert_key'],
            'vpn_private_key': v['private_key'],
        }
        FileHelper.write_file(command_file,
                              '\n'.join(commands) + '\n',
                              append=True)
    executor.exec_command(f'/IN:{command_file}', log_lvl=logger.INFO)
    logger.sep(logger.INFO)
    out = output_opts.make_file(
        f'{server_opts.hub}-{output_opts.to_file("json")}')
    logger.info(f'Export VPN accounts to {out}...')
    JsonHelper.dump(out, vpn_acc)
    logger.done()
コード例 #3
0
ファイル: device_resolver.py プロジェクト: play-iot/iot-vpn
 def reset_hook(self, vpn_nameserver_hook_conf: Path):
     logger.info(f'Reset VPN DNS config file...')
     if FileHelper.is_writable(vpn_nameserver_hook_conf):
         FileHelper.write_file(vpn_nameserver_hook_conf,
                               mode=0o644,
                               content='')
         FileHelper.create_symlink(vpn_nameserver_hook_conf,
                                   self._dnsmasq_vpn_hook_cfg,
                                   force=True)
     else:
         FileHelper.rm(self._dnsmasq_vpn_hook_cfg)
コード例 #4
0
ファイル: device_resolver.py プロジェクト: play-iot/iot-vpn
 def update_hook(self, reason: DHCPReason, priv_root_dns: str,
                 nameservers: list, vpn_nameserver_hook_conf: Path):
     logger.info(
         f'Update VPN DNS config file on [{reason.name}][{priv_root_dns}] with nameservers {nameservers}...'
     )
     servers = '\n'.join(
         [f'server=/{priv_root_dns}/{ns}' for ns in nameservers])
     FileHelper.write_file(
         vpn_nameserver_hook_conf,
         mode=0o644,
         content=
         f'### Generated at [{datetime.now().isoformat()}]\n{servers}\n')
コード例 #5
0
ファイル: cmd_secret.py プロジェクト: play-iot/iot-vpn
def gen_intermediate_cert(cert_key, private_key, prefix, items, output_opts: OutputOpts,
                          cert_attributes: CertAttributes):
    """
    Generate an Intermediate Signed certificate
    """
    outputs = {}
    ca_crt, ca_pkey = __load_key(cert_key, private_key)
    for item in items:
        outputs[item] = __gen_cert(f'{prefix}.{item}', cert_attributes, ca_crt, ca_pkey)
        FileHelper.write_file(output_opts.make_file(f"{item}.key"), outputs[item]['private_key'])
        FileHelper.write_file(output_opts.make_file(f"{item}.crt"), outputs[item]['cert_key'])
    JsonHelper.dump(output_opts.make_file(f"signed-intermediate-{output_opts.file}.json"), outputs)
コード例 #6
0
ファイル: cmd_secret.py プロジェクト: play-iot/iot-vpn
def gen_ssh(users, output_opts: OutputOpts):
    """
    Generate SSH key
    """
    output = {}
    crypto_backend = crypto_default_backend()
    for user in users:
        ssh_key = rsa.generate_private_key(backend=crypto_backend, public_exponent=65537, key_size=4096)
        private_ssh_key = __serialize_private_key(ssh_key)
        public_ssh_key = ssh_key.public_key() \
            .public_bytes(crypto_serialization.Encoding.OpenSSH, crypto_serialization.PublicFormat.OpenSSH) \
            .decode(DEFAULT_ENCODING)
        output[user] = {'private_ssh_key': private_ssh_key, 'public_ssh_key': public_ssh_key}
        FileHelper.write_file(output_opts.make_file(user + "_ssh"), private_ssh_key)
        FileHelper.write_file(output_opts.make_file(user + "_ssh.pub"), public_ssh_key)

    JsonHelper.dump(output_opts.to_fqn_file(".json"), output)
コード例 #7
0
ファイル: device_resolver.py プロジェクト: play-iot/iot-vpn
 def setup(self, vpn_service: str, origin_resolv_conf: Path,
           vpn_resolv_conf: Path, vpn_nameserver_hook_conf: Path):
     if not self._available:
         logger.error('[dnsmasq] is not yet installed or is corrupted')
         sys.exit(ErrorCode.MISSING_REQUIREMENT)
     logger.info('Setup DNS resolver[dnsmasq]...')
     dnsmasq_vpn_cfg = self._dnsmasq_vpn_cfg(vpn_service)
     runtime_resolv_cfg = self.adapt_dnsmasq(origin_resolv_conf,
                                             vpn_service)
     dnsmasq_opts = {
         '{{DNS_RESOLVED_FILE}}':
         self.__build_dnsmasq_conf('resolv-file', runtime_resolv_cfg),
         '{{PORT}}':
         self.__build_dnsmasq_conf('port',
                                   self.dnsmasq_options().get('port',
                                                              None)),
         '{{CACHE_SIZE}}':
         self.__build_dnsmasq_conf(
             'cache-size',
             self.dnsmasq_options().get('cache_size', None))
     }
     logger.debug(
         f'Add [dnsmasq] config for {vpn_service}[{dnsmasq_vpn_cfg}]...')
     FileHelper.copy(self.resource_dir.joinpath(self.DNSMASQ_CONFIG_TMPL),
                     dnsmasq_vpn_cfg,
                     force=True)
     FileHelper.replace_in_file(dnsmasq_vpn_cfg, dnsmasq_opts, backup='')
     FileHelper.chmod(dnsmasq_vpn_cfg, mode=0o0644)
     logger.debug(
         f'Symlink [dnsmasq] VPN nameserver runtime configuration [{vpn_nameserver_hook_conf}]...'
     )
     FileHelper.create_symlink(vpn_nameserver_hook_conf,
                               self._dnsmasq_vpn_hook_cfg,
                               force=True)
     logger.info(f'Generate System DNS config file from VPN service...')
     FileHelper.write_file(vpn_resolv_conf,
                           self.__dnsmasq_resolv(vpn_service),
                           mode=0o0644)
     FileHelper.create_symlink(vpn_resolv_conf,
                               DNSResolver.DNS_SYSTEM_FILE,
                               force=True)
     self.service.enable(self.config.identity)
コード例 #8
0
ファイル: device_resolver.py プロジェクト: play-iot/iot-vpn
 def create_config(self, vpn_service: str, auto_connman_dhcp: bool):
     if self.is_connman():
         FileHelper.write_file(self.connman_dhcp, str(auto_connman_dhcp))
         return
     if not FileHelper.is_readable(self.origin_resolv_cfg):
         logger.info(
             f'Backup System DNS config file to [{self.origin_resolv_cfg}]...'
         )
         FileHelper.backup(DNSResolver.DNS_SYSTEM_FILE,
                           self.origin_resolv_cfg,
                           remove=False)
     if not FileHelper.is_readable(self.origin_resolv_cfg):
         logger.error(
             f'Not found origin DNS config file [{self.origin_resolv_cfg}]')
         sys.exit(ErrorCode.FILE_CORRUPTED)
     if not FileHelper.is_readable(self.vpn_hook_cfg):
         FileHelper.touch(self.vpn_hook_cfg, 0o0644)
     self._resolver().setup(vpn_service, self.origin_resolv_cfg,
                            self.vpn_resolv_cfg, self.vpn_hook_cfg)
     self._resolver().restart(_all=True)
コード例 #9
0
ファイル: cmd_secret.py プロジェクト: play-iot/iot-vpn
def gen_root_cert(output_opts: OutputOpts, cert_attributes: CertAttributes):
    """
    Generate Root Certification
    """
    crypto_backend = crypto_default_backend()
    algorithm = hashes.SHA512()
    now = datetime.datetime.utcnow()
    private_key = rsa.generate_private_key(public_exponent=65537, key_size=4096, backend=crypto_backend)
    subject = issuer = cert_attributes.create_x509_attributes()
    crt = x509.CertificateBuilder() \
        .subject_name(subject).issuer_name(issuer).public_key(private_key.public_key()) \
        .serial_number(x509.random_serial_number()).not_valid_before(now) \
        .not_valid_after(now + datetime.timedelta(days=cert_attributes.valid_days)) \
        .sign(private_key, algorithm, crypto_backend)
    root_private_key = __serialize_private_key(private_key)
    root_cert_key = crt.public_bytes(encoding=crypto_serialization.Encoding.PEM).decode(DEFAULT_ENCODING)
    output = {'private_key': root_private_key, 'cert_key': root_cert_key, 'serial_number': f'{crt.serial_number:0>40X}'}
    FileHelper.write_file(output_opts.to_fqn_file("key"), root_private_key)
    FileHelper.write_file(output_opts.to_fqn_file("crt"), root_cert_key)
    JsonHelper.dump(output_opts.to_fqn_file("json"), output)
コード例 #10
0
ファイル: cmd_secret.py プロジェクト: play-iot/iot-vpn
def gen_signed_cert(cert_key, private_key, intermediate_code: str, fn: str, items: list, dump_to_file: bool,
                    seq: bool, quantity: int, start_from: int, prefix: str, length: int,
                    output_opts: OutputOpts, cert_attributes: CertAttributes):
    """
    Generate Signed certificate
    """
    if not seq and not items:
        raise RuntimeError('Must provide singed certification name')
    if seq:
        if quantity <= 0 or start_from <= 0 or length <= 0:
            raise RuntimeError('Invalid value in sequence mode. All of [quantity, start_from, length] must be > 0')
        seq_format = f'0{length}d'
        items = [f'{prefix}{x:{seq_format}}' for x in range(start_from, start_from + quantity)]
    outputs = {}
    ca_crt, ca_pkey = __load_key(cert_key, private_key)
    for item in items:
        outputs[item] = __gen_cert(f'{item}.{fn}.{intermediate_code}', cert_attributes, ca_crt, ca_pkey)
        if dump_to_file:
            FileHelper.write_file(output_opts.make_file(f"{item}.key"), outputs[item]['private_key'])
            FileHelper.write_file(output_opts.make_file(f"{item}.crt"), outputs[item]['cert_key'])
    JsonHelper.dump(output_opts.make_file(f"{intermediate_code}-{output_opts.file}.json"), outputs)
コード例 #11
0
ファイル: opts_vpn.py プロジェクト: play-iot/iot-vpn
 def export_env(self):
     FileHelper.write_file(VpnDirectory.PROFILE_D_ENV, f'export {AppEnv.VPN_HOME_ENV}="{self.vpn_dir}"',
                           mode=0o0644)