core (xmpp), plugin android: fixed DNS, SRV handling on Android:
Android doesn't have a "/etc/resolv.conf" that Twisted expect. As a result, SRV records can't be checked correctly on connection. To work around that, DNS servers used on Android are checked when necessary (on Android plugin startup and on connectivity change), using some hacks, and Twisted is patched to use them.
This commit is contained in:
parent
bc3abd6920
commit
104902f076
1 changed files with 63 additions and 5 deletions
|
|
@ -25,10 +25,14 @@ from sat.core.i18n import _, D_
|
|||
from sat.core.constants import Const as C
|
||||
from sat.core.log import getLogger
|
||||
from sat.core import exceptions
|
||||
from sat.tools.common import async_process
|
||||
from sat.memory import params
|
||||
from twisted.names import client as dns_client
|
||||
from twisted.python.procutils import which
|
||||
from twisted.internet import defer
|
||||
from twisted.internet import reactor
|
||||
from twisted.internet import protocol
|
||||
from twisted.internet import abstract
|
||||
from twisted.internet import error as int_error
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
|
@ -49,7 +53,9 @@ if sys.platform != "android":
|
|||
raise exceptions.CancelError("this module is not needed on this platform")
|
||||
|
||||
|
||||
import re
|
||||
from plyer import vibrator
|
||||
from android import api_version
|
||||
from plyer.platforms.android import activity
|
||||
from plyer.platforms.android.notification import AndroidNotification
|
||||
from jnius import autoclass
|
||||
|
|
@ -67,6 +73,11 @@ AndroidString = autoclass('java.lang.String')
|
|||
PendingIntent = autoclass('android.app.PendingIntent')
|
||||
Intent = autoclass('android.content.Intent')
|
||||
|
||||
# DNS
|
||||
# regex to find dns server prop with "getprop"
|
||||
RE_DNS = re.compile(r"^\[net\.[a-z0-9]+\.dns[0-4]\]: \[(.*)\]$", re.MULTILINE)
|
||||
SystemProperties = autoclass('android.os.SystemProperties')
|
||||
|
||||
#: delay between a pause event and sending the inactive indication to server, in seconds
|
||||
#: we don't send the indication immediately because user can be just checking something
|
||||
#: quickly on an other app.
|
||||
|
|
@ -213,6 +224,7 @@ class AndroidPlugin(object):
|
|||
|
||||
def __init__(self, host):
|
||||
log.info(_("plugin Android initialization"))
|
||||
log.info(f"using Android API {api_version}")
|
||||
self.host = host
|
||||
self._csi = host.plugins.get('XEP-0352')
|
||||
self._csi_timer = None
|
||||
|
|
@ -263,6 +275,9 @@ class AndroidPlugin(object):
|
|||
self.notif_player.setAudioStreamType(AudioManager.STREAM_NOTIFICATION)
|
||||
self.notif_player.prepare()
|
||||
|
||||
# DNS fix
|
||||
defer.ensureDeferred(self.updateResolver())
|
||||
|
||||
# Connectivity handling
|
||||
self.cm = activity.getSystemService(Context.CONNECTIVITY_SERVICE)
|
||||
self._net_type = None
|
||||
|
|
@ -424,6 +439,8 @@ class AndroidPlugin(object):
|
|||
for client in self.host.getClients(C.PROF_KEY_ALL):
|
||||
client.networkDisabled()
|
||||
else:
|
||||
# DNS servers may have changed
|
||||
await self.updateResolver()
|
||||
# client may be there but disabled (e.g. with stream management)
|
||||
for client in self.host.getClients(C.PROF_KEY_ALL):
|
||||
log.debug(f"enabling network for {client.profile}")
|
||||
|
|
@ -478,3 +495,49 @@ class AndroidPlugin(object):
|
|||
log.debug("onConnectivityChange called")
|
||||
d = defer.ensureDeferred(self._checkConnectivity())
|
||||
d.addErrback(self.host.logErrback)
|
||||
|
||||
async def updateResolver(self):
|
||||
# There is no "/etc/resolv.conf" on Android, which confuse Twisted and makes
|
||||
# SRV record checking unusable. We fixe that by checking DNS server used, and
|
||||
# updating Twisted's resolver accordingly
|
||||
dns_servers = await self.getDNSServers()
|
||||
|
||||
log.info(
|
||||
"Patching Twisted to use Android DNS resolver ({dns_servers})".format(
|
||||
dns_servers=', '.join([s[0] for s in dns_servers]))
|
||||
)
|
||||
dns_client.theResolver = dns_client.createResolver(servers=dns_servers)
|
||||
|
||||
async def getDNSServers(self):
|
||||
servers = []
|
||||
|
||||
if api_version < 26:
|
||||
# thanks to A-IV at https://stackoverflow.com/a/11362271 for the way to go
|
||||
log.debug("Old API, using SystemProperties to find DNS")
|
||||
for idx in range(1, 5):
|
||||
addr = SystemProperties.get(f'net.dns{idx}')
|
||||
if abstract.isIPAddress(addr):
|
||||
servers.append((addr, 53))
|
||||
else:
|
||||
log.debug(f"API {api_version} >= 26, using getprop to find DNS")
|
||||
# use of getprop inspired by various solutions at
|
||||
# https://stackoverflow.com/q/3070144
|
||||
# it's the most simple option, and it fit wells with async_process
|
||||
getprop_paths = which('getprop')
|
||||
if getprop_paths:
|
||||
try:
|
||||
getprop_path = getprop_paths[0]
|
||||
props = await async_process.run(getprop_path)
|
||||
servers = [(ip, 53) for ip in RE_DNS.findall(props.decode())
|
||||
if abstract.isIPAddress(ip)]
|
||||
except Exception as e:
|
||||
log.warning(f"Can't use \"getprop\" to find DNS server: {e}")
|
||||
if not servers:
|
||||
# FIXME: Cloudflare's 1.1.1.1 seems to have a better privacy policy, to be
|
||||
# checked.
|
||||
log.warning(
|
||||
"no server found, we have to use factory Google DNS, this is not ideal "
|
||||
"for privacy"
|
||||
)
|
||||
servers.append(('8.8.8.8', 53), ('8.8.4.4', 53))
|
||||
return servers
|
||||
|
|
|
|||
Loading…
Reference in a new issue