Run BGP on a Linux Box
This script runs on a linux machine and will establish a BGP session with a router.
#!/usr/bin/python3
import socket
import ipaddress
import struct
import threading
from time import sleep
from tkinter import *
#variables
hold_time = 90
version = 4
opts = b''
auth = b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'
old_routes = []
peers = {}
close = 1
#GUI stuff
myWindow = Tk()
myWindow.geometry('380x600')
myWindow.title('BGP Wizard')
peerIP_label = Label(myWindow,text='Peer IP')
peerIP_label.pack()
peerIP_label.config(font=('verdana', 12))
peerIP = Entry(myWindow)
peerIP.pack(ipady=3)
myIP_label = Label(myWindow,text='My IP')
myIP_label.pack()
myIP_label.config(font=('verdana', 12))
myIP = Entry(myWindow)
myIP.pack(ipady=3)
myAS_label = Label(myWindow,text='my AS Number')
myAS_label.pack()
myAS_label.config(font=('verdana', 12))
myAS = Entry(myWindow)
myAS.pack(ipady=3)
myASPath_label = Label(myWindow,text='AS Path to Advertise')
myASPath_label.pack()
myASPath_label.config(font=('verdana', 12))
myASPath = Entry(myWindow)
myASPath.pack(ipady=3)
localPref_label = Label(myWindow,text='Local Preference')
localPref_label.pack()
localPref_label.config(font=('verdana', 12))
localPref = Entry(myWindow)
localPref.pack(ipady=3)
routes_label = Label(myWindow,text='Routes to Advertise')
routes_label.pack()
routes_label.config(font=('verdana', 12))
text_box = Text(myWindow, height=12,width=30,)
text_box.pack()
#functions
def close_window():
#this function is for when the user closes the window
global close
close = 0
myWindow.destroy()
def packSubnet(network):
#this function is for the network advertisement
data = b''
temp_data = b''
binNetwork = struct.pack("!I", int(ipaddress.IPv4Network(network)[0]))
for x in struct.iter_unpack("B", binNetwork):
if x[0]:
data += temp_data #incase 0 bits in the middle
data += struct.pack("B", x[0])
else:
temp_data += struct.pack("B", x[0])
return data
def keepalive():
#this thread is for sending keepalives
global bgp_socket
while close:
data = auth + struct.pack("!Hb", 19, 4)
bgp_socket.send(data)
print("keepalive sent")
sleep(30)
def recBGPupdates():
#this thread is for BGP message communication
global bgp_socket
global peers
global close
while close:
auth = bgp_socket.recv(16)
length = struct.unpack("!H", bgp_socket.recv(2))
data = bgp_socket.recv(length[0] - 18)
(type, ) = struct.unpack("b", data[:1]) #get bgp message type
if type == 1:
#open
print("received an open message")
(bgp_version, peer_as, hold_time, peer_router_id, opts_length) = struct.unpack("!b2HIb", data[1:11])
elif type == 2:
#update
(withdraw_len, attr_len) = (struct.unpack("!2H", data[1:5]))
elif type == 3:
#notification
(major_err, minor_err) = (struct.unpack("2b", data[1:3]))
print("notification received")
close = 0
break
elif type == 4:
#keepalive
print("keepalive received")
def handleBGP():
#this function is for establishing the bgp session
global bgp_socket
global close
peer_ip = peerIP.get()
my_as = int(myAS.get())
my_ip = myIP.get()
close = 1
router_id = int(ipaddress.ip_address(my_ip))
if(ipaddress.ip_address(my_ip) < ipaddress.ip_address(peer_ip)):
#we initiate
mysocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mysocket.bind((my_ip, 179))
mysocket.listen(1)
(bgp_socket, client_ip) = mysocket.accept()
else:
#we are the client
bgp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
bgp_socket.connect((peer_ip, 179))
client_ip = peer_ip
updates_thread = threading.Thread(target=recBGPupdates)
updates_thread.start()
data = struct.pack("!bbHHI", 1, version, my_as, hold_time, router_id)
opts_length = len(opts)
data = data + struct.pack("b", opts_length) + opts
length = len(data) + 18
data = auth + struct.pack("!H", length) + data
bgp_socket.send(data)
keepalive_thread = threading.Thread(target=keepalive)
keepalive_thread.start()
def advertiseRoutes():
#this function is for advertising/withdrawing routes
global old_routes
global bgp_socket
next_hop = myIP.get()
as_path = myASPath.get().split()
local_pref = int(localPref.get())
new_routes = text_box.get('1.0', 'end').splitlines()
withdrawn_routes = set(old_routes) - set(new_routes)
old_routes = new_routes
data = b'\x02'
with_data = b''
if(withdrawn_routes):
for prefix in withdrawn_routes:
if(ipaddress.ip_network(prefix)):
line = prefix.split('/')
with_data += struct.pack("b", int(line[1]))
with_data += packSubnet(prefix)
data += struct.pack("!H", len(with_data))
data += with_data
adv_data = b''
as_data = b'\x02' #set AS segment type. used later
adv_data += b'\x40\x01\x01\x00' #origin IGP
adv_data += b'\x40\x02' #AS path
as_data += struct.pack("b", len(as_path))
for asn in as_path:
as_data += struct.pack("!H", int(asn))
adv_data += struct.pack("b", len(as_data)) + as_data
adv_data += b'\x40\x03\x04' #next hop #ipv4
adv_data += struct.pack("!I", int(ipaddress.ip_address(next_hop))) #for ipv4 only
adv_data += b'\x40\x05\x04' #local pref
adv_data += struct.pack("!I", local_pref)
data += struct.pack("!H", len(adv_data))
data += adv_data
for prefix in new_routes:
if(ipaddress.ip_network(prefix)):
line = prefix.split('/')
data += struct.pack("b", int(line[1]))
subnet = packSubnet(prefix)
data += subnet
data = auth + struct.pack("!H", len(data) + 18) + data
bgp_socket.send(data)
print("update sent")
start_session = Button(myWindow,text='Establish BGP', command=handleBGP)
start_session.pack()
send_update = Button(myWindow,text='Send Update', command=advertiseRoutes)
send_update.pack()
myWindow.protocol("WM_DELETE_WINDOW", close_window)
myWindow.mainloop()