diff --git a/README.md b/README.md index 8b4a4a9..56a3f52 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,21 @@ +# ProSafeLinux (psl-cli.py) -If your interface is **not** eth0 please specify it, when you call *psl.py*. +Query and set data on GS105E and GS108E Netgear ProSafe switches. + +These are known to work: + * GS105E 1.02.04 + * GS108Ev2 1.00.12 + * GS108Ev3 2.06.08EN (replies come via unicast) + +# Using psl-cli.py + + usage: psl-cli.py [-h] [--interface INTERFACE] [--debug] + [--timeout TIMEOUT] + {discover,exploit,query,query_raw,set} ... + + * Older switch firmware (before 2018?) returns responses to the broadcast address. + * Newer switch firmware (after 2018?) return responses to the sender. + * If your interface is **not** eth0 please specify it, when you call *psl.py*. # Examples @@ -19,12 +35,30 @@ Query all ports for their 802.1Q VLAN port VID ./psl-cli.py query --mac B0:B9:8A:57:F6:56 vlan_pvid +# Dependencies + +Required for cross-platform support of MacOS & Linux. + - pip install netifaces + +# Supported Platforms + +"discover" and "query" were recently tested on + * MacOS 10.15 with python 2.7 + * Raspbian Linux 4.19.66-v7+ with python 2.7 + +# Known issues + +Discovery only identifies the first switch that answers. + +Newer switches that have web servers may have "Switch Management Mode" set to "Web browser only", which will result in the switch only responding to discovery requests. To use this software, you may login to the web UI and set "Switch Management Mode" to "Web browser and Plus Utility". + +"query all" sometimes produces inconsistent results. More reliable responses seem to occur when you query one item at at time. # Help wanted -Im sorry I am not active at this project anymore. It is open-source so perhabs you could find soneone who can help you. +Im sorry I am not active at this project anymore. It is open-source so perhaps you could find soneone who can help you. -I have found a security problem with this switch and was very disapointed in the answer from netgear. They need more than 6 Month to fix it and want the ethernet adress of it +I have found a security problem with this switch and was very disappointed in the answer from netgear. They need more than 6 Month to fix it and want the ethernet adress of it Because of this, I do not use this switch anymore. @@ -32,7 +66,7 @@ If you can read german, please read this two articles: http://www.linux-magazin.de/Blogs/Insecurity-Bulletin/Gastbeitrag-Security-by-Obscurity-bei-Netgear-Switches http://www.linux-magazin.de/Ausgaben/2012/10/Switch -  + Please feel free to fork the code and do any push request. Please contact me if you like to do the new maintainer of the projekt Sven Anders <psl-github2013@sven.anders.im> @@ -48,6 +82,7 @@ https://github.com/Z3po/Netgearizer (We are merging code together.) * Svenne Krap * Shane Kerr * Sven Anders +* Steven Bytnar See also: http://git.asbjorn.biz/?p=gs105e.git;a=summary diff --git a/psl_class.py b/psl_class.py index 1ab0762..058b8e0 100644 --- a/psl_class.py +++ b/psl_class.py @@ -12,33 +12,17 @@ import psl_typ import inspect import errno +import select +import netifaces def get_hw_addr(ifname): "gives the hardware (mac) address of an interface (eth0,eth1..)" - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - ifname = ifname.encode('ascii') # struct.pack requires bytes in Python 3 - info = fcntl.ioctl(sock.fileno(), 0x8927, struct.pack('256s', ifname[:15])) - if type(info) is str: - return ''.join(['%02x:' % ord(char) for char in info[18:24]])[:-1] - else: - # Python 3 returns a list of bytes from ioctl, no need for ord() - return ''.join(['%02x:' % char for char in info[18:24]])[:-1] + return netifaces.ifaddresses(ifname)[netifaces.AF_LINK][0]['addr'] def get_ip_address(ifname): "returns the first ip address of an interface" - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - ifname = ifname.encode('ascii') # struct.pack requires bytes in Python 3 - try: - # 0x8915 = SIOCGIFADDR - addr = socket.inet_ntoa(fcntl.ioctl(sock.fileno(), 0x8915, - struct.pack('256s', - ifname[:15]))[20:24]) - return addr - except IOError as err: - if err.errno == errno.EADDRNOTAVAIL: - return None - raise + return netifaces.ifaddresses(ifname)[2][0]['addr'] def pack_mac(value): "packs the hardware address (mac) to the internal representation" @@ -142,18 +126,24 @@ def bind(self, interface): return False self.srcmac = pack_mac(get_hw_addr(interface)) - # send socket - self.ssocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + # send socket, can also be used to receive unicast! + self.ssocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) self.ssocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.ssocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) self.ssocket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + self.ssocket.bind((self.myhost, self.RECPORT)) + #self.ssocket.bind(('', self.RECPORT)) + #self.ssocket.bind(('', self.RECPORT)) - # receive socket + # separate broadcast receive socket self.rsocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.rsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - # self.rsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + self.rsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) self.rsocket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) - self.rsocket.bind(("255.255.255.255", self.RECPORT)) + #self.rsocket.bind(("", self.RECPORT)) + self.rsocket.bind(('', self.RECPORT)) + #self.rsocket.bind(("255.255.255.255", self.RECPORT)) return True @@ -194,15 +184,21 @@ def set_debug_output(self): def recv(self, maxlen=8192): "receive a packet from the switch" - self.rsocket.settimeout(self.timeout) + + sel = select.select([self.ssocket.fileno(), self.rsocket.fileno()], [], [], self.timeout) + if sel[0] and sel[0][0] == self.ssocket.fileno(): + rsock = self.ssocket + else: + rsock = self.rsocket + rsock.settimeout(self.timeout) try: - message, address = self.rsocket.recvfrom(maxlen) + message, address = rsock.recvfrom(maxlen) except socket.timeout: return (None, None) except socket.error as error: # according to the Python documentation this error # is system-specifc; this works on Linux - if error.errno == errno.EAGAIN: + if error.errno == errno.EAGAIN: return (None, None) raise if self.debug: