mirror of
https://github.com/aquasecurity/kube-hunter.git
synced 2026-05-11 03:37:52 +00:00
2. Started adding kubelet scanning. 3. Changed events architecture. All events are inheriting from "Event" class. when instantiating and defining a new event class, attributes other than what is important for that perticular event are not needed. the event handler will be stacking the events, so that each event will have all the attributes of its successors. This proccess is invisible to the developer, but needs to be acknowledged. *note: from now on, all executors needs to set self.event to given arg on init* Example (pseudo): @subscribe(NewHostEvent) def PortScan(event): publish(OpenPortEvent(port="8080")) @subscribe(OpenPortEvent) def print(event): print(event.host) publish(NewHostEvent(host="0.0.0.0")) >> output: 0.0.0.0 the print function recieves an open port event. even though when publishing the OpenPortEvent we did not specify a host, the print function can access the "host" attribute, as the OpenPortEvent successor was NewHostEvent. if "host" was not defined on the succesors, it is "None"
66 lines
2.2 KiB
Python
66 lines
2.2 KiB
Python
import inspect
|
|
import logging
|
|
from abc import ABCMeta
|
|
from collections import defaultdict
|
|
from Queue import Queue
|
|
from threading import Lock, Thread
|
|
|
|
# Inherits Queue object, handles events asynchronously
|
|
class EventQueue(Queue, object):
|
|
def __init__(self, num_worker=10):
|
|
super(EventQueue, self).__init__()
|
|
self.hooks = defaultdict(list)
|
|
self.running = True
|
|
|
|
for i in range(num_worker):
|
|
t = Thread(target=self.worker)
|
|
t.daemon = True
|
|
t.start()
|
|
|
|
# decorator wrapping for easy subscription
|
|
def subscribe(self, event, hook=None, predicate=None):
|
|
def wrapper(hook):
|
|
self.subscribe_event(event, hook=hook, predicate=predicate)
|
|
return hook
|
|
return wrapper
|
|
|
|
# getting uninstantiated event object
|
|
def subscribe_event(self, event, hook=None, predicate=None):
|
|
logging.debug('{} subscribed to {}'.format(event.__name__, hook))
|
|
if hook not in self.hooks[event.__name__]:
|
|
self.hooks[event.__name__].append((hook, predicate))
|
|
|
|
# getting instantiated event object
|
|
def publish_event(self, event):
|
|
logging.debug('Event {} got published with {}'.format(event.__class__.__name__, event))
|
|
event_name = event.__class__.__name__
|
|
if event_name in self.hooks:
|
|
for hook, predicate in self.hooks[event_name]:
|
|
if predicate and not predicate(event):
|
|
continue
|
|
|
|
# access to stack frame, can also be implemented by changing the function call to recieve self.
|
|
# TODO: decide whether invisibility to the developer is the best approach
|
|
last_frame = inspect.stack()[1][0]
|
|
if "self" in last_frame.f_locals:
|
|
event.previous = last_frame.f_locals["self"].event
|
|
|
|
self.put(hook(event))
|
|
|
|
# executes callbacks on dedicated thread as a daemon
|
|
def worker(self):
|
|
while self.running:
|
|
hook = self.get()
|
|
hook.execute()
|
|
self.task_done()
|
|
|
|
# stops execution of all daemons
|
|
def free(self):
|
|
self.running = False
|
|
with self.mutex:
|
|
self.queue.clear()
|
|
|
|
|
|
handler = EventQueue(800)
|
|
|