···11-Very WIP
22-Automatically connect to WIFIs.
33-passwords can be stored in an easy db format
44-55-Requirements:
66-- NetworkManager
77-- python3
88-99-example wifi db:
1010-```
1111-myssid/mywifipassword
1212-myssid2/mywifipassword2
1313-```
1414-1515-will fallback to open wifis if no known wifi is found.
1616-will try to ping the gateway on the wifi after connecting.
1717-1818-Available options:
1919-(all directory options take multiple directories)
2020-* `--scan-hooks, -s` - directories with hooks which are run after the scanning phase
2121-* `--connection-hooks, -c` - directories with hooks which are run after connecting to a wifi
2222-* `--wifi_dirs, -w` - directories with wifi dbs
2323-* `--loglevel, -l` - loglevel to log to STDOUT, takes INFO and DEBUG as arguments
2424-* `--pidfile, -p` - file to write the PID to
2525-* `--no-open` - don't connect to open wifis in the end
2626-2727-2828-## FLOW
2929-3030-
-290
5pkgs/autowifi/autowifi.py
···11-import argparse
22-import json
33-import logging
44-import os
55-import re
66-import signal
77-import socket
88-import struct
99-import subprocess
1010-import time
1111-import urllib.request
1212-1313-logger = logging.getLogger()
1414-got_signal = False
1515-1616-1717-def signal_handler(_, __):
1818- global got_signal
1919- got_signal = True
2020-2121-2222-def get_default_gateway() -> str:
2323- """Read the default gateway directly from /proc."""
2424- with open("/proc/net/route") as route_file:
2525- for line in route_file:
2626- fields = line.strip().split()
2727- if fields[1] != '00000000' or not int(fields[3], 16) & 2:
2828- continue
2929-3030- return socket.inet_ntoa(struct.pack("<L", int(fields[2], 16)))
3131-3232-3333-def connect(ssid, psk=None):
3434- subprocess.run(
3535- ["nmcli", "connection", "delete", "autowifi"],
3636- stdout=subprocess.PIPE,
3737- )
3838- logging.info('connecting to %s', ssid)
3939- if psk is None:
4040- subprocess.run(
4141- [
4242- "nmcli",
4343- "device",
4444- "wifi",
4545- "connect",
4646- ssid,
4747- "name",
4848- "autowifi",
4949- ],
5050- stdout=subprocess.PIPE,
5151- )
5252- else:
5353- subprocess.run(
5454- [
5555- "nmcli",
5656- "device",
5757- "wifi",
5858- "connect",
5959- ssid,
6060- "name",
6161- "autowifi",
6262- "password",
6363- psk,
6464- ],
6565- stdout=subprocess.PIPE,
6666- )
6767- time.sleep(5)
6868-6969-7070-def scan():
7171- logging.debug('scanning wifis')
7272- wifis_raw = subprocess.check_output([
7373- "nmcli",
7474- "-e", "no",
7575- "-f", "ssid,signal,security,rsn-flags,bssid",
7676- "-t",
7777- "device", "wifi", "list",
7878- "--rescan", "auto",
7979- ])
8080- wifis_list = wifis_raw.split(b'\n')
8181- logging.debug('scanning wifis finished')
8282- wifis = []
8383- for line in wifis_list:
8484- logging.debug(line)
8585- ls = re.split(rb'(?<!\\):', line)
8686- if len(ls) == 10:
8787- wifis.append({
8888- "ssid": ls[0],
8989- "signal": int(ls[1]),
9090- "crypto": ls[2],
9191- "flags": ls[3],
9292- "bssid": b':'.join(ls[4:]),
9393- })
9494- return wifis
9595-9696-9797-def get_known_wifis(wifi_dirs):
9898- wifis_lines = []
9999- for wdir in wifi_dirs:
100100- for wfile in os.listdir(wdir):
101101- with open(os.path.join(wdir, wfile)) as f:
102102- wifis_lines += f.read().splitlines()
103103- wifis = []
104104- for line in wifis_lines:
105105- ls = line.split('/')
106106- wifis.append({"ssid": ls[0].encode(), "psk": ls[1].encode()})
107107- return wifis
108108-109109-110110-def check_network():
111111- logging.debug('checking network')
112112-113113- gateway = get_default_gateway()
114114- if gateway:
115115- response = subprocess.run(
116116- [
117117- 'ping',
118118- '-q',
119119- '-c',
120120- '1',
121121- gateway,
122122- ],
123123- stdout=subprocess.PIPE,
124124- )
125125- if response.returncode == 0:
126126- logging.debug('host %s is up', gateway)
127127- return True
128128- else:
129129- logging.debug('host %s is down', gateway)
130130- return False
131131- else:
132132- logging.debug('no gateway')
133133- return False
134134-135135-136136-def check_internet():
137137- logging.debug('checking internet')
138138-139139- try:
140140- beacon = urllib.request.urlopen('http://krebsco.de/secret')
141141- except Exception as e: # noqa
142142- logging.debug(e)
143143- logging.info('no internet exc')
144144- return False
145145- if beacon.read() == b'1337\n':
146146- return True
147147- logging.info('no internet oh')
148148- return False
149149-150150-151151-def is_wifi_open(wifi):
152152- if wifi['crypto'] == b'':
153153- return True
154154- else:
155155- return False
156156-157157-158158-def is_wifi_seen(wifi, seen_wifis):
159159- for seen_wifi in seen_wifis:
160160- if seen_wifi["ssid"] == wifi["ssid"]:
161161- return True
162162- return False
163163-164164-165165-def run_hooks(dirs, wifi):
166166- outputs = {}
167167- for directory in dirs:
168168- for hfile in os.listdir(directory):
169169- try:
170170- hook_output = subprocess.check_output([
171171- str(os.path.join(directory, hfile)),
172172- json.dumps(wifi)
173173- ])
174174- outputs[hfile] = hook_output
175175- except OSError as e:
176176- logging.debug(e)
177177- logging.info('running plugin: {} failed'.format(hfile))
178178- return outputs
179179-180180-181181-def stay_connected_loop(allowed_fails=5):
182182- fails = 0
183183- if check_network():
184184- while True:
185185- global got_signal
186186- if got_signal:
187187- logging.info('got disconnect signal')
188188- got_signal = False
189189- break
190190- else:
191191- if check_network():
192192- time.sleep(10)
193193- else:
194194- fails += 1
195195- if fails > allowed_fails:
196196- logging.debug('network gone, giving up')
197197- break
198198- else:
199199- logging.debug('hmm, missed ping, will try again shortly')
200200- time.sleep(3)
201201-202202-203203-def main():
204204- parser = argparse.ArgumentParser()
205205-206206- parser.add_argument(
207207- '-x', '--scan-hooks',
208208- dest='scan_hooks',
209209- nargs='*',
210210- help='directories with scan hooks (executed after scan)',
211211- default=['/etc/autowifi/scan_hooks'],
212212- )
213213-214214- parser.add_argument(
215215- '-c', '--connection-hooks',
216216- dest='connect_hooks',
217217- nargs='*',
218218- help='directories with connection hooks (executed after connection)',
219219- default=['/etc/autowifi/connect_hooks'],
220220- )
221221-222222- parser.add_argument(
223223- '-w', '--wifi_dirs',
224224- dest='wifi_dirs',
225225- nargs='*',
226226- help='directories with wifi configs',
227227- default=['/etc/autowifi/wifis'],
228228- )
229229-230230- parser.add_argument(
231231- '-l', '--loglevel',
232232- dest='loglevel',
233233- help='loglevel to use',
234234- default=logging.INFO,
235235- )
236236-237237- parser.add_argument(
238238- '-p', '--pidfile',
239239- dest='pidfile',
240240- help='file to write the pid to',
241241- default=None,
242242- )
243243-244244- parser.add_argument(
245245- '--no-open',
246246- dest='no_open_networks',
247247- help='dont connect to open networks',
248248- default=False,
249249- action='store_true',
250250- )
251251-252252- args = parser.parse_args()
253253-254254- wifi_dirs = args.wifi_dirs
255255- logger.setLevel(args.loglevel)
256256-257257- signal.signal(signal.SIGUSR1, signal_handler)
258258-259259- if args.pidfile:
260260- with open(args.pidfile, 'w+') as f:
261261- f.write(str(os.getpid()))
262262-263263- while True:
264264- time.sleep(1)
265265- stay_connected_loop()
266266- wifis = scan()
267267- known_wifis = get_known_wifis(wifi_dirs)
268268- known_seen_wifis = [
269269- wifi for wifi in known_wifis if is_wifi_seen(wifi, wifis)
270270- ]
271271- for wifi in known_seen_wifis:
272272- connect(wifi['ssid'], wifi['psk'])
273273- if check_network():
274274- logging.debug('connected to secure wifi, going into busy loop')
275275- break
276276- if check_network():
277277- continue
278278- logging.debug('no known secure wifi, connecting to open ones')
279279- if not args.no_open_networks:
280280- logging.debug('connecting to open wifis')
281281- open_wifis = filter(is_wifi_open, wifis)
282282- for wifi in open_wifis:
283283- connect(wifi['ssid'])
284284- if check_network():
285285- run_hooks(args.connect_hooks, wifi)
286286- break
287287-288288-289289-if __name__ == '__main__':
290290- main()
···11-7NIGHTS_4AB/7nights4you
22-HUB/IFeelGood
33-continuousdelivery/Pr0ud70f81l3arly
44-cccac/23cccac42
55-devolo-guest-30d32d5ab677/QNWTHNJYAYUUQEPG
66-vodafoneACF3E4/puriri01
77-Rotorua Int Motor Inn/apple123
88-Fitzroy Beach Motel/Summ3r*S@nds
99-Hawera Central Motor Lodge/53princes