#!/bin/env python import sys import ipaddress import argparse import os from os.path import exists import subprocess import tempfile def guess_wifi() -> list[str]: return [interface for interface in os.listdir('/sys/class/net/') if exists(f'/sys/class/net/{interface}/wireless')] def guess_nowifi() -> list[str]: return [interface for interface in os.listdir('/sys/class/net/') if not exists(f'/sys/class/net/{interface}/wireless')] def guess_interface() -> list[str]: return [interface for interface in os.listdir('/sys/class/net/')] def guess_internet() -> list[str]: com = subprocess.Popen(['ip', 'route', 'show'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) stdout, stderr = com.communicate() if stderr: return [] print(str(stdout).split('\n')) internet_i = [line for line in [stripedLine(line) for line in str(stdout).split('\n') if 'default' in line] if line != ''] return list(set(internet_i)) def stripedLine(line) -> str: words = line.split(' ') if 'dev' in words and words.index('dev'): return words[words.index('dev') + 1] else: return '' def menu(listEntry, strInput, refresh=None) -> int: if listEntry == []: print(f"Error menu: Empty list\n({strInput})", file=sys.stderr) sys.exit(1) c = -1 if len(listEntry) == 1: c = 0 while not (0 < c <= len(listEntry)): for i, ii in enumerate(listEntry): print(f" {i + 1}) {ii}") r = input(f'{strInput} ' f'(q to quit{ ", r to refresh" if refresh else ""}) :') if refresh and r == 'r': listEntry = refresh() elif r.lower() in ['q', 'quit']: exit(0) else: try: c = int(r) except: pass return c - 1 ip = '10.5.6.11' netRange = '24' ssid = '🦖' password = 'chocoball' hostapd_conf = ''' interface={interface} ssid={ssid} wpa_passphrase={passphrase} wpa=1 channel=11 hw_mode=g # ieee80211d=1 # country_code=FR ieee80211n=1 # ieee80211ac=1 logger_syslog=-1 logger_syslog_level=2 logger_stdout=-1 logger_stdout_level=2 ctrl_interface=/var/run/hostapd ctrl_interface_group=0 beacon_int=100 dtim_period=2 max_num_sta=255 rts_threshold=2347 fragm_threshold=2346 macaddr_acl=0 auth_algs=3 ignore_broadcast_ssid=0 wmm_enabled=1 wmm_ac_bk_cwmin=4 wmm_ac_bk_cwmax=10 wmm_ac_bk_aifs=7 wmm_ac_bk_txop_limit=0 wmm_ac_bk_acm=0 wmm_ac_be_aifs=3 wmm_ac_be_cwmin=4 wmm_ac_be_cwmax=10 wmm_ac_be_txop_limit=0 wmm_ac_be_acm=0 wmm_ac_vi_aifs=2 wmm_ac_vi_cwmin=3 wmm_ac_vi_cwmax=4 wmm_ac_vi_txop_limit=94 wmm_ac_vi_acm=0 wmm_ac_vo_aifs=2 wmm_ac_vo_cwmin=2 wmm_ac_vo_cwmax=3 wmm_ac_vo_txop_limit=47 wmm_ac_vo_acm=0 wpa_key_mgmt=WPA-PSK rsn_pairwise=CCMP wpa=2 vht_oper_chwidth=3 eap_message=hello eapol_key_index_workaround=0 eap_server=0 ''' dnsmasq_conf = ''' interface={interface} listen-address={ip} dhcp-range={dhcp_range} ''' # dhcp_range=$(echo ${ip_start}{$ip_start_tmp\,,254}),12h if __name__ == '__main__': parser = argparse.ArgumentParser(description='Automaticaly set up a DHCP server') parser.add_argument('--ip', dest='ip', default=ip, help='IP on the DHCP network') parser.add_argument('-r', '--range', dest='range', default=netRange, help='number of bit of the IP that are part of the ' 'network address') parser.add_argument('-s', '--ssid', dest='ssid', default=ssid, help='Wifi\'s "name"') parser.add_argument('--password', dest='passwd', default=password, help='the password of the Wifi network if any') parser.add_argument('--no-password', dest='nopass', action='store_true', help='disable password') parser.add_argument('-t', '--tethering', dest='teth', action='store_true', help='configure tethering on the DHCP network') parser.add_argument('-w', '--wifi', dest='wifi', action='store_true', help='DHCP on a wifi interface') parser.add_argument('--no-wifi', dest='nowifi', action='store_true', help='DHCP not on a wifi interface') parser.add_argument('-in', '--inet-iface', dest='internet_interface', help='the internet interface to use when tethering') parser.add_argument('-i', '--iface', dest='interface', help='DHCP network\'s interface') arg = parser.parse_args() if arg.wifi and arg.nowifi: print('Wifi or not Wifi, that is the question', file=sys.stderr) exit(1) ip = ipaddress.ip_address(arg.ip) inetInt = arg.internet_interface netInt = arg.interface if arg.teth: if not arg.internet_interface: inet_int = guess_internet() i = menu(inet_int, "Select the internet network interface", refresh=guess_internet) inetInt = inet_int[i] interfaces_list = [] refresh = None if arg.wifi: refresh = guess_wifi elif arg.nowifi: refresh = guess_nowifi else: refresh = guess_interface interfaces_list = refresh() if not netInt: c = menu(interfaces_list, "Select the DHCP network's interface", refresh) netInt = interfaces_list[c] else: if netInt not in interfaces_list: if arg.wifi: print(f"{netInt} not a valid wifi interface", file=sys.stderr) exit(2) elif arg.nowifi: if netInt in guess_interface(): print(f'Warning: {netInt} is a wifi interface') else: print(f"{netInt} not a valid interface", file=sys.stderr) exit(2) else: print(f"{netInt} not a valid interface", file=sys.stderr) exit(2) os.system(f'ip link set {netInt} up') os.system(f'ip addr add {ip}/{netRange} dev {netInt}') fd, dnsConfPath = tempfile.mkstemp(dir="/tmp/") f_, pidPath = tempfile.mkstemp(dir="/tmp/") os.close(f_) with os.fdopen(fd, 'w') as tmp: network = ipaddress.ip_network(f'{ip}/{netRange}', strict=False) nextIp = ipaddress.ip_address(int(ip) + 1) lastIp = ipaddress.ip_address(int(network.broadcast_address) - 1) if nextIp >= lastIp: print('Error: Empty DHCP range', file=sys.stderr) exit(3) dhcp_range = f'{nextIp}, {lastIp}, 12h' tmp.write(dnsmasq_conf.format(interface=netInt, ip=ip, dhcp_range=dhcp_range)) print("🔧 - Setting up dns server", f"Range : {dhcp_range}", f"Server IP: {ip}", sep='\n') ret = os.system(f'dnsmasq --conf-file={dnsConfPath} --pid-file={pidPath}') os.remove(dnsConfPath) pid = None with open(pidPath, "r") as f: pid = f.read().strip() os.remove(pidPath) if ret: print('Error: dnsmasq failed to launch', file=sys.stderr) exit(1) else: print(f'✅ dnsmasq launch with pid ({pid})') if arg.teth: os.system('sysctl net.ipv4.ip_forward=1') os.system('sysctl net.ipv6.conf.all.forwarding=1') os.system(f'iptables -t nat -A POSTROUTING -o {inetInt} -j MASQUERADE') os.system('iptables -A FORWARD -m conntrack --ctstate' ' RELATED,ESTABLISHED -j ACCEPT') os.system(f'iptables -A FORWARD -i {netInt} -o {inetInt} -j ACCEPT') print("Tethering set") if arg.wifi: fd2, hostAPConfPath = tempfile.mkstemp(dir="/tmp/") with os.fdopen(fd2, 'w') as tmp: tmp.write(hostapd_conf.format(ssid=arg.ssid, interface=netInt, passphrase=arg.passwd)) print("⚙️ - Setting up hostapd", f"SSID: {ssid}", f"Password: {arg.passwd}", f"Interface: {netInt}", sep='\n') ret = os.system(f'hostapd {hostAPConfPath}') if ret: print('Error: hostapd failed to launch', file=sys.stderr) if pid is not None: os.system(f'kill {pid}') exit(1) if pid is not None: print(" 🤖 - Terminating DHCP server") ret = os.system(f'kill {pid}') print("✅ Hasta la vista, baby") print("Thant you for using autoDHCP ! 💋 ")