Skip to content

Commit 1c096cb

Browse files
committed
add support for per instance spki and pfx update callbacks
Since rtrlib itself does not support this, we do this by abusing the facts that rtrlib does not care about the actual size of a rtr_socket and that the rtr_socket the update originates from is passed to the callback function. We can just add some more data after the actual content of the rtr_socket and access it from the callback function to find the per instance callback and call it.
1 parent 2ade90e commit 1c096cb

File tree

7 files changed

+88
-98
lines changed

7 files changed

+88
-98
lines changed

docs/callbacks.rst

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ This callback can be used to iterate over the entire pfx table.
3939
:param data: Arbitrary data object provided by the user
4040
:type data: object or None
4141

42-
.. warning:: You should **not** register more than one function per callback for the following callbacks, it will **not** work and result in undefined behaviour
43-
4442

4543
PFX update callback
4644
-------------------
@@ -53,24 +51,26 @@ This callback is called for any change to the Prefix validation table, it takes
5351
:type pfx_record: :class:`rtrlib.records.PFXRecord`
5452
:param added: Indicates whether the record was added or removed
5553
:type added: :class:`bool`
54+
:param data: Data Object, if defined at manager initialization
5655

57-
This callback can be registered using the :func:`rtrlib.register_pfx_update_callback` function
58-
59-
.. autofunction:: rtrlib.register_pfx_update_callback
56+
This callback is registered at manager initialization using the pfx_update_callback parameter.
57+
The data object may be passed with the pfx_update_callback_data parameter.
6058

6159

6260
SPKI update callback
6361
--------------------
6462

6563
This callback is called for any change to the Subject Public Key Info table, it takes two arguments.
6664

65+
.. warning:: This callback is untested due to the lack of spki support in rtr cache server implementations.
66+
6767
.. function:: spki_update_callback(spki_record, added):
6868

6969
:param spki_record: The affected spki record
70-
:type spki_record: :class:`rtrlib.records.PFXRecord`
70+
:type spki_record: :class:`rtrlib.records.SPKIRecord`
7171
:param added: Indicates whether the record was added or removed
7272
:type added: :class:`bool`
73+
:param data: Data Object, if defined at manager initialization
7374

74-
This callback can be registered using the :func:`rtrlib.register_spki_update_callback` function
75-
76-
.. autofunction:: rtrlib.register_spki_update_callback
75+
This callback is registered at manager initialization using the spki_update_callback parameter.
76+
The data object may be passed with the spki_update_callback_data parameter.

docs/usage.rst

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,12 @@ Print PFX updates
6767

6868
::
6969

70-
from rtrlib import RTRManager, register_pfx_update_callback
70+
from rtrlib import RTRManager
7171

72-
def callback(pfx_record, added):
72+
def callback(pfx_record, added, data):
7373
print('%s %s' % ('+' if added else '-', pfx_record))
7474

75-
register_pfx_update_callback(callback)
76-
77-
mgr = RTRManager('rpki-validator.realmv6.org', 8282)
75+
mgr = RTRManager('rpki-validator.realmv6.org', 8282, pfx_update_callback=callback)
7876
mgr.start()
7977

8078
mgr.stop()

