From 88a3ef76d8a6bdbab39ac0745ca22f4ef65e286b Mon Sep 17 00:00:00 2001 From: ache Date: Wed, 5 May 2021 15:23:38 +0200 Subject: Better DHCP --- autoDHCP.py | 285 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100755 autoDHCP.py diff --git a/autoDHCP.py b/autoDHCP.py new file mode 100755 index 0000000..ce699c4 --- /dev/null +++ b/autoDHCP.py @@ -0,0 +1,285 @@ +#!/bin/env python + +import sys +import ipaddress +import argparse +import os +from os.path import exists +import subprocess +import tempfile + + +def guess_wifi(): + return [interface for interface in os.listdir('/sys/class/net/') if + exists(f'/sys/class/net/{interface}/wireless')] + + +def guess_nowifi(): + return [interface for interface in os.listdir('/sys/class/net/') if + not exists(f'/sys/class/net/{interface}/wireless')] + + +def guess_interface(): + return [interface for interface in os.listdir('/sys/class/net/')] + + +def guess_internet(): + 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): + 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): + if listEntry == []: + print(f"Error menu: Empty list\n({strInput})", file=sys.stderr) + 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(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 ! 💋 ") + -- cgit v1.2.3