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