This basic example shows how to create simple python module which will pass on the requests to the iterator.
If you look into unbound configuration file, you can find the option module-config which specifies the names and the order of modules to be used. To get the pythonmod works use this string:
module-config: "validator python iterator"
As soon as the DNS query arrive, the unbound call the validator module (it is the first module in the list). The validator does not know the answer (it can validate only), thus it will pass on the event to the next module. Next module is pythonmod which can
- a) generate answer (response)
- When python module generates the response unbound calls validator. Validator grabs the answer and determines the security flag.
- b) pass on the event to the iterator.
- When iterator resolves the query, unbound informs python module. In the end, when the python module is done, validator is called.
In order to change the scripts, a configuration option is provided. When unbound starts and initializes the modules, the pythonmod loads the script which name is given in python-script option:
python-script: "/unbound/test/ubmodule.py"
Each python module must contain four compulsory functions:
Initialize module internals, like database etc. Called just once on module load.
Parameters: |
|
---|
def init(id, cfg):
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, cfg.port, cfg.python_script))
return True
Deinitialize module internals. Called just once on module unload.
Parameters: |
|
---|
def deinit(id):
log_info("pythonmod: deinit called, module id is %d" % id)
return True
Inform mesh.
Parameters: |
|
---|
def inform_super(id, qstate, superqstate, qdata):
return True
Perform action on pending query. It’s basically a state machine (MODULE_EVENT_NEW, MODULE_EVENT_PASS, MODULE_EVENT_MODDONE), which can be extended for your needs. Result is stored in ext_state under module identifier.
Parameters: |
|
---|
def operate(id, event, qstate, qdata):
log_info("pythonmod: operate called, id: %d, event:%s" % (id, strmodulevent(event)))
if event == MODULE_EVENT_NEW:
qstate.ext_state[id] = MODULE_WAIT_MODULE
return True
if event == MODULE_EVENT_MODDONE:
log_info("pythonmod: previous module done")
qstate.ext_state[id] = MODULE_FINISHED
return True
if event == MODULE_EVENT_PASS:
log_info("pythonmod: event_pass")
qstate.ext_state[id] = MODULE_ERROR
return True
log_err("pythonmod: BAD event")
qstate.ext_state[id] = MODULE_ERROR
return True
print mod_env.fname # Print module script name
mod_env.data = "test" # Store global module data
def init(id, cfg):
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, cfg.port, cfg.python_script))
return True
def deinit(id):
log_info("pythonmod: deinit called, module id is %d" % id)
return True
def inform_super(id, qstate, superqstate, qdata):
return True
def operate(id, event, qstate, qdata):
log_info("pythonmod: operate called, id: %d, event:%s" % (id, strmodulevent(event)))
if event == MODULE_EVENT_NEW:
qstate.ext_state[id] = MODULE_WAIT_MODULE
return True
if event == MODULE_EVENT_MODDONE:
log_info("pythonmod: previous module done")
qstate.ext_state[id] = MODULE_FINISHED
return True
if event == MODULE_EVENT_PASS:
log_info("pythonmod: event_pass")
qstate.ext_state[id] = MODULE_ERROR
return True
log_err("pythonmod: BAD event")
qstate.ext_state[id] = MODULE_ERROR
return True
log_info("pythonmod: script loaded.")
As you can see, the source code is much more flexible in contrast to C modules. Moreover, compulsory functions called on appropriate module events allows to handle almost anything from web control to query analysis.