Merge accepted SSL changes.

This commit is contained in:
Steve Haskew 2018-07-23 16:18:28 +01:00
commit 6ed57c7496
2 changed files with 36 additions and 7 deletions

View file

@ -9,20 +9,31 @@ from routeros_api import exceptions
from routeros_api import resource
def connect(host, username='admin', password='', port=8728, insecure_login=False):
return RouterOsApiPool(host, username, password, port, insecure_login).get_api()
def connect(host, username='admin', password='', port=None, insecure_login=False, use_ssl=False, ssl_verify=True, ssl_verify_hostname=True, ssl_context=None):
return RouterOsApiPool(host, username, password, port, insecure_login, use_ssl, ssl_verify, ssl_verify_hostname, ssl_context).get_api()
class RouterOsApiPool(object):
socket_timeout = 15.
socket_timeout = 15.0
def __init__(self, host, username='admin', password='', port=8728, insecure_login=False):
def __init__(self, host, username='admin', password='', port=None, insecure_login=False, use_ssl=False, ssl_verify=True, ssl_verify_hostname=True, ssl_context=None):
self.host = host
self.username = username
self.password = password
self.port = port
# Don't send the new-style login (can expose password in plaintext!)
self.insecure_login = insecure_login
self.ssl_context = ssl_context
# Use SSL? Ignored when using a context, so we will set it for simple reference when port-switching:
if ssl_context is not None:
self.use_ssl = True
else:
self.use_ssl = use_ssl
self.ssl_verify = ssl_verify
self.ssl_verify_hostname = ssl_verify_hostname
self.port = port or self._select_default_port(use_ssl)
self.connected = False
self.socket = api_socket.DummySocket()
self.communication_exception_parser = (
@ -31,7 +42,7 @@ class RouterOsApiPool(object):
def get_api(self):
if not self.connected:
self.socket = api_socket.get_socket(self.host, self.port,
timeout=self.socket_timeout)
timeout=self.socket_timeout, use_ssl=self.use_ssl, ssl_verify=self.ssl_verify, ssl_verify_hostname=self.ssl_verify_hostname, ssl_context=self.ssl_context)
base = base_api.Connection(self.socket)
communicator = api_communicator.ApiCommunicator(base)
self.api = RouterOsApi(communicator)
@ -54,6 +65,12 @@ class RouterOsApiPool(object):
yield CloseConnectionExceptionHandler(self)
yield self.communication_exception_parser
def _select_default_port(self, use_ssl):
if use_ssl:
return 8729
else:
return 8728
class RouterOsApi(object):
def __init__(self, communicator):

View file

@ -1,4 +1,5 @@
import socket
import ssl
from routeros_api import exceptions
try:
import errno
@ -7,7 +8,7 @@ except ImportError:
EINTR = getattr(errno, 'EINTR', 4)
def get_socket(hostname, port, timeout=15.0):
def get_socket(hostname, port, use_ssl=False, ssl_verify=True, ssl_verify_hostname=True, ssl_context=None, timeout=15.0):
api_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
api_socket.settimeout(timeout)
while True:
@ -19,6 +20,17 @@ def get_socket(hostname, port, timeout=15.0):
else:
break
set_keepalive(api_socket, after_idle_sec=10)
# A provided ssl_context overrides any options
if ssl_context is None and use_ssl:
ssl_context = ssl.create_default_context()
if ssl_verify:
ssl_context.check_hostname = ssl_verify_hostname
ssl_context.verify_mode = ssl.CERT_REQUIRED
else:
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
if ssl_context is not None:
api_socket = ssl_context.wrap_socket(api_socket,server_hostname=hostname)
return SocketWrapper(api_socket)
# http://stackoverflow.com/a/14855726