Compare commits

...

3 Commits

Author SHA1 Message Date
alex18_huang
e3ce9c10e3 Ensure qdisc is created on each interface
Signed-off-by: alex18_huang <alex18_huang@accton.com>
2025-04-10 14:30:45 +08:00
alex18_huang
cecb75e621 1. Explicitly specify the priority of tc ingress rule installed by udhcpinject to 32 (higher than dhcp-relay)
2. Delete tc ingress rule of priority 32 on reload
 3. Don't delete ingress qdisc on reload

Signed-off-by: alex18_huang <alex18_huang@accton.com>
2025-04-09 14:10:02 +08:00
alex18_huang
8767714457 WIFI-14018: Allow option 82 DHCP fields to be transparently injected into client DHCP requests
1. Added userspace application udhcpinject to inject DHCP option 82 transparently
      2. Added README.md for example usage

Signed-off-by: alex18_huang <alex18_huang@accton.com>

	new file:   feeds/ucentral/udhcpinject/Makefile
	new file:   feeds/ucentral/udhcpinject/README.md
	new file:   feeds/ucentral/udhcpinject/files/etc/config/dhcpinject
	new file:   feeds/ucentral/udhcpinject/files/etc/init.d/dhcpinject
	new file:   feeds/ucentral/udhcpinject/src/Makefile
	new file:   feeds/ucentral/udhcpinject/src/udhcpinject.c
	new file:   feeds/ucentral/udhcpinject/src/udhcpinject.h
2025-04-08 16:38:11 +08:00
7 changed files with 916 additions and 0 deletions

View File

@@ -0,0 +1,44 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=udhcpinject
PKG_VERSION:=1.0
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
define Package/udhcpinject
SECTION:=net
CATEGORY:=Network
TITLE:=An agent to inject DHCP option
DEPENDS:=+libpcap +kmod-ifb +tc
MAINTAINER:=kmk <alex18_huang@accton.com>
endef
define Package/udhcpinject/description
A utility to insert DHCP option 82 transparently into DHCP Discover packets.
The format is as follows:
Option 82: (82) Agent Information
Option: (1) Agent Circuit ID
Agent Circuit ID: BSSID:ESSID
Option: (2) Agent Remote ID
Agent Remote ID: AP Hostname
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Package/udhcpinject/conffiles
/etc/config/dhcpinject
endef
define Package/udhcpinject/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/udhcpinject $(1)/usr/bin/
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,udhcpinject))

View File

@@ -0,0 +1,107 @@
# DHCP Option82 injector
inject DHCP option 82 transparently on TIP AP
## Format
```
Option 82: (82) Agent Information
Option: (1) Agent Circuit ID
Agent Circuit ID: BSSID:ESSID
Option: (2) Agent Remote ID
Agent Remote ID: AP Hostname
```
## Usage
add "dhcpinject" under ssid->services
```json
{
"interfaces": [
{
"ethernet": [
{
"select-ports": [
"WAN*"
]
}
],
"ipv4": {
"addressing": "dynamic"
},
"name": "WAN",
"role": "upstream",
"services": [
"ssh",
"lldp",
"dhcp-snooping",
"http"
],
"ssids": [
{
"bss-mode": "ap",
"encryption": {
"ieee80211w": "optional",
"key": "ERC981206",
"proto": "psk2"
},
"name": "EAP101-ERICHI",
"services": [
"wifi-frames",
"dhcpinject" <-- devices connected to this ssid will trigger this application
],
"wifi-bands": [
"2G",
"5G"
]
},
{
"bss-mode": "ap",
"encryption": {
"ieee80211w": "optional",
"key": "AKH981016",
"proto": "psk2"
},
"name": "EAP101-AKIHO",
"services": [
"wifi-frames", <-- devices connected to this ssid will NOT trigger this application
],
"wifi-bands": [
"2G",
"5G"
]
},
{
"bss-mode": "ap",
"encryption": {
"ieee80211w": "optional",
"key": "DMY971128",
"proto": "psk2"
},
"name": "EAP101-DAMAYU",
"services": [
"wifi-frames",
"dhcpinject" <-- devices connected to this ssid will trigger this application
],
"wifi-bands": [
"2G"
]
}
]
}
],
"services": {
"dhcp-inject": {
"select-ports": [
"WAN*" <-- Will fallback to eth0 if no ports are provided
]
}
}
}
```
## Workflow
Suppose SSID EAP101-ERICHI binds to iface wlan0
- Application read SSIDs and uplink ports from env variable `$SSIDs` and `$PORTs` (generated by script `/etc/init.d/udhcpinject`)
- Apply `tc` on `wlan0` to redirect DHCP Discover/Request to iface `ifb-inject`
- Application listen on interface `ifb-inject` for incoming DHCP packets
- On packets arrive, application identify the src interface by vlan tag and insert corresponding attribute
- Forward packet to up0v0

