From: burris Date: Wed, 22 Jan 2003 07:22:48 +0000 (+0000) Subject: check responses and fail if they don't come from the peer we were X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=67ea324e46570a42861fe6a342c626738134bbfc;p=quix0rs-apt-p2p.git check responses and fail if they don't come from the peer we were expecting them to come from added bencode.py, whoops --- diff --git a/actions.py b/actions.py index f367c53..7a3a5b9 100644 --- a/actions.py +++ b/actions.py @@ -85,6 +85,7 @@ class FindNode(ActionBase): def makeMsgFailed(self, node): def defaultGotNodes(err, self=self, node=node): + print ">>> find failed" self.table.table.nodeFailed(node) self.outstanding = self.outstanding - 1 self.schedule() @@ -195,6 +196,7 @@ class StoreValue(ActionBase): self.schedule() def storeFailed(self, t, node): + print ">>> store failed" self.table.nodeFailed(node) self.outstanding -= 1 if self.finished: diff --git a/airhook.py b/airhook.py index c100cdf..60078bd 100644 --- a/airhook.py +++ b/airhook.py @@ -101,7 +101,7 @@ class AirhookConnection(protocol.ConnectedDatagramProtocol, interfaces.IUDPConne self.lastTransmit = 0 # time we last sent a packet with messages self.lastReceieved = 0 # time we last received a packet with messages self.lastTransmitSeq = -1 # last sequence we sent a packet - self.state = pending + self.state = pending # one of pending, sent, confirmed self.outMsgs = [None] * 256 # outgoing messages (seq sent, message), index = message number self.omsgq = [] # list of messages to go out @@ -226,7 +226,7 @@ class AirhookConnection(protocol.ConnectedDatagramProtocol, interfaces.IUDPConne ids += pack("!L", self.sessionID) else: - if self.state == sent or self.sendSession: + if self.state == sent or self.sendSession != None: if self.state == confirmed and (self.obSeq - self.sendSession) % 2**16 < 256: self.sendSession = None else: diff --git a/bencode.py b/bencode.py new file mode 100644 index 0000000..93af407 --- /dev/null +++ b/bencode.py @@ -0,0 +1,254 @@ +# Written by Petru Paler +# see LICENSE.txt for license information + +from types import IntType, LongType, StringType, ListType, TupleType, DictType +import re +from cStringIO import StringIO + +int_filter = re.compile('(0|-?[1-9][0-9]*)e') + +def decode_int(x, f): + m = int_filter.match(x, f) + if m is None: + raise ValueError + return (long(m.group(1)), m.end()) + +string_filter = re.compile('(0|[1-9][0-9]*):') + +def decode_string(x, f): + m = string_filter.match(x, f) + if m is None: + raise ValueError + l = int(m.group(1)) + s = m.end() + return (x[s:s+l], s + l) + +def decode_list(x, f): + r = [] + while x[f] != 'e': + v, f = bdecode_rec(x, f) + r.append(v) + return (r, f + 1) + +def decode_dict(x, f): + r = {} + lastkey = None + while x[f] != 'e': + k, f = decode_string(x, f) + if lastkey is not None and lastkey >= k: + raise ValueError + lastkey = k + v, f = bdecode_rec(x, f) + r[k] = v + return (r, f + 1) + +def bdecode_rec(x, f): + t = x[f] + if t == 'i': + return decode_int(x, f + 1) + elif t == 'l': + return decode_list(x, f + 1) + elif t == 'd': + return decode_dict(x, f + 1) + else: + return decode_string(x, f) + +def bdecode(x): + try: + r, l = bdecode_rec(x, 0) + except IndexError: + raise ValueError + if l != len(x): + raise ValueError + return r + +def test_bdecode(): + try: + bdecode('0:0:') + assert 0 + except ValueError: + pass + try: + bdecode('ie') + assert 0 + except ValueError: + pass + try: + bdecode('i341foo382e') + assert 0 + except ValueError: + pass + assert bdecode('i4e') == 4L + assert bdecode('i0e') == 0L + assert bdecode('i123456789e') == 123456789L + assert bdecode('i-10e') == -10L + try: + bdecode('i-0e') + assert 0 + except ValueError: + pass + try: + bdecode('i123') + assert 0 + except ValueError: + pass + try: + bdecode('') + assert 0 + except ValueError: + pass + try: + bdecode('i6easd') + assert 0 + except ValueError: + pass + try: + bdecode('35208734823ljdahflajhdf') + assert 0 + except ValueError: + pass + try: + bdecode('2:abfdjslhfld') + assert 0 + except ValueError: + pass + assert bdecode('0:') == '' + assert bdecode('3:abc') == 'abc' + assert bdecode('10:1234567890') == '1234567890' + try: + bdecode('02:xy') + assert 0 + except ValueError: + pass + try: + bdecode('l') + assert 0 + except ValueError: + pass + assert bdecode('le') == [] + try: + bdecode('leanfdldjfh') + assert 0 + except ValueError: + pass + assert bdecode('l0:0:0:e') == ['', '', ''] + try: + bdecode('relwjhrlewjh') + assert 0 + except ValueError: + pass + assert bdecode('li1ei2ei3ee') == [1, 2, 3] + assert bdecode('l3:asd2:xye') == ['asd', 'xy'] + assert bdecode('ll5:Alice3:Bobeli2ei3eee') == [['Alice', 'Bob'], [2, 3]] + try: + bdecode('d') + assert 0 + except ValueError: + pass + try: + bdecode('defoobar') + assert 0 + except ValueError: + pass + assert bdecode('de') == {} + assert bdecode('d3:agei25e4:eyes4:bluee') == {'age': 25, 'eyes': 'blue'} + assert bdecode('d8:spam.mp3d6:author5:Alice6:lengthi100000eee') == {'spam.mp3': {'author': 'Alice', 'length': 100000}} + try: + bdecode('d3:fooe') + assert 0 + except ValueError: + pass + try: + bdecode('di1e0:e') + assert 0 + except ValueError: + pass + try: + bdecode('d1:b0:1:a0:e') + assert 0 + except ValueError: + pass + try: + bdecode('d1:a0:1:a0:e') + assert 0 + except ValueError: + pass + try: + bdecode('i03e') + assert 0 + except ValueError: + pass + try: + bdecode('l01:ae') + assert 0 + except ValueError: + pass + try: + bdecode('9999:x') + assert 0 + except ValueError: + pass + try: + bdecode('l0:') + assert 0 + except ValueError: + pass + try: + bdecode('d0:0:') + assert 0 + except ValueError: + pass + try: + bdecode('d0:') + assert 0 + except ValueError: + pass + +def bencode_rec(x, b): + t = type(x) + if t in (IntType, LongType): + b.write('i%de' % x) + elif t is StringType: + b.write('%d:%s' % (len(x), x)) + elif t in (ListType, TupleType): + b.write('l') + for e in x: + bencode_rec(e, b) + b.write('e') + elif t is DictType: + b.write('d') + keylist = x.keys() + keylist.sort() + for k in keylist: + assert type(k) is StringType + bencode_rec(k, b) + bencode_rec(x[k], b) + b.write('e') + else: + assert 0 + +def bencode(x): + b = StringIO() + bencode_rec(x, b) + return b.getvalue() + +def test_bencode(): + assert bencode(4) == 'i4e' + assert bencode(0) == 'i0e' + assert bencode(-10) == 'i-10e' + assert bencode(12345678901234567890L) == 'i12345678901234567890e' + assert bencode('') == '0:' + assert bencode('abc') == '3:abc' + assert bencode('1234567890') == '10:1234567890' + assert bencode([]) == 'le' + assert bencode([1, 2, 3]) == 'li1ei2ei3ee' + assert bencode([['Alice', 'Bob'], [2, 3]]) == 'll5:Alice3:Bobeli2ei3eee' + assert bencode({}) == 'de' + assert bencode({'age': 25, 'eyes': 'blue'}) == 'd3:agei25e4:eyes4:bluee' + assert bencode({'spam.mp3': {'author': 'Alice', 'length': 100000}}) == 'd8:spam.mp3d6:author5:Alice6:lengthi100000eee' + try: + bencode({1: 'foo'}) + assert 0 + except AssertionError: + pass + diff --git a/const.py b/const.py index ee1da1f..bade7c4 100644 --- a/const.py +++ b/const.py @@ -1,9 +1,16 @@ from twisted.internet.default import SelectReactor ## twistedmatrix.com reactor = SelectReactor(installSignalHandlers=0) + from twisted.internet import main main.installReactor(reactor) +try: + import twisted.names.client + reactor.installResolver(twisted.names.client.theResolver) +except IOError: + print "no resolv.conf!" + # magic id to use before we know a peer's id NULL_ID = 20 * '\0' diff --git a/knode.py b/knode.py index b5ecedc..f952795 100644 --- a/knode.py +++ b/knode.py @@ -2,26 +2,35 @@ from node import Node from twisted.internet.defer import Deferred from const import reactor, NULL_ID + +class IDChecker: + def __init__(id): + self.id = id + class KNode(Node): - def makeResponse(self, df): - """ Make our callback cover that checks to make sure the id of the response is the same as what we are expecting """ - def _callback(dict, d=df): - try: - senderid = dict['sender']['id'] - except KeyError: - d.errback() - else: - if self.id != NULL_ID and senderid != self._senderDict['id']: - d.errback() - else: - d.callback(dict) - return _callback + def checkSender(self, dict): + try: + senderid = dict['sender']['id'] + except KeyError: + raise Exception, "No peer id in response." + else: + if self.id != NULL_ID and senderid != self.id: + raise Exception, "Got response from different node than expected." + return dict def ping(self, sender): - return self.conn.protocol.sendRequest('ping', {"sender":sender}) + df = self.conn.protocol.sendRequest('ping', {"sender":sender}) + df.addCallback(self.checkSender) + return df def findNode(self, target, sender): - return self.conn.protocol.sendRequest('find_node', {"target" : target, "sender": sender}) + df = self.conn.protocol.sendRequest('find_node', {"target" : target, "sender": sender}) + df.addCallback(self.checkSender) + return df def storeValue(self, key, value, sender): - return self.conn.protocol.sendRequest('store_value', {"key" : key, "value" : value, "sender": sender}) + df = self.conn.protocol.sendRequest('store_value', {"key" : key, "value" : value, "sender": sender}) + df.addCallback(self.checkSender) + return df def findValue(self, key, sender): - return self.conn.protocol.sendRequest('find_value', {"key" : key, "sender" : sender}) \ No newline at end of file + df = self.conn.protocol.sendRequest('find_value', {"key" : key, "sender" : sender}) + df.addCallback(self.checkSender) + return df diff --git a/krpc.py b/krpc.py index 8569bbf..40ed862 100644 --- a/krpc.py +++ b/krpc.py @@ -3,6 +3,7 @@ from twisted.internet.defer import Deferred from twisted.protocols import basic from bencode import bencode, bdecode from twisted.internet import reactor +import time import hash @@ -57,7 +58,7 @@ class KRPC(basic.NetstringReceiver): olen = len(str) self.sendString(str) if self.noisy: - print "%s >>> (%s, %s) - %s %s %s" % (self.transport.addr, self.factory.node.host, self.factory.node.port, + print "%s %s >>> %s - %s %s %s" % (time.asctime(), self.transport.addr, self.factory.node.port, ilen, msg['req'], olen) elif msg['typ'] == 'rsp': # if response diff --git a/test_krpc.py b/test_krpc.py index 5f2c5b7..42b7b16 100644 --- a/test_krpc.py +++ b/test_krpc.py @@ -2,6 +2,8 @@ from unittest import * from krpc import * from airhook import * +KRPC.noisy = 0 + import sys if __name__ =="__main__": @@ -31,7 +33,7 @@ class SimpleTest(TestCase): self.b = listenAirhookStream(4041, self.bf) def testSimpleMessage(self): - self.noisy = 1 + self.noisy = 0 self.a.connectionForAddr(('127.0.0.1', 4041)).protocol.sendRequest('store', {'msg' : "This is a test."}) reactor.iterate() reactor.iterate()