/* * scalpel.c -- USB Virtual Network Tap (Nettap) module * * SPDX-License-Identifier: GPL-2.0-or-later * * USB virtual network tap. Captures IP packets from usb0 via raw * AF_PACKET socket, parses src/dst IPv4 addresses, displays them * on an LVGL console, and coalesces writes to disk via the * flash-safe timed logger. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "h2_ui.h" #include "log_manager.h" #define NUM_WINDOWS 5 #define CONSOLE_MAX_LINES 20 const log_window_t window_durations[NUM_WINDOWS] = { WINDOW_30S, WINDOW_1M, WINDOW_2M, WINDOW_5M, WINDOW_10M }; const char *window_labels[NUM_WINDOWS] = { "30 SECONDS", "1 MINUTE", "2 MINUTES", "5 MINUTES", "10 MINUTES" }; static lv_obj_t *console; static timed_logger_t *logger; static void process_ip_packet(const uint8_t *pkt, ssize_t pkt_len) { uint16_t ethertype = ((uint16_t)pkt[12] << 8) | pkt[13]; if (ethertype != 0x0800) return; if (pkt_len < 34) return; char display_row[64]; snprintf(display_row, sizeof(display_row), "IP: %d.%d.%d.%d -> %d.%d.%d.%d", pkt[26], pkt[27], pkt[28], pkt[29], pkt[30], pkt[31], pkt[32], pkt[33]); char log_row[128]; snprintf(log_row, sizeof(log_row), "[%ld] SIZE:%ld %d.%d.%d.%d->%d.%d.%d.%d\n", (long)time(NULL), (long)pkt_len, pkt[26], pkt[27], pkt[28], pkt[29], pkt[30], pkt[31], pkt[32], pkt[33]); if (logger) timed_log_write(logger, log_row); lv_list_add_text(console, display_row); static int line_count; line_count++; if (line_count > CONSOLE_MAX_LINES) { lv_obj_clean(console); line_count = 0; } } int main(void) { init_h2_graphics_runtime("USB TAP MANAGER NODE"); LOG_INF("nettap module started"); lv_obj_t *scr = lv_scr_act(); lv_obj_t *title = lv_label_create(scr); lv_label_set_text(title, "USB VIRTUAL NETTAP"); lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 10); lv_obj_set_style_text_color(title, COLOR_PRIMARY, LV_PART_MAIN); lv_obj_t *config_card = lv_obj_create(scr); lv_obj_set_size(config_card, 290, 160); lv_obj_align(config_card, LV_ALIGN_CENTER, 0, 15); lv_obj_set_style_bg_color(config_card, lv_color_make(22, 28, 38), LV_PART_MAIN); lv_obj_t *cfg_lbl = lv_label_create(config_card); lv_label_set_text(cfg_lbl, "SET DATA FLUSH TIME WINDOW:"); lv_obj_align(cfg_lbl, LV_ALIGN_TOP_MID, 0, 10); lv_obj_t *window_lbl = lv_label_create(config_card); lv_obj_align(window_lbl, LV_ALIGN_CENTER, 0, -5); lv_obj_set_style_text_color(window_lbl, COLOR_ACCENT, LV_PART_MAIN); int input_fd = open("/dev/input/event0", O_RDONLY | O_NONBLOCK); struct input_event ev; int sel = 1; while (1) { lv_label_set_text(window_lbl, window_labels[sel]); lv_timer_handler(); if (input_fd < 0) { usleep(15000); continue; } if (read(input_fd, &ev, sizeof(struct input_event)) <= 0) { usleep(15000); continue; } if (ev.type == EV_REL && ev.code == 0) { if (ev.value > 0 && sel < NUM_WINDOWS - 1) sel++; if (ev.value < 0 && sel > 0) sel--; } if (ev.type == EV_KEY && ev.value == 1 && ev.code == H2_KEY_PLAY) break; usleep(15000); } logger = timed_log_init("/data/loot_drop/tether_stream.log", window_durations[sel]); lv_obj_del(config_card); console = lv_list_create(scr); lv_obj_set_size(console, 300, 160); lv_obj_align(console, LV_ALIGN_CENTER, 0, 15); int sysfd = open("/sys/class/net/usb0/operstate", O_WRONLY); if (sysfd >= 0) { (void)write(sysfd, "up", 2); close(sysfd); } int sock_raw = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (sock_raw >= 0) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, "usb0", IFNAMSIZ - 1); if (ioctl(sock_raw, SIOCGIFINDEX, &ifr) >= 0) { fcntl(sock_raw, F_SETFL, O_NONBLOCK); lv_obj_t *l = lv_list_add_text(console, "NETTAP ACTIVE: Listening on usb0..."); lv_obj_set_style_text_color(l, COLOR_ACCENT, LV_PART_MAIN); LOG_INF("nettap listening on usb0, flush window: %s", window_labels[sel]); } } uint8_t pkt_buf[2048]; while (1) { lv_timer_handler(); if (sock_raw >= 0) { ssize_t pkt_len = recvfrom(sock_raw, pkt_buf, sizeof(pkt_buf), 0, NULL, NULL); if (pkt_len > 0) process_ip_packet(pkt_buf, pkt_len); } if (logger && (time(NULL) - logger->window_start >= logger->window_duration)) timed_log_flush_to_media(logger); if (input_fd >= 0 && read(input_fd, &ev, sizeof(struct input_event)) > 0) { if (ev.type == EV_KEY && ev.code == H2_KEY_BACK && ev.value == 1) break; } usleep(5000); } if (logger) timed_log_close(logger); if (sock_raw >= 0) close(sock_raw); if (input_fd >= 0) close(input_fd); LOG_INF("nettap module exited"); return 0; }