[kea-dev] Strange behaviour with Option 53 - what am I missing?
Dave Cole
davecole at nbnco.com.au
Tue Jan 30 04:00:12 UTC 2018
After looking into this more deeply I suspect the only way I can provide a sensible wrapper for the Option class is to do a bunch of dynamic_pointer_cast operations in my Python wrapper constructor and save a type code. Then I can just perform a switch in each method that has the potential to fail when I have a reference to an Option sub-class rather than the generic Option super-class.
I am not sure it makes sense to ever expose the ability to construct an Option sub-class from Python.
In any event, I am not going to bother doing this until I have tests for all of the functionality currently implemented. You can quite happily do anything you need with just the Option class and methods. For example:
>>> from kea import *
>>> from ipaddress import IPv4Address
>>> name_servers = [IPv4Address(u'192.0.3.1'), IPv4Address(u'192.0.3.2')]
>>> packed_name_servers = ''.join([addr.packed for addr in name_servers])
>>> o = Option(DHO_DOMAIN_NAME_SERVERS).setString(packed_name_servers)
>>> o.getString()
'\xc0\x00\x03\x01\xc0\x00\x03\x02'
Hmm... On further investigation, I am going to have to do the funny dynamic cast thing - even though we will not use it here :-).
>>> from kea import *
>>> from pcapfile import savefile
>>>
>>> def make_packet(frame):
... ll = frame.packet
... ip = ll.payload
... udp = ip.payload
... p = Pkt4(udp.payload.decode('hex'))
... p.setLocalAddr(ip.src)
... p.setRemoteAddr(ip.dst)
... p.setLocalPort(udp.src_port)
... p.setRemotePort(udp.dst_port)
... p.unpack()
... return p
...
>>> pcap = savefile.load_savefile(open('dhcp-trace.pcap'), layers=3)
>>> p = make_packet(pcap.packets[1])
>>> print p.toText()
local_address=172.20.0.4:67, remote_address=11.0.0.1:67, msg_type=DHCPOFFER (2), transid=0x566fcf25,
options:
type=001, len=004: 255.255.240.0 (ipv4-address)
type=003, len=004: 11.0.0.1
type=042, len=004: 10.10.3.10
type=043, len=058: 01:38:68:74:74:70:73:***private stuff***
type=051, len=004: 86400 (uint32)
type=053, len=001: 2 (uint8)
type=054, len=004: 172.20.0.4 (ipv4-address)
type=058, len=004: 43200 (uint32)
type=059, len=004: 75600 (uint32)
type=082, len=050:,
options:
type=001, len=033: 53:57:***private stuff***
type=002, len=013: 55:4e:***private stuff***
>>>
>>> o = p.getOption(3).getUint16()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Length (0) of buffer is insufficient to read a uint16_t
Oh well :-)
________________________________
From: kea-dev <kea-dev-bounces at lists.isc.org> on behalf of Dave Cole <davecole at nbnco.com.au>
Sent: Tuesday, 30 January 2018 11:45:12 AM
To: kea-dev at lists.isc.org
Subject: [kea-dev] Strange behaviour with Option 53 - what am I missing?
I have decided that before publishing my Python bindings I should add a bunch of unit tests. In the process I discovered something strange:
>>> from kea import *
>>> p = Pkt4(DHCPDISCOVER, 0)
>>> o = p.getOptions()[DHO_DHCP_MESSAGE_TYPE]
>>> o.getUint8()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Attempt to read uint8 from option 53 that has size 0
>>> o.getString()
'\x01'
The implementation of getUint8 is:
static PyObject *
Option_getUint8(OptionObj *self, PyObject *args) {
try {
return (PyInt_FromLong(self->option_ptr->getUint8()));
} catch (const exception &e) {
return (raisePythonError(PyExc_TypeError, e.what()));
}
}
Whereas the getString is:
static PyObject *
Option_getString(OptionObj *self, PyObject *args) {
try {
vector<uint8_t> value = self->option_ptr->toBinary();
return (PyString_FromStringAndSize((const char *) &value[0], value.size()));
} catch (const exception &e) {
return (raisePythonError(PyExc_TypeError, e.what()));
}
}
So when I step through the code with gdb it appears that DHO_DHCP_MESSAGE_TYPE is an instance of OptionInt which does not use the data_ member of Option, instead it has another member value_ of the type defined in the template argument.
Is it a deliberate choice in the code to require application code to just know that getUint8 does not work for OptionInt (which subclasses Option)?
Someone with more of a clue about c++ than me might be able to tell me an easy (and efficient) way I can make my code notice an OptionInt and internally use getValue() rather than getUint8(). Would a dynamic_pointer_cast<OptionUint8>(self->option_ptr) be the way to go?
_______________________________________________
kea-dev mailing list
kea-dev at lists.isc.org
https://lists.isc.org/mailman/listinfo/kea-dev
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.isc.org/pipermail/kea-dev/attachments/20180130/8ef5d103/attachment-0001.html>
More information about the kea-dev
mailing list