def _packet_handler(self, pkt): if pkt.haslayer(DHCP): # self.logger.error(pkt[DHCP].command()) params = {} # dhcp request # options = dict(pkt[DHCP].options) # if options.get('message-type', 0) == 3 and options.get('requested_addr', None): for entry in pkt[DHCP].options: if entry[0] == "message-type": params['message-type'] = entry[1] elif entry[0] == "vendor_class_id": # self.logger.info("%s %s", entry[0], entry[1]) params['dhcp_vendor'] = entry[1] elif entry[0] == 'requested_addr': params['ip'] = entry[1] elif entry[0] == 'hostname': params['hostname'] = entry[1] elif entry[0] == "client_id": # client_id value is hardware type (0x01) and mac address params['mac'] = ":".join( hexstr(entry[1], onlyhex=True).split(" ")[-6:]) elif entry[0] == 'param_req_list': # DHCP fingerprint in fingerbank format params['dhcp_fingerprint'] = ",".join([ str(int(num, 16)) for num in hexstr(entry[1], onlyhex=True).split(" ") ]) if params.get('message-type', 0) == 3 and params.get('ip', None): insert_or_update_fingerprint(self.conn, self.logger, **params)
def _handle_dhcp(self, pkt): # self.logger.error(pkt[DHCP].command()) params = {} params['mac'] = str(":".join(hexstr(pkt[BOOTP].chaddr, onlyhex=True).split(" ")[:6])).lower() for entry in pkt[DHCP].options: if entry[0] == "message-type": params['message-type'] = entry[1] elif entry[0] == "vendor_class_id": # self.logger.info("%s %s", entry[0], entry[1]) params['dhcp_vendor'] = entry[1] elif entry[0] == 'requested_addr': params['ip'] = entry[1] elif entry[0] == 'hostname': params['hostname'] = entry[1] elif entry[0] == 'param_req_list': # DHCP fingerprint in fingerbank format params['dhcp_fingerprint'] = ",".join([str(int(num, 16)) for num in hexstr(entry[1], onlyhex=True).split(" ")]) if params.get('message-type', 0) == 3 and check_preconditions(params.get('ip', None), params.get('mac', None)): try: insert_or_update_fingerprint(self.conn, **params) self.logger.debug("registered dhcp: ip: {}, mac: {}".format(params.get('ip', None), params.get('mac', None))) except TypeError as te: self.logger.error(insert_or_update_fingerprint.__name__ + " needs keyword-only argument ip") except sqlite3.Error as sqle: self.logger.exception(sqle) except ValueError as ve: self.logger.exception(ve)
def run(self): try: self.conn = sqlite3.connect(self.dbfile) with self.conn: c = self.conn.cursor() while True: try: c.execute(self._QUERY) devices = list(sum(c.fetchall(), ())) if devices: ans, unans = arping(devices, iface=None, verbose=0) for device in ans: if check_preconditions(device[1][ARP].psrc, device[1][ARP].hwsrc): insert_or_update_fingerprint( self.conn, ip=device[1][ARP].psrc, mac=device[1][ARP].hwsrc) self.logger.info("checked no mode devices: " + str(devices)) time.sleep(self._SLEEP) except sqlite3.Error as sqle: self.logger.error("a database error occurred") self.logger.exception(sqle) except sqlite3.Error as sqle: self.logger.error( "Failed to connect to sqlite database at path %s" % (self.dbfile, )) self.logger.exception(sqle) raise DaemonError()
def _handle_ssdp(self, pkt): parser = HttpParser() params = {} user_agents = [] id = None if not all(pkt.haslayer(layer) for layer in [Ether, IP, UDP]): self.logger.debug("packet does not contain all required layers") self.logger.debug(pkt.command()) return params['mac'] = pkt[Ether].src params['ip'] = pkt[IP].src if check_preconditions(params.get('ip', None), params.get('mac', None)): try: id = insert_or_update_fingerprint(self.conn, **params) self.logger.debug("registered ssdp: ip: {}, mac: {}".format(params.get('ip', None), params.get('mac', None))) except TypeError as te: self.logger.error(insert_or_update_fingerprint.__name__ + " needs keyword-only argument ip") except sqlite3.Error as sqle: self.logger.exception(sqle) if id is None: return try: if parser.execute(pkt[UDP].payload.load, len(pkt[UDP].payload.load)) != len(pkt[UDP].payload.load): self.logger.warning("error while parsing HTTP payload of ssdp packet") return except AttributeError: self.logger.warning("received UDP packet without payload") headers = parser.get_headers() if "user-agent" in headers: # e.g. chrome appends user agent to ssdp:discover user_agents.append((headers['user-agent'], False)) if "server" in headers: user_agents.append((headers['server'], False)) if "location" in headers: req = url.Request(headers['location']) host = "" ip = None try: ip = socket.gethostbyname_ex(req.get_host().split(":")[0]) except ValueError: self.logger.warning("malformed location value") except socket.error: self.logger.warning("Unable to get ip of host") else: # only allow locations inside private networks if IPAddress(ip[2][0]).is_private(): try: xml_content = url.urlopen(req).read() spec = xmltodict.parse(xml_content) user_agents.append((spec['root']['device']['friendlyName'], True)) except url.URLError as urle: self.logger.warning("Unable to get content of url " + headers['location']) self.logger.warning(urle) except xml.parsers.expat.ExpatError: self.logger.error("Unable to parse upnp xml from url " + headers['location']) except KeyError: self.logger.error("xml does not contain required friendlyName from url " + headers['location']) except BadStatusLine: self.logger.warning("Server responded with bad status line for url " + headers['location']) except socket.error as e: if e.errno != errno.ECONNRESET: raise self.logger.warning("Connection reset by peer connecting to url " + headers['location']) else: try: user_agents.append((spec['root']['device']['modelDescription'], True)) except KeyError: # modelDescription is not mandatory, only recommended pass for agent, model in user_agents: insert_useragent(self.conn, agent, id, model)