def _send_remote_peer_request(self, infohash, callback): #make sure we have a circuit to send it out on: if self.circ and self.circ.is_done(): self.circ = None if not self.circ: self.circ = self.app.find_or_build_best_circuit(force=True, protocol="DHT") if self.circ == None: log_msg("Could not build circuit for DHT remote peer request", 0, "dht") return #generate the message: (version, infohash, peerList) msg = "" #header: msg += Basic.write_byte(Node.VERSION) #infohash: msg += infohash #peers: for host, port in self.knownNodes: #is this an IP address? if isIPAddress(host): msg += Basic.write_byte(0) msg += struct.pack("!4sH", socket.inet_aton(host), port) #otherwise, it's a URL that has to be resolved remotely else: msg += Basic.write_byte(1) msg += Basic.write_lenstr(host) msg += Basic.write_short(port) self.circ.send_dht_request(msg, self.make_callback_wrapper(callback))
def write_request(self, data, protocol, replyPort): #write the header: msg = self._write_header("request") #determine the protocol ID: protocolType = None for protocolId, protocolName in self.TEST_TYPES.iteritems(): if protocolName == protocol: protocolType = protocolId break assert protocolType != None, "Specified bad protocol: %s" % (protocol) #write the protocol type: msg += Basic.write_byte(protocolType) #write the port: msg += Basic.write_short(replyPort) #finally, add the data: msg += data return msg
def send_direct_tor_message(self, msg, msgType, forward=True, numHops=1, sendOverCircuit=False): """Tunnel a message through Tor. There are two ways to send data: sendOverCircuit=True: These messages are visible (plain-text) to the hops that they pass through! Callers are responsible for any necessary secrecy and intergrity. sendOverCircuit=False: These messages are encrypted like normal, relayed Tor cells. They are thus encrypted and authenticated, but messages may not be sent between two relays (only between the origin and relays) In either case, messages that are too long will be sent in multiple cells. @param msg: the message to send @type msg: str @param msgType: the type of message. Must be one of MESSAGE_CODES. @type msgType: str @param forward: whether to send towards the exit (True) or towards the origin (False) @type forward: bool @param numHops: how many relays to traverse before the message is delivered. MUST NOT BE 0--in that case, call the handler directly yourself. @type numHops: int @param sendOverCircuit: whether to send over the circuit (True) or simply send over OR connections to adjacent hops (False) @type sendOverCircuit: bool""" if not self.torApp.is_ready(): raise TorCtl.TorCtlClosed if self.isClosed: log_msg("Cannot send Tor message, circuit was closed (%s)" % (msgType)) return # if numHops is 0, you should handle the message yourself, not send it assert numHops != 0, "cannot send a zero hop message" msg = Basic.write_byte(MESSAGE_CODES[msgType]) + msg # put the length in front of the message: msgLen = len(msg) msg = Basic.write_short(msgLen) + msg # who to send it to: nextHexId = self.nextHexId nextCircId = self.nextCircId if not forward: nextCircId = self.prevCircId nextHexId = self.prevHexId dList = [] # different message lengths depending on if sendOverCircuit if True or False: if sendOverCircuit: # are sent as normal relayed messages, so they should be this long WRITABLE_BYTES = 498 else: # since the Tor cell is 512 bytes, but we need 2 for circid, and 1 for the cell command WRITABLE_BYTES = 507 while len(msg) > 0: dataToSend = msg[:WRITABLE_BYTES] msg = msg[WRITABLE_BYTES:] def add_padding(tmp, desiredLen): extraChars = desiredLen - len(tmp) return tmp + (" " * extraChars) dataToSend = add_padding(dataToSend, WRITABLE_BYTES) dataToSend = dataToSend.encode("base64") dataToSend = dataToSend.replace("\n", "").replace("=", "") # convert sendOverCircuit to "1" or "0" for the control connection: if sendOverCircuit: sendOverCircuitToken = "1" else: sendOverCircuitToken = "0" dataToSend = "SENDPAYMENT %s %s %s %s %s\r\n" % ( nextHexId, nextCircId, dataToSend, numHops, sendOverCircuitToken, ) d = self.torApp.conn.sendAndRecv(dataToSend) dList.append(d) d = DeferredList(dList) def response(result): for x in result: if not x[0]: raise Exception(str(x)) if x[1][0][0] != "250": raise Exception(str(result)) read, write = x[1][0][1].split(" ") read = int(read) write = int(write) return (read, write) d.addCallback(response) def error(failure): # this happens occasionally when the circuit is closed at approximately the same time that we send a payment # it can be safely ignored because the circuit is closed and we already learned about it if "552 Cannot find circuit with id" in str(failure): log_msg("A circuit that we tried to send a payment message to was closed. Oops.", 4) self.close() return # otherwise, log an error because this is unexpected log_ex(failure, "SENDPAYMENT failed for circuit=%s" % (nextCircId), [TorCtl.ErrorReply]) d.addErrback(error) return d
def send_direct_tor_message(self, msg, msgType, forward=True, numHops=1, sendOverCircuit=False): """Tunnel a message through Tor. There are two ways to send data: sendOverCircuit=True: These messages are visible (plain-text) to the hops that they pass through! Callers are responsible for any necessary secrecy and intergrity. sendOverCircuit=False: These messages are encrypted like normal, relayed Tor cells. They are thus encrypted and authenticated, but messages may not be sent between two relays (only between the origin and relays) In either case, messages that are too long will be sent in multiple cells. @param msg: the message to send @type msg: str @param msgType: the type of message. Must be one of MESSAGE_CODES. @type msgType: str @param forward: whether to send towards the exit (True) or towards the origin (False) @type forward: bool @param numHops: how many relays to traverse before the message is delivered. MUST NOT BE 0--in that case, call the handler directly yourself. @type numHops: int @param sendOverCircuit: whether to send over the circuit (True) or simply send over OR connections to adjacent hops (False) @type sendOverCircuit: bool""" if not self.torApp.is_ready(): raise TorCtl.TorCtlClosed if self.isClosed: log_msg("Cannot send Tor message, circuit was closed (%s)" % (msgType)) return #if numHops is 0, you should handle the message yourself, not send it assert numHops != 0, "cannot send a zero hop message" msg = Basic.write_byte(MESSAGE_CODES[msgType]) + msg #put the length in front of the message: msgLen = len(msg) msg = Basic.write_short(msgLen) + msg #who to send it to: nextHexId = self.nextHexId nextCircId = self.nextCircId if not forward: nextCircId = self.prevCircId nextHexId = self.prevHexId dList = [] #different message lengths depending on if sendOverCircuit if True or False: if sendOverCircuit: #are sent as normal relayed messages, so they should be this long WRITABLE_BYTES = 498 else: #since the Tor cell is 512 bytes, but we need 2 for circid, and 1 for the cell command WRITABLE_BYTES = 507 while len(msg) > 0: dataToSend = msg[:WRITABLE_BYTES] msg = msg[WRITABLE_BYTES:] def add_padding(tmp, desiredLen): extraChars = desiredLen - len(tmp) return tmp + (" " * extraChars) dataToSend = add_padding(dataToSend, WRITABLE_BYTES) dataToSend = dataToSend.encode("base64") dataToSend = dataToSend.replace('\n', '').replace('=', '') #convert sendOverCircuit to "1" or "0" for the control connection: if sendOverCircuit: sendOverCircuitToken = "1" else: sendOverCircuitToken = "0" dataToSend = "SENDPAYMENT %s %s %s %s %s\r\n" % (nextHexId, nextCircId, dataToSend, numHops, sendOverCircuitToken) d = self.torApp.conn.sendAndRecv(dataToSend) dList.append(d) d = DeferredList(dList) def response(result): for x in result: if not x[0]: raise Exception(str(x)) if x[1][0][0] != '250': raise Exception(str(result)) read, write = x[1][0][1].split(" ") read = int(read) write = int(write) return (read, write) d.addCallback(response) def error(failure): #this happens occasionally when the circuit is closed at approximately the same time that we send a payment #it can be safely ignored because the circuit is closed and we already learned about it if "552 Cannot find circuit with id" in str(failure): log_msg("A circuit that we tried to send a payment message to was closed. Oops.", 4) self.close() return #otherwise, log an error because this is unexpected log_ex(failure, "SENDPAYMENT failed for circuit=%s" % (nextCircId), [TorCtl.ErrorReply]) d.addErrback(error) return d