|
@@ -0,0 +1,116 @@ |
|
|
|
|
|
from noise.connection import NoiseConnection, Keypair |
|
|
|
|
|
from twistednoise import genkeypair |
|
|
|
|
|
|
|
|
|
|
|
import os.path |
|
|
|
|
|
import shutil |
|
|
|
|
|
import socket |
|
|
|
|
|
import tempfile |
|
|
|
|
|
import threading |
|
|
|
|
|
import unittest |
|
|
|
|
|
|
|
|
|
|
|
def _makeunix(path): |
|
|
|
|
|
'''Make a properly formed unix path socket string.''' |
|
|
|
|
|
|
|
|
|
|
|
return 'unix:%s' % path |
|
|
|
|
|
|
|
|
|
|
|
def _acceptfun(s, fun): |
|
|
|
|
|
while True: |
|
|
|
|
|
sock = s.accept() |
|
|
|
|
|
|
|
|
|
|
|
fun(*sock) |
|
|
|
|
|
|
|
|
|
|
|
def listensocket(sockstr, fun): |
|
|
|
|
|
'''Listen for connections on sockstr. When ever a connection |
|
|
|
|
|
is accepted, the parameter fun is called with the socket and |
|
|
|
|
|
the from address. The return will be a Thread object. Note |
|
|
|
|
|
that fun MUST NOT block, as if it does, it will stop accepting |
|
|
|
|
|
other connections. |
|
|
|
|
|
|
|
|
|
|
|
The format of sockstr is: 'proto:param=value[,param2=value2]'. |
|
|
|
|
|
If the proto has a default parameter, the value can be used |
|
|
|
|
|
directly, like: 'proto:value'. This is only allowed when the |
|
|
|
|
|
value can unambiguously be determined not to be a param. |
|
|
|
|
|
|
|
|
|
|
|
The characters that define 'param' must be all lower case ascii |
|
|
|
|
|
characters and may contain an underscore. The first character |
|
|
|
|
|
must not be and underscore. |
|
|
|
|
|
|
|
|
|
|
|
Supported protocols: |
|
|
|
|
|
unix: |
|
|
|
|
|
Default parameter is path. |
|
|
|
|
|
The path parameter specifies the path to the |
|
|
|
|
|
unix domain socket. The path MUST start w/ a |
|
|
|
|
|
slash if it is used as a default parameter. |
|
|
|
|
|
''' |
|
|
|
|
|
|
|
|
|
|
|
proto, rem = sockstr.split(':', 1) |
|
|
|
|
|
|
|
|
|
|
|
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) |
|
|
|
|
|
s.bind(rem) |
|
|
|
|
|
s.listen(-1) |
|
|
|
|
|
|
|
|
|
|
|
thr = threading.Thread(target=_acceptfun, name='accept thread: %s' % repr(sockstr), args=(s, fun)) |
|
|
|
|
|
thr.setDaemon(True) |
|
|
|
|
|
|
|
|
|
|
|
thr.start() |
|
|
|
|
|
|
|
|
|
|
|
return thr |
|
|
|
|
|
|
|
|
|
|
|
class NoiseForwarder(object): |
|
|
|
|
|
def __init__(self, mode, sock, ): |
|
|
|
|
|
nf = NoiseForwarder('resp', self.server_key_pair[1], ssock, pttarg) |
|
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
class TestListenSocket(unittest.TestCase): |
|
|
|
|
|
def test_listensocket(self): |
|
|
|
|
|
# XXX write test |
|
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
class Tests(unittest.TestCase): |
|
|
|
|
|
def setUp(self): |
|
|
|
|
|
# setup temporary directory |
|
|
|
|
|
d = os.path.realpath(tempfile.mkdtemp()) |
|
|
|
|
|
self.basetempdir = d |
|
|
|
|
|
self.tempdir = os.path.join(d, 'subdir') |
|
|
|
|
|
os.mkdir(self.tempdir) |
|
|
|
|
|
|
|
|
|
|
|
# Generate key pairs |
|
|
|
|
|
self.server_key_pair = genkeypair() |
|
|
|
|
|
self.client_key_pair = genkeypair() |
|
|
|
|
|
|
|
|
|
|
|
def tearDown(self): |
|
|
|
|
|
shutil.rmtree(self.basetempdir) |
|
|
|
|
|
self.tempdir = None |
|
|
|
|
|
|
|
|
|
|
|
def test_server(self): |
|
|
|
|
|
# Path that the server will sit on |
|
|
|
|
|
servsockpath = os.path.join(self.tempdir, 'servsock') |
|
|
|
|
|
servarg = _makeunix(servsockpath) |
|
|
|
|
|
|
|
|
|
|
|
# Path that the server will send pt data to |
|
|
|
|
|
servsockpath = os.path.join(self.tempdir, 'servptsock') |
|
|
|
|
|
|
|
|
|
|
|
# Setup pt target listener |
|
|
|
|
|
pttarg = _makeunix(servsockpath) |
|
|
|
|
|
ptsock = [] |
|
|
|
|
|
def ptsockaccept(sock, frm, ptsock=ptsock): |
|
|
|
|
|
ptsock.append(sock) |
|
|
|
|
|
|
|
|
|
|
|
# Bind to pt listener |
|
|
|
|
|
lsock = listensocket(pttarg, ptsockaccept) |
|
|
|
|
|
|
|
|
|
|
|
# Setup server listener |
|
|
|
|
|
ssock = listensocket(servarg, lambda x, y: NoiseForwarder('resp', self.server_key_pair[1], x, pttarg)) |
|
|
|
|
|
|
|
|
|
|
|
# Create client |
|
|
|
|
|
proto = NoiseConnection.from_name(b'Noise_XK_448_ChaChaPoly_SHA256') |
|
|
|
|
|
proto.set_as_initiator() |
|
|
|
|
|
|
|
|
|
|
|
# Setup required keys |
|
|
|
|
|
proto.set_keypair_from_private_bytes(Keypair.STATIC, self.client_key_pair[1]) |
|
|
|
|
|
proto.set_keypair_from_public_bytes(Keypair.REMOTE_STATIC, self.server_key_pair[0]) |
|
|
|
|
|
|
|
|
|
|
|
proto.start_handshake() |
|
|
|
|
|
|
|
|
|
|
|
# Send first message |
|
|
|
|
|
message = proto.write_message() |