def default_holdtime_expiry(clnt): """Handle hold time expiry the easy if lame way: Just print a message. The "correct" thing to do would be to end the connection at this point. But for the present program, just printing a message and doing nothing else seems reasonable.""" bmisc.stamprint("Hold time expired.")
def recv(self): "Return a received BGPMessage, or None if there is none" if not self.ista: # already know there isn't one, don't waste time checking if dbg.sokw: bmisc.stamprint("SocketWrap.recv(): None") return (None) if len(self.ipnd) < 19: # there isn't a full header if dbg.sokw: bmisc.stamprint("SocketWrap.recv(): not a full header yet") self.ista = False return (None) # read the message length field of the header ml = (self.ipnd[16] << 8) + self.ipnd[17] if len(self.ipnd) < ml: # there isn't a full message if dbg.sokw: bmisc.stamprint("SocketWrap.recv(): not a full message yet") self.ista = False return (None) # consume, parse, and return the message mr = self.ipnd[:ml] self.ipnd = self.ipnd[ml:] if dbg.sokw: bmisc.stamprint("SocketWrap.recv(): message, " + repr(ml) + " bytes") msg = brepr.BGPMessage.parse(self.env, ParseCtx(mr)) if not self.quiet: bmisc.stamprint("Recv: " + str(msg)) return (msg)
def tcp_hex_handler(wrpsok, rw, data): if len(data) == 0: return # nothing to do if rw == "r": (posa, rws) = (tcp_hex_ipos, "tcp-rcv") else: (posa, rws) = (tcp_hex_opos, "tcp-snd") bmisc.stamprint(rws + ", " + str(len(data)) + " bytes:") # byte values vs = list(map("{:02x}".format, data)) # padding for alignment with posa[0] vs = [" "] * (posa[0] & 15) + vs # display as lines, 16 bytes per line, with an address prefixed to it i = 0 for i in range(0, len(vs), 16): print("{}.{:010x}: {}".format(rws, ((posa[0] & ~15) + i), " ".join(vs[i:(i + 16)])), file=sys.stderr) posa[0] += len(data)
def able_recv(self): """Called when select() indicates this socket can receive something. Returns True normally, False if socket closed.""" if dbg.sokw: bmisc.stamprint("SocketWrap.able_recv() called") if self.ibroke: bmisc.stamprint( "SocketWrap.able_recv() doing nothing: conn broken") return get = 512 try: got = self.sok.recv(get) except BrokenPipeError: got = bytes() except ConnectionResetError: got = bytes() if len(got): self.ipnd += got # we got something: buffer it self.ista = True # and it *might* be a message if self.env.data_cb is not None: self.env.data_cb(self, "r", got) else: # Connection has been closed self.ibroke = True if dbg.sokw: bmisc.stamprint("connection closure detected on recv") return (False) return (True)
def accept_connection(self): """Accept a connection on this client's socket, moving it out of listen_mode into normal operation.""" # sanity check if not self.listen_mode or self.wrpsok is not None: raise Exception("internal error, accepting connection" + " twice or something") # get a connection sok, remote = self.sok.accept() # close and replace the socket since we won't be accepting # any more connections on it self.sok.close() self.sok = sok self.wrpsok = boper.SocketWrap(sok, self.env) self.wrpsok.set_quiet(self.quiet) self.listen_mode = False # and announce what's happened bmisc.stamprint("Accepted connection from " + repr(remote))
def send(self, msg): "Queue a BGPMessage for sending" if self.obroke: bmisc.stamprint("SocketWrap.send(): disabled because connection" + " was closed.") self.opnd += msg.raw if not self.quiet: bmisc.stamprint("Send: " + str(msg)) if dbg.sokw: bmisc.stamprint("SocketWrap.send(): " + repr(len(msg.raw)) + " bytes added to queue, => " + repr(len(self.opnd)))
def able_send(self): "Called when select() indicates this socket can send something" if dbg.sokw: bmisc.stamprint("SocketWrap.able_send() called") if self.obroke: bmisc.stamprint( "SocketWrap.able_send() doing nothing: conn broken") return try: sent = self.sok.send(self.opnd) except BrokenPipeError: sent = 0 except ConnectionResetError: sent = 0 if sent > 0: # we sent something, remove it from the output buffer if self.env.data_cb is not None: self.env.data_cb(self, "w", self.opnd[:sent]) self.opnd = self.opnd[sent:] else: self.obroke = True if dbg.sokw: bmisc.stamprint("connection closure detected on send")
def __init__(self, sok, local_as, router_id, outfile=sys.stdout, errfile=sys.stderr, holdtime_sec=60, holdtime_expiry=default_holdtime_expiry, as4_us=False, rr_us=False, listen_mode=False, quiet=False): """Constructor. Various parameters: Required: sok -- TCP socket connected to the peer local_as -- our local autonomous system (AS) number router_id -- router ID -- 32 bit integer or IPv4 address represented as int or 4 bytes Optional: outfile -- regular output stream, default is stdout errfile -- error output stream, default is stderr holdtime_sec -- hold time to propose in seconds holdtime_expiry -- function (passed this Client object) to call when the negotiated hold time has expired as4_us -- whether to support 4-octet AS number (RFC 6793); whether it's actually implemented depends on the peer rr_us -- whether to advertise route refresh capability (RFC 2918); the actual functionality is not implemented in bgpy listen_mode -- whether we're waiting for a connection (True) or are already connected (False); True is normal operation and is the usual case quiet -- whether to suppress many details of what we're doing from the log output """ if type(holdtime_sec) is not int: raise TypeError("Hold time must be an integer") if holdtime_sec != 0 and holdtime_sec < 3: raise ValueError("Hold time must be 0 or >= 3 seconds") if holdtime_sec > 65535: raise ValueError("Hold time may be no more than 65535 seconds") self.env = brepr.BGPEnv() self.sok = sok self.listen_mode = listen_mode self.quiet = quiet if self.listen_mode: self.wrpsok = None # not connected, can't wrap it yet else: self.wrpsok = boper.SocketWrap(sok, self.env) self.wrpsok.set_quiet(self.quiet) self.local_as = local_as if type(router_id) is int: if (router_id >> 32): raise ValueError("Router id must be 32 bits") ba = bytearray() bmisc.ba_put_be4(ba, router_id) router_id = ba router_id = bytes(router_id) if len(router_id) != 4: raise ValueError("Router id must be 32 bits") self.router_id = router_id self.outfile = outfile self.errfile = errfile self.holdtime_sec = holdtime_sec self.open_sent = None # BGP Open message we sent if any self.open_recv = None # BGP Open message we received if any self.as4_us = as4_us self.rr_us = rr_us if self.listen_mode: bmisc.stamprint("Listening.") else: bmisc.stamprint("Connected.")
if len(sys.argv) < 2: usage() for a in sys.argv[1:-1]: try: equal_parms.parse(a) except Exception as e: print(str(e), file=sys.stderr) if dbg.estk: print_exc(file=sys.stderr) usage() peer_addr = sys.argv[-1] bmisc.stamprint("Started.") # figure out addresses af, connect_addr = bmisc.addr_for_socket(peer_addr, port=brepr.BGP_TCP_PORT) bind_to = None if equal_parms["local-addr"] != "" or equal_parms["passive"]: bind_to_addr = equal_parms["local-addr"] if bind_to_addr == "": if af == socket.AF_INET: bind_to_addr = "0.0.0.0" else: bind_to_addr = "::" bind_to_port = None