-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add bgp_rpki_topo1 topotest to validate the RPKI feature. Use a RTR RPKI server from the above link. Link: https://raw.githubusercontent.com/SmartValidator/rtr-python/368a4e268aaae0de7d88d0c34665315661851d40/rtrd.py Signed-off-by: Louis Scalbert <[email protected]>
- Loading branch information
1 parent
9561c86
commit 8129be6
Showing
9 changed files
with
417 additions
and
0 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,271 @@ | ||
#!/usr/bin/python3 | ||
# | ||
# by Tomas Hlavacek ([email protected]) | ||
|
||
import socket | ||
import threading | ||
import socketserver | ||
import struct | ||
import ipaddress | ||
|
||
HOST, PORT = "0.0.0.0", 15432 | ||
|
||
|
||
def dbg(m): | ||
print(m) | ||
|
||
|
||
class RTRDatabase(object): | ||
def __init__(self): | ||
self.last_serial = 0 | ||
|
||
def get_serial(self): | ||
return self.last_serial | ||
|
||
def set_serial(self, serial): | ||
self.last_serial = serial | ||
|
||
def get_announcements4(self, serial=0): | ||
if serial > self.last_serial: | ||
return [(29134, "217.31.48.0/20", 20), (29134, "62.109.128.0/19", 19)] | ||
else: | ||
return [] | ||
|
||
def get_withdrawals4(self, serial=0): | ||
return [] | ||
|
||
def get_announcements6(self, serial=0): | ||
return [] | ||
|
||
def get_withdrawals6(self, serial=0): | ||
return [] | ||
|
||
|
||
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): | ||
def __init__(self, bind, handler, db): | ||
super().__init__(bind, handler) | ||
self.db = db | ||
|
||
|
||
class RTRConnHandler(socketserver.BaseRequestHandler): | ||
PROTO_VERSION = 0 | ||
|
||
def setup(self): | ||
self.session_id = 2345 | ||
self.serial = 1024 | ||
|
||
dbg("New connection from: %s " % str(self.client_address)) | ||
# TODO: register for notifies | ||
|
||
def finish(self): | ||
pass | ||
# TODO: de-register | ||
|
||
HEADER_LEN = 8 | ||
|
||
def decode_header(self, buf): | ||
# common header in all received packets | ||
return struct.unpack("!BBHI", buf) | ||
# reutnrs (proto_ver, pdu_type, sess_id, length) | ||
|
||
SERNOTIFY_TYPE = 0 | ||
SERNOTIFY_LEN = 12 | ||
|
||
def send_sernotify(self, serial): | ||
# serial notify PDU | ||
dbg("<Serial Notify session_id=%d serial=%d" % (self.session_id, serial)) | ||
self.request.send( | ||
struct.pack( | ||
"!BBHII", | ||
self.PROTO_VERSION, | ||
self.SERNOTIFY_TYPE, | ||
self.session_id, | ||
self.SERNOTIFY_LEN, | ||
serial, | ||
) | ||
) | ||
|
||
CACHERESPONSE_TYPE = 3 | ||
CACHERESPONSE_LEN = 8 | ||
|
||
def send_cacheresponse(self): | ||
# cache response PDU | ||
dbg("<Cache response session_id=%d" % self.session_id) | ||
self.request.send( | ||
struct.pack( | ||
"!BBHI", | ||
self.PROTO_VERSION, | ||
self.CACHERESPONSE_TYPE, | ||
self.session_id, | ||
self.CACHERESPONSE_LEN, | ||
) | ||
) | ||
|
||
FLAGS_ANNOUNCE = 1 | ||
FLAGS_WITHDRAW = 0 | ||
|
||
IPV4_TYPE = 4 | ||
IPV4_LEN = 20 | ||
|
||
def send_ipv4(self, ipnet, asn, maxlen, flags): | ||
# IPv4 PDU | ||
dbg("<IPv4 net=%s asn=%d maxlen=%d flags=%d" % (ipnet, asn, maxlen, flags)) | ||
ip = ipaddress.IPv4Network(ipnet) | ||
self.request.send( | ||
struct.pack( | ||
"!BBHIBBBB4sI", | ||
self.PROTO_VERSION, | ||
self.IPV4_TYPE, | ||
0, | ||
self.IPV4_LEN, | ||
flags, | ||
ip.prefixlen, | ||
maxlen, | ||
0, | ||
ip.network_address.packed, | ||
asn, | ||
) | ||
) | ||
|
||
def announce_ipv4(self, ipnet, asn, maxlen): | ||
self.send_ipv4(ipnet, asn, maxlen, self.FLAGS_ANNOUNCE) | ||
|
||
def withdraw_ipv4(self, ipnet, asn, maxlen): | ||
self.send_ipv4(ipnet, asn, maxlen, self.FLAGS_WITHDRAW) | ||
|
||
IPV6_TYPE = 6 | ||
IPV6_LEN = 32 | ||
|
||
def send_ipv6(self, ipnet, asn, maxlen, flags): | ||
# IPv6 PDU | ||
dbg("<IPv6 net=%s asn=%d maxlen=%d flags=%d" % (ipnet, asn, maxlen, flags)) | ||
ip = ipaddress.IPv6Network(ipnet) | ||
self.request.send( | ||
struct.pack( | ||
"!BBHIBBBB16sI", | ||
self.PROTO_VERSION, | ||
self.IPV6_TYPE, | ||
0, | ||
self.IPV6_LEN, | ||
flags, | ||
ip.prefixlen, | ||
maxlen, | ||
0, | ||
ip.network_address.packed, | ||
asn, | ||
) | ||
) | ||
|
||
def announce_ipv6(self, ipnet, asn, maxlen): | ||
self.send_ipv6(ipnet, asn, maxlen, self.FLAGS_ANNOUNCE) | ||
|
||
def withdraw_ipv6(self, ipnet, asn, maxlen): | ||
self.send_ipv6(ipnet, asn, maxlen, self.FLAGS_WITHDRAW) | ||
|
||
EOD_TYPE = 7 | ||
EOD_LEN = 12 | ||
|
||
def send_endofdata(self, serial): | ||
# end of data PDU | ||
dbg("<End of Data session_id=%d serial=%d" % (self.session_id, serial)) | ||
self.server.db.set_serial(serial) | ||
self.request.send( | ||
struct.pack( | ||
"!BBHII", | ||
self.PROTO_VERSION, | ||
self.EOD_TYPE, | ||
self.session_id, | ||
self.EOD_LEN, | ||
serial, | ||
) | ||
) | ||
|
||
CACHERESET_TYPE = 8 | ||
CACHERESET_LEN = 8 | ||
|
||
def send_cachereset(self): | ||
# cache reset PDU | ||
dbg("<Cache Reset") | ||
self.request.send( | ||
struct.pack( | ||
"!BBHI", | ||
self.PROTO_VERSION, | ||
self.CACHERESET_TYPE, | ||
0, | ||
self.CACHERESET_LEN, | ||
) | ||
) | ||
|
||
SERIAL_QUERY_TYPE = 1 | ||
SERIAL_QUERY_LEN = 12 | ||
|
||
def handle_serial_query(self, buf): | ||
serial = struct.unpack("!I", buf)[0] | ||
dbg(">Serial query: %d" % serial) | ||
self.send_cacheresponse() | ||
|
||
for asn, ipnet, maxlen in self.server.db.get_announcements4(serial): | ||
self.announce_ipv4(ipnet, asn, maxlen) | ||
|
||
for asn, ipnet, maxlen in self.server.db.get_withdrawals4(serial): | ||
self.withdraw_ipv4(ipnet, asn, maxlen) | ||
|
||
for asn, ipnet, maxlen in self.server.db.get_announcements6(serial): | ||
self.announce_ipv6(ipnet, asn, maxlen) | ||
|
||
for asn, ipnet, maxlen in self.server.db.get_withdrawals6(serial): | ||
self.withdraw_ipv6(ipnet, asn, maxlen) | ||
|
||
self.send_endofdata(self.serial) | ||
|
||
RESET_TYPE = 2 | ||
|
||
def handle_reset(self): | ||
dbg(">Reset") | ||
self.session_id += 1 | ||
self.send_cacheresponse() | ||
|
||
for asn, ipnet, maxlen in self.server.db.get_announcements4(self.serial): | ||
self.announce_ipv4(ipnet, asn, maxlen) | ||
|
||
for asn, ipnet, maxlen in self.server.db.get_announcements6(self.serial): | ||
self.announce_ipv6(ipnet, asn, maxlen) | ||
|
||
self.send_endofdata(self.serial) | ||
|
||
ERROR_TYPE = 10 | ||
|
||
def handle_error(self, buf): | ||
dbg(">Error: %s" % str(buf)) | ||
|
||
def handle(self): | ||
while True: | ||
b = self.request.recv(self.HEADER_LEN, socket.MSG_WAITALL) | ||
proto_ver, pdu_type, sess_id, length = self.decode_header(b) | ||
dbg( | ||
">Header proto_ver=%d pdu_type=%d sess_id=%d length=%d" | ||
% (proto_ver, pdu_type, sess_id, length) | ||
) | ||
|
||
if pdu_type == self.SERIAL_QUERY_TYPE: | ||
b = self.request.recv( | ||
self.SERIAL_QUERY_LEN - self.HEADER_LEN, socket.MSG_WAITALL | ||
) | ||
self.handle_serial_query(b) | ||
|
||
elif pdu_type == self.RESET_TYPE: | ||
self.handle_reset() | ||
|
||
elif pdu_type == self.ERROR_TYPE: | ||
b = self.request.recv(length - self.HEADER_LEN, socket.MSG_WAITALL) | ||
self.handle_error(b) | ||
|
||
|
||
def main(): | ||
db = RTRDatabase() | ||
server = ThreadedTCPServer((HOST, PORT), RTRConnHandler, db) | ||
server.serve_forever() | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
ip route 192.0.2.2/32 192.168.1.2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
! | ||
interface lo | ||
ip address 192.0.2.1/32 | ||
! | ||
interface r1-eth0 | ||
ip address 192.168.1.1/24 | ||
! |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"prefixes":[ | ||
{ | ||
"prefix":"62.109.128.0", | ||
"prefixLenMin":19, | ||
"prefixLenMax":19, | ||
"asn":29134 | ||
}, | ||
{ | ||
"prefix":"217.31.48.0", | ||
"prefixLenMin":20, | ||
"prefixLenMax":20, | ||
"asn":29134 | ||
} | ||
], | ||
"ipv4PrefixCount":2, | ||
"ipv6PrefixCount":0 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
ip route 192.0.2.1/32 192.168.1.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
! | ||
int lo | ||
ip address 192.0.2.2/32 | ||
! | ||
interface r2-eth0 | ||
ip address 192.168.1.2/24 | ||
! | ||
interface r2-eth1 | ||
ip address 192.168.2.2/24 | ||
! | ||
|
Oops, something went wrong.