Skip to content

Commit

Permalink
http filter example
Browse files Browse the repository at this point in the history
  • Loading branch information
mbertrone committed Feb 6, 2016
1 parent b095058 commit 8177cdb
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 61 deletions.
12 changes: 6 additions & 6 deletions examples/networking/http_filter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

[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

Expand All @@ -27,13 +28,12 @@ Matching packets are forwarded to user space, others dropped by the filter.<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 />

# Usage
#v1 vs v2

Require:
- BPF Compiler Collection [BCC](https://github.com/iovisor/bcc)
- Follow [INSTALL](https://github.com/iovisor/bcc/blob/master/INSTALL.md) guide
First version is the simple one: if the url is too long (splitted in more than one packet) is truncated.
Second version is quite more complex: if necessary reassembles packets belonging to the same session and prints the complete url.

# To run:
#To run:

```Shell
$ sudo python http-parse.py
Expand Down
Binary file not shown.
Binary file not shown.
30 changes: 15 additions & 15 deletions examples/networking/http_filter/http-parse-v2.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ int http_filter(struct __sk_buff *skb) {

struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
//filter IP packets (ethernet type = 0x0800)
if (!(ethernet->type == 0x0800)){
if (!(ethernet->type == 0x0800)) {
goto DROP;
}

Expand Down Expand Up @@ -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
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_length = ip->tlen - ip_header_length - tcp_header_length;

//https://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
//include empty payload
if(payload_length < 7){
if(payload_length < 7) {
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
unsigned long payload_array[7];
unsigned long p[7];
int i = 0;
int j = 0;
for (i = payload_offset ; i < (payload_offset + 7) ; i++){
payload_array[j] = load_byte(skb , i);
for (i = payload_offset ; i < (payload_offset + 7) ; i++) {
p[j] = load_byte(skb , i);
j++;
}

//find a match with an HTTP message
//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;
}
//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;
}
//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;
}
//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;
}
//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;
}
//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;
}

//no HTTP match
//check if packet belong to an HTTP session
struct Leaf * lookup_leaf = sessions.lookup(&key);
if(lookup_leaf){
if(lookup_leaf) {
//send packet to userspace
goto KEEP;
}
Expand Down
26 changes: 13 additions & 13 deletions examples/networking/http_filter/http-parse-v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def cleanup():

while 1:
#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

#DEBUG - print raw packet in hex format
Expand All @@ -133,18 +133,18 @@ def cleanup():
#value to multiply * 4 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.

#calculate packet total lenght
total_lenght = packet_bytearray[ETH_HLEN + 2] #load MSB
total_lenght = total_lenght << 8 #shift MSB
total_lenght = total_lenght + packet_bytearray[ETH_HLEN+3] #add LSB
#calculate packet total length
total_length = packet_bytearray[ETH_HLEN + 2] #load MSB
total_length = total_length << 8 #shift MSB
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 = 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
ip_src_str = packet_str[ETH_HLEN+12:ETH_HLEN+16] #ip source offset 12..15
Expand All @@ -168,10 +168,10 @@ def cleanup():
#value to multiply * 4 byte
#e.g. DataOffset = 5 ; TCP Header Length = 5 * 4 byte = 20 byte

#calculate tcp header lenght
tcp_header_lenght = packet_bytearray[ETH_HLEN + ip_header_length + 12] #load Byte
tcp_header_lenght = tcp_header_lenght & 0xF0 #mask bit 4..7
tcp_header_lenght = tcp_header_lenght >> 2 #SHR 4 ; SHL 2 -> SHR 2
#calculate tcp header length
tcp_header_length = packet_bytearray[ETH_HLEN + ip_header_length + 12] #load Byte
tcp_header_length = tcp_header_length & 0xF0 #mask bit 4..7
tcp_header_length = tcp_header_length >> 2 #SHR 4 ; SHL 2 -> SHR 2

#retrieve port source/dest
port_src_str = packet_str[ETH_HLEN+ip_header_length:ETH_HLEN+ip_header_length+2]
Expand All @@ -181,7 +181,7 @@ def cleanup():
port_dst = int(toHex(port_dst_str),16)

#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 = packet_str[(payload_offset):(len(packet_bytearray))]
Expand Down
30 changes: 15 additions & 15 deletions examples/networking/http_filter/http-parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ int http_filter(struct __sk_buff *skb) {

struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
//filter IP packets (ethernet type = 0x0800)
if (!(ethernet->type == 0x0800)){
if (!(ethernet->type == 0x0800)) {
goto DROP;
}

Expand All @@ -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
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_length = ip->tlen - ip_header_length - tcp_header_length;

//https://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
//include empty payload
if(payload_length < 7){
if(payload_length < 7) {
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
unsigned long payload_array[7];
unsigned long p[7];
int i = 0;
int j = 0;
for (i = payload_offset ; i < (payload_offset + 7) ; i++){
payload_array[j] = load_byte(skb , i);
for (i = payload_offset ; i < (payload_offset + 7) ; i++) {
p[j] = load_byte(skb , i);
j++;
}

//find a match with an HTTP message
//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;
}
//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;
}
//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;
}
//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;
}
//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;
}
//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;
}

Expand All @@ -105,4 +105,4 @@ int http_filter(struct __sk_buff *skb) {
DROP:
return 0;

}
}
24 changes: 12 additions & 12 deletions examples/networking/http_filter/http-parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,18 @@
#value to multiply * 4 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.

#calculate packet total lenght
total_lenght = packet_bytearray[ETH_HLEN + 2] #load MSB
total_lenght = total_lenght << 8 #shift MSB
total_lenght = total_lenght + packet_bytearray[ETH_HLEN+3] #add LSB
#calculate packet total length
total_length = packet_bytearray[ETH_HLEN + 2] #load MSB
total_length = total_length << 8 #shift MSB
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 = 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
#https://www.rfc-editor.org/rfc/rfc793.txt
Expand All @@ -92,13 +92,13 @@
#value to multiply * 4 byte
#e.g. DataOffset = 5 ; TCP Header Length = 5 * 4 byte = 20 byte

#calculate tcp header lenght
tcp_header_lenght = packet_bytearray[ETH_HLEN + ip_header_length + 12] #load Byte
tcp_header_lenght = tcp_header_lenght & 0xF0 #mask bit 4..7
tcp_header_lenght = tcp_header_lenght >> 2 #SHR 4 ; SHL 2 -> SHR 2
#calculate tcp header length
tcp_header_length = packet_bytearray[ETH_HLEN + ip_header_length + 12] #load Byte
tcp_header_length = tcp_header_length & 0xF0 #mask bit 4..7
tcp_header_length = tcp_header_length >> 2 #SHR 4 ; SHL 2 -> SHR 2

#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
#line ends with 0xOD 0xOA (\r\n)
Expand Down

0 comments on commit 8177cdb

Please sign in to comment.