Skip to content

Added HTTP parser example using DPDK #98

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions examples/http-parser/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Define compiler and flags
CC = gcc
CFLAGS += -O3 -g
LDFLAGS += -L$(RTE_LIBRTE_PMD) -lrte_pmd

# Define the executable
EXE = http-parser

# Source file
SRC = main.c

# Build target
all: $(EXE)

$(EXE): $(SRC)
$(CC) $(CFLAGS) -o $@ $(SRC) $(LDFLAGS)

clean:
rm -f $(EXE)
112 changes: 112 additions & 0 deletions examples/http-parser/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# HTTP Message Parser Example Using DPDK

This example demonstrates how to use the **DPDK (Data Plane Development Kit)** packet processing API to parse HTTP messages from network packets. The HTTP parser identifies the request type (e.g., GET, POST), extracts headers, and prints the payload from captured packets.

## Overview

The goal of this project is to create a working example that utilizes **DPDK**'s packet processing capabilities to capture and parse HTTP messages from network traffic.

### Key Features:
- Capture network packets using **libpcap**.
- Parse HTTP messages including the method (GET, POST), headers, and payload.
- Use DPDK's packet processing API to efficiently handle network traffic.

## Prerequisites

Before you begin, ensure you have the following installed:

- **DPDK**: A high-performance packet processing library.
- **libpcap**: A library used for capturing network packets.
- **gcc**: A compiler for building C programs.
- **Make**: A tool for managing the build process.

## Setup Instructions

### Step 1: Install DPDK

To use DPDK, you need to set up the environment and install DPDK on your system.

#### On Linux:

Follow the official DPDK setup instructions:
[DPDK Installation Guide](https://doc.dpdk.org/guides/linux_gsg/index.html)

#### On macOS:

You can use a **Docker** container to run DPDK if it is not supported natively on macOS.

1. **Clone the Docker repository** and build the DPDK environment.

2. **Run the Docker container** with DPDK:
```bash
docker run --rm -it --privileged dpdk-docker
```

### Step 2: Install libpcap

You will need `libpcap` to capture network packets.

#### On Ubuntu/Debian-based systems:
```bash
sudo apt-get install libpcap-dev
```

#### On macOS (using Homebrew):
```bash
brew install libpcap
```

### Step 3: Clone the Repository

Clone the repository containing the HTTP parser example:

```bash
git clone https://github.com/Brijitha1609/dpdk.git
cd dpdk
```

### Step 4: Build the Project

1. **Install dependencies** (on Linux-based systems):
```bash
sudo apt-get update
sudo apt-get install build-essential libnuma-dev meson ninja-build
```

2. **Compile the program**:
```bash
make
```

Alternatively, if you are using `meson`:
```bash
meson build
ninja -C build
```

### Step 5: Run the HTTP Parser

1. **Prepare your network interface** to capture packets (you may need root privileges).

2. **Run the HTTP parser**:
```bash
sudo ./main
```

The program will start capturing network packets from the network interface (default `en0` in the code) and parse HTTP messages from the captured packets.

Example output:
```
Using device: en0
HTTP Method: GET
Headers:
Host: example.com
User-Agent: curl/7.64.1
Payload: <Request Payload Here>
```

## Troubleshooting

- **Permission Issues**: Ensure you have permission to capture packets on the network interface. You may need to run the program as `sudo` or grant your user the necessary permissions.
- **DPDK Environment Errors**: Ensure that the environment variables (`RTE_SDK`, `RTE_TARGET`) are correctly configured. Follow the DPDK setup guide for more details.

Binary file added examples/http-parser/main
Binary file not shown.
105 changes: 105 additions & 0 deletions examples/http-parser/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#include <pcap.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <net/ethernet.h> // Correct header for macOS

// Function to handle the captured packet
void packet_handler(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) {
// Ethernet header
struct ether_header *eth_header = (struct ether_header*) packet;

// Check if the packet is an IP packet (Ethernet Type is 0x0800 for IP)
if (ntohs(eth_header->ether_type) != ETHERTYPE_IP) {
printf("Not an IP packet\n");
return;
}

// IP header
struct ip *ip_header = (struct ip*)(packet + sizeof(struct ether_header));

// Check if the packet is a TCP packet (IP protocol number 6 for TCP)
if (ip_header->ip_p != IPPROTO_TCP) {
printf("Not a TCP packet\n");
return;
}

// TCP header
struct tcphdr *tcp_header = (struct tcphdr*)(packet + sizeof(struct ether_header) + sizeof(struct ip));

// Source and destination IP addresses
char src_ip[INET_ADDRSTRLEN];
char dst_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(ip_header->ip_src), src_ip, INET_ADDRSTRLEN);
inet_ntop(AF_INET, &(ip_header->ip_dst), dst_ip, INET_ADDRSTRLEN);

// Source and destination TCP ports
uint16_t src_port = ntohs(tcp_header->th_sport);
uint16_t dst_port = ntohs(tcp_header->th_dport);

// Display basic info about the packet
printf("Captured packet from IP: %s to IP: %s\n", src_ip, dst_ip);
printf("TCP Src Port: %d, Dst Port: %d\n", src_port, dst_port);

// If it's an HTTP packet (we assume port 80 for HTTP)
if (dst_port == 80 || src_port == 80) {
printf("This is an HTTP packet!\n");

// Optionally, parse the TCP payload for HTTP content
const u_char *http_payload = packet + sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct tcphdr);
int payload_len = header->len - (http_payload - packet);

// Try to print first few bytes of the HTTP message (for example)
printf("HTTP Payload (First 50 bytes):\n");
for (int i = 0; i < 50 && i < payload_len; i++) {
printf("%c", http_payload[i]);
}
printf("\n\n");
}
}

