mirror of
https://github.com/jayofelony/pwnagotchi.git
synced 2025-07-01 18:37:27 -04:00
bt-tether rework
- Move connexion to NetworkManager autoconnect for more reliability - Check options formats for several values - Add a dns option to be able to choose another DNS provider (ex: OpenNIC for no traceability) - The "BT" show more information (Device Connected/disconnected, Connexion Up/Down) - Status now show a message on error - nmcli calls are non-blocking - Less logs when disconnected (ex: phone's bluetooth is off) Signed-off-by: Frédéric <fmatray@users.noreply.github.com>
This commit is contained in:
@ -1,93 +1,130 @@
|
|||||||
import logging
|
import logging
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import re
|
||||||
|
|
||||||
import pwnagotchi.plugins as plugins
|
import pwnagotchi.plugins as plugins
|
||||||
import pwnagotchi.ui.fonts as fonts
|
import pwnagotchi.ui.fonts as fonts
|
||||||
from pwnagotchi.ui.components import LabeledValue
|
from pwnagotchi.ui.components import LabeledValue
|
||||||
from pwnagotchi.ui.view import BLACK
|
from pwnagotchi.ui.view import BLACK
|
||||||
|
|
||||||
|
MAC_PTTRN = "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$"
|
||||||
|
IP_PTTRN = "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$"
|
||||||
|
|
||||||
class BTTether(plugins.Plugin):
|
class BTTether(plugins.Plugin):
|
||||||
__author__ = 'Jayofelony'
|
__author__ = "Jayofelony, modified my fmatray"
|
||||||
__version__ = '1.2'
|
__version__ = "1.3"
|
||||||
__license__ = 'GPL3'
|
__license__ = "GPL3"
|
||||||
__description__ = 'A new BT-Tether plugin'
|
__description__ = "A new BT-Tether plugin"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.ready = False
|
self.ready = False
|
||||||
self.options = dict()
|
self.options = dict()
|
||||||
self.status = '-'
|
self.phone_name = None
|
||||||
|
self.mac = None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def nmcli(args, pattern=None):
|
||||||
|
try:
|
||||||
|
result = subprocess.run(["nmcli"] + args,
|
||||||
|
check=True, capture_output=True, text=True)
|
||||||
|
if pattern:
|
||||||
|
return result.stdout.find(pattern)
|
||||||
|
return result
|
||||||
|
except Exception as exp:
|
||||||
|
logging.error(f"[BT-Tether] Error with nmcli: {exp}")
|
||||||
|
raise exp
|
||||||
|
|
||||||
def on_loaded(self):
|
def on_loaded(self):
|
||||||
logging.info("[BT-Tether] plugin loaded.")
|
logging.info("[BT-Tether] plugin loaded.")
|
||||||
|
|
||||||
def on_config_changed(self, config):
|
def on_config_changed(self, config):
|
||||||
if any(self.options[key] == '' for key in ['phone', 'phone-name', 'ip', 'mac']):
|
if "phone-name" not in self.options:
|
||||||
self.ready = False
|
logging.error("[BT-Tether] Phone name not provided")
|
||||||
ip = self.options['ip']
|
return
|
||||||
mac = self.options['mac']
|
if not ("mac" in self.options and re.match(MAC_PTTRN, self.options["mac"])):
|
||||||
phone_name = self.options['phone-name'] + ' Network'
|
logging.error("[BT-Tether] Error with mac adresse")
|
||||||
if self.options['phone'].lower() == 'android':
|
return
|
||||||
address = f'{ip}'
|
|
||||||
gateway = '192.168.44.1'
|
if not ("phone" in self.options and self.options["phone"].lower() in ["android", "ios"]):
|
||||||
elif self.options['phone'].lower() == 'ios':
|
logging.error("[BT-Tether] Phone type not supported")
|
||||||
address = f'{ip}'
|
return
|
||||||
gateway = '172.20.10.1'
|
if self.options["phone"].lower() == "android":
|
||||||
else:
|
address = self.options.get("ip", "192.168.44.2")
|
||||||
logging.error("[BT-Tether] Phone type not supported.")
|
gateway = "192.168.44.1"
|
||||||
|
elif self.options["phone"].lower() == "ios":
|
||||||
|
address = self.options.get("ip", "172.20.10.2")
|
||||||
|
gateway = "172.20.10.1"
|
||||||
|
if not re.match(IP_PTTRN, address):
|
||||||
|
logging.error(f"[BT-Tether] IP error: {address}")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.phone_name = self.options["phone-name"] + " Network"
|
||||||
|
self.mac = self.options["mac"]
|
||||||
|
dns = self.options.get("dns", "8.8.8.8 1.1.1.1").replace(",", " ").replace(";", " ")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Configure connection. Metric is set to 200 to prefer connection over USB
|
||||||
|
self.nmcli(["connection", "modify", f"{self.phone_name}",
|
||||||
|
"connection.type", "bluetooth",
|
||||||
|
"bluetooth.type", "panu",
|
||||||
|
"bluetooth.bdaddr", f"{self.mac}",
|
||||||
|
"connection.autoconnect", "yes",
|
||||||
|
"connection.autoconnect-retries", "0",
|
||||||
|
"ipv4.method", "manual",
|
||||||
|
"ipv4.dns", f"{dns}",
|
||||||
|
"ipv4.addresses", f"{address}/24",
|
||||||
|
"ipv4.gateway", f"{gateway}",
|
||||||
|
"ipv4.route-metric", "200" ])
|
||||||
|
self.nmcli(["connection", "reload"])
|
||||||
|
self.ready = True
|
||||||
|
logging.info(f"[BT-Tether] Connection {self.phone_name} configured")
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"[BT-Tether] Error while configuring: {e}")
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
subprocess.run([
|
self.nmcli(["connection", "up", f"{self.phone_name}"])
|
||||||
'nmcli', 'connection', 'modify', f'{phone_name}',
|
|
||||||
'connection.type', 'bluetooth',
|
|
||||||
'bluetooth.type', 'panu',
|
|
||||||
'bluetooth.bdaddr', f'{mac}',
|
|
||||||
'ipv4.method', 'manual',
|
|
||||||
'ipv4.dns', '8.8.8.8 1.1.1.1',
|
|
||||||
'ipv4.addresses', f'{address}/24',
|
|
||||||
'ipv4.gateway', f'{gateway}',
|
|
||||||
'ipv4.route-metric', '100'
|
|
||||||
], check=True)
|
|
||||||
subprocess.run(['nmcli', 'connection', 'reload'], check=True)
|
|
||||||
subprocess.run(['nmcli', 'connection', 'up', f'{phone_name}'], check=True)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"[BT-Tether] Failed to connect to device: {e}")
|
logging.error(f"[BT-Tether] Failed to connect to device: {e}")
|
||||||
logging.error(f"[BT-Tether] Failed to connect to device: have you enabled bluetooth tethering on your phone?")
|
logging.error(
|
||||||
self.ready = True
|
f"[BT-Tether] Failed to connect to device: have you enabled bluetooth tethering on your phone?"
|
||||||
|
)
|
||||||
def on_ready(self, agent):
|
|
||||||
if any(self.options[key] == '' for key in ['phone', 'phone-name', 'ip', 'mac']):
|
|
||||||
self.ready = False
|
|
||||||
self.ready = True
|
|
||||||
|
|
||||||
def on_ui_setup(self, ui):
|
def on_ui_setup(self, ui):
|
||||||
with ui._lock:
|
with ui._lock:
|
||||||
ui.add_element('bluetooth', LabeledValue(color=BLACK, label='BT', value='-',
|
ui.add_element('bluetooth', LabeledValue(color=BLACK, label='BT', value='-',
|
||||||
position=(ui.width() / 2 - 10, 0),
|
position=(ui.width() / 2 - 10, 0),
|
||||||
label_font=fonts.Bold, text_font=fonts.Medium))
|
label_font=fonts.Bold, text_font=fonts.Medium))
|
||||||
|
|
||||||
def on_ui_update(self, ui):
|
def on_ui_update(self, ui):
|
||||||
if self.ready:
|
if not self.ready:
|
||||||
phone_name = self.options['phone-name'] + ' Network'
|
return
|
||||||
if (subprocess.run(['bluetoothctl', 'info'], capture_output=True, text=True)).stdout.find('Connected: yes') != -1:
|
with ui._lock:
|
||||||
self.status = 'C'
|
status = ""
|
||||||
else:
|
try:
|
||||||
self.status = '-'
|
# Checking connection
|
||||||
try:
|
if self.nmcli(["-w", "0", "-g", "GENERAL.STATE", "connection", "show", self.phone_name],
|
||||||
subprocess.run(['nmcli', 'connection', 'up', f'{phone_name}'], check=True)
|
"activated") != -1:
|
||||||
except Exception as e:
|
ui.set("bluetooth", "U")
|
||||||
logging.debug(f"[BT-Tether] Failed to connect to device: {e}")
|
return
|
||||||
logging.error(f"[BT-Tether] Failed to connect to device: have you enabled bluetooth tethering on your phone?")
|
else:
|
||||||
ui.set('bluetooth', self.status)
|
ui.set("bluetooth", "D")
|
||||||
return
|
status = "BT Conn. down"
|
||||||
|
|
||||||
|
# Checking device
|
||||||
|
if self.nmcli(["-w", "0", "-g", "GENERAL.STATE", "device", "show", self.mac],
|
||||||
|
"(connected)") != -1:
|
||||||
|
ui.set("bluetooth", "C")
|
||||||
|
status += "\nBT dev conn."
|
||||||
|
else:
|
||||||
|
ui.set("bluetooth", "-")
|
||||||
|
status += "\nBT dev disconn."
|
||||||
|
ui.set("status", status)
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"[BT-Tether] Error on update: {e}")
|
||||||
|
|
||||||
def on_unload(self, ui):
|
def on_unload(self, ui):
|
||||||
phone_name = self.options['phone-name'] + ' Network'
|
|
||||||
with ui._lock:
|
with ui._lock:
|
||||||
ui.remove_element('bluetooth')
|
ui.remove_element("bluetooth")
|
||||||
try:
|
try:
|
||||||
if (subprocess.run(['bluetoothctl', 'info'], capture_output=True, text=True)).stdout.find('Connected: yes') != -1:
|
self.nmcli(["connection", "down", f"{self.phone_name}"])
|
||||||
subprocess.run(['nmcli', 'connection', 'down', f'{phone_name}'], check=True)
|
|
||||||
logging.info(f"[BT-Tether] Disconnected from device with name: {phone_name}")
|
|
||||||
else:
|
|
||||||
logging.info(f"[BT-Tether] Device with name {phone_name} is not connected, not disconnecting")
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"[BT-Tether] Failed to disconnect from device: {e}")
|
logging.error(f"[BT-Tether] Failed to disconnect from device: {e}")
|
Reference in New Issue
Block a user