/* * Copyright (c) 2018-2023, OARC, Inc. * All rights reserved. * * This file is part of dnsjit. * * dnsjit is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * dnsjit is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with dnsjit. If not, see . */ #include "config.h" #include "input/mmpcap.h" #include "core/assert.h" #include "core/object/pcap.h" #include #include #include #include #include #include #ifdef HAVE_ENDIAN_H #include #else #ifdef HAVE_SYS_ENDIAN_H #include #else #ifdef HAVE_MACHINE_ENDIAN_H #include #endif #endif #endif #ifdef HAVE_BYTESWAP_H #include #endif #ifndef bswap_16 #ifndef bswap16 #define bswap_16(x) swap16(x) #define bswap_32(x) swap32(x) #define bswap_64(x) swap64(x) #else #define bswap_16(x) bswap16(x) #define bswap_32(x) bswap32(x) #define bswap_64(x) bswap64(x) #endif #endif #include static core_log_t _log = LOG_T_INIT("input.mmpcap"); static input_mmpcap_t _defaults = { LOG_T_INIT_OBJ("input.mmpcap"), 0, 0, 0, 0, 0, CORE_OBJECT_PCAP_INIT(0), -1, 0, 0, 0, MAP_FAILED, 0, 0, 0, 0, 0, 0, 0, 0 }; core_log_t* input_mmpcap_log() { return &_log; } void input_mmpcap_init(input_mmpcap_t* self) { mlassert_self(); *self = _defaults; } void input_mmpcap_destroy(input_mmpcap_t* self) { mlassert_self(); if (self->buf != MAP_FAILED) { munmap(self->buf, self->len); } if (self->fd > -1) { close(self->fd); } } int input_mmpcap_open(input_mmpcap_t* self, const char* file) { struct stat sb; mlassert_self(); lassert(file, "file is nil"); if (self->fd != -1) { lfatal("already opened"); } if ((self->fd = open(file, O_RDONLY)) < 0) { lcritical("open(%s) error %s", file, core_log_errstr(errno)); return -1; } if (fstat(self->fd, &sb)) { lcritical("stat(%s) error %s", file, core_log_errstr(errno)); return -1; } self->len = sb.st_size; if ((self->buf = mmap(0, self->len, PROT_READ, MAP_PRIVATE, self->fd, 0)) == MAP_FAILED) { lcritical("mmap(%s) error %s", file, core_log_errstr(errno)); return -1; } if (self->len < 24) { lcritical("could not read full PCAP header"); return -2; } memcpy(&self->magic_number, self->buf, 4); memcpy(&self->version_major, self->buf + 4, 2); memcpy(&self->version_minor, self->buf + 6, 2); memcpy(&self->thiszone, self->buf + 8, 4); memcpy(&self->sigfigs, self->buf + 12, 4); memcpy(&self->snaplen, self->buf + 16, 4); memcpy(&self->network, self->buf + 20, 4); self->at = 24; switch (self->magic_number) { case 0x4d3cb2a1: self->is_nanosec = 1; case 0xd4c3b2a1: self->is_swapped = 1; self->version_major = bswap_16(self->version_major); self->version_minor = bswap_16(self->version_minor); self->thiszone = (int32_t)bswap_32((uint32_t)self->thiszone); self->sigfigs = bswap_32(self->sigfigs); self->snaplen = bswap_32(self->snaplen); self->network = bswap_32(self->network); break; case 0xa1b2c3d4: case 0xa1b23c4d: break; default: lcritical("invalid PCAP header"); return -2; } if (self->version_major != 2 || self->version_minor != 4) { lcritical("unsupported PCAP version v%u.%u", self->version_major, self->version_minor); return -2; } /* * Translation taken from https://github.com/the-tcpdump-group/libpcap/blob/90543970fd5fbed261d3637f5ec4811d7dde4e49/pcap-common.c#L1212 . */ switch (self->network) { case 101: /* LINKTYPE_RAW */ self->linktype = DLT_RAW; break; #ifdef DLT_FR case 107: /* LINKTYPE_FRELAY */ self->linktype = DLT_FR; break; #endif case 100: /* LINKTYPE_ATM_RFC1483 */ self->linktype = DLT_ATM_RFC1483; break; case 102: /* LINKTYPE_SLIP_BSDOS */ self->linktype = DLT_SLIP_BSDOS; break; case 103: /* LINKTYPE_PPP_BSDOS */ self->linktype = DLT_PPP_BSDOS; break; case 104: /* LINKTYPE_C_HDLC */ self->linktype = DLT_C_HDLC; break; case 106: /* LINKTYPE_ATM_CLIP */ self->linktype = DLT_ATM_CLIP; break; case 50: /* LINKTYPE_PPP_HDLC */ self->linktype = DLT_PPP_SERIAL; break; case 51: /* LINKTYPE_PPP_ETHER */ self->linktype = DLT_PPP_ETHER; break; default: self->linktype = self->network; } self->prod_pkt.snaplen = self->snaplen; self->prod_pkt.linktype = self->linktype; self->prod_pkt.is_swapped = self->is_swapped; ldebug("pcap v%u.%u snaplen:%lu %s", self->version_major, self->version_minor, self->snaplen, self->is_swapped ? " swapped" : ""); return 0; } int input_mmpcap_run(input_mmpcap_t* self) { struct { uint32_t ts_sec; uint32_t ts_usec; uint32_t incl_len; uint32_t orig_len; } hdr; core_object_pcap_t pkt = CORE_OBJECT_PCAP_INIT(0); mlassert_self(); if (self->buf == MAP_FAILED) { lfatal("no PCAP opened"); } if (!self->recv) { lfatal("no receiver set"); } pkt.snaplen = self->snaplen; pkt.linktype = self->linktype; pkt.is_swapped = self->is_swapped; while (self->len - self->at > 16) { memcpy(&hdr, &self->buf[self->at], 16); self->at += 16; if (self->is_swapped) { hdr.ts_sec = bswap_32(hdr.ts_sec); hdr.ts_usec = bswap_32(hdr.ts_usec); hdr.incl_len = bswap_32(hdr.incl_len); hdr.orig_len = bswap_32(hdr.orig_len); } if (hdr.incl_len > self->snaplen) { lwarning("invalid packet length, larger then snaplen"); return -1; } if (self->len - self->at < hdr.incl_len) { lwarning("could not read all of packet, aborting"); return -1; } self->pkts++; pkt.ts.sec = hdr.ts_sec; if (self->is_nanosec) { pkt.ts.nsec = hdr.ts_usec; } else { pkt.ts.nsec = hdr.ts_usec * 1000; } pkt.bytes = (unsigned char*)&self->buf[self->at]; pkt.caplen = hdr.incl_len; pkt.len = hdr.orig_len; self->recv(self->ctx, (core_object_t*)&pkt); self->at += hdr.incl_len; } if (self->at < self->len) { lwarning("could not read next PCAP header, aborting"); return -1; } return 0; } static const core_object_t* _produce(input_mmpcap_t* self) { struct { uint32_t ts_sec; uint32_t ts_usec; uint32_t incl_len; uint32_t orig_len; } hdr; mlassert_self(); if (self->is_broken) { lwarning("PCAP is broken, will not read next packet"); return 0; } if (self->len - self->at < 16) { if (self->at < self->len) { lwarning("could not read next PCAP header, aborting"); self->is_broken = 1; } return 0; } memcpy(&hdr, &self->buf[self->at], 16); self->at += 16; if (self->is_swapped) { hdr.ts_sec = bswap_32(hdr.ts_sec); hdr.ts_usec = bswap_32(hdr.ts_usec); hdr.incl_len = bswap_32(hdr.incl_len); hdr.orig_len = bswap_32(hdr.orig_len); } if (hdr.incl_len > self->snaplen) { lwarning("invalid packet length, larger then snaplen"); self->is_broken = 1; return 0; } if (self->len - self->at < hdr.incl_len) { lwarning("could not read all of packet, aborting"); self->is_broken = 1; return 0; } self->pkts++; self->prod_pkt.ts.sec = hdr.ts_sec; if (self->is_nanosec) { self->prod_pkt.ts.nsec = hdr.ts_usec; } else { self->prod_pkt.ts.nsec = hdr.ts_usec * 1000; } self->prod_pkt.bytes = (unsigned char*)&self->buf[self->at]; self->prod_pkt.caplen = hdr.incl_len; self->prod_pkt.len = hdr.orig_len; self->at += hdr.incl_len; return (core_object_t*)&self->prod_pkt; } core_producer_t input_mmpcap_producer(input_mmpcap_t* self) { mlassert_self(); if (self->buf == MAP_FAILED) { lfatal("no PCAP opened"); } return (core_producer_t)_produce; }