merge transit_common into twisted.transit
This commit is contained in:
parent
db137c26e5
commit
a8446d2bc5
|
@ -1,87 +0,0 @@
|
||||||
import re
|
|
||||||
from binascii import hexlify
|
|
||||||
from .util.hkdf import HKDF
|
|
||||||
|
|
||||||
class TransitError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class BadHandshake(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class TransitClosed(TransitError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class BadNonce(TransitError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# The beginning of each TCP connection consists of the following handshake
|
|
||||||
# messages. The sender transmits the same text regardless of whether it is on
|
|
||||||
# the initiating/connecting end of the TCP connection, or on the
|
|
||||||
# listening/accepting side. Same for the receiver.
|
|
||||||
#
|
|
||||||
# sender -> receiver: transit sender TXID_HEX ready\n\n
|
|
||||||
# receiver -> sender: transit receiver RXID_HEX ready\n\n
|
|
||||||
#
|
|
||||||
# Any deviations from this result in the socket being closed. The handshake
|
|
||||||
# messages are designed to provoke an invalid response from other sorts of
|
|
||||||
# servers (HTTP, SMTP, echo).
|
|
||||||
#
|
|
||||||
# If the sender is satisfied with the handshake, and this is the first socket
|
|
||||||
# to complete negotiation, the sender does:
|
|
||||||
#
|
|
||||||
# sender -> receiver: go\n
|
|
||||||
#
|
|
||||||
# and the next byte on the wire will be from the application.
|
|
||||||
#
|
|
||||||
# If this is not the first socket, the sender does:
|
|
||||||
#
|
|
||||||
# sender -> receiver: nevermind\n
|
|
||||||
#
|
|
||||||
# and closes the socket.
|
|
||||||
|
|
||||||
# So the receiver looks for "transit sender TXID_HEX ready\n\ngo\n" and hangs
|
|
||||||
# up upon the first wrong byte. The sender lookgs for "transit receiver
|
|
||||||
# RXID_HEX ready\n\n" and then makes a first/not-first decision about sending
|
|
||||||
# "go\n" or "nevermind\n"+close().
|
|
||||||
|
|
||||||
def build_receiver_handshake(key):
|
|
||||||
hexid = HKDF(key, 32, CTXinfo=b"transit_receiver")
|
|
||||||
return b"transit receiver "+hexlify(hexid)+b" ready\n\n"
|
|
||||||
|
|
||||||
def build_sender_handshake(key):
|
|
||||||
hexid = HKDF(key, 32, CTXinfo=b"transit_sender")
|
|
||||||
return b"transit sender "+hexlify(hexid)+b" ready\n\n"
|
|
||||||
|
|
||||||
def build_relay_handshake(key):
|
|
||||||
token = HKDF(key, 32, CTXinfo=b"transit_relay_token")
|
|
||||||
return b"please relay "+hexlify(token)+b"\n"
|
|
||||||
|
|
||||||
# The hint format is: TYPE,VALUE= /^([a-zA-Z0-9]+):(.*)$/ . VALUE depends
|
|
||||||
# upon TYPE, and it can have more colons in it. For TYPE=tcp (the only one
|
|
||||||
# currently defined), ADDR,PORT = /^(.*):(\d+)$/ , so ADDR can have colons.
|
|
||||||
# ADDR can be a hostname, ipv4 dotted-quad, or ipv6 colon-hex. If the hint
|
|
||||||
# publisher wants anonymity, their only hint's ADDR will end in .onion .
|
|
||||||
|
|
||||||
def parse_hint_tcp(hint):
|
|
||||||
assert isinstance(hint, type(u""))
|
|
||||||
# return tuple or None for an unparseable hint
|
|
||||||
mo = re.search(r'^([a-zA-Z0-9]+):(.*)$', hint)
|
|
||||||
if not mo:
|
|
||||||
print("unparseable hint '%s'" % (hint,))
|
|
||||||
return None
|
|
||||||
hint_type = mo.group(1)
|
|
||||||
if hint_type != "tcp":
|
|
||||||
print("unknown hint type '%s' in '%s'" % (hint_type, hint))
|
|
||||||
return None
|
|
||||||
hint_value = mo.group(2)
|
|
||||||
mo = re.search(r'^(.*):(\d+)$', hint_value)
|
|
||||||
if not mo:
|
|
||||||
print("unparseable TCP hint '%s'" % (hint,))
|
|
||||||
return None
|
|
||||||
hint_host = mo.group(1)
|
|
||||||
try:
|
|
||||||
hint_port = int(mo.group(2))
|
|
||||||
except ValueError:
|
|
||||||
print("non-numeric port in TCP hint '%s'" % (hint,))
|
|
||||||
return None
|
|
||||||
return hint_host, hint_port
|
|
|
@ -1,5 +1,5 @@
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import sys, time, socket, collections
|
import re, sys, time, socket, collections
|
||||||
from binascii import hexlify, unhexlify
|
from binascii import hexlify, unhexlify
|
||||||
from zope.interface import implementer
|
from zope.interface import implementer
|
||||||
from twisted.python.runtime import platformType
|
from twisted.python.runtime import platformType
|
||||||
|
@ -12,11 +12,6 @@ from ..util import ipaddrs
|
||||||
from ..util.hkdf import HKDF
|
from ..util.hkdf import HKDF
|
||||||
from ..errors import UsageError
|
from ..errors import UsageError
|
||||||
from ..timing import DebugTiming
|
from ..timing import DebugTiming
|
||||||
from ..transit_common import (BadHandshake,
|
|
||||||
BadNonce,
|
|
||||||
build_receiver_handshake,
|
|
||||||
build_sender_handshake,
|
|
||||||
build_relay_handshake)
|
|
||||||
|
|
||||||
def debug(msg):
|
def debug(msg):
|
||||||
if False:
|
if False:
|
||||||
|
@ -24,6 +19,90 @@ def debug(msg):
|
||||||
def since(start):
|
def since(start):
|
||||||
return time.time() - start
|
return time.time() - start
|
||||||
|
|
||||||
|
class TransitError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class BadHandshake(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class TransitClosed(TransitError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class BadNonce(TransitError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# The beginning of each TCP connection consists of the following handshake
|
||||||
|
# messages. The sender transmits the same text regardless of whether it is on
|
||||||
|
# the initiating/connecting end of the TCP connection, or on the
|
||||||
|
# listening/accepting side. Same for the receiver.
|
||||||
|
#
|
||||||
|
# sender -> receiver: transit sender TXID_HEX ready\n\n
|
||||||
|
# receiver -> sender: transit receiver RXID_HEX ready\n\n
|
||||||
|
#
|
||||||
|
# Any deviations from this result in the socket being closed. The handshake
|
||||||
|
# messages are designed to provoke an invalid response from other sorts of
|
||||||
|
# servers (HTTP, SMTP, echo).
|
||||||
|
#
|
||||||
|
# If the sender is satisfied with the handshake, and this is the first socket
|
||||||
|
# to complete negotiation, the sender does:
|
||||||
|
#
|
||||||
|
# sender -> receiver: go\n
|
||||||
|
#
|
||||||
|
# and the next byte on the wire will be from the application.
|
||||||
|
#
|
||||||
|
# If this is not the first socket, the sender does:
|
||||||
|
#
|
||||||
|
# sender -> receiver: nevermind\n
|
||||||
|
#
|
||||||
|
# and closes the socket.
|
||||||
|
|
||||||
|
# So the receiver looks for "transit sender TXID_HEX ready\n\ngo\n" and hangs
|
||||||
|
# up upon the first wrong byte. The sender lookgs for "transit receiver
|
||||||
|
# RXID_HEX ready\n\n" and then makes a first/not-first decision about sending
|
||||||
|
# "go\n" or "nevermind\n"+close().
|
||||||
|
|
||||||
|
def build_receiver_handshake(key):
|
||||||
|
hexid = HKDF(key, 32, CTXinfo=b"transit_receiver")
|
||||||
|
return b"transit receiver "+hexlify(hexid)+b" ready\n\n"
|
||||||
|
|
||||||
|
def build_sender_handshake(key):
|
||||||
|
hexid = HKDF(key, 32, CTXinfo=b"transit_sender")
|
||||||
|
return b"transit sender "+hexlify(hexid)+b" ready\n\n"
|
||||||
|
|
||||||
|
def build_relay_handshake(key):
|
||||||
|
token = HKDF(key, 32, CTXinfo=b"transit_relay_token")
|
||||||
|
return b"please relay "+hexlify(token)+b"\n"
|
||||||
|
|
||||||
|
# The hint format is: TYPE,VALUE= /^([a-zA-Z0-9]+):(.*)$/ . VALUE depends
|
||||||
|
# upon TYPE, and it can have more colons in it. For TYPE=tcp (the only one
|
||||||
|
# currently defined), ADDR,PORT = /^(.*):(\d+)$/ , so ADDR can have colons.
|
||||||
|
# ADDR can be a hostname, ipv4 dotted-quad, or ipv6 colon-hex. If the hint
|
||||||
|
# publisher wants anonymity, their only hint's ADDR will end in .onion .
|
||||||
|
|
||||||
|
def parse_hint_tcp(hint):
|
||||||
|
assert isinstance(hint, type(u""))
|
||||||
|
# return tuple or None for an unparseable hint
|
||||||
|
mo = re.search(r'^([a-zA-Z0-9]+):(.*)$', hint)
|
||||||
|
if not mo:
|
||||||
|
print("unparseable hint '%s'" % (hint,))
|
||||||
|
return None
|
||||||
|
hint_type = mo.group(1)
|
||||||
|
if hint_type != "tcp":
|
||||||
|
print("unknown hint type '%s' in '%s'" % (hint_type, hint))
|
||||||
|
return None
|
||||||
|
hint_value = mo.group(2)
|
||||||
|
mo = re.search(r'^(.*):(\d+)$', hint_value)
|
||||||
|
if not mo:
|
||||||
|
print("unparseable TCP hint '%s'" % (hint,))
|
||||||
|
return None
|
||||||
|
hint_host = mo.group(1)
|
||||||
|
try:
|
||||||
|
hint_port = int(mo.group(2))
|
||||||
|
except ValueError:
|
||||||
|
print("non-numeric port in TCP hint '%s'" % (hint,))
|
||||||
|
return None
|
||||||
|
return hint_host, hint_port
|
||||||
|
|
||||||
TIMEOUT=15
|
TIMEOUT=15
|
||||||
|
|
||||||
@implementer(interfaces.IProducer, interfaces.IConsumer)
|
@implementer(interfaces.IProducer, interfaces.IConsumer)
|
||||||
|
@ -684,7 +763,7 @@ class Common:
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def _endpoint_from_hint(self, hint):
|
def _endpoint_from_hint(self, hint):
|
||||||
# TODO: use transit_common.parse_hint_tcp
|
# TODO: use parse_hint_tcp
|
||||||
if ":" not in hint:
|
if ":" not in hint:
|
||||||
return None
|
return None
|
||||||
pieces = hint.split(":")
|
pieces = hint.split(":")
|
||||||
|
|
Loading…
Reference in New Issue
Block a user