├── .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 | --------------------------------------------------------------------------------