]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- With ./configure --with-pyunbound --with-pythonmodule
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 22 Nov 2018 13:01:29 +0000 (13:01 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 22 Nov 2018 13:01:29 +0000 (13:01 +0000)
  PYTHON_VERSION=3.6 or with 2.7 unbound can compile and unit tests
  succeed for the python module.
- pythonmod logs the python error and traceback on failure.

git-svn-id: file:///svn/unbound/trunk@4966 be551aaa-1e26-0410-a405-d3ace91eadb9

Makefile.in
doc/Changelog
doc/unbound.doxygen
pythonmod/interface.i
pythonmod/pythonmod.c
testdata/pylib.tdir/pylib.test
testdata/pymod.tdir/pymod.py
testdata/pymod_thread.tdir/pymod_thread.py
testdata/pymod_thread.tdir/pymod_thread.testns

index 07a29825b6942cab17538aba4489cfc75500fb45..8788412bc81fca39a64c91e1cd1b2e85e3022d8d 100644 (file)
@@ -482,9 +482,9 @@ doc:
        if test -n "$(doxygen)"; then \
                $(doxygen) $(srcdir)/doc/unbound.doxygen; fi
        if test "$(WITH_PYUNBOUND)" = "yes" -o "$(WITH_PYTHONMODULE)" = "yes"; \
-           then if test -x "`which sphinx-build 2>&1`"; then \
-               sphinx-build -b html pythonmod/doc doc/html/pythonmod; \
-               sphinx-build -b html libunbound/python/doc doc/html/pyunbound;\
+           then if test -x "`which sphinx-build-$(PY_MAJOR_VERSION) 2>&1`"; then \
+               sphinx-build-$(PY_MAJOR_VERSION) -b html pythonmod/doc doc/html/pythonmod; \
+               sphinx-build-$(PY_MAJOR_VERSION) -b html libunbound/python/doc doc/html/pyunbound;\
            fi ;\
        fi
 
index c339e15b6ddb9fb53f902d3692103fe334617a8b..4f33a9b1118d0936d4bbb19d76c98a5b0245c16f 100644 (file)
@@ -1,3 +1,9 @@
+22 November 2018: Wouter
+       - With ./configure --with-pyunbound --with-pythonmodule
+         PYTHON_VERSION=3.6 or with 2.7 unbound can compile and unit tests
+         succeed for the python module.
+       - pythonmod logs the python error and traceback on failure.
+
 21 November 2018: Wouter
        - Scrub NS records from NODATA responses as well.
 
index fe39876816b51fa7259b258e05a4001a321d965d..bea788896450472f982e4828a6c01b704ec50793 100644 (file)
@@ -612,17 +612,21 @@ RECURSIVE              = YES
 
 EXCLUDE                = ./build \
                          ./compat \
+                        ./contrib \
                          util/configparser.c \
                          util/configparser.h \
                          util/configlexer.c \
                          util/locks.h \
+                         pythonmod/doc \
+                         pythonmod/examples \
                          pythonmod/unboundmodule.py \
                          pythonmod/interface.h \
-                         pythonmod/examples/resgen.py \
-                         pythonmod/examples/resmod.py \
-                         pythonmod/examples/resip.py \
+                         pythonmod/ubmodule-msg.py \
+                         pythonmod/ubmodule-tst.py \
                          libunbound/python/unbound.py \
                          libunbound/python/libunbound_wrap.c \
+                         libunbound/python/doc \
+                         libunbound/python/examples \
                          ./ldns-src \
                         doc/control_proto_spec.txt \
                         doc/requirements.txt
index 68e0975aaa070f45528d60705178523429112f25..473135f42e60e9e2f2a72f1f21aeb206238d37d2 100644 (file)
 
      i = 0;
      while (i < len) {
-        i += name[i] + 1;
+        i += ((unsigned int)name[i]) + 1;
         cnt++;
      }
 
      list = PyList_New(cnt);
      i = 0; cnt = 0;
      while (i < len) {
-        PyList_SetItem(list, cnt, PyBytes_FromStringAndSize(name + i + 1, name[i]));
-        i += name[i] + 1;
+        char buf[LDNS_MAX_LABELLEN+1];
+        if(((unsigned int)name[i])+1 <= (int)sizeof(buf)) {
+                memmove(buf, name + i + 1, (unsigned int)name[i]);
+                buf[(unsigned int)name[i]] = 0;
+                PyList_SetItem(list, cnt, PyString_FromString(buf));
+        }
+        i += ((unsigned int)name[i]) + 1;
         cnt++;
      }
      return list;
@@ -161,11 +166,11 @@ struct query_info {
 %}
 
 %inline %{
-   PyObject* dnameAsStr(const char* dname) {
+   PyObject* dnameAsStr(PyObject* dname) {
        char buf[LDNS_MAX_DOMAINLEN+1];
        buf[0] = '\0';
-       dname_str((uint8_t*)dname, buf);
-       return PyBytes_FromString(buf);
+       dname_str((uint8_t*)PyBytes_AsString(dname), buf);
+       return PyString_FromString(buf);
    }
 %}
 
@@ -1211,7 +1216,7 @@ int checkList(PyObject *l)
        for (i=0; i < PyList_Size(l); i++)
        {
            item = PyList_GetItem(l, i);
-           if (!PyBytes_Check(item))
+           if (!PyBytes_Check(item) && !PyUnicode_Check(item))
               return 0;
        }
        return 1;
@@ -1226,23 +1231,40 @@ int pushRRList(sldns_buffer* qb, PyObject *l, uint32_t default_ttl, int qsec,
     PyObject* item;
     int i;
     size_t len;
+    char* s;
+    PyObject* ascstr;
 
     for (i=0; i < PyList_Size(l); i++)
     {
+        ascstr = NULL;
         item = PyList_GetItem(l, i);
+        if(PyObject_TypeCheck(item, &PyBytes_Type)) {
+                s = PyBytes_AsString(item);
+        } else {
+                ascstr = PyUnicode_AsASCIIString(item);
+                s = PyBytes_AsString(ascstr);
+        }
 
         len = sldns_buffer_remaining(qb);
         if(qsec) {
-                if(sldns_str2wire_rr_question_buf(PyBytes_AsString(item),
+                if(sldns_str2wire_rr_question_buf(s,
                         sldns_buffer_current(qb), &len, NULL, NULL, 0, NULL, 0)
-                        != 0)
+                        != 0) {
+                        if(ascstr)
+                            Py_DECREF(ascstr);
                         return 0;
+                }
         } else {
-                if(sldns_str2wire_rr_buf(PyBytes_AsString(item),
+                if(sldns_str2wire_rr_buf(s,
                         sldns_buffer_current(qb), &len, NULL, default_ttl,
-                        NULL, 0, NULL, 0) != 0)
+                        NULL, 0, NULL, 0) != 0) {
+                        if(ascstr)
+                            Py_DECREF(ascstr);
                         return 0;
+                }
         }
+        if(ascstr)
+            Py_DECREF(ascstr);
         sldns_buffer_skip(qb, len);
 
         sldns_buffer_write_u16_at(qb, count_offset,
index 35a20434b935e00aa463cd6b445a155a795a1fcb..1e3d30b911165c626543f87367b88d02c1c84658 100644 (file)
@@ -110,6 +110,128 @@ struct pythonmod_qstate {
 #include "pythonmod/interface.h"
 #endif
 
+/** log python error */
+static void
+log_py_err(void)
+{
+       char *result = NULL;
+       PyObject *modStringIO = NULL;
+       PyObject *modTB = NULL;
+       PyObject *obFuncStringIO = NULL;
+       PyObject *obStringIO = NULL;
+       PyObject *obFuncTB = NULL;
+       PyObject *argsTB = NULL;
+       PyObject *obResult = NULL;
+       PyObject *ascstr = NULL;
+       PyObject *exc_typ, *exc_val, *exc_tb;
+
+       /* Fetch the error state now before we cruch it */
+       /* exc val contains the error message
+        * exc tb contains stack traceback and other info. */
+       PyErr_Fetch(&exc_typ, &exc_val, &exc_tb);
+       PyErr_NormalizeException(&exc_typ, &exc_val, &exc_tb);
+
+       /* Import the modules we need - cStringIO and traceback */
+       modStringIO = PyImport_ImportModule("cStringIO");
+       if (modStringIO==NULL) /* python 1.4 and before */
+               modStringIO = PyImport_ImportModule("StringIO");
+       if (modStringIO==NULL) /* python 3 */
+               modStringIO = PyImport_ImportModule("io");
+       if (modStringIO==NULL) {
+               log_err("pythonmod: cannot print exception, "
+                       "cannot ImportModule cStringIO or StringIO");
+               goto cleanup;
+       }
+       modTB = PyImport_ImportModule("traceback");
+       if (modTB==NULL) {
+               log_err("pythonmod: cannot print exception, "
+                       "cannot ImportModule traceback");
+               goto cleanup;
+       }
+
+       /* Construct a cStringIO object */
+       obFuncStringIO = PyObject_GetAttrString(modStringIO, "StringIO");
+       if (obFuncStringIO==NULL) {
+               log_err("pythonmod: cannot print exception, "
+                       "cannot GetAttrString cStringIO.StringIO");
+               goto cleanup;
+       }
+       obStringIO = PyObject_CallObject(obFuncStringIO, NULL);
+       if (obStringIO==NULL) {
+               log_err("pythonmod: cannot print exception, "
+                       "cannot cStringIO.StringIO()");
+               goto cleanup;
+       }
+
+       /* Get the traceback.print_exception function, and call it. */
+       obFuncTB = PyObject_GetAttrString(modTB, "print_exception");
+       if (obFuncTB==NULL) {
+               log_err("pythonmod: cannot print exception, "
+                       "cannot GetAttrString traceback.print_exception");
+               goto cleanup;
+       }
+       argsTB = Py_BuildValue("OOOOO", (exc_typ ? exc_typ : Py_None),
+               (exc_val ? exc_val : Py_None), (exc_tb  ? exc_tb  : Py_None),
+               Py_None, obStringIO);
+       if (argsTB==NULL) {
+               log_err("pythonmod: cannot print exception, "
+                       "cannot BuildValue for print_exception");
+               goto cleanup;
+       }
+
+       obResult = PyObject_CallObject(obFuncTB, argsTB);
+       if (obResult==NULL) {
+               PyErr_Print();
+               log_err("pythonmod: cannot print exception, "
+                       "call traceback.print_exception() failed");
+               goto cleanup;
+       }
+
+       /* Now call the getvalue() method in the StringIO instance */
+       Py_DECREF(obFuncStringIO);
+       obFuncStringIO = PyObject_GetAttrString(obStringIO, "getvalue");
+       if (obFuncStringIO==NULL) {
+               log_err("pythonmod: cannot print exception, "
+                       "cannot GetAttrString cStringIO.getvalue");
+               goto cleanup;
+       }
+       Py_DECREF(obResult);
+       obResult = PyObject_CallObject(obFuncStringIO, NULL);
+       if (obResult==NULL) {
+               log_err("pythonmod: cannot print exception, "
+                       "call cStringIO.getvalue() failed");
+               goto cleanup;
+       }
+
+       /* And it should be a string all ready to go - duplicate it. */
+       if (!PyString_Check(obResult) && !PyUnicode_Check(obResult)) {
+               log_err("pythonmod: cannot print exception, "
+                       "cStringIO.getvalue() result did not String_Check");
+               goto cleanup;
+       }
+       if(PyString_Check(obResult)) {
+               result = PyString_AsString(obResult);
+       } else {
+               ascstr = PyUnicode_AsASCIIString(obResult);
+               result = PyBytes_AsString(ascstr);
+       }
+       log_err("pythonmod: python error: %s", result);
+
+cleanup:
+       Py_XDECREF(modStringIO);
+       Py_XDECREF(modTB);
+       Py_XDECREF(obFuncStringIO);
+       Py_XDECREF(obStringIO);
+       Py_XDECREF(obFuncTB);
+       Py_XDECREF(argsTB);
+       Py_XDECREF(obResult);
+       Py_XDECREF(ascstr);
+
+       /* clear the exception, by not restoring it */
+       /* Restore the exception state */
+       /* PyErr_Restore(exc_typ, exc_val, exc_tb); */
+}
+
 int pythonmod_init(struct module_env* env, int id)
 {
    /* Initialize module */
@@ -193,13 +315,26 @@ int pythonmod_init(struct module_env* env, int id)
 
    /* TODO: deallocation of pe->... if an error occurs */
 
-   if (PyRun_SimpleFile(script_py, pe->fname) < 0)
-   {
+   if (PyRun_SimpleFile(script_py, pe->fname) < 0) {
       log_err("pythonmod: can't parse Python script %s", pe->fname);
+      /* print the error to logs too, run it again */
+      fseek(script_py, 0, SEEK_SET);
+      /* we don't run the file, like this, because then side-effects
+       *    s = PyRun_File(script_py, pe->fname, Py_file_input, 
+       *        PyModule_GetDict(PyImport_AddModule("__main__")), pe->dict);
+       * could happen (again). Instead we parse the file again to get
+       * the error string in the logs, for when the daemon has stderr
+       * removed.  SimpleFile run already printed to stderr, for then
+       * this is called from unbound-checkconf or unbound -dd the user
+       * has a nice formatted error.
+      */
+      /* ignore the NULL return of _node, it is NULL due to the parse failure
+       * that we are expecting */
+      (void)PyParser_SimpleParseFile(script_py, pe->fname, Py_file_input);
+      log_py_err();
       PyGILState_Release(gil);
       return 0;
    }
-
    fclose(script_py);
 
    if ((pe->func_init = PyDict_GetItemString(pe->dict, "init_standard")) == NULL)
@@ -244,7 +379,7 @@ int pythonmod_init(struct module_env* env, int id)
    if (PyErr_Occurred())
    {
       log_err("pythonmod: Exception occurred in function init");
-      PyErr_Print();
+      log_py_err();
       Py_XDECREF(res);
       Py_XDECREF(py_init_arg);
       PyGILState_Release(gil);
@@ -274,7 +409,7 @@ void pythonmod_deinit(struct module_env* env, int id)
       res = PyObject_CallFunction(pe->func_deinit, "i", id);
       if (PyErr_Occurred()) {
          log_err("pythonmod: Exception occurred in function deinit");
-         PyErr_Print();
+         log_py_err();
       }
       /* Free result if any */
       Py_XDECREF(res);
@@ -312,7 +447,7 @@ void pythonmod_inform_super(struct module_qstate* qstate, int id, struct module_
    if (PyErr_Occurred())
    {
       log_err("pythonmod: Exception occurred in function inform_super");
-      PyErr_Print();
+      log_py_err();
       qstate->ext_state[id] = module_error;
    }
    else if ((res == NULL)  || (!PyObject_IsTrue(res)))
@@ -353,7 +488,7 @@ void pythonmod_operate(struct module_qstate* qstate, enum module_ev event,
    if (PyErr_Occurred())
    {
       log_err("pythonmod: Exception occurred in function operate, event: %s", strmodulevent(event));
-      PyErr_Print();
+      log_py_err();
       qstate->ext_state[id] = module_error;
    }
    else if ((res == NULL)  || (!PyObject_IsTrue(res)))
index 9456691aa6e149dfab94d377b6bbc38c50460ff3..893aaf64f252f589edbb41511cfb0c447edecfd3 100644 (file)
@@ -19,9 +19,13 @@ fi
 #echo export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:../../.libs:."
 #export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:../../.libs:."
 
+if grep "PY_MAJOR_VERSION=3" $PRE/Makefile; then
+       PYTHON="python3"; else PYTHON="python2"; fi
+if test ! -x `which $PYTHON` 2>&1; then PYTHON="python"; fi
+
 # do the test
 echo "> pylib.lookup.py www.example.com."
-./pylib.lookup.py www.example.com. | tee outfile
+$PYTHON pylib.lookup.py www.example.com. | tee outfile
 
 echo "> cat logfiles"
 cat fwd.log
index 3f6fed1c696babe42a6675716ac5bec063063267..a8018e7f75e7a3f96adad9e15b0c9e00ba58b707 100644 (file)
@@ -59,12 +59,15 @@ def setTTL(qstate, ttl):
 
 def dataHex(data, prefix=""):
     res = ""
-    for i in range(0, (len(data)+15)/16):
+    for i in range(0, int((len(data)+15)/16)):
         res += "%s0x%02X | " % (prefix, i*16)
-        d = map(lambda x:ord(x), data[i*16:i*16+17])
+        if type(data[0]) == type(1):
+            d = map(lambda x:int(x), data[i*16:i*16+17])
+        else:
+            d = map(lambda x:ord(x), data[i*16:i*16+17])
         for ch in d:
             res += "%02X " % ch
-        for i in range(0,17-len(d)):
+        for i in range(0,17-len(data[i*16:i*16+17])):
             res += "   "
         res += "| "
         for ch in d:
@@ -76,35 +79,35 @@ def dataHex(data, prefix=""):
     return res
 
 def printReturnMsg(qstate):
-    print "Return MSG rep   :: flags: %04X, QDcount: %d, Security:%d, TTL=%d" % (qstate.return_msg.rep.flags, qstate.return_msg.rep.qdcount,qstate.return_msg.rep.security, qstate.return_msg.rep.ttl)
-    print "           qinfo :: qname:",qstate.return_msg.qinfo.qname_list, qstate.return_msg.qinfo.qname_str, "type:",qstate.return_msg.qinfo.qtype_str, "class:",qstate.return_msg.qinfo.qclass_str
+    print ("Return MSG rep   :: flags: %04X, QDcount: %d, Security:%d, TTL=%d" % (qstate.return_msg.rep.flags, qstate.return_msg.rep.qdcount, qstate.return_msg.rep.security, qstate.return_msg.rep.ttl))
+    print ("           qinfo :: qname:",qstate.return_msg.qinfo.qname_list, qstate.return_msg.qinfo.qname_str, "type:",qstate.return_msg.qinfo.qtype_str, "class:",qstate.return_msg.qinfo.qclass_str)
     if (qstate.return_msg.rep):
-        print "RRSets:",qstate.return_msg.rep.rrset_count
+        print ("RRSets:",qstate.return_msg.rep.rrset_count)
         prevkey = None
         for i in range(0,qstate.return_msg.rep.rrset_count):
             r = qstate.return_msg.rep.rrsets[i]
             rk = r.rk
-            print i,":",rk.dname_list, rk.dname_str, "flags: %04X" % rk.flags,
-            print "type:",rk.type_str,"(%d)" % ntohs(rk.type), "class:",rk.rrset_class_str,"(%d)" % ntohs(rk.rrset_class)
+            print (i,":",rk.dname_list, rk.dname_str, "flags: %04X" % rk.flags)
+            print ("type:",rk.type_str,"(%d)" % ntohs(rk.type), "class:",rk.rrset_class_str,"(%d)" % ntohs(rk.rrset_class))
 
             d = r.entry.data
-            print "    RRDatas:",d.count+d.rrsig_count
+            print ("    RRDatas:",d.count+d.rrsig_count)
             for j in range(0,d.count+d.rrsig_count):
-                print "    ",j,":","TTL=",d.rr_ttl[j],"RR data:"
-                print dataHex(d.rr_data[j],"         ")
+                print ("    ",j,":","TTL=",d.rr_ttl[j],"RR data:")
+                print (dataHex(d.rr_data[j],"         "))
 
 
 def operate(id, event, qstate, qdata):
     log_info("pythonmod: operate called, id: %d, event:%s" % (id, strmodulevent(event)))
-    #print "pythonmod: per query data", qdata
+    #print ("pythonmod: per query data", qdata)
 
-    print "Query:", ''.join(map(lambda x:chr(max(32,ord(x))),qstate.qinfo.qname)), qstate.qinfo.qname_list, qstate.qinfo.qname_str,
-    print "Type:",qstate.qinfo.qtype_str,"(%d)" % qstate.qinfo.qtype,
-    print "Class:",qstate.qinfo.qclass_str,"(%d)" % qstate.qinfo.qclass
-    print
+    print ("Query:", qstate.qinfo.qname, qstate.qinfo.qname_list, qstate.qinfo.qname_str)
+    print ("Type:",qstate.qinfo.qtype_str,"(%d)" % qstate.qinfo.qtype)
+    print ("Class:",qstate.qinfo.qclass_str,"(%d)" % qstate.qinfo.qclass)
+    print ()
 
     if (event == MODULE_EVENT_NEW or event == MODULE_EVENT_PASS) and (qstate.qinfo.qname_str.endswith("www2.example.com.")):
-        print qstate.qinfo.qname_str
+        print (qstate.qinfo.qname_str)
 
         qstate.ext_state[id] = MODULE_FINISHED 
 
@@ -121,6 +124,7 @@ def operate(id, event, qstate, qdata):
         if (qstate.qinfo.qtype == RR_TYPE_TXT) or (qstate.qinfo.qtype == RR_TYPE_ANY):
             msg.answer.append("%s 10 IN TXT path=/" % qstate.qinfo.qname_str)
 
+        print(msg.answer)
         if not msg.set_return_msg(qstate):
             qstate.ext_state[id] = MODULE_ERROR 
             return True
index 31e1d43f64ae9e530c30e8318ec05c76df59d8aa..30c2588758f53e23ec96d24b1af115076435ce7d 100644 (file)
@@ -59,12 +59,15 @@ def setTTL(qstate, ttl):
 
 def dataHex(data, prefix=""):
     res = ""
-    for i in range(0, (len(data)+15)/16):
+    for i in range(0, int((len(data)+15)/16)):
         res += "%s0x%02X | " % (prefix, i*16)
-        d = map(lambda x:ord(x), data[i*16:i*16+17])
+        if type(data[0]) == type(1):
+            d = map(lambda x:int(x), data[i*16:i*16+17])
+        else:
+            d = map(lambda x:ord(x), data[i*16:i*16+17])
         for ch in d:
-            res += "%02X " % ch
-        for i in range(0,17-len(d)):
+            res += "%02X " % int(ch)
+        for i in range(0,17-len(data[i*16:i*16+17])):
             res += "   "
         res += "| "
         for ch in d:
@@ -76,43 +79,43 @@ def dataHex(data, prefix=""):
     return res
 
 def printReturnMsg(qstate):
-    print "Return MSG rep   :: flags: %04X, QDcount: %d, Security:%d, TTL=%d" % (qstate.return_msg.rep.flags, qstate.return_msg.rep.qdcount,qstate.return_msg.rep.security, qstate.return_msg.rep.ttl)
-    print "           qinfo :: qname:",qstate.return_msg.qinfo.qname_list, qstate.return_msg.qinfo.qname_str, "type:",qstate.return_msg.qinfo.qtype_str, "class:",qstate.return_msg.qinfo.qclass_str
+    print ("Return MSG rep   :: flags: %04X, QDcount: %d, Security:%d, TTL=%d" % (qstate.return_msg.rep.flags, qstate.return_msg.rep.qdcount, qstate.return_msg.rep.security, qstate.return_msg.rep.ttl))
+    print ("           qinfo :: qname:",qstate.return_msg.qinfo.qname_list, qstate.return_msg.qinfo.qname_str, "type:",qstate.return_msg.qinfo.qtype_str, "class:",qstate.return_msg.qinfo.qclass_str)
     if (qstate.return_msg.rep):
-        print "RRSets:",qstate.return_msg.rep.rrset_count
+        print ("RRSets:",qstate.return_msg.rep.rrset_count)
         prevkey = None
         for i in range(0,qstate.return_msg.rep.rrset_count):
             r = qstate.return_msg.rep.rrsets[i]
             rk = r.rk
-            print i,":",rk.dname_list, rk.dname_str, "flags: %04X" % rk.flags,
-            print "type:",rk.type_str,"(%d)" % ntohs(rk.type), "class:",rk.rrset_class_str,"(%d)" % ntohs(rk.rrset_class)
+            print (i,":",rk.dname_list, rk.dname_str, "flags: %04X" % rk.flags)
+            print ("type:",rk.type_str,"(%d)" % ntohs(rk.type), "class:",rk.rrset_class_str,"(%d)" % ntohs(rk.rrset_class))
 
             d = r.entry.data
-            print "    RRDatas:",d.count+d.rrsig_count
+            print ("    RRDatas:",d.count+d.rrsig_count)
             for j in range(0,d.count+d.rrsig_count):
-                print "    ",j,":","TTL=",d.rr_ttl[j],"RR data:"
-                print dataHex(d.rr_data[j],"         ")
+                print ("    ",j,":","TTL=",d.rr_ttl[j],"RR data:")
+                print (dataHex(d.rr_data[j],"         "))
 
 
 def operate(id, event, qstate, qdata):
     log_info("pythonmod: operate called, id: %d, event:%s" % (id, strmodulevent(event)))
-    #print "pythonmod: per query data", qdata
+    #print ("pythonmod: per query data", qdata)
 
-    print "Query:", ''.join(map(lambda x:chr(max(32,ord(x))),qstate.qinfo.qname)), qstate.qinfo.qname_list, qstate.qinfo.qname_str,
-    print "Type:",qstate.qinfo.qtype_str,"(%d)" % qstate.qinfo.qtype,
-    print "Class:",qstate.qinfo.qclass_str,"(%d)" % qstate.qinfo.qclass
-    print
+    print ("Query:", qstate.qinfo.qname, qstate.qinfo.qname_list, qstate.qinfo.qname_str)
+    print ("Type:",qstate.qinfo.qtype_str,"(%d)" % qstate.qinfo.qtype)
+    print ("Class:",qstate.qinfo.qclass_str,"(%d)" % qstate.qinfo.qclass)
+    print ()
 
     if (event == MODULE_EVENT_NEW or event == MODULE_EVENT_PASS) and (qstate.qinfo.qname_str.endswith("example.com.")):
-        print qstate.qinfo.qname_str
+        print (qstate.qinfo.qname_str)
 
         qstate.ext_state[id] = MODULE_FINISHED 
 
-       # eat time
-       y = 20
-       for z in range(2, 10000):
-               y = y*2 - z/2
-               y = y/2 + z
+        # eat time
+        y = 20
+        for z in range(2, 10000):
+                y = y*2 - z/2
+                y = y/2 + z
 
         msg = DNSMessage(qstate.qinfo.qname_str, RR_TYPE_A, RR_CLASS_IN, PKT_QR | PKT_RA | PKT_AA) #, 300)
         #msg.authority.append("xxx.seznam.cz. 10 IN A 192.168.1.1")
index 55926bb50c9f59fee50ecfe2e0dce7c1c5676e49..c92a07909e7da8ca6d646e72902036dd2779e0de 100644 (file)
@@ -22,3 +22,83 @@ SECTION ANSWER
 www2   IN      A       10.20.30.40
 ENTRY_END
 
+ENTRY_BEGIN
+MATCH opcode qtype qname
+REPLY QR AA NOERROR
+ADJUST copy_id
+SECTION QUESTION
+www3   IN      A
+SECTION ANSWER
+www3   IN      A       10.20.30.40
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+REPLY QR AA NOERROR
+ADJUST copy_id
+SECTION QUESTION
+www4   IN      A
+SECTION ANSWER
+www4   IN      A       10.20.30.40
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+REPLY QR AA NOERROR
+ADJUST copy_id
+SECTION QUESTION
+www5   IN      A
+SECTION ANSWER
+www5   IN      A       10.20.30.40
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+REPLY QR AA NXDOMAIN
+ADJUST copy_id
+SECTION QUESTION
+www6   IN      A
+SECTION AUTHORITY
+example.com.           3600    IN      SOA     a. b. 2018100719 7200 3600 1209600 3600
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+REPLY QR AA NXDOMAIN
+ADJUST copy_id
+SECTION QUESTION
+www7   IN      A
+SECTION AUTHORITY
+example.com.           3600    IN      SOA     a. b. 2018100719 7200 3600 1209600 3600
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+REPLY QR AA NXDOMAIN
+ADJUST copy_id
+SECTION QUESTION
+www8   IN      A
+SECTION AUTHORITY
+example.com.           3600    IN      SOA     a. b. 2018100719 7200 3600 1209600 3600
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+REPLY QR AA NXDOMAIN
+ADJUST copy_id
+SECTION QUESTION
+www9   IN      A
+SECTION AUTHORITY
+example.com.           3600    IN      SOA     a. b. 2018100719 7200 3600 1209600 3600
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+REPLY QR AA NXDOMAIN
+ADJUST copy_id
+SECTION QUESTION
+www10  IN      A
+SECTION AUTHORITY
+example.com.           3600    IN      SOA     a. b. 2018100719 7200 3600 1209600 3600
+ENTRY_END
+