ffi_build.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@
2222
void free(void *ptr);
2323
""")
2424

25+
ffibuilder.cdef("""
26+
struct rtr_socket_wrapper {
27+
struct rtr_socket rtr_socket;
28+
void *data;
29+
};
30+
""")
31+
2532
ffibuilder.set_source("_rtrlib",
2633
"""
2734
#include <rtrlib/rtrlib.h>
@@ -47,6 +54,11 @@
4754
#ifdef RTRLIB_HAVE_LIBSSH
4855
int have_ssh(void) {return 1;}
4956
#endif
57+
58+
struct rtr_socket_wrapper {
59+
struct rtr_socket rtr_socket;
60+
void *data;
61+
};
5062
""",
5163
libraries=['rtr'])
5264

rtrlib/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111

1212
from .rtr_manager import RTRManager, PfxvState
1313
from .manager_group import ManagerGroupStatus
14-
from .callbacks import (register_pfx_update_callback,
15-
register_spki_update_callback)
1614

1715
logging.getLogger(__name__).addHandler(logging.NullHandler())
1816

rtrlib/callbacks.py

Lines changed: 17 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -6,58 +6,13 @@
66

77
import logging
88

9-
from _rtrlib import ffi, lib
9+
from _rtrlib import ffi
1010
from .manager_group import ManagerGroup, ManagerGroupStatus
1111
from .rtr_socket import RTRSocket
1212
from .records import PFXRecord, SPKIRecord
1313

1414
LOG = logging.getLogger(__name__)
1515

16-
PFX_UPDATE_CALLBACK = ffi.NULL
17-
SPKI_UPDATE_CALLBACK = ffi.NULL
18-
19-
20-
def register_pfx_update_callback(func):
21-
"""
22-
Register RTR manager pfx_update_callback
23-
24-
:param function func: Callback function
25-
"""
26-
global PFX_UPDATE_CALLBACK
27-
register_callback(
28-
pfx_update_callback_wrapper(func),
29-
"pfx_update_callback"
30-
)
31-
32-
PFX_UPDATE_CALLBACK = lib.pfx_update_callback
33-
34-
35-
def register_spki_update_callback(func):
36-
"""
37-
Register RTR manager spki update callback
38-
39-
.. warning:: This callback is untested, because at the time of writing
40-
no caching server with spki records was available.
41-
It should work but might cause you computer to explode.
42-
43-
:param function func: Callback function
44-
"""
45-
global SPKI_UPDATE_CALLBACK
46-
register_callback(
47-
spki_update_callback_wrapper(func),
48-
"spki_update_callback"
49-
)
50-
51-
SPKI_UPDATE_CALLBACK = lib.spki_update_callback
52-
53-
54-
def register_callback(callback, name):
55-
"""
56-
Registers a cffi callback
57-
"""
58-
LOG.debug('Registering callback %s', name)
59-
ffi.def_extern(name=name)(callback)
60-
6116

6217
@ffi.def_extern(name="rtr_mgr_status_callback")
6318
def status_callback(rtr_mgr_group, group_status, rtr_socket, object_handle):
@@ -87,35 +42,25 @@ def pfx_table_callback(pfx_record, object_handle):
8742
callback(PFXRecord(pfx_record), data)
8843

8944

90-
def pfx_update_callback_wrapper(func):
91-
"""
92-
Wraps the given python function and wraps it to hide cffi specifics.
93-
This wrapper is only for the pfx update callback of the rtrlib manager.
94-
"""
95-
def inner(pfx_table, pfx_record, added):
96-
"""
97-
Hides c structures
98-
"""
99-
LOG.debug("Calling pfx update callback")
100-
func(
101-
PFXRecord(pfx_record),
45+
@ffi.def_extern(name="pfx_update_callback")
46+
def pfx_update_callback(pfx_table, record, added):
47+
wrapped_socket = ffi.cast("struct rtr_socket_wrapper *", record.socket)
48+
mgr = ffi.from_handle(wrapped_socket.data)
49+
50+
mgr._pfx_update_callback(
51+
PFXRecord(record),
10252
added,
103-
)
104-
return inner
53+
mgr._pfx_update_callback_data,
54+
)
10555

10656

107-
def spki_update_callback_wrapper(func):
108-
"""
109-
Wraps the given python function and wraps it to hide cffi specifics.
110-
This wrapper is only for the spki update callback of the rtrlib manager.
111-
"""
112-
def inner(record, added):
113-
"""
114-
Hides c structures
115-
"""
116-
LOG.debug("Calling spki update callback")
117-
func(
57+
@ffi.def_extern(name="spki_update_callback")
58+
def spki_update_callback(spki_table, record, added):
59+
wrapped_socket = ffi.cast("struct rtr_socket_wrapper *", record.socket)
60+
mgr = ffi.from_handle(wrapped_socket.data)
61+
62+
mgr._spki_update_callback(
11863
SPKIRecord(record),
11964
added,
65+
mgr._spki_update_callback_data,
12066
)
121-
return inner

rtrlib/rtr_manager.py

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,18 @@ class RTRManager(object):
6464
callback.
6565
:type status_callback_data: object
6666
67+
:param pfx_update_callback: pfx update callback \
68+
called every time a pfx update is received
69+
:type pfx_update_callback: function
70+
71+
:param pfx_update_callback_data: data passed to the pfx update callback
72+
73+
:param spki_update_callback: spki update callback \
74+
called every time a spki update is received
75+
:type spki_update_callback: function
76+
77+
:param spki_update_callback_data: data passed to the spki update callback
78+
6779
:raises RTRInitError:
6880
6981
"""
@@ -76,7 +88,11 @@ def __init__(
7688
expire_interval=7200,
7789
retry_interval=600,
7890
status_callback=None,
79-
status_callback_data=None
91+
status_callback_data=None,
92+
pfx_update_callback=None,
93+
pfx_update_callback_data=None,
94+
spki_update_callback=None,
95+
spki_update_callback_data=None,
8096
):
8197

