diff --git a/plugins/openalias.py b/plugins/openalias.py index 545f789b..07485b01 100644 --- a/plugins/openalias.py +++ b/plugins/openalias.py @@ -1,5 +1,6 @@ from electrum_gui.qt.util import EnterButton from electrum.plugins import BasePlugin, hook +from electrum.util import print_msg from electrum.i18n import _ from PyQt4.QtGui import * from PyQt4.QtCore import * @@ -43,6 +44,7 @@ class Plugin(BasePlugin): return OA_READY def __init__(self, gui, name): + print_msg('[OA] Initialiasing OpenAlias plugin, OA_READY is ' + str(OA_READY)) BasePlugin.__init__(self, gui, name) self._is_available = OA_READY @@ -82,9 +84,12 @@ class Plugin(BasePlugin): if not data: return True + (address, name) = data + self.win.payto_e.setText(address) + if not self.validate_dnssec(url): msgBox = QMessageBox() - msgBox.setText(_('No valid DNSSEC trust chain!')) + msgBox.setText(_('WARNING: the address ' + address + ' could not be validated via an additional security check, DNSSEC, and thus may not be correct.')) msgBox.setInformativeText(_('Do you wish to continue?')) msgBox.setStandardButtons(QMessageBox.Cancel | QMessageBox.Ok) msgBox.setDefaultButton(QMessageBox.Cancel) @@ -92,8 +97,6 @@ class Plugin(BasePlugin): if reply != QMessageBox.Ok: return True - (address, name) = data - self.win.payto_e.setText(address) if self.config.get('openalias_autoadd') == 'checked': self.win.wallet.add_contact(address, name) return False @@ -150,9 +153,11 @@ class Plugin(BasePlugin): if not data: return + (address, name) = data + if not self.validate_dnssec(url): msgBox = QMessageBox() - msgBox.setText("No valid DNSSEC trust chain!") + msgBox.setText(_('WARNING: the address ' + address + ' could not be validated via an additional security check, DNSSEC, and thus may not be correct.')) msgBox.setInformativeText("Do you wish to continue?") msgBox.setStandardButtons(QMessageBox.Cancel | QMessageBox.Ok) msgBox.setDefaultButton(QMessageBox.Cancel) @@ -160,8 +165,6 @@ class Plugin(BasePlugin): if reply != QMessageBox.Ok: return - (address, name) = data - d2 = QDialog(self.win) vbox2 = QVBoxLayout(d2) grid2 = QGridLayout() @@ -196,15 +199,17 @@ class Plugin(BasePlugin): def resolve(self, url): '''Resolve OpenAlias address using url.''' + print_msg('[OA] Attempting to resolve OpenAlias data for ' + url) + prefix = 'btc' retries = 3 err = None for i in range(0, retries): try: resolver = dns.resolver.Resolver() - resolver.timeout = 15.0 - resolver.lifetime = 15.0 - records = resolver.query(url, 'TXT') + resolver.timeout = 2.0 + resolver.lifetime = 2.0 + records = resolver.query(url, dns.rdatatype.TXT) for record in records: string = record.strings[0] if string.startswith('oa1:' + prefix): @@ -215,10 +220,10 @@ class Plugin(BasePlugin): return (address, name) QMessageBox.warning(self.win, _('Error'), _('No OpenAlias record found.'), _('OK')) return 0 - except resolver.NXDOMAIN: + except dns.resolver.NXDOMAIN: err = _('No such domain.') continue - except resolver.Timeout: + except dns.resolver.Timeout: err = _('Timed out while resolving.') continue except DNSException: @@ -240,48 +245,53 @@ class Plugin(BasePlugin): return None def validate_dnssec(self, url): - default = dns.resolver.get_default_resolver() - ns = default.nameservers[0] - - parts = url.split('.') - - for i in xrange(len(parts), 0, -1): - sub = '.'.join(parts[i - 1:]) - - query = dns.message.make_query(sub, dns.rdatatype.NS) - response = dns.query.udp(query, ns, 5) - - if response.rcode() != dns.rcode.NOERROR: - return 0 - - if len(response.authority) > 0: - rrset = response.authority[0] - else: - rrset = response.answer[0] - - rr = rrset[0] - if rr.rdtype == dns.rdatatype.SOA: - #Same server is authoritative, don't check again - continue - - query = dns.message.make_query(sub, - dns.rdatatype.DNSKEY, - want_dnssec=True) - response = dns.query.udp(query, ns, 5) - - if response.rcode() != 0: - return 0 - # HANDLE QUERY FAILED (SERVER ERROR OR NO DNSKEY RECORD) - - # answer should contain two RRSET: DNSKEY and RRSIG(DNSKEY) - answer = response.answer - if len(answer) != 2: - return 0 - - # the DNSKEY should be self signed, validate it - name = dns.name.from_text(sub) - try: - dns.dnssec.validate(answer[0], answer[1], {name: answer[0]}) - except dns.dnssec.ValidationFailure: - return 0 + print_msg('[OA] Checking DNSSEC trust chain for ' + url) + + try: + default = dns.resolver.get_default_resolver() + ns = default.nameservers[0] + + parts = url.split('.') + + for i in xrange(len(parts), 0, -1): + sub = '.'.join(parts[i - 1:]) + + query = dns.message.make_query(sub, dns.rdatatype.NS) + response = dns.query.udp(query, ns, 1) + + if response.rcode() != dns.rcode.NOERROR: + return 0 + + if len(response.authority) > 0: + rrset = response.authority[0] + else: + rrset = response.answer[0] + + rr = rrset[0] + if rr.rdtype == dns.rdatatype.SOA: + #Same server is authoritative, don't check again + continue + + query = dns.message.make_query(sub, + dns.rdatatype.DNSKEY, + want_dnssec=True) + response = dns.query.udp(query, ns, 1) + + if response.rcode() != 0: + return 0 + # HANDLE QUERY FAILED (SERVER ERROR OR NO DNSKEY RECORD) + + # answer should contain two RRSET: DNSKEY and RRSIG(DNSKEY) + answer = response.answer + if len(answer) != 2: + return 0 + + # the DNSKEY should be self signed, validate it + name = dns.name.from_text(sub) + try: + dns.dnssec.validate(answer[0], answer[1], {name: answer[0]}) + except dns.dnssec.ValidationFailure: + return 0 + except Exception,e: + return 0 return 1 \ No newline at end of file