def makeList(fds, conn, pk): print("Start discovery process.") timestamp = time.time() * 1000 #ms単位の現在時刻 print("timestamp %d." % timestamp) #検索 priv_key = PrivateKey() priv_key.deserialize(pk) rlpxd = RLPxDiscovery(priv_key, my_port=22222) rlpxd.listen() for i in fds: if i[3] != ServerIdsTable.STATUS_ENABLE: continue ipport = urlparse(i[1]) print("Send PingPacket to %s %s:%d." % (i[2], ipport.hostname, ipport.port)) rlpxd.sendPing(ipport.hostname, ipport.port) print("Wait 5 seconds.") time.sleep(5) r = rlpxd.close() print("Recrived %d packets." % (len(r))) def toMsg(info): return "enode://%s:%d %s" % (info["addr"], info["port"], datetime.fromtimestamp( info["packet"]["payload"].timestamp). strftime("%Y/%m/%d:%H%M%S")) ret = [] for i in fds: if i[3] != ServerIdsTable.STATUS_ENABLE: continue #PONG受信した? msg = "" status = "OFFLINE" for j in r: #PONGのみを対象にする if j["packet"]["packet_type"] != PongPayload.PACKET_TYPE: #不明なパケットタイプ print("I", end="") continue #ip/portの一致チェック ipport = urlparse(i[1]) if ipport.hostname != j["addr"] or ipport.port != j["port"]: continue print("A", end="") msg = toMsg(j) status = "ONLINE" break #sid,timestamp,status,description,url ret.append([i[0], timestamp, status, msg, i[1]]) print() print("Done.") return ret
class PingServer(object): def __init__(self, my_endpoint: EndPoint): self.endpoint = my_endpoint # get private key with open('priv_key', 'r') as priv_key_file: priv_key_serialized = priv_key_file.read() self.priv_key = PrivateKey() # type: PrivateKey self.priv_key.deserialize(priv_key_serialized) # init socket self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.bind(('0.0.0.0', self.endpoint.udpPort)) def wrap_packet(self, packet): payload = packet.packet_type + rlp.encode(packet.pack()) sig = self.priv_key.ecdsa_sign_recoverable(keccak256(payload), raw=True) sig_serialized = self.priv_key.ecdsa_recoverable_serialize(sig) payload = b''.join( [sig_serialized[0], str.encode(chr(sig_serialized[1])), payload]) payload_hash = keccak256(payload) return payload_hash + payload def udp_listen(self): def receive_ping(): print("listening...") data, addr = self.sock.recvfrom(1024) print("received message[", addr, "]") return threading.Thread(target=receive_ping) def ping(self, endpoint: EndPoint): ping = PingNode(self.endpoint, endpoint) message = self.wrap_packet(ping) print("sending ping...") self.sock.sendto(message, (endpoint.address.exploded, endpoint.udpPort))
class Server(object): def __init__(self, my_endpoint): self.endpoint = my_endpoint # 获取私钥 priv_key_file = open('priv_key', 'r') priv_key_serialized = priv_key_file.read() priv_key_file.close() self.priv_key = PrivateKey() self.priv_key.deserialize(priv_key_serialized) # 初始化套接字 self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.bind(('0.0.0.0', self.endpoint.udpPort)) # set socket non-blocking mode self.sock.setblocking(0) def wrap_packet(self, packet): payload = packet.packet_type + rlp.encode(packet.pack()) sig = self.priv_key.ecdsa_sign_recoverable(keccak256(payload), raw=True) sig_serialized = self.priv_key.ecdsa_recoverable_serialize(sig) payload = sig_serialized[0] + chr(sig_serialized[1]) + payload payload_hash = keccak256(payload) return payload_hash + payload def listen(self): print "listening..." while True: ready = select.select([self.sock], [], [], 1.0) if ready[0]: data, addr = self.sock.recvfrom(2048) print "received message[", addr, "]:" self.receive(data) def listen_thread(self): thread = threading.Thread(target=self.listen) thread.daemon = True return thread def receive(self, data): # verify hash msg_hash = data[:32] if msg_hash != keccak256(data[32:]): print " First 32 bytes are not keccak256 hash of the rest." return else: print " Verified message hash." # verify signature signature = data[32:97] signed_data = data[97:] deserialized_sig = self.priv_key.ecdsa_recoverable_deserialize( signature[:64], ord(signature[64])) remote_pubkey = self.priv_key.ecdsa_recover(keccak256(signed_data), deserialized_sig, raw=True) pub = PublicKey() pub.public_key = remote_pubkey verified = pub.ecdsa_verify( keccak256(signed_data), pub.ecdsa_recoverable_convert(deserialized_sig), raw=True) if not verified: print " Signature invalid" return else: print " Verified signature." response_types = { PingNode.packet_type: self.receive_ping, Pong.packet_type: self.receive_pong, FindNeighbors.packet_type: self.receive_find_neighbors, Neighbors.packet_type: self.receive_neighbors } try: packet_type = data[97] dispatch = response_types[packet_type] except KeyError: print " Unknown message type: " + data[97] return payload = data[98:] dispatch(payload, msg_hash) def receive_pong(self, payload, msg_hash): print " received Pong" print "", Pong.unpack(rlp.decode(payload)) def receive_ping(self, payload, msg_hash): print " received Ping" ping = PingNode.unpack(rlp.decode(payload)) pong = Pong(ping.endpoint_from, msg_hash, time.time() + 60) print " sending Pong response: " + str(pong) self.send(pong, pong.to) def receive_find_neighbors(self, payload, msg_hash): print " received FindNeighbors" print "", FindNeighbors.unpack(rlp.decode(payload)) def receive_neighbors(self, payload, msg_hash): print " received Neighbors" print "", Neighbors.unpack(rlp.decode(payload)) def ping(self, endpoint): ping = PingNode(self.endpoint, endpoint, time.time() + 60) message = self.wrap_packet(ping) print "sending " + str(ping) self.sock.sendto(message, (endpoint.address.exploded, endpoint.udpPort)) def send(self, packet, endpoint): message = self.wrap_packet(packet) print "sending " + str(packet) self.sock.sendto(message, (endpoint.address.exploded, endpoint.udpPort))
from secp256k1 import PrivateKey priv_key_file = open('priv_key', 'r') priv_key_serialized = priv_key_file.read() priv_key_file.close() priv_key = PrivateKey() priv_key.deserialize(priv_key_serialized) sig = priv_key.ecdsa_sign_recoverable('asdasd', raw=True) print sig
class PingServer(object): def __init__(self, my_endpoint): self.endpoint = my_endpoint # get private key priv_key_file = open('priv_key', 'r') priv_key_serialized = priv_key_file.read() priv_key_file.close() self.priv_key = PrivateKey() self.priv_key.deserialize(priv_key_serialized) # init socket self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.bind(('0.0.0.0', self.endpoint.udpPort)) def wrap_packet(self, packet): payload = packet.packet_type + rlp.encode(packet.pack()) sig = self.priv_key.ecdsa_sign_recoverable(keccak256(payload), raw=True) sig_serialized = self.priv_key.ecdsa_recoverable_serialize(sig) payload = sig_serialized[0] + chr(sig_serialized[1]) + payload payload_hash = keccak256(payload) return payload_hash + payload def udp_listen(self): return threading.Thread(target=self.receive) def receive(self): print "listening..." data, addr = self.sock.recvfrom(1024) print "received message[", addr, "]" ## decode packet below ## verify hash msg_hash = data[:32] if msg_hash != keccak256(data[32:]): print " First 32 bytes are not keccak256 hash of the rest." return else: print " Verified message hash." ## verify signature signature = data[32:97] signed_data = data[97:] deserialized_sig = self.priv_key.ecdsa_recoverable_deserialize( signature[:64], ord(signature[64])) remote_pubkey = self.priv_key.ecdsa_recover(keccak256(signed_data), deserialized_sig, raw=True) pub = PublicKey() pub.public_key = remote_pubkey verified = pub.ecdsa_verify( keccak256(signed_data), pub.ecdsa_recoverable_convert(deserialized_sig), raw=True) if not verified: print " Signature invalid" return else: print " Verified signature." response_types = { PingNode.packet_type: self.receive_ping, Pong.packet_type: self.receive_pong } try: packet_type = data[97] dispatch = response_types[packet_type] except KeyError: print " Unknown message type: " + data[97] return payload = data[98:] dispatch(payload) def receive_pong(self, payload): print " received Pong" print "", Pong.unpack(rlp.decode(payload)) def receive_ping(self, payload): print " received Ping" print "", PingNode.unpack(rlp.decode(payload)) def ping(self, endpoint): ping = PingNode(self.endpoint, endpoint, time.time() + 60) message = self.wrap_packet(ping) print "sending " + str(ping) self.sock.sendto(message, (endpoint.address.exploded, endpoint.udpPort))
class PingServer(object): def __init__(self, my_endpoint): self.endpoint = my_endpoint ## get private key priv_key_file = open('priv_key', 'r') priv_key_serialized = priv_key_file.read() priv_key_file.close() self.priv_key = PrivateKey() self.priv_key.deserialize(priv_key_serialized) # bind socket self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.bind(('0.0.0.0', self.endpoint.udpPort)) # bind tcp socket self.tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.tcpsock.bind(('0.0.0.0', self.endpoint.tcpPort)) self.tcpsock.listen(10) # p2p is the based network # so, when the p2p network close # the system need to send a quit blockchain msg to Discover server def __del__(self): pass # # hash || signature || packet-type || packet-data def wrap_packet(self, packet): payload = packet.packet_type + rlp.encode(packet.pack()) temp = keccak256(payload) sig = self.priv_key.ecdsa_sign_recoverable(temp, raw = True) sig_serialized = self.priv_key.ecdsa_recoverable_serialize(sig) # signature || packet-type || packet-data payload = sig_serialized[0] + chr(sig_serialized[1]) + payload # hash payload_hash = keccak256(payload) return payload_hash + payload def verifyData(self, data): # verify hash msg_hash = data[:32] if msg_hash != keccak256(data[32:]): print " First 32 bytes are not keccak256 hash of the rest." return else: print " Verified message hash." # verify signature signature = data[32:97] signed_data = data[97:] deserialized_sig = self.priv_key.ecdsa_recoverable_deserialize(signature[:64], ord(signature[64])) remote_pubkey = self.priv_key.ecdsa_recover(keccak256(signed_data), deserialized_sig, raw = True) pub = PublicKey() pub.public_key = remote_pubkey verified = pub.ecdsa_verify(keccak256(signed_data), pub.ecdsa_recoverable_convert(deserialized_sig), raw = True) if not verified: print " Signature invalid" return False else: print " Verified signature." return True def recvfrom(self): try: print "listening..." while True : data, addr = self.sock.recvfrom(1024) print "recvived mssage[", addr, "]" res = self.verifyData(data) if res: self.dispatch_data(data) except: traceback.print_exc() raise RuntimeError('recvfrom error') def recvtcpfrom(self, sock): try: print "tcp socket listening..." while (True): data = sock.recv(1024) print "【TCP】: get data, data's length is: %d"%len(data) res = self.verifyData(data) if res: self.dispatch_data(data) except: traceback.print_exc() raise RuntimeError('recvtcpfrom error') # 分裂一个进程 def tcp_listern(self): try: while True: sock, addr = self.tcpsock.accept() t = threading.Thread(target=self.recvtcpfrom, args=(sock,)) t.setDaemon(True) t.start() except: traceback.print_exc() raise RuntimeError('tcp_listern error') # 分裂一个线程来进行对tcp监听 def start_tcp_listern(self): t = threading.Thread(target=self.tcp_listern) t.setDaemon(True) t.start() def start_udp_listern(self): # udp listern listern_thread = self.udp_listen() listern_thread.start() def udp_listen(self): thread = threading.Thread(target= self.recvfrom,) thread.setDaemon(True) return thread def rawsendudpmsg(self, endpoint, message): self.sock.sendto(message, (endpoint.address.exploded, endpoint.udpPort)) # ping send a hello msg def ping(self, endpoint): ping = PingProtrol(self.endpoint, endpoint, time.time()) message = self.wrap_packet(ping) self.rawsendudpmsg(endpoint, message) def pong(self, pongNode): message = self.wrap_packet(pongNode) self.rawsendudpmsg(pongNode.to, message) def dispatch_data(self, data): response_types = { PingProtrol.packet_type: self.receive_ping, PongProtrol.packet_type: self.receive_pong, JoinProtrol.packet_type: self.receive_join, WelcomeProtrol.packet_type: self.receive_welcome, InitNodeProtrol.packet_type: self.receive_initnode, ChainMsgProtrol.packet_type: self.receive_msg } try: packet_type = data[97] dispatch = response_types[packet_type] except: print " Unknown message type: " + data[97] return payload = data[98:] dispatch(payload) # the function need overrided def receive_pong(self, payload): print " received Pong" print "", PongProtrol.unpack(rlp.decode(payload)) def receive_ping(self, payload): print " received Ping" print "", PingProtrol.unpack(rlp.decode(payload)) def receive_join(self, payload): print " received Join" print "", JoinProtrol.unpack(rlp.decode(payload)) def receive_welcome(self, payload): print " received welcome" print "", JoinProtrol.unpack(rlp.decode(payload)) def receive_initnode(self, payload): print " received initNode" print "", JoinProtrol.unpack(rlp.decode(payload)) def receive_msg(self, payload): print " received msg" print "", JoinProtrol.unpack(rlp.decode(payload)) # common function @staticmethod def SpecialEncode(endpoint): temp = { 'ip': endpoint.address.exploded, 'port': endpoint.tcpPort } return json.dumps(temp) @staticmethod def SpecialDecode(msg): return json.loads(msg)
from secp256k1 import PrivateKey, PublicKey import binascii import sha3 N_ADDRESS_BYTES = 20 N_PUB_KEY_BYTES = 64 address = 0x6e5ab887860e199b91b92d81f418c95d9ffd32cb key = "40dad29726f7e1b56359d2f1cc5a5365cb105b410e1108b3da65c1d97bfe6f8e" # b = long_to_bytes(key) privkey = PrivateKey(bytes(bytearray.fromhex(key)), raw=True) privkey_der = privkey.serialize() assert privkey.deserialize(privkey_der) == privkey.private_key print "privkey", privkey.serialize() pubkey = privkey.pubkey pub = pubkey.serialize(compressed=False) print "pubkey", binascii.hexlify(pub[1:]) print "pubkey", sha3.keccak_256(pub[1:]).hexdigest()[-2 * N_ADDRESS_BYTES:]
class PingServer(object): def __init__(self, my_endpoint, remote_endpoint, pingSleep, privKeyFile, kid): self.myEndpoint = my_endpoint self.theirEndpoint = remote_endpoint self.pingSleep = pingSleep self.kid = kid ## get private key pkf = open(privKeyFile, "r") priv_key_serialized = pkf.read() pkf.close() self.priv_key = PrivateKey() self.priv_key.deserialize(priv_key_serialized) ## init socket self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.bind( (self.myEndpoint.address.exploded, self.myEndpoint.udpPort)) def startPingLoop(self): self.pingLoopThread = threading.Thread(target=self._pingLoop).start() def startListening(self): print("Server " + str(self.kid) + ", start listening") self.listenThread = threading.Thread(target=self._listenLoop).start() def _pingLoop(self): print("pingLoop") while True: self.ping(self.theirEndpoint) self.findnode( self.theirEndpoint, 0x6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0 ) # self.neighbors(self.theirEndpoint, 0x6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0) time.sleep(self.pingSleep) def wrap_packet(self, packet): payload = packet.packet_type + rlp.encode(packet.pack()) sig = self.priv_key.ecdsa_sign_recoverable(keccak256(payload), raw=True) sig_serialized = self.priv_key.ecdsa_recoverable_serialize(sig) # print(str(type(sig_serialized[0])) + " " + str(type(sig_serialized[1])) + str(type(payload))) # print(sig_serialized[1]) payload = sig_serialized[0] + bytes([sig_serialized[1]]) + payload payload_hash = keccak256(payload) return payload_hash + payload def _listenLoop(self): print("Start Listening...") while True: data, addr = self.sock.recvfrom(2048) print("--------------- New Packet (ID: " + str(self.kid) + ") -------------") self.handlePacket(data, addr) def handlePacket(self, data, addr): # print("received message[" + str(addr) + "]") msg_hash = data[:32] # 32 Byte Hash raw_sig = data[32:97] # 64 Byte + 1 Byte Signature ptype = data[97] # 1 Byte packet_type pdata = data[98:] # Rest is rlp-encoded data decdata = rlp.decode(pdata) signedData = data[97:] # Verify hash if msg_hash != keccak256(data[32:]): print("Invalid message hash!") exit(0) # Verify signature deserialized_sig = self.priv_key.ecdsa_recoverable_deserialize( raw_sig[:64], raw_sig[64]) remote_pubkey = self.priv_key.ecdsa_recover(keccak256(signedData), deserialized_sig, raw=True) pub = PublicKey() pub.public_key = remote_pubkey verified = pub.ecdsa_verify( keccak256(signedData), pub.ecdsa_recoverable_convert(deserialized_sig), raw=True) if not verified: print("Signature invalid!") exit(0) else: print("Public Key: " + pub.serialize().hex()) packet_type = bytes([ptype]) if packet_type == PingPacket.packet_type: print("Got ping.") recv_ping = PingPacket.unpack(rlp.decode(pdata)) print(str(recv_ping)) # self.pong(msg_hash, recv_ping.To()) # TODO: Find out the correct endpoint self.pong(self.theirEndpoint, msg_hash) if packet_type == PongPacket.packet_type: print("Got pong.") recv_pong = PongPacket.unpack(decdata) print(str(recv_pong)) # self.ping(self.theirEndpoint) if packet_type == FindNodePacket.packet_type: print("Got FindNodePacket.") recv_findnode = FindNodePacket.unpack(rlp.decode(pdata)) target = recv_findnode.target print("Target: " + str(target.hex())) self.neighbors(self.theirEndpoint, target) if packet_type == NeighborsPacket.packet_type: print("Got NeighborsPacket.") recv_neighbors = NeighborsPacket.unpack(rlp.decode(pdata)) print("# Neighbors: " + str(len(recv_neighbors.neighbors))) def ping(self, theirEndpoint): ping = PingPacket(self.myEndpoint, theirEndpoint, time.time() + 60) message = self.wrap_packet(ping) print("Sending ping to: " + str(theirEndpoint)) self.sock.sendto( message, (theirEndpoint.address.exploded, theirEndpoint.udpPort)) def pong(self, theirEndpoint, echo): pong = PongPacket(theirEndpoint, echo, time.time() + 60) message = self.wrap_packet(pong) print("Sending pong to: " + str(theirEndpoint)) self.sock.sendto( message, (theirEndpoint.address.exploded, theirEndpoint.udpPort)) def findnode(self, theirEndpoint, target): findnode = FindNodePacket(target, time.time() + 60) message = self.wrap_packet(findnode) print("Sending FindNodePacket to: " + str(theirEndpoint)) self.sock.sendto( message, (theirEndpoint.address.exploded, theirEndpoint.udpPort)) def neighbors(self, theirEndpoint, target): # Compute some close neighbors on the fly neighbors = self.computeClosestNeighbors(target) packet = NeighborsPacket(neighbors, time.time() + 60) message = self.wrap_packet(packet) print("Sending NeighborsPacket to: " + str(theirEndpoint)) self.sock.sendto( message, (theirEndpoint.address.exploded, theirEndpoint.udpPort)) def computeClosestNeighbors(self, target): # Just return some hard coded IDs for now return [ Node( self.myEndpoint.address, self.myEndpoint.udpPort, self.myEndpoint.tcpPort, 0x6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0 ), Node( self.myEndpoint.address, self.myEndpoint.udpPort, self.myEndpoint.tcpPort, 0x7f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0 ), ]
class CrawlServer(object): def __init__(self, my_endpoint): self.endpoint = my_endpoint with open('priv_key', 'r') as priv_key_file: priv_key_serialized = priv_key_file.read() self.priv_key = PrivateKey() self.priv_key.deserialize(priv_key_serialized) def wrap_packet(self, packet): #packet_type + packet_data signature_payload = packet.packet_type + rlp.encode(packet.pack()) # signature = sign(packet_type + packet_data) sig = self.priv_key.ecdsa_sign_recoverable(keccak256(signature_payload), raw=True) sig_serialized = self.priv_key.ecdsa_recoverable_serialize(sig) #signature encoded payload = sig_serialized[0] + bytes([sig_serialized[1]]) #signature + packet_type + packet_data payload = payload + signature_payload #hash = keccak256(signature + packet_type + packet_data) payload_hash = keccak256(payload) #hash + signature + packet_type + packet_data return payload_hash + payload def discover(self, q, qset, out, count, running): #socket sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind(('0.0.0.0', self.endpoint.udpPort+count)) sock.settimeout(5) def request_neighbour_lsb(bucket): #generate nodeID to discover specified bucket hashedID = keccak256(self.their_endpoint.nodeID) match = False mask = 1 while match is False: generatedID = bytes(random.randint(0,255) for _ in range(64)) genHashed = keccak256(generatedID) if bucket == 0: if (genHashed[0] ^ hashedID[0]) & mask == mask: match = True else: match = False else: #get the bytes in which the relevant bits are and iterate over them for x in range(int(bucket/8)+1): #make mask according to position in byte array (if last relevant byte get specific bit mask) if x == int(bucket/8): mask = pow(2, bucket%8)-1 else: mask = 255 #actual comparing if ~(genHashed[x] ^ hashedID[x]) & mask == mask: match = True else: match = False break #send request find_neighbour = NeighbourMsg(generatedID) message = self.wrap_packet(find_neighbour) logging.debug("sending find_node") sock.sendto(message, (self.their_endpoint.address.exploded, self.their_endpoint.udpPort)) def request_neighbour_msb(bucket): #generate nodeID to discover specified bucket hashedID = keccak256(self.their_endpoint.nodeID) match = False mask = 1 << 7 while match is False: generatedID = bytes(random.randint(0,255) for _ in range(64)) genHashed = keccak256(generatedID) if bucket == 0: if (genHashed[31] ^ hashedID[31]) & mask == mask: match = True else: match = False else: #get the bytes in which the relevant bits are and iterate over them for x in range(int(bucket/8)+1): #make mask according to position in byte array (if last relevant byte get specific bit mask) if x == int(bucket/8): mask = pow(2, bucket%8)-1 mask = mask << (8-bucket%8) else: mask = 255 #actual comparing if ~(genHashed[31-x] ^ hashedID[31-x]) & mask == mask: match = True else: match = False break #send request find_neighbour = NeighbourMsg(generatedID) message = self.wrap_packet(find_neighbour) logging.debug("sending find_node") sock.sendto(message, (self.their_endpoint.address.exploded, self.their_endpoint.udpPort)) def decode_worker(q, data, workerOut): nodes = rlp.decode(data[98:])[0] #[0] nodes [1] expiration for node in nodes: ip = ip_address(node[0]) if len(node[1]) == 2: udp_port = struct.unpack(">H", node[1]) if len(node[2]) == 2: tcp_port = struct.unpack(">H", node[2]) else: tcp_port = (0, ">I") nodeID = node[3] neighbour = Endpoint(str(ip), udp_port[0], tcp_port[0], nodeID) logging.debug("Neighbour: " + neighbour.serialize()) if neighbour not in list(qset.queue): q.put(neighbour) qset.put(neighbour) workerOut.put(neighbour) while running.is_set(): #start ping pong self.their_endpoint = q.get() ping = PingMsg(self.endpoint, self.their_endpoint) message = self.wrap_packet(ping) logging.info("sending ping to " + self.their_endpoint.address.exploded) sock.sendto(message, (self.their_endpoint.address.exploded, self.their_endpoint.udpPort)) serializeOut = self.their_endpoint.serialize() greeted = False while not greeted: try: data, addr = sock.recvfrom(1280) if data[97] == 1: logging.info("received ping from " + addr[0]) pinger = Endpoint(addr[0], addr[1], addr[1], b'') pong = PongMsg(pinger, data[:32]) message = self.wrap_packet(pong) logging.info("sending pong to " + str(pinger.address)) sock.sendto(message, (pinger.address.exploded, pinger.udpPort)) greeted = True if data[97] == 2: logging.info("received pong from " + addr[0]) except socket.timeout: serializeOut += ", no greeting" break #discover top 14 buckets of a neigbour (finding targets for all buckets would be hard/impossible) if greeted: for bucket in range(14): #discover a bucket request_neighbour_msb(bucket) counter = 0 workerOut = queue.Queue() workers = [] while counter < 2: try: data, addr = sock.recvfrom(1280) if data[97] == 4: #get up to 16 neighbours and add them to the q (12 neighbours per packet) workers.append(Thread(target = decode_worker, args = (q, data, workerOut))) workers[counter].start() logging.debug("received neighbours from " + addr[0]) counter += 1 #timeout because we received all neighbours available (less than 16) or didnt receive ping except socket.timeout: break for worker in workers: worker.join() serializeOut += ", \"[" for item in list(workerOut.queue): serializeOut += "[" + item.serialize() + "], " if serializeOut[-2] == ',': serializeOut = serializeOut[:-2] serializeOut += "]\"" logging.debug(serializeOut) out.put(serializeOut)
class PingServer(object): """Open sockets, sign and hash messages, send messages to other servers.""" def __init__(self, my_endpoint): """ Set up ping server. - Take an endpoint object (i.e: itself in the network space) - Used as a "from address" when sending packets - Load private key for server """ self.endpoint = my_endpoint # Load and serialize private key private_key_file = open('private_key', 'r') private_key_serialized = private_key_file.read() private_key_file.close() # Ethereum uses secp256k1, an elliptic curve, for assymetric encryption self.private_key = PrivateKey() self.private_key.deserialize(private_key_serialized) def wrap_packet(self, packet): """ Encode the packet. hash || signature || packet-type || packet-data """ # Append the packet type to the RLP encoding of the packet data payload = packet.packet_type + rlp.encode(packet.pack()) # Sign the hashed payload, use raw=True, cause we've already hashed, # and otherwise, the function would use its own hash function signature = self.private_key.ecdsa_sign_recoverable( keccak256(payload), raw=True, ) # Creates a tuple signature_serialized = self.private_key.ecdsa_recoverable_serialize(signature) payload = signature_serialized[0] + chr(signature_serialized[1] + payload) payload_hash = keccak256(payload) return payload_hash + payload def udp_listen(self): """Listen for incoming transmissions""" # Create socket and bind it to the server's endpoint sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind(('0.0.0.0', self.endpoint.udp_port)) def receive_ping(): """Listen at the socket for incoming data""" print 'listening...' data, addr = sock.recvfrom(1024) print 'received message[{}]'.format(addr) return threading.Thread(target=receive_ping) def ping(self, endpoint): sock = socket.socket(socket.AF_INET), socket.SOCK_DGRAM ping = PingNode(self.endpoint, endpoint) message = self.wrap_packet(ping) print "sending ping." sock.sendto( message, (endpoint.address.exploded, endpoint.udp_port) )
class Server(object): def __init__(self, boot_nodes): # the endpoint of this server # this is a fake ip address used in packets. self.endpoint = EndPoint(u'127.0.0.1', 30303, 30303) # boot nodes self.boot_nodes = boot_nodes # hold all of pending self.pending_hold = [] # last pong received time of the special node id self.last_pong_received = {} # last ping received time of the special node id self.last_ping_received = {} # have the private key priv_key_file = open('priv_key', 'r') priv_key_serialized = priv_key_file.read() priv_key_file.close() self.priv_key = PrivateKey() self.priv_key.deserialize(priv_key_serialized) # routing table self.table = RoutingTable( Node(self.endpoint, pubkey_format(self.priv_key.pubkey)[1:]), self) # initialize UDP socket self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.bind(('0.0.0.0', self.endpoint.udpPort)) # set socket non-blocking mode self.sock.setblocking(0) def add_table(self, node): self.table.add_node(node) def add_pending(self, pending): pending.start() self.pending_hold.append(pending) return pending def run(self): gevent.spawn(self.clean_pending) gevent.spawn(self.listen) # wait forever evt = Event() evt.wait() def clean_pending(self): while True: for pending in list(self.pending_hold): if not pending.is_alive: self.pending_hold.remove(pending) time.sleep(K_REQUEST_TIMEOUT) def listen(self): LOGGER.info("{:5} listening...".format('')) while True: ready = select([self.sock], [], [], 1.0) if ready[0]: data, addr = self.sock.recvfrom(2048) # non-block data reading gevent.spawn(self.receive, data, addr) def receive(self, data, addr): """ macSize = 256 / 8 = 32 sigSize = 520 / 8 = 65 headSize = macSize + sigSize = 97 hash, sig, sigdata := buf[:macSize], buf[macSize:headSize], buf[headSize:] shouldhash := crypto.Sha3(buf[macSize:]) """ # verify hash msg_hash = data[:32] assert msg_hash == keccak256( data[32:]), "First 32 bytes are not keccak256 hash of the rest" # verify signature signature = data[32:97] signed_data = data[97:] deserialized_sig = self.priv_key.ecdsa_recoverable_deserialize( signature[:64], ord(signature[64])) remote_pubkey = self.priv_key.ecdsa_recover(keccak256(signed_data), deserialized_sig, raw=True) pub = PublicKey() pub.public_key = remote_pubkey verified = pub.ecdsa_verify( keccak256(signed_data), pub.ecdsa_recoverable_convert(deserialized_sig), raw=True) assert verified, "Signature invalid" pubkey = pubkey_format(pub)[1:] hex_id = binascii.hexlify(keccak256(pubkey)) packet_type = data[97] payload = rlp.decode(data[98:]) if packet_type == PingNode.packet_type: # fake ip in packet payload[1][0] = addr[0] ping = PingNode.unpack(payload) if expired(ping): return self.receive_ping(addr, pubkey, ping, msg_hash) elif packet_type == Pong.packet_type: pong = Pong.unpack(payload) if expired(pong): return self.receive_pong(addr, pubkey, pong) elif packet_type == FindNeighbors.packet_type: fn = FindNeighbors.unpack(payload) if expired(fn): return self.receive_find_neighbors(addr, pubkey, fn) elif packet_type == Neighbors.packet_type: neighbours = Neighbors.unpack(payload) if expired(neighbours): return self.receive_neighbors(addr, pubkey, neighbours) else: assert False, " Unknown message type: {}".format(packet_type) def receive_pong(self, addr, pubkey, pong): remote_id = keccak256(pubkey) # response to ping last_pong_received = self.last_pong_received def match_callback(): # solicited reply last_pong_received[remote_id] = time.time() self.handle_reply(addr, pubkey, Pong.packet_type, pong, match_callback) def receive_ping(self, addr, pubkey, ping, msg_hash): remote_id = keccak256(pubkey) endpoint_to = EndPoint(addr[0], ping.endpoint_from.udpPort, ping.endpoint_from.tcpPort) pong = Pong(endpoint_to, msg_hash, time.time() + K_EXPIRATION) node_to = Node(pong.to, pubkey) # sending Pong response self.send_sock(pong, node_to) LOGGER.info("{:5} {}@{}:{} (Pong)".format( '---->', binascii.hexlify(node_to.node_id)[:8], addr[0], ping.endpoint_from.udpPort)) self.handle_reply(addr, pubkey, PingNode.packet_type, ping) node = Node(endpoint_to, pubkey) if time.time() - self.last_pong_received.get(remote_id, 0) > K_BOND_EXPIRATION: self.ping(node, lambda: self.add_table(node)) else: self.add_table(node) self.last_ping_received[remote_id] = time.time() def receive_find_neighbors(self, addr, pubkey, fn): remote_id = keccak256(pubkey) if time.time() - self.last_pong_received.get(remote_id, 0) > K_BOND_EXPIRATION: # lost origin or origin is off return target_id = keccak256(fn.target) closest = self.table.closest(target_id, BUCKET_SIZE) # sent neighbours in chunks ns = Neighbors([], time.time() + K_EXPIRATION) sent = False node_to = Node(EndPoint(addr[0], addr[1], addr[1]), pubkey) for c in closest: ns.nodes.append(c) if len(ns.nodes) == K_MAX_NEIGHBORS: self.send_sock(ns, node_to) LOGGER.info("{:5} {}@{}:{} {}".format( '---->', binascii.hexlify(node_to.node_id)[:8], addr[0], addr[1], ns)) ns.nodes = [] sent = True if len(ns.nodes) > 0 or not sent: self.send_sock(ns, node_to) LOGGER.info("{:5} {}@{}:{} {}".format( '---->', binascii.hexlify(node_to.node_id)[:8], addr[0], addr[1], ns)) def receive_neighbors(self, addr, pubkey, neighbours): # response to find neighbours self.handle_reply(addr, pubkey, Neighbors.packet_type, neighbours) def handle_reply(self, addr, pubkey, packet_type, packet, match_callback=None): remote_id = keccak256(pubkey) is_match = False for pending in self.pending_hold: if pending.is_alive and packet_type == pending.packet_type: if remote_id == pending.from_id: is_match = True pending.emit(packet) match_callback and match_callback() elif pending.ep is not None and pending.ep == addr: LOGGER.error('{:5} {}@{}:{} mismatch request {}'.format( '', binascii.hexlify(remote_id)[:8], addr[0], addr[1], binascii.hexlify(pending.from_id)[:8])) # is_match = True # pending.emit(packet) # match_callback and match_callback() # for bucket in self.table.buckets: # for node in bucket.nodes: # if node.node_id == pending.from_id: # node.set_pubkey(pubkey) if not is_match: LOGGER.warning('{:5} {}@{}:{} ({}) unsolicited response'.format( '<-//-', binascii.hexlify(remote_id)[:8], addr[0], addr[1], PACKET_TYPES.get(packet.packet_type))) def ping(self, node, callback=None): """ send a ping request to the given node and return instantly invoke callback while reply arrives """ ping = PingNode(self.endpoint, node.endpoint, time.time() + K_EXPIRATION) message = self.wrap_packet(ping) msg_hash = message[:32] def reply_call(chunks): if chunks.pop().echo == msg_hash: if callback is not None: callback() return True ep = (node.endpoint.address.exploded, node.endpoint.udpPort) pending = self.add_pending(Pending(node, Pong.packet_type, reply_call)) self.sock.sendto(message, ep) LOGGER.info("{:5} {}@{}:{} (Ping)".format( '---->', binascii.hexlify(node.node_id)[:8], ep[0], ep[1])) return pending def find_neighbors(self, node, target_key): """ send a find neighbours request to the given node and waits until the node has sent up to k neighbours """ node_id = node.node_id if time.time() - self.last_ping_received.get(node_id, 0) > K_BOND_EXPIRATION: send_ping = self.ping(node) receive_ping = self.add_pending( Pending(node, PingNode.packet_type, lambda _: True)) # wait until endpoint proof is finished gevent.joinall([send_ping, receive_ping]) fn = FindNeighbors(target_key, time.time() + K_EXPIRATION) def reply_call(chunks): num_received = 0 for neighbors in chunks: num_received += len(neighbors.nodes) if num_received >= BUCKET_SIZE: return True pending = self.add_pending( Pending(node, Neighbors.packet_type, reply_call, timeout=2)) self.send_sock(fn, node) ep = (node.endpoint.address.exploded, node.endpoint.udpPort) LOGGER.info("{:5} {}@{}:{} (FN {})".format( '---->', binascii.hexlify(node.node_id)[:8], ep[0], ep[1], binascii.hexlify(keccak256(fn.target))[:8])) # block to wait for neighbours ret = pending.get() if ret: neighbor_nodes = [] for chunk in ret: for n in chunk.nodes: neighbor_nodes.append(n) return neighbor_nodes def send_sock(self, packet, node): endpoint = node.endpoint message = self.wrap_packet(packet) ep = (endpoint.address.exploded, endpoint.udpPort) self.sock.sendto(message, ep) def wrap_packet(self, packet): """ UDP packets are structured as follows: hash || signature || packet-type || packet-data packet-type: single byte < 2**7 // valid values are [1,4] packet-data: RLP encoded list. Packet properties are serialized in the order in which they're defined. See packet-data below. Offset | 0 | MDC | Ensures integrity of packet, 65 | signature | Ensures authenticity of sender, `SIGN(sender-privkey, MDC)` 97 | type | Single byte in range [1, 4] that determines the structure of Data 98 | data | RLP encoded, see section Packet Data The packets are signed and authenticated. The sender's Node ID is determined by recovering the public key from the signature. sender-pubkey = ECRECOVER(Signature) The integrity of the packet can then be verified by computing the expected MDC of the packet as: MDC = SHA3(sender-pubkey || type || data) As an optimization, implementations may look up the public key by the UDP sending address and compute MDC before recovering the sender ID. If the MDC values do not match, the packet can be dropped. """ payload = packet.packet_type + rlp.encode(packet.pack()) sig = self.priv_key.ecdsa_sign_recoverable(keccak256(payload), raw=True) sig_serialized = self.priv_key.ecdsa_recoverable_serialize(sig) payload = sig_serialized[0] + chr(sig_serialized[1]) + payload payload_hash = keccak256(payload) return payload_hash + payload
class Server(object): def __init__(self, my_endpoint): self.endpoint = my_endpoint # 获取私钥 priv_key_file = open('priv_key', 'r') priv_key_serialized = priv_key_file.read() priv_key_file.close() self.priv_key = PrivateKey() self.priv_key.deserialize(priv_key_serialized) # 初始化套接字 self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.bind(('0.0.0.0', self.endpoint.udpPort)) # set socket non-blocking mode self.sock.setblocking(0) def wrap_packet(self, packet): """ UDP packets are structured as follows: hash || signature || packet-type || packet-data packet-type: single byte < 2**7 // valid values are [1,4] packet-data: RLP encoded list. Packet properties are serialized in the order in which they're defined. See packet-data below. Offset | 0 | MDC | Ensures integrity of packet, 65 | signature | Ensures authenticity of sender, `SIGN(sender-privkey, MDC)` 97 | type | Single byte in range [1, 4] that determines the structure of Data 98 | data | RLP encoded, see section Packet Data The packets are signed and authenticated. The sender's Node ID is determined by recovering the public key from the signature. sender-pubkey = ECRECOVER(Signature) The integrity of the packet can then be verified by computing the expected MDC of the packet as: MDC = SHA3(sender-pubkey || type || data) As an optimization, implementations may look up the public key by the UDP sending address and compute MDC before recovering the sender ID. If the MDC values do not match, the packet can be dropped. """ payload = packet.packet_type + rlp.encode(packet.pack()) sig = self.priv_key.ecdsa_sign_recoverable(keccak256(payload), raw=True) sig_serialized = self.priv_key.ecdsa_recoverable_serialize(sig) payload = sig_serialized[0] + chr(sig_serialized[1]) + payload payload_hash = keccak256(payload) return payload_hash + payload def listen(self): print "listening..." while True: ready = select.select([self.sock], [], [], 1.0) if ready[0]: data, addr = self.sock.recvfrom(2048) print "received message[", addr, "]:" self.receive(data, addr) def listen_thread(self): thread = threading.Thread(target=self.listen) thread.daemon = True return thread def receive(self, data, addr): """ macSize = 256 / 8 = 32 sigSize = 520 / 8 = 65 headSize = macSize + sigSize = 97 hash, sig, sigdata := buf[:macSize], buf[macSize:headSize], buf[headSize:] shouldhash := crypto.Sha3(buf[macSize:]) """ # verify hash msg_hash = data[:32] if msg_hash != keccak256(data[32:]): print " First 32 bytes are not keccak256 hash of the rest." return else: print " Verified message hash." # verify signature signature = data[32:97] signed_data = data[97:] deserialized_sig = self.priv_key.ecdsa_recoverable_deserialize(signature[:64], ord(signature[64])) remote_pubkey = self.priv_key.ecdsa_recover(keccak256(signed_data), deserialized_sig, raw=True) pub = PublicKey() pub.public_key = remote_pubkey verified = pub.ecdsa_verify(keccak256(signed_data), pub.ecdsa_recoverable_convert(deserialized_sig), raw=True) if not verified: print " Signature invalid" return else: print " Verified signature." response_types = { PingNode.packet_type: self.receive_ping, Pong.packet_type: self.receive_pong, FindNeighbors.packet_type: self.receive_find_neighbors, Neighbors.packet_type: self.receive_neighbors } try: packet_type = data[97] dispatch = response_types[packet_type] except KeyError: print " Unknown message type: " + data[97] return payload = data[98:] dispatch(payload, msg_hash, addr) def receive_pong(self, payload, msg_hash, addr): print " received Pong" print "", Pong.unpack(rlp.decode(payload)) def receive_ping(self, payload, msg_hash, addr): print " received Ping" ping = PingNode.unpack(rlp.decode(payload)) endpoint_to = EndPoint(addr[0], ping.endpoint_from.udpPort, ping.endpoint_from.tcpPort) pong = Pong(endpoint_to, msg_hash, time.time() + 60) print " sending Pong response: " + str(pong) self.send(pong, pong.to) def receive_find_neighbors(self, payload, msg_hash, addr): print " received FindNeighbors" print "", FindNeighbors.unpack(rlp.decode(payload)) def receive_neighbors(self, payload, msg_hash, addr): print " received Neighbors" print "", Neighbors.unpack(rlp.decode(payload)) def ping(self, endpoint): ping = PingNode(self.endpoint, endpoint, time.time() + 60) message = self.wrap_packet(ping) print "sending " + str(ping) self.sock.sendto(message, (endpoint.address.exploded, endpoint.udpPort)) def send(self, packet, endpoint): message = self.wrap_packet(packet) print "sending " + str(packet) self.sock.sendto(message, (endpoint.address.exploded, endpoint.udpPort))