View File

@@ -0,0 +1,7 @@
# config device 'uplink'
# list port 'eth0'
#
# config ssids 'ssids'
# list ssid 'EAP101-ERICHI'
# list ssid 'EAP101-AKIHO'
# list ssid 'EAP101-DAMAYU'

View File

@@ -0,0 +1,73 @@
#!/bin/sh /etc/rc.common
USE_PROCD=1
START=95
STOP=10
SERVICE_NAME="dhcpinject"
PROG=/usr/bin/udhcpinject
start_service() {
local ssid_list=""
local ssids=""
local ports=""
# Function to process each ssid
append_ssid() {
local value="$1"
if [ -n "$ssids" ]; then
ssids="$ssids,$value"
else
ssids="$value"
fi
}
append_port() {
local value="$1"
if [ -n "$ports" ]; then
ports="$ports,$value"
else
ports="$value"
fi
}
# Load the dhcpinject config
config_load dhcpinject
# Get the list of SSIDs
config_list_foreach ssids ssid append_ssid
# Get the list of ports
config_list_foreach uplink port append_port
# Fallback to eth0 if no ports are specified
if [ -z "$ports" ]; then
ports="eth0"
fi
# Optional: Log or echo for debugging
logger -t dhcp_inject "Generated SSIDs=$ssids, Uplink=$ports"
procd_open_instance "$SERVICE_NAME"
procd_set_param command $PROG
procd_set_param env SSIDs="$ssids" PORTs="$ports"
procd_set_param respawn 3600 10 10
procd_set_param file /etc/config/dhcpinject
procd_set_param reload_signal SIGHUP
procd_close_instance
}
stop_service() {
procd_kill $SERVICE_NAME
}
reload_service() {
procd_send_signal $SERVICE_NAME
}
restart_service() {
stop
sleep 1
start
}

View File

@@ -0,0 +1,16 @@
include $(TOPDIR)/rules.mk
TARGET_CFLAGS += -Wall
obj-y := udhcpinject.o
all: udhcpinject
udhcpinject: $(obj-y)
$(CC) $(LDFLAGS) -lpcap -o $@ $(obj-y)
%.o: %.c
$(CC) $(CFLAGS) $(TARGET_CFLAGS) -c $< -o $@
clean:
rm -f *.o udhcpinject

View File

