-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit cf3ae8f
Showing
5 changed files
with
320 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
Very WIP | ||
Automatically connect to WIFIs. | ||
passwords can be stored in an easy db format | ||
|
||
Requirements: | ||
- NetworkManager | ||
- python3 | ||
|
||
example wifi db: | ||
``` | ||
myssid/mywifipassword | ||
myssid2/mywifipassword2 | ||
``` | ||
|
||
will fallback to open wifis if no known wifi is found. | ||
will try to ping the gateway on the wifi after connecting. | ||
|
||
Available options: | ||
(all directory options take multiple directories) | ||
* `--scan-hooks, -s` - directories with hooks which are run after the scanning phase | ||
* `--wifi_dirs, -w` - directories with wifi dbs | ||
* `--connection-hooks, -c` - directories with hooks which are run after connecting to a wifi | ||
* `--loglevel, -l` - loglevel to log to STDOUT, takes INFO and DEBUG as arguments | ||
* `--pidfile, -p` - file to write the PID to | ||
* `--no-open` - don't connect to open wifis in the end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,291 @@ | ||
import argparse | ||
import logging | ||
import os | ||
import re | ||
import signal | ||
import socket | ||
import struct | ||
import subprocess | ||
import time | ||
import urllib.request | ||
|
||
logger = logging.getLogger() | ||
got_signal = False | ||
|
||
|
||
def signal_handler(_, __): | ||
global got_signal | ||
got_signal = True | ||
|
||
|
||
def get_default_gateway() -> str: | ||
"""Read the default gateway directly from /proc.""" | ||
with open("/proc/net/route") as route_file: | ||
for line in route_file: | ||
fields = line.strip().split() | ||
if fields[1] != '00000000' or not int(fields[3], 16) & 2: | ||
continue | ||
|
||
return socket.inet_ntoa(struct.pack("<L", int(fields[2], 16))) | ||
|
||
|
||
def connect(ssid, psk=None): | ||
subprocess.run( | ||
["nmcli", "connection", "delete", "autowifi"], | ||
stdout=subprocess.PIPE, | ||
) | ||
logging.info('connecting to %s', ssid) | ||
if psk is None: | ||
subprocess.run( | ||
[ | ||
"nmcli", | ||
"device", | ||
"wifi", | ||
"connect", | ||
ssid, | ||
"name", | ||
"autowifi", | ||
], | ||
stdout=subprocess.PIPE, | ||
) | ||
else: | ||
subprocess.run( | ||
[ | ||
"nmcli", | ||
"device", | ||
"wifi", | ||
"connect", | ||
ssid, | ||
"name", | ||
"autowifi", | ||
"password", | ||
psk, | ||
], | ||
stdout=subprocess.PIPE, | ||
) | ||
time.sleep(5) | ||
|
||
|
||
def scan(): | ||
logging.debug('scanning wifis') | ||
wifis_raw = subprocess.check_output([ | ||
"nmcli", | ||
"-e", "no", | ||
"-f", "ssid,signal,security,rsn-flags,bssid", | ||
"-t", | ||
"device", "wifi", "list", | ||
"--rescan", "auto", | ||
]) | ||
wifis_list = wifis_raw.split(b'\n') | ||
logging.debug('scanning wifis finished') | ||
wifis = [] | ||
for line in wifis_list: | ||
logging.debug(line) | ||
ls = re.split(rb'(?<!\\):', line) | ||
if len(ls) == 10: | ||
wifis.append({ | ||
"ssid": ls[0], | ||
"signal": int(ls[1]), | ||
"crypto": ls[2], | ||
"flags": ls[3], | ||
"bssid": b':'.join(ls[4:]), | ||
}) | ||
return wifis | ||
|
||
|
||
def get_known_wifis(wifi_dirs): | ||
wifis_lines = [] | ||
for wdir in wifi_dirs: | ||
for wfile in os.listdir(wdir): | ||
with open(os.path.join(wdir, wfile)) as f: | ||
wifis_lines += f.read().splitlines() | ||
wifis = [] | ||
for line in wifis_lines: | ||
ls = line.split('/') | ||
wifis.append({"ssid": ls[0].encode(), "psk": ls[1].encode()}) | ||
return wifis | ||
|
||
|
||
def check_network(): | ||
logging.debug('checking network') | ||
|
||
gateway = get_default_gateway() | ||
if gateway: | ||
response = subprocess.run( | ||
[ | ||
'ping', | ||
'-q', | ||
'-c', | ||
'1', | ||
gateway, | ||
], | ||
stdout=subprocess.PIPE, | ||
) | ||
if response.returncode == 0: | ||
logging.debug('host %s is up', gateway) | ||
return True | ||
else: | ||
logging.debug('host %s is down', gateway) | ||
return False | ||
else: | ||
logging.debug('no gateway') | ||
return False | ||
|
||
|
||
def check_internet(): | ||
logging.debug('checking internet') | ||
|
||
try: | ||
beacon = urllib.request.urlopen('http://krebsco.de/secret') | ||
except Exception as e: # noqa | ||
logging.debug(e) | ||
logging.info('no internet exc') | ||
return False | ||
if beacon.read() == b'1337\n': | ||
return True | ||
logging.info('no internet oh') | ||
return False | ||
|
||
|
||
def is_wifi_open(wifi): | ||
if wifi['crypto'] == b'': | ||
return True | ||
else: | ||
return False | ||
|
||
|
||
def is_wifi_seen(wifi, seen_wifis): | ||
for seen_wifi in seen_wifis: | ||
if seen_wifi["ssid"] == wifi["ssid"]: | ||
return True | ||
return False | ||
|
||
|
||
def run_hooks(dirs, wifi): | ||
outputs = {} | ||
for directory in dirs: | ||
for hfile in os.listdir(directory): | ||
try: | ||
hook_output = subprocess.check_output([ | ||
str(os.path.join(directory, hfile)), | ||
str(wifi['ssid']), | ||
str(wifi['signal']), | ||
str(wifi['crypto']), | ||
str(wifi['flags']), | ||
str(wifi['bssid']), | ||
]) | ||
outputs[hfile] = hook_output | ||
except OSError: | ||
logging.info('running plugin: {} failed'.format(hfile)) | ||
return outputs | ||
|
||
|
||
def stay_connected_loop(allowed_fails=5): | ||
fails = 0 | ||
if check_network(): | ||
while True: | ||
global got_signal | ||
if got_signal: | ||
logging.info('got disconnect signal') | ||
got_signal = False | ||
break | ||
else: | ||
if check_network(): | ||
time.sleep(10) | ||
else: | ||
fails += 1 | ||
if fails > allowed_fails: | ||
logging.debug('network gone, giving up') | ||
break | ||
else: | ||
logging.debug('hmm, missed ping, will try again shortly') | ||
time.sleep(3) | ||
|
||
|
||
def main(): | ||
parser = argparse.ArgumentParser() | ||
|
||
parser.add_argument( | ||
'-x', '--scan-hooks', | ||
dest='scan_hooks', | ||
nargs='*', | ||
help='directories with scan hooks (executed after scan)', | ||
default=['/etc/autowifi/scan_hooks'], | ||
) | ||
|
||
parser.add_argument( | ||
'-w', '--wifi_dirs', | ||
dest='wifi_dirs', | ||
nargs='*', | ||
help='directories with wifi configs', | ||
default=['/etc/autowifi/wifis'], | ||
) | ||
|
||
parser.add_argument( | ||
'-c', '--connection-hooks', | ||
dest='con_hooks', | ||
nargs='*', | ||
help='directories with connection hooks (executed after connection)', | ||
default=['/etc/autowifi/con_hooks'], | ||
) | ||
|
||
parser.add_argument( | ||
'-l', '--loglevel', | ||
dest='loglevel', | ||
help='loglevel to use', | ||
default=logging.INFO, | ||
) | ||
|
||
parser.add_argument( | ||
'-p', '--pidfile', | ||
dest='pidfile', | ||
help='file to write the pid to', | ||
default=None, | ||
) | ||
|
||
parser.add_argument( | ||
'--no-open', | ||
dest='no_open_networks', | ||
help='dont connect to open networks', | ||
default=False, | ||
action='store_true', | ||
) | ||
|
||
args = parser.parse_args() | ||
|
||
wifi_dirs = args.wifi_dirs | ||
logger.setLevel(args.loglevel) | ||
|
||
signal.signal(signal.SIGUSR1, signal_handler) | ||
|
||
if args.pidfile: | ||
with open(args.pidfile, 'w+') as f: | ||
f.write(str(os.getpid())) | ||
|
||
while True: | ||
stay_connected_loop() | ||
wifis = scan() | ||
known_wifis = get_known_wifis(wifi_dirs) | ||
known_seen_wifis = [ | ||
wifi for wifi in known_wifis if is_wifi_seen(wifi, wifis) | ||
] | ||
for wifi in known_seen_wifis: | ||
connect(wifi['ssid'], wifi['psk']) | ||
if check_network(): | ||
logging.debug('connected to secure wifi, going into busy loop') | ||
break | ||
if check_network(): | ||
continue | ||
logging.debug('no known secure wifi, connecting to open ones') | ||
if not args.no_open_networks: | ||
logging.debug('connecting to open wifis') | ||
open_wifis = filter(is_wifi_open, wifis) | ||
for wifi in open_wifis: | ||
connect(wifi['ssid']) | ||
if check_network(): | ||
run_hooks(args.con_hooks, wifi) | ||
break | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
myssid/mypassword |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pkgs.writers.writePython3Bin "autowifi" {} ./autowifi.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
#!/bin/sh | ||
nix-shell $HOME/sync/prison-break --run 'python $HOME/sync/prison-break/prisonbreak/cli.py --force-run' |