8298
LOG.debug('Initializing RTR manager')
@@ -98,23 +114,40 @@ def __init__(
98114
self._status_callback = ffi.NULL
99115
cffi_callback = ffi.NULL
100116

117+
self._pfx_update_callback_data = pfx_update_callback_data
118+
if pfx_update_callback:
119+
self._pfx_update_callback = pfx_update_callback
120+
pfx_cffi_callback = lib.pfx_update_callback
121+
else:
122+
self._pfx_update_callback = ffi.NULL
123+
pfx_cffi_callback = ffi.NULL
124+
125+
self._spki_update_callback_data = spki_update_callback_data
126+
if spki_update_callback:
127+
self._spki_update_callback = spki_update_callback
128+
spki_cffi_callback = lib.spki_update_callback
129+
else:
130+
self._spki_update_callback = ffi.NULL
131+
spki_cffi_callback = ffi.NULL
132+
101133
self.host = ffi.new('char[]', to_bytestr(host))
102134
self.port = ffi.new('char[]', to_bytestr(port))
103135

104136
rtr_manager_config = ffi.new('struct rtr_mgr_config **')
105137

106138
self.tcp_config = ffi.new('struct tr_tcp_config *')
107139
self.tr_socket = ffi.new('struct tr_socket *')
108-
self.rtr_socket = ffi.new('struct rtr_socket []', 1)
140+
self.rtr_socket = ffi.new('struct rtr_socket_wrapper *')
109141
self.rtr_group = ffi.new('struct rtr_mgr_group[]', 1)
110142

111143
self.tcp_config.host = self.host
112144
self.tcp_config.port = self.port
113145

114146
lib.tr_tcp_init(self.tcp_config, self.tr_socket)
115-
self.rtr_socket[0].tr_socket = self.tr_socket
147+
self.rtr_socket.rtr_socket.tr_socket = self.tr_socket
148+
self.rtr_socket[0].data = self._handle
116149
self.rtr_group[0].sockets_len = 1
117-
self.rtr_socketp = ffi.new('struct rtr_socket **', self.rtr_socket)
150+
self.rtr_socketp = ffi.new('struct rtr_socket **', ffi.cast("struct rtr_socket *", self.rtr_socket))
118151
self.rtr_group[0].sockets = self.rtr_socketp
119152
self.rtr_group[0].preference = 1
120153

@@ -124,8 +157,8 @@ def __init__(
124157
refresh_interval,
125158
expire_interval,
126159
retry_interval,
127-
callbacks.PFX_UPDATE_CALLBACK,
128-
callbacks.SPKI_UPDATE_CALLBACK,
160+
pfx_cffi_callback,
161+
spki_cffi_callback,
129162
cffi_callback,
130163
self._handle
131164
)

tools/rtrclient.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import argparse
55
import signal
66

7-
from rtrlib import RTRManager, register_pfx_update_callback, register_spki_update_callback
7+
from rtrlib import RTRManager
88

99
def pfx_callback(pfx_record, added):
1010
if added:
@@ -50,13 +50,17 @@ def main():
5050
args = parser.parse_args()
5151

5252
if args.p:
53-
register_pfx_update_callback(pfx_callback)
53+
pfx_fp = pfx_callback
54+
else:
55+
pfx_fp = None
5456

5557
if args.k:
56-
register_spki_update_callback(spki_callback)
58+
spki_fp = spki_callback
59+
else:
60+
spki_fp = None
5761

5862
print("{:40} {:3} {:4}".format("Prefix", "Prefix Length", "ASN"))
59-
with RTRManager(args.hostname, args.port) as mgr:
63+
with RTRManager(args.hostname, args.port, pfx_update_callback=pfx_fp, spki_update_callback=spki_fp) as mgr:
6064
try:
6165
signal.pause()
6266
except KeyboardInterrupt:

0 commit comments

Comments
 (0)