Add pcap_io object which represent pcap io API to simplify and make more transparent pcap access.
Signed-off-by: Vadim Kochan <vadi...@gmail.com> --- pcap_io.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pcap_io.h | 143 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 333 insertions(+) create mode 100644 pcap_io.c diff --git a/pcap_io.c b/pcap_io.c new file mode 100644 index 0000000..b82792a --- /dev/null +++ b/pcap_io.c @@ -0,0 +1,190 @@ +/* + * netsniff-ng - the packet sniffing beast + * Subject to the GPL, version 2. + */ + +#define _GNU_SOURCE + +#include <fcntl.h> +#include <sys/stat.h> + +#include "bpf.h" +#include "pcap_io.h" +#include "xmalloc.h" + +void pcap_io_init(struct pcap_io *io, enum pcap_ops_groups ops_type) +{ + io->ops = pcap_ops[ops_type]; + io->ops_type = ops_type; + io->bpf_ops = NULL; + io->jumbo = false; + io->truncated = 0; + io->path = NULL; + io->fd = -1; + + bug_on(!io->ops); +} + +void pcap_io_open(struct pcap_io *io, const char *path, enum pcap_mode mode) +{ + if (mode == PCAP_MODE_RD) { + if (!strncmp("-", path, strlen("-"))) { + io->fd = dup_or_die(fileno(stdin)); + close(fileno(stdin)); + + if (io->ops_type == PCAP_OPS_MM) + pcap_io_init(io, PCAP_OPS_SG); + } else { + io->fd = open(path, O_RDONLY | O_LARGEFILE | O_NOATIME); + if (io->fd < 0 && errno == EPERM) + io->fd = open_or_die(path, O_RDONLY | O_LARGEFILE); + } + } else if (mode == PCAP_MODE_WR) { + if (!strncmp("-", path, strlen("-"))) { + io->fd = dup_or_die(fileno(stdout)); + close(fileno(stdout)); + + if (io->ops_type == PCAP_OPS_MM) + pcap_io_init(io, PCAP_OPS_SG); + } else { + io->fd = open_or_die_m(path, O_RDWR | O_CREAT | O_TRUNC | + O_LARGEFILE, DEFFILEMODE); + } + } else { + bug(); + } + + if (io->fd < 0) + panic("pcap_io: Cannot open file %s! %s.\n", path, strerror(errno)); + + if (io->ops->init_once_pcap) + io->ops->init_once_pcap(io->enforce_prio); + + io->path = path; + io->mode = mode; +} + +static int pcap_io_prepare_access(struct pcap_io *io) +{ + int ret; + + if (io->ops->prepare_access_pcap) { + ret = io->ops->prepare_access_pcap(io->fd, io->mode, io->jumbo); + if (ret) { + fprintf(stderr, "pcap_io: Error prepare %s pcap!\n", + io->mode == PCAP_MODE_RD ? "reading" : "writing"); + + return ret; + } + } + + return 0; +} + +void pcap_io_header_copy(struct pcap_io *to, struct pcap_io *from) +{ + to->link_type = from->link_type; + to->magic = from->magic; +} + +int pcap_io_header_read(struct pcap_io *io) +{ + int ret; + + ret = io->ops->pull_fhdr_pcap(io->fd, &io->magic, &io->link_type); + if (ret) { + fprintf(stderr, "pcap_io: Error reading pcap header!\n"); + return ret; + } + + return pcap_io_prepare_access(io); +} + +int pcap_io_header_write(struct pcap_io *io) +{ + int ret; + + ret = io->ops->push_fhdr_pcap(io->fd, io->magic, io->link_type); + if (ret) { + fprintf(stderr, "pcap_io: Error writing pcap header!\n"); + return ret; + } + + return pcap_io_prepare_access(io); +} + +int pcap_io_packet_read(struct pcap_io *io, struct pcap_packet *pkt) +{ + int ret; + + do { + ret = io->ops->read_pcap(io->fd, &pkt->phdr, io->magic, + pkt->buf, pkt->buf_len); + if (unlikely(ret < 0)) { + return 0; + } + if (unlikely(pcap_packet_len_get(pkt) == 0)) { + pkt->io->truncated++; + continue; + } + if (unlikely(pcap_packet_len_get(pkt) > pkt->buf_len)) { + pcap_packet_len_set(pkt, pkt->buf_len); + pkt->io->truncated++; + } + } while (io->bpf_ops && + !bpf_run_filter(io->bpf_ops, pkt->buf, + pcap_packet_len_get(pkt))); + + return ret; +} + +int pcap_io_packet_write(struct pcap_io *io, struct pcap_packet *pkt) +{ + size_t pcap_len = pcap_get_length(&pkt->phdr, io->magic); + uint32_t len = io->ops->write_pcap(io->fd, &pkt->phdr, io->magic, + pkt->buf, pcap_len); + + if (unlikely(len != pcap_get_total_length(&pkt->phdr, io->magic))) + return -1; + + return 0; +} + +void pcap_io_close(struct pcap_io *io) +{ + if (io->fd >= 0) { + if (io->mode == PCAP_MODE_WR) + io->ops->fsync_pcap(io->fd); + + if (io->ops->prepare_close_pcap) + io->ops->prepare_close_pcap(io->fd, io->mode); + + if (!strncmp("-", io->path, strlen("-"))) + dup2(io->fd, fileno(stdin)); + + } +} + +struct pcap_packet *pcap_packet_alloc(struct pcap_io *io) +{ + struct pcap_packet *pkt = xzmalloc(sizeof(*io)); + + pkt->io = io; + return pkt; +} + +void pcap_packet_free(struct pcap_packet *pkt) +{ + if (pkt->is_buf_alloc) + xfree(pkt->buf); + + xfree(pkt); +} + +void pcap_packet_buf_alloc(struct pcap_packet *pkt, uint32_t len) +{ + pkt->buf = xmalloc_aligned(len, CO_CACHE_LINE_SIZE); + pkt->buf_len = len; + + pkt->is_buf_alloc = true; +} diff --git a/pcap_io.h b/pcap_io.h index 4e41362..0026361 100644 --- a/pcap_io.h +++ b/pcap_io.h @@ -17,6 +17,7 @@ #include <linux/if.h> #include <linux/if_packet.h> #include <linux/if_arp.h> +#include <linux/filter.h> #include "built_in.h" #include "die.h" @@ -164,6 +165,31 @@ struct pcap_file_ops { void (*fsync_pcap)(int fd); }; +struct pcap_io { + uint32_t link_type; + uint32_t magic; + + const struct pcap_file_ops *ops; + enum pcap_ops_groups ops_type; + enum pcap_type type; + enum pcap_mode mode; + const char *path; + bool enforce_prio; + bool jumbo; + int fd; + + struct sock_fprog *bpf_ops; + uint64_t truncated; +}; + +struct pcap_packet { + pcap_pkthdr_t phdr; + struct pcap_io *io; + bool is_buf_alloc; + uint32_t buf_len; + uint8_t *buf; +}; + extern const struct pcap_file_ops pcap_rw_ops __maybe_unused; extern const struct pcap_file_ops pcap_sg_ops __maybe_unused; extern const struct pcap_file_ops pcap_mm_ops __maybe_unused; @@ -896,4 +922,121 @@ static int pcap_generic_push_fhdr(int fd, uint32_t magic, uint32_t linktype) return 0; } +extern void pcap_io_init(struct pcap_io *io, enum pcap_ops_groups ops_type); +extern void pcap_io_open(struct pcap_io *io, const char *path, enum pcap_mode mode); +extern void pcap_io_header_copy(struct pcap_io *to, struct pcap_io *from); +extern int pcap_io_header_read(struct pcap_io *io); +extern int pcap_io_header_write(struct pcap_io *io); +extern int pcap_io_packet_read(struct pcap_io *io, struct pcap_packet *pk); +extern int pcap_io_packet_write(struct pcap_io *io, struct pcap_packet *pkt); +extern void pcap_io_close(struct pcap_io *io); + +extern struct pcap_packet *pcap_packet_alloc(struct pcap_io *io); +extern void pcap_packet_free(struct pcap_packet *pkt); +extern void pcap_packet_buf_alloc(struct pcap_packet *pkt, uint32_t len); + +static inline uint32_t pcap_packet_len_get(struct pcap_packet *pkt) +{ + return pcap_get_length(&pkt->phdr, pkt->io->magic); +} + +static inline void pcap_packet_len_set(struct pcap_packet *pkt, uint32_t len) +{ + pcap_set_length(&pkt->phdr, pkt->io->magic, len); +} + +static inline uint32_t pcap_io_pcap_type_get(struct pcap_io *io) +{ + return io->magic; +} + +static inline void pcap_io_pcap_type_set(struct pcap_io *io, uint32_t type) +{ + io->magic = type; +} + +static inline uint32_t pcap_io_link_type_get(struct pcap_io *io) +{ + return io->link_type; +} + +static inline void pcap_io_link_type_set(struct pcap_io *io, uint32_t link_type) +{ + io->link_type = link_type; +} + +static inline void pcap_io_enforce_prio_set(struct pcap_io *io, bool enforce) +{ + io->enforce_prio = enforce; +} + +static inline void pcap_io_jumbo_enable_set(struct pcap_io *io, bool jumbo) +{ + io->jumbo = jumbo; +} + +static inline void pcap_io_bpf_apply(struct pcap_io *io, struct sock_fprog *bpf) +{ + io->bpf_ops = bpf; +} + +static inline uint64_t pcap_io_truncated_get(struct pcap_io *io) +{ + return io->truncated; +} + +static inline void pcap_packet_buf_set(struct pcap_packet *pkt, uint8_t *buf) +{ + pkt->buf = buf; +} + +static inline uint8_t *pcap_packet_buf_get(struct pcap_packet *pkt) +{ + return pkt->buf; +} + +static inline void pcap_packet_buf_len_set(struct pcap_packet *pkt, uint32_t len) +{ + pkt->buf_len = len; +} + +static inline uint32_t pcap_packet_buf_len_get(struct pcap_packet *pkt) +{ + return pkt->buf_len; +} + +static inline uint8_t *pcap_packet_payload_get(struct pcap_packet *pkt) +{ + return pkt->buf; +} + +static inline pcap_pkthdr_t *pcap_packet_header_get(struct pcap_packet *pkt) +{ + return &pkt->phdr; +} + +static inline void pcap_packet_to_tpacket2(struct pcap_packet *pkt, + struct tpacket2_hdr *thdr, + struct sockaddr_ll *sll) +{ + pcap_pkthdr_to_tpacket_hdr(&pkt->phdr, pkt->io->magic, thdr, sll); +} + +static inline void pcap_packet_from_tpacket2(struct pcap_packet *pkt, + struct tpacket2_hdr *thdr, + struct sockaddr_ll *sll) +{ + tpacket_hdr_to_pcap_pkthdr(thdr, sll, &pkt->phdr, pkt->io->magic); +} + +#ifdef HAVE_TPACKET3 +static inline void pcap_packet_from_tpacket3(struct pcap_packet *pkt, + struct tpacket3_hdr *thdr, + struct sockaddr_ll *sll) + +{ + tpacket3_hdr_to_pcap_pkthdr(thdr, sll, &pkt->phdr, pkt->io->magic); +} +#endif + #endif /* PCAP_IO_H */ -- 2.10.2 -- You received this message because you are subscribed to the Google Groups "netsniff-ng" group. To unsubscribe from this group and stop receiving emails from it, send an email to netsniff-ng+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.