# Copyright 2021 VyOS maintainers and contributors # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library. If not, see . import os import socket import sys import tempfile from ftplib import FTP import urllib.parse import urllib.request from vyos.util import cmd from paramiko import SSHClient def upload_ftp(local_path, hostname, remote_path,\ username='anonymous', password='', port=21, source=None): with open(local_path, 'rb') as file: with FTP(source_address=source) as conn: conn.connect(hostname, port) conn.login(username, password) conn.storbinary(f'STOR {remote_path}', file) def download_ftp(local_path, hostname, remote_path,\ username='anonymous', password='', port=21, source=None): with open(local_path, 'wb') as file: with FTP(source_address=source) as conn: conn.connect(hostname, port) conn.login(username, password) conn.retrbinary(f'RETR {remote_path}', file.write) def upload_sftp(local_path, hostname, remote_path,\ username=None, password=None, port=22, source=None): sock = None if source: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind((source, 0)) sock.connect((hostname, port)) with SSHClient() as ssh: ssh.load_system_host_keys() ssh.connect(hostname, port, username, password, sock=sock) with ssh.open_sftp() as sftp: sftp.put(local_path, remote_path) if sock: sock.shutdown() sock.close() def download_sftp(local_path, hostname, remote_path,\ username=None, password=None, port=22, source=None): sock = None if source: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind((source, 0)) sock.connect((hostname, port)) with SSHClient() as ssh: ssh.load_system_host_keys() ssh.connect(hostname, port, username, password, sock=sock) with ssh.open_sftp() as sftp: sftp.get(remote_path, local_path) if sock: sock.shutdown() sock.close() def upload_tftp(local_path, hostname, remote_path, port=69, source=None): source_option = f'--interface {source}' if source else '' with open(local_path, 'rb') as file: cmd(f'curl {source_option} -s -T - tftp://{hostname}:{port}/{remote_path}',\ stderr=None, input=file.read()).encode() def download_tftp(local_path, hostname, remote_path, port=69, source=None): source_option = f'--interface {source}' if source else '' with open(local_path, 'wb') as file: file.write(cmd(f'curl {source_option} -s tftp://{hostname}:{port}/{remote_path}',\ stderr=None).encode()) def download_http(urlstring, local_path): with open(local_path, 'wb') as file: with urllib.request.urlopen(urlstring) as response: file.write(response.read()) def download(local_path, urlstring, source=None): """ Dispatch the appropriate download function for the given URL and save to local path. """ url = urllib.parse.urlparse(urlstring) if url.scheme == 'http' or url.scheme == 'https': if source: print("Warning: Custom source address not supported for HTTP connections.", file=sys.stderr) download_http(urlstring, local_path) elif url.scheme == 'ftp': username = url.username if url.username else 'anonymous' download_ftp(local_path, url.hostname, url.path, username, url.password, source=source) elif url.scheme == 'sftp' or url.scheme == 'scp': download_sftp(local_path, url.hostname, url.path, url.username, url.password, source=source) elif url.scheme == 'tftp': download_tftp(local_path, url.hostname, url.path, source=source) else: raise ValueError(f'Unsupported URL scheme: {url.scheme}') def upload(local_path, urlstring, source=None): """ Dispatch the appropriate upload function for the given URL and upload from local path. """ url = urllib.parse.urlparse(urlstring) if url.scheme == 'ftp': username = url.username if url.username else 'anonymous' upload_ftp(local_path, url.hostname, url.path, username, url.password, source=source) elif url.scheme == 'sftp' or url.scheme == 'scp': upload_sftp(local_path, url.hostname, url.path, url.username, url.password, source=source) elif url.scheme == 'tftp': upload_tftp(local_path, url.hostname, url.path, source=source) else: raise ValueError(f'Unsupported URL scheme: {url.scheme}') def get_remote_config(urlstring): """ Download remote (config) file and return the contents. Args: remote file URI: scp://[:]@/ sftp://[:]@/ http:/// https:/// ftp://[[:]@]/ tftp:/// """ url = urllib.parse.urlparse(urlstring) temp = tempfile.NamedTemporaryFile(delete=False).name try: download(temp, urlstring) with open(temp, 'r') as file: return file.read() finally: os.remove(temp)