diff --git a/joinmarket/configure.py b/joinmarket/configure.py index c46039f3..6d94fd09 100644 --- a/joinmarket/configure.py +++ b/joinmarket/configure.py @@ -117,10 +117,17 @@ def jm_single(): socks5_port = 9050 #for tor #host = 6dvj6v5imhny3anf.onion +#for switching nyms between reconnects +#newnym = true +#newnym_delay = 60 +#tor_ctrl_host = localhost +#tor_ctrl_port = 9051 +#tor_ctrl_pass = #port = 6697 #usessl = true #socks5 = true maker_timeout_sec = 30 +reconnect_delay = 30 [POLICY] # for dust sweeping, try merge_algorithm = gradual diff --git a/joinmarket/irc.py b/joinmarket/irc.py index bf5708e4..85978a38 100644 --- a/joinmarket/irc.py +++ b/joinmarket/irc.py @@ -8,6 +8,7 @@ import time import Queue +from ConfigParser import NoOptionError from joinmarket.configure import jm_single, get_config_irc_channel from joinmarket.message_channel import MessageChannel, CJPeerError from joinmarket.enc_wrapper import encrypt_encode, decode_decrypt @@ -497,8 +498,9 @@ def __handle_line(self, line): if self.on_nick_leave: self.on_nick_leave(nick) elif _chunks[1] == '433': # nick in use - # self.nick = random_nick() self.nick += '_' # helps keep identity constant if just _ added + if self.newnyms: + self.nick = random_nick() self.send_raw('NICK ' + self.nick) if self.password: if _chunks[1] == 'CAP': @@ -583,6 +585,24 @@ def __init__(self, self.socks5_port = int(config.get("MESSAGING", "socks5_port")) self.channel = get_config_irc_channel() self.userrealname = (username, realname) + self.reconnect_delay = 30 + self.newnyms = False + try: + self.reconnect_delay = int(config.get("MESSAGING", "reconnect_delay")) + self.newnyms = (config.get("MESSAGING", "newnym").lower() == 'true') + self.tor_ctrl_host = config.get("MESSAGING", "tor_ctrl_host") + self.tor_ctrl_port = int(config.get("MESSAGING", "tor_ctrl_port")) + self.tor_ctrl_pass = config.get("MESSAGING", "tor_ctrl_pass") + self.newnym_delay = int(config.get("MESSAGING", "newnym_delay")) + except NoOptionError as ex: + log.debug('The following newnym option is missing:') + log.debug(ex) + log.debug('.. disabling the feature.') + self.newnyms = False + + if self.newnyms and self.serverport[0].lower().endswith('.onion'): + raise Exception("you can't use newnym=true with host=something.onion") + if password and len(password) == 0: password = None self.given_password = password @@ -590,6 +610,18 @@ def __init__(self, self.throttleQ = Queue.Queue() self.obQ = Queue.Queue() + def newnym(self): + ctrl = socket.create_connection((self.tor_ctrl_host, self.tor_ctrl_port)) + ctrl.send('AUTHENTICATE "%s"\r\n'%self.tor_ctrl_pass) + resp = ctrl.recv(1024) + if resp.startswith('250'): + ctrl.send("signal NEWNYM\r\n") + if resp.startswith('250'): + ctrl.close() + return + ctrl.close() + raise IOError("newnym failed "+resp) + def run(self): self.waiting = {} self.built_privmsg = {} @@ -604,6 +636,10 @@ def run(self): try: config = jm_single().config log.debug('connecting') + if self.newnyms: + log.debug("Grabbing new Tor identity") + self.newnym() + self.nick = random_nick() if config.get("MESSAGING", "socks5").lower() == 'true': log.debug("Using socks5 proxy %s:%d" % (self.socks5_host, self.socks5_port)) @@ -649,6 +685,8 @@ def run(self): self.on_disconnect() log.debug('disconnected irc') if not self.give_up: - time.sleep(30) + time.sleep(self.reconnect_delay) + if self.newnyms: + time.sleep(random.randint(0,self.newnym_delay)) log.debug('ending irc') self.give_up = True diff --git a/joinmarket/maker.py b/joinmarket/maker.py index d90e70bf..d3bfc842 100644 --- a/joinmarket/maker.py +++ b/joinmarket/maker.py @@ -213,7 +213,8 @@ def __init__(self, msgchan, wallet): self.active_orders = {} self.wallet = wallet self.nextoid = -1 - self.orderlist = self.create_my_orders() + if not self.msgchan.newnyms: + self.orderlist = self.create_my_orders() self.wallet_unspent_lock = threading.Lock() def get_crypto_box_from_nick(self, nick): @@ -265,6 +266,8 @@ def on_push_tx(self, nick, txhex): self.msgchan.send_error(nick, 'Unable to push tx') def on_welcome(self): + if self.msgchan.newnyms: + self.orderlist = self.create_my_orders() self.msgchan.announce_orders(self.orderlist) self.active_orders = {} diff --git a/joinmarket/message_channel.py b/joinmarket/message_channel.py index 0a6d4b2d..8f220ab0 100644 --- a/joinmarket/message_channel.py +++ b/joinmarket/message_channel.py @@ -29,6 +29,8 @@ def __init__(self): self.on_seen_auth = None self.on_seen_tx = None self.on_push_tx = None + # chan-specific attributes + self.newnyms = False def run(self): pass