A Short Introduction
Welcome back! Last week we covered the elusive LDAP, so this week is going to be a bit more shallow — we’ll cover the Boarder Gateway Protocol (BGP) as defined by RFC 4271 and RFC 2918. Don’t worry about the protocol and its purpose too much, because the DPI part is quite easy and distinctive. As always, the code presented is part of a new DPI library, which will be made available via a BSD/ISC license. Ready? Ok, here we go.
OpenDPI Does a Good Job
The code isn’t long since BGP has a well-defined static header structure to wrap its private messages.
if (packet->payload_packet_len > 18 && get_u64(packet->payload, 0) == 0xffffffffffffffffULL && get_u64(packet->payload, 8) == 0xffffffffffffffffULL &&
BGP starts off with 128 enabled bits. The header is at least 19 bytes long. Great work so far!
ntohs(get_u16(packet->payload, 16)) <= packet->payload_packet_len && (packet->tcp->dest == htons(179) || packet->tcp->source == htons(179)) &&
The message length is pulled from the packet and tested against the actual segment length present in the packet. It is verified that the header length is included in the message length. And then port numbers, really? Although it’s a good indicator of BGP, port numbers should be the very last resort in modern DPI code. Last bit is interesting for the message type:
packet->payload[18] < 5) {
Message types defined are 1 to 4 plus an additional 5, so the test fails to address that zero is not a valid type and forgets about 5 completely. But I liked the effort -- the RFCs have been consulted to some degree.
Just a Little Further Please
So the goals for me would be to better visualise the BGP header (via a struct), change the program flow (more if directives don't hurt), and to properly validate the message types. All input is welcome. Use the comment functionality below...
LI_DESCRIBE_APP(bgp) { struct bgp { uint32_t marker[4]; uint16_t msg_length; uint8_t msg_type; } __packed *ptr = (void *)packet->app.raw; if (packet->app_len < sizeof(struct bgp)) { return (0); } if (memcmp(ptr->marker, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", sizeof(ptr->marker))) { /* marker is filled with ones */ return (0); } if (be16dec(&ptr->msg_length) < sizeof(struct bgp)) { /* total length must include header length */ return (0); } switch (ptr->msg_type) { case 1: /* Open RFC 4271 */ case 2: /* Update RFC 4271 */ case 3: /* Notification RFC 4271 */ case 4: /* KeepAlive RFC 4271 */ case 5: /* RouteRefresh RFC 2918 */ break; default: /* not a known type */ return (0); } return (1); }