1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
#!/usr/bin/env python
# $Id$
#
# Copyright (C) 2014 Dragon Research Labs ("DRL")
# Portions copyright (C) 2009-2013 Internet Systems Consortium ("ISC")
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notices and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND DRL AND ISC DISCLAIM ALL
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DRL OR
# ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
import asyncore
import bisect
import glob
import logging
import os
import shutil
import sqlite3
import subprocess
import sys
import time
import rpki.POW
import rpki.oids
import rpki.rtr.channels
import rpki.rtr.client
import rpki.rtr.generator
import rpki.rtr.pdus
import rpki.rtr.server
from rpki.rtr.channels import Timestamp
class ReplayClock(object):
"""
Internal clock for replaying a set of rpki-rtr database files.
This class replaces the normal on-disk serial number mechanism with
an in-memory version based on pre-computed data.
DO NOT USE THIS IN PRODUCTION.
You have been warned.
"""
def __init__(self):
self.timestamps = dict((v, sorted(set(Timestamp(int(f.split(".")[0]))
for f in glob.iglob("*.ax.v%d" % v))))
for v in rpki.rtr.pdus.PDU.version_map)
self.epoch = min(t[0] for t in self.timestamps.itervalues())
self.offset = self.epoch - Timestamp.now()
self.nonce = rpki.rtr.generator.AXFRSet.new_nonce(0)
def __nonzero__(self):
return sum(len(t) for t in self.timestamps.itervalues()) > 0
def now(self):
now = Timestamp.now(self.offset)
return now
def read_current(self, version):
now = self.now()
if version is None:
return self.epoch, self.nonce
while len(self.timestamps[version]) > 1 and now >= self.timestamps[version][1]:
del self.timestamps[version][0]
return self.timestamps[version][0], self.nonce
def siesta(self):
try:
when = min(t[1] for t in self.timestamps.itervalues() if len(t) > 1)
except ValueError:
return None
now = self.now()
if now < when:
return when - now
else:
return 1
def server_main(args):
"""
Reply rpki-data from a historical database.
This is a clone of server_main() which replaces the external serial
number updates triggered via the kickme channel by cronjob_main with
an internal clocking mechanism to replay historical test data.
DO NOT USE THIS IN PRODUCTION.
You have been warned.
"""
logger = logging.LoggerAdapter(logging.root, dict(connection = rpki.rtr.server._hostport_tag()))
logger.debug("[Starting]")
if args.rpki_rtr_dir:
try:
os.chdir(args.rpki_rtr_dir)
except OSError, e:
sys.exit(e)
# Yes, this really does replace a global function defined in another
# module with a bound method to our clock object. Fun stuff, huh?
clock = ReplayClock()
rpki.rtr.server.read_current = clock.read_current
try:
server = rpki.rtr.server.ServerChannel(logger = logger, refresh = args.refresh, retry = args.retry, expire = args.expire)
old_serial = server.get_serial()
logger.debug("[Starting at serial %d (%s)]", old_serial, old_serial)
while clock:
new_serial = server.get_serial()
if old_serial != new_serial:
logger.debug("[Serial bumped from %d (%s) to %d (%s)]", old_serial, old_serial, new_serial, new_serial)
server.notify(force = True)
old_serial = new_serial
asyncore.loop(timeout = clock.siesta(), count = 1)
except KeyboardInterrupt:
sys.exit(0)
# Splice our extensions into server
rpki.rtr.server.server_main = server_main
# And run the program
import rpki.rtr.main
rpki.rtr.main.main()
|