// Main function
int main(int argc, char *argv[]) {
pcap_if_t *alldevs;
pcap_if_t *device;
pcap_t *handle;
char errbuf[PCAP_ERRBUF_SIZE];

// Get the list of all devices
if (pcap_findalldevs(&alldevs, errbuf) == -1) {
fprintf(stderr, "Error finding devices: %s\n", errbuf);
return 1;
}

// Choose the first device for simplicity
device = alldevs;
printf("Using device: %s\n", device->name);

// Open the device for capturing
handle = pcap_open_live(device->name, BUFSIZ, 1, 1000, errbuf);
if (handle == NULL) {
fprintf(stderr, "Couldn't open device %s: %s\n", device->name, errbuf);
return 2;
}

// Set a filter to capture only TCP packets on port 80 or 443 (HTTP/HTTPS)
struct bpf_program fp;
if (pcap_compile(handle, &fp, "tcp port 80 or tcp port 443", 0, PCAP_NETMASK_UNKNOWN) == -1) {
fprintf(stderr, "Could not parse filter\n");
return 2;
}
if (pcap_setfilter(handle, &fp) == -1) {
fprintf(stderr, "Could not install filter\n");
return 2;
}

// Start capturing packets (capturing 10 packets for demonstration)
pcap_loop(handle, 10, packet_handler, NULL);

// Cleanup
pcap_close(handle);
pcap_freealldevs(alldevs);
return 0;
}
7 changes: 7 additions & 0 deletions examples/http-parser/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
project('http-parser', 'c')

# Find DPDK library
rte_lib = cc.find_library('rte_pmd', dirs: '/usr/local/lib')

# Define the executable
executable('http-parser', 'main.c', dependencies: rte_lib)
45 changes: 45 additions & 0 deletions examples/http-parser/test-http.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const http = require('http');
const https = require('https');
const url = require('url');

// Create an HTTP server to send test HTTP requests
const sendHttpRequest = (hostname, port, path, method) => {
const options = {
hostname: hostname,
port: port,
path: path,
method: method,
headers: {
'User-Agent': 'Node.js HTTP Test Client',
'Content-Type': 'application/json'
}
};

const req = http.request(options, (res) => {
console.log(`HTTP Response: ${res.statusCode} ${res.statusMessage}`);
res.on('data', (chunk) => {
console.log(`Body: ${chunk}`);
});
});

req.on('error', (error) => {
console.error(`Error: ${error}`);
});

req.end();
};

// Test HTTP requests (adjust the IP and port based on your setup)
const testUrl = 'localhost'; // DPDK application is listening on localhost
const testPort = 80; // Standard HTTP port

const testRequests = [
{ method: 'GET', path: '/' },
{ method: 'POST', path: '/test' },
{ method: 'GET', path: '/about' },
];

// Send test HTTP requests
testRequests.forEach(({ method, path }) => {
sendHttpRequest(testUrl, testPort, path, method);
});