@@ -0,0 +1,623 @@
#include <arpa/inet.h>
#include <errno.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <net/if.h>
#include <netinet/in.h>
#include <pcap.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <syslog.h>
#include <unistd.h>
#include "udhcpinject.h"
#define MAX_INTERFACES 48
#define MAX_PORTS 8
// Global variables
struct iface_info *iface_map = NULL;
static struct port_info *ports = NULL;
int iface_count = 0;
int port_count = 0;
static pcap_t *handle = NULL;
static char *provided_ssids = NULL;
static char *provided_ports = NULL;
// Function to cleanup tc rules
void cleanup_tc() {
char cmd[1024];
for (int i = 0; i < iface_count; i++) {
snprintf(cmd, sizeof(cmd), "tc filter del dev %s ingress 2>/dev/null",
iface_map[i].iface);
system(cmd);
snprintf(cmd, sizeof(cmd), "tc qdisc del dev %s ingress 2>/dev/null",
iface_map[i].iface);
system(cmd);
}
}
// Cleanup function
void cleanup() {
syslog(LOG_INFO, "Cleaning up resources...\n");
cleanup_tc();
if (handle) {
pcap_close(handle);
handle = NULL;
}
if (ports) {
for (int i = 0; i < port_count; i++) {
if (ports[i].sock >= 0) {
close(ports[i].sock);
}
}
free(ports);
ports = NULL;
port_count = 0;
}
if (iface_map) {
free(iface_map);
iface_map = NULL;
iface_count = 0;
}
if (provided_ssids) {
free(provided_ssids);
provided_ssids = NULL;
}
if (provided_ports) {
free(provided_ports);
provided_ports = NULL;
}
syslog(LOG_INFO, "Cleanup complete.\n");
}
// Function to parse SSIDs and populate iface_map
int parse_ssids(const char *ssids) {
if (iface_map) {
free(iface_map);
iface_map = NULL;
iface_count = 0;
}
// Create a set of provided SSIDs for efficient lookup
char ssids_copy[256];
strncpy(ssids_copy, ssids, sizeof(ssids_copy) - 1);
ssids_copy[sizeof(ssids_copy) - 1] = '\0';
// Count number of SSIDs for allocation
int ssid_count = 1; // Start at 1 for first SSID
for (int i = 0; ssids_copy[i]; i++) {
if (ssids_copy[i] == ',')
ssid_count++;
}
char **ssid_set = malloc(ssid_count * sizeof(char *));
if (!ssid_set) {
syslog(LOG_ERR, "Failed to allocate memory for SSID set\n");
return -1;
}
int ssid_idx = 0;
char *token = strtok(ssids_copy, ",");
while (token) {
ssid_set[ssid_idx++] = token;
token = strtok(NULL, ",");
}
// Execute iwinfo command and capture output
FILE *pipe = popen("iwinfo | grep wlan -A1 | grep -v \"^--\" | tr -d '\"' "
"| awk '/wlan/ {name=$1; essid=$3} /Access Point/ "
"{print name \"=\" essid \",\" $3}' | tr -d ':'",
"r");
if (!pipe) {
syslog(LOG_ERR, "Failed to execute iwinfo command\n");
free(ssid_set);
return -1;
}
char line[256];
while (fgets(line, sizeof(line), pipe) != NULL) {
// Remove trailing newline
line[strcspn(line, "\n")] = 0;
// Parse line format: wlanX=SSID,BSSID
char *iface = strtok(line, "=");
char *rest = strtok(NULL, "=");
if (!iface || !rest)
continue;
char *essid = strtok(rest, ",");
char *bssid = strtok(NULL, ",");
if (!essid || !bssid)
continue;
// Check if this SSID is in our provided set
int match = 0;
for (int i = 0; i < ssid_idx; i++) {
if (strcmp(essid, ssid_set[i]) == 0) {
match = 1;
break;
}
}
if (!match)
continue;
// Add matching interface to iface_map
if (iface_count >= MAX_INTERFACES) {
syslog(LOG_ERR, "Too many matching interfaces, max is %d\n",
MAX_INTERFACES);
pclose(pipe);
free(ssid_set);
return -1;
}
iface_map =
realloc(iface_map, (iface_count + 1) * sizeof(struct iface_info));
if (!iface_map) {
syslog(LOG_ERR, "Failed to reallocate iface_map\n");
pclose(pipe);
free(ssid_set);
return -1;
}
struct iface_info *info = &iface_map[iface_count];
info->serial = iface_count + 1;
strncpy(info->iface, iface, LEN_IFACE);
info->iface[LEN_IFACE] = '\0';
strncpy(info->essid, essid, LEN_ESSID);
info->essid[LEN_ESSID] = '\0';
strncpy(info->bssid, bssid, LEN_BSSID);
info->bssid[LEN_BSSID] = '\0';
iface_count++;
}
int pipe_status = pclose(pipe);
if (pipe_status == -1) {
syslog(LOG_ERR, "Error closing iwinfo pipe: %s\n", strerror(errno));
}
free(ssid_set);
if (iface_count == 0) {
syslog(LOG_ERR, "No matching interfaces found for provided SSIDs\n");
return -1;
}
syslog(LOG_INFO, "Found %d matching interfaces\n", iface_count);
return 0;
}
int parse_ports(const char *port_list) {
if (ports) {
for (int i = 0; i < port_count; i++) {
if (ports[i].sock >= 0) {
close(ports[i].sock);
}
}
free(ports);
ports = NULL;
port_count = 0;
}
char ports_copy[256];
strncpy(ports_copy, port_list, sizeof(ports_copy) - 1);
ports_copy[sizeof(ports_copy) - 1] = '\0';
port_count = 1;
for (int i = 0; ports_copy[i]; i++) {
if (ports_copy[i] == ',') {
port_count++;
}
}
if (port_count > MAX_PORTS) {
syslog(LOG_ERR, "Too many ports specified, maximum is %d\n", MAX_PORTS);
return -1;
}
ports = calloc(port_count, sizeof(struct port_info));
if (!ports) {
syslog(LOG_ERR, "Failed to allocate memory for ports\n");
return -1;
}
char *token = strtok(ports_copy, ",");
int idx = 0;
while (token && idx < port_count) {
strncpy(ports[idx].name, token, LEN_IFACE);
ports[idx].name[LEN_IFACE] = '\0';
ports[idx].sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (ports[idx].sock < 0) {
syslog(LOG_ERR, "Socket creation failed for %s: %s\n",
ports[idx].name, strerror(errno));
return -1;
}
ports[idx].ifindex = if_nametoindex(ports[idx].name);
if (ports[idx].ifindex == 0) {
syslog(LOG_ERR, "Failed to get interface index for %s: %s\n",
ports[idx].name, strerror(errno));
return -1;
}
token = strtok(NULL, ",");
idx++;
}
syslog(LOG_INFO, "Configured %d ports for forwarding\n", port_count);
return 0;
}
// Function to setup tc rules (same as before but using iface_map)
int setup_tc() {
char cmd[1024];
snprintf(cmd, sizeof(cmd), "ip link show ifb-inject >/dev/null 2>&1");
if (system(cmd) != 0) {
snprintf(cmd, sizeof(cmd),
"ip link add name ifb-inject type ifb && ip link set "
"ifb-inject up");
if (system(cmd) != 0) {
syslog(LOG_ERR, "Failed to setup ifb-inject\n");
return -1;
}
}
for (int i = 0; i < iface_count; i++) {
snprintf(cmd, sizeof(cmd), "tc qdisc add dev %s ingress 2>/dev/null 1>2",
iface_map[i].iface);
int result = system(cmd);
if (result == 2) {
syslog(LOG_INFO, "Ingress qdisc already exists for %s on %s\n", iface_map[i].essid, iface_map[i].iface);
}
else if (result == 1) {
syslog(LOG_INFO, "Failed to add ingress qdisc for %s on %s\n", iface_map[i].essid, iface_map[i].iface);
}
snprintf(cmd, sizeof(cmd),
"tc filter add dev %s ingress protocol ip u32 "
"match ip protocol 17 0xff "
"match u16 0x0044 0xffff at 20 "
"match u16 0x0043 0xffff at 22 "
"match u8 0x01 0xff at 28 "
"action vlan push id %d pipe "
"action mirred egress mirror dev ifb-inject pipe "
"action drop",
iface_map[i].iface, iface_map[i].serial);
if (system(cmd) != 0) {
syslog(LOG_ERR, "Failed to setup tc for %s\n", iface_map[i].iface);
return -1;
}
}
return 0;
}
// Signal handler
void signal_handler(int sig) {
if (sig == SIGTERM) {
syslog(LOG_INFO, "Received SIGTERM, cleaning up...\n");
cleanup();
exit(0);
} else if (sig == SIGHUP) {
syslog(LOG_INFO, "Received reload signal, reconfiguring...\n");
sleep(5);
// Clean up existing resources
cleanup_tc();
// Free old SSIDs and get new ones
if (provided_ssids) {
free(provided_ssids);
}
provided_ssids = getenv("SSIDs");
if (!provided_ssids) {
syslog(LOG_ERR, "No SSIDs provided on reload\n");
return;
}
// Reload SSIDs
if (parse_ssids(provided_ssids) != 0) {
syslog(LOG_ERR, "Failed to reload SSIDs configuration\n");
return;
}
// Free old ports and get new ones
if (provided_ports) {
free(provided_ports);
}
provided_ports = getenv("PORTs");
if (!provided_ports) {
syslog(LOG_ERR, "No PORTs provided on reload\n");
return;
}
// Close existing sockets and reopen with new config
if (ports) {
for (int i = 0; i < port_count; i++) {
if (ports[i].sock >= 0) {
close(ports[i].sock);
}
}
free(ports);
ports = NULL;
port_count = 0;
}
// Reload ports
if (parse_ports(provided_ports) != 0) {
syslog(LOG_ERR, "Failed to reload ports configuration\n");
return;
}
// Reapply tc rules
if (setup_tc() == 0) {
syslog(LOG_INFO, "Reloaded with SSIDs: %s and Ports: %s\n",
provided_ssids, provided_ports);
} else {
syslog(LOG_ERR, "Failed to reload tc configuration\n");
}
}
}
char *get_hostname() {
static char hostname[256];
if (gethostname(hostname, sizeof(hostname)) != 0) {
strcpy(hostname, "unknown");
}
return hostname;
}
struct iface_info *find_iface_info_by_vlan(int vlan_id) {
for (int i = 0; i < iface_count; i++) {
if (iface_map[i].serial == vlan_id) {
return &iface_map[i];
}
}
return NULL;
}
void process_packet(unsigned char *user, const struct pcap_pkthdr *header,
const unsigned char *packet) {
int orig_len = header->len;
struct ethhdr *eth = (struct ethhdr *)packet;
int vlan_id = -1;
int eth_offset = sizeof(struct ethhdr);
if (ntohs(eth->h_proto) != ETH_P_8021Q) {
syslog(LOG_DEBUG,
"No VLAN header found in packet (EtherType: 0x%04x)\n",
ntohs(eth->h_proto));
return;
}
struct vlan_hdr *vlan = (struct vlan_hdr *)(packet + eth_offset);
vlan_id = ntohs(vlan->h_vlan_TCI) & 0x0FFF;
eth_offset += sizeof(struct vlan_hdr);
struct iface_info *info = find_iface_info_by_vlan(vlan_id);
if (!info) {
syslog(LOG_ERR, "No interface info found for VLAN ID %d\n", vlan_id);
return;
}
char *hostname = get_hostname();
int circuit_id_len = strlen(info->bssid) + 1 + strlen(info->essid);
int remote_id_len = strlen(hostname);
int opt82_len = 2 + 2 + circuit_id_len + 2 + remote_id_len;
// Find DHCP options end from the end of the packet
int ip_offset = eth_offset;
struct iphdr *ip = (struct iphdr *)(packet + ip_offset);
int udp_offset = ip_offset + (ip->ihl * 4);
struct udphdr *udp = (struct udphdr *)(packet + udp_offset);
int dhcp_offset = udp_offset + sizeof(struct udphdr);
unsigned char *dhcp_start = (unsigned char *)(packet + dhcp_offset);
int dhcp_len = ntohs(udp->len) - sizeof(struct udphdr);
int options_end = -1;
for (int i = dhcp_len - 1; i >= 0; i--) {
if (dhcp_start[i] == 0xFF) { // End option
options_end = i;
break;
}
}
if (options_end == -1) {
syslog(LOG_DEBUG, "Could not find DHCP options end tag\n");
return;
}
// Calculate new packet size: remove VLAN (-4), remove end tag (-1), add
// Option 82, add end tag (+1)
int orig_options_len = options_end;
int new_len = orig_len - 4 - 1 + opt82_len + 1;
unsigned char *new_packet = malloc(new_len);
if (!new_packet) {
syslog(LOG_ERR, "Failed to allocate memory for new packet\n");
return;
}
// Copy Ethernet header
struct ethhdr *new_eth = (struct ethhdr *)new_packet;
memcpy(new_eth, eth, sizeof(struct ethhdr));
new_eth->h_proto = vlan->h_vlan_encapsulated_proto;
// Copy IP header
struct iphdr *new_ip = (struct iphdr *)(new_packet + sizeof(struct ethhdr));
memcpy(new_ip, ip, ip->ihl * 4);
// Copy UDP header
struct udphdr *new_udp =
(struct udphdr *)(new_packet + sizeof(struct ethhdr) + (ip->ihl * 4));
memcpy(new_udp, udp, sizeof(struct udphdr));
// Copy DHCP payload up to options end, add Option 82, add end tag
unsigned char *new_dhcp =
(unsigned char *)(new_packet + sizeof(struct ethhdr) + (ip->ihl * 4) +
sizeof(struct udphdr));
memcpy(new_dhcp, dhcp_start, orig_options_len);
// Add Option 82
int opt82_offset = orig_options_len;
new_dhcp[opt82_offset++] = 82; // Option code
new_dhcp[opt82_offset++] = opt82_len - 2; // Option length
// Sub-option 1: Circuit ID (BSSID:ESSID)
new_dhcp[opt82_offset++] = 1; // Sub-option code
new_dhcp[opt82_offset++] = circuit_id_len; // Sub-option length
memcpy(new_dhcp + opt82_offset, info->bssid, strlen(info->bssid));
opt82_offset += strlen(info->bssid);
new_dhcp[opt82_offset++] = ':';
memcpy(new_dhcp + opt82_offset, info->essid, strlen(info->essid));
opt82_offset += strlen(info->essid);
// Sub-option 2: Remote ID (hostname)
new_dhcp[opt82_offset++] = 2; // Sub-option code
new_dhcp[opt82_offset++] = remote_id_len;
memcpy(new_dhcp + opt82_offset, hostname, remote_id_len);
opt82_offset += remote_id_len;
// Add end tag
new_dhcp[opt82_offset++] = 0xFF;
// Update lengths
new_ip->tot_len = htons(ntohs(ip->tot_len) + opt82_len);
new_udp->len = htons(ntohs(udp->len) + opt82_len);
// Recalculate IP checksum
new_ip->check = 0;
unsigned int sum = 0;
unsigned short *ip_ptr = (unsigned short *)new_ip;
for (int i = 0; i < ip->ihl * 2; i++) {
sum += *ip_ptr++;
}
while (sum >> 16) {
sum = (sum & 0xFFFF) + (sum >> 16);
}
new_ip->check = ~sum;
// Recalculate UDP checksum
new_udp->check = 0;
sum = 0;
// Pseudo-header
sum +=
(ntohs(new_ip->saddr) & 0xFFFF) + (ntohs(new_ip->saddr >> 16) & 0xFFFF);
sum +=
(ntohs(new_ip->daddr) & 0xFFFF) + (ntohs(new_ip->daddr >> 16) & 0xFFFF);
sum += htons(IPPROTO_UDP);
sum += new_udp->len;
// UDP header and data
unsigned char *udp_start = (unsigned char *)new_udp;
int udp_total_len = ntohs(new_udp->len);
unsigned short *udp_ptr = (unsigned short *)udp_start;
for (int i = 0; i < udp_total_len / 2; i++) {
sum += *udp_ptr++;
}
if (udp_total_len % 2) {
sum += *(unsigned char *)udp_ptr;
}
while (sum >> 16) {
sum = (sum & 0xFFFF) + (sum >> 16);
}
new_udp->check = ~sum;
if (new_udp->check == 0)
new_udp->check = 0xFFFF;
// Send the packet
struct sockaddr_ll socket_address = {0};
socket_address.sll_family = AF_PACKET;
socket_address.sll_protocol = htons(ETH_P_ALL);
for (int i = 0; i < port_count; i++) {
socket_address.sll_ifindex = ports[i].ifindex;
if (sendto(ports[i].sock, new_packet, new_len, 0,
(struct sockaddr *)&socket_address,
sizeof(socket_address)) < 0) {
syslog(LOG_ERR, "Failed to send packet to %s: %s\n",
ports[i].name, strerror(errno));
} else {
syslog(LOG_DEBUG,
"Successfully forwarded packet to %s (new length: %d)\n",
ports[i].name, new_len);
}
}
free(new_packet);
}
int main(int argc, char *argv[]) {
openlog("dhcp_inject:", LOG_PID | LOG_CONS, LOG_DAEMON);
signal(SIGTERM, signal_handler);
signal(SIGHUP, signal_handler);
provided_ssids = getenv("SSIDs");
syslog(LOG_INFO, "Provided SSIDs: %s\n", provided_ssids);
if (!provided_ssids && argc > 1) {
provided_ssids = strdup(argv[1]);
}
if (!provided_ssids) {
syslog(LOG_ERR, "No SSIDs provided. Exiting...\n");
return 1;
}
provided_ports = getenv("PORTs");
syslog(LOG_INFO, "Provided PORTs: %s\n", provided_ports);
if (!provided_ports) {
syslog(LOG_ERR, "No PORTs provided. Exiting...\n");
cleanup();
return 1;
}
sleep(5);
if (parse_ssids(provided_ssids) != 0) {
syslog(LOG_ERR, "Failed to parse SSIDs\n");
cleanup();
return 1;
}
if (parse_ports(provided_ports) != 0) {
syslog(LOG_ERR, "Failed to parse ports\n");
cleanup();
return 1;
}
if (setup_tc() != 0) {
syslog(LOG_ERR, "Setup failed\n");
cleanup();
return 1;
}
syslog(LOG_INFO, "Setup complete for SSIDs: %s and Ports: %s\n",
provided_ssids, provided_ports);
char errbuf[PCAP_ERRBUF_SIZE];
handle = pcap_open_live("ifb-inject", BUFSIZ, 1, 1000, errbuf);
if (handle == NULL) {
syslog(LOG_ERR, "Couldn't open device ifb-inject: %s\n", errbuf);
cleanup();
return 1;
}
if (pcap_loop(handle, -1, process_packet, NULL) < 0) {
syslog(LOG_ERR, "pcap_loop failed: %s\n", pcap_geterr(handle));
cleanup();
return 1;
}
cleanup();
return 0;
}

View File

@@ -0,0 +1,46 @@
#include <stdint.h>
#include <netinet/in.h>
#define LEN_ESSID 32
#define LEN_BSSID 12
#define LEN_IFACE 15
// DHCP header structure
struct dhcp_packet {
uint8_t op;
uint8_t htype;
uint8_t hlen;
uint8_t hops;
uint32_t xid;
uint16_t secs;
uint16_t flags;
struct in_addr ciaddr;
struct in_addr yiaddr;
struct in_addr siaddr;
struct in_addr giaddr;
uint8_t chaddr[16];
char sname[64];
char file[128];
uint32_t magic;
uint8_t options[];
};
// Structure to hold interface info
struct iface_info {
char iface[LEN_IFACE + 1];
char essid[LEN_ESSID + 1];
char bssid[LEN_BSSID + 1];
int serial;
};
struct port_info {
char name[LEN_IFACE + 1];
int sock;
int ifindex;
};
// VLAN header structure
struct vlan_hdr {
__be16 h_vlan_TCI; // VLAN Tag Control Information
__be16 h_vlan_encapsulated_proto; // Encapsulated protocol
};