edns_python.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <cassert>
  15. #include <dns/edns.h>
  16. using namespace isc::dns;
  17. using namespace isc::dns::rdata;
  18. //
  19. // Definition of the classes
  20. //
  21. // For each class, we need a struct, a helper functions (init, destroy,
  22. // and static wrappers around the methods we export), a list of methods,
  23. // and a type description
  24. namespace {
  25. //
  26. // EDNS
  27. //
  28. // The s_* Class simply covers one instantiation of the object
  29. class s_EDNS : public PyObject {
  30. public:
  31. EDNS* edns;
  32. };
  33. //
  34. // We declare the functions here, the definitions are below
  35. // the type definition of the object, since both can use the other
  36. //
  37. // General creation and destruction
  38. int EDNS_init(s_EDNS* self, PyObject* args);
  39. void EDNS_destroy(s_EDNS* self);
  40. // These are the functions we export
  41. PyObject* EDNS_toText(const s_EDNS* self);
  42. // This is a second version of toText, we need one where the argument
  43. // is a PyObject*, for the str() function in python.
  44. PyObject* EDNS_str(PyObject* self);
  45. PyObject* EDNS_toWire(const s_EDNS* self, PyObject* args);
  46. PyObject* EDNS_getVersion(const s_EDNS* self);
  47. PyObject* EDNS_getDNSSECAwareness(const s_EDNS* self);
  48. PyObject* EDNS_setDNSSECAwareness(s_EDNS* self, PyObject* args);
  49. PyObject* EDNS_getUDPSize(const s_EDNS* self);
  50. PyObject* EDNS_setUDPSize(s_EDNS* self, PyObject* args);
  51. PyObject* EDNS_createFromRR(const s_EDNS* null_self, PyObject* args);
  52. // This list contains the actual set of functions we have in
  53. // python. Each entry has
  54. // 1. Python method name
  55. // 2. Our static function here
  56. // 3. Argument type
  57. // 4. Documentation
  58. PyMethodDef EDNS_methods[] = {
  59. { "to_text", reinterpret_cast<PyCFunction>(EDNS_toText), METH_NOARGS,
  60. "Returns the string representation" },
  61. { "to_wire", reinterpret_cast<PyCFunction>(EDNS_toWire), METH_VARARGS,
  62. "Converts the EDNS object to wire format.\n"
  63. "The argument can be either a MessageRenderer or an object that "
  64. "implements the sequence interface. If the object is mutable "
  65. "(for instance a bytearray()), the wire data is added in-place.\n"
  66. "If it is not (for instance a bytes() object), a new object is "
  67. "returned" },
  68. { "get_version",
  69. reinterpret_cast<PyCFunction>(EDNS_getVersion), METH_NOARGS,
  70. "Returns the version of EDNS." },
  71. { "get_dnssec_awareness",
  72. reinterpret_cast<PyCFunction>(EDNS_getDNSSECAwareness), METH_NOARGS,
  73. "Returns whether the message sender is DNSSEC aware." },
  74. { "set_dnssec_awareness",
  75. reinterpret_cast<PyCFunction>(EDNS_setDNSSECAwareness), METH_VARARGS,
  76. "Specifies whether the sender of the message containing this "
  77. "EDNS is DNSSEC aware." },
  78. { "get_udp_size",
  79. reinterpret_cast<PyCFunction>(EDNS_getUDPSize), METH_NOARGS,
  80. "Return the maximum buffer size of UDP messages for the sender "
  81. "of the message." },
  82. { "set_udp_size",
  83. reinterpret_cast<PyCFunction>(EDNS_setUDPSize), METH_VARARGS,
  84. "Specify the maximum buffer size of UDP messages that use this EDNS." },
  85. { "create_from_rr",
  86. reinterpret_cast<PyCFunction>(EDNS_createFromRR),
  87. METH_VARARGS | METH_STATIC,
  88. "Create a new EDNS object from a set of RR parameters, also providing "
  89. "the extended RCODE value." },
  90. { NULL, NULL, 0, NULL }
  91. };
  92. // This defines the complete type for reflection in python and
  93. // parsing of PyObject* to s_EDNS
  94. // Most of the functions are not actually implemented and NULL here.
  95. PyTypeObject edns_type = {
  96. PyVarObject_HEAD_INIT(NULL, 0)
  97. "libdns_python.EDNS",
  98. sizeof(s_EDNS), // tp_basicsize
  99. 0, // tp_itemsize
  100. (destructor)EDNS_destroy, // tp_dealloc
  101. NULL, // tp_print
  102. NULL, // tp_getattr
  103. NULL, // tp_setattr
  104. NULL, // tp_reserved
  105. NULL, // tp_repr
  106. NULL, // tp_as_number
  107. NULL, // tp_as_sequence
  108. NULL, // tp_as_mapping
  109. NULL, // tp_hash
  110. NULL, // tp_call
  111. EDNS_str, // tp_str
  112. NULL, // tp_getattro
  113. NULL, // tp_setattro
  114. NULL, // tp_as_buffer
  115. Py_TPFLAGS_DEFAULT, // tp_flags
  116. "The EDNS class encapsulates DNS extensions "
  117. "provided by the EDNSx protocol.",
  118. NULL, // tp_traverse
  119. NULL, // tp_clear
  120. NULL, // tp_richcompare
  121. 0, // tp_weaklistoffset
  122. NULL, // tp_iter
  123. NULL, // tp_iternext
  124. EDNS_methods, // tp_methods
  125. NULL, // tp_members
  126. NULL, // tp_getset
  127. NULL, // tp_base
  128. NULL, // tp_dict
  129. NULL, // tp_descr_get
  130. NULL, // tp_descr_set
  131. 0, // tp_dictoffset
  132. (initproc)EDNS_init, // tp_init
  133. NULL, // tp_alloc
  134. PyType_GenericNew, // tp_new
  135. NULL, // tp_free
  136. NULL, // tp_is_gc
  137. NULL, // tp_bases
  138. NULL, // tp_mro
  139. NULL, // tp_cache
  140. NULL, // tp_subclasses
  141. NULL, // tp_weaklist
  142. NULL, // tp_del
  143. 0 // tp_version_tag
  144. };
  145. EDNS*
  146. createFromRR(const Name& name, const RRClass& rrclass, const RRType& rrtype,
  147. const RRTTL& rrttl, const Rdata& rdata, uint8_t& extended_rcode)
  148. {
  149. try {
  150. return (createEDNSFromRR(name, rrclass, rrtype, rrttl, rdata,
  151. extended_rcode));
  152. } catch (const isc::InvalidParameter& ex) {
  153. PyErr_SetString(po_InvalidParameter, ex.what());
  154. } catch (const DNSMessageFORMERR& ex) {
  155. PyErr_SetString(po_DNSMessageFORMERR, ex.what());
  156. } catch (const DNSMessageBADVERS& ex) {
  157. PyErr_SetString(po_DNSMessageBADVERS, ex.what());
  158. } catch (...) {
  159. PyErr_SetString(po_IscException, "Unexpected exception");
  160. }
  161. return (NULL);
  162. }
  163. int
  164. EDNS_init(s_EDNS* self, PyObject* args) {
  165. uint8_t version = EDNS::SUPPORTED_VERSION;
  166. const s_Name* name;
  167. const s_RRClass* rrclass;
  168. const s_RRType* rrtype;
  169. const s_RRTTL* rrttl;
  170. const s_Rdata* rdata;
  171. if (PyArg_ParseTuple(args, "|b", &version)) {
  172. try {
  173. self->edns = new EDNS(version);
  174. } catch (const isc::InvalidParameter& ex) {
  175. PyErr_SetString(po_InvalidParameter, ex.what());
  176. return (-1);
  177. } catch (...) {
  178. PyErr_SetString(po_IscException, "Unexpected exception");
  179. return (-1);
  180. }
  181. return (0);
  182. } else if (PyArg_ParseTuple(args, "O!O!O!O!O!", &name_type, &name,
  183. &rrclass_type, &rrclass, &rrtype_type, &rrtype,
  184. &rrttl_type, &rrttl, &rdata_type, &rdata)) {
  185. // We use createFromRR() even if we don't need to know extended_rcode
  186. // in this context so that we can share the try-catch logic with
  187. // EDNS_createFromRR() (see below).
  188. uint8_t extended_rcode;
  189. self->edns = createFromRR(*name->name, *rrclass->rrclass,
  190. *rrtype->rrtype, *rrttl->rrttl,
  191. *rdata->rdata, extended_rcode);
  192. return (self->edns != NULL ? 0 : -1);
  193. }
  194. PyErr_Clear();
  195. PyErr_SetString(PyExc_TypeError, "Invalid arguments to EDNS constructor");
  196. return (-1);
  197. }
  198. void
  199. EDNS_destroy(s_EDNS* const self) {
  200. delete self->edns;
  201. self->edns = NULL;
  202. Py_TYPE(self)->tp_free(self);
  203. }
  204. PyObject*
  205. EDNS_toText(const s_EDNS* const self) {
  206. // Py_BuildValue makes python objects from native data
  207. return (Py_BuildValue("s", self->edns->toText().c_str()));
  208. }
  209. PyObject*
  210. EDNS_str(PyObject* const self) {
  211. // Simply call the to_text method we already defined
  212. return (PyObject_CallMethod(self,
  213. const_cast<char*>("to_text"),
  214. const_cast<char*>("")));
  215. }
  216. PyObject*
  217. EDNS_toWire(const s_EDNS* const self, PyObject* args) {
  218. PyObject* bytes;
  219. uint8_t extended_rcode;
  220. s_MessageRenderer* renderer;
  221. if (PyArg_ParseTuple(args, "Ob", &bytes, &extended_rcode) &&
  222. PySequence_Check(bytes)) {
  223. PyObject* bytes_o = bytes;
  224. OutputBuffer buffer(0);
  225. self->edns->toWire(buffer, extended_rcode);
  226. PyObject* rd_bytes = PyBytes_FromStringAndSize(
  227. static_cast<const char*>(buffer.getData()), buffer.getLength());
  228. PyObject* result = PySequence_InPlaceConcat(bytes_o, rd_bytes);
  229. // We need to release the object we temporarily created here
  230. // to prevent memory leak
  231. Py_DECREF(rd_bytes);
  232. return (result);
  233. } else if (PyArg_ParseTuple(args, "O!b", &messagerenderer_type,
  234. &renderer, &extended_rcode)) {
  235. const unsigned int n = self->edns->toWire(*renderer->messagerenderer,
  236. extended_rcode);
  237. return (Py_BuildValue("I", n));
  238. }
  239. PyErr_Clear();
  240. PyErr_SetString(PyExc_TypeError, "Incorrect arguments for EDNS.to_wire()");
  241. return (NULL);
  242. }
  243. PyObject*
  244. EDNS_getVersion(const s_EDNS* const self) {
  245. return (Py_BuildValue("B", self->edns->getVersion()));
  246. }
  247. PyObject*
  248. EDNS_getDNSSECAwareness(const s_EDNS* const self) {
  249. if (self->edns->getDNSSECAwareness()) {
  250. Py_RETURN_TRUE;
  251. } else {
  252. Py_RETURN_FALSE;
  253. }
  254. }
  255. PyObject*
  256. EDNS_setDNSSECAwareness(s_EDNS* self, PyObject* args) {
  257. const PyObject *b;
  258. if (!PyArg_ParseTuple(args, "O!", &PyBool_Type, &b)) {
  259. return (NULL);
  260. }
  261. self->edns->setDNSSECAwareness(b == Py_True);
  262. Py_RETURN_NONE;
  263. }
  264. PyObject*
  265. EDNS_getUDPSize(const s_EDNS* const self) {
  266. return (Py_BuildValue("I", self->edns->getUDPSize()));
  267. }
  268. PyObject*
  269. EDNS_setUDPSize(s_EDNS* self, PyObject* args) {
  270. long size;
  271. if (!PyArg_ParseTuple(args, "l", &size)) {
  272. PyErr_Clear();
  273. PyErr_SetString(PyExc_TypeError,
  274. "No valid type in set_udp_size argument");
  275. return (NULL);
  276. }
  277. if (size < 0 || size > 0xffff) {
  278. PyErr_SetString(PyExc_ValueError,
  279. "UDP size is not an unsigned 16-bit integer");
  280. return (NULL);
  281. }
  282. self->edns->setUDPSize(size);
  283. Py_RETURN_NONE;
  284. }
  285. PyObject*
  286. EDNS_createFromRR(const s_EDNS* null_self, PyObject* args) {
  287. const s_Name* name;
  288. const s_RRClass* rrclass;
  289. const s_RRType* rrtype;
  290. const s_RRTTL* rrttl;
  291. const s_Rdata* rdata;
  292. s_EDNS* edns_obj = NULL;
  293. assert(null_self == NULL);
  294. if (PyArg_ParseTuple(args, "O!O!O!O!O!", &name_type, &name,
  295. &rrclass_type, &rrclass, &rrtype_type, &rrtype,
  296. &rrttl_type, &rrttl, &rdata_type, &rdata)) {
  297. uint8_t extended_rcode;
  298. edns_obj = PyObject_New(s_EDNS, &edns_type);
  299. if (edns_obj == NULL) {
  300. return (NULL);
  301. }
  302. edns_obj->edns = createFromRR(*name->name, *rrclass->rrclass,
  303. *rrtype->rrtype, *rrttl->rrttl,
  304. *rdata->rdata, extended_rcode);
  305. if (edns_obj->edns != NULL) {
  306. PyObject* extrcode_obj = Py_BuildValue("B", extended_rcode);
  307. return (Py_BuildValue("OO", edns_obj, extrcode_obj));
  308. }
  309. Py_DECREF(edns_obj);
  310. return (NULL);
  311. }
  312. PyErr_Clear();
  313. PyErr_SetString(PyExc_TypeError,
  314. "Incorrect arguments for EDNS.create_from_rr()");
  315. return (NULL);
  316. }
  317. } // end of anonymous namespace
  318. // end of EDNS
  319. // Module Initialization, all statics are initialized here
  320. bool
  321. initModulePart_EDNS(PyObject* mod) {
  322. // We initialize the static description object with PyType_Ready(),
  323. // then add it to the module. This is not just a check! (leaving
  324. // this out results in segmentation faults)
  325. if (PyType_Ready(&edns_type) < 0) {
  326. return (false);
  327. }
  328. Py_INCREF(&edns_type);
  329. void* p = &edns_type;
  330. PyModule_AddObject(mod, "EDNS", static_cast<PyObject*>(p));
  331. addClassVariable(edns_type, "SUPPORTED_VERSION",
  332. Py_BuildValue("B", EDNS::SUPPORTED_VERSION));
  333. return (true);
  334. }