Search code examples
scapybgp

Changing BGP packet size less than 19 and greater than 4096


I am working with bgp implementation on ubuntu. I want to do some malformation in bgp packets , bgp restrict us on size between 19 to 4096 , however for testing purpose I am changing the size less than 19 and greater than 4096. After this when I send this packet from one to second, on established bgp session between two speakers, second one should send notification message containing error: bad message length. But I am not getting that rather it is showing malformed packet in wireshark and also I am not able to open that packet in wireshark. Can anybody help me in this malformation of packet and to get notification error.

Just for information: I have tried every packets like open, update and keepalive. malformed open packet:


Solution

  • UPDATED ANSWER BELOW

    The BGP packet shown in Wireshark has marker field (16 x ff) followed by length 16 (00 10).

    Thus, this is indeed the scenario that you wanted to test: your tester BGP speaker sent a BGP packet with an incorrect length, and the remote BGP speaker under test should respond by sending back a NOTIFICATION packet with error code "Message Header Error" and error sub-code "Bad Message Length".

    Wireshark is showing the malformed BGP packet that was sent from the tester BGP speaker to the BGP speaker under test. Wireshark is correct to complain that it is a malformed BGP packet: it is malformed because the length is invalid. Evidently, Wireshark is not very specific about what it doesn't like about the packet.

    You should look in the TCP stream in the reverse direction (source 10.0.0.2 destination 10.0.0.1) and look for the BGP NOTIFICATION packet that the BGP speaker under test sent back.

    UPDATED ANSWER STARTS HERE

    Based on the error message ([Error] bgp_read_packet error: Connection reset), it looks like you are testing Free Range Routing, or one of its predecessors Quagga or Zebra.

    I reproduced the scenario you are testing.

    I am running a Free Range Routing (FRR) BGP speaker with the following configuration:

    Current configuration:
    !
    frr version 7.1-dev-MyOwnFRRVersion
    frr defaults traditional
    hostname ip-172-31-31-121
    log file /var/log/frr/debug.log
    log syslog
    service integrated-vtysh-config
    !
    debug bgp neighbor-events
    !
    router bgp 100
     neighbor X.X.X.X remote-as 200   
    !
    line vty
    !
    end
    

    I use the following Python test program to send a message with a "too short" header:

    #!/usr/bin/env python3
    
    import socket
    
    BGP_IP = 'Y.Y.Y.Y'
    
    SHORT_MSG = (b'\xff\xff\xff\xff\xff\xff\xff\xff'     # First 8 bytes of marker
                 b'\xff\xff\xff\xff\xff\xff\xff\xff'     # Last 8 bytes of marker
                 b'\x00\x10'                             # Length 16
                 b'\x01')                                # Open
    
    def main():
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        print("Socket created")
        sock.connect((BGP_IP, 179))
        print("Socket connected")
        sock.send(SHORT_MSG)
        print("Short message sent")
        while True:
            data = sock.recv(1)
            if data == b'':
                print("Connection closed or reset")
                break
            print("Received:", data)
    
    if __name__ == "__main__":
        main()
    

    Replace X.X.X.X with the IP address of the tester, and replace Y.Y.Y.Y with the IP address of the BGP speaker under test.

    In this scenario, the BGP speaker under test does indeed send the correct NOTIFICATION message.

    Here is what the FRR log reports:

    2019/02/09 21:49:05 BGP: 172.31.17.121 [FSM] Timer (connect timer expire)
    2019/02/09 21:49:05 BGP: 172.31.17.121 [FSM] ConnectRetry_timer_expired (Active->Connect), fd -1
    2019/02/09 21:49:05 BGP: 172.31.17.121 [Event] Connect start to 172.31.17.121 fd 26
    2019/02/09 21:49:05 BGP: 172.31.17.121 [FSM] Non blocking connect waiting result, fd 26
    2019/02/09 21:49:05 BGP: bgp_fsm_change_status : vrf 0, established_peers 0
    2019/02/09 21:49:05 BGP: 172.31.17.121 went from Active to Connect
    2019/02/09 21:49:05 BGP: 172.31.17.121 [Event] Connect failed 111(Connection refused)
    2019/02/09 21:49:05 BGP: 172.31.17.121 [FSM] TCP_connection_open_failed (Connect->Active), fd 26
    2019/02/09 21:49:05 BGP: bgp_fsm_change_status : vrf 0, established_peers 0
    2019/02/09 21:49:05 BGP: 172.31.17.121 went from Connect to Active
    2019/02/09 21:49:08 BGP: [Event] BGP connection from host 172.31.17.121 fd 26
    2019/02/09 21:49:08 BGP: bgp_fsm_change_status : vrf 0, established_peers 0
    2019/02/09 21:49:08 BGP: 172.31.17.121 went from Idle to Active
    2019/02/09 21:49:08 BGP: 172.31.17.121 [FSM] TCP_connection_open (Active->OpenSent), fd 26
    2019/02/09 21:49:08 BGP: 172.31.17.121 passive open
    2019/02/09 21:49:08 BGP: 172.31.17.121 Sending hostname cap with hn = ip-172-31-31-121, dn = (null)
    2019/02/09 21:49:08 BGP: 172.31.17.121 sending OPEN, version 4, my as 100, holdtime 180, id 172.31.31.121
    2019/02/09 21:49:08 BGP: bgp_fsm_change_status : vrf 0, established_peers 0
    2019/02/09 21:49:08 BGP: 172.31.17.121 went from Active to OpenSent
    2019/02/09 21:49:08 BGP: 172.31.17.121 bad message length - 16 for OPEN
    2019/02/09 21:49:08 BGP: %NOTIFICATION: sent to neighbor 172.31.17.121 1/2 (Message Header Error/Bad Message Length) 2 bytes 00 10
    2019/02/09 21:49:08 BGP: 172.31.17.121 [FSM] BGP_Stop (OpenSent->Idle), fd 26
    2019/02/09 21:49:08 BGP: bgp_fsm_change_status : vrf 0, established_peers 0
    2019/02/09 21:49:08 BGP: 172.31.17.121 went from OpenSent to Deleted
    

    Note the "Bad Message Length" message.

    Here is what the test program reports:

    Socket created
    Socket connected
    Short message sent
    Received: b'\xff'
    Received: b'\xff'
    Received: b'\xff'
    Received: b'\xff'
    Received: b'\xff'
    Received: b'\xff'
    Received: b'\xff'
    Received: b'\xff'
    Received: b'\xff'
    Received: b'\xff'
    Received: b'\xff'
    Received: b'\xff'
    Received: b'\xff'
    Received: b'\xff'
    Received: b'\xff'
    Received: b'\xff'
    Received: b'\x00'
    Received: b'\x17'
    Received: b'\x03'
    Received: b'\x01'
    Received: b'\x02'
    Received: b'\x00'
    Received: b'\x10'
    Connection closed or reset
    

    Note that this is the correct Bad Message Length NOTIFICATION.

    Here is the Wireshark decode of the bad message:

    enter image description here

    Here is the Wireshark decode of the NOTIFICATION:

    enter image description here

    If the test program terminates without attempting to read the NOTIFICATION message, then the BGP speaker under test will not be able to send the NOTIFICATION message on the wire. This is because it will receive a TCP RST message before it is able to send the NOTIFICATION. This is most likely why you did not see the NOTIFICATION on the wire.

    Indeed, I was able to reproduce this hypothesis by modifying the test program as follows:

    #!/usr/bin/env python3
    
    import socket
    import struct
    
    BGP_IP = '172.31.31.121'
    
    SHORT_MSG = (b'\xff\xff\xff\xff\xff\xff\xff\xff'     # First 8 bytes of marker
                 b'\xff\xff\xff\xff\xff\xff\xff\xff'     # Last 8 bytes of marker
                 b'\x00\x10'                             # Length 16
                 b'\x01')                                # Open
    
    def main():
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        print("Socket created")
        sock.connect((BGP_IP, 179))
        print("Socket connected")
        sock.send(SHORT_MSG)
        # Trick TCP into sending a RST when the socket is closed
        on_off = 1
        linger = 0
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', on_off, linger))
        print("Socket linger time set to 0")
        # Close the socket
        sock.close()
        print("Socket closed")
        # Terminate without reading the response NOTIFICATION
    
    if __name__ == "__main__":
        main()
    

    Using this test program, the NOTIFICATION is missing from the Wireshark trace (exactly as you reported it):

    enter image description here

    Note that I had to jump through some hoops (specifically setting the linger time to zero) to force the test program to send a RST as opposed to a FIN ACK. (See Sending a reset in TCP/IP Socket connection for details.)

    If the test program sends a FIN ACK instead of a RST (which happens if you gracefully close the socket, or even terminate normally without closing the socket), then the BGP speaker under test will be able to send the NOTIFICATION after receiving the FIN ACK but before sending its own FIN ACK.