├── .server.py.swp
├── README
└── htcp
└── p2pnetwork
├── discover
├── __init__.py
└── stunDiscover.py
├── htcp
├── connectionBroker.py
├── punchProtocol.py
└── puncher.py
├── stun
├── .stun.py.swp
├── __init__.py
├── server.py
└── stun.py
└── testtcp
├── natTravCB.py
├── sniff.py
├── sniffer.py
├── spoof.py
├── spoofSniffer.py
├── testTCPcl.py
└── udpSniffer.py
/.server.py.swp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/myrual/python-stun/6d1477a42397c6c57ebfeddc79b223170448f998/.server.py.swp
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/myrual/python-stun/6d1477a42397c6c57ebfeddc79b223170448f998/README
--------------------------------------------------------------------------------
/htcp/p2pnetwork/discover/__init__.py:
--------------------------------------------------------------------------------
1 |
2 | # Twisted, the Framework of Your Internet
3 | # Copyright (C) 2001 Matthew W. Lefkowitz
4 | #
5 | # This library is free software; you can redistribute it and/or
6 | # modify it under the terms of version 2.1 of the GNU Lesser General Public
7 | # License as published by the Free Software Foundation.
8 | #
9 | # This library is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | # Lesser General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU Lesser General Public
15 | # License along with this library; if not, write to the Free Software
16 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 |
18 | """
19 |
20 | Twisted Internet: Asynchronous I/O and Events.
21 |
22 | """
23 |
--------------------------------------------------------------------------------
/htcp/p2pnetwork/discover/stunDiscover.py:
--------------------------------------------------------------------------------
1 | #
2 | # Solipsis, a peer-to-peer serverless virtual world.
3 | # Copyright (C) 2002-2005 France Telecom R&D
4 | #
5 | # This software is free software; you can redistribute it and/or
6 | # modify it under the terms of the GNU Lesser General Public
7 | # License as published by the Free Software Foundation; either
8 | # version 2.1 of the License, or (at your option) any later version.
9 | #
10 | # This software is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | # Lesser General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU Lesser General Public
16 | # License along with this software; if not, write to the Free Software
17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 | #
19 |
20 | import os
21 | import twisted.internet.defer as defer
22 | from twisted.python import log, failure
23 | import ConfigParser
24 |
25 | import p2pNetwork.stun.stun as stun
26 |
27 | stun_section = {
28 | 'servers': ('stun_servers', str, ""),
29 | }
30 |
31 | transport = None
32 |
33 | #class _StunDiscovery(cnProtocol.CNProtocol):
34 | class _StunDiscovery(stun.StunClient):
35 |
36 |
37 | def __init__(self, servers = ''): #, *args, **kargs):
38 | super(_StunDiscovery, self).__init__()
39 | self.servers = servers
40 | self.attempt = 0
41 |
42 | def Start(self, myPort, reactor, deferred):
43 | """
44 | Start listening for STUN replies.
45 | """
46 |
47 | self.listening = reactor.listenUDP(myPort, self)
48 | self.myPort = myPort
49 | self.reactor = reactor
50 | # Pass all the variables to the Protocol implemetation
51 | #self.setDeferred(deferred)
52 | #self.setTransport(self.transport)
53 | #self.setListenPort(myPort)
54 | self.listenPort = myPort
55 | self.deferred = deferred
56 |
57 | self.Discover()
58 |
59 | def Discover(self):
60 |
61 | d = defer.Deferred()
62 | s = defer.Deferred()
63 |
64 | # Try to contact the n STUN servers
65 | host, port = self.servers[self.attempt]
66 | self.attempt = self.attempt + 1
67 | def _resolved(host, port):
68 | print 'Try to contact Stun server:', host, port
69 | s = self.sendRequest((host, port))
70 |
71 | def _unresolved(failure):
72 | print failure.getErrorMessage()
73 |
74 | d = self.reactor.resolve(host)
75 | d.addCallback(_resolved, port)
76 | d.addErrback(_unresolved)
77 |
78 | def Stop(self):
79 | """
80 | Stop listening.
81 | """
82 |
83 | self.listening.stopListening()
84 | self.listening = None
85 | #TODO: alive
86 |
87 | def gotMappedAddress(self, addr = '', port = 0):
88 | """
89 | Called back when STUN discovered our public address.
90 | """
91 | if not self.deferred.called:
92 | self.deferred.callback((addr, int(port)))
93 |
94 | def record(self, config):
95 | """Registration in the rendezvous server"""
96 | self.publicAddr = config[1]
97 | self.privateAddr = config[2]
98 | self.registration(('', self.publicAddr, self.privateAddr, ''))
99 |
100 | def connectionMade(self, addr = '', port = 0):
101 | """
102 | Called back when STUN discovered our public address.
103 | """
104 | if not self.deferred.called:
105 | print "Connection made!!!!!!!"
106 | #self.deferred.callback((addr, int(port)))
107 |
108 |
109 | def DiscoverAddress(port, reactor):
110 | d = defer.Deferred()
111 | #params.LoadSection('stun', stun_section)
112 | #servers = params.stun_servers or '127.0.0.1'
113 |
114 | # Load configuration
115 | config = ConfigParser.ConfigParser()
116 | config.read("p2pNetwork.conf")
117 | servers = config.get('stun', 'WellKnownStunServer')
118 |
119 | #servers = 'localhost'
120 | serv_list = [(s.strip(), 3478) for s in servers.split(',')]
121 | discovery = _StunDiscovery(servers=serv_list)
122 |
123 | def startDiscover():
124 | d = defer.Deferred()
125 | print 'start resend'
126 |
127 | d.addCallback(_succeed)
128 | d.addErrback(_fail)
129 | d = discovery.Discover()
130 |
131 |
132 | def _succeed(value):
133 | # Don't stop: continue to listen on the same port
134 | discovery.Stop()
135 | return value
136 |
137 | def _fail(failure):
138 | print "Discovery result:", failure.getErrorMessage()
139 | d.errback(failure)
140 |
141 | d.addCallback(_succeed)
142 | d.addErrback(_fail)
143 | # Start listening
144 | discovery.Start(port, reactor, d)
145 | return d
146 |
147 | # --------------------------------------------------------------
148 |
149 | def printConfiguration():
150 | """Prints the peer's network configuration"""
151 | discovery = _StunDiscovery()
152 | discovery.printConfiguration()
153 |
154 | def getConfiguration():
155 | """Gets a list with the network configuration:
156 | (NAT presence, NAT type, private address, public address)"""
157 | discovery = _StunDiscovery()
158 | return discovery.getConfiguration()
159 |
160 | def getNATType():
161 | """Returns the NAT's type"""
162 | discovery = _StunDiscovery()
163 | return discovery.getNATType()
164 |
165 | def getPrivateAddress():
166 | """Retruns the client's private address"""
167 | discovery = _StunDiscovery()
168 | return discovery.getPrivateAddress()
169 |
170 | def getPublicAddress():
171 | """Retruns the client's public address"""
172 | discovery = _StunDiscovery()
173 | return discovery.getPublicAddress()
174 |
175 |
--------------------------------------------------------------------------------
/htcp/p2pnetwork/htcp/connectionBroker.py:
--------------------------------------------------------------------------------
1 | from twisted.internet.protocol import DatagramProtocol
2 | from twisted.internet import reactor
3 | from p2pNetwork.htcp.punchProtocol import ConnectionBroker
4 |
5 |
6 | import struct, socket, time, logging
7 |
8 | class MessageReceived(ConnectionBroker):
9 | pass
10 |
11 | reactor.listenUDP(6060, MessageReceived())
12 | reactor.run()
13 |
--------------------------------------------------------------------------------
/htcp/p2pnetwork/htcp/punchProtocol.py:
--------------------------------------------------------------------------------
1 | #
2 | # Solipsis, a peer-to-peer serverless virtual world.
3 | # Copyright (C) 2002-2005 France Telecom R&D
4 | #
5 | # This software is free software; you can redistribute it and/or
6 | # modify it under the terms of the GNU Lesser General Public
7 | # License as published by the Free Software Foundation; either
8 | # version 2.1 of the License, or (at your option) any later version.
9 | #
10 | # This software is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | # Lesser General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU Lesser General Public
16 | # License along with this software; if not, write to the Free Software
17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 | #
19 |
20 | import struct, socket, time, logging
21 |
22 | from twisted.internet import reactor, defer
23 | from twisted.internet.protocol import DatagramProtocol
24 | from twisted.internet.protocol import Protocol
25 | from twisted.python import log, failure
26 |
27 | #
28 | # This is a list of allowed arguments in the "Hole Punching" protocol.
29 |
30 | # The Message Types
31 | PunchTypes = {0x1001 : 'Lookup Request', \
32 | 0x1101 : 'Lookup Response', \
33 | 0x1111 : 'Connection Request', \
34 | 0x1002 : 'Registration Request', \
35 | 0x1003 : 'Registration Response', \
36 | 0x1102 : 'Connection to peer', \
37 | 0x1112 : 'Error Response'}
38 |
39 | # The Message Attributes types
40 | PunchAttributes = { 0x0001 : 'USER-ID', \
41 | 0x0002 : 'PUBLIC-ADDRESSE', \
42 | 0x0003 : 'PRIVATE-ADDRESSE', \
43 | 0x0004 : 'NAT-TYPE' , \
44 | 0x0005 : 'REQUESTOR-PUBLIC-ADDRESSE', \
45 | 0x0006 : 'REQUESTOR-PRIVATE-ADDRESSE',\
46 | 0x0007 : 'REQUESTOR-NAT-TYPE', \
47 | 0x0008 : 'ERROR-CODE', \
48 | 0x0009 : 'UNKNOWN-ATTRIBUTES' }
49 |
50 | # The Error Code
51 | ResponseCodes = {
52 | 400 : 'Bad Request',
53 | 420 : 'Unknown attribute',
54 | 431 : 'Integrity Check Failure',
55 | 500 : 'Server Error',
56 | 600 : 'Global Failure'
57 | }
58 |
59 | DefaultServers = [
60 | ('localhost', 6060),
61 | ]
62 |
63 | import os
64 | if os.path.exists('/dev/urandom'):
65 | def getRandomTID():
66 | return open('/dev/urandom').read(16)
67 | else:
68 | def getRandomTID():
69 | # It's not necessary to have a particularly strong TID here
70 | import random
71 | tid = [ chr(random.randint(0,255)) for x in range(16) ]
72 | tid = ''.join(tid)
73 | return tid
74 |
75 | # ============================================================================
76 | # The Hole Punching protocol client/server methods
77 | # ============================================================================
78 | class PunchProtocol(DatagramProtocol, Protocol, object):
79 | """
80 | This class parses and builds hole punching messages.
81 | """
82 |
83 | avtypeList = {}
84 | mt, pktlen, tid = (0, 0, '0')
85 | toAddr = ('0.0.0.0', 0)
86 |
87 | # The ID table with: | id (=primary key) | public IP (= foreign key)|
88 | peersIDTab = {}
89 | # The IP table with: | public IP (=primary key)| private IP | NAT type |
90 | peersIPTab = {}
91 |
92 | def __init__(self, *args, **kwargs):
93 | # Initialize the variables
94 | self._pending = {}
95 | super(PunchProtocol, self).__init__(*args, **kwargs)
96 | self.TCPsessionStarted = 0
97 | print 'TCP:', self.TCPsessionStarted
98 |
99 | def datagramReceived(self, dgram, address):
100 | """Called when a message is arrived"""
101 | self.stopTimeout()
102 | print 'Received message from:' , address
103 | self.parseMessage(dgram)
104 | self.analyseMessage(address)
105 |
106 | def dataReceived(self, data):
107 | print 'dataReceived'
108 | stdout.write(data)
109 |
110 | def startedConnecting(self, connector):
111 | print 'Started to connect.'
112 |
113 | def clientConnectionFailed(self, connector, reason):
114 | print 'Connection failed. Reason:', reason
115 |
116 | def parseMessage(self, dgram):
117 | """Parse the message received"""
118 | self.avtypeList = {}
119 | # Header
120 | self.mt, self.pktlen, self.tid = struct.unpack('!hh16s', dgram[:20])
121 | # Payload
122 | remainder = dgram[20:]
123 | while remainder:
124 | avtype, avlen = struct.unpack('!hh', remainder[:4])
125 | val = remainder[4:4+avlen]
126 | avtype = PunchAttributes.get(avtype, 'Unknown type:%04x'%avtype)
127 | self.avtypeList[avtype] = val
128 | remainder = remainder[4+avlen:]
129 |
130 | def createMessage(self, toAddr, listAttr):
131 | """Pack the response and send it to the client"""
132 | avpairs = ()
133 | if self.responseType == "Lookup Request":
134 | self.mt = 0x1001 # Lookup Request
135 | elif self.responseType == "Lookup Response":
136 | self.mt = 0x1101 # Lookup Response
137 | elif self.responseType == "Connection Request":
138 | self.mt = 0x1111 # Connection Request
139 | elif self.responseType == "Registration Request":
140 | self.mt = 0x1002 # Registration Request
141 | elif self.responseType == "Registration Response":
142 | self.mt = 0x1003 # Registration Response
143 | elif self.responseType == "Connection to peer":
144 | self.mt = 0x1102 # Connection to peer
145 | elif self.responseType == "Error Response":
146 | self.mt = 0x1112 # Error Response
147 | avpairs = avpairs + listAttr
148 | ## self.send(toAddr, avpairs)
149 |
150 | ## def send(self, toAddr, avpairs=()):
151 | ## """Pack the response and send it"""
152 |
153 | self.toAddr = toAddr
154 | avstr = ''
155 | # add any attributes in Payload
156 | for a,v in avpairs:
157 | if a == 0x0001:
158 | flength = len(v)
159 | if flength%4 != 0:
160 | flength = 4 - len(v)%4 + len(v)
161 | v = v.zfill(flength)
162 | avstr = avstr + struct.pack( \
163 | '!hh%ds'%flength, a, len(v), v)
164 | elif a == 0x0002 or a == 0x0003 or a == 0x0005 or a == 0x0006:
165 | avstr = avstr + struct.pack( \
166 | '!hhccH4s', a, len(v), '0', '%d' % 0x01, int(v[:4]), v[4:])
167 | elif a == 0x0004 or a == 0x0006:
168 | pass
169 | elif a == 0x0008:
170 | err_class = int(v[0])
171 | number = int(v) - err_class*100
172 | phrase = responseCodes[int(v)]
173 | avstr = avstr + struct.pack( \
174 | '!hhi%ds' % len(phrase), a, 4 + len(phrase), \
175 | (err_class<<8) + number, phrase)
176 | elif a == 0x0009:
177 | avstr = avstr + struct.pack('!hh', a, len(v)*2)
178 | for unkAttr in v:
179 | avstr = avstr + struct.pack('!h', unkAttr)
180 |
181 | pktlen = len(avstr)
182 | if pktlen > 65535:
183 | raise ValueError, "stun request too big (%d bytes)" % pktlen
184 | # Add header and send
185 | self.pkt = struct.pack('!hh16s', self.mt, pktlen, self.tid) + avstr
186 |
187 | if self.TCPsessionStarted:
188 | pass
189 | else:
190 | self.transport.write(self.pkt, self.toAddr)
191 |
192 | def sendPack(self):
193 | """Send pack: used in retrasmission"""
194 | self.transport.write(self.pkt, self.toAddr)
195 |
196 | def getPortIpList(self, address):
197 | """Return a well formatted string with the address"""
198 | return '%d%s' % (address[1], socket.inet_aton(address[0]))
199 |
200 | def setServer(self, server):
201 | """Sets the Rendezvous server address"""
202 | self.server = server
203 |
204 | def setTransport(self, transport):
205 | """Set the transport object to send message on network"""
206 | self.transport = transport
207 |
208 | def stopTimeout(self):
209 | pass
210 |
211 |
212 | #=============================================================================
213 | # Connection Broker for Hole Punching Protocol
214 | # ============================================================================
215 | class ConnectionBroker(PunchProtocol, object):
216 | """ The code for the server """
217 |
218 | # TODO: read conf from file
219 | ## myAddress = (socket.gethostbyname(socket.gethostname()), 3478)
220 | ## myOtherAddress = (socket.gethostbyname(socket.gethostname()), 3479)
221 | myAddress = ('127.0.0.1', 3478)
222 | myOtherAddress = ('127.0.0.1', 3479)
223 | otherRdvServer = ('127.0.0.1', 3478)
224 |
225 |
226 | def analyseMessage(self, fromAddr):
227 | """Analyse the message received"""
228 |
229 | self.responseType = 'Binding Response'
230 | listAttr = ()
231 | listUnkAttr = ()
232 | toAddr = fromAddr # reply to ...
233 | numUnkAttr = 0 # Number of unknown attributes
234 |
235 |
236 | if self.mt == 0x1001:
237 | # -------------------------------------------------------------
238 | # if Lookup Request
239 |
240 | print "Lookup Request"
241 |
242 | #TODO
243 | #if checkUnkAttributes(...):
244 | # return
245 | logging.info("got PUNCH request from %s" % repr(fromAddr))
246 | #**************************************************************
247 | # Reply to requestor
248 | toAddr = fromAddr
249 | if not ('USER-ID' in self.avtypeList):
250 | dummy,family,port,ip = struct.unpack( \
251 | '!ccH4s', self.avtypeList['PUBLIC-ADDRESSE'])
252 | addr = (socket.inet_ntoa(ip), port)
253 | key = addr
254 | else:
255 | key = self.avtypeList['USER-ID']
256 |
257 | # Load the peer configuration
258 | peerInfo = self.getPeerInfo(key)
259 | print "--", peerInfo, "--"
260 | if peerInfo == ():
261 | # TODO: contact other connection broker
262 | # TODO: send error to client
263 | return
264 | if peerInfo[0] != '':
265 | listAttr = listAttr + ((0x0001, peerInfo[0]),)
266 |
267 | listAttr = listAttr + ((0x0002, self.getPortIpList(peerInfo[1])),)
268 | listAttr = listAttr + ((0x0003, self.getPortIpList(peerInfo[2])),)
269 | # TODO: add NAT type (?)
270 | #listAttr = listAttr + ((0x0004, peerInfo[4]),)
271 |
272 | self.responseType = "Lookup Response"
273 | self.createMessage(toAddr, listAttr)
274 |
275 | #**************************************************************
276 | # Advise peer
277 | toAddr = peerInfo[1] # the peer's address
278 | if 'REQUESTOR-PUBLIC-ADDRESSE' in self.avtypeList:
279 | dummy,family,port,ip = struct.unpack( \
280 | '!ccH4s', self.avtypeList['REQUESTOR-PUBLIC-ADDRESSE'])
281 | addr = (socket.inet_ntoa(ip), port)
282 | listAttr = listAttr + ((0x0005, self.getPortIpList(addr)),)
283 |
284 | if 'REQUESTOR-PRIVATE-ADDRESSE' in self.avtypeList:
285 | dummy,family,port,ip = struct.unpack( \
286 | '!ccH4s', self.avtypeList['REQUESTOR-PRIVATE-ADDRESSE'])
287 | addr = (socket.inet_ntoa(ip), port)
288 | listAttr = listAttr + ((0x0006, self.getPortIpList(addr)),)
289 | # TODO: add NAT type (?)
290 | #listAttr = listAttr + ((0x0007, listConf[4]),)
291 |
292 | self.responseType = "Connection Request"
293 | self.createMessage(toAddr, listAttr)
294 |
295 | elif self.mt == 0x1002:
296 | # -------------------------------------------------------------
297 | # Registration Request
298 |
299 | #TODO
300 | #if checkUnkAttributes(...):
301 | # return
302 | URI = self.avtypeList['USER-ID']
303 | publAddr = fromAddr
304 | ## dummy,family,port,ip = struct.unpack( \
305 | ## '!ccH4s', self.avtypeList['PUBLIC-ADDRESSE'])
306 | ## publAddr = (socket.inet_ntoa(ip), port)
307 | dummy,family,port,ip = struct.unpack( \
308 | '!ccH4s', self.avtypeList['PRIVATE-ADDRESSE'])
309 | privAddr = (socket.inet_ntoa(ip), port)
310 | # TODO: add id and NAT type
311 | peerInfo = (URI, publAddr, privAddr, '')
312 | self.registrePeer(peerInfo)
313 | self.printActiveConnection()
314 |
315 | # TODO: send ok response to Registration Requestor
316 | listAttr = listAttr + ((0x0002, self.getPortIpList(publAddr)),)
317 | listAttr = listAttr + ((0x0003, self.getPortIpList(privAddr)),)
318 | self.responseType = 'Registration Response'
319 | self.createMessage(toAddr, listAttr)
320 |
321 | else:
322 | # -------------------------------------------------------------
323 | # Bad Request
324 | listAttr = listAttr + ((0x0009, '400'),) # ERROR-CODE
325 | self.responseType = "Error Response"
326 | self.createResponse(toAddr, listAttr)
327 | logging.error("Punch error")
328 |
329 |
330 | def checkUnkAttributes(self,):
331 | """Check if there is some unknown attributes in request message"""
332 |
333 | listAttr = ()
334 | listUnkAttr = ()
335 | # For unknown attributes in request message
336 | for avtype in self.avtypeList:
337 | if avtype[:12] == 'Unknown type':
338 | listAttr = listAttr + ((0x0009, '420'),) # ERROR-CODE
339 | unkAttr = int(avtype[13:])
340 | listUnkAttr = listUnkAttr + (unkAttr,)
341 | numUnkAttr+=1
342 | self.responseType = "Binding Error Response"
343 |
344 | # To respect the that the total length of the list
345 | # is a multiple of 4 bytes
346 | if numUnkAttr%2 != 0:
347 | listUnkAttr = listUnkAttr + (unkAttr,)
348 | if listUnkAttr != ():
349 | listAttr = listAttr + ((0x000a, listUnkAttr),)
350 |
351 | return listAttr
352 |
353 | def getPeerInfo(self, key):
354 | """Return the client's infos: search by key.
355 | (id, public address, private address, NAT type)"""
356 |
357 | if key in self.peersIDTab:
358 | return key, self.peersIDTab[key], \
359 | self.peersIPTab[self.peersIDTab[key]][0], \
360 | self.peersIPTab[self.peersIDTab[key]][1]
361 | elif key in self.peersIPTab:
362 | return '', key, self.peersIPTab[key][0], self.peersIPTab[key][1]
363 | return ()
364 |
365 | def registrePeer(self, (userId, publicIP, privateIp, natType)):
366 | """Records the customer in the customer table"""
367 |
368 | if userId != '' :
369 | # If the client has an ID registre it
370 | self.peersIDTab[userId] = publicIP
371 | self.peersIPTab[publicIP] = (privateIp, natType)
372 |
373 | def printActiveConnection(self):
374 | """Print the table with the active connection"""
375 |
376 | print '*-------------------------------------------------------------------------*'
377 | print '* Active connections *'
378 | t = {}
379 | for peer in self.peersIDTab:
380 | t[self.peersIDTab[peer]] = ''
381 | print "| %12s | %22s | %22s | %4s |" % \
382 | (peer, self.peersIDTab[peer], \
383 | self.peersIPTab[self.peersIDTab[peer]][0], \
384 | self.peersIPTab[self.peersIDTab[peer]][1])
385 |
386 | for peer in self.peersIPTab:
387 | if peer not in t:
388 | print "| | %22s | %22s | %4s |" % \
389 | (peer, self.peersIPTab[peer][0], \
390 | self.peersIPTab[peer][1])
391 | print '*-------------------------------------------------------------------------*'
392 |
393 |
394 | # ============================================================================
395 | # Hole Punching Protocol: peer
396 | # ============================================================================
397 | class PunchPeer(PunchProtocol, object):
398 |
399 | activeConnection = ()
400 |
401 | # Initial timeout valor
402 | punch_timeout = 0.3
403 |
404 | def stopTimeout(self):
405 | """Stops the active timeout"""
406 | try:
407 | self.timeout.cancel()
408 | #print "timeout stopped"
409 | except:
410 | #print "except timeout"
411 | pass
412 | # Reinitialise variables
413 | self.punch_timeout = 0.1
414 | self.request = 1
415 |
416 | def analyseMessage(self, address):
417 | """
418 | Analyse the server's response
419 | """
420 | self.fromAddress = address
421 | listAttr = ()
422 |
423 |
424 | # TODO:
425 | # A tid for every connection
426 | # Check tid is one we sent and haven't had a reply to yet
427 | if self._pending.has_key(self.tid):
428 | #del self._pending[self.tid]
429 | pass
430 | elif self.mt == 0x1111: # Is a connection request
431 | # Add the tid to table (in "connection request" case)
432 | pass
433 | else:
434 | logging.error("error, unknown transaction ID %s, have %r" \
435 | % (self.tid, self._pending.keys()))
436 | return
437 |
438 | if self.mt == 0x1101:
439 | # -------------------------------------------------------------
440 | # Lookup Response
441 | logging.info("got punch response from %s"%repr(address))
442 |
443 | dummy,family,port,addr = struct.unpack( \
444 | '!ccH4s', self.avtypeList["PUBLIC-ADDRESSE"])
445 | publicAddress = (socket.inet_ntoa(addr), port)
446 | dummy,family,port,addr = struct.unpack( \
447 | '!ccH4s', self.avtypeList["PRIVATE-ADDRESSE"])
448 | privateAddress = (socket.inet_ntoa(addr), port)
449 | # TODO: read NAT type
450 | # If Nat type is sym: wait for message from peer
451 |
452 | # Puts peer in the active connection list and try to contact it
453 | self.activeConnection = self.activeConnection + (publicAddress,)
454 | self.activeConnection = self.activeConnection + (privateAddress,)
455 | self.responseType = "Connection to peer"
456 |
457 | if self.protocol == 'TCP':
458 | self.reactor.listenTCP(self.port, self)
459 | print 'Listen on port:', self.port
460 | reactor.connectTCP(publicAddress[0], publicAddress[1], self)
461 | print 'Connect with:', publicAddress
462 | self.TCPsessionStarted = 1
463 |
464 | # Msg to the peer's public address
465 | self.sendMessage(publicAddress)
466 | # Msg to the peer's public address
467 | self.sendMessage(privateAddress)
468 |
469 | elif self.mt == 0x1003:
470 | # -------------------------------------------------------------
471 | # Registration Response
472 | dummy,family,port,addr = struct.unpack( \
473 | '!ccH4s', self.avtypeList["PUBLIC-ADDRESSE"])
474 | self.publicAddr = (socket.inet_ntoa(addr), port)
475 | self.registrationMade()
476 |
477 | elif self.mt == 0x1111:
478 | # -------------------------------------------------------------
479 | # Connection Request
480 | print "Connection Request!!!"
481 |
482 | self.responseType = "Connection to peer"
483 |
484 | dummy,family,port,addr = struct.unpack( \
485 | '!ccH4s', self.avtypeList["REQUESTOR-PUBLIC-ADDRESSE"])
486 | publicAddress = (socket.inet_ntoa(addr), port)
487 | self.activeConnection = self.activeConnection + (publicAddress,)
488 |
489 | # Add tid: it's a new connection
490 | self._pending[self.tid] = (time.time(), publicAddress)
491 |
492 | # If the other peer client is bihind a NAT too
493 | if 'REQUESTOR-PRIVATE-IP' in self.avtypeList:
494 | dummy,family,port,addr = struct.unpack( \
495 | '!ccH4s', self.avtypeList["REQUESTOR-PRIVATE-ADDRESSE"])
496 | privateAddress = (socket.inet_ntoa(addr), port)
497 | self.activeConnection = self.activeConnection + (privateAddress,)
498 | # Send msg to the peer's private address
499 | #self.sendMessage(privateAddress)
500 |
501 |
502 | if self.protocol == 'TCP':
503 | self.reactor.listenTCP(self.port, self)
504 | print 'Listen on port:', self.port
505 | reactor.connectTCP(publicAddress[0], publicAddress[1], self)
506 | print 'Connect with:', publicAddress
507 | self.TCPsessionStarted = 1
508 |
509 | # Send msg to the peer's public address
510 | self.sendMessage(publicAddress)
511 |
512 | elif self.mt == 0x1102:
513 | # -------------------------------------------------------------
514 | # Connection to peer
515 | self.responseType = "Connection to peer"
516 |
517 | if self.fromAddress in self.activeConnection:
518 | # The connection is established
519 | self.connectionMade()
520 | else:
521 | # Send msg to the peer's address
522 | self.sendMessage(self.fromAddress)
523 |
524 |
525 | elif self.mt == 0x1112:
526 | # -------------------------------------------------------------
527 | # Error Response
528 |
529 | logging.error("STUN got an error response:")
530 | # Extract the class and number
531 | error, phrase = self.getErrorCode()
532 | if error == 420:
533 | _listUnkAttr = self.getListUnkAttr()
534 | logging.error((error, phrase, _listUnkAttr))
535 | else:
536 | logging.error((error, phrase))
537 | else:
538 | logging.error("STUN got unknown message")
539 |
540 | def sendMessage(self, server, avpairs=()):
541 |
542 | self._pending[self.tid] = (time.time(), server)
543 | self.timeout = 0.1
544 | self.request = 1
545 | #self.timeout = reactor.callLater(self.timeout, self._timeout)
546 | self.createMessage(server, avpairs)
547 |
548 |
549 | def _timeout(self):
550 | """If a timeout is expired
551 | Send 9 message at:
552 | 0ms, 100ms, 300ms, 700ms, 1500ms, 3100ms, 4700ms, 6300ms, 7900ms
553 | """
554 |
555 | print 'timeout', self.request
556 | self.request += 1
557 | if self.request == 10:
558 | self.retransmissionEnded()
559 | return
560 | if self.punch_timeout < 1.6:
561 | self.punch_timeout = 2 * self.punch_timeout
562 | self.timeout = reactor.callLater(self.punch_timeout, self._timeout)
563 | self.sendPack()
564 |
565 | def retransmissionEnded(self):
566 | """Connection have failed (called at 9500ms)"""
567 |
568 | self.stun_timeout = 0.1
569 | self.request = 1
570 |
571 |
572 | def getErrorCode(self):
573 | """If an error occurred: return the error code"""
574 |
575 | # Extract the class and number
576 | error, phrase = struct.unpack( \
577 | '!i%ds' % (len(self.avtypeList["ERROR-CODE"])-4), \
578 | self.avtypeList["ERROR-CODE"])
579 | number = error - ((error>>8)<<8)
580 | err_class = ((error - number)>>8)*100
581 | return err_class + number, phrase
582 |
583 | def getListUnkAttr(self):
584 | """Return the list of Unknown attributes"""
585 |
586 | _listUnkAttr = ()
587 | listUnkAttr = struct.unpack( \
588 | '!%dh' % int(len(self.avtypeList["UNKNOWN-ATTRIBUTES"])/2), \
589 | self.avtypeList["UNKNOWN-ATTRIBUTES"])
590 | for attr in listUnkAttr:
591 | _listUnkAttr = _listUnkAttr + ('0x%04x' % attr,)
592 | return _listUnkAttr
593 |
594 | def connectByAddress(self, address):
595 | """Try to connect to a peer by his address"""
596 | avpairs = ()
597 |
598 | self.tid = getRandomTID()
599 | self.responseType = 'Lookup Request'
600 | avpairs = avpairs + ((0x0002, self.getPortIpList(address)),)
601 | avpairs = avpairs + ((0x0005, self.getPortIpList(self.publicAddr)),)
602 | avpairs = avpairs + ((0x0006, self.getPortIpList(self.privateAddr)),)
603 | self.sendMessage(self.server, avpairs)
604 |
605 | def connectByURI(self, URI):
606 | """Try to connect to a peer by his URI"""
607 | avpairs = ()
608 |
609 | self.tid = getRandomTID()
610 | self.responseType = 'Lookup Request'
611 | avpairs = avpairs + ((0x0001, URI),)
612 | avpairs = avpairs + ((0x0005, self.getPortIpList(self.publicAddr)),)
613 | avpairs = avpairs + ((0x0006, self.getPortIpList(self.privateAddr)),)
614 | self.sendMessage(self.server, avpairs)
615 |
616 | def registration(self, (userId, publicAddr, privateAddr, natType)):
617 | """Create and send a register message to the rendezvous server"""
618 |
619 | # TODO: indipendent from protocol!!!
620 | self.protocol = '!TCP'
621 |
622 | listAttr = ()
623 | self.publicAddr = publicAddr
624 | self.privateAddr = privateAddr
625 |
626 | listAttr = listAttr + ((0x0001, userId),)
627 | listAttr = listAttr + ((0x0002, self.getPortIpList(publicAddr)),)
628 | listAttr = listAttr + ((0x0003, self.getPortIpList(privateAddr)),)
629 |
630 | self.responseType = 'Registration Request'
631 | self.tid = getRandomTID()
632 | #self.timeout = reactor.callLater(self.punch_timeout, self._timeout)
633 | self.sendMessage(self.server, listAttr)
634 |
635 | def registrationMade(self):
636 | print "Registration made"
637 | return
638 |
639 | ## def connect(self, (userId, ip, port)):
640 | ## """Make a connection with a peer"""
641 |
642 | ## self.punch.setEstablishUDPsessionArgs((userId, ip, port))
643 | ## self.punch.sendMessage(self.rdvIP, self.rdvPort)
644 |
645 | def connectionMade(self):
646 | """The connection with the peer is established"""
647 |
648 | # TODO: send a callback signal
649 | print "Connection Made!!!"
650 |
651 | def setRdvServer(self, (host, port)):
652 | self.rdvIP, self.rdvPort = (host, port)
653 |
654 | def setTransport(self, transport):
655 | self.punch.setTransport(transport)
656 |
657 | def keepAlive(self):
658 | #TODO
659 | pass
660 |
661 | def setSelf(self, _self):
662 | print _self, self
663 | print "request", _self.request,
664 | print self.request
665 | self = _self
666 |
667 | def setReactor(self, reactor):
668 | self.reactor = reactor
669 |
--------------------------------------------------------------------------------
/htcp/p2pnetwork/htcp/puncher.py:
--------------------------------------------------------------------------------
1 | #
2 | # Solipsis, a peer-to-peer serverless virtual world.
3 | # Copyright (C) 2002-2005 France Telecom R&D
4 | #
5 | # This software is free software; you can redistribute it and/or
6 | # modify it under the terms of the GNU Lesser General Public
7 | # License as published by the Free Software Foundation; either
8 | # version 2.1 of the License, or (at your option) any later version.
9 | #
10 | # This software is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | # Lesser General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU Lesser General Public
16 | # License along with this software; if not, write to the Free Software
17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 | #
19 |
20 | import twisted.internet.defer as defer
21 | from twisted.python import log, failure
22 | from twisted.internet import reactor
23 | import ConfigParser
24 |
25 | from p2pNetwork.htcp import punchProtocol
26 |
27 | stun_section = {
28 | 'servers': ('stun_servers', str, ""),
29 | }
30 |
31 |
32 | class _Puncher(punchProtocol.PunchPeer):
33 |
34 | def __init__(self, port = 0, config = (), id = '', *args, **kargs):
35 | super(_Puncher, self).__init__(*args, **kargs)
36 |
37 | # Load configuration
38 | p2pConfig = ConfigParser.ConfigParser()
39 | p2pConfig.read("p2pNetwork.conf")
40 |
41 | server = p2pConfig.get('holePunch', 'ConnectionBroker').split(':')
42 | server = (server[0], int(server[1]))
43 | self.setServer(server)
44 | self.privateAddr = (config[2][0], port)
45 | self.publicAddr = config[3]
46 | self.id = id
47 |
48 | def register(self, port, reactor, deferred):
49 |
50 | self.deferred = deferred
51 | self.port = port
52 | self.reactor = reactor
53 | self.listening = reactor.listenUDP(port, self)
54 | self.registration((self.id, self.publicAddr, self.privateAddr, ''))
55 |
56 | def connectionMade(self, addr = '', port = 0):
57 | """
58 | Called back when STUN discovered our public address.
59 | """
60 | print "Connection made!!!"
61 | if not self.deferred.called:
62 | pass
63 | #self.deferred.callback((addr, int(port)))
64 |
65 | def registrationMade(self):
66 | print "Registration made!!!"
67 |
68 | if not self.deferred.called:
69 | self.deferred.callback((self.transport, self))
70 |
71 | def Stop():
72 | pass
73 |
74 | def HolePunching(port, reactor, config, id):
75 | d = defer.Deferred()
76 | puncher = _Puncher(port, config, id)
77 |
78 | # Define timeout callback
79 | def _timeout():
80 | puncher.Stop()
81 | d.errback(Exception("timed out with servers %s" % servers))
82 | # Define intermediary succeed callback
83 | def _succeed(value):
84 | # Don't stop: continue to listen on the same port
85 | #discovery.Stop(reactor)
86 | return value
87 | def _fail(failure):
88 | print "Discovery result:", failure.getErrorMessage()
89 | d.errback(failure)
90 | return failure
91 |
92 | d.addCallback(_succeed)
93 | d.addErrback(_fail)
94 | # Start listening
95 | puncher.register(port, reactor, d)
96 | return d, puncher
97 |
98 |
99 | def connectByURI(URI, netconf, id, transport, port):
100 | d = defer.Deferred()
101 | discovery = _Puncher(port, netconf, id)
102 |
103 | # Define intermediary succeed callback
104 | def _succeed(value):
105 | # Don't stop: continue to listen on the same port
106 | #discovery.Stop(reactor)
107 | return value
108 | def _fail(failure):
109 | print "Discovery result:", failure.getErrorMessage()
110 | d.errback(failure)
111 | return failure
112 |
113 | d.addCallback(_succeed)
114 | d.addErrback(_fail)
115 |
116 | discovery.connectByURI(URI)
117 |
--------------------------------------------------------------------------------
/htcp/p2pnetwork/stun/.stun.py.swp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/myrual/python-stun/6d1477a42397c6c57ebfeddc79b223170448f998/htcp/p2pnetwork/stun/.stun.py.swp
--------------------------------------------------------------------------------
/htcp/p2pnetwork/stun/__init__.py:
--------------------------------------------------------------------------------
1 |
2 | # Twisted, the Framework of Your Internet
3 | # Copyright (C) 2001 Matthew W. Lefkowitz
4 | #
5 | # This library is free software; you can redistribute it and/or
6 | # modify it under the terms of version 2.1 of the GNU Lesser General Public
7 | # License as published by the Free Software Foundation.
8 | #
9 | # This library is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | # Lesser General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU Lesser General Public
15 | # License along with this library; if not, write to the Free Software
16 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 |
18 | """
19 |
20 | Twisted Internet: Asynchronous I/O and Events.
21 |
22 | """
23 |
--------------------------------------------------------------------------------
/htcp/p2pnetwork/stun/server.py:
--------------------------------------------------------------------------------
1 | from twisted.internet.protocol import DatagramProtocol
2 | from twisted.internet import reactor
3 | from p2pNetwork.stun.stun import StunServer
4 |
5 |
6 | import struct, socket, time, logging
7 |
8 | stun = StunServer()
9 |
10 | class MessageReceived(StunServer):
11 |
12 | def __init__(self):
13 | pass
14 |
15 | reactor.listenUDP(3478, MessageReceived())
16 | reactor.listenUDP(3479, MessageReceived())
17 | reactor.run()
18 |
--------------------------------------------------------------------------------
/htcp/p2pnetwork/stun/stun.py:
--------------------------------------------------------------------------------
1 | #
2 | # Solipsis, a peer-to-peer serverless virtual world.
3 | # Copyright (C) 2002-2005 France Telecom R&D
4 | #
5 | # This software is free software; you can redistribute it and/or
6 | # modify it under the terms of the GNU Lesser General Public
7 | # License as published by the Free Software Foundation; either
8 | # version 2.1 of the License, or (at your option) any later version.
9 | #
10 | # This software is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | # Lesser General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU Lesser General Public
16 | # License along with this software; if not, write to the Free Software
17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 | #
19 |
20 | import struct, socket, time, logging
21 |
22 | from twisted.internet import reactor, defer
23 | from twisted.internet.protocol import DatagramProtocol
24 | from twisted.python import log, failure
25 | import ConfigParser
26 |
27 |
28 | # This should be replaced with lookups of
29 | # _stun._udp.divmod.com and _stun._udp.wirlab.net
30 | DefaultServers = [
31 | ('stun.xten.net', 3478),
32 | ('sip.iptel.org', 3478),
33 | ('stun2.wirlab.net', 3478),
34 | ('stun.wirlab.net', 3478),
35 | ('stun1.vovida.org', 3478),
36 | ('tesla.divmod.net', 3478),
37 | ('erlang.divmod.net', 3478),
38 | ]
39 |
40 | # The Message Types
41 | StunTypes = {
42 | 0x0001: "Binding Request",
43 | 0x0101: "Binding Response",
44 | 0x0111: "Binding Error Response",
45 | 0x0002: "Shared Secret Request",
46 | 0x0102: "Shared Secret Response",
47 | 0x0112: "Shared Secret Error Response"
48 | }
49 |
50 | # The Message Attributes types
51 | StunAttributes = {
52 | 0x0001: 'MAPPED-ADDRESS',
53 | 0x0002: 'RESPONSE-ADDRESS',
54 | 0x0003: 'CHANGE-REQUEST',
55 | 0x0004: 'SOURCE-ADDRESS',
56 | 0x0005: 'CHANGED-ADDRESS',
57 | 0x0006: 'USERNAME',
58 | 0x0007: 'PASSWORD',
59 | 0x0008: 'MESSAGE-INTEGRITY',
60 | 0x0009: 'ERROR-CODE',
61 | 0x000a: 'UNKNOWN-ATTRIBUTES',
62 | 0x000b: 'REFLECTED-FROM',
63 | }
64 |
65 | # The Error Code
66 | responseCodes = {
67 | 400 : 'Bad Request',
68 | 420 : 'Unknown attribute',
69 | 431 : 'Integrity Check Failure',
70 | 500 : 'Server Error',
71 | 600 : 'Global Failure'
72 | }
73 |
74 | import os
75 | if os.path.exists('/dev/urandom'):
76 | def getRandomTID():
77 | return open('/dev/urandom').read(16)
78 | else:
79 | def getRandomTID():
80 | # It's not necessary to have a particularly strong TID here
81 | import random
82 | tid = [ chr(random.randint(0,255)) for x in range(16) ]
83 | tid = ''.join(tid)
84 | return tid
85 |
86 | # ============================================================================
87 | # The STUN protocol client/server methods
88 | # ============================================================================
89 | class StunProtocol(DatagramProtocol, object):
90 |
91 | def __init__(self, servers=DefaultServers, *args, **kwargs):
92 | self._pending = {}
93 | self.servers = servers
94 | super(StunProtocol, self).__init__(*args, **kwargs)
95 |
96 | # Initialise the variable
97 | avtypeList = {}
98 | mt, pktlen, tid = (0, 0, '0')
99 | toAddr = ('0.0.0.0', 0)
100 |
101 | def datagramReceived(self, dgram, address):
102 | """Called when a message is arrived"""
103 | try:
104 | self.stopTimeout()
105 | except:
106 | pass
107 |
108 | print 'Received message from:' , address
109 | self.parseMessage(dgram)
110 | self.analyseMessage(address)
111 |
112 | def parseMessage(self, dgram):
113 | """Parse the message received"""
114 | self.avtypeList = {}
115 | # Header
116 | self.mt, self.pktlen, self.tid = struct.unpack('!hh16s', dgram[:20])
117 | # Payload
118 | remainder = dgram[20:]
119 | while remainder:
120 | avtype, avlen = struct.unpack('!hh', remainder[:4])
121 | val = remainder[4:4+avlen]
122 | avtype = StunAttributes.get(avtype, 'Unknown type:%04x'%avtype)
123 | self.avtypeList[avtype] = val
124 | remainder = remainder[4+avlen:]
125 |
126 | def send(self, to, avpairs=()):
127 | """Pack the response and send it to the client"""
128 |
129 | self.toAddr = to
130 | avstr = ''
131 | # add any attributes in Payload
132 | for a,v in avpairs:
133 | if a == 0x0001 or a == 0x0002 or a == 0x0004 \
134 | or a == 0x0005 or a == 0x000b:
135 | avstr = avstr + struct.pack( \
136 | '!hhccH4s', a, len(v), '0', '%d' % 0x01, int(v[:4]), v[4:])
137 |
138 | elif a == 0x0003 or a == 0x0000:
139 | avstr = avstr + struct.pack('!hhi', a, 4, int(v))
140 |
141 | elif a == 0x0009:
142 | err_class = int(v[0])
143 | number = int(v) - err_class*100
144 | phrase = responseCodes[int(v)]
145 | avstr = avstr + struct.pack( \
146 | '!hhi%ds' % len(phrase), a, 4 + len(phrase), \
147 | (err_class<<8) + number, phrase)
148 |
149 | elif a == 0x000a:
150 | avstr = avstr + struct.pack('!hh', a, len(v)*2)
151 | for unkAttr in v:
152 | avstr = avstr + struct.pack('!h', unkAttr)
153 |
154 | pktlen = len(avstr)
155 | if pktlen > 65535:
156 | raise ValueError, "stun request too big (%d bytes)" % pktlen
157 | # Add header and send
158 | self.pkt = struct.pack('!hh16s', self.mt, pktlen, self.tid) + avstr
159 | #print 'Send to:', self.toAddr
160 | self.transport.write(self.pkt, self.toAddr)
161 |
162 | def sendPack(self):
163 | """Send pack: used in retrasmission"""
164 | self.transport.write(self.pkt, self.toAddr)
165 |
166 | def blatServers(self):
167 | for s in self.servers:
168 | self.sendRequest(s)
169 |
170 | def gotMappedAddress(self, addr, port):
171 | """When the procedure has discovered the network configuration"""
172 |
173 | logging.info("got address %s %s (should I have been overridden?)" \
174 | % (addr, port))
175 |
176 |
177 | # ------- Implemented in server/client ----------
178 | def stopTimeout(self):
179 | pass
180 |
181 | def analyseMessage(self):
182 | pass
183 |
184 | def checkMessage(self):
185 | pass
186 |
187 | def Stop(self):
188 | """ Stop listening. """
189 | pass
190 |
191 |
192 | #=============================================================================
193 | # STUN Server
194 | # ============================================================================
195 | class StunServer(StunProtocol, object):
196 | """ The code for the server """
197 |
198 | # Load configuration
199 | config = ConfigParser.ConfigParser()
200 | config.read("p2pNetwork.conf")
201 | #config = ConfigData('p2pNetwork.p2pNetwork.conf')
202 | ## myAddress = (socket.gethostbyname(socket.gethostname()), \
203 | ## int(config.get('stun', 'stunPort')))
204 | ## myOtherAddress = (socket.gethostbyname(socket.gethostname()), \
205 | ## int(config.get('stun', 'otherStunPort')))
206 | myAddress = ('127.0.0.1', int(config.get('stun', 'stunPort')))
207 | myOtherAddress = ('127.0.0.1', int(config.get('stun', 'otherStunPort')))
208 | _otherStunServer = config.get('stun', 'otherStunServer').split(':')
209 | otherStunServer = (_otherStunServer[0], int(_otherStunServer[1]))
210 | _otherStunServer = config.get('stun', 'otherStunServerPort').split(':')
211 | otherStunServerPort = (_otherStunServer[0], int(_otherStunServer[1]))
212 |
213 |
214 | ## myAddress = (socket.gethostbyname(socket.gethostname()), 3478)
215 | ## myOtherAddress = (socket.gethostbyname(socket.gethostname()), 3479)
216 | ## otherRdvServer = ('127.0.0.1', 3478)
217 | ## otherRdvServerPort = ('127.0.0.1', 3479)
218 |
219 | def analyseMessage(self, fromAddr):
220 | """Analyse the message received"""
221 |
222 | self.responseType = 'Binding Response'
223 | listAttr = ()
224 | listUnkAttr = ()
225 | toAddr = fromAddr # reply to ...
226 | numUnkAttr = 0 # Number of unknown attributes
227 |
228 |
229 | if self.mt == 0x0001:
230 | # -------------------------------------------------------------
231 | # if binding request
232 | logging.info("got STUN request from %s" % repr(fromAddr))
233 | # response
234 | for avtype in self.avtypeList:
235 | # For all correct attributes
236 | if avtype == 'RESPONSE-ADDRESS':
237 | # Send the response to the address in RESPONSE-ADDRESS
238 | # and add REFLECTED-FROM attribute
239 | dummy,family,port,addr = struct.unpack('!ccH4s', self.avtypeList[avtype])
240 | toAddr = (socket.inet_ntoa(addr), port)
241 | listAttr = listAttr + ((0x000b, self.getPortIpList(self.myAddress)),)
242 | self.responseType = "Binding Response"
243 | elif avtype == 'CHANGE-REQUEST':
244 | change = (struct.unpack('!i', self.avtypeList[avtype]))[0]
245 | if change == 2:
246 | # change the source Port --> send from/to the other port
247 | # TODO: change reactor
248 | toAddr = self.myOtherAddress
249 | # RESPONSE-ADDRESS
250 | listAttr = listAttr + ((0x0002, self.getPortIpList(fromAddr)),)
251 | self.responseType = "Binding Request"
252 | elif change == 4:
253 | # change the source IP --> send from/to the other server
254 | toAddr = self.otherStunServer
255 | # RESPONSE-ADDRESS
256 | listAttr = listAttr + ((0x0002, self.getPortIpList(fromAddr)),)
257 | self.responseType = "Binding Request"
258 | elif change == 6:
259 | # change the source IP/Port --> send from/to the other server
260 | toAddr = self.otherStunServerPort
261 | #toAddr = self.myAddress
262 | # RESPONSE-ADDRESS
263 | listAttr = listAttr + ((0x0002, self.getPortIpList(fromAddr)),)
264 | self.responseType = "Binding Request"
265 | elif avtype[:12] == 'Unknown type':
266 | listAttr = listAttr + ((0x0009, '420'),) # ERROR-CODE
267 | unkAttr = int(avtype[13:])
268 | listUnkAttr = listUnkAttr + (unkAttr,)
269 | numUnkAttr+=1
270 | self.responseType = "Binding Error Response"
271 |
272 | # To respect that the total length of the list is a multiple of 4 bytes
273 | if numUnkAttr%2 != 0:
274 | listUnkAttr = listUnkAttr + (unkAttr,)
275 | if listUnkAttr != ():
276 | listAttr = listAttr + ((0x000a, listUnkAttr),)
277 |
278 | self.createResponse(toAddr, listAttr)
279 | else:
280 | # -------------------------------------------------------------
281 | # Other not implemented request
282 | listAttr = listAttr + ((0x0009, '400'),) # ERROR-CODE
283 | self.responseType = "Binding Error Response"
284 | self.createResponse(toAddr, listAttr)
285 | logging.error("STUN not implemented")
286 |
287 | def createResponse(self, toAddr, listAttr):
288 | """Pack the response and send it to the client"""
289 | avpairs = ()
290 | if self.responseType == "Binding Response":
291 | self.mt = 0x0101 # binding response
292 | # MAPPED-ADDRESS # SOURCE-ADDRESS # CHANGED-ADDRESS
293 | avpairs = avpairs + ((0x0001, self.getPortIpList(toAddr)),)
294 | avpairs = avpairs + ((0x0004, self.getPortIpList(self.myAddress)),)
295 | avpairs = avpairs + ((0x0005, self.getPortIpList(self.otherStunServer)),)
296 | elif self.responseType == "Binding Request":
297 | self.mt = 0x0001 # binding request (to other rdv server)
298 | elif self.responseType == "Binding Error Response":
299 | self.mt = 0x0111 # binding error response
300 |
301 | avpairs = avpairs + listAttr
302 | self.send(toAddr, avpairs)
303 |
304 | def getPortIpList(self, address):
305 | a, b, c, d = address[0].split('.')
306 | return '%d%c%c%c%c' % (address[1], int(a), int(b), int(c), int(d))
307 |
308 | #=============================================================================
309 | # STUN Client
310 | # ============================================================================
311 | class StunClient(StunProtocol, object):
312 |
313 | # A structure to save the client network configuration
314 | configurationText = ['NAT presence ', \
315 | 'NAT type ', \
316 | 'My private address', \
317 | 'My public address ', \
318 | 'Informations ']
319 |
320 | configuration = ['unknown', \
321 | 'unknown', \
322 | 'unknown:unknown', \
323 | 'unknown:unknown',\
324 | '...']
325 | # Initial timeout valor
326 | stun_timeout = 0.1
327 |
328 | # For the tests like in rfc 3489
329 | test = 1
330 | addressMatch = 1
331 | oldMappedAddress = ''
332 |
333 | def stopTimeout(self):
334 | """Stops the active timeout"""
335 | self.timeout.cancel()
336 | # Reinitialise variables
337 | self.stun_timeout = 0.1
338 | self.request = 1
339 |
340 | def analyseMessage(self, address):
341 | """
342 | Analyse the server's response
343 | """
344 |
345 | listAttr = ()
346 | ## self.configuration[2] = (socket.gethostbyname(socket.gethostname()), \
347 | ## self.listenPort)
348 | self.configuration[2] = ('127.0.0.1', self.listenPort)
349 |
350 | # Check tid is one we sent and haven't had a reply to yet
351 | if self._pending.has_key(self.tid):
352 | del self._pending[self.tid]
353 | else:
354 | logging.error("Error, unknown transaction ID %s, have %r" \
355 | % (self.tid, self._pending.keys()))
356 | return
357 |
358 | if self.mt == 0x0101:
359 | # -------------------------------------------------------------
360 | # binding response
361 |
362 | dummy,family,port,addr = struct.unpack( \
363 | '!ccH4s', self.avtypeList["MAPPED-ADDRESS"])
364 | mappedAddress = (socket.inet_ntoa(addr), port)
365 |
366 | if self.test == 1:
367 | # ********************************************************
368 | # If it's in the first test (see rfc3489)
369 |
370 | if self.addressMatch:
371 | # It's the first test 1
372 | if mappedAddress[0] == self.configuration[2][0] :
373 | print ' >> test 1 (first time): address match'
374 | self.addressMatch = 1
375 | # No NAT !!!
376 | self.configuration[0] = "none"
377 | self.configuration[1] = "none"
378 |
379 | # It does test 2
380 | print " # Start test 2"
381 | self.test = 2
382 | listAttr = listAttr + ((0x0003, 6),) # CHANGE-REQUEST
383 | self.sendRequest(address, listAttr)
384 | return
385 | else :
386 | print(' >> test 1 (first time): address does not match')
387 | self.addressMatch = 0
388 | # Behind a NAT !!!
389 | self.configuration[0] = "Yes"
390 | # It does test 2
391 | print(" # Start test 2")
392 | self.test = 2
393 | listAttr = listAttr + ((0x0003, 6),) # CHANGE-REQUEST
394 | self.sendRequest(address, listAttr)
395 | return
396 | else:
397 | # It's the second time test 1
398 | if self.oldMappedAddress != mappedAddress:
399 | # Symmetric NAT --> exit
400 | print ' >> test 1 (second time): address does not match'
401 | self.configuration[1] = 'Symmetric'
402 | self.configuration[3] = mappedAddress
403 | self.gotMappedAddress(socket.inet_ntoa(addr),port)
404 | return
405 | else:
406 | # Either behind a restricted or port restricted NAT
407 | # It does test 3
408 | print ' >> test 1 (second time): address match'
409 | print(" # Start test 3")
410 | self.configuration[3] = self.oldMappedAddress
411 | self.test = 3
412 | listAttr = listAttr + ((0x0003, 2),) # CHANGE-REQUEST
413 | self.sendRequest(address, listAttr)
414 | return
415 |
416 | elif self.test == 2:
417 | # ********************************************************
418 | # If it's in the second test (see rfc3489)
419 |
420 | if self.addressMatch:
421 | # Open access to internet
422 | print(' >> test 2: address matched ')
423 | self.configuration[3] = self.configuration[2]
424 | self.configuration[4] = "Open access to internet"
425 | self.gotMappedAddress(socket.inet_ntoa(addr),port)
426 | return
427 | else:
428 | #Full cone NAT
429 | print(' >> test 2: address did not match ')
430 | self.configuration[1] = "Full cone"
431 | self.configuration[3] = mappedAddress
432 | self.gotMappedAddress(socket.inet_ntoa(addr),port)
433 | return
434 |
435 | elif self.test == 3:
436 | # ********************************************************
437 | # If it's in the third test (see rfc3489)
438 |
439 | # Restricted NAT
440 | self.configuration[1] = "Restricted cone"
441 | self.configuration[3] = mappedAddress[0], 'unknown'
442 | self.gotMappedAddress(socket.inet_ntoa(addr),port)
443 | return
444 |
445 | return
446 |
447 | elif self.mt == 0x0111:
448 | # -------------------------------------------------------------
449 | # Binding Error Response
450 | logging.error("STUN got an error response:")
451 | # Extract the class and number
452 | error, phrase = self.getErrorCode()
453 | if error == 420:
454 | _listUnkAttr = self.getListUnkAttr()
455 | logging.error((error, phrase, _listUnkAttr))
456 | else:
457 | logging.error((error, phrase))
458 | else:
459 | logging.error("STUN got unknown message")
460 |
461 | def sendRequest(self, server, avpairs=()):
462 | """Send the initial request
463 | to discover network configuration"""
464 |
465 | self.tid = getRandomTID()
466 | self.mt = 0x0001 # binding request
467 | self._pending[self.tid] = (time.time(), server)
468 | self.stun_timeout = 0.1
469 | self.request = 1
470 | self.server = server
471 | # Start timeout and send message
472 | self.timeout = reactor.callLater(self.stun_timeout, self._timeout)
473 | self.send(self.server, avpairs)
474 |
475 | def _timeout(self):
476 | """If a timeout is expired
477 | Send 9 message at:
478 | 0ms, 100ms, 300ms, 700ms, 1500ms, 3100ms, 4700ms, 6300ms, 7900ms
479 | """
480 | self.request += 1
481 | if self.request == 10:
482 | self.retransmissionEnded()
483 | return
484 | if self.stun_timeout < 1.6:
485 | self.stun_timeout = 2 * self.stun_timeout
486 | # Re-send message
487 | self.timeout = reactor.callLater(self.stun_timeout, self._timeout)
488 | self.sendPack()
489 |
490 | def retransmissionEnded(self):
491 | """Transaction have failed (called at 9500ms)"""
492 |
493 | self.stun_timeout = 0.1
494 | self.request = 1
495 |
496 | if self.test == 1:
497 | # ********************************************************
498 | # If it's in the first test (see rfc3489)
499 | # UDP blocked --> exit
500 | print ' >> test 1 (first time)(timeout): UDP blocked'
501 | self.configuration[4] = 'UDP blocked'
502 | self.deferred.errback(failure.DefaultException("UDP blocked"))
503 | return
504 |
505 | elif self.test == 2:
506 | # ********************************************************
507 | # If it's in the second test (see rfc3489)
508 | if self.addressMatch:
509 | # Symmetric UDP Firewall --> exit
510 | print ' >> test 2 (timeout): Symmetric UDP Firewall'
511 | self.configuration[4] = 'Symmetric UDP Firewall'
512 | self.gotMappedAddress(self.configuration[2])
513 | return
514 | else:
515 | # Start Test 1 (second time)
516 | print ' >> test 2 (timeout)'
517 | print " # Start test 1 (second time)"
518 | dummy,family,port,addr = struct.unpack( \
519 | '!ccH4s', self.avtypeList["MAPPED-ADDRESS"])
520 | mappedAddress = (socket.inet_ntoa(addr), port)
521 | self.oldMappedAddress = mappedAddress
522 | self.test = 1
523 | dummy,family,port,addr = struct.unpack( \
524 | '!ccH4s', self.avtypeList["CHANGED-ADDRESS"])
525 | server = (socket.inet_ntoa(addr), port)
526 | self.sendRequest(server)
527 | return
528 |
529 | # If it's in the third test (see rfc3489)
530 | elif self.test == 3:
531 | # Port restricted
532 | print ' >> test 3 (timeout): Port Restricted cone'
533 | self.configuration[1] = "Port Restricted cone"
534 | self.gotMappedAddress(self.configuration[3])
535 | return
536 |
537 | return
538 |
539 | def getErrorCode(self):
540 | """If an error occurred: return the error code"""
541 |
542 | # Extract the class and number
543 | error, phrase = struct.unpack('!i%ds' % (len(self.avtypeList["ERROR-CODE"])-4), \
544 | self.avtypeList["ERROR-CODE"])
545 | number = error - ((error>>8)<<8)
546 | err_class = ((error - number)>>8)*100
547 | return err_class + number, phrase
548 |
549 | def getListUnkAttr(self):
550 | """Return the list of Unknown attributes"""
551 |
552 | _listUnkAttr = ()
553 | listUnkAttr = struct.unpack( \
554 | '!%dh' % int(len(self.avtypeList["UNKNOWN-ATTRIBUTES"])/2), \
555 | self.avtypeList["UNKNOWN-ATTRIBUTES"])
556 | for attr in listUnkAttr:
557 | _listUnkAttr = _listUnkAttr + ('0x%04x'%attr,)
558 | return _listUnkAttr
559 |
560 | def printConfiguration(self):
561 | """ Print the client's network configuration """
562 |
563 | print "\n*---------------------------------------------------------------*"
564 | print "Configuration:\n"
565 | for i in range(0,5):
566 | print "\t", self.configurationText[i], "\t", self.configuration[i]
567 | print "*---------------------------------------------------------------*"
568 |
569 | def getConfiguration(self):
570 | """Gets a list with the network configuration:
571 | (NAT presence, NAT type, private address, public address)"""
572 | return self.configuration
573 |
574 | def getNATType(self):
575 | """Returns the NAT's type"""
576 | return self.configuration[1]
577 |
578 | def getPrivateAddress(self):
579 | """Retruns the client's private address"""
580 | return self.configuration[2]
581 |
582 | def getPublicAddress(self):
583 | """Retruns the client's public address"""
584 | return self.configuration[3]
585 |
--------------------------------------------------------------------------------
/htcp/p2pnetwork/testtcp/natTravCB.py:
--------------------------------------------------------------------------------
1 | # Echo server program
2 | import socket
3 | import sys, time
4 | from twisted.internet import reactor
5 | from twisted.internet.protocol import Protocol, ClientFactory
6 | from twisted.internet.protocol import DatagramProtocol
7 | from twisted.internet import threads
8 | import twisted.internet.defer as defer
9 |
10 | import signal, os
11 | import random
12 | import p2pNetwork.testTCP.sniffer as sniffer
13 | from impacket import ImpactPacket
14 |
15 |
16 | class ConnectionBroker(DatagramProtocol):
17 | """Listen on UDP port for the two SYNs from peers"""
18 |
19 | def __init__(self):
20 | self.t = [0, 0]
21 | #self.t[1] = (('10.193.161.57', 50007), random.randint(0, 9999) )
22 | self.msg_from_peer = 0
23 |
24 | def datagramReceived(self, data, addr):
25 | print "received %r from:" % (data), addr
26 | self.msg_from_peer += 1
27 | self.t[self.msg_from_peer-1] = (addr, int(data))
28 |
29 | if self.msg_from_peer == 2:
30 | self.msg_from_peer = 0
31 | b = Broker()
32 | b.fakeConnection(self.t)
33 |
34 |
35 |
36 |
37 | class Broker(Protocol):
38 | """Broke the NAT firewall sending spoofed packet"""
39 |
40 | def __init__(self):
41 |
42 | # Start to sniff packets
43 | # run method in thread and get result as defer.Deferred
44 | #reactor.callInThread(sniffer.sniff, self)
45 | pass
46 |
47 | #=================================================================
48 | def fakeConnection(self, table):
49 |
50 | for i in (0, 1):
51 | port = 50007
52 | dhost = table[i][0][0] # The remote host
53 | shost = table[(i+1)%2][0][0] # The source host
54 | dport = port # The same port as used by the server
55 | sport = dport # The source port
56 |
57 | SYN = table[(i+1)%2][1]
58 | ACK = table[i][1]+1
59 |
60 | # Create a new IP packet and set its source and destination addresses.
61 | ip = ImpactPacket.IP()
62 | print 'IPs:', shost, dhost
63 | ip.set_ip_src(shost)
64 | ip.set_ip_dst(dhost)
65 |
66 | # Create a new TCP
67 | tcp = ImpactPacket.TCP()
68 |
69 | # Set the parameters for the connection
70 | print 'Ports:', sport, dport
71 | tcp.set_th_sport(sport)
72 | tcp.set_th_dport(dport)
73 | print 'SYN-ACK:', SYN, ACK
74 | tcp.set_th_seq(SYN)
75 | tcp.set_SYN()
76 | tcp.set_th_ack(ACK)
77 | tcp.set_ACK()
78 |
79 |
80 | # Have the IP packet contain the TCP packet
81 | ip.contains(tcp)
82 |
83 | # Open a raw socket. Special permissions are usually required.
84 | protocol_num = socket.getprotobyname('tcp')
85 | self.s = socket.socket(socket.AF_INET, socket.SOCK_RAW, protocol_num)
86 | self.s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
87 | #self._bind()
88 |
89 | # Calculate its checksum.
90 | tcp.calculate_checksum()
91 | tcp.auto_checksum = 1
92 |
93 | # Send it to the target host.
94 | self.s.sendto(ip.get_packet(), (dhost, dport))
95 |
96 | def connection(self):
97 | """DEPRECATED"""
98 | RHOST = '10.193.161.93' # The remote host
99 | RPORT = 50007 # The same port as used by the server
100 |
101 | self._bind()
102 |
103 | # Start timeout and try to connect
104 | print 'Try to connect...'
105 | time.sleep(1)
106 | self.s.connect((RHOST, RPORT))
107 | print 'connection made'
108 |
109 | def _sniffed(self, packet):
110 | """Print infos on sniffed packet"""
111 |
112 | print 'Packet sniffed'
113 | print packet
114 | print 'SYNn:', packet.child().get_th_seq()
115 | print 'SYN:', packet.child().get_SYN()
116 | print 'ACK:', packet.child().get_ACK()
117 | print 'ACKn:', packet.child().get_th_ack()
118 |
119 | ## if __name__ == '__main__':
120 | ## b = Broker()
121 | ## b.fakeConnection(sys.argv, len(sys.argv))
122 |
123 | reactor.listenUDP(9999, ConnectionBroker())
124 | reactor.run()
125 |
--------------------------------------------------------------------------------
/htcp/p2pnetwork/testtcp/sniff.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 |
3 | import sys
4 | import pcap
5 | import string
6 | import time
7 | import socket
8 | import struct
9 |
10 | from twisted.internet.protocol import DatagramProtocol
11 | from twisted.internet import reactor
12 | import p2pNetwork.testTCP.spoof as spoof
13 |
14 | protocols={socket.IPPROTO_TCP:'tcp',
15 | socket.IPPROTO_UDP:'udp',
16 | socket.IPPROTO_ICMP:'icmp'}
17 |
18 | def decode_ip_packet(s):
19 | d={}
20 | d['version']=(ord(s[0]) & 0xf0) >> 4
21 | d['header_len']=ord(s[0]) & 0x0f
22 | d['tos']=ord(s[1])
23 | d['total_len']=socket.ntohs(struct.unpack('H',s[2:4])[0])
24 | d['id']=socket.ntohs(struct.unpack('H',s[4:6])[0])
25 | d['flags']=(ord(s[6]) & 0xe0) >> 5
26 | d['fragment_offset']=socket.ntohs(struct.unpack('H',s[6:8])[0] & 0x1f)
27 | d['ttl']=ord(s[8])
28 | d['protocol']=ord(s[9])
29 | d['checksum']=socket.ntohs(struct.unpack('H',s[10:12])[0])
30 | #d['source_address']=pcap.ntoa(struct.unpack('i',s[12:16])[0])
31 | #d['destination_address']=pcap.ntoa(struct.unpack('i',s[16:20])[0])
32 | d['source_address']='?'
33 | d['destination_address']='?'
34 | if d['header_len']>5:
35 | d['options']=s[20:4*(d['header_len']-5)]
36 | else:
37 | d['options']=None
38 | d['data']=s[4*d['header_len']:]
39 | decode_tcp_packet(d['data'], d)
40 | return d
41 |
42 | def decode_tcp_packet(s, d):
43 | d['synno']=struct.unpack('!L', s[4:8])[0]
44 | d['ackno']=struct.unpack('!L', s[8:12])[0]
45 |
46 |
47 | def dumphex(s):
48 | bytes = map(lambda x: '%.2x' % x, map(ord, s))
49 | for i in xrange(0,len(bytes)/16):
50 | print ' %s' % string.join(bytes[i*16:(i+1)*16],' ')
51 | print ' %s' % string.join(bytes[(i+1)*16:],' ')
52 |
53 |
54 | def print_packet(timestamp, data, arg=''):
55 | if not data:
56 | return
57 |
58 | if data[12:14]=='\x08\x00':
59 | decoded=decode_ip_packet(data[14:])
60 | print '\n%s.%f %s > %s' % (time.strftime('%H:%M',
61 | time.localtime(timestamp)),
62 | timestamp % 60,
63 | decoded['source_address'],
64 | decoded['destination_address'])
65 | for key in ['version', 'header_len', 'tos', 'total_len', 'id',
66 | 'flags', 'fragment_offset', 'ttl']:
67 | print ' %s: %d' % (key, decoded[key])
68 | print ' protocol: %s' % protocols[decoded['protocol']]
69 | print ' header checksum: %d' % decoded['checksum']
70 | print ' data:'
71 | dumphex(decoded['data'])
72 | print ' SYNno:', decoded['synno']
73 | print ' ACKno:', decoded['ackno']
74 |
75 |
76 |
77 |
78 |
79 | #if __name__=='__main__':
80 | def sniff(argv, udp_obj):
81 | """Sniff packets using pcap libriry
82 | and call the method to send the SYN nomber to hte peer
83 | or to Connection Broker"""
84 |
85 | sys.argv = argv
86 | if len(sys.argv) < 3:
87 | print 'usage: sniff.py '
88 | sys.exit(0)
89 |
90 | dev = sys.argv[1]
91 | #p = pcap.pcap(dev)
92 | p = pcap.pcapObject()
93 | #dev = pcap.lookupdev()
94 | net, mask = pcap.lookupnet(dev)
95 | # note: to_ms does nothing on linux
96 | p.open_live(dev, 1600, 0, 100)
97 | #p.dump_open('dumpfile')
98 | p.setfilter(string.join(sys.argv[2:],' '), 0, 0)
99 |
100 | # try-except block to catch keyboard interrupt. Failure to shut
101 | # down cleanly can result in the interface not being taken out of promisc.
102 | # mode
103 | #p.setnonblock(1)
104 | #udp_obj = UDP_factory()
105 | #reactor.run()
106 | udp_obj.punchHole()
107 | try:
108 | while 1:
109 | #for ts, pkt in p:
110 | #for i in range(1,9):
111 | #print i
112 | #print_packet(ts, pkt)
113 | #p.dispatch(print_packet, -1)
114 | p.dispatch(1, udp_obj.send_SYN_to_ConnectionBroker)
115 | #p.loop(1, udp_obj.send_SYN_to_ConnectionBroker)
116 |
117 | #udp_obj.send_SYN_to_ConnectionBroker(ts, pkt)
118 | #break
119 | print 'break'
120 | break
121 | # specify 'None' to dump to dumpfile, assuming you have called
122 | # the dump_open method
123 | # p.dispatch(0, None)
124 |
125 | # the loop method is another way of doing things
126 | # p.loop(1, print_packet)
127 |
128 | # as is the next() method
129 | # p.next() returns a (pktlen, data, timestamp) tuple
130 | # apply(print_packet,p.next())
131 | except KeyboardInterrupt:
132 | print '%s' % sys.exc_type
133 | print 'shutting down'
134 | print '%d packets received, %d packets dropped, %d packets dropped by interface' % p.stats()
135 |
136 |
137 |
--------------------------------------------------------------------------------
/htcp/p2pnetwork/testtcp/sniffer.py:
--------------------------------------------------------------------------------
1 | from select import select
2 | import socket
3 | import sys
4 |
5 | import impacket
6 | from impacket import ImpactDecoder
7 | from impacket import ImpactPacket
8 |
9 | import twisted.internet.defer as defer
10 |
11 | DEFAULT_PROTOCOLS = ('tcp',)
12 |
13 | toListen = DEFAULT_PROTOCOLS
14 |
15 | # A special option is set on the socket so that IP headers are included with
16 | # the returned data.
17 | def sniff(traverser):
18 | """Just a sniffer"""
19 |
20 | sniff_deferred = defer.Deferred()
21 |
22 | sockets = []
23 | for protocol in toListen:
24 | try:
25 | protocol_num = socket.getprotobyname(protocol)
26 | except socket.error:
27 | print "Ignoring unknown protocol:", protocol
28 | toListen.remove(protocol)
29 | continue
30 | s = socket.socket(socket.AF_INET, socket.SOCK_RAW, protocol_num)
31 | s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
32 | sockets.append(s)
33 |
34 | if 0 == len(toListen):
35 | print "There are no protocols available."
36 | sys.exit(0)
37 |
38 | print "Listening on protocols:", toListen
39 |
40 | # Instantiate an IP packets decoder.
41 | # As all the packets include their IP header, that decoder only is enough.
42 | decoder = ImpactDecoder.IPDecoder()
43 |
44 | while len(sockets) > 0:
45 | # Wait for an incoming packet on any socket.
46 | ready = select(sockets, [], [])[0]
47 | for s in ready:
48 | packet = s.recvfrom(4096)[0]
49 | if 0 == len(packet):
50 | # Socket remotely closed. Discard it.
51 | sockets.remove(s)
52 | s.close()
53 | else:
54 | # Packet received. Decode and display it.
55 | packet = decoder.decode(packet)
56 | #print packet.get_ip_src(), packet.child().get_th_sport()
57 | if isinstance(packet.child(),ImpactPacket.TCP) and \
58 | packet.child().get_th_sport() > 50000:
59 | traverser._sniffed(packet)
60 |
--------------------------------------------------------------------------------
/htcp/p2pnetwork/testtcp/spoof.py:
--------------------------------------------------------------------------------
1 | import socket
2 | import sys, time
3 |
4 | import signal, os
5 | from impacket import ImpactPacket
6 | from impacket import ImpactDecoder
7 |
8 | class Spoofer:
9 | """Send a spoofed TCP packet
10 | USAGE: IP-destination port IP-source SYNno ACKno"""
11 |
12 | def __init__(self):
13 | pass
14 |
15 | #=================================================================
16 | def fakeConnection(self, argv, argc):
17 |
18 | dhost = argv[1] # The remote host
19 | dport = int(argv[2]) # The same port as used by the server
20 | sport = dport # The source port
21 | shost = argv[3] # The source host
22 |
23 | if argc >= 5:
24 | SYN = int(argv[4])
25 | if argc == 6:
26 | ACK = int(argv[5])
27 |
28 | # Create a new IP packet and set its source and destination addresses.
29 | ip = ImpactPacket.IP()
30 | ip.set_ip_src(shost)
31 | ip.set_ip_dst(dhost)
32 |
33 | # Create a new TCP
34 | tcp = ImpactPacket.TCP()
35 |
36 | # Set the parameters for the connection
37 | tcp.set_th_sport(sport)
38 | tcp.set_th_dport(dport)
39 | tcp.set_th_seq(SYN)
40 | tcp.set_SYN()
41 | if argc == 6:
42 | tcp.set_th_ack(ACK)
43 | tcp.set_ACK()
44 |
45 |
46 | # Have the IP packet contain the TCP packet
47 | ip.contains(tcp)
48 |
49 | # Open a raw socket. Special permissions are usually required.
50 | protocol_num = socket.getprotobyname('tcp')
51 | self.s = socket.socket(socket.AF_INET, socket.SOCK_RAW, protocol_num)
52 | self.s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
53 |
54 | # Calculate its checksum.
55 | tcp.calculate_checksum()
56 | tcp.auto_checksum = 1
57 |
58 | # Send it to the target host.
59 | self.s.sendto(ip.get_packet(), (dhost, dport))
60 |
61 | # Instantiate an IP packets decoder.
62 | # As all the packets include their IP header, that decoder only is enough.
63 | ## decoder = ImpactDecoder.IPDecoder()
64 |
65 | ## while 1:
66 | ## packet = self.s.recvfrom(4096)[0]
67 | ## # Packet received. Decode and display it.
68 | ## packet = decoder.decode(packet)
69 | ## print 'source:', packet.get_ip_src()
70 | ## #print packet.get_ip_src(), packet.child().get_th_sport()
71 | ## if isinstance(packet.child(),ImpactPacket.TCP) and \
72 | ## packet.child().get_th_sport() > 50000:
73 | ## self._sniffed(packet)
74 |
75 | def _bind(self, shost):
76 | HOST = shost # Symbolic name meaning the local host
77 | PORT = 50007 # Arbitrary non-privileged port
78 | self.stcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
79 | #self.stcp.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
80 | self.stcp.bind((HOST, PORT))
81 |
82 | def _sniffed(self, packet):
83 | print 'Packet sniffed'
84 | print packet
85 | print 'SYN:', packet.child().get_SYN()
86 | print 'SYNn:', packet.child().get_th_seq()
87 | print 'ACK:', packet.child().get_ACK()
88 | print 'ACKn:', packet.child().get_th_ack()
89 |
90 | if __name__ == '__main__':
91 | p = Spoofer()
92 | p.fakeConnection(sys.argv, len(sys.argv))
93 |
94 |
95 |
--------------------------------------------------------------------------------
/htcp/p2pnetwork/testtcp/spoofSniffer.py:
--------------------------------------------------------------------------------
1 | import socket
2 | import sys, time
3 |
4 | import signal, os
5 | from impacket import ImpactPacket
6 | from impacket import ImpactDecoder
7 |
8 | class Spoofer:
9 | """Send a spoofed TCP packet and listen to spoof packets
10 | USAGE: IP-destination port IP-source SYNno ACKno"""
11 |
12 | def __init__(self):
13 | pass
14 |
15 | #=================================================================
16 | def fakeConnection(self, argv, argc):
17 |
18 | dhost = argv[1] # The remote host
19 | dport = int(argv[2]) # The same port as used by the server
20 | sport = dport # The source port
21 | shost = argv[3] # The source host
22 |
23 | if argc >= 5:
24 | SYN = int(argv[4])
25 | if argc == 6:
26 | ACK = int(argv[5])
27 |
28 | # Create a new IP packet and set its source and destination addresses.
29 | ip = ImpactPacket.IP()
30 | ip.set_ip_src(shost)
31 | ip.set_ip_dst(dhost)
32 |
33 | # Create a new TCP
34 | tcp = ImpactPacket.TCP()
35 |
36 | # Set the parameters for the connection
37 | tcp.set_th_sport(sport)
38 | tcp.set_th_dport(dport)
39 | tcp.set_th_seq(SYN)
40 | tcp.set_SYN()
41 | if argc == 6:
42 | tcp.set_th_ack(ACK)
43 | tcp.set_ACK()
44 |
45 |
46 | # Have the IP packet contain the TCP packet
47 | ip.contains(tcp)
48 |
49 | # Open a raw socket. Special permissions are usually required.
50 | protocol_num = socket.getprotobyname('tcp')
51 | self.s = socket.socket(socket.AF_INET, socket.SOCK_RAW, protocol_num)
52 | self.s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
53 |
54 | # Calculate its checksum.
55 | tcp.calculate_checksum()
56 | tcp.auto_checksum = 1
57 |
58 | # Send it to the target host.
59 | self.s.sendto(ip.get_packet(), (dhost, dport))
60 |
61 | # Instantiate an IP packets decoder.
62 | # As all the packets include their IP header, that decoder only is enough.
63 | decoder = ImpactDecoder.IPDecoder()
64 |
65 | while 1:
66 | packet = self.s.recvfrom(4096)[0]
67 | # Packet received. Decode and display it.
68 | packet = decoder.decode(packet)
69 | print 'source:', packet.get_ip_src()
70 | #print packet.get_ip_src(), packet.child().get_th_sport()
71 | if isinstance(packet.child(),ImpactPacket.TCP) and \
72 | packet.child().get_th_sport() > 50000:
73 | self._sniffed(packet)
74 |
75 | def _bind(self, shost):
76 | HOST = shost # Symbolic name meaning the local host
77 | PORT = 50007 # Arbitrary non-privileged port
78 | self.stcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
79 | #self.stcp.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
80 | self.stcp.bind((HOST, PORT))
81 |
82 | def _sniffed(self, packet):
83 | print 'Packet sniffed'
84 | print packet
85 | print 'SYN:', packet.child().get_SYN()
86 | print 'SYNn:', packet.child().get_th_seq()
87 | print 'ACK:', packet.child().get_ACK()
88 | print 'ACKn:', packet.child().get_th_ack()
89 |
90 | if __name__ == '__main__':
91 | p = Spoofer()
92 | p.fakeConnection(sys.argv, len(sys.argv))
93 |
94 |
95 |
--------------------------------------------------------------------------------
/htcp/p2pnetwork/testtcp/testTCPcl.py:
--------------------------------------------------------------------------------
1 | from twisted.internet.protocol import Protocol, ClientFactory, Factory
2 | from twisted.internet import reactor
3 | from twisted.internet import threads
4 | from sys import stdout, stdin
5 |
6 | import sys
7 | import socket
8 | import time
9 |
10 | import p2pNetwork.testTCP.sniffy as sniffer
11 | import p2pNetwork.testTCP.udpSniffer as udp_sniffer
12 |
13 | class Echo(Protocol):
14 | """A test for TCP connection:
15 | - a normal TCP connection
16 | - with a thread to simulate the simultaneous TCP initiation"""
17 |
18 | def dataReceived(self, data = ''):
19 | stdout.write(data)
20 |
21 | def connectionMade(self):
22 | print 'Connection Made!!!'
23 |
24 | data=stdin.readline()
25 | while data != 'exit\n':
26 | self.transport.write(data)
27 | data=stdin.readline()
28 | self.transport.loseConnection()
29 |
30 | class EchoClientFactory(ClientFactory):
31 |
32 |
33 | def startedConnecting(self, connector):
34 | print 'Started to connect.'
35 | self.e = Echo()
36 |
37 | def buildProtocol(self, addr):
38 | print 'Connected.'
39 | return self.e
40 |
41 | def clientConnectionLost(self, connector, reason):
42 | print 'Lost connection. Reason:', reason
43 | reactor.stop()
44 |
45 | def clientConnectionFailed(self, connector, reason):
46 | print 'Connection failed. Reason:', reason
47 | reactor.stop()
48 |
49 | # Start to listen for UDP connection
50 | #reactor.listenUDP(9999, udp_sniffer.UDP_factory())
51 | udp_obj = udp_sniffer.UDP_factory()
52 |
53 | # Start to sniff packets (run method in thread)
54 | argv = ('', 'eth0', 'tcp port 50007')
55 | sniffer.sniff(argv, udp_obj)
56 |
57 | # Wait a little bit...
58 | time.sleep(2)
59 |
60 | # Start TCP connection
61 | print 'Start TCP connection'
62 | reactor.connectTCP('10.193.167.86', 50007, EchoClientFactory(), 30, ('192.168.1.109', 50007))
63 | reactor.run()
64 |
--------------------------------------------------------------------------------
/htcp/p2pnetwork/testtcp/udpSniffer.py:
--------------------------------------------------------------------------------
1 | from twisted.internet.protocol import DatagramProtocol
2 | from twisted.internet import reactor
3 | import p2pNetwork.testTCP.spoof as spoof
4 | import p2pNetwork.testTCP.sniff as sniffer
5 |
6 | class UDP_factory(DatagramProtocol):
7 | """An UDP service to allow a TCP connection:
8 | - Hole punching to connect in UDP to the other peer
9 | - Forces the ack number in a TCP response packet sent via UDP hole"""
10 |
11 | def __init__(self):
12 | self.sp = spoof.Spoofer()
13 | print 'Start to listen'
14 | reactor.listenUDP(9999, self)
15 | self.receivedSYN = 0
16 | self.sentSYN = 0
17 |
18 |
19 | def datagramReceived(self, data, (host, port)):
20 | """Listen for the peer's SYN
21 | If it has the SYN and the ACK send the TCP simulated response"""
22 |
23 | print "received %r from %s:%d\n" % (data, host, port)
24 | if data == "":
25 | return
26 | else:
27 | self.receivedSYN = 1
28 | self.ACK=int(data)+1
29 | self.fakeConnection()
30 |
31 | def punchHole(self):
32 | """To punch an hole in the NAT for UDP communication with the peer"""
33 | # Send void packet to punch an hole
34 | host = '10.193.167.86'
35 | port = 9999
36 |
37 | print "Punch hole..."
38 | self.transport.write("", (host, port))
39 |
40 |
41 | def send_SYN_to_ConnectionBroker(self, syn):
42 | """Sends the SYN number of my connect()ion to:
43 | - the other peer for TCP connction without spoofing
44 | - the connection broker for spoofing"""
45 |
46 | # Send SYN to connection broker via UDP protocol
47 | host = '10.193.167.86'
48 | port = 9999
49 |
50 | print "Send SYN to peer: "
51 | self.sentSYN = 1
52 | self.SYN=int(syn)
53 | #reactor.listenUDP(50007, self)
54 | #self.transport.write("%ld"%self.SYN, (host, port))
55 | #reactor.stop()
56 | self.fakeConnection()
57 |
58 | def fakeConnection(self):
59 | """Sends the SYNACK packet to the other peer
60 | Optional: sends a SYNACK to himself for a unidirectional
61 | simulated TCP connection"""
62 |
63 | print 'Fake connection:', self.sentSYN, self.receivedSYN, '\n'
64 | if self.sentSYN and self.receivedSYN:
65 | dhost = '10.193.167.86'
66 | dport = 50007
67 | shost = '10.193.161.57'
68 | sport = 50007
69 | argv = ('', dhost, '%d'%dport, shost, '%ld'%self.SYN, '%ld'%self.ACK)
70 | argc = len(argv)
71 | self.sp.fakeConnection(argv, argc)
72 |
73 | # -----------------------------------------
74 | # Auto send SYNACK
75 | ## dhost = '10.193.161.57'
76 | ## dport = 50007
77 | ## shost = '10.193.167.86'
78 | ## sport = 50007
79 | ## self.SYN = self.ACK - 1
80 | ## self.ACK = self.SYN + 1
81 | ## argv = ('', dhost, '%d'%dport, shost, '%ld'%self.SYN, '%ld'%self.ACK)
82 | ## argc = len(argv)
83 | ## self.sp.fakeConnection(argv, argc)
84 | # -----------------------------------------
85 |
86 |
--------------------------------------------------------------------------------