diff --git a/examples/http-parser/Makefile b/examples/http-parser/Makefile new file mode 100644 index 00000000000..1c67a176c01 --- /dev/null +++ b/examples/http-parser/Makefile @@ -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) diff --git a/examples/http-parser/README.md b/examples/http-parser/README.md new file mode 100644 index 00000000000..d77ee553b36 --- /dev/null +++ b/examples/http-parser/README.md @@ -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: + ``` + +## 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. + diff --git a/examples/http-parser/main b/examples/http-parser/main new file mode 100755 index 00000000000..bebf075b472 Binary files /dev/null and b/examples/http-parser/main differ diff --git a/examples/http-parser/main.c b/examples/http-parser/main.c new file mode 100644 index 00000000000..7efcb4a01dd --- /dev/null +++ b/examples/http-parser/main.c @@ -0,0 +1,105 @@ +#include +#include +#include +#include +#include +#include +#include // 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; +} diff --git a/examples/http-parser/meson.build b/examples/http-parser/meson.build new file mode 100644 index 00000000000..b1609c8dd0a --- /dev/null +++ b/examples/http-parser/meson.build @@ -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) diff --git a/examples/http-parser/test-http.js b/examples/http-parser/test-http.js new file mode 100644 index 00000000000..ddff8b885bb --- /dev/null +++ b/examples/http-parser/test-http.js @@ -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); +});