Commit 8177cdb1 authored by Bertrone Matteo's avatar Bertrone Matteo

http filter example

parent b0950589
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
Write an eBPF application that parses HTTP packets and extracts (and prints on screen) the URL contained in the GET/POST request. Write an eBPF application that parses HTTP packets and extracts (and prints on screen) the URL contained in the GET/POST request.
[https://github.com/netgroup-polito/ebpf-test](https://github.com/netgroup-polito/ebpf-test) [eBPF HTTP Filter - Short Presentation](https://github.com/iovisor/bpf-docs/blob/master/ebpf_http_filter.pdf)
[Original Projct](https://github.com/netgroup-polito/ebpf-test)
#Usage Example #Usage Example
...@@ -27,13 +28,12 @@ Matching packets are forwarded to user space, others dropped by the filter.<br / ...@@ -27,13 +28,12 @@ Matching packets are forwarded to user space, others dropped by the filter.<br /
<br /> <br />
Python script reads filtered raw packets from the socket, if necessary reassembles packets belonging to the same session, and prints on stdout the first line of the HTTP GET/POST request. <br /> Python script reads filtered raw packets from the socket, if necessary reassembles packets belonging to the same session, and prints on stdout the first line of the HTTP GET/POST request. <br />
# Usage #v1 vs v2
Require: First version is the simple one: if the url is too long (splitted in more than one packet) is truncated.
- BPF Compiler Collection [BCC](https://github.com/iovisor/bcc) Second version is quite more complex: if necessary reassembles packets belonging to the same session and prints the complete url.
- Follow [INSTALL](https://github.com/iovisor/bcc/blob/master/INSTALL.md) guide
# To run: #To run:
```Shell ```Shell
$ sudo python http-parse.py $ sudo python http-parse.py
......
...@@ -39,7 +39,7 @@ int http_filter(struct __sk_buff *skb) { ...@@ -39,7 +39,7 @@ int http_filter(struct __sk_buff *skb) {
struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet)); struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
//filter IP packets (ethernet type = 0x0800) //filter IP packets (ethernet type = 0x0800)
if (!(ethernet->type == 0x0800)){ if (!(ethernet->type == 0x0800)) {
goto DROP; goto DROP;
} }
...@@ -75,58 +75,58 @@ int http_filter(struct __sk_buff *skb) { ...@@ -75,58 +75,58 @@ int http_filter(struct __sk_buff *skb) {
//e.g. tcp->offset = 5 ; TCP Header Length = 5 x 4 byte = 20 byte //e.g. tcp->offset = 5 ; TCP Header Length = 5 x 4 byte = 20 byte
tcp_header_length = tcp->offset << 2; //SHL 2 -> *4 multiply tcp_header_length = tcp->offset << 2; //SHL 2 -> *4 multiply
//calculate patload offset and lenght //calculate patload offset and length
payload_offset = ETH_HLEN + ip_header_length + tcp_header_length; payload_offset = ETH_HLEN + ip_header_length + tcp_header_length;
payload_length = ip->tlen - ip_header_length - tcp_header_length; payload_length = ip->tlen - ip_header_length - tcp_header_length;
//http://stackoverflow.com/questions/25047905/http-request-minimum-size-in-bytes //http://stackoverflow.com/questions/25047905/http-request-minimum-size-in-bytes
//minimum lenght of http request is always geater than 7 bytes //minimum length of http request is always geater than 7 bytes
//avoid invalid access memory //avoid invalid access memory
//include empty payload //include empty payload
if(payload_length < 7){ if(payload_length < 7) {
goto DROP; goto DROP;
} }
//load firt 7 byte of payload into payload_array //load firt 7 byte of payload into p (payload_array)
//direct access to skb not allowed //direct access to skb not allowed
unsigned long payload_array[7]; unsigned long p[7];
int i = 0; int i = 0;
int j = 0; int j = 0;
for (i = payload_offset ; i < (payload_offset + 7) ; i++){ for (i = payload_offset ; i < (payload_offset + 7) ; i++) {
payload_array[j] = load_byte(skb , i); p[j] = load_byte(skb , i);
j++; j++;
} }
//find a match with an HTTP message //find a match with an HTTP message
//HTTP //HTTP
if ( (payload_array[0] == 'H') && (payload_array[1] == 'T') && (payload_array[2] == 'T') && (payload_array[3] == 'P')){ if ((p[0] == 'H') && (p[1] == 'T') && (p[2] == 'T') && (p[3] == 'P')) {
goto HTTP_MATCH; goto HTTP_MATCH;
} }
//GET //GET
if ( (payload_array[0] == 'G') && (payload_array[1] == 'E') && (payload_array[2] == 'T') ){ if ((p[0] == 'G') && (p[1] == 'E') && (p[2] == 'T')) {
goto HTTP_MATCH; goto HTTP_MATCH;
} }
//POST //POST
if ( (payload_array[0] == 'P') && (payload_array[1] == 'O') && (payload_array[2] == 'S') && (payload_array[3] == 'T')){ if ((p[0] == 'P') && (p[1] == 'O') && (p[2] == 'S') && (p[3] == 'T')) {
goto HTTP_MATCH; goto HTTP_MATCH;
} }
//PUT //PUT
if ( (payload_array[0] == 'P') && (payload_array[1] == 'U') && (payload_array[2] == 'T') ){ if ((p[0] == 'P') && (p[1] == 'U') && (p[2] == 'T')) {
goto HTTP_MATCH; goto HTTP_MATCH;
} }
//DELETE //DELETE
if ( (payload_array[0] == 'D') && (payload_array[1] == 'E') && (payload_array[2] == 'L') && (payload_array[3] == 'E') && (payload_array[4] == 'T') && (payload_array[5] == 'E')){ if ((p[0] == 'D') && (p[1] == 'E') && (p[2] == 'L') && (p[3] == 'E') && (p[4] == 'T') && (p[5] == 'E')) {
goto HTTP_MATCH; goto HTTP_MATCH;
} }
//HEAD //HEAD
if ( (payload_array[0] == 'H') && (payload_array[1] == 'E') && (payload_array[2] == 'A') && (payload_array[3] == 'D')){ if ((p[0] == 'H') && (p[1] == 'E') && (p[2] == 'A') && (p[3] == 'D')) {
goto HTTP_MATCH; goto HTTP_MATCH;
} }
//no HTTP match //no HTTP match
//check if packet belong to an HTTP session //check if packet belong to an HTTP session
struct Leaf * lookup_leaf = sessions.lookup(&key); struct Leaf * lookup_leaf = sessions.lookup(&key);
if(lookup_leaf){ if(lookup_leaf) {
//send packet to userspace //send packet to userspace
goto KEEP; goto KEEP;
} }
......
...@@ -109,7 +109,7 @@ local_dictionary = {} ...@@ -109,7 +109,7 @@ local_dictionary = {}
while 1: while 1:
#retrieve raw packet from socket #retrieve raw packet from socket
packet_str = os.read(socket_fd,4096) #set packet lenght to max packet lenght on the interface packet_str = os.read(socket_fd,4096) #set packet length to max packet length on the interface
packet_count += 1 packet_count += 1
#DEBUG - print raw packet in hex format #DEBUG - print raw packet in hex format
...@@ -133,18 +133,18 @@ while 1: ...@@ -133,18 +133,18 @@ while 1:
#value to multiply * 4 byte #value to multiply * 4 byte
#e.g. IHL = 5 ; IP Header Length = 5 * 4 byte = 20 byte #e.g. IHL = 5 ; IP Header Length = 5 * 4 byte = 20 byte
# #
#Total Lenght: This 16-bit field defines the entire packet size, #Total length: This 16-bit field defines the entire packet size,
#including header and data, in bytes. #including header and data, in bytes.
#calculate packet total lenght #calculate packet total length
total_lenght = packet_bytearray[ETH_HLEN + 2] #load MSB total_length = packet_bytearray[ETH_HLEN + 2] #load MSB
total_lenght = total_lenght << 8 #shift MSB total_length = total_length << 8 #shift MSB
total_lenght = total_lenght + packet_bytearray[ETH_HLEN+3] #add LSB total_length = total_length + packet_bytearray[ETH_HLEN+3] #add LSB
#calculate ip header lenght #calculate ip header length
ip_header_length = packet_bytearray[ETH_HLEN] #load Byte ip_header_length = packet_bytearray[ETH_HLEN] #load Byte
ip_header_length = ip_header_length & 0x0F #mask bits 0..3 ip_header_length = ip_header_length & 0x0F #mask bits 0..3
ip_header_length = ip_header_length << 2 #shift to obtain lenght ip_header_length = ip_header_length << 2 #shift to obtain length
#retrieve ip source/dest #retrieve ip source/dest
ip_src_str = packet_str[ETH_HLEN+12:ETH_HLEN+16] #ip source offset 12..15 ip_src_str = packet_str[ETH_HLEN+12:ETH_HLEN+16] #ip source offset 12..15
...@@ -168,10 +168,10 @@ while 1: ...@@ -168,10 +168,10 @@ while 1:
#value to multiply * 4 byte #value to multiply * 4 byte
#e.g. DataOffset = 5 ; TCP Header Length = 5 * 4 byte = 20 byte #e.g. DataOffset = 5 ; TCP Header Length = 5 * 4 byte = 20 byte
#calculate tcp header lenght #calculate tcp header length
tcp_header_lenght = packet_bytearray[ETH_HLEN + ip_header_length + 12] #load Byte tcp_header_length = packet_bytearray[ETH_HLEN + ip_header_length + 12] #load Byte
tcp_header_lenght = tcp_header_lenght & 0xF0 #mask bit 4..7 tcp_header_length = tcp_header_length & 0xF0 #mask bit 4..7
tcp_header_lenght = tcp_header_lenght >> 2 #SHR 4 ; SHL 2 -> SHR 2 tcp_header_length = tcp_header_length >> 2 #SHR 4 ; SHL 2 -> SHR 2
#retrieve port source/dest #retrieve port source/dest
port_src_str = packet_str[ETH_HLEN+ip_header_length:ETH_HLEN+ip_header_length+2] port_src_str = packet_str[ETH_HLEN+ip_header_length:ETH_HLEN+ip_header_length+2]
...@@ -181,7 +181,7 @@ while 1: ...@@ -181,7 +181,7 @@ while 1:
port_dst = int(toHex(port_dst_str),16) port_dst = int(toHex(port_dst_str),16)
#calculate payload offset #calculate payload offset
payload_offset = ETH_HLEN + ip_header_length + tcp_header_lenght payload_offset = ETH_HLEN + ip_header_length + tcp_header_length
#payload_string contains only packet payload #payload_string contains only packet payload
payload_string = packet_str[(payload_offset):(len(packet_bytearray))] payload_string = packet_str[(payload_offset):(len(packet_bytearray))]
......
...@@ -19,7 +19,7 @@ int http_filter(struct __sk_buff *skb) { ...@@ -19,7 +19,7 @@ int http_filter(struct __sk_buff *skb) {
struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet)); struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
//filter IP packets (ethernet type = 0x0800) //filter IP packets (ethernet type = 0x0800)
if (!(ethernet->type == 0x0800)){ if (!(ethernet->type == 0x0800)) {
goto DROP; goto DROP;
} }
...@@ -46,51 +46,51 @@ int http_filter(struct __sk_buff *skb) { ...@@ -46,51 +46,51 @@ int http_filter(struct __sk_buff *skb) {
//e.g. tcp->offset = 5 ; TCP Header Length = 5 x 4 byte = 20 byte //e.g. tcp->offset = 5 ; TCP Header Length = 5 x 4 byte = 20 byte
tcp_header_length = tcp->offset << 2; //SHL 2 -> *4 multiply tcp_header_length = tcp->offset << 2; //SHL 2 -> *4 multiply
//calculate patload offset and lenght //calculate patload offset and length
payload_offset = ETH_HLEN + ip_header_length + tcp_header_length; payload_offset = ETH_HLEN + ip_header_length + tcp_header_length;
payload_length = ip->tlen - ip_header_length - tcp_header_length; payload_length = ip->tlen - ip_header_length - tcp_header_length;
//http://stackoverflow.com/questions/25047905/http-request-minimum-size-in-bytes //http://stackoverflow.com/questions/25047905/http-request-minimum-size-in-bytes
//minimum lenght of http request is always geater than 7 bytes //minimum length of http request is always geater than 7 bytes
//avoid invalid access memory //avoid invalid access memory
//include empty payload //include empty payload
if(payload_length < 7){ if(payload_length < 7) {
goto DROP; goto DROP;
} }
//load firt 7 byte of payload into payload_array //load firt 7 byte of payload into p (payload_array)
//direct access to skb not allowed //direct access to skb not allowed
unsigned long payload_array[7]; unsigned long p[7];
int i = 0; int i = 0;
int j = 0; int j = 0;
for (i = payload_offset ; i < (payload_offset + 7) ; i++){ for (i = payload_offset ; i < (payload_offset + 7) ; i++) {
payload_array[j] = load_byte(skb , i); p[j] = load_byte(skb , i);
j++; j++;
} }
//find a match with an HTTP message //find a match with an HTTP message
//HTTP //HTTP
if ( (payload_array[0] == 'H') && (payload_array[1] == 'T') && (payload_array[2] == 'T') && (payload_array[3] == 'P')){ if ((p[0] == 'H') && (p[1] == 'T') && (p[2] == 'T') && (p[3] == 'P')) {
goto KEEP; goto KEEP;
} }
//GET //GET
if ( (payload_array[0] == 'G') && (payload_array[1] == 'E') && (payload_array[2] == 'T') ){ if ((p[0] == 'G') && (p[1] == 'E') && (p[2] == 'T')) {
goto KEEP; goto KEEP;
} }
//POST //POST
if ( (payload_array[0] == 'P') && (payload_array[1] == 'O') && (payload_array[2] == 'S') && (payload_array[3] == 'T')){ if ((p[0] == 'P') && (p[1] == 'O') && (p[2] == 'S') && (p[3] == 'T')) {
goto KEEP; goto KEEP;
} }
//PUT //PUT
if ( (payload_array[0] == 'P') && (payload_array[1] == 'U') && (payload_array[2] == 'T') ){ if ((p[0] == 'P') && (p[1] == 'U') && (p[2] == 'T')) {
goto KEEP; goto KEEP;
} }
//DELETE //DELETE
if ( (payload_array[0] == 'D') && (payload_array[1] == 'E') && (payload_array[2] == 'L') && (payload_array[3] == 'E') && (payload_array[4] == 'T') && (payload_array[5] == 'E')){ if ((p[0] == 'D') && (p[1] == 'E') && (p[2] == 'L') && (p[3] == 'E') && (p[4] == 'T') && (p[5] == 'E')) {
goto KEEP; goto KEEP;
} }
//HEAD //HEAD
if ( (payload_array[0] == 'H') && (payload_array[1] == 'E') && (payload_array[2] == 'A') && (payload_array[3] == 'D')){ if ((p[0] == 'H') && (p[1] == 'E') && (p[2] == 'A') && (p[3] == 'D')) {
goto KEEP; goto KEEP;
} }
...@@ -105,4 +105,4 @@ int http_filter(struct __sk_buff *skb) { ...@@ -105,4 +105,4 @@ int http_filter(struct __sk_buff *skb) {
DROP: DROP:
return 0; return 0;
} }
\ No newline at end of file
...@@ -64,18 +64,18 @@ while 1: ...@@ -64,18 +64,18 @@ while 1:
#value to multiply * 4 byte #value to multiply * 4 byte
#e.g. IHL = 5 ; IP Header Length = 5 * 4 byte = 20 byte #e.g. IHL = 5 ; IP Header Length = 5 * 4 byte = 20 byte
# #
#Total Lenght: This 16-bit field defines the entire packet size, #Total length: This 16-bit field defines the entire packet size,
#including header and data, in bytes. #including header and data, in bytes.
#calculate packet total lenght #calculate packet total length
total_lenght = packet_bytearray[ETH_HLEN + 2] #load MSB total_length = packet_bytearray[ETH_HLEN + 2] #load MSB
total_lenght = total_lenght << 8 #shift MSB total_length = total_length << 8 #shift MSB
total_lenght = total_lenght + packet_bytearray[ETH_HLEN+3] #add LSB total_length = total_length + packet_bytearray[ETH_HLEN+3] #add LSB
#calculate ip header lenght #calculate ip header length
ip_header_length = packet_bytearray[ETH_HLEN] #load Byte ip_header_length = packet_bytearray[ETH_HLEN] #load Byte
ip_header_length = ip_header_length & 0x0F #mask bits 0..3 ip_header_length = ip_header_length & 0x0F #mask bits 0..3
ip_header_length = ip_header_length << 2 #shift to obtain lenght ip_header_length = ip_header_length << 2 #shift to obtain length
#TCP HEADER #TCP HEADER
#https://www.rfc-editor.org/rfc/rfc793.txt #https://www.rfc-editor.org/rfc/rfc793.txt
...@@ -92,13 +92,13 @@ while 1: ...@@ -92,13 +92,13 @@ while 1:
#value to multiply * 4 byte #value to multiply * 4 byte
#e.g. DataOffset = 5 ; TCP Header Length = 5 * 4 byte = 20 byte #e.g. DataOffset = 5 ; TCP Header Length = 5 * 4 byte = 20 byte
#calculate tcp header lenght #calculate tcp header length
tcp_header_lenght = packet_bytearray[ETH_HLEN + ip_header_length + 12] #load Byte tcp_header_length = packet_bytearray[ETH_HLEN + ip_header_length + 12] #load Byte
tcp_header_lenght = tcp_header_lenght & 0xF0 #mask bit 4..7 tcp_header_length = tcp_header_length & 0xF0 #mask bit 4..7
tcp_header_lenght = tcp_header_lenght >> 2 #SHR 4 ; SHL 2 -> SHR 2 tcp_header_length = tcp_header_length >> 2 #SHR 4 ; SHL 2 -> SHR 2
#calculate payload offset #calculate payload offset
payload_offset = ETH_HLEN + ip_header_length + tcp_header_lenght payload_offset = ETH_HLEN + ip_header_length + tcp_header_length
#print first line of the HTTP GET/POST request #print first line of the HTTP GET/POST request
#line ends with 0xOD 0xOA (\r\n) #line ends with 0xOD 0xOA (\r\n)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment