In the previous section, we learned that subsystems can be used to leverage Unix network applications to provide high-performance services for Honeyd. The performance benefit was mostly due to the fact that subsystems do not require to start a new process for every connection, which is the main drawback of service scripts:
action ::= ["tarpit"] "internal" cmd-string
Honeyd offers yet another alternative called Internal Python Services. Internal Python services use a nonblocking I/O model in which the Python service receives callbacks when more data can be read from the network or written to it. It is implemented using libevent, an event notification library default by one of the authors. Because internal Python services are callback based, you need to encapsulate all your states in a single Python object that is being provided as part of the callback. If your Python service handles multiple connections at once, each connection will have its own state object. A simple example of an internal Python service is shown in Figure 5.5. Read the following section for a detailed description of the functions an internal Python service must provide.
Code View: import honeyd def honeyd_init(data): mydata = {} # my very own state object honeyd.read_selector(honeyd.EVENT_ON) # i am willing to accept data honeyd.write_selector(honeyd.EVENT_ON) # i have data to write mydata["write"] = "SSH-1.99-OpenSSH_3.6.1\n" # i want to write this return mydata def honeyd_readdata(mydata, data): # everything read from network is in the string 'data'. honeyd.read_selector(honeyd.EVENT_ON) # we want to read more # we don't want to echo comments back to the user if data.startswith('#'): return 0 # we have some to write; which is just the data we got honeyd.write_selector(honeyd.EVENT_ON) mydata["write"] = data return 0 def honeyd_writedata(mydata): data = mydata["write"] del mydata["write"] return data def honeyd_end(mydata): del mydata return 0 |
The filename of a Python internal service must end in ".py" and may not have any "-" in it. Every internal Python service needs to make the following four functions available:
honeyd_init: The function gets called when a new connection has been established to this service. The function needs to return a state object that contains all the internal information that the service requires to deal with calls to honeyd_readdata and honeyd_writedata. The argument passed to this function is a dictionary that contains the following keys: HONEYD_IP_SRC, HONEYD_IP_DST, HONEYD_SRC_PORT, HONEYD_DST_PORT, and HONEYD_REMOTE_OS.
honeyd readdata: This function gets called whenever more data was read from the network. Your service needs to return 0 on success or -1 on failure. Honeyd will terminate the connection when any of your functions return a failure code.
honeyd_writedata: This function gets called whenever the network is ready to send more data to the remote host. You can either return the data to be sent or None. On returning None, Honeyd will terminate the connection.
honeyd_end: This callback is executed when a connection has been terminated and should be used to clean up all remaining states.
To make internal Python services more flexible, additional functionality is available via the Honeyd Python module. The module exports the following functions:
read_selector: Tells Honeyd whether the internal Python service wants to read more data. By turning the read selector off, it's possible to throttle the data received by Honeyd. When the service wants to read more data, it needs to turn the read selector back on in the honeyd_writedata function.
write_selector: Similiar to the read selection, this function tells Honeyd when the service would like to write more data. Keep in mind that either reading or writing needs to be enabled, or the service is never going to get a call again.
log: This function allows the service to write information into Honeyd's service log.
raw_log: By calling raw_log, a service can write information directly to syslog. Writing to syslog may be helpful for debugging or for logging critical error messages.
Unlike subsystems, callbacks for Python internal services are invoked only on network events — that is, either when data can be read or when data can be written. The services have no opportunity to compute in the background or initiate any time-dependent activity. You also should never turn off both read_selector and write_selector at the same time because your service will not get control again until the connection has been terminated by the remote site. Furthermore, Python services are not isolated from the rest of Honeyd, and any bugs in them that cause the Python interpreter to crash will also take down Honeyd. However, besides these drawbacks, if you have a problem that can be solved via a Python internal service, the resulting performance is usually very good.