Skip to content

Instantly share code, notes, and snippets.

@shen-xianpeng
Forked from koenbollen/punch.py
Created March 2, 2017 16:01
Show Gist options
  • Save shen-xianpeng/6f42d2fd2fdfe16a2d814a36f97e87f8 to your computer and use it in GitHub Desktop.
Save shen-xianpeng/6f42d2fd2fdfe16a2d814a36f97e87f8 to your computer and use it in GitHub Desktop.
Proof of Concept: UDP Hole Punching
#!/usr/bin/env python
#
# Proof of Concept: UDP Hole Punching
# Two client connect to a server and get redirected to each other.
#
# This is the client.
#
# Koen Bollen <meneer koenbollen nl>
# 2010 GPL
#
import sys
import socket
from select import select
import struct
def bytes2addr( bytes ):
"""Convert a hash to an address pair."""
if len(bytes) != 6:
raise ValueError, "invalid bytes"
host = socket.inet_ntoa( bytes[:4] )
port, = struct.unpack( "H", bytes[-2:] )
return host, port
def main():
try:
master = (sys.argv[1], int(sys.argv[2]))
pool = sys.argv[3].strip()
except (IndexError, ValueError):
print >>sys.stderr, "usage: %s <host> <port> <pool>" % sys.argv[0]
sys.exit(65)
sockfd = socket.socket( socket.AF_INET, socket.SOCK_DGRAM )
sockfd.sendto( pool, master )
data, addr = sockfd.recvfrom( len(pool)+3 )
if data != "ok "+pool:
print >>sys.stderr, "unable to request!"
sys.exit(1)
sockfd.sendto( "ok", master )
print >>sys.stderr, "request sent, waiting for parkner in pool '%s'..." % pool
data, addr = sockfd.recvfrom( 6 )
target = bytes2addr(data)
print >>sys.stderr, "connected to %s:%d" % target
while True:
rfds,_,_ = select( [0, sockfd], [], [] )
if 0 in rfds:
data = sys.stdin.readline()
if not data:
break
sockfd.sendto( data, target )
elif sockfd in rfds:
data, addr = sockfd.recvfrom( 1024 )
sys.stdout.write( data )
sockfd.close()
if __name__ == "__main__":
main()
# vim: expandtab shiftwidth=4 softtabstop=4 textwidth=79:
#!/usr/bin/env python
#
# Proof of Concept: UDP Hole Punching
# Two client connect to a server and get redirected to each other.
#
# This is the rendezvous server.
#
# Koen Bollen <meneer koenbollen nl>
# 2010 GPL
#
import socket
import struct
import sys
def addr2bytes( addr ):
"""Convert an address pair to a hash."""
host, port = addr
try:
host = socket.gethostbyname( host )
except (socket.gaierror, socket.error):
raise ValueError, "invalid host"
try:
port = int(port)
except ValueError:
raise ValueError, "invalid port"
bytes = socket.inet_aton( host )
bytes += struct.pack( "H", port )
return bytes
def main():
port = 4653
try:
port = int(sys.argv[1])
except (IndexError, ValueError):
pass
sockfd = socket.socket( socket.AF_INET, socket.SOCK_DGRAM )
sockfd.bind( ("", port) )
print "listening on *:%d (udp)" % port
poolqueue = {}
while True:
data, addr = sockfd.recvfrom(32)
print "connection from %s:%d" % addr
pool = data.strip()
sockfd.sendto( "ok "+pool, addr )
data, addr = sockfd.recvfrom(2)
if data != "ok":
continue
print "request received for pool:", pool
try:
a, b = poolqueue[pool], addr
sockfd.sendto( addr2bytes(a), b )
sockfd.sendto( addr2bytes(b), a )
print "linked", pool
del poolqueue[pool]
except KeyError:
poolqueue[pool] = addr
if __name__ == "__main__":
main()
# vim: expandtab shiftwidth=4 softtabstop=4 textwidth=79:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment