# Datagram Transport Layer Security for Python
PyDTLS brings Datagram Transport Layer Security (DTLS - RFC 6347:
http://tools.ietf.org/html/rfc6347) to the Python environment. In a
nutshell, DTLS brings security (encryption, server authentication,
user authentication, and message authentication) to UDP datagram
payloads in a manner equivalent to what SSL/TLS does for TCP stream
content.
DTLS is now very easy to use in Python. If you're familiar with the
ssl module in Python's standard library, you already know how. All it
takes is passing a datagram/UDP socket to the *wrap_socket* function
instead of a stream/TCP socket. Here's how one sets up the client side
of a connection:
```
import ssl
from socket import socket, AF_INET, SOCK_DGRAM
from dtls import do_patch
do_patch()
sock = ssl.wrap_socket(socket(AF_INET, SOCK_DGRAM))
sock.connect(('foo.bar.com', 1234))
sock.send('Hi there')
```
As of version 1.3.0, PyDTLS supports DTLS version 1.2 in addition to
version 1.0. This version also introduces forward secrecy using
elliptic curve cryptography and more fine-grained configuration options.
## Installation
To install from PyPI, on any supported platform enter:
```
pip install python3-dtls
```
## Design Goals
The primary design goal of PyDTLS is broad availability. It has therefore
been built to be widely compatible with the following:
* Operating systems: apart from the Python standard library, PyDTLS
relies on the OpenSSL library only. OpenSSL is widely ported, and
in fact the Python standard library's *ssl* module also uses it.
* Python runtime environments: PyDTLS is a package consisting of
pure Python modules only. It should therefore be portable to many
interpreters and runtime environments. It interfaces with OpenSSL
strictly through the standard library's *ctypes* foreign function
library.
* The Python standard library: the standard library's *ssl* module is
Python's de facto interface to SSL/TLS. PyDTLS aims to be compatible
with the full public interface presented by this module. The ssl
module ought to behave identically with respect to all of its
functions and options when used in conjunction with PyDTLS and
datagram sockets as when used without PyDTLS and stream sockets.
* Connection-based protocols: as outlined below, layering security
on top of datagram sockets requires introducing certain
connection constructs normally absent from datagram
sockets. These constructs have been added in such a way as to be
compatible with code that expects to interoperate with
connection-oriented stream sockets. For example, code that
expects to go through server-side bind/listen/accept connection
establishment should be reusable with PyDTLS sockets.
## Distributions
PyDTLS requires version 1.1.1 or higher of the OpenSSL
library. Since packaged distributions of this version of OpenSSL are
available for many popular operating systems, OpenSSL-1.1.1 is an
installation requirement before PyDTLS functionality can be called.
In comparison, installation of OpenSSL on Microsoft Windows operating
systems is inconvenient. For this reason, source distributions of
PyDTLS are available that include OpenSSL dll's for 32-bit and 64-bit
Windows. All dll's have been linked with the Visual Studio 2015
version of the Microsoft C runtime library, msvcr90.dll, the version
used by CPython 3.6. Installation of Microsoft redistributable runtime
packages should therefore not be required on machines with CPython
3.6.
The OpenSSL version used by PyDTLS can be determined from the values
of *sslconnection's* DTLS_OPENSSL_VERSION_NUMBER,
DTLS_OPENSSL_VERSION, and DTLS_OPENSSL_VERSION_INFO. These variables
are available through the *ssl* module also if *do_patch* has been
called (see below). Note that the OpenSSL version used by PyDTLS may
differ from the one used by the *ssl* module.
## Interfaces
PyDTLS' top-level package, *dtls*, provides DTLS support through the
**SSLConnection** class of its *sslconnection*
module. **SSLConnection** is in-line documented, and
dtls/test/echo_seq.py demonstrates how to take a simple echo server
through a listen/accept/echo/shutdown sequence using this class. The
corresponding client side can look like the snippet at the top of this
document, followed by a call to the *unwrap* method for shutdown (or a
call to the **SSLConnection** *shutdown* method, if an instance of
this class is used for the client side also). Note that the *dtls*
package does not depend on the standard library's *ssl* module, and
**SSLConnection** can therefore be used in environments where *ssl* is
unavailable or incompatible.
It is expected that with the *ssl* module being an established, familiar
interface to TLS, it will be the preferred module through which to
access DTLS. To do so, one must call the *dtls* package's *do_patch*
function before passing sockets of type SOCK_DGRAM to either *ssl's*
*wrap_socket* function, or *ssl's* **SSLSocket** constructor.
It should be noted that once *do_patch* is called, *dtls* will raise
exceptions of type **ssl.SSLError** instead of its default
**dtls.err.SSLError**. This allows users' error handling code paths to
remain identical when interfacing with *ssl* across stream and
datagram sockets.
## Connection Handling
The DTLS protocol implies a connection as an association between two
network peers where the overall association state is characterized by the
handshake status of each peer endpoint (see RFC 6347). The OpenSSL library
records this handshake status in "SSL" type instances (a.k.a. struct
ssl_st). Datagrams can be securely sent and received by referring to a
unique "SSL" instance after handshaking has been completed with this
instance and its network peer. A connection is implied in that traffic
may be directed to or received from only that network peer with whose
"SSL" instance the handshake has been completed. The fact that the
underlying network protocol, UDP in most cases, is itself connectionless
is immaterial.
Further, in order to prevent denial-of-service attacks on UDP DTLS
servers, clients must undergo a cookie exchange phase early in the
handshaking protocol, and before server-side resources are committed to
a particular client (see section 4.2.1 of RFC 6347). The cookie exchange
proves to the server that a client can indeed receive IP traffic at
the source IP address with which its handshake-initiating ClientHello
datagram is marked.
PyDTLS implements this connection establishment through the *connect*
method on the client side, and the *accept* method on the server side.
The latter returns a new **dtls.SSLConnection** or **ssl.SSLSocket**
object (depending on which interface is used, see above), which is
"connected" to its peer. In addition to the *read* and *write* methods
(at both interface levels), **SSLSocket's** *send* and *recv* methods
can be used; use of *sendto* and *recvfrom* on connected sockets is
prohibited by *ssl*. *accept* returns peer address information, as
expected. Note that when using the *ssl* interface to *dtls*, *listen*
must be called before calling *accept*.
## Demultiplexing
At the network io layer, only datagrams from its connected peer must be
passed to a **SSLConnection** or **SSLSocket** object (unless the object
is unconnected on the server-side, in which case it can be in listening
mode, the initial server-side socket whose role it is to listen for
incoming client connection requests).
The initial server-side listening socket is not useful for performing this
datagram routing function. This is because it must remain unconnected and
ready to receive additional connection requests from new, unknown clients.
The function of passing incoming datagrams to the proper connection is
performed by the *dtls.demux* package. **SSLConnection** requests a new
connection from the demux when a handshake has cleared the cookie
exchange phase. An efficient implementation of this request is provided
by the *osnet* module of the demux package: it creates a new socket that
is bound to the same network interface and port as the listening socket,
but connected to the peer. UDP stacks such as the one included with Linux
route incoming datagrams to such a connected socket in preference to an
unconnected socket bound to the same port.
Unfortunately such is not the behavior on Microsoft Windows. Windows
UDP routes datagrams to whichever currently existing socket bound to
the particular port the earliest (and whether or not that socket is
unconnected, or connected to the datagram's peer, or a different
peer). Other sockets bound to the same port will not receive traffic,
if and until they become the earliest bound socket because another
socket is closed.
The demux package therefore provides and automatically selects the module
*router* on Windows platforms. This module also creates a new socket when
receiving a new connection request; but instead of binding this socket
to the same port as the listening socket, it binds to a new ephemeral
port. *router* then forwards datagrams originating from the peer for which
a connection was requested to the corresponding socket.
For efficiency's sake, no forwarding is performed on outgoing traffic.
Instead, **SSLConnection** directs outgoing traffic from the original
listening socket, using *sendto*. At the OpenSSL level this requires
separate read and write datagram BIO's for an "SSL" instance, one in
"connected" state and one in "peer set" state, respectively, and
associated with two separate network sockets.
From the perspective of a PyDTLS user, this selection of and
difference between demux implementations should be transparent, with
the possible exception of performance deviation. This transparency
does however have some limits: for example, when *router* is in use,
the *accept* methods can return *None*. This happens when
**SSLConnection** detects that the demux has forwarded a datagram to a
known connection instead of initiating a connection to a new peer
through *accept*. Returning *None* in this case is important whenever
non-blocking sockets or sockets with timeouts are used, since another
socket might now be readable as a result of the forwarded
datagram. *accept* must return so that the application can iterate on
its asynchronous *select* loop.
## Shutdown and Unwrapping
PyDTLS implements the SSL/TLS shutdown protocol as it has been adapted
for DTLS. **SSLConnection's** *shutdown* and **SSLSocket's** *unwrap*
invoke this protocol. As is the case with DTLS handshaking in general,
applications must be prepared to use the *get_timeout* and
*handle_timeout* methods in addition to re-invoking *shutdown* or
*unwrap* when sockets become readable and an exception carried
SSL_ERROR_WANT_READ. (See more on asynchronous IO in the Testing section.)
**SSLConnection's** *shutdown* and **SSLSocket's** *unwrap* return a
(possibly new) socket that can be used for unsecured communication
with the peer, as set forth by the *ssl* module. The demux
infrastructure remains in use for this communication until the
returned socket is cleaned up. Note that when the *router* demux is
in use, the object returned will be one derived from
*socket.socket*. This is because the send and recv paths must still be
directed to two different OS sockets. In addition, the right thing
happens if secured communication is resumed over such a socket by
passing it to *ssl.wrap_socket* or the **SSLConnection**
constructor. If *osnet* is used, an actual *socket.socket* instance is
returned.
## Framework Compatibility
PyDTLS sockets have been tested under the following usage modes:
* Using blocking sockets and sockets with timeouts in
multi-threaded UDP servers
* Using non-blocking sockets, and in conjunction with the
asynchronous socket handler, asyncore
* Using blocking sockets, and in conjunction with the network
server framework SocketServer - ThreadingTCPServer (this works
because of PyDTLS's emulation of connection-related calls)
## Multi-thread Support
Using multiple threads with OpenSSL requires implementing a locking
callback. PyDTLS does implement this, and therefore multi-threaded
programming with PyDTLS is safe in any environment. However, being a
pure Python library, these callbacks do carry some overhead. The *ssl*
module implements an equivalent locking callback in its C extension
module. Not requiring interpreter re-entry, this approach can be
expected to perform better. PyDTLS therefore queries OpenSSL as to
whether a locking callback is already in place, and does not overwrite
it if there is. Loading *ssl* can therefore improve performance, even
when only the *sslconnection* interface is used.
Note that loading order does not matter: to obtain the performance
benefit, *ssl* can be loaded before or after the dtls package. This is
because *ssl* does not do an equivalent existing locking callback
check, and will simply overwrite the PyDTLS callback if it has already
been installed. But *ssl* should not be loaded while *dtls* operation
is already in progress, when some locks may be in their acquired
state.
Also note that this performance enhancement is available only on
platforms where PyDTLS loads the same OpenSSL shared object as
*ssl*. On Ubuntu 12.04, for example, this is the case, but on
Microsoft Windows it is not.
## Testing
A simple echo server is available to be executed from the project root
directory with `python3 -m dtls.test.echo_seq`. The echo server is
reachable using the code snippet at the top of this document, using port
28000 at "localhost".
Unit test suites can be executed from the project root directory with
`python3 -m dtls.test.unit [-v]` and `python3 -m dtls.test.unit_wrapper`
(for the client and server wrappers)
Almost all of the Python standard library's *ssl* unit tests from the
module *test_ssl.py* have been ported to *dtls.test.unit.py*. All tests
have been adjusted to operate with datagram sockets. On Linux, each
test is executed four times, varying the address family among IPv4 and
IPv6 and the demux among *osnet* and *router*. On Windows, where
*osnet* is unavailable, each test is run twice, once with IPv4 and once
with IPv6.
The unit test suite includes tests for each of the above-mentioned
compatible frameworks. The class **AsyncoreEchoServer** serves as an
example of how to use non-blocking datagram sockets and implement the
resulting timeout detection requirements. DTLS in general and OpenSSL
in particular require being called back when used with non-blocking
sockets (or sockets with timeout option) after DTLS timeouts expire to
handle packet loss using re-transmission during a
handshake. Handshaking may occur during any read or write operation,
even after an initial handshake completes successfully, in case
renegotiation is requested by a peer.
Running with the -v switch executes all unit tests in verbose mode.
dtls/test/test_perf.py implements an interactive performance test
suite that compares the raw throughput of TCP, UDP, SSL, and DTLS.
It can be executed locally through the loopback interface, or between
remote clients and servers. In the latter case, test jobs are sent to
remote connected clients whenever a suite run is initiated through the
interactive interface. Run test_perf.py -h for more information.
It should be noted that comparing the performance of protocols that
don't offer congestion control (UDP and DTLS) with those that do (TCP
and SSL) is a difficult undertaking. Raw throughput even across
gigabit network links can be expected to suffer without congestion
control and peers that generate data as fast as possible without
throttling (as this test does): the link's throughput will drop
significantly as it enters congestion collapse. Similarly, loopback is
an imperfect test interface since it rarely drops packets, and never
duplicates or reorders them (thus negating the relative performance
benefits of DTLS over SSL). Nevertheless, some useful insights can be
gained by observing the operation of test_perf.py, including software
stack behavior in the presence of some amount of packet loss.
## Logging
The *dtls* package and its sub-packages log various occurrences,
primarily events that can aid debugging. Especially *router* emits many
messages when the logging level is set to at least *logging.DEBUG*.
dtls/test/echo_seq.py activates this logging level during its operation.
Raw data
{
"_id": null,
"home_page": "https://github.com/mcfreis/pydtls",
"name": "python3-dtls",
"maintainer": "Bjorn Freise",
"docs_url": null,
"requires_python": "",
"maintainer_email": "mcfreis@gmx.net",
"keywords": "",
"author": "Ray Brown",
"author_email": "code@liquibits.com",
"download_url": "",
"platform": "",
"description": "# Datagram Transport Layer Security for Python\n\nPyDTLS brings Datagram Transport Layer Security (DTLS - RFC 6347:\nhttp://tools.ietf.org/html/rfc6347) to the Python environment. In a\nnutshell, DTLS brings security (encryption, server authentication,\nuser authentication, and message authentication) to UDP datagram\npayloads in a manner equivalent to what SSL/TLS does for TCP stream\ncontent.\n\nDTLS is now very easy to use in Python. If you're familiar with the\nssl module in Python's standard library, you already know how. All it\ntakes is passing a datagram/UDP socket to the *wrap_socket* function\ninstead of a stream/TCP socket. Here's how one sets up the client side\nof a connection:\n\n```\nimport ssl\nfrom socket import socket, AF_INET, SOCK_DGRAM\nfrom dtls import do_patch\ndo_patch()\nsock = ssl.wrap_socket(socket(AF_INET, SOCK_DGRAM))\nsock.connect(('foo.bar.com', 1234))\nsock.send('Hi there')\n```\n\nAs of version 1.3.0, PyDTLS supports DTLS version 1.2 in addition to\nversion 1.0. This version also introduces forward secrecy using\nelliptic curve cryptography and more fine-grained configuration options.\n\n## Installation\n\nTo install from PyPI, on any supported platform enter:\n\n```\npip install python3-dtls\n```\n\n## Design Goals\n\nThe primary design goal of PyDTLS is broad availability. It has therefore\nbeen built to be widely compatible with the following:\n\n * Operating systems: apart from the Python standard library, PyDTLS\n relies on the OpenSSL library only. OpenSSL is widely ported, and\n in fact the Python standard library's *ssl* module also uses it.\n * Python runtime environments: PyDTLS is a package consisting of\n pure Python modules only. It should therefore be portable to many\n interpreters and runtime environments. It interfaces with OpenSSL\n strictly through the standard library's *ctypes* foreign function\n library.\n * The Python standard library: the standard library's *ssl* module is\n Python's de facto interface to SSL/TLS. PyDTLS aims to be compatible\n with the full public interface presented by this module. The ssl\n module ought to behave identically with respect to all of its\n functions and options when used in conjunction with PyDTLS and\n datagram sockets as when used without PyDTLS and stream sockets.\n * Connection-based protocols: as outlined below, layering security\n on top of datagram sockets requires introducing certain\n connection constructs normally absent from datagram\n sockets. These constructs have been added in such a way as to be\n compatible with code that expects to interoperate with\n connection-oriented stream sockets. For example, code that\n expects to go through server-side bind/listen/accept connection\n establishment should be reusable with PyDTLS sockets.\n\n## Distributions\n\nPyDTLS requires version 1.1.1 or higher of the OpenSSL\nlibrary. Since packaged distributions of this version of OpenSSL are\navailable for many popular operating systems, OpenSSL-1.1.1 is an\ninstallation requirement before PyDTLS functionality can be called.\n\nIn comparison, installation of OpenSSL on Microsoft Windows operating\nsystems is inconvenient. For this reason, source distributions of\nPyDTLS are available that include OpenSSL dll's for 32-bit and 64-bit\nWindows. All dll's have been linked with the Visual Studio 2015\nversion of the Microsoft C runtime library, msvcr90.dll, the version\nused by CPython 3.6. Installation of Microsoft redistributable runtime\npackages should therefore not be required on machines with CPython\n3.6.\n\nThe OpenSSL version used by PyDTLS can be determined from the values\nof *sslconnection's* DTLS_OPENSSL_VERSION_NUMBER,\nDTLS_OPENSSL_VERSION, and DTLS_OPENSSL_VERSION_INFO. These variables\nare available through the *ssl* module also if *do_patch* has been\ncalled (see below). Note that the OpenSSL version used by PyDTLS may\ndiffer from the one used by the *ssl* module.\n\n## Interfaces\n\nPyDTLS' top-level package, *dtls*, provides DTLS support through the\n**SSLConnection** class of its *sslconnection*\nmodule. **SSLConnection** is in-line documented, and\ndtls/test/echo_seq.py demonstrates how to take a simple echo server\nthrough a listen/accept/echo/shutdown sequence using this class. The\ncorresponding client side can look like the snippet at the top of this\ndocument, followed by a call to the *unwrap* method for shutdown (or a\ncall to the **SSLConnection** *shutdown* method, if an instance of\nthis class is used for the client side also). Note that the *dtls*\npackage does not depend on the standard library's *ssl* module, and\n**SSLConnection** can therefore be used in environments where *ssl* is\nunavailable or incompatible.\n\nIt is expected that with the *ssl* module being an established, familiar\ninterface to TLS, it will be the preferred module through which to\naccess DTLS. To do so, one must call the *dtls* package's *do_patch*\nfunction before passing sockets of type SOCK_DGRAM to either *ssl's*\n*wrap_socket* function, or *ssl's* **SSLSocket** constructor.\n\nIt should be noted that once *do_patch* is called, *dtls* will raise\nexceptions of type **ssl.SSLError** instead of its default\n**dtls.err.SSLError**. This allows users' error handling code paths to\nremain identical when interfacing with *ssl* across stream and\ndatagram sockets.\n\n## Connection Handling\n\nThe DTLS protocol implies a connection as an association between two\nnetwork peers where the overall association state is characterized by the\nhandshake status of each peer endpoint (see RFC 6347). The OpenSSL library\nrecords this handshake status in \"SSL\" type instances (a.k.a. struct\nssl_st). Datagrams can be securely sent and received by referring to a\nunique \"SSL\" instance after handshaking has been completed with this\ninstance and its network peer. A connection is implied in that traffic\nmay be directed to or received from only that network peer with whose\n\"SSL\" instance the handshake has been completed. The fact that the\nunderlying network protocol, UDP in most cases, is itself connectionless\nis immaterial.\n\nFurther, in order to prevent denial-of-service attacks on UDP DTLS\nservers, clients must undergo a cookie exchange phase early in the\nhandshaking protocol, and before server-side resources are committed to\na particular client (see section 4.2.1 of RFC 6347). The cookie exchange\nproves to the server that a client can indeed receive IP traffic at\nthe source IP address with which its handshake-initiating ClientHello\ndatagram is marked.\n\nPyDTLS implements this connection establishment through the *connect*\nmethod on the client side, and the *accept* method on the server side.\nThe latter returns a new **dtls.SSLConnection** or **ssl.SSLSocket**\nobject (depending on which interface is used, see above), which is\n\"connected\" to its peer. In addition to the *read* and *write* methods\n(at both interface levels), **SSLSocket's** *send* and *recv* methods\ncan be used; use of *sendto* and *recvfrom* on connected sockets is\nprohibited by *ssl*. *accept* returns peer address information, as\nexpected. Note that when using the *ssl* interface to *dtls*, *listen*\nmust be called before calling *accept*.\n\n## Demultiplexing\n\nAt the network io layer, only datagrams from its connected peer must be\npassed to a **SSLConnection** or **SSLSocket** object (unless the object\nis unconnected on the server-side, in which case it can be in listening\nmode, the initial server-side socket whose role it is to listen for\nincoming client connection requests).\n\nThe initial server-side listening socket is not useful for performing this\ndatagram routing function. This is because it must remain unconnected and\nready to receive additional connection requests from new, unknown clients.\n\nThe function of passing incoming datagrams to the proper connection is\nperformed by the *dtls.demux* package. **SSLConnection** requests a new\nconnection from the demux when a handshake has cleared the cookie\nexchange phase. An efficient implementation of this request is provided\nby the *osnet* module of the demux package: it creates a new socket that\nis bound to the same network interface and port as the listening socket,\nbut connected to the peer. UDP stacks such as the one included with Linux\nroute incoming datagrams to such a connected socket in preference to an\nunconnected socket bound to the same port.\n\nUnfortunately such is not the behavior on Microsoft Windows. Windows\nUDP routes datagrams to whichever currently existing socket bound to\nthe particular port the earliest (and whether or not that socket is\nunconnected, or connected to the datagram's peer, or a different\npeer). Other sockets bound to the same port will not receive traffic,\nif and until they become the earliest bound socket because another\nsocket is closed.\n\nThe demux package therefore provides and automatically selects the module\n*router* on Windows platforms. This module also creates a new socket when\nreceiving a new connection request; but instead of binding this socket\nto the same port as the listening socket, it binds to a new ephemeral\nport. *router* then forwards datagrams originating from the peer for which\na connection was requested to the corresponding socket.\n\nFor efficiency's sake, no forwarding is performed on outgoing traffic.\nInstead, **SSLConnection** directs outgoing traffic from the original\nlistening socket, using *sendto*. At the OpenSSL level this requires\nseparate read and write datagram BIO's for an \"SSL\" instance, one in\n\"connected\" state and one in \"peer set\" state, respectively, and\nassociated with two separate network sockets.\n\nFrom the perspective of a PyDTLS user, this selection of and\ndifference between demux implementations should be transparent, with\nthe possible exception of performance deviation. This transparency\ndoes however have some limits: for example, when *router* is in use,\nthe *accept* methods can return *None*. This happens when\n**SSLConnection** detects that the demux has forwarded a datagram to a\nknown connection instead of initiating a connection to a new peer\nthrough *accept*. Returning *None* in this case is important whenever\nnon-blocking sockets or sockets with timeouts are used, since another\nsocket might now be readable as a result of the forwarded\ndatagram. *accept* must return so that the application can iterate on\nits asynchronous *select* loop.\n\n## Shutdown and Unwrapping\n\nPyDTLS implements the SSL/TLS shutdown protocol as it has been adapted\nfor DTLS. **SSLConnection's** *shutdown* and **SSLSocket's** *unwrap*\ninvoke this protocol. As is the case with DTLS handshaking in general,\napplications must be prepared to use the *get_timeout* and\n*handle_timeout* methods in addition to re-invoking *shutdown* or\n*unwrap* when sockets become readable and an exception carried\nSSL_ERROR_WANT_READ. (See more on asynchronous IO in the Testing section.)\n\n**SSLConnection's** *shutdown* and **SSLSocket's** *unwrap* return a\n(possibly new) socket that can be used for unsecured communication\nwith the peer, as set forth by the *ssl* module. The demux\ninfrastructure remains in use for this communication until the\nreturned socket is cleaned up. Note that when the *router* demux is\nin use, the object returned will be one derived from\n*socket.socket*. This is because the send and recv paths must still be\ndirected to two different OS sockets. In addition, the right thing\nhappens if secured communication is resumed over such a socket by\npassing it to *ssl.wrap_socket* or the **SSLConnection**\nconstructor. If *osnet* is used, an actual *socket.socket* instance is\nreturned.\n\n## Framework Compatibility\n\nPyDTLS sockets have been tested under the following usage modes:\n\n * Using blocking sockets and sockets with timeouts in\n multi-threaded UDP servers\n * Using non-blocking sockets, and in conjunction with the\n asynchronous socket handler, asyncore\n * Using blocking sockets, and in conjunction with the network\n server framework SocketServer - ThreadingTCPServer (this works\n because of PyDTLS's emulation of connection-related calls)\n\n## Multi-thread Support\n\nUsing multiple threads with OpenSSL requires implementing a locking\ncallback. PyDTLS does implement this, and therefore multi-threaded\nprogramming with PyDTLS is safe in any environment. However, being a\npure Python library, these callbacks do carry some overhead. The *ssl*\nmodule implements an equivalent locking callback in its C extension\nmodule. Not requiring interpreter re-entry, this approach can be\nexpected to perform better. PyDTLS therefore queries OpenSSL as to\nwhether a locking callback is already in place, and does not overwrite\nit if there is. Loading *ssl* can therefore improve performance, even\nwhen only the *sslconnection* interface is used.\n\nNote that loading order does not matter: to obtain the performance\nbenefit, *ssl* can be loaded before or after the dtls package. This is\nbecause *ssl* does not do an equivalent existing locking callback\ncheck, and will simply overwrite the PyDTLS callback if it has already\nbeen installed. But *ssl* should not be loaded while *dtls* operation\nis already in progress, when some locks may be in their acquired\nstate.\n\nAlso note that this performance enhancement is available only on\nplatforms where PyDTLS loads the same OpenSSL shared object as\n*ssl*. On Ubuntu 12.04, for example, this is the case, but on\nMicrosoft Windows it is not.\n\n## Testing\n\nA simple echo server is available to be executed from the project root\ndirectory with `python3 -m dtls.test.echo_seq`. The echo server is\nreachable using the code snippet at the top of this document, using port\n28000 at \"localhost\".\n\nUnit test suites can be executed from the project root directory with\n`python3 -m dtls.test.unit [-v]` and `python3 -m dtls.test.unit_wrapper`\n(for the client and server wrappers)\n\nAlmost all of the Python standard library's *ssl* unit tests from the\nmodule *test_ssl.py* have been ported to *dtls.test.unit.py*. All tests\nhave been adjusted to operate with datagram sockets. On Linux, each\ntest is executed four times, varying the address family among IPv4 and\nIPv6 and the demux among *osnet* and *router*. On Windows, where\n*osnet* is unavailable, each test is run twice, once with IPv4 and once\nwith IPv6.\n\nThe unit test suite includes tests for each of the above-mentioned\ncompatible frameworks. The class **AsyncoreEchoServer** serves as an\nexample of how to use non-blocking datagram sockets and implement the\nresulting timeout detection requirements. DTLS in general and OpenSSL\nin particular require being called back when used with non-blocking\nsockets (or sockets with timeout option) after DTLS timeouts expire to\nhandle packet loss using re-transmission during a\nhandshake. Handshaking may occur during any read or write operation,\neven after an initial handshake completes successfully, in case\nrenegotiation is requested by a peer.\n\nRunning with the -v switch executes all unit tests in verbose mode.\n\ndtls/test/test_perf.py implements an interactive performance test\nsuite that compares the raw throughput of TCP, UDP, SSL, and DTLS.\nIt can be executed locally through the loopback interface, or between\nremote clients and servers. In the latter case, test jobs are sent to\nremote connected clients whenever a suite run is initiated through the\ninteractive interface. Run test_perf.py -h for more information.\n\nIt should be noted that comparing the performance of protocols that\ndon't offer congestion control (UDP and DTLS) with those that do (TCP\nand SSL) is a difficult undertaking. Raw throughput even across\ngigabit network links can be expected to suffer without congestion\ncontrol and peers that generate data as fast as possible without\nthrottling (as this test does): the link's throughput will drop\nsignificantly as it enters congestion collapse. Similarly, loopback is\nan imperfect test interface since it rarely drops packets, and never\nduplicates or reorders them (thus negating the relative performance\nbenefits of DTLS over SSL). Nevertheless, some useful insights can be\ngained by observing the operation of test_perf.py, including software\nstack behavior in the presence of some amount of packet loss.\n\n## Logging\n\nThe *dtls* package and its sub-packages log various occurrences,\nprimarily events that can aid debugging. Especially *router* emits many\nmessages when the logging level is set to at least *logging.DEBUG*.\ndtls/test/echo_seq.py activates this logging level during its operation.\n\n\n",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "Python Datagram Transport Layer Security",
"version": "1.3.0",
"project_urls": {
"Homepage": "https://github.com/mcfreis/pydtls"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "05807a974781064c5c12e740a7588bbb6874016dbd38d9c74f72852d340b75f9",
"md5": "973a232a1559223de956f3e4f04ceb9f",
"sha256": "c0f0f48cd1513eb8530479131500928287c4686ddff2c842408b513387698eb1"
},
"downloads": -1,
"filename": "python3_dtls-1.3.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "973a232a1559223de956f3e4f04ceb9f",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 102503,
"upload_time": "2020-11-06T13:21:55",
"upload_time_iso_8601": "2020-11-06T13:21:55.858884Z",
"url": "https://files.pythonhosted.org/packages/05/80/7a974781064c5c12e740a7588bbb6874016dbd38d9c74f72852d340b75f9/python3_dtls-1.3.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "4720953aa88c1a04a5fc9fcb0b40314c9a5ea45ecdc77797b52803be1c9f52d2",
"md5": "0c1cdf7a5267bb9c89e4228fee39fc6e",
"sha256": "9c7927a52e146ccace6747521de8b47cdf431ce4ccc4034a8e3488b0ccaac8e7"
},
"downloads": -1,
"filename": "python3_dtls-1.3.0-py3-none-win32.whl",
"has_sig": false,
"md5_digest": "0c1cdf7a5267bb9c89e4228fee39fc6e",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 1356922,
"upload_time": "2020-11-06T13:22:02",
"upload_time_iso_8601": "2020-11-06T13:22:02.843866Z",
"url": "https://files.pythonhosted.org/packages/47/20/953aa88c1a04a5fc9fcb0b40314c9a5ea45ecdc77797b52803be1c9f52d2/python3_dtls-1.3.0-py3-none-win32.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "2835437a47935a653b13670eb3a343a2eee422b4454a98f3004dbce5f7aecd1f",
"md5": "ef76982cd50e5681fa5ddfea04c5e230",
"sha256": "6b8dbfe0622a4b26535a9c576f1b5f7150d276dfe121d5f2873c78e0ac0cd5f5"
},
"downloads": -1,
"filename": "python3_dtls-1.3.0-py3-none-win_amd64.whl",
"has_sig": false,
"md5_digest": "ef76982cd50e5681fa5ddfea04c5e230",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 1639293,
"upload_time": "2020-11-06T13:22:07",
"upload_time_iso_8601": "2020-11-06T13:22:07.158724Z",
"url": "https://files.pythonhosted.org/packages/28/35/437a47935a653b13670eb3a343a2eee422b4454a98f3004dbce5f7aecd1f/python3_dtls-1.3.0-py3-none-win_amd64.whl",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2020-11-06 13:21:55",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "mcfreis",
"github_project": "pydtls",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "python3-dtls"
}