#!/usr/bin/python # -*- coding: utf-8 -*- # # https://github.com/Z3po/Netgearizer # Licensed under the GPLv3 # # Modified by 2018/04/08 import socket import fcntl import struct import binascii from sys import exit, argv class NetgearConfig: # {{{ # addressing information DESTIP = '' DESTPORT = 63322 SRCPORT = 63321 # global hex data privilegedanswer = '0104' portmirrorvalues = ('80','40','20','10','08','04','02','01') # selected switch selectedSwitch = None switchattributes = {'switch-type' : ('0001','string'), 'switch-mac' : ('0004','mac'), 'switch-port-statistics' : ('1000','port-counter')} def __init__(self, ifname): # {{{ # initialize a socket # SOCK_DGRAM specifies that this is UDP self.connection = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) info = fcntl.ioctl(self.connection.fileno(), 0x8927, struct.pack('256s', ifname[:15])) self.mymac = binascii.hexlify(info[18:24]) #print 'My MAC: ' + self.mymac self.destmac = '000000000000' self.sequence = '00000000' # set socket options (allows us to send broadcasts) self.connection.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) # set socket timeout self.connection.settimeout(1) # bind to SRCPORT self.connection.bind(('',self.SRCPORT)) discoveryresult = self.__sendData('get',(('0001',''),('0002',''),('0003',''),('0004',''),('0005',''),('0006',''),('0007',''),('0008',''),('000b',''),('000c',''),('000d',''),('000e',''),('000f',''),('7400',''))) discoveryresult = self.__sendData('get',(('0001',''),('0002',''),('0003',''),('0004',''),('0005',''),('0006',''),('0007',''),('0008',''),('000b',''),('000c',''),('000d',''),('000e',''),('000f',''))) switchMac = {} switchType = {} for key in self.switches.keys(): switchdict = self.__parseData(self.switches[key]) switchMac[key] = switchdict[self.switchattributes['switch-mac'][0]] switchType[key] = switchdict[self.switchattributes['switch-type'][0]] for key in switchMac.keys(): print 'IP: ' + key print 'MAC: ' + self.__convertFromHex(switchMac[key],'mac') print 'Type: '+ self.__convertFromHex(switchType[key],'string') self.destmac = switchMac[key] result = self.__sendData('get', self.switchattributes['switch-port-statistics'][0]) self.selectedSwitch = key self.__printResult(result) # }}} def __del__(self): # {{{ """Destructor""" self.connection.close() # }}} def __socketSend(self, __sendData): # {{{ """Send the data out via SOCKET""" # send the data data = None self.switches = {} self.connection.sendto(__sendData,(self.DESTIP, self.DESTPORT)) try: while True: data, server = self.connection.recvfrom(1024) server = server[0] if not data: break if server in self.switches: self.switches[server] += data else: self.switches.update({ server : data }) return True except socket.timeout: if data == None: print 'SOCKET TIMED OUT' print 'Are you connected to the switch?' exit(2) else: return True # }}} def __sendData(self, reqtype, datalist): # {{{ """This function builds the data to send them out via __socketSend""" self.switches = {} self.__increaseSequence() nsdpnoerror = '000000000000' nsdpseperator = '00000000' enddata = 'ffff0000' nsdpheader = 'NSDP'.encode('hex') if reqtype == 'set': data = '0103' elif reqtype == 'get': data = '0101' else: print 'Unknown request type.' return None data += nsdpnoerror + self.mymac + self.destmac data += self.sequence + nsdpheader + nsdpseperator if isinstance(datalist[0], tuple): for datapair in datalist: if len(datapair[1]) < 2: length=0 else: length=len(datapair[1])/2 data += datapair[0] + hex(length)[2:].rjust(4,'0') data += datapair[1] else: if isinstance(datalist, tuple): attribute = datalist[0] value = datalist[1] if len(datalist[1]) < 2: length=0 else: length=len(datalist[1])/2 elif isinstance(datalist, str): length=0 attribute = datalist value = '' else: print 'Error with input data.' return None data += attribute + hex(length)[2:].rjust(4,'0') data += value data += enddata result = self.__socketSend(binascii.unhexlify(data)) return result # }}} def __parseData(self,hexvalue): # {{{ """This function parses the hexdata we get back from the switch. hexvalue : hexvalue from the switch returns : a dictionary with the parse results """ if hexvalue == None: dataresult = { 'ERROR' : 'NO RESULT' } return dataresult data = binascii.hexlify(hexvalue) nsdpnoerror = '000000000000' dataresult = { 'packettype' : data[:4] } data = data[4:] if data[:12] == nsdpnoerror: data = data[36:] if data[:8] == self.sequence: data = data[24:] while data[:8] != 'ffff0000': length = 2*int('0x'+data[4:8],0) if data[:4] in dataresult: if isinstance(dataresult[data[:4]],list): dataresult[data[:4]].append(data[8:(8+length)]) else: temp = dataresult[data[:4]] dataresult.update({ data[:4] : [temp,data[8:(8+length)]] }) else: dataresult.update({ data[:4] : data[8:(8+length)] }) data = data[(8+length):] else: dataresult.update({ 'ERROR' : 'Not a response to my request!' }) else: dataresult.update({ 'ERROR' : data[4:8] }) return dataresult # }}} def __convertFromHex(self, hexvalue, target): # {{{ """This function converts hexdata to a target type hexvalue : the value we want to convert target : target type, any of 'ip', 'string', 'cipher', 'mac', 'dhcpoption', 'link-status', 'port-mirror', 'vlan-status' """ if target == 'ip': result = str(int('0x' + hexvalue[:2],0)) + '.' + str(int('0x' + hexvalue[2:4],0)) + '.' \ + str(int('0x' + hexvalue[4:6],0)) + '.' + str(int('0x' + hexvalue[6:8],0)) elif target == 'string': result = binascii.unhexlify(hexvalue) elif target == 'cipher': result = str(int(hexvalue, 16)) elif target == 'mac': result = '' while len(hexvalue) > 2: result += hexvalue[:2] + ':' hexvalue = hexvalue[2:] result += hexvalue elif target == 'boolean': if hexvalue == '00': result = 'disabled' elif hexvalue == '01': result = 'enabled' else: result = 'unknown' elif target == 'port-counter': result = [] for port in hexvalue: receivestats = self.__convertFromHex(port[2:18],'cipher') sendstats = self.__convertFromHex(port[18:34],'cipher') crcerrors = self.__convertFromHex(port[82:98],'cipher') result.append(( 'Port' + str(port[:2]), (('rx', receivestats), ('tx', sendstats), ('err', crcerrors)))) else: result = hexvalue return result # }}} def __convertToHex(self, value, sourcetype): # {{{ """This function converts data of sourcetype to hex. value : the value we want to convert sourcetype : the type of data we had """ data = '' if sourcetype == 'ip': ip = value.split('.') for pair in ip: data += self.__convertToHex(pair, 'int') elif sourcetype == 'int': try: data += str(hex(int(value)))[2:].rjust(2,'0') except ValueError: print 'please give a valid numeric value' return False elif sourcetype == 'boolean': if value == 'disable': data = '00' elif value == 'enable': data = '01' else: print 'please use enable or disable as option' return False else: print 'sourcetype not yet implemented...' return False return data # }}} def __increaseSequence(self): # {{{ """This function does nothing than increase the sequence number we use""" self.sequence = hex(int(self.sequence, 16) + 1)[2:].rjust(8,'0') # }}} def __printResult(self, result): # {{{ """This function prints the results result: hexvalue we get from the switch""" if self.selectedSwitch != None: resultdict = self.__parseData(self.switches[self.selectedSwitch]) if 'ERROR' in resultdict: found = None for key in self.switchattributes.keys(): if resultdict['ERROR'] == self.switchattributes[key][0]: found = key break if found != None: print 'ERROR with ' + found else: print 'ERROR: ' + resultdict['ERROR'] elif resultdict['packettype'] == self.privilegedanswer: print 'Successful' else: for key in self.switchattributes.keys(): if self.switchattributes[key][0] in resultdict and len(resultdict[self.switchattributes[key][0]]) > 0: convertdata = self.__convertFromHex(resultdict[self.switchattributes[key][0]],self.switchattributes[key][1]) if type(convertdata).__name__ == 'list': print key + ': ' for element in convertdata: if type(element[1]).__name__ == 'tuple': line = ' ' + element[0] for data in element[1]: line += ' ' + data[0] + ':' + data[1] print line else: print ' -> ' + element[0] + ': ' + element[1] else: print key + ': ' + convertdata # }}} def __splitLine(self,argumentcount,line): # {{{ splitline = line.split() if len(splitline) > argumentcount: print 'Too many arguments!' return False else: if len(splitline) < argumentcount: count=len(splitline) while count < argumentcount: splitline.append(None) count += 1 elif argumentcount == 1: return splitline[0] return splitline # }}} # }}} if __name__ == '__main__': argc = len(argv) if (argc != 2): print 'Usage: %s ' % argv[0] exit(1) NetgearConfig(argv[1]) # vim:filetype=python:foldmethod=marker:autoindent:expandtab:tabstop=4