diff --git a/src/source-pcap-file-helper.c b/src/source-pcap-file-helper.c index 1c9f5933b..afecaddbf 100644 --- a/src/source-pcap-file-helper.c +++ b/src/source-pcap-file-helper.c @@ -193,6 +193,137 @@ static bool PeekFirstPacketTimestamp(PcapFileFileVars *pfv) return true; } +TmEcode RunPcapOverIP(PcapFileFileVars *pfv) +{ + char errbuf[PCAP_ERRBUF_SIZE] = ""; + int sockfd; + struct sockaddr_in server_addr; + FILE *file; + char *ip = NULL; + int port = 0; + + if(unlikely(pfv->filename == NULL)) { + SCLogError("Filename was null"); + SCReturnInt(TM_ECODE_FAILED); + } + + // Parse the filename to extract IP and port + if (strncmp(pfv->filename, "TCP@", 4) == 0) { + char *ip_port = pfv->filename + 4; // Skip "TCP@" + char *colon = strchr(ip_port, ':'); + if (colon) { + *colon = '\0'; // Temporarily null-terminate the IP + ip = strdup(ip_port); + port = atoi(colon + 1); + *colon = ':'; // Restore the colon + } + } + + if (!ip || port == 0) { + SCLogError("Invalid filename format. Expected TCP@ip:port"); + free(ip); + SCReturnInt(TM_ECODE_FAILED); + } + + SCLogInfo("Connecting to %s on port %d", ip, port); + + while (1) { // Outer loop to keep reconnecting + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + SCLogError("socket failed: %s", strerror(errno)); + goto next; + } + + // Initialize server address struct + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + if (inet_pton(AF_INET, ip, &server_addr.sin_addr) <= 0) { + SCLogError("inet_pton failed: %s", strerror(errno)); + goto next_close_sock; + } + + // Connect to the server + if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + SCLogError("connect failed: %s", strerror(errno)); + goto next_close_sock; + } + + + SCLogInfo("Connected to server %s on port %d.", ip, port); + + file = fdopen(sockfd, "r"); + if (file == NULL) { + SCLogError("fdopen failed: %s", strerror(errno)); + goto next_close_sock; + } + + pfv->pcap_handle = pcap_fopen_offline(file, errbuf); + if (pfv->pcap_handle == NULL) { + SCLogError("%s", errbuf); + fclose(file); + goto next_close_sock; + } + + if (pfv->shared != NULL && pfv->shared->bpf_string != NULL) { + SCLogInfo("using bpf-filter \"%s\"", pfv->shared->bpf_string); + + if (pcap_compile(pfv->pcap_handle, &pfv->filter, pfv->shared->bpf_string, 1, 0) < 0) { + SCLogError("bpf compilation error %s for %s", pcap_geterr(pfv->pcap_handle), + pfv->filename); + + pcap_close(pfv->pcap_handle); + close(sockfd); + SCReturnInt(TM_ECODE_FAILED); + } + + if (pcap_setfilter(pfv->pcap_handle, &pfv->filter) < 0) { + SCLogError("could not set bpf filter %s for %s", pcap_geterr(pfv->pcap_handle), + pfv->filename); + pcap_freecode(&pfv->filter); + + pcap_close(pfv->pcap_handle); + close(sockfd); + SCReturnInt(TM_ECODE_FAILED); + } + pcap_freecode(&pfv->filter); + } + + pfv->datalink = pcap_datalink(pfv->pcap_handle); + SCLogDebug("datalink %" PRId32 "", pfv->datalink); + DatalinkSetGlobalType(pfv->datalink); + + if (!PeekFirstPacketTimestamp(pfv)) + SCReturnInt(TM_ECODE_FAILED); + + DecoderFunc UnusedFnPtr; + TmEcode validated = ValidateLinkType(pfv->datalink, &UnusedFnPtr); + if (validated != TM_ECODE_OK) + SCReturnInt(validated); + + TmEcode result = PcapFileDispatch(pfv); + + pcap_close(pfv->pcap_handle); + + if (result == TM_ECODE_FAILED) { + SCLogError("PcapFileDispatch failed"); + SCReturnInt(TM_ECODE_FAILED); + } + + SCLogInfo("Finished processing. Waiting 5 seconds before reconnecting..."); + + // file is already closed by closing the handle no need for fclose + next_close_sock: + close(sockfd); + next: + sleep(5); + } + + // This point should never be reached due to the infinite loop + SCReturnInt(TM_ECODE_OK); +} + + TmEcode InitPcapFile(PcapFileFileVars *pfv) { char errbuf[PCAP_ERRBUF_SIZE] = ""; diff --git a/src/source-pcap-file-helper.h b/src/source-pcap-file-helper.h index 2de7d16cc..4a23d2ac1 100644 --- a/src/source-pcap-file-helper.h +++ b/src/source-pcap-file-helper.h @@ -97,6 +97,8 @@ typedef struct PcapFileFileVars_ */ TmEcode PcapFileDispatch(PcapFileFileVars *ptv); +TmEcode RunPcapOverIP(PcapFileFileVars *pfv); + /** * From a PcapFileFileVars, prepare the filename for processing by setting * pcap_handle, datalink, and filter diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index 4492f4698..819ec2dbe 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -201,8 +201,13 @@ TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot) TmThreadsSetFlag(tv, THV_RUNNING); if(ptv->is_directory == 0) { - SCLogInfo("Starting file run for %s", ptv->behavior.file->filename); - status = PcapFileDispatch(ptv->behavior.file); + char* pcap_overip_prefix = "TCP@"; + if (!strncmp(ptv->behavior.file->filename, pcap_overip_prefix, 4)) { + RunPcapOverIP(ptv->behavior.file); + } else { + SCLogInfo("Starting file run for %s", ptv->behavior.file->filename); + status = PcapFileDispatch(ptv->behavior.file); + } CleanupPcapFileFromThreadVars(ptv, ptv->behavior.file); } else { SCLogInfo("Starting directory run for %s", ptv->behavior.directory->filename); @@ -264,7 +269,30 @@ TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, const void *initdata, void **d if (ConfGetBool("pcap-file.delete-when-done", &should_delete) == 1) { ptv->shared.should_delete = should_delete == 1; } + char* pcap_overip_prefix = "TCP@"; + if (!strncmp(initdata, pcap_overip_prefix, 4)) { + SCLogDebug("argument %s was a file", (char *)initdata); + const size_t toalloc = sizeof(PcapFileFileVars) + pcap_g.read_buffer_size; + PcapFileFileVars *pv = SCCalloc(1, toalloc); + if (unlikely(pv == NULL)) { + SCLogError("Failed to allocate file vars"); + CleanupPcapFileThreadVars(ptv); + SCReturnInt(TM_ECODE_OK); + } + pv->filename = SCStrdup((char *)initdata); + if (unlikely(pv->filename == NULL)) { + SCLogError("Failed to allocate filename"); + CleanupPcapFileFileVars(pv); + CleanupPcapFileThreadVars(ptv); + SCReturnInt(TM_ECODE_OK); + } + + pv->shared = &ptv->shared; + ptv->is_directory = 0; + ptv->behavior.file = pv; + goto NEXT_CHECK; + } DIR *directory = NULL; SCLogDebug("checking file or directory %s", (char*)initdata); if(PcapDetermineDirectoryOrFile((char *)initdata, &directory) == TM_ECODE_FAILED) { @@ -371,7 +399,7 @@ TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, const void *initdata, void **d ptv->is_directory = 1; ptv->behavior.directory = pv; } - + NEXT_CHECK: if (ConfGet("pcap-file.checksum-checks", &tmpstring) != 1) { pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_AUTO; } else { diff --git a/src/suricata.c b/src/suricata.c index 293df00b2..ca75c771e 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -1957,11 +1957,11 @@ TmEcode SCParseCommandLine(int argc, char **argv) PrintUsage(argv[0]); return TM_ECODE_FAILED; } - SCStat buf; - if (SCStatFn(optarg, &buf) != 0) { - SCLogError("pcap file '%s': %s", optarg, strerror(errno)); - return TM_ECODE_FAILED; - } + // SCStat buf; + // if (SCStatFn(optarg, &buf) != 0) { + // SCLogError("pcap file '%s': %s", optarg, strerror(errno)); + // return TM_ECODE_FAILED; + // } if (ConfSetFinal("pcap-file.file", optarg) != 1) { SCLogError("ERROR: Failed to set pcap-file.file\n"); return TM_ECODE_FAILED;