├── Makefile ├── Makefile.evconnections ├── Makefile.evmerger ├── Makefile.evreader ├── Makefile.test_segments ├── README.md ├── evconnections.cpp ├── evmerger.cpp ├── evreader.cpp ├── fs ├── file.cpp └── file.h ├── html ├── events.css ├── events.html └── events.js ├── memory └── unique_ptr.h ├── net ├── address.h ├── capture │ ├── callbacks.h │ ├── limits.h │ ├── method.h │ ├── ring_buffer.cpp │ ├── ring_buffer.h │ ├── socket.cpp │ └── socket.h ├── limits.h ├── mask.cpp ├── mask.h ├── mon │ ├── configuration.cpp │ ├── configuration.h │ ├── dns │ │ ├── inverted_cache.h │ │ ├── message.cpp │ │ └── message.h │ ├── event │ │ ├── base.cpp │ │ ├── base.h │ │ ├── dns.cpp │ │ ├── dns.h │ │ ├── events.h │ │ ├── file.h │ │ ├── grammar │ │ │ ├── expressions.cpp │ │ │ ├── expressions.h │ │ │ ├── parser.cpp │ │ │ └── parser.h │ │ ├── icmp.cpp │ │ ├── icmp.h │ │ ├── merger.cpp │ │ ├── merger.h │ │ ├── printer │ │ │ ├── base.h │ │ │ ├── csv.h │ │ │ ├── db │ │ │ │ ├── sqlite.cpp │ │ │ │ └── sqlite.h │ │ │ ├── format.h │ │ │ ├── human_readable.h │ │ │ └── json.h │ │ ├── reader.cpp │ │ ├── reader.h │ │ ├── tcp_begin.cpp │ │ ├── tcp_begin.h │ │ ├── tcp_data.cpp │ │ ├── tcp_data.h │ │ ├── tcp_end.cpp │ │ ├── tcp_end.h │ │ ├── udp.cpp │ │ ├── udp.h │ │ ├── util.h │ │ ├── writer.cpp │ │ └── writer.h │ ├── ipv4 │ │ ├── address.h │ │ └── tcp │ │ │ └── connection.h │ ├── ipv6 │ │ ├── address.h │ │ └── tcp │ │ │ └── connection.h │ ├── tcp │ │ ├── connection.cpp │ │ ├── connection.h │ │ ├── connections.h │ │ ├── port_pair.h │ │ ├── segments.cpp │ │ └── segments.h │ ├── worker.cpp │ ├── worker.h │ ├── workers.cpp │ └── workers.h ├── parser.cpp └── parser.h ├── netmon.cpp ├── pcap ├── pcap.h ├── reader.cpp └── reader.h ├── php ├── index.php └── style.css ├── qevents ├── README.md ├── connection.cpp ├── connection.h ├── event.cpp ├── event.h ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui └── qevents.pro ├── string ├── buffer.cpp └── buffer.h ├── test_segments.cpp └── util ├── hash.cpp ├── hash.h ├── node.h └── parser ├── number.cpp ├── number.h ├── size.cpp └── size.h /Makefile: -------------------------------------------------------------------------------- 1 | CC=g++ 2 | CXXFLAGS=-O3 -std=c++11 -Wall -pedantic -D_GNU_SOURCE -I. 3 | 4 | # Is packet mmap version 3 available? 5 | CXXFLAGS+=-DHAVE_TPACKET_V3 6 | 7 | LDFLAGS=-lpthread 8 | 9 | MAKEDEPEND=${CC} -MM 10 | PROGRAM=netmon 11 | 12 | OBJS = string/buffer.o util/hash.o util/parser/number.o util/parser/size.o \ 13 | fs/file.o pcap/reader.o \ 14 | net/parser.o net/mon/event/base.o net/mon/event/icmp.o \ 15 | net/mon/event/udp.o net/mon/event/dns.o net/mon/event/tcp_begin.o \ 16 | net/mon/event/tcp_data.o net/mon/event/tcp_end.o net/mon/event/writer.o \ 17 | net/mon/dns/message.o net/mon/tcp/connection.o net/mon/worker.o \ 18 | net/mon/workers.o net/capture/ring_buffer.o net/capture/socket.o \ 19 | net/mon/configuration.o \ 20 | netmon.o 21 | 22 | DEPS:= ${OBJS:%.o=%.d} 23 | 24 | all: $(PROGRAM) 25 | 26 | ${PROGRAM}: ${OBJS} 27 | ${CC} ${OBJS} ${LIBS} -o $@ ${LDFLAGS} 28 | 29 | clean: 30 | rm -f ${PROGRAM} ${OBJS} ${DEPS} 31 | 32 | ${OBJS} ${DEPS} ${PROGRAM} : Makefile 33 | 34 | .PHONY : all clean 35 | 36 | %.d : %.cpp 37 | ${MAKEDEPEND} ${CXXFLAGS} $< -MT ${@:%.d=%.o} > $@ 38 | 39 | %.o : %.cpp 40 | ${CC} ${CXXFLAGS} -c -o $@ $< 41 | 42 | -include ${DEPS} 43 | -------------------------------------------------------------------------------- /Makefile.evconnections: -------------------------------------------------------------------------------- 1 | CC=g++ 2 | CXXFLAGS=-O3 -std=c++11 -Wall -pedantic -D_GNU_SOURCE -I. 3 | 4 | LDFLAGS= 5 | 6 | MAKEDEPEND=${CC} -MM 7 | PROGRAM=evconnections 8 | 9 | OBJS = string/buffer.o fs/file.o util/parser/number.o net/mon/event/base.o \ 10 | net/mon/event/icmp.o net/mon/event/udp.o net/mon/event/dns.o \ 11 | net/mon/event/tcp_begin.o net/mon/event/tcp_data.o \ 12 | net/mon/event/tcp_end.o net/mon/event/reader.o \ 13 | evconnections.o 14 | 15 | DEPS:= ${OBJS:%.o=%.d} 16 | 17 | all: $(PROGRAM) 18 | 19 | ${PROGRAM}: ${OBJS} 20 | ${CC} ${OBJS} ${LIBS} -o $@ ${LDFLAGS} 21 | 22 | clean: 23 | rm -f ${PROGRAM} ${OBJS} ${DEPS} 24 | 25 | ${OBJS} ${DEPS} ${PROGRAM} : Makefile.evconnections 26 | 27 | .PHONY : all clean 28 | 29 | %.d : %.cpp 30 | ${MAKEDEPEND} ${CXXFLAGS} $< -MT ${@:%.d=%.o} > $@ 31 | 32 | %.o : %.cpp 33 | ${CC} ${CXXFLAGS} -c -o $@ $< 34 | 35 | -include ${DEPS} 36 | -------------------------------------------------------------------------------- /Makefile.evmerger: -------------------------------------------------------------------------------- 1 | CC=g++ 2 | CXXFLAGS=-O3 -std=c++11 -Wall -pedantic -D_GNU_SOURCE -I. 3 | 4 | LDFLAGS= 5 | 6 | MAKEDEPEND=${CC} -MM 7 | PROGRAM=evmerger 8 | 9 | OBJS = string/buffer.o fs/file.o \ 10 | net/mon/event/base.o net/mon/event/icmp.o net/mon/event/udp.o \ 11 | net/mon/event/dns.o net/mon/event/tcp_begin.o net/mon/event/tcp_data.o \ 12 | net/mon/event/tcp_end.o net/mon/event/reader.o net/mon/event/merger.o \ 13 | evmerger.o 14 | 15 | DEPS:= ${OBJS:%.o=%.d} 16 | 17 | all: $(PROGRAM) 18 | 19 | ${PROGRAM}: ${OBJS} 20 | ${CC} ${OBJS} ${LIBS} -o $@ ${LDFLAGS} 21 | 22 | clean: 23 | rm -f ${PROGRAM} ${OBJS} ${DEPS} 24 | 25 | ${OBJS} ${DEPS} ${PROGRAM} : Makefile.evmerger 26 | 27 | .PHONY : all clean 28 | 29 | %.d : %.cpp 30 | ${MAKEDEPEND} ${CXXFLAGS} $< -MT ${@:%.d=%.o} > $@ 31 | 32 | %.o : %.cpp 33 | ${CC} ${CXXFLAGS} -c -o $@ $< 34 | 35 | -include ${DEPS} 36 | -------------------------------------------------------------------------------- /Makefile.evreader: -------------------------------------------------------------------------------- 1 | CC=g++ 2 | CXXFLAGS=-O3 -std=c++11 -Wall -pedantic -D_GNU_SOURCE -I. 3 | 4 | # Is SQLite available? 5 | CXXFLAGS+=-DHAVE_SQLITE 6 | 7 | LDFLAGS= 8 | 9 | ifneq (,$(findstring HAVE_SQLITE, $(CXXFLAGS))) 10 | LDFLAGS=-lsqlite3 11 | endif 12 | 13 | MAKEDEPEND=${CC} -MM 14 | PROGRAM=evreader 15 | 16 | OBJS = string/buffer.o fs/file.o util/parser/number.o net/mon/event/base.o \ 17 | net/mon/event/icmp.o net/mon/event/udp.o net/mon/event/dns.o \ 18 | net/mon/event/tcp_begin.o net/mon/event/tcp_data.o \ 19 | net/mon/event/tcp_end.o net/mon/event/reader.o \ 20 | net/mon/event/grammar/expressions.o net/mon/event/grammar/parser.o \ 21 | net/mask.o \ 22 | evreader.o 23 | 24 | ifneq (,$(findstring HAVE_SQLITE, $(CXXFLAGS))) 25 | OBJS+=net/mon/event/printer/db/sqlite.o 26 | endif 27 | 28 | DEPS:= ${OBJS:%.o=%.d} 29 | 30 | all: $(PROGRAM) 31 | 32 | ${PROGRAM}: ${OBJS} 33 | ${CC} ${OBJS} ${LIBS} -o $@ ${LDFLAGS} 34 | 35 | clean: 36 | rm -f ${PROGRAM} ${OBJS} ${DEPS} 37 | 38 | ${OBJS} ${DEPS} ${PROGRAM} : Makefile.evreader 39 | 40 | .PHONY : all clean 41 | 42 | %.d : %.cpp 43 | ${MAKEDEPEND} ${CXXFLAGS} $< -MT ${@:%.d=%.o} > $@ 44 | 45 | %.o : %.cpp 46 | ${CC} ${CXXFLAGS} -c -o $@ $< 47 | 48 | -include ${DEPS} 49 | -------------------------------------------------------------------------------- /Makefile.test_segments: -------------------------------------------------------------------------------- 1 | CC=g++ 2 | CXXFLAGS=-g -std=c++11 -Wall -pedantic -D_GNU_SOURCE -I. 3 | 4 | LDFLAGS= 5 | 6 | MAKEDEPEND=${CC} -MM 7 | PROGRAM=test_segments 8 | 9 | OBJS = net/mon/tcp/segments.o test_segments.o 10 | 11 | DEPS:= ${OBJS:%.o=%.d} 12 | 13 | all: $(PROGRAM) 14 | 15 | ${PROGRAM}: ${OBJS} 16 | ${CC} ${OBJS} ${LIBS} -o $@ ${LDFLAGS} 17 | 18 | clean: 19 | rm -f ${PROGRAM} ${OBJS} ${DEPS} 20 | 21 | ${OBJS} ${DEPS} ${PROGRAM} : Makefile.test_segments 22 | 23 | .PHONY : all clean 24 | 25 | %.d : %.cpp 26 | ${MAKEDEPEND} ${CXXFLAGS} $< -MT ${@:%.d=%.o} > $@ 27 | 28 | %.o : %.cpp 29 | ${CC} ${CXXFLAGS} -c -o $@ $< 30 | 31 | -include ${DEPS} 32 | -------------------------------------------------------------------------------- /evmerger.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "net/mon/event/merger.h" 4 | 5 | int main(int argc, const char** argv) 6 | { 7 | if (argc >= 4) { 8 | net::mon::event::merger evmerger; 9 | if (evmerger.merge(argv + 1, argc - 2, argv[argc - 1])) { 10 | return 0; 11 | } else { 12 | fprintf(stderr, "Error merging files.\n"); 13 | } 14 | } else { 15 | fprintf(stderr, 16 | "Usage: %s ... " 17 | "\n", 18 | argv[0]); 19 | } 20 | 21 | return -1; 22 | } 23 | -------------------------------------------------------------------------------- /fs/file.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fs/file.h" 3 | 4 | ssize_t fs::file::pread(void* buf, size_t count, uint64_t off) 5 | { 6 | uint64_t end; 7 | if ((end = off + count) >= off) { 8 | // If the offset is not beyond the end of the file... 9 | if (off < _M_used) { 10 | if (end > _M_used) { 11 | count = _M_used - off; 12 | } 13 | 14 | uint8_t* b = static_cast(buf); 15 | size_t read = 0; 16 | 17 | do { 18 | ssize_t ret; 19 | switch (ret = ::pread(_M_fd, b, count, off)) { 20 | default: 21 | read += ret; 22 | 23 | if ((count -= ret) == 0) { 24 | return read; 25 | } 26 | 27 | b += ret; 28 | off += ret; 29 | 30 | break; 31 | case 0: 32 | return read; 33 | case -1: 34 | if (errno != EINTR) { 35 | return (read > 0) ? read : -1; 36 | } 37 | 38 | break; 39 | } 40 | } while (true); 41 | } else if (off == _M_used) { 42 | return 0; 43 | } 44 | } 45 | 46 | return -1; 47 | } 48 | 49 | bool fs::file::pwrite(const void* buf, size_t count, uint64_t off) 50 | { 51 | uint64_t end; 52 | if ((end = off + count) >= off) { 53 | // If the file has to be extended... 54 | if (end > _M_size) { 55 | uint64_t size = _M_allocation_size; 56 | uint64_t diff = end - _M_size; 57 | 58 | while (size < diff) { 59 | uint64_t tmp; 60 | if ((tmp = size + _M_allocation_size) > size) { 61 | size = tmp; 62 | } else { 63 | // Overflow. 64 | return false; 65 | } 66 | } 67 | 68 | if (!reserve(size)) { 69 | return false; 70 | } 71 | } 72 | 73 | const uint8_t* b = static_cast(buf); 74 | 75 | do { 76 | ssize_t ret; 77 | switch (ret = ::pwrite(_M_fd, b, count, off)) { 78 | default: 79 | if ((count -= ret) == 0) { 80 | if (end > _M_used) { 81 | _M_used = end; 82 | } 83 | 84 | return true; 85 | } 86 | 87 | b += ret; 88 | off += ret; 89 | 90 | break; 91 | case 0: 92 | return (count == 0); 93 | case -1: 94 | if (errno != EINTR) { 95 | return false; 96 | } 97 | 98 | break; 99 | } 100 | } while (true); 101 | } 102 | 103 | return false; 104 | } 105 | -------------------------------------------------------------------------------- /fs/file.h: -------------------------------------------------------------------------------- 1 | #ifndef FS_FILE_H 2 | #define FS_FILE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace fs { 9 | class file { 10 | public: 11 | // Default allocation size. 12 | static constexpr const uint64_t 13 | default_allocation_size = 1024ull * 1024ull * 1024ull; 14 | 15 | // Constructor. 16 | file(uint64_t allocation_size = default_allocation_size); 17 | 18 | // Destructor. 19 | ~file(); 20 | 21 | // Open. 22 | bool open(const char* filename); 23 | 24 | // Is the file open? 25 | bool open() const; 26 | 27 | // Close. 28 | bool close(); 29 | 30 | // Read at a given offset. 31 | ssize_t pread(void* buf, size_t count, uint64_t off); 32 | 33 | // Write. 34 | bool write(const void* buf, size_t count); 35 | 36 | // Write at a given offset. 37 | bool pwrite(const void* buf, size_t count, uint64_t off); 38 | 39 | // Get filesize. 40 | uint64_t size() const; 41 | 42 | // Is the file empty? 43 | bool empty() const; 44 | 45 | private: 46 | int _M_fd = -1; 47 | 48 | uint64_t _M_size; 49 | uint64_t _M_used; 50 | 51 | uint64_t _M_allocation_size; 52 | 53 | // Reserve space in the file. 54 | bool reserve(uint64_t count); 55 | 56 | // Disable copy constructor and assignment operator. 57 | file(const file&) = delete; 58 | file& operator=(const file&) = delete; 59 | }; 60 | 61 | inline file::file(uint64_t allocation_size) 62 | : _M_allocation_size(allocation_size) 63 | { 64 | } 65 | 66 | inline file::~file() 67 | { 68 | close(); 69 | } 70 | 71 | inline bool file::open(const char* filename) 72 | { 73 | if ((_M_fd = ::open(filename, O_CREAT | O_RDWR, 0644)) != -1) { 74 | // Get filesize. 75 | off_t filesize; 76 | if ((filesize = lseek(_M_fd, 0, SEEK_END)) != -1) { 77 | // Save filesize. 78 | _M_size = filesize; 79 | _M_used = filesize; 80 | 81 | return reserve(_M_allocation_size); 82 | } 83 | } 84 | 85 | return false; 86 | } 87 | 88 | inline bool file::open() const 89 | { 90 | return (_M_fd != -1); 91 | } 92 | 93 | inline bool file::close() 94 | { 95 | if (_M_fd != -1) { 96 | bool ret = (ftruncate(_M_fd, _M_used) == 0); 97 | 98 | ::close(_M_fd); 99 | _M_fd = -1; 100 | 101 | return ret; 102 | } 103 | 104 | return true; 105 | } 106 | 107 | inline bool file::write(const void* buf, size_t count) 108 | { 109 | return pwrite(buf, count, _M_used); 110 | } 111 | 112 | inline uint64_t file::size() const 113 | { 114 | return _M_used; 115 | } 116 | 117 | inline bool file::empty() const 118 | { 119 | return (_M_used == 0); 120 | } 121 | 122 | inline bool file::reserve(uint64_t count) 123 | { 124 | uint64_t size; 125 | if ((size = _M_size + count) >= _M_size) { 126 | if (ftruncate(_M_fd, size) == 0) { 127 | _M_size = size; 128 | 129 | return true; 130 | } 131 | } 132 | 133 | return false; 134 | } 135 | } 136 | 137 | #endif // FS_FILE_H 138 | -------------------------------------------------------------------------------- /html/events.css: -------------------------------------------------------------------------------- 1 | .table { 2 | display: table; 3 | } 4 | 5 | .heading { 6 | display: table-row; 7 | font-weight: bold; 8 | text-align: center; 9 | } 10 | 11 | .row { 12 | display: table-row; 13 | } 14 | 15 | .cell { 16 | display: table-cell; 17 | border: solid; 18 | border-width: thin; 19 | padding-left: 5px; 20 | padding-right: 5px; 21 | } 22 | -------------------------------------------------------------------------------- /html/events.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Events 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |
30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /memory/unique_ptr.h: -------------------------------------------------------------------------------- 1 | #ifndef MEMORY_UNIQUE_PTR_H 2 | #define MEMORY_UNIQUE_PTR_H 3 | 4 | namespace memory { 5 | template 6 | class unique_ptr { 7 | public: 8 | // Constructor. 9 | unique_ptr() = default; 10 | unique_ptr(T* p); 11 | 12 | // Destructor. 13 | ~unique_ptr(); 14 | 15 | // Reset. 16 | void reset(T* p = nullptr); 17 | 18 | // Release ownership. 19 | T* release(); 20 | 21 | // Assigment operator. 22 | unique_ptr& operator=(T* p); 23 | 24 | // Dereference the stored pointer. 25 | T& operator*() const; 26 | 27 | // Return the stored pointer. 28 | T* operator->() const; 29 | 30 | // Return the stored pointer. 31 | T* get() const; 32 | 33 | // Return true if the stored pointer is not null. 34 | operator bool() const; 35 | 36 | private: 37 | T* _M_ptr = nullptr; 38 | 39 | // Disable copy constructor and assignment operator. 40 | unique_ptr(const unique_ptr&) = delete; 41 | unique_ptr& operator=(const unique_ptr&) = delete; 42 | }; 43 | 44 | template 45 | inline unique_ptr::unique_ptr(T* p) 46 | : _M_ptr(p) 47 | { 48 | } 49 | 50 | template 51 | inline unique_ptr::~unique_ptr() 52 | { 53 | reset(); 54 | } 55 | 56 | template 57 | inline void unique_ptr::reset(T* p) 58 | { 59 | if (_M_ptr) { 60 | delete _M_ptr; 61 | } 62 | 63 | _M_ptr = p; 64 | } 65 | 66 | template 67 | inline T* unique_ptr::release() 68 | { 69 | T* p = _M_ptr; 70 | _M_ptr = nullptr; 71 | 72 | return p; 73 | } 74 | 75 | template 76 | inline unique_ptr& unique_ptr::operator=(T* p) 77 | { 78 | if (p != _M_ptr) { 79 | reset(p); 80 | } 81 | 82 | return *this; 83 | } 84 | 85 | template 86 | inline T& unique_ptr::operator*() const 87 | { 88 | return *_M_ptr; 89 | } 90 | 91 | template 92 | inline T* unique_ptr::operator->() const 93 | { 94 | return get(); 95 | } 96 | 97 | template 98 | inline T* unique_ptr::get() const 99 | { 100 | return _M_ptr; 101 | } 102 | 103 | template 104 | inline unique_ptr::operator bool() const 105 | { 106 | return (_M_ptr != nullptr); 107 | } 108 | } 109 | 110 | #endif // MEMORY_UNIQUE_PTR_H 111 | -------------------------------------------------------------------------------- /net/address.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_ADDRESS_H 2 | #define NET_ADDRESS_H 3 | 4 | #include 5 | 6 | namespace net { 7 | typedef uint8_t address[16]; 8 | } 9 | 10 | #endif // NET_ADDRESS_H 11 | -------------------------------------------------------------------------------- /net/capture/callbacks.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_CAPTURE_CALLBACKS_H 2 | #define NET_CAPTURE_CALLBACKS_H 3 | 4 | #include 5 | #include 6 | 7 | namespace net { 8 | namespace capture { 9 | // Capture callbacks. 10 | struct callbacks { 11 | typedef bool (*ethernet_t)(const void* buf, 12 | size_t len, 13 | const struct timeval& timestamp, 14 | void* user); 15 | 16 | typedef void (*idle_t)(void* user); 17 | 18 | // Constructor. 19 | callbacks() = default; 20 | callbacks(ethernet_t ethernet, idle_t idle); 21 | 22 | ethernet_t ethernet = nullptr; 23 | idle_t idle = nullptr; 24 | }; 25 | 26 | inline callbacks::callbacks(ethernet_t ethernet, idle_t idle) 27 | : ethernet(ethernet), 28 | idle(idle) 29 | { 30 | } 31 | } 32 | } 33 | 34 | #endif // NET_CAPTURE_CALLBACKS_H 35 | -------------------------------------------------------------------------------- /net/capture/limits.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_CAPTURE_LIMITS_H 2 | #define NET_CAPTURE_LIMITS_H 3 | 4 | namespace net { 5 | namespace capture { 6 | // Minimum size of the socket receive buffer. 7 | static constexpr const int min_rcvbuf_size = 2 * 1024; 8 | } 9 | } 10 | 11 | #endif // NET_CAPTURE_LIMITS_H 12 | -------------------------------------------------------------------------------- /net/capture/method.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_CAPTURE_METHOD_H 2 | #define NET_CAPTURE_METHOD_H 3 | 4 | namespace net { 5 | namespace capture { 6 | // Capture method. 7 | enum class method { 8 | ring_buffer, 9 | socket 10 | }; 11 | } 12 | } 13 | 14 | #endif // NET_CAPTURE_METHOD_H 15 | -------------------------------------------------------------------------------- /net/capture/ring_buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_CAPTURE_RING_BUFFER_H 2 | #define NET_CAPTURE_RING_BUFFER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "net/capture/callbacks.h" 9 | 10 | namespace net { 11 | namespace capture { 12 | // Ring buffer. 13 | class ring_buffer { 14 | public: 15 | static constexpr const size_t min_block_size = 128; 16 | static constexpr const size_t max_block_size = ULONG_MAX; 17 | static constexpr const size_t 18 | default_block_size = static_cast(1) << 12; 19 | 20 | static constexpr const size_t min_frame_size = 128; 21 | static constexpr const size_t max_frame_size = ULONG_MAX; 22 | static constexpr const size_t 23 | default_frame_size = static_cast(1) << 11; 24 | 25 | static constexpr const size_t min_frames = 8; 26 | static constexpr const size_t max_frames = ULONG_MAX; 27 | static constexpr const size_t 28 | default_frames = static_cast(1) << 9; 29 | 30 | // Constructor. 31 | ring_buffer() = default; 32 | 33 | // Destructor. 34 | ~ring_buffer(); 35 | 36 | // Clear. 37 | void clear(); 38 | 39 | // Create. 40 | bool create(const char* interface, 41 | int rcvbuf_size, 42 | bool promiscuous_mode, 43 | size_t block_size, 44 | size_t frame_size, 45 | size_t frame_count); 46 | 47 | bool create(unsigned ifindex, 48 | int rcvbuf_size, 49 | bool promiscuous_mode, 50 | size_t block_size, 51 | size_t frame_size, 52 | size_t frame_count); 53 | 54 | // Loop. 55 | bool loop(const callbacks& callbacks, void* user = nullptr); 56 | 57 | // Stop. 58 | void stop(); 59 | 60 | // Show statistics. 61 | bool show_statistics(); 62 | 63 | private: 64 | int _M_fd = -1; 65 | 66 | void* _M_buf = MAP_FAILED; 67 | size_t _M_ring_size; 68 | 69 | // For TPACKET_V2: 70 | // _M_count = req.tp_frame_nr 71 | // _M_size = req.tp_frame_size 72 | // 73 | // For TPACKET_V3: 74 | // _M_count = req3.tp_block_nr 75 | // _M_size = req3.tp_block_size 76 | size_t _M_count; 77 | size_t _M_size; 78 | 79 | size_t _M_nframes; 80 | 81 | struct iovec* _M_frames = nullptr; 82 | 83 | size_t _M_idx = 0; 84 | 85 | // Callbacks. 86 | callbacks _M_callbacks; 87 | void* _M_user; 88 | 89 | // Running? 90 | bool _M_running = false; 91 | 92 | // Set up socket. 93 | bool setup_socket(int rcvbuf_size); 94 | 95 | // Set up packet ring. 96 | bool setup_ring(size_t block_size, 97 | size_t frame_size, 98 | size_t frame_count); 99 | 100 | // Set up mmap packet ring. 101 | bool mmap_ring(); 102 | 103 | // Bind packet ring. 104 | bool bind_ring(unsigned ifindex, bool promiscuous_mode); 105 | 106 | #if HAVE_TPACKET_V3 107 | // Configure for TPACKET_V3. 108 | void config_v3(size_t block_size, 109 | size_t frame_size, 110 | size_t frame_count, 111 | struct tpacket_req3& req); 112 | 113 | // Receive packet for TPACKET_V3. 114 | bool recv_v3(); 115 | #else 116 | // Configure for TPACKET_V2. 117 | void config_v2(size_t block_size, 118 | size_t frame_size, 119 | size_t frame_count, 120 | struct tpacket_req& req); 121 | 122 | // Receive packet for TPACKET_V2. 123 | bool recv_v2(); 124 | #endif 125 | 126 | // Disable copy constructor and assignment operator. 127 | ring_buffer(const ring_buffer&) = delete; 128 | ring_buffer& operator=(const ring_buffer&) = delete; 129 | }; 130 | 131 | inline ring_buffer::~ring_buffer() 132 | { 133 | clear(); 134 | } 135 | 136 | inline bool ring_buffer::create(const char* interface, 137 | int rcvbuf_size, 138 | bool promiscuous_mode, 139 | size_t block_size, 140 | size_t frame_size, 141 | size_t frame_count) 142 | { 143 | return create(if_nametoindex(interface), 144 | rcvbuf_size, 145 | promiscuous_mode, 146 | block_size, 147 | frame_size, 148 | frame_count); 149 | } 150 | 151 | inline void ring_buffer::stop() 152 | { 153 | _M_running = false; 154 | } 155 | } 156 | } 157 | 158 | #endif // NET_CAPTURE_RING_BUFFER_H 159 | -------------------------------------------------------------------------------- /net/capture/socket.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "net/capture/socket.h" 15 | #include "net/capture/limits.h" 16 | 17 | void net::capture::socket::clear() 18 | { 19 | if (_M_fd != -1) { 20 | close(_M_fd); 21 | _M_fd = -1; 22 | } 23 | 24 | if (_M_buf) { 25 | free(_M_buf); 26 | _M_buf = nullptr; 27 | } 28 | } 29 | 30 | bool net::capture::socket::create(unsigned ifindex, 31 | int rcvbuf_size, 32 | bool promiscuous_mode) 33 | { 34 | if ((ifindex > 0) && 35 | ((rcvbuf_size == 0) || (rcvbuf_size >= min_rcvbuf_size))) { 36 | if ((setup_socket(rcvbuf_size)) && 37 | (bind(ifindex, promiscuous_mode)) && 38 | ((_M_buf = static_cast( 39 | malloc(max_messages * max_message_size) 40 | )) != nullptr)) { 41 | #if defined(PACKET_FANOUT) 42 | // Create fanout group. 43 | int optval = ((PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_DEFRAG) << 16) | 44 | ((getpid() ^ ifindex) & 0xffff); 45 | 46 | if (setsockopt(_M_fd, 47 | SOL_PACKET, 48 | PACKET_FANOUT, 49 | &optval, 50 | sizeof(int)) < 0) { 51 | return false; 52 | } 53 | #endif // defined(PACKET_FANOUT) 54 | 55 | // Initialize messages. 56 | uint8_t* buf = _M_buf; 57 | for (size_t i = 0; i < max_messages; i++) { 58 | _M_iov[i].iov_base = buf; 59 | _M_iov[i].iov_len = max_message_size; 60 | 61 | _M_msg[i].msg_hdr.msg_name = nullptr; 62 | _M_msg[i].msg_hdr.msg_namelen = 0; 63 | _M_msg[i].msg_hdr.msg_iov = _M_iov + i; 64 | _M_msg[i].msg_hdr.msg_iovlen = 1; 65 | _M_msg[i].msg_hdr.msg_control = nullptr; 66 | _M_msg[i].msg_hdr.msg_controllen = 0; 67 | _M_msg[i].msg_hdr.msg_flags = 0; 68 | 69 | buf += max_message_size; 70 | } 71 | 72 | return true; 73 | } 74 | } 75 | 76 | return false; 77 | } 78 | 79 | bool net::capture::socket::loop(const callbacks& callbacks, void* user) 80 | { 81 | static constexpr const int timeout = 100; 82 | 83 | _M_callbacks = callbacks; 84 | _M_user = user; 85 | 86 | struct pollfd pfd; 87 | pfd.fd = _M_fd; 88 | pfd.events = POLLIN; 89 | 90 | _M_running = true; 91 | 92 | do { 93 | switch (poll(&pfd, 1, timeout)) { 94 | case 1: 95 | recv(); 96 | break; 97 | case 0: // Timeout. 98 | if (callbacks.idle) { 99 | callbacks.idle(user); 100 | } 101 | 102 | break; 103 | default: 104 | if (errno != EINTR) { 105 | return false; 106 | } 107 | } 108 | } while (_M_running); 109 | 110 | return true; 111 | } 112 | 113 | bool net::capture::socket::show_statistics() 114 | { 115 | struct tpacket_stats stats; 116 | socklen_t optlen = static_cast(sizeof(struct tpacket_stats)); 117 | 118 | if (getsockopt(_M_fd, SOL_PACKET, PACKET_STATISTICS, &stats, &optlen) == 0) { 119 | printf(" %u packets received.\n", stats.tp_packets); 120 | printf(" %u packets dropped by kernel.\n", stats.tp_drops); 121 | 122 | return true; 123 | } 124 | 125 | return false; 126 | } 127 | 128 | bool net::capture::socket::setup_socket(int rcvbuf_size) 129 | { 130 | // Create socket. 131 | if ((_M_fd = ::socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) != -1) { 132 | if (rcvbuf_size != 0) { 133 | return (setsockopt(_M_fd, 134 | SOL_SOCKET, 135 | SO_RCVBUF, 136 | &rcvbuf_size, 137 | sizeof(int)) == 0); 138 | } 139 | 140 | return true; 141 | } 142 | 143 | return false; 144 | } 145 | 146 | bool net::capture::socket::bind(unsigned ifindex, bool promiscuous_mode) 147 | { 148 | if (promiscuous_mode) { 149 | // Put the interface in promiscuous mode. 150 | struct packet_mreq mr; 151 | memset(&mr, 0, sizeof(struct packet_mreq)); 152 | mr.mr_ifindex = ifindex; 153 | mr.mr_type = PACKET_MR_PROMISC; 154 | if (setsockopt(_M_fd, 155 | SOL_PACKET, 156 | PACKET_ADD_MEMBERSHIP, 157 | &mr, 158 | sizeof(struct packet_mreq)) < 0) { 159 | return false; 160 | } 161 | } 162 | 163 | // Bind. 164 | struct sockaddr_ll addr; 165 | memset(&addr, 0, sizeof(struct sockaddr_ll)); 166 | addr.sll_family = AF_PACKET; 167 | addr.sll_protocol = htons(ETH_P_ALL); 168 | addr.sll_ifindex = ifindex; 169 | 170 | return (::bind(_M_fd, 171 | reinterpret_cast(&addr), 172 | static_cast(sizeof(struct sockaddr_ll))) == 0); 173 | } 174 | 175 | bool net::capture::socket::recv() 176 | { 177 | // Receive messages. 178 | int nmsgs = recvmmsg(_M_fd, 179 | _M_msg, 180 | max_messages, 181 | MSG_TRUNC | MSG_DONTWAIT, 182 | nullptr); 183 | 184 | // If we have received at least one packet... 185 | if (nmsgs >= 1) { 186 | // Get timestamp of the last packet. 187 | struct timeval tv; 188 | if (ioctl(_M_fd, SIOCGSTAMP, &tv) != -1) { 189 | // For each received message... 190 | for (int i = 0; i < nmsgs; i++) { 191 | // Process packet. 192 | _M_callbacks.ethernet(_M_msg[i].msg_hdr.msg_iov->iov_base, 193 | _M_msg[i].msg_len, 194 | tv, 195 | _M_user); 196 | } 197 | } 198 | } 199 | 200 | return true; 201 | } 202 | -------------------------------------------------------------------------------- /net/capture/socket.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_CAPTURE_SOCKET_H 2 | #define NET_CAPTURE_SOCKET_H 3 | 4 | #include 5 | #include 6 | #include "net/capture/callbacks.h" 7 | 8 | namespace net { 9 | namespace capture { 10 | // Raw socket. 11 | class socket { 12 | public: 13 | // Constructor. 14 | socket() = default; 15 | 16 | // Destructor. 17 | ~socket(); 18 | 19 | // Clear. 20 | void clear(); 21 | 22 | // Create. 23 | bool create(const char* interface, 24 | int rcvbuf_size, 25 | bool promiscuous_mode); 26 | 27 | bool create(unsigned ifindex, int rcvbuf_size, bool promiscuous_mode); 28 | 29 | // Loop. 30 | bool loop(const callbacks& callbacks, void* user = nullptr); 31 | 32 | // Stop. 33 | void stop(); 34 | 35 | // Show statistics. 36 | bool show_statistics(); 37 | 38 | private: 39 | // Maximum number of messages to receive with one read operation. 40 | static constexpr const unsigned max_messages = 256; 41 | 42 | // Maximum message size. 43 | static constexpr const size_t max_message_size = 64 * 1024; 44 | 45 | int _M_fd = -1; 46 | 47 | struct mmsghdr _M_msg[max_messages]; 48 | struct iovec _M_iov[max_messages]; 49 | 50 | uint8_t* _M_buf = nullptr; 51 | 52 | // Callbacks. 53 | callbacks _M_callbacks; 54 | void* _M_user; 55 | 56 | // Running? 57 | bool _M_running = false; 58 | 59 | // Set up socket. 60 | bool setup_socket(int rcvbuf_size); 61 | 62 | // Bind. 63 | bool bind(unsigned ifindex, bool promiscuous_mode); 64 | 65 | // Receive packets. 66 | bool recv(); 67 | 68 | // Disable copy constructor and assignment operator. 69 | socket(const socket&) = delete; 70 | socket& operator=(const socket&) = delete; 71 | }; 72 | 73 | inline socket::~socket() 74 | { 75 | clear(); 76 | } 77 | 78 | inline bool socket::create(const char* interface, 79 | int rcvbuf_size, 80 | bool promiscuous_mode) 81 | { 82 | return create(if_nametoindex(interface), rcvbuf_size, promiscuous_mode); 83 | } 84 | 85 | inline void socket::stop() 86 | { 87 | _M_running = false; 88 | } 89 | } 90 | } 91 | 92 | #endif // NET_CAPTURE_SOCKET_H 93 | -------------------------------------------------------------------------------- /net/limits.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_LIMITS_H 2 | #define NET_LIMITS_H 3 | 4 | namespace net { 5 | static constexpr const size_t domain_name_max_len = 255; 6 | } 7 | 8 | #endif // NET_LIMITS_H 9 | -------------------------------------------------------------------------------- /net/mask.cpp: -------------------------------------------------------------------------------- 1 | #include "net/mask.h" 2 | #include "util/parser/number.h" 3 | 4 | bool net::mask::build(const char* s) 5 | { 6 | const char* const slash = strchr(s, '/'); 7 | 8 | if (!slash) { 9 | if (inet_pton(AF_INET, s, _M_netmask.addr32) == 1) { 10 | _M_type = type::ipv4; 11 | 12 | _M_netmask.addr32[0] = ntohl(_M_netmask.addr32[0]); 13 | _M_mask.addr32[0] = 0xffffffffu; 14 | 15 | return true; 16 | } else if (inet_pton(AF_INET6, s, _M_netmask.addr32) == 1) { 17 | _M_type = type::ipv6; 18 | 19 | _M_mask.addr32[0] = 0xffffffffu; 20 | _M_mask.addr32[1] = 0xffffffffu; 21 | _M_mask.addr32[2] = 0xffffffffu; 22 | _M_mask.addr32[3] = 0xffffffffu; 23 | 24 | return true; 25 | } 26 | } else { 27 | const size_t len = slash - s; 28 | 29 | // If the length is neither too short nor too long... 30 | if ((len > 0) && (len < INET6_ADDRSTRLEN)) { 31 | char ip[INET6_ADDRSTRLEN]; 32 | memcpy(ip, s, len); 33 | ip[len] = 0; 34 | 35 | if (inet_pton(AF_INET, ip, _M_netmask.addr32) == 1) { 36 | uint64_t n; 37 | if (util::parser::number::parse(slash + 1, n, 1, 32)) { 38 | _M_type = type::ipv4; 39 | 40 | const size_t shift = 32 - static_cast(n); 41 | 42 | _M_mask.addr32[0] = (0xffffffffu >> shift) << shift; 43 | 44 | _M_netmask.addr32[0] = ntohl(_M_netmask.addr32[0]) & 45 | _M_mask.addr32[0]; 46 | 47 | return true; 48 | } 49 | } else if (inet_pton(AF_INET6, ip, _M_netmask.addr32) == 1) { 50 | uint64_t n; 51 | if (util::parser::number::parse(slash + 1, n, 1, 128)) { 52 | _M_type = type::ipv6; 53 | 54 | size_t idx = static_cast(n) >> 3; 55 | 56 | if (idx > 0) { 57 | memset(_M_mask.addr8, 0xff, idx); 58 | } 59 | 60 | const size_t mod = static_cast(n) & 0x07; 61 | 62 | if (mod != 0) { 63 | const size_t shift = 8 - mod; 64 | 65 | _M_mask.addr8[idx] = (static_cast(0xff) >> shift) << shift; 66 | 67 | idx++; 68 | } 69 | 70 | if (idx < sizeof(_M_mask)) { 71 | memset(_M_mask.addr8 + idx, 0, sizeof(_M_mask) - idx); 72 | } 73 | 74 | _M_netmask.addr32[0] &= _M_mask.addr32[0]; 75 | _M_netmask.addr32[1] &= _M_mask.addr32[1]; 76 | _M_netmask.addr32[2] &= _M_mask.addr32[2]; 77 | _M_netmask.addr32[3] &= _M_mask.addr32[3]; 78 | 79 | return true; 80 | } 81 | } 82 | } 83 | } 84 | 85 | return false; 86 | } 87 | -------------------------------------------------------------------------------- /net/mask.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MASK_H 2 | #define NET_MASK_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace net { 11 | class mask { 12 | public: 13 | // Constructor. 14 | mask() = default; 15 | 16 | // Destructor. 17 | ~mask() = default; 18 | 19 | // Build mask. 20 | bool build(const char* s); 21 | 22 | // Matches? 23 | bool match(const char* s) const; 24 | bool match(struct in_addr addr) const; 25 | bool match(uint32_t addr) const; 26 | bool match(const struct in6_addr& addr) const; 27 | bool match(const void* addr, size_t addrlen) const; 28 | 29 | private: 30 | enum class type { 31 | ipv4, 32 | ipv6 33 | }; 34 | 35 | type _M_type; 36 | 37 | union address { 38 | uint8_t addr8[16]; 39 | uint32_t addr32[4]; 40 | }; 41 | 42 | address _M_netmask; 43 | address _M_mask; 44 | }; 45 | 46 | inline bool mask::match(const char* s) const 47 | { 48 | struct in6_addr addr; 49 | if (inet_pton(AF_INET, s, &addr) == 1) { 50 | return match(addr.s6_addr32[0]); 51 | } else if (inet_pton(AF_INET6, s, &addr) == 1) { 52 | return match(addr); 53 | } else { 54 | return false; 55 | } 56 | } 57 | 58 | inline bool mask::match(struct in_addr addr) const 59 | { 60 | return match(addr.s_addr); 61 | } 62 | 63 | inline bool mask::match(uint32_t addr) const 64 | { 65 | return ((_M_type == type::ipv4) && 66 | ((ntohl(addr) & _M_mask.addr32[0]) == _M_netmask.addr32[0])); 67 | } 68 | 69 | inline bool mask::match(const struct in6_addr& addr) const 70 | { 71 | return ((_M_type == type::ipv6) && 72 | ((addr.s6_addr32[0] & _M_mask.addr32[0]) == _M_netmask.addr32[0]) && 73 | ((addr.s6_addr32[1] & _M_mask.addr32[1]) == _M_netmask.addr32[1]) && 74 | ((addr.s6_addr32[2] & _M_mask.addr32[2]) == _M_netmask.addr32[2]) && 75 | ((addr.s6_addr32[3] & _M_mask.addr32[3]) == _M_netmask.addr32[3])); 76 | } 77 | 78 | inline bool mask::match(const void* addr, size_t addrlen) const 79 | { 80 | switch (addrlen) { 81 | case sizeof(struct in_addr): 82 | { 83 | uint32_t address; 84 | memcpy(&address, addr, sizeof(struct in_addr)); 85 | 86 | return match(address); 87 | } 88 | case sizeof(struct in6_addr): 89 | { 90 | struct in6_addr address; 91 | memcpy(&address, addr, sizeof(struct in6_addr)); 92 | 93 | return match(address); 94 | } 95 | default: 96 | return false; 97 | } 98 | } 99 | } 100 | 101 | #endif // NET_MASK_H 102 | -------------------------------------------------------------------------------- /net/mon/configuration.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_CONFIGURATION_H 2 | #define NET_MON_CONFIGURATION_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "net/capture/ring_buffer.h" 8 | #include "net/mon/workers.h" 9 | #include "fs/file.h" 10 | 11 | namespace net { 12 | namespace mon { 13 | // Network monitor configuration. 14 | class configuration { 15 | public: 16 | // Capture configuration. 17 | class capture { 18 | public: 19 | // Ring buffer configuration. 20 | class ring_buffer { 21 | public: 22 | // Constructor. 23 | ring_buffer() = default; 24 | 25 | // Destructor. 26 | ~ring_buffer() = default; 27 | 28 | // Valid configuration? 29 | bool valid() const; 30 | 31 | // Print configuration. 32 | void print() const; 33 | 34 | // Show help. 35 | static void help(); 36 | 37 | // Block size. 38 | size_t block_size = 39 | net::capture::ring_buffer::default_block_size; 40 | 41 | // Frame size. 42 | size_t frame_size = 43 | net::capture::ring_buffer::default_frame_size; 44 | 45 | // Frame count. 46 | size_t frame_count = net::capture::ring_buffer::default_frames; 47 | }; 48 | 49 | // Constructor. 50 | capture() = default; 51 | 52 | // Destructor. 53 | ~capture() = default; 54 | 55 | // Valid configuration? 56 | bool valid() const; 57 | 58 | // Print configuration. 59 | void print() const; 60 | 61 | // Show help. 62 | static void help(); 63 | 64 | // Capture method. 65 | enum class method { 66 | none, 67 | pcap, 68 | ring_buffer, 69 | socket 70 | }; 71 | 72 | method m = method::none; 73 | 74 | // Name of the capture device (either a PCAP filename or the 75 | // name of a network interface). 76 | const char* device = nullptr; 77 | 78 | // Index of the network interface. 79 | unsigned ifindex = 0; 80 | 81 | // Size of the socket receive buffer. 82 | int rcvbuf_size = 0; 83 | 84 | // Enable promiscuous mode? 85 | bool promiscuous_mode = false; 86 | 87 | // Ring buffer configuration. 88 | ring_buffer rb; 89 | }; 90 | 91 | // TCP configuration. 92 | template 93 | class tcp { 94 | public: 95 | // Constructor. 96 | tcp() = default; 97 | 98 | // Destructor. 99 | ~tcp() = default; 100 | 101 | // Valid configuration? 102 | bool valid() const; 103 | 104 | // Print configuration. 105 | void print() const; 106 | 107 | // Show help. 108 | static void help(); 109 | 110 | // Type of the connections class. 111 | typedef net::mon::tcp::connections 112 | connections_type; 113 | 114 | // Hash table size. 115 | size_t size = connections_type::default_size; 116 | 117 | // Maximum number of connections. 118 | size_t maxconns = connections_type::default_max_connections; 119 | 120 | // Connection timeout (seconds). 121 | uint64_t timeout = connections_type::default_timeout; 122 | 123 | // TCP time wait (seconds). 124 | uint64_t time_wait = connections_type::default_time_wait; 125 | }; 126 | 127 | // Constructor. 128 | configuration() = default; 129 | 130 | // Destructor. 131 | ~configuration() = default; 132 | 133 | // Initialize. 134 | bool init(); 135 | 136 | // Parse configuration. 137 | bool parse(size_t argc, const char** argv); 138 | 139 | // Valid configuration? 140 | bool valid() const; 141 | 142 | // Print configuration. 143 | void print() const; 144 | 145 | // Show help. 146 | void help(const char* program); 147 | 148 | // Number of workers. 149 | size_t nworkers = 0; 150 | 151 | // Processor indexes. 152 | size_t processors[workers::max_workers]; 153 | 154 | // Events directory. 155 | char evdir[PATH_MAX]; 156 | 157 | static_assert(strlen(worker::default_directory) < sizeof(evdir), 158 | "Name of the events directory is too long."); 159 | 160 | // File allocation size. 161 | uint64_t file_allocation_size = fs::file::default_allocation_size; 162 | 163 | // Buffer size of the event writer. 164 | size_t buffer_size = event::writer::default_buffer_size; 165 | 166 | // Capture configuration. 167 | capture cap; 168 | 169 | // TCP/IPv4 configuration. 170 | typedef tcp tcp4_type; 171 | tcp4_type tcp4; 172 | 173 | // TCP/IPv6 configuration. 174 | typedef tcp tcp6_type; 175 | tcp6_type tcp6; 176 | 177 | private: 178 | // Number of processors currently online. 179 | size_t _M_nprocessors; 180 | 181 | // Events directory. 182 | const char* _M_evdir = nullptr; 183 | 184 | // Get the number of processors currently online. 185 | static bool get_number_processors(size_t& nprocessors); 186 | 187 | // Parse number list. 188 | static bool parse_number_list(const char* s, 189 | size_t min, 190 | size_t max, 191 | size_t minval, 192 | size_t maxval, 193 | size_t& count, 194 | size_t* numbers); 195 | }; 196 | 197 | inline bool configuration::init() 198 | { 199 | // Get the number of processors currently online. 200 | if (get_number_processors(_M_nprocessors)) { 201 | // Initialize processors. 202 | for (size_t i = 0; i < workers::max_workers; i++) { 203 | processors[i] = worker::no_processor; 204 | } 205 | 206 | return true; 207 | } 208 | 209 | return false; 210 | } 211 | } 212 | } 213 | 214 | #endif // NET_MON_CONFIGURATION_H 215 | -------------------------------------------------------------------------------- /net/mon/dns/message.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_DNS_MESSAGE_H 2 | #define NET_MON_DNS_MESSAGE_H 3 | 4 | #include 5 | #include 6 | #include "net/mon/event/dns.h" 7 | 8 | namespace net { 9 | namespace mon { 10 | namespace dns { 11 | // DNS port in network byte order. 12 | static constexpr const uint16_t port = static_cast(53) << 8; 13 | 14 | class message { 15 | public: 16 | // Constructor. 17 | message(const void* buf, size_t len); 18 | 19 | // Destructor. 20 | ~message() = default; 21 | 22 | // Parse DNS message. 23 | bool parse(event::dns& ev); 24 | 25 | private: 26 | // Maximum length of a DNS message. 27 | static constexpr const size_t max_len = 512; 28 | 29 | // Length of the DNS header. 30 | static constexpr const size_t header_len = 12; 31 | 32 | // Maximum number of DNS pointers. 33 | static constexpr const size_t max_pointers = 64; 34 | 35 | // Message buffer. 36 | const uint8_t* const _M_buf; 37 | 38 | // Message length. 39 | const size_t _M_len; 40 | 41 | // Current offset. 42 | size_t _M_off; 43 | 44 | // Skip question. 45 | bool skip_question(); 46 | 47 | // Parse domain-name. 48 | bool parse_domain_name(char* domain, uint8_t& domainlen); 49 | 50 | // Skip domain-name. 51 | bool skip_domain_name(); 52 | }; 53 | 54 | inline message::message(const void* buf, size_t len) 55 | : _M_buf(static_cast(buf)), 56 | _M_len(len) 57 | { 58 | } 59 | 60 | inline bool message::skip_question() 61 | { 62 | if ((skip_domain_name()) && (_M_off + 4 <= _M_len)) { 63 | _M_off += 4; 64 | 65 | return true; 66 | } else { 67 | return false; 68 | } 69 | } 70 | } 71 | } 72 | } 73 | 74 | #endif // NET_MON_DNS_MESSAGE_H 75 | -------------------------------------------------------------------------------- /net/mon/event/base.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_EVENT_BASE_H 2 | #define NET_MON_EVENT_BASE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "net/address.h" 8 | #include "net/mon/event/util.h" 9 | #include "net/mon/event/printer/format.h" 10 | 11 | namespace net { 12 | namespace mon { 13 | namespace event { 14 | // Event length type. 15 | typedef uint16_t evlen_t; 16 | 17 | // Event types. 18 | enum class type : uint8_t { 19 | icmp, 20 | udp, 21 | dns, 22 | tcp_begin, 23 | tcp_data, 24 | tcp_end 25 | }; 26 | 27 | // Minimum length of an event (size of the base event for IPv4). 28 | static constexpr const size_t 29 | minlen = sizeof(evlen_t) + // Length. 30 | 8 + // Timestamp. 31 | sizeof(type) + // Type. 32 | 1 + // Address length. 33 | 4 + // Source address. 34 | 4; // Destination address. 35 | 36 | // Maximum length of an event (must be greater or equal than the biggest 37 | // event). 38 | static constexpr const size_t maxlen = 1024; 39 | 40 | // Base event. 41 | struct base { 42 | // Number of microseconds since the Epoch, 43 | // 1970-01-01 00:00:00 +0000 (UTC). 44 | uint64_t timestamp; 45 | 46 | // Address length (either 4 [IPv4] or 16 [IPv6]). 47 | uint8_t addrlen; 48 | 49 | // Source address. 50 | address saddr; 51 | 52 | // Destination address. 53 | address daddr; 54 | 55 | // Extract length. 56 | static evlen_t extract_length(const void* buf); 57 | 58 | // Extract timestamp. 59 | static uint64_t extract_timestamp(const void* buf); 60 | 61 | // Extract type. 62 | static type extract_type(const void* buf); 63 | 64 | // Build event. 65 | bool build(const void* buf, size_t len); 66 | 67 | // Get size. 68 | size_t size() const; 69 | 70 | // Serialize. 71 | void* serialize(void* buf, type t) const; 72 | 73 | // Print human readable. 74 | void print_human_readable(FILE* file, 75 | printer::format fmt, 76 | const char* srchost, 77 | const char* dsthost) const; 78 | 79 | void print_human_readable(FILE* file, 80 | printer::format fmt, 81 | const char* srchost, 82 | const char* dsthost, 83 | in_port_t sport, 84 | in_port_t dport) const; 85 | 86 | // Print JSON. 87 | void print_json(FILE* file, 88 | printer::format fmt, 89 | const char* srchost, 90 | const char* dsthost) const; 91 | 92 | void print_json(FILE* file, 93 | printer::format fmt, 94 | const char* srchost, 95 | const char* dsthost, 96 | in_port_t sport, 97 | in_port_t dport) const; 98 | 99 | // Print CSV. 100 | void print_csv(FILE* file, 101 | char separator, 102 | const char* srchost, 103 | const char* dsthost) const; 104 | 105 | void print_csv(FILE* file, 106 | char separator, 107 | const char* srchost, 108 | const char* dsthost, 109 | in_port_t sport, 110 | in_port_t dport) const; 111 | }; 112 | 113 | inline evlen_t base::extract_length(const void* buf) 114 | { 115 | evlen_t len; 116 | return event::deserialize(len, buf); 117 | } 118 | 119 | inline uint64_t base::extract_timestamp(const void* buf) 120 | { 121 | uint64_t timestamp; 122 | return event::deserialize(timestamp, 123 | static_cast(buf) + 124 | sizeof(evlen_t)); 125 | } 126 | 127 | inline type base::extract_type(const void* buf) 128 | { 129 | return static_cast( 130 | static_cast(buf)[sizeof(evlen_t) + 8] 131 | ); 132 | } 133 | 134 | inline size_t base::size() const 135 | { 136 | return sizeof(evlen_t) + // Length. 137 | 8 + // Timestamp. 138 | sizeof(type) + // Type. 139 | 1 + // Address length. 140 | addrlen + // Source address. 141 | addrlen; // Destination address. 142 | } 143 | 144 | inline void* base::serialize(void* buf, type t) const 145 | { 146 | // Serialize timestamp, leaving space for the length. 147 | buf = event::serialize(static_cast(buf) + sizeof(evlen_t), 148 | timestamp); 149 | 150 | // Serialize type. 151 | buf = event::serialize(buf, static_cast(t)); 152 | 153 | // Serialize address length. 154 | buf = event::serialize(buf, addrlen); 155 | 156 | // Copy source address. 157 | buf = static_cast(memcpy(buf, saddr, addrlen)) + addrlen; 158 | 159 | // Copy destination address. 160 | return static_cast(memcpy(buf, daddr, addrlen)) + addrlen; 161 | } 162 | } 163 | } 164 | } 165 | 166 | #endif // NET_MON_EVENT_BASE_H 167 | -------------------------------------------------------------------------------- /net/mon/event/dns.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_EVENT_DNS_H 2 | #define NET_MON_EVENT_DNS_H 3 | 4 | #include "net/mon/event/base.h" 5 | #include "net/limits.h" 6 | #include "string/buffer.h" 7 | 8 | namespace net { 9 | namespace mon { 10 | namespace event { 11 | // 'DNS' event. 12 | struct dns : public base { 13 | static constexpr const type t = type::dns; 14 | static constexpr const size_t max_responses = 24; 15 | 16 | // Source port. 17 | in_port_t sport; 18 | 19 | // Destination port. 20 | in_port_t dport; 21 | 22 | // # of bytes transferred. 23 | uint16_t transferred; 24 | 25 | // Query type. 26 | uint8_t qtype; 27 | 28 | // Domain length. 29 | uint8_t domainlen; 30 | 31 | // Domain. 32 | char domain[domain_name_max_len]; 33 | 34 | struct response { 35 | uint8_t addrlen; 36 | address addr; 37 | }; 38 | 39 | // # of DNS responses. 40 | uint8_t nresponses; 41 | 42 | // DNS responses. 43 | response responses[max_responses]; 44 | 45 | // Build 'DNS' event. 46 | bool build(const void* buf, size_t len); 47 | 48 | // Get size. 49 | size_t size() const; 50 | 51 | // Serialize. 52 | bool serialize(string::buffer& buf) const; 53 | 54 | // Print human readable. 55 | void print_human_readable(FILE* file, 56 | printer::format fmt, 57 | const char* srchost, 58 | const char* dsthost) const; 59 | 60 | // Print JSON. 61 | void print_json(FILE* file, 62 | printer::format fmt, 63 | const char* srchost, 64 | const char* dsthost) const; 65 | 66 | // Print CSV. 67 | void print_csv(FILE* file, 68 | char separator, 69 | const char* srchost, 70 | const char* dsthost) const; 71 | }; 72 | 73 | static_assert(sizeof(evlen_t) + sizeof(type) + sizeof(dns) <= maxlen, 74 | "'maxlen' is smaller than sizeof(dns)"); 75 | 76 | inline size_t dns::size() const 77 | { 78 | size_t s = base::size() + // Size of the base event. 79 | sizeof(in_port_t) + // Source port. 80 | sizeof(in_port_t) + // Destination port. 81 | 2 + // Transferred. 82 | 1 + // Query type. 83 | 1 + // Domain length. 84 | domainlen + // Domain. 85 | 1; // Number of responses. 86 | 87 | for (size_t i = 0; i < nresponses; i++) { 88 | s += (1 + // Address length. 89 | responses[i].addrlen); // Response. 90 | } 91 | 92 | return s; 93 | } 94 | } 95 | } 96 | } 97 | 98 | #endif // NET_MON_EVENT_DNS_H 99 | -------------------------------------------------------------------------------- /net/mon/event/events.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_EVENT_EVENTS_H 2 | #define NET_MON_EVENT_EVENTS_H 3 | 4 | #include "net/mon/event/icmp.h" 5 | #include "net/mon/event/udp.h" 6 | #include "net/mon/event/dns.h" 7 | #include "net/mon/event/tcp_begin.h" 8 | #include "net/mon/event/tcp_data.h" 9 | #include "net/mon/event/tcp_end.h" 10 | 11 | #endif // NET_MON_EVENT_EVENTS_H 12 | -------------------------------------------------------------------------------- /net/mon/event/file.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_EVENT_FILE_H 2 | #define NET_MON_EVENT_FILE_H 3 | 4 | #include 5 | #include 6 | #include "net/mon/event/util.h" 7 | 8 | namespace net { 9 | namespace mon { 10 | namespace event { 11 | // Event file. 12 | class file { 13 | public: 14 | // Event file header. 15 | class header { 16 | public: 17 | // Magic number. 18 | static constexpr const uint64_t magic = 0x6e65746d6f6e0001; 19 | 20 | // Timestamp of the first and last events. 21 | struct { 22 | uint64_t first; 23 | uint64_t last; 24 | } timestamp; 25 | 26 | // Header size. 27 | static constexpr const size_t size = sizeof(magic) + 28 | sizeof(timestamp); 29 | 30 | // Constructor. 31 | header() = default; 32 | 33 | // Destructor. 34 | ~header() = default; 35 | 36 | // Serialize. 37 | ssize_t serialize(void* buf, size_t size) const; 38 | 39 | // Deserialize. 40 | ssize_t deserialize(const void* buf, size_t size); 41 | }; 42 | }; 43 | 44 | inline ssize_t file::header::serialize(void* buf, size_t size) const 45 | { 46 | if (size >= header::size) { 47 | buf = event::serialize(buf, magic); 48 | buf = event::serialize(buf, timestamp.first); 49 | event::serialize(buf, timestamp.last); 50 | 51 | return header::size; 52 | } 53 | 54 | return -1; 55 | } 56 | 57 | inline ssize_t file::header::deserialize(const void* buf, size_t size) 58 | { 59 | uint64_t n; 60 | if ((size >= header::size) && (event::deserialize(n, buf) == magic)) { 61 | event::deserialize(timestamp.first, 62 | static_cast(buf) + sizeof(magic)); 63 | 64 | event::deserialize(timestamp.last, 65 | static_cast(buf) + 66 | sizeof(magic) + 67 | 8); 68 | 69 | return header::size; 70 | } 71 | 72 | return -1; 73 | } 74 | } 75 | } 76 | } 77 | 78 | #endif // NET_MON_EVENT_FILE_H 79 | -------------------------------------------------------------------------------- /net/mon/event/grammar/parser.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_EVENT_GRAMMAR_PARSER_H 2 | #define NET_MON_EVENT_GRAMMAR_PARSER_H 3 | 4 | #include "net/mon/event/grammar/expressions.h" 5 | #include "memory/unique_ptr.h" 6 | 7 | namespace net { 8 | namespace mon { 9 | namespace event { 10 | namespace grammar { 11 | // Parser. 12 | class parser { 13 | public: 14 | // Constructor. 15 | parser() = default; 16 | 17 | // Destructor. 18 | ~parser() = default; 19 | 20 | // Parse. 21 | static conditional_expression* parse(const char* s); 22 | 23 | private: 24 | // Maximum depth. 25 | static constexpr const size_t max_depth = 64; 26 | 27 | // Create event expression. 28 | static event_expression* create_expression(identifier id, 29 | relational_operator op, 30 | uint64_t n); 31 | 32 | static event_expression* create_expression(identifier id, 33 | relational_operator op, 34 | const char* s, 35 | size_t len); 36 | 37 | // Add expression. 38 | static bool add(memory::unique_ptr& dest, 39 | memory::unique_ptr& src, 40 | uint8_t logical_operator); 41 | 42 | // Get event type from string. 43 | static bool from_string(const char* s, size_t len, event::type& t); 44 | 45 | // Parse timestamp. 46 | static bool parse_timestamp(const char* s, 47 | size_t len, 48 | uint64_t& timestamp); 49 | 50 | // Is alphabetic. 51 | static bool isalpha(uint8_t c); 52 | 53 | // Is digit. 54 | static bool isdigit(uint8_t c); 55 | 56 | // Is alphanumeric. 57 | static bool isalnum(uint8_t c); 58 | }; 59 | 60 | inline bool parser::isalpha(uint8_t c) 61 | { 62 | return (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'))); 63 | } 64 | 65 | inline bool parser::isdigit(uint8_t c) 66 | { 67 | return ((c >= '0') && (c <= '9')); 68 | } 69 | 70 | inline bool parser::isalnum(uint8_t c) 71 | { 72 | return ((isalpha(c)) || (isdigit(c))); 73 | } 74 | } 75 | } 76 | } 77 | } 78 | 79 | #endif // NET_MON_EVENT_GRAMMAR_PARSER_H 80 | -------------------------------------------------------------------------------- /net/mon/event/icmp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "net/mon/event/icmp.h" 3 | 4 | bool net::mon::event::icmp::build(const void* buf, size_t len) 5 | { 6 | if ((base::build(buf, len)) && (size() == len)) { 7 | // Make 'b' point after the base event. 8 | const uint8_t* const b = static_cast(buf) + 9 | base::size(); 10 | 11 | // Extract ICMP type. 12 | icmp_type = *b; 13 | 14 | // Extract ICMP code. 15 | icmp_code = b[1]; 16 | 17 | // Extract transferred. 18 | deserialize(transferred, b + 2); 19 | 20 | return true; 21 | } 22 | 23 | return false; 24 | } 25 | 26 | bool net::mon::event::icmp::serialize(string::buffer& buf) const 27 | { 28 | // Allocate memory for the event. 29 | if (buf.allocate(maxlen)) { 30 | // Save a pointer to the position where the length will be stored. 31 | void* begin = buf.end(); 32 | 33 | // Serialize base event. 34 | void* b = base::serialize(begin, t); 35 | 36 | // Serialize ICMP type. 37 | b = event::serialize(b, icmp_type); 38 | 39 | // Serialize ICMP code. 40 | b = event::serialize(b, icmp_code); 41 | 42 | // Serialize transferred. 43 | b = event::serialize(b, transferred); 44 | 45 | // Compute length. 46 | size_t len = static_cast(b) - 47 | static_cast(begin); 48 | 49 | // Increment buffer length. 50 | buf.increment_length(len); 51 | 52 | // Store length. 53 | event::serialize(begin, static_cast(len)); 54 | 55 | return true; 56 | } 57 | 58 | return false; 59 | } 60 | 61 | void net::mon::event::icmp::print_human_readable(FILE* file, 62 | printer::format fmt, 63 | const char* srchost, 64 | const char* dsthost) const 65 | { 66 | base::print_human_readable(file, fmt, srchost, dsthost); 67 | 68 | if (fmt == printer::format::pretty_print) { 69 | fprintf(file, " Event type: ICMP\n"); 70 | 71 | fprintf(file, " ICMP type: %u\n", icmp_type); 72 | 73 | fprintf(file, " ICMP code: %u\n", icmp_code); 74 | 75 | fprintf(file, " Transferred: %u\n", transferred); 76 | } else { 77 | fprintf(file, "[ICMP] "); 78 | 79 | fprintf(file, "ICMP type: %u, ", icmp_type); 80 | 81 | fprintf(file, "ICMP code: %u, ", icmp_code); 82 | 83 | fprintf(file, "transferred: %u", transferred); 84 | } 85 | } 86 | 87 | void net::mon::event::icmp::print_json(FILE* file, 88 | printer::format fmt, 89 | const char* srchost, 90 | const char* dsthost) const 91 | { 92 | base::print_json(file, fmt, srchost, dsthost); 93 | 94 | if (fmt == printer::format::pretty_print) { 95 | fprintf(file, " \"event-type\": \"ICMP\",\n"); 96 | 97 | fprintf(file, " \"icmp-type\": %u,\n", icmp_type); 98 | 99 | fprintf(file, " \"icmp-code\": %u,\n", icmp_code); 100 | 101 | fprintf(file, " \"transferred\": %u\n", transferred); 102 | } else { 103 | fprintf(file, "\"event-type\":\"ICMP\","); 104 | 105 | fprintf(file, "\"icmp-type\":%u,", icmp_type); 106 | 107 | fprintf(file, "\"icmp-code\":%u,", icmp_code); 108 | 109 | fprintf(file, "\"transferred\":%u", transferred); 110 | } 111 | } 112 | 113 | void net::mon::event::icmp::print_csv(FILE* file, 114 | char separator, 115 | const char* srchost, 116 | const char* dsthost) const 117 | { 118 | base::print_csv(file, separator, srchost, dsthost); 119 | 120 | fprintf(file, "ICMP%c", separator); 121 | 122 | fprintf(file, "%u%c", icmp_type, separator); 123 | 124 | fprintf(file, "%u%c", icmp_code, separator); 125 | 126 | fprintf(file, "%u", transferred); 127 | } 128 | -------------------------------------------------------------------------------- /net/mon/event/icmp.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_EVENT_ICMP_H 2 | #define NET_MON_EVENT_ICMP_H 3 | 4 | #include "net/mon/event/base.h" 5 | #include "string/buffer.h" 6 | 7 | namespace net { 8 | namespace mon { 9 | namespace event { 10 | // 'ICMP' event. 11 | struct icmp : public base { 12 | static constexpr const type t = type::icmp; 13 | 14 | // ICMP type. 15 | uint8_t icmp_type; 16 | 17 | // ICMP code. 18 | uint8_t icmp_code; 19 | 20 | // # of bytes transferred. 21 | uint16_t transferred; 22 | 23 | // Build 'ICMP' event. 24 | bool build(const void* buf, size_t len); 25 | 26 | // Get size. 27 | size_t size() const; 28 | 29 | // Serialize. 30 | bool serialize(string::buffer& buf) const; 31 | 32 | // Print human readable. 33 | void print_human_readable(FILE* file, 34 | printer::format fmt, 35 | const char* srchost, 36 | const char* dsthost) const; 37 | 38 | // Print JSON. 39 | void print_json(FILE* file, 40 | printer::format fmt, 41 | const char* srchost, 42 | const char* dsthost) const; 43 | 44 | // Print CSV. 45 | void print_csv(FILE* file, 46 | char separator, 47 | const char* srchost, 48 | const char* dsthost) const; 49 | }; 50 | 51 | static_assert(sizeof(evlen_t) + sizeof(type) + sizeof(icmp) <= maxlen, 52 | "'maxlen' is smaller than sizeof(icmp)"); 53 | 54 | inline size_t icmp::size() const 55 | { 56 | return base::size() + // Size of the base event. 57 | 1 + // ICMP type. 58 | 1 + // ICMP code. 59 | 2; // Transferred. 60 | } 61 | } 62 | } 63 | } 64 | 65 | #endif // NET_MON_EVENT_ICMP_H 66 | -------------------------------------------------------------------------------- /net/mon/event/merger.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "net/mon/event/merger.h" 7 | #include "net/mon/event/reader.h" 8 | #include "fs/file.h" 9 | #include "string/buffer.h" 10 | 11 | bool net::mon::event::merger::merge(const char** infiles, 12 | size_t ninfiles, 13 | const char* outfile) 14 | { 15 | struct stat sbuf; 16 | if ((ninfiles >= 2) && (stat(outfile, &sbuf) < 0)) { 17 | reader* readers; 18 | if ((readers = new (std::nothrow) reader[ninfiles]) != nullptr) { 19 | // Open input files. 20 | for (size_t i = 0; i < ninfiles; i++) { 21 | if (!readers[i].open(infiles[i])) { 22 | delete [] readers; 23 | return false; 24 | } 25 | } 26 | 27 | // Open output file. 28 | fs::file output; 29 | if (output.open(outfile)) { 30 | struct entry { 31 | const void* event; 32 | size_t len; 33 | uint64_t timestamp; 34 | }; 35 | 36 | entry* entries; 37 | if ((entries = new (std::nothrow) entry[ninfiles]) != nullptr) { 38 | file::header header; 39 | header.timestamp.first = ULLONG_MAX; 40 | header.timestamp.last = 0; 41 | 42 | // Fill entries with the first event of each input file. 43 | for (size_t i = 0; i < ninfiles; i++) { 44 | if (readers[i].next(entries[i].event, 45 | entries[i].len, 46 | entries[i].timestamp)) { 47 | if (entries[i].timestamp < header.timestamp.first) { 48 | header.timestamp.first = entries[i].timestamp; 49 | } 50 | } else { 51 | entries[i].timestamp = ULLONG_MAX; 52 | } 53 | } 54 | 55 | string::buffer buf; 56 | 57 | uint64_t off = file::header::size; 58 | 59 | do { 60 | uint64_t timestamp = ULLONG_MAX; 61 | 62 | // Search event with the oldest timestamp. 63 | size_t idx = 0; 64 | for (size_t i = 0; i < ninfiles; i++) { 65 | if (entries[i].timestamp < timestamp) { 66 | timestamp = entries[i].timestamp; 67 | 68 | // Save index. 69 | idx = i; 70 | } 71 | } 72 | 73 | // If there are still events... 74 | if (timestamp != ULLONG_MAX) { 75 | // Add event to the buffer. 76 | if (buf.append(static_cast(entries[idx].event), 77 | entries[idx].len)) { 78 | header.timestamp.last = timestamp; 79 | 80 | // If the buffer is full... 81 | if (buf.length() >= max_buffer_size) { 82 | // Write buffer to disk. 83 | if (output.pwrite(buf.data(), buf.length(), off)) { 84 | off += buf.length(); 85 | 86 | buf.clear(); 87 | } else { 88 | output.close(); 89 | 90 | unlink(outfile); 91 | 92 | delete [] entries; 93 | delete [] readers; 94 | 95 | return false; 96 | } 97 | } 98 | 99 | // Read next event. 100 | if (!readers[idx].next(entries[idx].event, 101 | entries[idx].len, 102 | entries[idx].timestamp)) { 103 | entries[idx].timestamp = ULLONG_MAX; 104 | } 105 | } else { 106 | output.close(); 107 | 108 | unlink(outfile); 109 | 110 | delete [] entries; 111 | delete [] readers; 112 | 113 | return false; 114 | } 115 | } else { 116 | break; 117 | } 118 | } while (true); 119 | 120 | delete [] entries; 121 | delete [] readers; 122 | 123 | // If there are events... 124 | if (header.timestamp.first != ULLONG_MAX) { 125 | if ((buf.empty()) || 126 | (output.pwrite(buf.data(), buf.length(), off))) { 127 | // Serialize header. 128 | uint8_t buf[file::header::size]; 129 | header.serialize(buf, sizeof(buf)); 130 | 131 | // Write header at the beginning of the file. 132 | if (output.pwrite(buf, sizeof(buf), 0)) { 133 | return true; 134 | } 135 | } 136 | } 137 | 138 | output.close(); 139 | 140 | unlink(outfile); 141 | 142 | return (header.timestamp.first == ULLONG_MAX); 143 | } 144 | } 145 | 146 | delete [] readers; 147 | } 148 | } 149 | 150 | return false; 151 | } 152 | -------------------------------------------------------------------------------- /net/mon/event/merger.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_EVENT_MERGER_H 2 | #define NET_MON_EVENT_MERGER_H 3 | 4 | #include 5 | 6 | namespace net { 7 | namespace mon { 8 | namespace event { 9 | // Event merger. 10 | class merger { 11 | public: 12 | // Merge events in the input files into the output file. 13 | static bool merge(const char** infiles, 14 | size_t ninfiles, 15 | const char* outfile); 16 | 17 | private: 18 | // Maximum buffer size before writing the events to disk. 19 | static constexpr const size_t max_buffer_size = 64 * 1024; 20 | }; 21 | } 22 | } 23 | } 24 | 25 | #endif // NET_MON_EVENT_MERGER_H 26 | -------------------------------------------------------------------------------- /net/mon/event/printer/base.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_EVENT_PRINTER_BASE_H 2 | #define NET_MON_EVENT_PRINTER_BASE_H 3 | 4 | #include 5 | #include 6 | #include "net/mon/event/events.h" 7 | 8 | namespace net { 9 | namespace mon { 10 | namespace event { 11 | namespace printer { 12 | // Base event printer. 13 | class base { 14 | public: 15 | // Constructor. 16 | base() = default; 17 | 18 | // Destructor. 19 | virtual ~base(); 20 | 21 | // Open. 22 | bool open(const char* filename); 23 | 24 | // Set file. 25 | void file(FILE* f); 26 | 27 | // Close. 28 | void close(); 29 | 30 | // Print 'ICMP' event. 31 | virtual void print(uint64_t nevent, 32 | const event::icmp& ev, 33 | const char* srchost, 34 | const char* dsthost) = 0; 35 | 36 | // Print 'UDP' event. 37 | virtual void print(uint64_t nevent, 38 | const event::udp& ev, 39 | const char* srchost, 40 | const char* dsthost) = 0; 41 | 42 | // Print 'DNS' event. 43 | virtual void print(uint64_t nevent, 44 | const event::dns& ev, 45 | const char* srchost, 46 | const char* dsthost) = 0; 47 | 48 | // Print 'Begin TCP connection' event. 49 | virtual void print(uint64_t nevent, 50 | const event::tcp_begin& ev, 51 | const char* srchost, 52 | const char* dsthost) = 0; 53 | 54 | // Print 'TCP data' event. 55 | virtual void print(uint64_t nevent, 56 | const event::tcp_data& ev, 57 | const char* srchost, 58 | const char* dsthost) = 0; 59 | 60 | // Print 'End TCP connection' event. 61 | virtual void print(uint64_t nevent, 62 | const event::tcp_end& ev, 63 | const char* srchost, 64 | const char* dsthost) = 0; 65 | 66 | protected: 67 | // File. 68 | FILE* _M_file = nullptr; 69 | }; 70 | 71 | inline base::~base() 72 | { 73 | close(); 74 | } 75 | 76 | inline bool base::open(const char* filename) 77 | { 78 | return ((_M_file = fopen(filename, "w+")) != nullptr); 79 | } 80 | 81 | inline void base::file(FILE* f) 82 | { 83 | _M_file = f; 84 | } 85 | 86 | inline void base::close() 87 | { 88 | if ((_M_file) && (_M_file != stdout) && (_M_file != stderr)) { 89 | fclose(_M_file); 90 | _M_file = nullptr; 91 | } 92 | } 93 | } 94 | } 95 | } 96 | } 97 | 98 | #endif // NET_MON_EVENT_PRINTER_BASE_H 99 | -------------------------------------------------------------------------------- /net/mon/event/printer/csv.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_EVENT_PRINTER_CSV_H 2 | #define NET_MON_EVENT_PRINTER_CSV_H 3 | 4 | #include 5 | #include "net/mon/event/printer/base.h" 6 | 7 | namespace net { 8 | namespace mon { 9 | namespace event { 10 | namespace printer { 11 | // CSV printer. 12 | class csv : public base { 13 | public: 14 | // Default CSV separator. 15 | static constexpr const char default_separator = ','; 16 | 17 | // Constructor. 18 | csv(char separator = default_separator); 19 | 20 | // Print 'ICMP' event. 21 | void print(uint64_t nevent, 22 | const event::icmp& ev, 23 | const char* srchost, 24 | const char* dsthost) final; 25 | 26 | // Print 'UDP' event. 27 | void print(uint64_t nevent, 28 | const event::udp& ev, 29 | const char* srchost, 30 | const char* dsthost) final; 31 | 32 | // Print 'DNS' event. 33 | void print(uint64_t nevent, 34 | const event::dns& ev, 35 | const char* srchost, 36 | const char* dsthost) final; 37 | 38 | // Print 'Begin TCP connection' event. 39 | void print(uint64_t nevent, 40 | const event::tcp_begin& ev, 41 | const char* srchost, 42 | const char* dsthost) final; 43 | 44 | // Print 'TCP data' event. 45 | void print(uint64_t nevent, 46 | const event::tcp_data& ev, 47 | const char* srchost, 48 | const char* dsthost) final; 49 | 50 | // Print 'End TCP connection' event. 51 | void print(uint64_t nevent, 52 | const event::tcp_end& ev, 53 | const char* srchost, 54 | const char* dsthost) final; 55 | 56 | private: 57 | // CSV separator. 58 | char _M_separator; 59 | 60 | // Print generic event. 61 | template 62 | void print_(uint64_t nevent, 63 | const Event& ev, 64 | const char* srchost, 65 | const char* dsthost) const; 66 | }; 67 | 68 | inline csv::csv(char separator) 69 | : _M_separator(separator) 70 | { 71 | } 72 | 73 | inline void csv::print(uint64_t nevent, 74 | const event::icmp& ev, 75 | const char* srchost, 76 | const char* dsthost) 77 | { 78 | print_(nevent, ev, srchost, dsthost); 79 | } 80 | 81 | inline void csv::print(uint64_t nevent, 82 | const event::udp& ev, 83 | const char* srchost, 84 | const char* dsthost) 85 | { 86 | print_(nevent, ev, srchost, dsthost); 87 | } 88 | 89 | inline void csv::print(uint64_t nevent, 90 | const event::dns& ev, 91 | const char* srchost, 92 | const char* dsthost) 93 | { 94 | print_(nevent, ev, srchost, dsthost); 95 | } 96 | 97 | inline void csv::print(uint64_t nevent, 98 | const event::tcp_begin& ev, 99 | const char* srchost, 100 | const char* dsthost) 101 | { 102 | print_(nevent, ev, srchost, dsthost); 103 | } 104 | 105 | inline void csv::print(uint64_t nevent, 106 | const event::tcp_data& ev, 107 | const char* srchost, 108 | const char* dsthost) 109 | { 110 | print_(nevent, ev, srchost, dsthost); 111 | } 112 | 113 | inline void csv::print(uint64_t nevent, 114 | const event::tcp_end& ev, 115 | const char* srchost, 116 | const char* dsthost) 117 | { 118 | print_(nevent, ev, srchost, dsthost); 119 | } 120 | 121 | template 122 | inline void csv::print_(uint64_t nevent, 123 | const Event& ev, 124 | const char* srchost, 125 | const char* dsthost) const 126 | { 127 | fprintf(_M_file, "%" PRIu64 "%c", nevent, _M_separator); 128 | ev.print_csv(_M_file, _M_separator, srchost, dsthost); 129 | fprintf(_M_file, "\n"); 130 | } 131 | } 132 | } 133 | } 134 | } 135 | 136 | #endif // NET_MON_EVENT_PRINTER_CSV_H 137 | -------------------------------------------------------------------------------- /net/mon/event/printer/db/sqlite.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_EVENT_PRINTER_DB_SQLITE_H 2 | #define NET_MON_EVENT_PRINTER_DB_SQLITE_H 3 | 4 | #include 5 | #include 6 | #include "net/mon/event/printer/base.h" 7 | 8 | namespace net { 9 | namespace mon { 10 | namespace event { 11 | namespace printer { 12 | namespace db { 13 | // SQLite database printer. 14 | class sqlite : public base { 15 | public: 16 | // Constructor. 17 | sqlite(); 18 | 19 | // Destructor. 20 | ~sqlite(); 21 | 22 | // Open. 23 | bool open(const char* filename); 24 | 25 | // Close. 26 | bool close(); 27 | 28 | // Initialize. 29 | bool init(); 30 | 31 | // Print 'ICMP' event. 32 | void print(uint64_t nevent, 33 | const event::icmp& ev, 34 | const char* srchost, 35 | const char* dsthost) final; 36 | 37 | // Print 'UDP' event. 38 | void print(uint64_t nevent, 39 | const event::udp& ev, 40 | const char* srchost, 41 | const char* dsthost) final; 42 | 43 | // Print 'DNS' event. 44 | void print(uint64_t nevent, 45 | const event::dns& ev, 46 | const char* srchost, 47 | const char* dsthost) final; 48 | 49 | // Print 'Begin TCP connection' event. 50 | void print(uint64_t nevent, 51 | const event::tcp_begin& ev, 52 | const char* srchost, 53 | const char* dsthost) final; 54 | 55 | // Print 'TCP data' event. 56 | void print(uint64_t nevent, 57 | const event::tcp_data& ev, 58 | const char* srchost, 59 | const char* dsthost) final; 60 | 61 | // Print 'End TCP connection' event. 62 | void print(uint64_t nevent, 63 | const event::tcp_end& ev, 64 | const char* srchost, 65 | const char* dsthost) final; 66 | 67 | private: 68 | // SQLite database handle. 69 | sqlite3* _M_db = nullptr; 70 | 71 | // SQL statements. 72 | sqlite3_stmt* _M_statements[6]; 73 | 74 | char _M_src[INET6_ADDRSTRLEN]; 75 | char _M_dst[INET6_ADDRSTRLEN]; 76 | 77 | // Configure. 78 | bool configure(); 79 | 80 | // Create tables. 81 | bool create_tables(); 82 | 83 | // Create indices. 84 | bool create_indices(); 85 | 86 | // Prepare statements. 87 | bool prepare_statements(); 88 | 89 | // Bind values. 90 | template 91 | bool bind(size_t idx, const Event& ev); 92 | 93 | // Bind values. 94 | template 95 | bool bind(size_t idx, 96 | const Event& ev, 97 | const char* srchost, 98 | const char* dsthost); 99 | 100 | // Disable copy constructor and assignment operator. 101 | sqlite(const sqlite&) = delete; 102 | sqlite& operator=(const sqlite&) = delete; 103 | }; 104 | 105 | inline sqlite::sqlite() 106 | : _M_statements{nullptr, 107 | nullptr, 108 | nullptr, 109 | nullptr, 110 | nullptr, 111 | nullptr} 112 | { 113 | } 114 | 115 | inline sqlite::~sqlite() 116 | { 117 | // Close database. 118 | close(); 119 | } 120 | 121 | inline bool sqlite::open(const char* filename) 122 | { 123 | // Open database. 124 | if (sqlite3_open(filename, &_M_db) == SQLITE_OK) { 125 | return true; 126 | } 127 | 128 | close(); 129 | 130 | return false; 131 | } 132 | 133 | inline bool sqlite::init() 134 | { 135 | return ((configure()) && 136 | (create_tables()) && 137 | (create_indices()) && 138 | (prepare_statements())); 139 | } 140 | 141 | template 142 | bool sqlite::bind(size_t idx, const Event& ev) 143 | { 144 | if (ev.addrlen == 4) { 145 | if ((!inet_ntop(AF_INET, ev.saddr, _M_src, sizeof(_M_src))) || 146 | (!inet_ntop(AF_INET, ev.daddr, _M_dst, sizeof(_M_dst)))) { 147 | return false; 148 | } 149 | } else { 150 | if ((!inet_ntop(AF_INET6, ev.saddr, _M_src, sizeof(_M_src))) || 151 | (!inet_ntop(AF_INET6, ev.daddr, _M_dst, sizeof(_M_dst)))) { 152 | return false; 153 | } 154 | } 155 | 156 | return ((sqlite3_reset(_M_statements[idx]) == SQLITE_OK) && 157 | (sqlite3_clear_bindings(_M_statements[idx]) == SQLITE_OK) && 158 | (sqlite3_bind_int64(_M_statements[idx], 159 | 1, 160 | ev.timestamp) == SQLITE_OK) && 161 | (sqlite3_bind_text(_M_statements[idx], 162 | 2, 163 | _M_src, 164 | -1, 165 | SQLITE_STATIC) == SQLITE_OK) && 166 | (sqlite3_bind_text(_M_statements[idx], 167 | 3, 168 | _M_dst, 169 | -1, 170 | SQLITE_STATIC) == SQLITE_OK)); 171 | } 172 | 173 | template 174 | bool sqlite::bind(size_t idx, 175 | const Event& ev, 176 | const char* srchost, 177 | const char* dsthost) 178 | { 179 | return ((bind(idx, ev)) && 180 | (sqlite3_bind_text(_M_statements[idx], 181 | 4, 182 | srchost, 183 | -1, 184 | SQLITE_STATIC) == SQLITE_OK) && 185 | (sqlite3_bind_text(_M_statements[idx], 186 | 5, 187 | dsthost, 188 | -1, 189 | SQLITE_STATIC) == SQLITE_OK)); 190 | } 191 | } 192 | } 193 | } 194 | } 195 | } 196 | 197 | #endif // NET_MON_EVENT_PRINTER_DB_SQLITE_H 198 | -------------------------------------------------------------------------------- /net/mon/event/printer/format.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_EVENT_PRINTER_FORMAT_H 2 | #define NET_MON_EVENT_PRINTER_FORMAT_H 3 | 4 | namespace net { 5 | namespace mon { 6 | namespace event { 7 | namespace printer { 8 | // Print format. 9 | enum class format { 10 | pretty_print, 11 | compact 12 | }; 13 | } 14 | } 15 | } 16 | } 17 | 18 | #endif // NET_MON_EVENT_PRINTER_FORMAT_H 19 | -------------------------------------------------------------------------------- /net/mon/event/printer/human_readable.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_EVENT_PRINTER_HUMAN_READABLE_H 2 | #define NET_MON_EVENT_PRINTER_HUMAN_READABLE_H 3 | 4 | #include 5 | #include "net/mon/event/printer/base.h" 6 | #include "net/mon/event/printer/format.h" 7 | 8 | namespace net { 9 | namespace mon { 10 | namespace event { 11 | namespace printer { 12 | // Human readable printer. 13 | class human_readable : public base { 14 | public: 15 | // Constructor. 16 | human_readable(format fmt = format::pretty_print); 17 | 18 | // Print 'ICMP' event. 19 | void print(uint64_t nevent, 20 | const event::icmp& ev, 21 | const char* srchost, 22 | const char* dsthost) final; 23 | 24 | // Print 'UDP' event. 25 | void print(uint64_t nevent, 26 | const event::udp& ev, 27 | const char* srchost, 28 | const char* dsthost) final; 29 | 30 | // Print 'DNS' event. 31 | void print(uint64_t nevent, 32 | const event::dns& ev, 33 | const char* srchost, 34 | const char* dsthost) final; 35 | 36 | // Print 'Begin TCP connection' event. 37 | void print(uint64_t nevent, 38 | const event::tcp_begin& ev, 39 | const char* srchost, 40 | const char* dsthost) final; 41 | 42 | // Print 'TCP data' event. 43 | void print(uint64_t nevent, 44 | const event::tcp_data& ev, 45 | const char* srchost, 46 | const char* dsthost) final; 47 | 48 | // Print 'End TCP connection' event. 49 | void print(uint64_t nevent, 50 | const event::tcp_end& ev, 51 | const char* srchost, 52 | const char* dsthost) final; 53 | 54 | private: 55 | // Print format. 56 | format _M_format; 57 | 58 | // Print generic event. 59 | template 60 | void print_(uint64_t nevent, 61 | const Event& ev, 62 | const char* srchost, 63 | const char* dsthost) const; 64 | }; 65 | 66 | inline human_readable::human_readable(format fmt) 67 | : _M_format(fmt) 68 | { 69 | } 70 | 71 | inline void human_readable::print(uint64_t nevent, 72 | const event::icmp& ev, 73 | const char* srchost, 74 | const char* dsthost) 75 | { 76 | print_(nevent, ev, srchost, dsthost); 77 | } 78 | 79 | inline void human_readable::print(uint64_t nevent, 80 | const event::udp& ev, 81 | const char* srchost, 82 | const char* dsthost) 83 | { 84 | print_(nevent, ev, srchost, dsthost); 85 | } 86 | 87 | inline void human_readable::print(uint64_t nevent, 88 | const event::dns& ev, 89 | const char* srchost, 90 | const char* dsthost) 91 | { 92 | print_(nevent, ev, srchost, dsthost); 93 | } 94 | 95 | inline void human_readable::print(uint64_t nevent, 96 | const event::tcp_begin& ev, 97 | const char* srchost, 98 | const char* dsthost) 99 | { 100 | print_(nevent, ev, srchost, dsthost); 101 | } 102 | 103 | inline void human_readable::print(uint64_t nevent, 104 | const event::tcp_data& ev, 105 | const char* srchost, 106 | const char* dsthost) 107 | { 108 | print_(nevent, ev, srchost, dsthost); 109 | } 110 | 111 | inline void human_readable::print(uint64_t nevent, 112 | const event::tcp_end& ev, 113 | const char* srchost, 114 | const char* dsthost) 115 | { 116 | print_(nevent, ev, srchost, dsthost); 117 | } 118 | 119 | template 120 | inline void human_readable::print_(uint64_t nevent, 121 | const Event& ev, 122 | const char* srchost, 123 | const char* dsthost) const 124 | { 125 | if (_M_format == format::pretty_print) { 126 | fprintf(_M_file, "Event: %" PRIu64 "\n", nevent); 127 | } else { 128 | fprintf(_M_file, "[#%" PRIu64 "] ", nevent); 129 | } 130 | 131 | ev.print_human_readable(_M_file, _M_format, srchost, dsthost); 132 | fprintf(_M_file, "\n"); 133 | } 134 | } 135 | } 136 | } 137 | } 138 | 139 | #endif // NET_MON_EVENT_PRINTER_HUMAN_READABLE_H 140 | -------------------------------------------------------------------------------- /net/mon/event/printer/json.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_EVENT_PRINTER_JSON_H 2 | #define NET_MON_EVENT_PRINTER_JSON_H 3 | 4 | #include 5 | #include "net/mon/event/printer/base.h" 6 | #include "net/mon/event/printer/format.h" 7 | 8 | namespace net { 9 | namespace mon { 10 | namespace event { 11 | namespace printer { 12 | // JSON printer. 13 | class json : public base { 14 | public: 15 | // Constructor. 16 | json(format fmt = format::pretty_print, 17 | const char* prefix = nullptr, 18 | const char* suffix = nullptr); 19 | 20 | // Destructor. 21 | ~json(); 22 | 23 | // Print 'ICMP' event. 24 | void print(uint64_t nevent, 25 | const event::icmp& ev, 26 | const char* srchost, 27 | const char* dsthost) final; 28 | 29 | // Print 'UDP' event. 30 | void print(uint64_t nevent, 31 | const event::udp& ev, 32 | const char* srchost, 33 | const char* dsthost) final; 34 | 35 | // Print 'DNS' event. 36 | void print(uint64_t nevent, 37 | const event::dns& ev, 38 | const char* srchost, 39 | const char* dsthost) final; 40 | 41 | // Print 'Begin TCP connection' event. 42 | void print(uint64_t nevent, 43 | const event::tcp_begin& ev, 44 | const char* srchost, 45 | const char* dsthost) final; 46 | 47 | // Print 'TCP data' event. 48 | void print(uint64_t nevent, 49 | const event::tcp_data& ev, 50 | const char* srchost, 51 | const char* dsthost) final; 52 | 53 | // Print 'End TCP connection' event. 54 | void print(uint64_t nevent, 55 | const event::tcp_end& ev, 56 | const char* srchost, 57 | const char* dsthost) final; 58 | 59 | private: 60 | // Print format. 61 | format _M_format; 62 | 63 | const char* const _M_prefix; 64 | const char* const _M_suffix; 65 | 66 | size_t _M_nevents = 0; 67 | 68 | // Print generic event. 69 | template 70 | void print_(uint64_t nevent, 71 | const Event& ev, 72 | const char* srchost, 73 | const char* dsthost); 74 | }; 75 | 76 | inline json::json(format fmt, const char* prefix, const char* suffix) 77 | : _M_format(fmt), 78 | _M_prefix(prefix), 79 | _M_suffix(suffix) 80 | { 81 | } 82 | 83 | inline json::~json() 84 | { 85 | if (_M_file) { 86 | if (_M_format == format::pretty_print) { 87 | fprintf(_M_file, 88 | "%s\n]%s\n", 89 | (_M_nevents > 0) ? "" : "[", 90 | _M_suffix ? _M_suffix : ""); 91 | } else { 92 | fprintf(_M_file, 93 | "%s]%s", 94 | (_M_nevents > 0) ? "" : "[", 95 | _M_suffix ? _M_suffix : ""); 96 | } 97 | } 98 | } 99 | 100 | inline void json::print(uint64_t nevent, 101 | const event::icmp& ev, 102 | const char* srchost, 103 | const char* dsthost) 104 | { 105 | print_(nevent, ev, srchost, dsthost); 106 | } 107 | 108 | inline void json::print(uint64_t nevent, 109 | const event::udp& ev, 110 | const char* srchost, 111 | const char* dsthost) 112 | { 113 | print_(nevent, ev, srchost, dsthost); 114 | } 115 | 116 | inline void json::print(uint64_t nevent, 117 | const event::dns& ev, 118 | const char* srchost, 119 | const char* dsthost) 120 | { 121 | print_(nevent, ev, srchost, dsthost); 122 | } 123 | 124 | inline void json::print(uint64_t nevent, 125 | const event::tcp_begin& ev, 126 | const char* srchost, 127 | const char* dsthost) 128 | { 129 | print_(nevent, ev, srchost, dsthost); 130 | } 131 | 132 | inline void json::print(uint64_t nevent, 133 | const event::tcp_data& ev, 134 | const char* srchost, 135 | const char* dsthost) 136 | { 137 | print_(nevent, ev, srchost, dsthost); 138 | } 139 | 140 | inline void json::print(uint64_t nevent, 141 | const event::tcp_end& ev, 142 | const char* srchost, 143 | const char* dsthost) 144 | { 145 | print_(nevent, ev, srchost, dsthost); 146 | } 147 | 148 | template 149 | inline void json::print_(uint64_t nevent, 150 | const Event& ev, 151 | const char* srchost, 152 | const char* dsthost) 153 | { 154 | _M_nevents++; 155 | 156 | if (_M_format == format::pretty_print) { 157 | if (nevent > 1) { 158 | fprintf(_M_file, ",\n {\n"); 159 | } else { 160 | fprintf(_M_file, "%s[\n {\n", _M_prefix ? _M_prefix : ""); 161 | } 162 | 163 | fprintf(_M_file, " \"event-number\": %" PRIu64 ",\n", nevent); 164 | } else { 165 | if (nevent > 1) { 166 | fprintf(_M_file, ",{"); 167 | } else { 168 | fprintf(_M_file, "%s[{", _M_prefix ? _M_prefix : ""); 169 | } 170 | 171 | fprintf(_M_file, "\"event-number\":%" PRIu64 ",", nevent); 172 | } 173 | 174 | ev.print_json(_M_file, _M_format, srchost, dsthost); 175 | 176 | fprintf(_M_file, 177 | "%s}", 178 | (_M_format == format::pretty_print) ? " " : ""); 179 | } 180 | } 181 | } 182 | } 183 | } 184 | 185 | #endif // NET_MON_EVENT_PRINTER_JSON_H 186 | -------------------------------------------------------------------------------- /net/mon/event/reader.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_EVENT_READER_H 2 | #define NET_MON_EVENT_READER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "net/mon/event/events.h" 8 | #include "net/mon/event/file.h" 9 | #include "net/mon/event/printer/base.h" 10 | #include "net/mon/event/grammar/expressions.h" 11 | #include "net/mon/dns/inverted_cache.h" 12 | #include "net/mon/ipv4/address.h" 13 | #include "net/mon/ipv6/address.h" 14 | 15 | namespace net { 16 | namespace mon { 17 | namespace event { 18 | // Event reader. 19 | class reader { 20 | public: 21 | // Constructor. 22 | reader() = default; 23 | reader(printer::base* printer); 24 | 25 | // Destructor. 26 | ~reader(); 27 | 28 | // Open event file. 29 | bool open(const char* filename); 30 | 31 | // Close event file. 32 | void close(); 33 | 34 | // Get next event. 35 | bool next(const grammar::conditional_expression* expr = nullptr); 36 | 37 | // Get next event. 38 | bool next(const void*& event, size_t& len, uint64_t& timestamp); 39 | 40 | // Get timestamp of the first event. 41 | uint64_t first_timestamp() const; 42 | 43 | // Get timestamp of the last event. 44 | uint64_t last_timestamp() const; 45 | 46 | private: 47 | int _M_fd = -1; 48 | 49 | void* _M_base = MAP_FAILED; 50 | 51 | // Size of the file. 52 | size_t _M_filesize; 53 | 54 | // Pointer to the end. 55 | const uint8_t* _M_end; 56 | 57 | // Pointer to the next event. 58 | const uint8_t* _M_ptr; 59 | 60 | // Event file header. 61 | file::header _M_header; 62 | 63 | // Printer. 64 | printer::base* _M_printer = nullptr; 65 | 66 | // Event number. 67 | uint64_t _M_nevent = 0; 68 | 69 | // IPv4 DNS cache. 70 | mon::dns::inverted_cache _M_ipv4_dns_cache; 71 | 72 | // IPv6 DNS cache. 73 | mon::dns::inverted_cache _M_ipv6_dns_cache; 74 | 75 | // Get source host. 76 | template 77 | const char* source_host(const Event& ev) const; 78 | 79 | // Get destination host. 80 | template 81 | const char* destination_host(const Event& ev) const; 82 | 83 | // Get host. 84 | const char* host(const void* addr, size_t addrlen) const; 85 | 86 | // Disable copy constructor and assignment operator. 87 | reader(const reader&) = delete; 88 | reader& operator=(const reader&) = delete; 89 | }; 90 | 91 | inline reader::reader(printer::base* printer) 92 | : _M_printer(printer) 93 | { 94 | } 95 | 96 | inline reader::~reader() 97 | { 98 | close(); 99 | } 100 | 101 | inline void reader::close() 102 | { 103 | if (_M_base != MAP_FAILED) { 104 | munmap(_M_base, _M_filesize); 105 | _M_base = MAP_FAILED; 106 | } 107 | 108 | if (_M_fd != -1) { 109 | ::close(_M_fd); 110 | _M_fd = -1; 111 | } 112 | } 113 | 114 | inline uint64_t reader::first_timestamp() const 115 | { 116 | return _M_header.timestamp.first; 117 | } 118 | 119 | inline uint64_t reader::last_timestamp() const 120 | { 121 | return _M_header.timestamp.last; 122 | } 123 | 124 | template 125 | inline const char* reader::source_host(const Event& ev) const 126 | { 127 | return host(ev.saddr, ev.addrlen); 128 | } 129 | 130 | template 131 | inline const char* reader::destination_host(const Event& ev) const 132 | { 133 | return host(ev.daddr, ev.addrlen); 134 | } 135 | 136 | inline const char* reader::host(const void* addr, size_t addrlen) const 137 | { 138 | if (addrlen == 4) { 139 | ipv4::address address(addr); 140 | return _M_ipv4_dns_cache.host(address); 141 | } else { 142 | ipv6::address address(addr); 143 | return _M_ipv6_dns_cache.host(address); 144 | } 145 | } 146 | } 147 | } 148 | } 149 | 150 | #endif // NET_MON_EVENT_READER_H 151 | -------------------------------------------------------------------------------- /net/mon/event/tcp_begin.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "net/mon/event/tcp_begin.h" 3 | 4 | bool net::mon::event::tcp_begin::build(const void* buf, size_t len) 5 | { 6 | if ((base::build(buf, len)) && (size() == len)) { 7 | // Make 'b' point after the base event. 8 | const uint8_t* const b = static_cast(buf) + 9 | base::size(); 10 | 11 | // Extract source port. 12 | deserialize(sport, b); 13 | 14 | // Extract destination port. 15 | deserialize(dport, b + 2); 16 | 17 | return true; 18 | } 19 | 20 | return false; 21 | } 22 | 23 | bool net::mon::event::tcp_begin::serialize(string::buffer& buf) const 24 | { 25 | // Allocate memory for the event. 26 | if (buf.allocate(maxlen)) { 27 | // Save a pointer to the position where the length will be stored. 28 | void* begin = buf.end(); 29 | 30 | // Serialize base event. 31 | void* b = base::serialize(begin, t); 32 | 33 | // Serialize source port. 34 | b = event::serialize(b, sport); 35 | 36 | // Serialize destination port. 37 | b = event::serialize(b, dport); 38 | 39 | // Compute length. 40 | size_t len = static_cast(b) - 41 | static_cast(begin); 42 | 43 | // Increment buffer length. 44 | buf.increment_length(len); 45 | 46 | // Store length. 47 | event::serialize(begin, static_cast(len)); 48 | 49 | return true; 50 | } 51 | 52 | return false; 53 | } 54 | 55 | void net::mon::event::tcp_begin::print_human_readable(FILE* file, 56 | printer::format fmt, 57 | const char* srchost, 58 | const char* dsthost) const 59 | { 60 | base::print_human_readable(file, fmt, srchost, dsthost, sport, dport); 61 | 62 | if (fmt == printer::format::pretty_print) { 63 | fprintf(file, " Event type: 'Begin TCP connection'\n"); 64 | } else { 65 | fprintf(file, "[Begin TCP connection]"); 66 | } 67 | } 68 | 69 | void net::mon::event::tcp_begin::print_json(FILE* file, 70 | printer::format fmt, 71 | const char* srchost, 72 | const char* dsthost) const 73 | { 74 | base::print_json(file, fmt, srchost, dsthost, sport, dport); 75 | 76 | if (fmt == printer::format::pretty_print) { 77 | fprintf(file, " \"event-type\": \"begin-tcp-connection\"\n"); 78 | } else { 79 | fprintf(file, "\"event-type\":\"begin-tcp-connection\""); 80 | } 81 | } 82 | 83 | void net::mon::event::tcp_begin::print_csv(FILE* file, 84 | char separator, 85 | const char* srchost, 86 | const char* dsthost) const 87 | { 88 | base::print_csv(file, separator, srchost, dsthost, sport, dport); 89 | 90 | fprintf(file, "begin-tcp-connection"); 91 | } 92 | -------------------------------------------------------------------------------- /net/mon/event/tcp_begin.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_EVENT_TCP_BEGIN_H 2 | #define NET_MON_EVENT_TCP_BEGIN_H 3 | 4 | #include "net/mon/event/base.h" 5 | #include "string/buffer.h" 6 | 7 | namespace net { 8 | namespace mon { 9 | namespace event { 10 | // 'Begin TCP connection' event. 11 | struct tcp_begin : public base { 12 | static constexpr const type t = type::tcp_begin; 13 | 14 | // Source port. 15 | in_port_t sport; 16 | 17 | // Destination port. 18 | in_port_t dport; 19 | 20 | // Build 'Begin TCP connection' event. 21 | bool build(const void* buf, size_t len); 22 | 23 | // Get size. 24 | size_t size() const; 25 | 26 | // Serialize. 27 | bool serialize(string::buffer& buf) const; 28 | 29 | // Print human readable. 30 | void print_human_readable(FILE* file, 31 | printer::format fmt, 32 | const char* srchost, 33 | const char* dsthost) const; 34 | 35 | // Print JSON. 36 | void print_json(FILE* file, 37 | printer::format fmt, 38 | const char* srchost, 39 | const char* dsthost) const; 40 | 41 | // Print CSV. 42 | void print_csv(FILE* file, 43 | char separator, 44 | const char* srchost, 45 | const char* dsthost) const; 46 | }; 47 | 48 | static_assert(sizeof(evlen_t) + 49 | sizeof(type) + 50 | sizeof(tcp_begin) <= maxlen, 51 | "'maxlen' is smaller than sizeof(tcp_begin)"); 52 | 53 | inline size_t tcp_begin::size() const 54 | { 55 | return base::size() + // Size of the base event. 56 | sizeof(in_port_t) + // Source port. 57 | sizeof(in_port_t); // Destination port. 58 | } 59 | } 60 | } 61 | } 62 | 63 | #endif // NET_MON_EVENT_TCP_BEGIN_H 64 | -------------------------------------------------------------------------------- /net/mon/event/tcp_data.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "net/mon/event/tcp_data.h" 4 | 5 | bool net::mon::event::tcp_data::build(const void* buf, size_t len) 6 | { 7 | if ((base::build(buf, len)) && (size() == len)) { 8 | // Make 'b' point after the base event. 9 | const uint8_t* const b = static_cast(buf) + 10 | base::size(); 11 | 12 | // Extract source port. 13 | deserialize(sport, b); 14 | 15 | // Extract destination port. 16 | deserialize(dport, b + 2); 17 | 18 | // Extract creation timestamp. 19 | deserialize(creation, b + 4); 20 | 21 | // Extract payload. 22 | deserialize(payload, b + 12); 23 | 24 | return true; 25 | } 26 | 27 | return false; 28 | } 29 | 30 | bool net::mon::event::tcp_data::serialize(string::buffer& buf) const 31 | { 32 | // Allocate memory for the event. 33 | if (buf.allocate(maxlen)) { 34 | // Save a pointer to the position where the length will be stored. 35 | void* begin = buf.end(); 36 | 37 | // Serialize base event. 38 | void* b = base::serialize(begin, t); 39 | 40 | // Serialize source port. 41 | b = event::serialize(b, sport); 42 | 43 | // Serialize destination port. 44 | b = event::serialize(b, dport); 45 | 46 | // Serialize creation timestamp. 47 | b = event::serialize(b, creation); 48 | 49 | // Serialize payload. 50 | b = event::serialize(b, payload); 51 | 52 | // Compute length. 53 | size_t len = static_cast(b) - 54 | static_cast(begin); 55 | 56 | // Increment buffer length. 57 | buf.increment_length(len); 58 | 59 | // Store length. 60 | event::serialize(begin, static_cast(len)); 61 | 62 | return true; 63 | } 64 | 65 | return false; 66 | } 67 | 68 | void net::mon::event::tcp_data::print_human_readable(FILE* file, 69 | printer::format fmt, 70 | const char* srchost, 71 | const char* dsthost) const 72 | { 73 | base::print_human_readable(file, fmt, srchost, dsthost, sport, dport); 74 | 75 | time_t sec = creation / 1000000; 76 | suseconds_t usec = creation % 1000000; 77 | 78 | struct tm tm; 79 | localtime_r(&sec, &tm); 80 | 81 | if (fmt == printer::format::pretty_print) { 82 | fprintf(file, " Event type: 'TCP data'\n"); 83 | 84 | fprintf(file, 85 | " Creation: %04u/%02u/%02u %02u:%02u:%02u.%06ld\n", 86 | 1900 + tm.tm_year, 87 | 1 + tm.tm_mon, 88 | tm.tm_mday, 89 | tm.tm_hour, 90 | tm.tm_min, 91 | tm.tm_sec, 92 | usec); 93 | 94 | fprintf(file, " Payload: %u\n", payload); 95 | } else { 96 | fprintf(file, "[TCP data] "); 97 | 98 | fprintf(file, 99 | "Creation: %04u/%02u/%02u %02u:%02u:%02u.%06ld, ", 100 | 1900 + tm.tm_year, 101 | 1 + tm.tm_mon, 102 | tm.tm_mday, 103 | tm.tm_hour, 104 | tm.tm_min, 105 | tm.tm_sec, 106 | usec); 107 | 108 | fprintf(file, "Payload: %u", payload); 109 | } 110 | } 111 | 112 | void net::mon::event::tcp_data::print_json(FILE* file, 113 | printer::format fmt, 114 | const char* srchost, 115 | const char* dsthost) const 116 | { 117 | base::print_json(file, fmt, srchost, dsthost, sport, dport); 118 | 119 | time_t sec = creation / 1000000; 120 | suseconds_t usec = creation % 1000000; 121 | 122 | struct tm tm; 123 | localtime_r(&sec, &tm); 124 | 125 | if (fmt == printer::format::pretty_print) { 126 | fprintf(file, " \"event-type\": \"tcp-data\",\n"); 127 | 128 | fprintf(file, 129 | " \"creation\": \"%04u/%02u/%02u %02u:%02u:%02u.%06ld\",\n", 130 | 1900 + tm.tm_year, 131 | 1 + tm.tm_mon, 132 | tm.tm_mday, 133 | tm.tm_hour, 134 | tm.tm_min, 135 | tm.tm_sec, 136 | usec); 137 | 138 | fprintf(file, " \"payload\": %u\n", payload); 139 | } else { 140 | fprintf(file, "\"event-type\":\"tcp-data\","); 141 | 142 | fprintf(file, 143 | "\"creation\":\"%04u/%02u/%02u %02u:%02u:%02u.%06ld\",", 144 | 1900 + tm.tm_year, 145 | 1 + tm.tm_mon, 146 | tm.tm_mday, 147 | tm.tm_hour, 148 | tm.tm_min, 149 | tm.tm_sec, 150 | usec); 151 | 152 | fprintf(file, "\"payload\":%u", payload); 153 | } 154 | } 155 | 156 | void net::mon::event::tcp_data::print_csv(FILE* file, 157 | char separator, 158 | const char* srchost, 159 | const char* dsthost) const 160 | { 161 | base::print_csv(file, separator, srchost, dsthost, sport, dport); 162 | 163 | time_t sec = creation / 1000000; 164 | suseconds_t usec = creation % 1000000; 165 | 166 | struct tm tm; 167 | localtime_r(&sec, &tm); 168 | 169 | fprintf(file, "tcp-data%c", separator); 170 | 171 | fprintf(file, 172 | "%04u/%02u/%02u %02u:%02u:%02u.%06ld%c", 173 | 1900 + tm.tm_year, 174 | 1 + tm.tm_mon, 175 | tm.tm_mday, 176 | tm.tm_hour, 177 | tm.tm_min, 178 | tm.tm_sec, 179 | usec, 180 | separator); 181 | 182 | fprintf(file, "%u", payload); 183 | } 184 | -------------------------------------------------------------------------------- /net/mon/event/tcp_data.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_EVENT_TCP_DATA_H 2 | #define NET_MON_EVENT_TCP_DATA_H 3 | 4 | #include "net/mon/event/base.h" 5 | #include "string/buffer.h" 6 | 7 | namespace net { 8 | namespace mon { 9 | namespace event { 10 | // 'TCP data' event. 11 | struct tcp_data : public base { 12 | static constexpr const type t = type::tcp_data; 13 | 14 | // Source port. 15 | in_port_t sport; 16 | 17 | // Destination port. 18 | in_port_t dport; 19 | 20 | // Creation timestamp. 21 | uint64_t creation; 22 | 23 | // # of bytes of payload. 24 | uint16_t payload; 25 | 26 | // Build 'TCP data' event. 27 | bool build(const void* buf, size_t len); 28 | 29 | // Get size. 30 | size_t size() const; 31 | 32 | // Serialize. 33 | bool serialize(string::buffer& buf) const; 34 | 35 | // Print human readable. 36 | void print_human_readable(FILE* file, 37 | printer::format fmt, 38 | const char* srchost, 39 | const char* dsthost) const; 40 | 41 | // Print JSON. 42 | void print_json(FILE* file, 43 | printer::format fmt, 44 | const char* srchost, 45 | const char* dsthost) const; 46 | 47 | // Print CSV. 48 | void print_csv(FILE* file, 49 | char separator, 50 | const char* srchost, 51 | const char* dsthost) const; 52 | }; 53 | 54 | static_assert(sizeof(evlen_t) + sizeof(type) + sizeof(tcp_data) <= maxlen, 55 | "'maxlen' is smaller than sizeof(tcp_data)"); 56 | 57 | inline size_t tcp_data::size() const 58 | { 59 | return base::size() + // Size of the base event. 60 | sizeof(in_port_t) + // Source port. 61 | sizeof(in_port_t) + // Destination port. 62 | 8 + // Creation timestamp. 63 | 2; // Payload. 64 | } 65 | } 66 | } 67 | } 68 | 69 | #endif // NET_MON_EVENT_TCP_DATA_H 70 | -------------------------------------------------------------------------------- /net/mon/event/tcp_end.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "net/mon/event/tcp_end.h" 5 | 6 | bool net::mon::event::tcp_end::build(const void* buf, size_t len) 7 | { 8 | if ((base::build(buf, len)) && (size() == len)) { 9 | // Make 'b' point after the base event. 10 | const uint8_t* const b = static_cast(buf) + 11 | base::size(); 12 | 13 | // Extract source port. 14 | deserialize(sport, b); 15 | 16 | // Extract destination port. 17 | deserialize(dport, b + 2); 18 | 19 | // Extract creation timestamp. 20 | deserialize(creation, b + 4); 21 | 22 | // Extract number of bytes sent by the client. 23 | deserialize(transferred_client, b + 12); 24 | 25 | // Extract number of bytes sent by the server. 26 | deserialize(transferred_server, b + 20); 27 | 28 | return true; 29 | } 30 | 31 | return false; 32 | } 33 | 34 | bool net::mon::event::tcp_end::serialize(string::buffer& buf) const 35 | { 36 | // Allocate memory for the event. 37 | if (buf.allocate(maxlen)) { 38 | // Save a pointer to the position where the length will be stored. 39 | void* begin = buf.end(); 40 | 41 | // Serialize base event. 42 | void* b = base::serialize(begin, t); 43 | 44 | // Serialize source port. 45 | b = event::serialize(b, sport); 46 | 47 | // Serialize destination port. 48 | b = event::serialize(b, dport); 49 | 50 | // Serialize creation timestamp. 51 | b = event::serialize(b, creation); 52 | 53 | // Serialize number of bytes sent by the client. 54 | b = event::serialize(b, transferred_client); 55 | 56 | // Serialize number of bytes sent by the server. 57 | b = event::serialize(b, transferred_server); 58 | 59 | // Compute length. 60 | size_t len = static_cast(b) - 61 | static_cast(begin); 62 | 63 | // Increment buffer length. 64 | buf.increment_length(len); 65 | 66 | // Store length. 67 | event::serialize(begin, static_cast(len)); 68 | 69 | return true; 70 | } 71 | 72 | return false; 73 | } 74 | 75 | void net::mon::event::tcp_end::print_human_readable(FILE* file, 76 | printer::format fmt, 77 | const char* srchost, 78 | const char* dsthost) const 79 | { 80 | base::print_human_readable(file, fmt, srchost, dsthost, sport, dport); 81 | 82 | time_t sec = creation / 1000000; 83 | suseconds_t usec = creation % 1000000; 84 | 85 | struct tm tm; 86 | localtime_r(&sec, &tm); 87 | 88 | if (fmt == printer::format::pretty_print) { 89 | fprintf(file, " Event type: 'End TCP connection'\n"); 90 | 91 | fprintf(file, 92 | " Creation: %04u/%02u/%02u %02u:%02u:%02u.%06ld\n", 93 | 1900 + tm.tm_year, 94 | 1 + tm.tm_mon, 95 | tm.tm_mday, 96 | tm.tm_hour, 97 | tm.tm_min, 98 | tm.tm_sec, 99 | usec); 100 | 101 | fprintf(file, " Transferred client: %" PRIu64 "\n", transferred_client); 102 | 103 | fprintf(file, " Transferred server: %" PRIu64 "\n", transferred_server); 104 | } else { 105 | fprintf(file, "[End TCP connection] "); 106 | 107 | fprintf(file, 108 | "Creation: %04u/%02u/%02u %02u:%02u:%02u.%06ld, ", 109 | 1900 + tm.tm_year, 110 | 1 + tm.tm_mon, 111 | tm.tm_mday, 112 | tm.tm_hour, 113 | tm.tm_min, 114 | tm.tm_sec, 115 | usec); 116 | 117 | fprintf(file, "transferred client: %" PRIu64 ", ", transferred_client); 118 | 119 | fprintf(file, "transferred server: %" PRIu64, transferred_server); 120 | } 121 | } 122 | 123 | void net::mon::event::tcp_end::print_json(FILE* file, 124 | printer::format fmt, 125 | const char* srchost, 126 | const char* dsthost) const 127 | { 128 | base::print_json(file, fmt, srchost, dsthost, sport, dport); 129 | 130 | time_t sec = creation / 1000000; 131 | suseconds_t usec = creation % 1000000; 132 | 133 | struct tm tm; 134 | localtime_r(&sec, &tm); 135 | 136 | if (fmt == printer::format::pretty_print) { 137 | fprintf(file, " \"event-type\": \"end-tcp-connection\",\n"); 138 | 139 | fprintf(file, 140 | " \"creation\": \"%04u/%02u/%02u %02u:%02u:%02u.%06ld\",\n", 141 | 1900 + tm.tm_year, 142 | 1 + tm.tm_mon, 143 | tm.tm_mday, 144 | tm.tm_hour, 145 | tm.tm_min, 146 | tm.tm_sec, 147 | usec); 148 | 149 | fprintf(file, 150 | " \"transferred-client\": %" PRIu64 ",\n", 151 | transferred_client); 152 | 153 | fprintf(file, 154 | " \"transferred-server\": %" PRIu64 "\n", 155 | transferred_server); 156 | } else { 157 | fprintf(file, "\"event-type\":\"end-tcp-connection\","); 158 | 159 | fprintf(file, 160 | "\"creation\":\"%04u/%02u/%02u %02u:%02u:%02u.%06ld\",", 161 | 1900 + tm.tm_year, 162 | 1 + tm.tm_mon, 163 | tm.tm_mday, 164 | tm.tm_hour, 165 | tm.tm_min, 166 | tm.tm_sec, 167 | usec); 168 | 169 | fprintf(file, "\"transferred-client\":%" PRIu64 ",", transferred_client); 170 | 171 | fprintf(file, "\"transferred-server\":%" PRIu64, transferred_server); 172 | } 173 | } 174 | 175 | void net::mon::event::tcp_end::print_csv(FILE* file, 176 | char separator, 177 | const char* srchost, 178 | const char* dsthost) const 179 | { 180 | base::print_csv(file, separator, srchost, dsthost, sport, dport); 181 | 182 | time_t sec = creation / 1000000; 183 | suseconds_t usec = creation % 1000000; 184 | 185 | struct tm tm; 186 | localtime_r(&sec, &tm); 187 | 188 | fprintf(file, "end-tcp-connection%c", separator); 189 | 190 | fprintf(file, 191 | "%04u/%02u/%02u %02u:%02u:%02u.%06ld%c", 192 | 1900 + tm.tm_year, 193 | 1 + tm.tm_mon, 194 | tm.tm_mday, 195 | tm.tm_hour, 196 | tm.tm_min, 197 | tm.tm_sec, 198 | usec, 199 | separator); 200 | 201 | fprintf(file, "%" PRIu64 "%c", transferred_client, separator); 202 | 203 | fprintf(file, "%" PRIu64, transferred_server); 204 | } 205 | -------------------------------------------------------------------------------- /net/mon/event/tcp_end.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_EVENT_TCP_END_H 2 | #define NET_MON_EVENT_TCP_END_H 3 | 4 | #include "net/mon/event/base.h" 5 | #include "string/buffer.h" 6 | 7 | namespace net { 8 | namespace mon { 9 | namespace event { 10 | // 'End TCP connection' event. 11 | struct tcp_end : public base { 12 | static constexpr const type t = type::tcp_end; 13 | 14 | // Source port. 15 | in_port_t sport; 16 | 17 | // Destination port. 18 | in_port_t dport; 19 | 20 | // Creation timestamp. 21 | uint64_t creation; 22 | 23 | // # of bytes sent by the client. 24 | uint64_t transferred_client; 25 | 26 | // # of bytes sent by the server. 27 | uint64_t transferred_server; 28 | 29 | // Build 'End TCP connection' event. 30 | bool build(const void* buf, size_t len); 31 | 32 | // Get size. 33 | size_t size() const; 34 | 35 | // Serialize. 36 | bool serialize(string::buffer& buf) const; 37 | 38 | // Print human readable. 39 | void print_human_readable(FILE* file, 40 | printer::format fmt, 41 | const char* srchost, 42 | const char* dsthost) const; 43 | 44 | // Print JSON. 45 | void print_json(FILE* file, 46 | printer::format fmt, 47 | const char* srchost, 48 | const char* dsthost) const; 49 | 50 | // Print CSV. 51 | void print_csv(FILE* file, 52 | char separator, 53 | const char* srchost, 54 | const char* dsthost) const; 55 | }; 56 | 57 | static_assert(sizeof(evlen_t) + sizeof(type) + sizeof(tcp_end) <= maxlen, 58 | "'maxlen' is smaller than sizeof(tcp_end)"); 59 | 60 | inline size_t tcp_end::size() const 61 | { 62 | return base::size() + // Size of the base event. 63 | sizeof(in_port_t) + // Source port. 64 | sizeof(in_port_t) + // Destination port. 65 | 8 + // Creation timestamp. 66 | 8 + // # of bytes sent by the client. 67 | 8; // # of bytes sent by the server. 68 | } 69 | } 70 | } 71 | } 72 | 73 | #endif // NET_MON_EVENT_TCP_END_H 74 | -------------------------------------------------------------------------------- /net/mon/event/udp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "net/mon/event/udp.h" 3 | 4 | bool net::mon::event::udp::build(const void* buf, size_t len) 5 | { 6 | if ((base::build(buf, len)) && (size() == len)) { 7 | // Make 'b' point after the base event. 8 | const uint8_t* const b = static_cast(buf) + 9 | base::size(); 10 | 11 | // Extract source port. 12 | deserialize(sport, b); 13 | 14 | // Extract destination port. 15 | deserialize(dport, b + 2); 16 | 17 | // Extract transferred. 18 | deserialize(transferred, b + 4); 19 | 20 | return true; 21 | } 22 | 23 | return false; 24 | } 25 | 26 | bool net::mon::event::udp::serialize(string::buffer& buf) const 27 | { 28 | // Allocate memory for the event. 29 | if (buf.allocate(maxlen)) { 30 | // Save a pointer to the position where the length will be stored. 31 | void* begin = buf.end(); 32 | 33 | // Serialize base event. 34 | void* b = base::serialize(begin, t); 35 | 36 | // Serialize source port. 37 | b = event::serialize(b, sport); 38 | 39 | // Serialize destination port. 40 | b = event::serialize(b, dport); 41 | 42 | // Serialize transferred. 43 | b = event::serialize(b, transferred); 44 | 45 | // Compute length. 46 | size_t len = static_cast(b) - 47 | static_cast(begin); 48 | 49 | // Increment buffer length. 50 | buf.increment_length(len); 51 | 52 | // Store length. 53 | event::serialize(begin, static_cast(len)); 54 | 55 | return true; 56 | } 57 | 58 | return false; 59 | } 60 | 61 | void net::mon::event::udp::print_human_readable(FILE* file, 62 | printer::format fmt, 63 | const char* srchost, 64 | const char* dsthost) const 65 | { 66 | base::print_human_readable(file, fmt, srchost, dsthost, sport, dport); 67 | 68 | if (fmt == printer::format::pretty_print) { 69 | fprintf(file, " Event type: UDP\n"); 70 | 71 | fprintf(file, " Transferred: %u\n", transferred); 72 | } else { 73 | fprintf(file, "[UDP] "); 74 | 75 | fprintf(file, "Transferred: %u", transferred); 76 | } 77 | } 78 | 79 | void net::mon::event::udp::print_json(FILE* file, 80 | printer::format fmt, 81 | const char* srchost, 82 | const char* dsthost) const 83 | { 84 | base::print_json(file, fmt, srchost, dsthost, sport, dport); 85 | 86 | if (fmt == printer::format::pretty_print) { 87 | fprintf(file, " \"event-type\": \"UDP\",\n"); 88 | 89 | fprintf(file, " \"transferred\": %u\n", transferred); 90 | } else { 91 | fprintf(file, "\"event-type\":\"UDP\","); 92 | 93 | fprintf(file, "\"transferred\":%u", transferred); 94 | } 95 | } 96 | 97 | void net::mon::event::udp::print_csv(FILE* file, 98 | char separator, 99 | const char* srchost, 100 | const char* dsthost) const 101 | { 102 | base::print_csv(file, separator, srchost, dsthost, sport, dport); 103 | 104 | fprintf(file, "UDP%c", separator); 105 | 106 | fprintf(file, "%u", transferred); 107 | } 108 | -------------------------------------------------------------------------------- /net/mon/event/udp.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_EVENT_UDP_H 2 | #define NET_MON_EVENT_UDP_H 3 | 4 | #include "net/mon/event/base.h" 5 | #include "string/buffer.h" 6 | 7 | namespace net { 8 | namespace mon { 9 | namespace event { 10 | // 'UDP' event. 11 | struct udp : public base { 12 | static constexpr const type t = type::udp; 13 | 14 | // Source port. 15 | in_port_t sport; 16 | 17 | // Destination port. 18 | in_port_t dport; 19 | 20 | // # of bytes transferred. 21 | uint16_t transferred; 22 | 23 | // Build 'UDP' event. 24 | bool build(const void* buf, size_t len); 25 | 26 | // Get size. 27 | size_t size() const; 28 | 29 | // Serialize. 30 | bool serialize(string::buffer& buf) const; 31 | 32 | // Print human readable. 33 | void print_human_readable(FILE* file, 34 | printer::format fmt, 35 | const char* srchost, 36 | const char* dsthost) const; 37 | 38 | // Print JSON. 39 | void print_json(FILE* file, 40 | printer::format fmt, 41 | const char* srchost, 42 | const char* dsthost) const; 43 | 44 | // Print CSV. 45 | void print_csv(FILE* file, 46 | char separator, 47 | const char* srchost, 48 | const char* dsthost) const; 49 | }; 50 | 51 | static_assert(sizeof(evlen_t) + sizeof(type) + sizeof(udp) <= maxlen, 52 | "'maxlen' is smaller than sizeof(udp)"); 53 | 54 | inline size_t udp::size() const 55 | { 56 | return base::size() + // Size of the base event. 57 | sizeof(in_port_t) + // Source port. 58 | sizeof(in_port_t) + // Destination port. 59 | 2; // Transferred. 60 | } 61 | } 62 | } 63 | } 64 | 65 | #endif // NET_MON_EVENT_UDP_H 66 | -------------------------------------------------------------------------------- /net/mon/event/util.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_EVENT_UTIL_H 2 | #define NET_MON_EVENT_UTIL_H 3 | 4 | #include 5 | 6 | namespace net { 7 | namespace mon { 8 | namespace event { 9 | static inline void* serialize(void* buf, uint8_t n) 10 | { 11 | static_cast(buf)[0] = n; 12 | 13 | return static_cast(buf) + sizeof(n); 14 | } 15 | 16 | static inline void* serialize(void* buf, uint16_t n) 17 | { 18 | static_cast(buf)[0] = (n >> 8) & 0xff; 19 | static_cast(buf)[1] = n & 0xff; 20 | 21 | return static_cast(buf) + sizeof(n); 22 | } 23 | 24 | static inline void* serialize(void* buf, uint32_t n) 25 | { 26 | static_cast(buf)[0] = (n >> 24) & 0xff; 27 | static_cast(buf)[1] = (n >> 16) & 0xff; 28 | static_cast(buf)[2] = (n >> 8) & 0xff; 29 | static_cast(buf)[3] = n & 0xff; 30 | 31 | return static_cast(buf) + sizeof(n); 32 | } 33 | 34 | static inline void* serialize(void* buf, uint64_t n) 35 | { 36 | static_cast(buf)[0] = (n >> 56) & 0xff; 37 | static_cast(buf)[1] = (n >> 48) & 0xff; 38 | static_cast(buf)[2] = (n >> 40) & 0xff; 39 | static_cast(buf)[3] = (n >> 32) & 0xff; 40 | static_cast(buf)[4] = (n >> 24) & 0xff; 41 | static_cast(buf)[5] = (n >> 16) & 0xff; 42 | static_cast(buf)[6] = (n >> 8) & 0xff; 43 | static_cast(buf)[7] = n & 0xff; 44 | 45 | return static_cast(buf) + sizeof(n); 46 | } 47 | 48 | static inline uint8_t deserialize(uint8_t& n, const void* buf) 49 | { 50 | n = *static_cast(buf); 51 | return n; 52 | } 53 | 54 | static inline uint16_t deserialize(uint16_t& n, const void* buf) 55 | { 56 | n = (static_cast(static_cast(buf)[0]) << 8) | 57 | static_cast(static_cast(buf)[1]); 58 | 59 | return n; 60 | } 61 | 62 | static inline uint32_t deserialize(uint32_t& n, const void* buf) 63 | { 64 | n = (static_cast(static_cast(buf)[0]) << 24) | 65 | (static_cast(static_cast(buf)[1]) << 16) | 66 | (static_cast(static_cast(buf)[2]) << 8) | 67 | static_cast(static_cast(buf)[3]); 68 | 69 | return n; 70 | } 71 | 72 | static inline uint64_t deserialize(uint64_t& n, const void* buf) 73 | { 74 | n = (static_cast(static_cast(buf)[0]) << 56) | 75 | (static_cast(static_cast(buf)[1]) << 48) | 76 | (static_cast(static_cast(buf)[2]) << 40) | 77 | (static_cast(static_cast(buf)[3]) << 32) | 78 | (static_cast(static_cast(buf)[4]) << 24) | 79 | (static_cast(static_cast(buf)[5]) << 16) | 80 | (static_cast(static_cast(buf)[6]) << 8) | 81 | static_cast(static_cast(buf)[7]); 82 | 83 | return n; 84 | } 85 | } 86 | } 87 | } 88 | 89 | #endif // NET_MON_EVENT_UTIL_H 90 | -------------------------------------------------------------------------------- /net/mon/event/writer.cpp: -------------------------------------------------------------------------------- 1 | #include "net/mon/event/writer.h" 2 | 3 | bool net::mon::event::writer::open(const char* filename) 4 | { 5 | // Open file. 6 | if (_M_file.open(filename)) { 7 | uint8_t header[file::header::size]; 8 | 9 | // If the file is not empty... 10 | if (!_M_file.empty()) { 11 | // Read header. 12 | if (_M_file.pread(header, sizeof(header), 0) == 13 | static_cast(sizeof(header))) { 14 | // Deserialize header. 15 | if (_M_header.deserialize(header, sizeof(header))) { 16 | return true; 17 | } 18 | } 19 | } else { 20 | // File is empty. 21 | 22 | // Initialize header. 23 | _M_header.timestamp.first = 0; 24 | _M_header.timestamp.last = 0; 25 | 26 | // Serialize header. 27 | _M_header.serialize(header, sizeof(header)); 28 | 29 | // Write header at the beginning of the file. 30 | if (_M_file.pwrite(header, sizeof(header), 0)) { 31 | return true; 32 | } 33 | } 34 | 35 | _M_file.close(); 36 | } 37 | 38 | return false; 39 | } 40 | 41 | bool net::mon::event::writer::close() 42 | { 43 | // If the file is open... 44 | if (_M_file.open()) { 45 | // Flush remaining data (if any). 46 | if (flush()) { 47 | // Serialize header. 48 | uint8_t header[file::header::size]; 49 | _M_header.serialize(header, sizeof(header)); 50 | 51 | // Write header at the beginning of the file. 52 | bool ret = _M_file.pwrite(header, sizeof(header), 0); 53 | 54 | _M_file.close(); 55 | 56 | return ret; 57 | } else { 58 | _M_file.close(); 59 | 60 | return false; 61 | } 62 | } else { 63 | return true; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /net/mon/event/writer.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_EVENT_WRITER_H 2 | #define NET_MON_EVENT_WRITER_H 3 | 4 | #include "net/mon/event/events.h" 5 | #include "net/mon/event/file.h" 6 | #include "fs/file.h" 7 | 8 | namespace net { 9 | namespace mon { 10 | namespace event { 11 | // Event writer. 12 | class writer { 13 | public: 14 | // Minimum buffer size. 15 | static constexpr const size_t min_buffer_size = event::maxlen; 16 | 17 | // Default buffer size. 18 | static constexpr const size_t default_buffer_size = 32 * 1024; 19 | 20 | // Constructor. 21 | writer(uint64_t file_allocation_size = 22 | fs::file::default_allocation_size, 23 | size_t buffer_size = default_buffer_size); 24 | 25 | // Destructor. 26 | ~writer(); 27 | 28 | // Initialize. 29 | bool init(); 30 | 31 | // Open event file for writing. 32 | bool open(const char* filename); 33 | 34 | // Close event file. 35 | bool close(); 36 | 37 | // Write event. 38 | template 39 | bool write(const Event& ev); 40 | 41 | // Flush buffer. 42 | bool flush(); 43 | 44 | private: 45 | fs::file _M_file; 46 | 47 | file::header _M_header; 48 | 49 | string::buffer _M_buf; 50 | 51 | size_t _M_buffer_size; 52 | 53 | // Flush buffer. 54 | bool flush_(); 55 | 56 | // Disable copy constructor and assignment operator. 57 | writer(const writer&) = delete; 58 | writer& operator=(const writer&) = delete; 59 | }; 60 | 61 | inline writer::writer(uint64_t file_allocation_size, size_t buffer_size) 62 | : _M_file(file_allocation_size), 63 | _M_buffer_size(buffer_size) 64 | { 65 | } 66 | 67 | inline writer::~writer() 68 | { 69 | close(); 70 | } 71 | 72 | inline bool writer::init() 73 | { 74 | return (_M_buf.allocate(_M_buffer_size * 2)); 75 | } 76 | 77 | template 78 | inline bool writer::write(const Event& ev) 79 | { 80 | if ((ev.serialize(_M_buf)) && 81 | ((_M_buf.length() < _M_buffer_size) || (flush_()))) { 82 | if (_M_header.timestamp.first == 0) { 83 | _M_header.timestamp.first = ev.timestamp; 84 | } 85 | 86 | _M_header.timestamp.last = ev.timestamp; 87 | 88 | return true; 89 | } 90 | 91 | return false; 92 | } 93 | 94 | inline bool writer::flush() 95 | { 96 | return !_M_buf.empty() ? flush_() : true; 97 | } 98 | 99 | inline bool writer::flush_() 100 | { 101 | // Write buffer to file. 102 | if (_M_file.write(_M_buf.data(), _M_buf.length())) { 103 | _M_buf.clear(); 104 | 105 | return true; 106 | } 107 | 108 | return false; 109 | } 110 | } 111 | } 112 | } 113 | 114 | #endif // NET_MON_EVENT_WRITER_H 115 | -------------------------------------------------------------------------------- /net/mon/ipv4/address.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_IPV4_ADDRESS_H 2 | #define NET_MON_IPV4_ADDRESS_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace net { 9 | namespace mon { 10 | namespace ipv4 { 11 | struct address : public in_addr { 12 | // Constructor. 13 | address() = default; 14 | address(uint32_t addr); 15 | address(const void* addr); 16 | 17 | // Equal operator. 18 | bool operator==(struct in_addr other) const; 19 | 20 | // Compare. 21 | int compare(struct in_addr other) const; 22 | 23 | // Hash. 24 | uint32_t hash() const; 25 | }; 26 | 27 | struct address_pair { 28 | union { 29 | uint64_t addresses; 30 | 31 | struct { 32 | struct in_addr address2; 33 | struct in_addr address1; 34 | } a; 35 | }; 36 | 37 | // Constructor. 38 | address_pair() = default; 39 | address_pair(struct in_addr addr1, struct in_addr addr2); 40 | 41 | // Assign. 42 | void assign(struct in_addr addr1, struct in_addr addr2); 43 | 44 | // Equal operator. 45 | bool operator==(address_pair other) const; 46 | }; 47 | 48 | inline address::address(uint32_t addr) 49 | { 50 | s_addr = addr; 51 | } 52 | 53 | inline address::address(const void* addr) 54 | { 55 | memcpy(&s_addr, addr, sizeof(s_addr)); 56 | } 57 | 58 | inline bool address::operator==(struct in_addr other) const 59 | { 60 | return (s_addr == other.s_addr); 61 | } 62 | 63 | inline int address::compare(struct in_addr other) const 64 | { 65 | return (s_addr - other.s_addr); 66 | } 67 | 68 | inline uint32_t address::hash() const 69 | { 70 | return s_addr; 71 | } 72 | 73 | inline address_pair::address_pair(struct in_addr addr1, 74 | struct in_addr addr2) 75 | { 76 | assign(addr1, addr2); 77 | } 78 | 79 | inline void address_pair::assign(struct in_addr addr1, 80 | struct in_addr addr2) 81 | { 82 | addresses = (static_cast(addr1.s_addr) << 32) | addr2.s_addr; 83 | } 84 | 85 | inline bool address_pair::operator==(address_pair other) const 86 | { 87 | return (addresses == other.addresses); 88 | } 89 | } 90 | } 91 | } 92 | 93 | #endif // NET_MON_IPV4_ADDRESS_H 94 | -------------------------------------------------------------------------------- /net/mon/ipv4/tcp/connection.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_IPV4_TCP_CONNECTION_H 2 | #define NET_MON_IPV4_TCP_CONNECTION_H 3 | 4 | #include 5 | #include "net/mon/tcp/connection.h" 6 | #include "net/mon/ipv4/address.h" 7 | #include "net/mon/tcp/port_pair.h" 8 | 9 | namespace net { 10 | namespace mon { 11 | namespace ipv4 { 12 | namespace tcp { 13 | class connection : public net::mon::tcp::connection { 14 | public: 15 | typedef address address_type; 16 | 17 | // Constructor. 18 | connection() = default; 19 | connection(struct in_addr addr1, 20 | in_port_t port1, 21 | struct in_addr addr2, 22 | in_port_t port2); 23 | 24 | // Assign. 25 | void assign(struct in_addr addr1, 26 | in_port_t port1, 27 | struct in_addr addr2, 28 | in_port_t port2); 29 | 30 | // Equal operator. 31 | bool operator==(const connection& other) const; 32 | 33 | // Get addresses. 34 | const address_pair& addresses() const; 35 | 36 | // Get ports. 37 | const mon::tcp::port_pair& ports() const; 38 | 39 | private: 40 | address_pair _M_addresses; 41 | mon::tcp::port_pair _M_ports; 42 | 43 | // Disable copy constructor and assignment operator. 44 | connection(const connection&) = delete; 45 | connection& operator=(const connection&) = delete; 46 | }; 47 | 48 | inline connection::connection(struct in_addr addr1, 49 | in_port_t port1, 50 | struct in_addr addr2, 51 | in_port_t port2) 52 | { 53 | assign(addr1, port1, addr2, port2); 54 | } 55 | 56 | inline void connection::assign(struct in_addr addr1, 57 | in_port_t port1, 58 | struct in_addr addr2, 59 | in_port_t port2) 60 | { 61 | _M_addresses.assign(addr1, addr2); 62 | _M_ports.assign(port1, port2); 63 | } 64 | 65 | inline bool connection::operator==(const connection& other) const 66 | { 67 | return ((_M_ports == other._M_ports) && 68 | (_M_addresses == other._M_addresses)); 69 | } 70 | 71 | inline const address_pair& connection::addresses() const 72 | { 73 | return _M_addresses; 74 | } 75 | 76 | inline const mon::tcp::port_pair& connection::ports() const 77 | { 78 | return _M_ports; 79 | } 80 | } 81 | } 82 | } 83 | } 84 | 85 | #endif // NET_MON_IPV4_TCP_CONNECTION_H 86 | -------------------------------------------------------------------------------- /net/mon/ipv6/address.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_IPV6_ADDRESS_H 2 | #define NET_MON_IPV6_ADDRESS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "util/hash.h" 8 | 9 | namespace net { 10 | namespace mon { 11 | namespace ipv6 { 12 | struct address : public in6_addr { 13 | // Constructor. 14 | address() = default; 15 | address(const void* addr); 16 | 17 | // Equal operator. 18 | bool operator==(const struct in6_addr& other) const; 19 | 20 | // Compare. 21 | int compare(const struct in6_addr& other) const; 22 | 23 | // Hash. 24 | uint32_t hash() const; 25 | }; 26 | 27 | struct address_pair { 28 | struct { 29 | address address2; 30 | address address1; 31 | } a; 32 | 33 | // Constructor. 34 | address_pair() = default; 35 | address_pair(const struct in6_addr& addr1, 36 | const struct in6_addr& addr2); 37 | 38 | // Assign. 39 | void assign(const struct in6_addr& addr1, const struct in6_addr& addr2); 40 | 41 | // Equal operator. 42 | bool operator==(const address_pair& other) const; 43 | }; 44 | 45 | inline address::address(const void* addr) 46 | { 47 | memcpy(s6_addr32, addr, sizeof(s6_addr32)); 48 | } 49 | 50 | inline bool address::operator==(const struct in6_addr& other) const 51 | { 52 | return (((s6_addr32[0] ^ other.s6_addr32[0]) | 53 | (s6_addr32[1] ^ other.s6_addr32[1]) | 54 | (s6_addr32[2] ^ other.s6_addr32[2]) | 55 | (s6_addr32[3] ^ other.s6_addr32[3])) == 0); 56 | } 57 | 58 | inline int address::compare(const struct in6_addr& other) const 59 | { 60 | return memcmp(s6_addr32, other.s6_addr32, sizeof(struct in6_addr)); 61 | } 62 | 63 | inline uint32_t address::hash() const 64 | { 65 | static constexpr const uint32_t initval = 0; 66 | 67 | return util::hash::hash_3words(s6_addr32[0] ^ s6_addr32[1], 68 | s6_addr32[2], 69 | s6_addr32[3], 70 | initval); 71 | } 72 | 73 | inline address_pair::address_pair(const struct in6_addr& addr1, 74 | const struct in6_addr& addr2) 75 | { 76 | assign(addr1, addr2); 77 | } 78 | 79 | inline void address_pair::assign(const struct in6_addr& addr1, 80 | const struct in6_addr& addr2) 81 | { 82 | a.address1.s6_addr32[0] = addr1.s6_addr32[0]; 83 | a.address1.s6_addr32[1] = addr1.s6_addr32[1]; 84 | a.address1.s6_addr32[2] = addr1.s6_addr32[2]; 85 | a.address1.s6_addr32[3] = addr1.s6_addr32[3]; 86 | 87 | a.address2.s6_addr32[0] = addr2.s6_addr32[0]; 88 | a.address2.s6_addr32[1] = addr2.s6_addr32[1]; 89 | a.address2.s6_addr32[2] = addr2.s6_addr32[2]; 90 | a.address2.s6_addr32[3] = addr2.s6_addr32[3]; 91 | } 92 | 93 | inline bool address_pair::operator==(const address_pair& other) const 94 | { 95 | return ((a.address1 == other.a.address1) && 96 | (a.address2 == other.a.address2)); 97 | } 98 | } 99 | } 100 | } 101 | 102 | #endif // NET_MON_IPV6_ADDRESS_H 103 | -------------------------------------------------------------------------------- /net/mon/ipv6/tcp/connection.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_IPV6_TCP_CONNECTION_H 2 | #define NET_MON_IPV6_TCP_CONNECTION_H 3 | 4 | #include 5 | #include "net/mon/tcp/connection.h" 6 | #include "net/mon/ipv6/address.h" 7 | #include "net/mon/tcp/port_pair.h" 8 | 9 | namespace net { 10 | namespace mon { 11 | namespace ipv6 { 12 | namespace tcp { 13 | class connection : public net::mon::tcp::connection { 14 | public: 15 | typedef address address_type; 16 | 17 | // Constructor. 18 | connection() = default; 19 | connection(const struct in6_addr& addr1, 20 | in_port_t port1, 21 | const struct in6_addr& addr2, 22 | in_port_t port2); 23 | 24 | // Assign. 25 | void assign(const struct in6_addr& addr1, 26 | in_port_t port1, 27 | const struct in6_addr& addr2, 28 | in_port_t port2); 29 | 30 | // Equal operator. 31 | bool operator==(const connection& other) const; 32 | 33 | // Get addresses. 34 | const address_pair& addresses() const; 35 | 36 | // Get ports. 37 | const mon::tcp::port_pair& ports() const; 38 | 39 | private: 40 | address_pair _M_addresses; 41 | mon::tcp::port_pair _M_ports; 42 | 43 | // Disable copy constructor and assignment operator. 44 | connection(const connection&) = delete; 45 | connection& operator=(const connection&) = delete; 46 | }; 47 | 48 | inline connection::connection(const struct in6_addr& addr1, 49 | in_port_t port1, 50 | const struct in6_addr& addr2, 51 | in_port_t port2) 52 | { 53 | assign(addr1, port1, addr2, port2); 54 | } 55 | 56 | inline void connection::assign(const struct in6_addr& addr1, 57 | in_port_t port1, 58 | const struct in6_addr& addr2, 59 | in_port_t port2) 60 | { 61 | _M_addresses.assign(addr1, addr2); 62 | _M_ports.assign(port1, port2); 63 | } 64 | 65 | inline bool connection::operator==(const connection& other) const 66 | { 67 | return ((_M_ports == other._M_ports) && 68 | (_M_addresses == other._M_addresses)); 69 | } 70 | 71 | inline const address_pair& connection::addresses() const 72 | { 73 | return _M_addresses; 74 | } 75 | 76 | inline const mon::tcp::port_pair& connection::ports() const 77 | { 78 | return _M_ports; 79 | } 80 | } 81 | } 82 | } 83 | } 84 | 85 | #endif // NET_MON_IPV6_TCP_CONNECTION_H 86 | -------------------------------------------------------------------------------- /net/mon/tcp/connection.cpp: -------------------------------------------------------------------------------- 1 | #include "net/mon/tcp/connection.h" 2 | 3 | bool net::mon::tcp::connection::process_packet(direction dir, 4 | uint8_t flags, 5 | uint16_t size, 6 | uint64_t now) 7 | { 8 | // http://cradpdf.drdc-rddc.gc.ca/PDFS/unc25/p520460.pdf 9 | 10 | switch (s) { 11 | case state::listen: 12 | if ((flags & flag_mask) == syn) { 13 | init(dir, size, now); 14 | 15 | return true; 16 | } 17 | 18 | break; 19 | case state::connection_requested: 20 | switch (flags & flag_mask) { 21 | case syn | ack: 22 | if (static_cast(dir) != active_opener) { 23 | s = state::connection_established; 24 | 25 | sent[static_cast(dir)] += size; 26 | timestamp.last_packet = now; 27 | 28 | return true; 29 | } 30 | 31 | break; 32 | case syn: 33 | case ack: 34 | // Retransmission / out-of-order? 35 | if (static_cast(dir) == active_opener) { 36 | return true; 37 | } 38 | 39 | break; 40 | case rst: 41 | case rst | ack: 42 | s = state::closed; 43 | 44 | active_closer = static_cast(dir); 45 | 46 | sent[static_cast(dir)] += size; 47 | timestamp.last_packet = now; 48 | 49 | return true; 50 | } 51 | 52 | break; 53 | case state::connection_established: 54 | switch (flags & flag_mask) { 55 | case ack: 56 | if (static_cast(dir) == active_opener) { 57 | s = state::data_transfer; 58 | 59 | sent[static_cast(dir)] += size; 60 | timestamp.last_packet = now; 61 | 62 | return true; 63 | } 64 | 65 | break; 66 | case syn: 67 | // Retransmission / out-of-order? 68 | if (static_cast(dir) == active_opener) { 69 | return true; 70 | } 71 | 72 | break; 73 | case syn | ack: 74 | // Retransmission / out-of-order? 75 | if (static_cast(dir) != active_opener) { 76 | return true; 77 | } 78 | 79 | break; 80 | case rst: 81 | case rst | ack: 82 | s = state::closed; 83 | 84 | active_closer = static_cast(dir); 85 | 86 | sent[static_cast(dir)] += size; 87 | timestamp.last_packet = now; 88 | 89 | return true; 90 | } 91 | 92 | break; 93 | case state::data_transfer: 94 | switch (flags & flag_mask) { 95 | case ack: 96 | sent[static_cast(dir)] += size; 97 | timestamp.last_packet = now; 98 | 99 | return true; 100 | case fin: 101 | case fin | ack: 102 | s = state::closing; 103 | 104 | active_closer = static_cast(dir); 105 | 106 | sent[static_cast(dir)] += size; 107 | timestamp.last_packet = now; 108 | 109 | return true; 110 | case rst: 111 | case rst | ack: 112 | s = state::closed; 113 | 114 | active_closer = static_cast(dir); 115 | 116 | sent[static_cast(dir)] += size; 117 | timestamp.last_packet = now; 118 | 119 | return true; 120 | } 121 | 122 | break; 123 | case state::closing: 124 | switch (flags & flag_mask) { 125 | case ack: 126 | sent[static_cast(dir)] += size; 127 | timestamp.last_packet = now; 128 | 129 | return true; 130 | case fin: 131 | case fin | ack: 132 | if (static_cast(dir) != active_closer) { 133 | s = state::closed; 134 | 135 | sent[static_cast(dir)] += size; 136 | timestamp.last_packet = now; 137 | } 138 | 139 | return true; 140 | case rst: 141 | case rst | ack: 142 | s = state::closed; 143 | 144 | sent[static_cast(dir)] += size; 145 | timestamp.last_packet = now; 146 | 147 | return true; 148 | } 149 | 150 | break; 151 | case state::closed: 152 | switch (flags & flag_mask) { 153 | case ack: 154 | case fin: 155 | case fin | ack: 156 | case rst: 157 | case rst | ack: 158 | sent[static_cast(dir)] += size; 159 | timestamp.last_packet = now; 160 | 161 | return true; 162 | } 163 | 164 | break; 165 | case state::failure: 166 | return false; 167 | } 168 | 169 | s = state::failure; 170 | 171 | return false; 172 | } 173 | -------------------------------------------------------------------------------- /net/mon/tcp/connection.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_TCP_CONNECTION_H 2 | #define NET_MON_TCP_CONNECTION_H 3 | 4 | #include 5 | #include 6 | #include "util/node.h" 7 | 8 | namespace net { 9 | namespace mon { 10 | namespace tcp { 11 | class connection : private util::node { 12 | template 13 | friend class connections; 14 | 15 | public: 16 | static constexpr const uint8_t ack = 0x10; 17 | static constexpr const uint8_t rst = 0x04; 18 | static constexpr const uint8_t syn = 0x02; 19 | static constexpr const uint8_t fin = 0x01; 20 | 21 | static constexpr const uint8_t flag_mask = ack | rst | syn | fin; 22 | 23 | // Connection state: 24 | // http://cradpdf.drdc-rddc.gc.ca/PDFS/unc25/p520460.pdf 25 | enum class state : uint8_t { 26 | listen, 27 | connection_requested, 28 | connection_established, 29 | data_transfer, 30 | closing, 31 | closed, 32 | failure 33 | }; 34 | 35 | // Originator. 36 | enum class originator : uint8_t { 37 | addr1, 38 | addr2 39 | }; 40 | 41 | // Packet direction. 42 | enum class direction : uint8_t { 43 | from_addr1 = static_cast(originator::addr1), 44 | from_addr2 = static_cast(originator::addr2) 45 | }; 46 | 47 | state s; 48 | 49 | originator active_opener; 50 | originator active_closer; 51 | 52 | uint64_t sent[2]; 53 | 54 | struct { 55 | uint64_t creation; 56 | uint64_t last_packet; 57 | } timestamp; 58 | 59 | // Initialize. 60 | void init(direction dir, uint16_t size, uint64_t now); 61 | 62 | // Process packet. 63 | bool process_packet(direction dir, 64 | uint8_t flags, 65 | uint16_t size, 66 | uint64_t now); 67 | }; 68 | 69 | inline void connection::init(direction dir, uint16_t size, uint64_t now) 70 | { 71 | s = state::connection_requested; 72 | 73 | active_opener = static_cast(dir); 74 | 75 | sent[static_cast(dir)] = size; 76 | sent[!static_cast(dir)] = 0; 77 | 78 | timestamp.creation = now; 79 | timestamp.last_packet = now; 80 | } 81 | } 82 | } 83 | } 84 | 85 | #endif // NET_MON_TCP_CONNECTION_H 86 | -------------------------------------------------------------------------------- /net/mon/tcp/port_pair.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_TCP_PORT_PAIR_H 2 | #define NET_MON_TCP_PORT_PAIR_H 3 | 4 | #include 5 | #include 6 | 7 | namespace net { 8 | namespace mon { 9 | namespace tcp { 10 | struct port_pair { 11 | union { 12 | uint32_t ports; 13 | 14 | struct { 15 | in_port_t port2; 16 | in_port_t port1; 17 | } p; 18 | }; 19 | 20 | // Constructor. 21 | port_pair() = default; 22 | port_pair(in_port_t port1, in_port_t port2); 23 | 24 | // Assign. 25 | void assign(in_port_t port1, in_port_t port2); 26 | 27 | // Equal operator. 28 | bool operator==(port_pair other) const; 29 | }; 30 | 31 | inline port_pair::port_pair(in_port_t port1, in_port_t port2) 32 | { 33 | assign(port1, port2); 34 | } 35 | 36 | inline void port_pair::assign(in_port_t port1, in_port_t port2) 37 | { 38 | ports = (static_cast(port1) << 16) | port2; 39 | } 40 | 41 | inline bool port_pair::operator==(port_pair other) const 42 | { 43 | return (ports == other.ports); 44 | } 45 | } 46 | } 47 | } 48 | 49 | #endif // NET_MON_TCP_PORT_PAIR_H 50 | -------------------------------------------------------------------------------- /net/mon/tcp/segments.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_TCP_SEGMENTS_H 2 | #define NET_MON_TCP_SEGMENTS_H 3 | 4 | #include 5 | #include 6 | 7 | namespace net { 8 | namespace mon { 9 | namespace tcp { 10 | class segments { 11 | public: 12 | // Payload callback. 13 | typedef void (*payloadfn_t)(const void*, size_t, void*); 14 | 15 | // Gap callback. 16 | typedef void (*gapfn_t)(size_t, void*); 17 | 18 | // Constructor. 19 | segments() = default; 20 | 21 | // Destructor. 22 | ~segments(); 23 | 24 | // Create. 25 | bool create(payloadfn_t payloadfn, 26 | gapfn_t gapfn, 27 | void* user = nullptr); 28 | 29 | // Clear. 30 | void clear(); 31 | 32 | // Add segment. 33 | bool add(uint32_t seqno, const void* payload, size_t len); 34 | 35 | // FIN has been received. 36 | void fin(); 37 | 38 | // Set next sequence number. 39 | void next_sequence_number(uint32_t seqno); 40 | 41 | private: 42 | // Maximum number of segments. 43 | static constexpr const size_t max_segments = 32; 44 | 45 | // Maximum payload size. 46 | static constexpr const size_t max_size = 64 * 1024; 47 | 48 | // Segment. 49 | struct segment { 50 | uint32_t seqno; 51 | void* payload; 52 | size_t len; 53 | 54 | ssize_t prev; 55 | ssize_t next; 56 | }; 57 | 58 | // Segments. 59 | segment _M_segments[max_segments]; 60 | 61 | // First segment. 62 | ssize_t _M_first_segment = -1; 63 | 64 | // Last segment. 65 | ssize_t _M_last_segment = -1; 66 | 67 | // First free segment. 68 | ssize_t _M_free_segment = 0; 69 | 70 | // Payloads. 71 | uint8_t* _M_payloads = nullptr; 72 | 73 | // Next sequence number. 74 | uint32_t _M_next_seqno; 75 | 76 | // Payload callback. 77 | payloadfn_t _M_payloadfn; 78 | 79 | // Gap callback. 80 | gapfn_t _M_gapfn; 81 | 82 | // User pointer. 83 | void* _M_user; 84 | 85 | // Check payloads. 86 | void check_payloads(); 87 | 88 | // Disable copy constructor and assignment operator. 89 | segments(const segments&) = delete; 90 | segments& operator=(const segments&) = delete; 91 | }; 92 | 93 | inline segments::~segments() 94 | { 95 | if (_M_payloads) { 96 | free(_M_payloads); 97 | } 98 | } 99 | 100 | inline void segments::clear() 101 | { 102 | for (size_t i = 0; i < max_segments - 1; i++) { 103 | _M_segments[i].next = i + 1; 104 | } 105 | 106 | _M_segments[max_segments - 1].next = -1; 107 | 108 | _M_first_segment = -1; 109 | _M_last_segment = -1; 110 | _M_free_segment = 0; 111 | } 112 | 113 | inline void segments::next_sequence_number(uint32_t seqno) 114 | { 115 | _M_next_seqno = seqno; 116 | } 117 | } 118 | } 119 | } 120 | 121 | #endif // NET_MON_TCP_SEGMENTS_H 122 | -------------------------------------------------------------------------------- /net/mon/workers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "net/mon/workers.h" 3 | 4 | bool net::mon::workers::create(size_t nworkers, 5 | const size_t* processors, 6 | const char* evdir, 7 | uint64_t file_allocation_size, 8 | size_t buffer_size, 9 | capture::method capture_method, 10 | const char* device, 11 | unsigned ifindex, 12 | int rcvbuf_size, 13 | bool promiscuous_mode, 14 | size_t ring_buffer_block_size, 15 | size_t ring_buffer_frame_size, 16 | size_t ring_buffer_frame_count, 17 | size_t tcp_ipv4_size, 18 | size_t tcp_ipv4_maxconns, 19 | size_t tcp_ipv6_size, 20 | size_t tcp_ipv6_maxconns, 21 | uint64_t tcp_timeout, 22 | uint64_t tcp_time_wait) 23 | { 24 | if ((nworkers >= min_workers) && 25 | (nworkers <= max_workers) && 26 | (buffer_size >= event::writer::min_buffer_size)) { 27 | // Create threads. 28 | for (size_t i = 0; i < nworkers; i++) { 29 | if ((_M_workers[i] = new (std::nothrow) worker(i, 30 | processors[i], 31 | evdir, 32 | file_allocation_size, 33 | buffer_size)) == nullptr) { 34 | _M_nworkers = i; 35 | return false; 36 | } 37 | } 38 | 39 | _M_nworkers = nworkers; 40 | 41 | // Initialize threads. 42 | if (capture_method == capture::method::ring_buffer) { 43 | for (size_t i = 0; i < nworkers; i++) { 44 | if (!_M_workers[i]->init(device, 45 | ifindex, 46 | rcvbuf_size, 47 | promiscuous_mode, 48 | ring_buffer_block_size, 49 | ring_buffer_frame_size, 50 | ring_buffer_frame_count, 51 | tcp_ipv4_size, 52 | tcp_ipv4_maxconns, 53 | tcp_ipv6_size, 54 | tcp_ipv6_maxconns, 55 | tcp_timeout, 56 | tcp_time_wait)) { 57 | return false; 58 | } 59 | } 60 | } else { 61 | for (size_t i = 0; i < nworkers; i++) { 62 | if (!_M_workers[i]->init(device, 63 | ifindex, 64 | rcvbuf_size, 65 | promiscuous_mode, 66 | tcp_ipv4_size, 67 | tcp_ipv4_maxconns, 68 | tcp_ipv6_size, 69 | tcp_ipv6_maxconns, 70 | tcp_timeout, 71 | tcp_time_wait)) { 72 | return false; 73 | } 74 | } 75 | } 76 | 77 | return true; 78 | } 79 | 80 | return false; 81 | } 82 | -------------------------------------------------------------------------------- /net/mon/workers.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_MON_WORKERS_H 2 | #define NET_MON_WORKERS_H 3 | 4 | #include 5 | #include "net/mon/worker.h" 6 | #include "net/capture/method.h" 7 | 8 | namespace net { 9 | namespace mon { 10 | class workers { 11 | public: 12 | static constexpr const size_t min_workers = 1; 13 | static constexpr const size_t max_workers = 1024; 14 | static constexpr const size_t default_workers = 4; 15 | 16 | // Constructor. 17 | workers() = default; 18 | 19 | // Destructor. 20 | ~workers(); 21 | 22 | // Create workers. 23 | bool create(size_t nworkers, 24 | const size_t* processors, 25 | const char* evdir, 26 | uint64_t file_allocation_size, 27 | size_t buffer_size, 28 | capture::method capture_method, 29 | const char* device, 30 | unsigned ifindex, 31 | int rcvbuf_size, 32 | bool promiscuous_mode, 33 | size_t ring_buffer_block_size, 34 | size_t ring_buffer_frame_size, 35 | size_t ring_buffer_frame_count, 36 | size_t tcp_ipv4_size, 37 | size_t tcp_ipv4_maxconns, 38 | size_t tcp_ipv6_size, 39 | size_t tcp_ipv6_maxconns, 40 | uint64_t tcp_timeout, 41 | uint64_t tcp_time_wait); 42 | 43 | // Start workers. 44 | bool start(); 45 | 46 | // Stop workers. 47 | void stop(); 48 | 49 | // Show statistics. 50 | bool show_statistics(); 51 | 52 | private: 53 | // Workers. 54 | worker* _M_workers[max_workers]; 55 | 56 | // Number of workers. 57 | size_t _M_nworkers = 0; 58 | 59 | // Disable copy constructor and assignment operator. 60 | workers(const workers&) = delete; 61 | workers& operator=(const workers&) = delete; 62 | }; 63 | 64 | inline workers::~workers() 65 | { 66 | for (size_t i = 0; i < _M_nworkers; i++) { 67 | delete _M_workers[i]; 68 | } 69 | } 70 | 71 | inline bool workers::start() 72 | { 73 | for (size_t i = 0; i < _M_nworkers; i++) { 74 | if (!_M_workers[i]->start()) { 75 | return false; 76 | } 77 | } 78 | 79 | return true; 80 | } 81 | 82 | inline void workers::stop() 83 | { 84 | for (size_t i = 0; i < _M_nworkers; i++) { 85 | _M_workers[i]->stop(); 86 | } 87 | } 88 | 89 | inline bool workers::show_statistics() 90 | { 91 | for (size_t i = 0; i < _M_nworkers; i++) { 92 | if (!_M_workers[i]->show_statistics()) { 93 | return false; 94 | } 95 | } 96 | 97 | return true; 98 | } 99 | } 100 | } 101 | 102 | #endif // NET_MON_WORKERS_H 103 | -------------------------------------------------------------------------------- /net/parser.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_PARSER_H 2 | #define NET_PARSER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace net { 12 | class parser { 13 | public: 14 | // Parser callbacks. 15 | struct callbacks { 16 | // Process ICMP datagram. 17 | typedef bool (*icmp_t)(const struct iphdr* iphdr, 18 | size_t iphdrsize, 19 | size_t pktsize, 20 | const struct timeval& timestamp, 21 | void* user); 22 | 23 | // Process ICMPv6 datagram. 24 | typedef bool (*icmpv6_t)(const struct ip6_hdr* iphdr, 25 | size_t iphdrsize, 26 | size_t pktsize, 27 | const struct timeval& timestamp, 28 | void* user); 29 | 30 | // Process TCP/IPv4 segment. 31 | typedef bool (*tcp_ipv4_t)(const struct iphdr* iphdr, 32 | size_t iphdrsize, 33 | size_t pktsize, 34 | const struct timeval& timestamp, 35 | void* user); 36 | 37 | // Process TCP/IPv6 segment. 38 | typedef bool (*tcp_ipv6_t)(const struct ip6_hdr* iphdr, 39 | size_t iphdrsize, 40 | size_t pktsize, 41 | const struct timeval& timestamp, 42 | void* user); 43 | 44 | // Process UDP/IPv4 segment. 45 | typedef bool (*udp_ipv4_t)(const struct iphdr* iphdr, 46 | size_t iphdrsize, 47 | size_t pktsize, 48 | const struct timeval& timestamp, 49 | void* user); 50 | 51 | // Process UDP/IPv6 segment. 52 | typedef bool (*udp_ipv6_t)(const struct ip6_hdr* iphdr, 53 | size_t iphdrsize, 54 | size_t pktsize, 55 | const struct timeval& timestamp, 56 | void* user); 57 | 58 | // Constructor. 59 | callbacks() = default; 60 | callbacks(icmp_t icmp, 61 | icmpv6_t icmpv6, 62 | tcp_ipv4_t tcp_ipv4, 63 | tcp_ipv6_t tcp_ipv6, 64 | udp_ipv4_t udp_ipv4, 65 | udp_ipv6_t udp_ipv6); 66 | 67 | // Destructor. 68 | ~callbacks() = default; 69 | 70 | icmp_t icmp = nullptr; 71 | icmpv6_t icmpv6 = nullptr; 72 | tcp_ipv4_t tcp_ipv4 = nullptr; 73 | tcp_ipv6_t tcp_ipv6 = nullptr; 74 | udp_ipv4_t udp_ipv4 = nullptr; 75 | udp_ipv6_t udp_ipv6 = nullptr; 76 | }; 77 | 78 | // Constructor. 79 | parser(const callbacks& callbacks, void* user = nullptr); 80 | 81 | // Destructor. 82 | ~parser() = default; 83 | 84 | // Process ethernet frame. 85 | bool process_ethernet(const void* buf, 86 | size_t len, 87 | const struct timeval& timestamp); 88 | 89 | // Process IPv4 packet. 90 | bool process_ipv4(const void* buf, 91 | size_t len, 92 | const struct timeval& timestamp); 93 | 94 | // Process IPv6 packet. 95 | bool process_ipv6(const void* buf, 96 | size_t len, 97 | const struct timeval& timestamp); 98 | 99 | private: 100 | callbacks _M_callbacks; 101 | 102 | void* _M_user; 103 | 104 | // Is extension header? 105 | static bool is_extension_header(uint8_t nxt); 106 | }; 107 | 108 | inline parser::callbacks::callbacks(icmp_t icmp, 109 | icmpv6_t icmpv6, 110 | tcp_ipv4_t tcp_ipv4, 111 | tcp_ipv6_t tcp_ipv6, 112 | udp_ipv4_t udp_ipv4, 113 | udp_ipv6_t udp_ipv6) 114 | : icmp(icmp), 115 | icmpv6(icmpv6), 116 | tcp_ipv4(tcp_ipv4), 117 | tcp_ipv6(tcp_ipv6), 118 | udp_ipv4(udp_ipv4), 119 | udp_ipv6(udp_ipv6) 120 | { 121 | } 122 | 123 | inline parser::parser(const callbacks& callbacks, void* user) 124 | : _M_callbacks(callbacks), 125 | _M_user(user) 126 | { 127 | } 128 | 129 | inline bool parser::is_extension_header(uint8_t nxt) 130 | { 131 | switch (nxt) { 132 | case IPPROTO_HOPOPTS: // 0: IPv6 hop-by-hop options. 133 | case IPPROTO_DSTOPTS: // 60: IPv6 destination options. 134 | case IPPROTO_ROUTING: // 43: IPv6 routing header. 135 | case IPPROTO_FRAGMENT: // 44: IPv6 fragmentation header. 136 | case 51: // 51: Authentication header. 137 | case 50: // 50: Encapsulating Security Payload. 138 | case IPPROTO_NONE: // 59: IPv6 no next header. 139 | case IPPROTO_MH: // 135: IPv6 mobility header. 140 | case 139: // 139: Host Identity Protocol. 141 | case 140: // 140: Shim6 Protocol. 142 | return true; 143 | default: 144 | return false; 145 | } 146 | } 147 | } 148 | 149 | #endif // NET_PARSER_H 150 | -------------------------------------------------------------------------------- /netmon.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "net/mon/workers.h" 5 | #include "net/mon/configuration.h" 6 | #include "net/capture/method.h" 7 | #include "pcap/reader.h" 8 | 9 | static bool process_pcap_file(const net::mon::configuration& config); 10 | static bool process_interface(const net::mon::configuration& config); 11 | 12 | static bool ethernet(const void* buf, 13 | size_t len, 14 | const pcap::timeval& ts, 15 | void* user); 16 | 17 | static bool ipv4(const void* buf, 18 | size_t len, 19 | const pcap::timeval& ts, 20 | void* user); 21 | 22 | static bool ipv6(const void* buf, 23 | size_t len, 24 | const pcap::timeval& ts, 25 | void* user); 26 | 27 | struct pcap_argument { 28 | net::mon::worker* worker; 29 | const pcap::reader* reader; 30 | }; 31 | 32 | int main(int argc, const char** argv) 33 | { 34 | // Initialize configuration. 35 | net::mon::configuration config; 36 | if (config.init()) { 37 | // Parse program options. 38 | if (config.parse(argc, argv)) { 39 | // Print configuration. 40 | config.print(); 41 | 42 | if (config.cap.m == net::mon::configuration::capture::method::pcap) { 43 | if (process_pcap_file(config)) { 44 | return 0; 45 | } 46 | } else { 47 | if (process_interface(config)) { 48 | return 0; 49 | } 50 | } 51 | } else { 52 | config.help(argv[0]); 53 | } 54 | } else { 55 | fprintf(stderr, "Error initializing configuration.\n"); 56 | } 57 | 58 | return -1; 59 | } 60 | 61 | bool process_pcap_file(const net::mon::configuration& config) 62 | { 63 | // Open PCAP file. 64 | pcap::reader reader; 65 | if (reader.open(config.cap.device)) { 66 | // Initialize netmon worker. 67 | net::mon::worker worker(0, 68 | net::mon::worker::no_processor, 69 | config.evdir, 70 | config.file_allocation_size, 71 | config.buffer_size); 72 | 73 | if (worker.init("pcap", 74 | config.tcp4.size, 75 | config.tcp4.maxconns, 76 | config.tcp6.size, 77 | config.tcp6.maxconns, 78 | config.tcp4.timeout, 79 | config.tcp4.time_wait)) { 80 | pcap::callbacks callbacks; 81 | callbacks.ethernet = ethernet; 82 | callbacks.ipv4 = ipv4; 83 | callbacks.ipv6 = ipv6; 84 | 85 | pcap_argument arg; 86 | arg.worker = &worker; 87 | arg.reader = &reader; 88 | 89 | // Read PCAP file. 90 | if (reader.read_all(callbacks, &arg)) { 91 | // Remove expired connections. 92 | const pcap::timeval& timestamp = reader.timestamp(); 93 | 94 | worker.remove_expired((timestamp.tv_sec * 1000000ull) + 95 | timestamp.tv_usec); 96 | 97 | return true; 98 | } 99 | 100 | fprintf(stderr, "Error adding packet.\n"); 101 | } else { 102 | fprintf(stderr, "Error initializing netmon worker.\n"); 103 | } 104 | } else { 105 | fprintf(stderr, 106 | "Error opening file '%s' for reading.\n", 107 | config.cap.device); 108 | } 109 | 110 | return false; 111 | } 112 | 113 | bool process_interface(const net::mon::configuration& config) 114 | { 115 | net::capture::method capture_method; 116 | if (config.cap.m == net::mon::configuration::capture::method::ring_buffer) { 117 | capture_method = net::capture::method::ring_buffer; 118 | } else { 119 | capture_method = net::capture::method::socket; 120 | } 121 | 122 | // Create netmon workers. 123 | net::mon::workers workers; 124 | if (workers.create(config.nworkers, 125 | config.processors, 126 | config.evdir, 127 | config.file_allocation_size, 128 | config.buffer_size, 129 | capture_method, 130 | config.cap.device, 131 | config.cap.ifindex, 132 | config.cap.rcvbuf_size, 133 | config.cap.promiscuous_mode, 134 | config.cap.rb.block_size, 135 | config.cap.rb.frame_size, 136 | config.cap.rb.frame_count, 137 | config.tcp4.size, 138 | config.tcp4.maxconns, 139 | config.tcp6.size, 140 | config.tcp6.maxconns, 141 | config.tcp4.timeout, 142 | config.tcp4.time_wait)) { 143 | // Block signals SIGINT and SIGTERM. 144 | sigset_t set; 145 | sigemptyset(&set); 146 | sigaddset(&set, SIGINT); 147 | sigaddset(&set, SIGTERM); 148 | if (pthread_sigmask(SIG_BLOCK, &set, NULL) == 0) { 149 | // Start workers. 150 | if (workers.start()) { 151 | printf("Waiting for signal to arrive.\n"); 152 | 153 | // Wait for signal to arrive. 154 | int sig; 155 | while (sigwait(&set, &sig) != 0); 156 | 157 | printf("Signal received.\n"); 158 | 159 | workers.stop(); 160 | 161 | workers.show_statistics(); 162 | 163 | return true; 164 | } else { 165 | fprintf(stderr, "Error starting workers.\n"); 166 | } 167 | } else { 168 | fprintf(stderr, "Error blocking signals SIGINT and SIGTERM.\n"); 169 | } 170 | } else { 171 | fprintf(stderr, "Error creating workers.\n"); 172 | } 173 | 174 | return false; 175 | } 176 | 177 | bool ethernet(const void* buf, size_t len, const pcap::timeval& ts, void* user) 178 | { 179 | uint32_t usec = (static_cast(user)->reader->resolution() == 180 | pcap::resolution::microseconds) ? ts.tv_usec : 181 | ts.tv_usec / 1000; 182 | 183 | // Process ethernet frame. 184 | return static_cast(user)->worker->process_ethernet( 185 | buf, 186 | len, 187 | {static_cast(ts.tv_sec), static_cast(usec)} 188 | ); 189 | } 190 | 191 | bool ipv4(const void* buf, size_t len, const pcap::timeval& ts, void* user) 192 | { 193 | uint32_t usec = (static_cast(user)->reader->resolution() == 194 | pcap::resolution::microseconds) ? ts.tv_usec : 195 | ts.tv_usec / 1000; 196 | 197 | // Process IPv4 packet. 198 | return static_cast(user)->worker->process_ipv4( 199 | buf, 200 | len, 201 | {static_cast(ts.tv_sec), static_cast(usec)} 202 | ); 203 | } 204 | 205 | bool ipv6(const void* buf, size_t len, const pcap::timeval& ts, void* user) 206 | { 207 | uint32_t usec = (static_cast(user)->reader->resolution() == 208 | pcap::resolution::microseconds) ? ts.tv_usec : 209 | ts.tv_usec / 1000; 210 | 211 | // Process IPv6 packet. 212 | return static_cast(user)->worker->process_ipv6( 213 | buf, 214 | len, 215 | {static_cast(ts.tv_sec), static_cast(usec)} 216 | ); 217 | } 218 | -------------------------------------------------------------------------------- /pcap/pcap.h: -------------------------------------------------------------------------------- 1 | #ifndef PCAP_H 2 | #define PCAP_H 3 | 4 | #include 5 | 6 | namespace pcap { 7 | enum class magic : uint32_t { 8 | microseconds = 0xa1b2c3d4, 9 | nanoseconds = 0xa1b23c4d 10 | }; 11 | 12 | static constexpr const uint16_t version_major = 2; 13 | static constexpr const uint16_t version_minor = 4; 14 | 15 | enum class linklayer_header : uint32_t { 16 | ethernet = 1, 17 | raw = 101, 18 | linux_sll = 113 19 | }; 20 | 21 | struct pcap_file_header { 22 | uint32_t magic; 23 | uint16_t version_major; 24 | uint16_t version_minor; 25 | int32_t thiszone; 26 | uint32_t sigfigs; 27 | uint32_t snaplen; 28 | uint32_t linktype; 29 | }; 30 | 31 | struct timeval { 32 | uint32_t tv_sec; 33 | uint32_t tv_usec; 34 | }; 35 | 36 | struct pcap_pkthdr { 37 | timeval ts; 38 | uint32_t caplen; 39 | uint32_t len; 40 | }; 41 | 42 | enum class resolution { 43 | microseconds, 44 | nanoseconds 45 | }; 46 | } 47 | 48 | #endif // PCAP_H 49 | -------------------------------------------------------------------------------- /pcap/reader.h: -------------------------------------------------------------------------------- 1 | #ifndef PCAP_READER_H 2 | #define PCAP_READER_H 3 | 4 | #include 5 | #include "pcap/pcap.h" 6 | 7 | namespace pcap { 8 | // Packet callbacks. 9 | struct callbacks { 10 | bool (*ethernet)(const void* buf, 11 | size_t len, 12 | const struct timeval& timestamp, 13 | void* user) = nullptr; 14 | 15 | bool (*ipv4)(const void* buf, 16 | size_t len, 17 | const struct timeval& timestamp, 18 | void* user) = nullptr; 19 | 20 | bool (*ipv6)(const void* buf, 21 | size_t len, 22 | const struct timeval& timestamp, 23 | void* user) = nullptr; 24 | }; 25 | 26 | class reader { 27 | public: 28 | // Constructor. 29 | reader() = default; 30 | 31 | // Destructor. 32 | ~reader(); 33 | 34 | // Open PCAP file. 35 | bool open(const char* filename); 36 | 37 | // Close PCAP file. 38 | void close(); 39 | 40 | // Get next packet. 41 | const void* next(pcap_pkthdr& pkthdr); 42 | 43 | // Read all file. 44 | bool read_all(const callbacks& callbacks, void* user = nullptr); 45 | 46 | // Get PCAP file header. 47 | const pcap_file_header* file_header() const; 48 | 49 | // Get resolution. 50 | pcap::resolution resolution() const; 51 | 52 | // Get timestamp of the last packet. 53 | const timeval& timestamp() const; 54 | 55 | private: 56 | int _M_fd = -1; 57 | 58 | void* _M_base = MAP_FAILED; 59 | 60 | // Size of the file. 61 | size_t _M_filesize; 62 | 63 | // Pointer to the end. 64 | const uint8_t* _M_end; 65 | 66 | // Pointer to the next packet. 67 | const uint8_t* _M_ptr; 68 | 69 | // Resolution. 70 | pcap::resolution _M_resolution; 71 | 72 | // Timestamp of the last packet. 73 | timeval _M_timestamp = {}; 74 | 75 | // Read ethernet file. 76 | bool read_ethernet(const callbacks& callbacks, void* user); 77 | 78 | // Read raw file. 79 | bool read_raw(const callbacks& callbacks, void* user); 80 | 81 | // Read Linux SLL file. 82 | bool read_linux_sll(const callbacks& callbacks, void* user); 83 | 84 | // Process ethernet frame. 85 | static bool process_ethernet(const pcap_pkthdr& pkthdr, 86 | const void* pkt, 87 | const callbacks& callbacks, 88 | void* user); 89 | 90 | // Disable copy constructor and assignment operator. 91 | reader(const reader&) = delete; 92 | reader& operator=(const reader&) = delete; 93 | }; 94 | 95 | inline reader::~reader() 96 | { 97 | close(); 98 | } 99 | 100 | inline bool reader::read_all(const callbacks& callbacks, void* user) 101 | { 102 | switch (static_cast(file_header()->linktype)) { 103 | case linklayer_header::ethernet: 104 | return read_ethernet(callbacks, user); 105 | case linklayer_header::raw: 106 | return read_raw(callbacks, user); 107 | case linklayer_header::linux_sll: 108 | return read_linux_sll(callbacks, user); 109 | default: 110 | return false; 111 | } 112 | } 113 | 114 | inline const pcap_file_header* reader::file_header() const 115 | { 116 | return static_cast(_M_base); 117 | } 118 | 119 | inline pcap::resolution reader::resolution() const 120 | { 121 | return _M_resolution; 122 | } 123 | 124 | inline const timeval& reader::timestamp() const 125 | { 126 | return _M_timestamp; 127 | } 128 | } 129 | 130 | #endif // PCAP_READER_H 131 | -------------------------------------------------------------------------------- /php/style.css: -------------------------------------------------------------------------------- 1 | table, th, td { 2 | border: 1px solid black; 3 | } 4 | -------------------------------------------------------------------------------- /qevents/README.md: -------------------------------------------------------------------------------- 1 | qevents 2 | ======= 3 | Qt program which displays the TCP connections from a JSON file containing events. 4 | 5 | * Start `qevents`. 6 | * Click on `File` and then on `Open`. 7 | * Open the JSON file containing the events produced by `evreader` using as output `json`. 8 | * The listbox `IP addresses` is filled with all the IP addresses contained in the events file. 9 | * The listbox `Hosts` is filled with all the hostnames contained in the events file. 10 | * If you click on one IP address or on one host, the table below will be filled with all the connections from/to that IP address/host. 11 | * If you click on one of the connections, the table below will be filled with all the payload sizes sent either by the client or by the server. 12 | -------------------------------------------------------------------------------- /qevents/connection.cpp: -------------------------------------------------------------------------------- 1 | #include "connection.h" 2 | 3 | namespace event { 4 | 5 | void Connections::beginTcpConnection(const QString& sourceAddress, 6 | const QString& sourceHostname, 7 | in_port_t sourcePort, 8 | const QString& destinationAddress, 9 | const QString& destinationHostname, 10 | in_port_t destinationPort, 11 | uint64_t timestamp) 12 | { 13 | // Build connection key. 14 | Connection::Key key = Connection::Key::build(sourceAddress, 15 | sourcePort, 16 | destinationAddress, 17 | destinationPort); 18 | 19 | // Search connection. 20 | std::map::iterator 21 | it = m_openConnections.find(key); 22 | 23 | // If the connection has been found... 24 | if (it != m_openConnections.end()) { 25 | // Add connection to the list of closed connections. 26 | m_closedConnections.emplace_back(std::move(it->second)); 27 | 28 | // Remove open connection. 29 | m_openConnections.erase(it); 30 | } 31 | 32 | Connection conn(sourceAddress, 33 | sourceHostname, 34 | sourcePort, 35 | destinationAddress, 36 | destinationHostname, 37 | destinationPort, 38 | timestamp); 39 | 40 | // Add connection. 41 | m_openConnections.emplace(std::piecewise_construct, 42 | std::forward_as_tuple(key), 43 | std::forward_as_tuple(conn)); 44 | } 45 | 46 | void Connections::tcpData(const QString& sourceAddress, 47 | in_port_t sourcePort, 48 | const QString& destinationAddress, 49 | in_port_t destinationPort, 50 | uint64_t timestamp, 51 | uint16_t payload) 52 | { 53 | // Build connection key. 54 | Connection::Key key = Connection::Key::build(sourceAddress, 55 | sourcePort, 56 | destinationAddress, 57 | destinationPort); 58 | 59 | // Search connection. 60 | std::map::iterator 61 | it = m_openConnections.find(key); 62 | 63 | // If the connection has been found... 64 | if (it != m_openConnections.end()) { 65 | // Client payload? 66 | if ((sourcePort == it->second.clientPort()) && 67 | (sourceAddress == it->second.clientIp())) { 68 | it->second.addClientPayload(timestamp, payload); 69 | } else { 70 | it->second.addServerPayload(timestamp, payload); 71 | } 72 | } 73 | } 74 | 75 | void Connections::endTcpConnection(const QString& sourceAddress, 76 | in_port_t sourcePort, 77 | const QString& destinationAddress, 78 | in_port_t destinationPort, 79 | uint64_t timestamp, 80 | uint64_t transferredClient, 81 | uint64_t transferredServer) 82 | { 83 | // Build connection key. 84 | Connection::Key key = Connection::Key::build(sourceAddress, 85 | sourcePort, 86 | destinationAddress, 87 | destinationPort); 88 | 89 | // Search connection. 90 | std::map::iterator 91 | it = m_openConnections.find(key); 92 | 93 | // If the connection has been found... 94 | if (it != m_openConnections.end()) { 95 | it->second.end(timestamp); 96 | 97 | it->second.transferredClient(transferredClient); 98 | it->second.transferredServer(transferredServer); 99 | 100 | // Add connection to the list of closed connections. 101 | m_closedConnections.emplace_back(std::move(it->second)); 102 | 103 | // Remove open connection. 104 | m_openConnections.erase(it); 105 | } 106 | } 107 | 108 | } // namespace event 109 | -------------------------------------------------------------------------------- /qevents/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | MainWindow w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /qevents/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "event.h" 9 | 10 | namespace Ui { 11 | class MainWindow; 12 | } 13 | 14 | class MainWindow : public QMainWindow { 15 | Q_OBJECT 16 | 17 | public: 18 | // Constructor. 19 | explicit MainWindow(QWidget *parent = nullptr); 20 | 21 | // Destructor. 22 | ~MainWindow(); 23 | 24 | private slots: 25 | // On file open. 26 | void onOpen(); 27 | 28 | // On IP address selected. 29 | void onIpAddress(QListWidgetItem* item, QListWidgetItem* previous); 30 | 31 | // On host selected. 32 | void onHost(QListWidgetItem* item, QListWidgetItem* previous); 33 | 34 | // On connection selected. 35 | void onConnection(QTableWidgetItem* current, QTableWidgetItem* previous); 36 | 37 | private: 38 | // Events. 39 | event::Events m_events; 40 | 41 | // Connections. 42 | event::Connections m_connections; 43 | 44 | // Connections. 45 | std::vector m_connectionIndices; 46 | 47 | // Main window. 48 | Ui::MainWindow* m_ui; 49 | 50 | // Fill connections. 51 | void fillConnections(const std::function< 52 | bool(const event::Connection&) 53 | >& match); 54 | 55 | // Get time string. 56 | static QString getTimeString(uint64_t timestamp); 57 | }; 58 | 59 | #endif // MAINWINDOW_H 60 | -------------------------------------------------------------------------------- /qevents/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 791 10 | 660 11 | 12 | 13 | 14 | Events 15 | 16 | 17 | 18 | 19 | 20 | 30 21 | 30 22 | 300 23 | 131 24 | 25 | 26 | 27 | QFrame::WinPanel 28 | 29 | 30 | 31 | 32 | 33 | 350 34 | 30 35 | 400 36 | 131 37 | 38 | 39 | 40 | QFrame::WinPanel 41 | 42 | 43 | 44 | 45 | 46 | 30 47 | 10 48 | 91 49 | 16 50 | 51 | 52 | 53 | <html><head/><body><p>IP addresses:</p></body></html> 54 | 55 | 56 | 57 | 58 | 59 | 350 60 | 10 61 | 91 62 | 16 63 | 64 | 65 | 66 | <html><head/><body><p>Hosts:</p></body></html> 67 | 68 | 69 | 70 | 71 | 72 | 30 73 | 190 74 | 721 75 | 161 76 | 77 | 78 | 79 | 80 | 81 | 82 | 30 83 | 170 84 | 400 85 | 15 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 30 96 | 390 97 | 721 98 | 221 99 | 100 | 101 | 102 | 103 | 104 | 105 | 30 106 | 373 107 | 721 108 | 15 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 0 120 | 0 121 | 791 122 | 21 123 | 124 | 125 | 126 | 127 | File 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | &Open 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /qevents/qevents.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2019-02-08T06:21:09 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | QMAKE_CXXFLAGS += -g -Wall --pedantic -std=c++11 9 | 10 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 11 | 12 | TARGET = qevents 13 | TEMPLATE = app 14 | 15 | 16 | SOURCES += main.cpp\ 17 | mainwindow.cpp \ 18 | event.cpp \ 19 | connection.cpp 20 | 21 | HEADERS += mainwindow.h \ 22 | connection.h \ 23 | event.h 24 | 25 | FORMS += mainwindow.ui 26 | -------------------------------------------------------------------------------- /string/buffer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "string/buffer.h" 4 | 5 | bool string::buffer::allocate(size_t size) 6 | { 7 | // Add space for the null character. 8 | size_t s; 9 | if ((s = _M_used + size + 1) > size) { 10 | if (s <= _M_size) { 11 | return true; 12 | } 13 | 14 | size = s; 15 | 16 | if (_M_size > 0) { 17 | if ((s = _M_size * 2) <= _M_size) { 18 | // Overflow. 19 | return false; 20 | } 21 | } else { 22 | s = initial_size; 23 | } 24 | 25 | while (s < size) { 26 | size_t tmp; 27 | if ((tmp = s * 2) > s) { 28 | s = tmp; 29 | } else { 30 | // Overflow. 31 | return false; 32 | } 33 | } 34 | 35 | char* data; 36 | if ((data = static_cast(realloc(_M_data, s))) != nullptr) { 37 | _M_data = data; 38 | _M_size = s; 39 | 40 | return true; 41 | } 42 | } 43 | 44 | return false; 45 | } 46 | 47 | bool string::buffer::vformat(const char* format, va_list ap) 48 | { 49 | if (allocate(initial_size - 1)) { 50 | size_t size = remaining(); 51 | 52 | do { 53 | va_list aq; 54 | va_copy(aq, ap); 55 | int n = vsnprintf(end(), size, format, aq); 56 | va_end(aq); 57 | 58 | if (n > -1) { 59 | if (static_cast(n) < size) { 60 | increment_length(n); 61 | return true; 62 | } 63 | 64 | size = n + 1; 65 | } else { 66 | size *= 2; 67 | } 68 | } while (allocate(size)); 69 | } 70 | 71 | return false; 72 | } 73 | -------------------------------------------------------------------------------- /string/buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef STRING_BUFFER_H 2 | #define STRING_BUFFER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace string { 9 | class buffer { 10 | public: 11 | // Constructor. 12 | buffer(); 13 | buffer(buffer&& other); 14 | 15 | // Destructor. 16 | ~buffer(); 17 | 18 | // Move assignment operator. 19 | buffer& operator=(buffer&& other); 20 | 21 | // Swap content. 22 | void swap(buffer& other); 23 | 24 | // Free buffer. 25 | void free(); 26 | 27 | // Clear buffer. 28 | void clear(); 29 | 30 | // Get data. 31 | const char* data() const; 32 | char* data(); 33 | 34 | // Get end. 35 | char* end(); 36 | 37 | // Get size of allocated storage. 38 | size_t capacity() const; 39 | 40 | // Empty? 41 | bool empty() const; 42 | 43 | // Get length. 44 | size_t length() const; 45 | 46 | // Increment length. 47 | void increment_length(size_t inc); 48 | 49 | // Get remaining space available. 50 | size_t remaining() const; 51 | 52 | // Allocate memory. 53 | bool allocate(size_t size); 54 | 55 | // Append. 56 | bool append(char c); 57 | bool append(const char* string); 58 | bool append(const char* string, size_t len); 59 | 60 | // NULL-terminate string. 61 | void null_terminate(); 62 | 63 | // Format string. 64 | bool format(const char* format, ...); 65 | bool vformat(const char* format, va_list ap); 66 | 67 | private: 68 | static constexpr const size_t initial_size = 32; 69 | 70 | char* _M_data; 71 | size_t _M_size; 72 | size_t _M_used; 73 | 74 | // Disable copy constructor and assignment operator. 75 | buffer(const buffer&) = delete; 76 | buffer& operator=(const buffer&) = delete; 77 | }; 78 | 79 | inline buffer::buffer() 80 | : _M_data(nullptr), 81 | _M_size(0), 82 | _M_used(0) 83 | { 84 | } 85 | 86 | inline buffer::buffer(buffer&& other) 87 | : _M_data(other._M_data), 88 | _M_size(other._M_size), 89 | _M_used(other._M_used) 90 | { 91 | other._M_data = nullptr; 92 | other._M_size = 0; 93 | other._M_used = 0; 94 | } 95 | 96 | inline buffer::~buffer() 97 | { 98 | free(); 99 | } 100 | 101 | inline buffer& buffer::operator=(buffer&& other) 102 | { 103 | _M_data = other._M_data; 104 | _M_size = other._M_size; 105 | _M_used = other._M_used; 106 | 107 | other._M_data = nullptr; 108 | other._M_size = 0; 109 | other._M_used = 0; 110 | 111 | return *this; 112 | } 113 | 114 | inline void buffer::swap(buffer& other) 115 | { 116 | char* data = _M_data; 117 | _M_data = other._M_data; 118 | other._M_data = data; 119 | 120 | size_t s = _M_size; 121 | _M_size = other._M_size; 122 | other._M_size = s; 123 | 124 | s = _M_used; 125 | _M_used = other._M_used; 126 | other._M_used = s; 127 | } 128 | 129 | inline void buffer::free() 130 | { 131 | if (_M_data) { 132 | ::free(_M_data); 133 | _M_data = nullptr; 134 | } 135 | 136 | _M_size = 0; 137 | _M_used = 0; 138 | } 139 | 140 | inline void buffer::clear() 141 | { 142 | _M_used = 0; 143 | } 144 | 145 | inline const char* buffer::data() const 146 | { 147 | return _M_data; 148 | } 149 | 150 | inline char* buffer::data() 151 | { 152 | return _M_data; 153 | } 154 | 155 | inline char* buffer::end() 156 | { 157 | return _M_data + _M_used; 158 | } 159 | 160 | inline size_t buffer::capacity() const 161 | { 162 | return _M_size; 163 | } 164 | 165 | inline bool buffer::empty() const 166 | { 167 | return (_M_used == 0); 168 | } 169 | 170 | inline size_t buffer::length() const 171 | { 172 | return _M_used; 173 | } 174 | 175 | inline void buffer::increment_length(size_t inc) 176 | { 177 | _M_used += inc; 178 | } 179 | 180 | inline size_t buffer::remaining() const 181 | { 182 | return _M_size - _M_used; 183 | } 184 | 185 | inline bool buffer::append(char c) 186 | { 187 | if (allocate(1)) { 188 | _M_data[_M_used++] = c; 189 | return true; 190 | } 191 | 192 | return false; 193 | } 194 | 195 | inline bool buffer::append(const char* string) 196 | { 197 | return string ? append(string, strlen(string)) : true; 198 | } 199 | 200 | inline bool buffer::append(const char* string, size_t len) 201 | { 202 | if (len > 0) { 203 | if (allocate(len)) { 204 | memcpy(end(), string, len); 205 | _M_used += len; 206 | 207 | return true; 208 | } 209 | 210 | return false; 211 | } 212 | 213 | return true; 214 | } 215 | 216 | inline void buffer::null_terminate() 217 | { 218 | _M_data[_M_used] = 0; 219 | } 220 | 221 | inline bool buffer::format(const char* format, ...) 222 | { 223 | va_list ap; 224 | va_start(ap, format); 225 | 226 | bool ret = vformat(format, ap); 227 | 228 | va_end(ap); 229 | 230 | return ret; 231 | } 232 | } 233 | 234 | #endif // STRING_BUFFER_H 235 | -------------------------------------------------------------------------------- /test_segments.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "net/mon/tcp/segments.h" 5 | 6 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) 7 | 8 | static void payloadfn(const void*, size_t, void*); 9 | static void gapfn(size_t, void*); 10 | 11 | int main() 12 | { 13 | struct segment { 14 | uint32_t seqno; 15 | const char* payload; 16 | size_t len; 17 | }; 18 | 19 | net::mon::tcp::segments segments; 20 | if (segments.create(payloadfn, gapfn)) { 21 | { 22 | segments.next_sequence_number(0); 23 | 24 | static constexpr const segment segs[] = { 25 | {25, "Z0123", 5}, 26 | {15, "PQRST", 5}, 27 | {10, "KLMNO", 5}, 28 | { 5, "FGHIJ", 5}, 29 | { 0, "ABCDE", 5} 30 | }; 31 | 32 | for (size_t i = 0; i < ARRAY_SIZE(segs); i++) { 33 | if (!segments.add(segs[i].seqno, segs[i].payload, segs[i].len)) { 34 | fprintf(stderr, "Error adding segment %zu.\n", i + 1); 35 | return -1; 36 | } 37 | } 38 | 39 | segments.fin(); 40 | 41 | printf("========================================\n"); 42 | } 43 | 44 | { 45 | segments.clear(); 46 | segments.next_sequence_number(UINT_MAX - 2); 47 | 48 | static constexpr const segment segs[] = { 49 | { 22, "Z0123", 5}, 50 | { 12, "PQRST", 5}, 51 | { 7, "KLMNO", 5}, 52 | { 2, "FGHIJ", 5}, 53 | {UINT_MAX - 2, "ABCDE", 5} 54 | }; 55 | 56 | for (size_t i = 0; i < ARRAY_SIZE(segs); i++) { 57 | if (!segments.add(segs[i].seqno, segs[i].payload, segs[i].len)) { 58 | fprintf(stderr, "Error adding segment %zu.\n", i + 1); 59 | return -1; 60 | } 61 | } 62 | 63 | segments.fin(); 64 | 65 | printf("========================================\n"); 66 | } 67 | 68 | { 69 | segments.clear(); 70 | segments.next_sequence_number(UINT_MAX - 2); 71 | 72 | static constexpr const segment segs[] = { 73 | {UINT_MAX - 2, "ABCDE", 5}, 74 | { 2, "FGHIJ", 5}, 75 | { 7, "KLMNO", 5}, 76 | { 12, "PQRST", 5}, 77 | { 22, "Z0123", 5} 78 | }; 79 | 80 | for (size_t i = 0; i < ARRAY_SIZE(segs); i++) { 81 | if (!segments.add(segs[i].seqno, segs[i].payload, segs[i].len)) { 82 | fprintf(stderr, "Error adding segment %zu.\n", i + 1); 83 | return -1; 84 | } 85 | } 86 | 87 | segments.fin(); 88 | } 89 | 90 | return 0; 91 | } else { 92 | fprintf(stderr, "Error creating segments.\n"); 93 | } 94 | 95 | return -1; 96 | } 97 | 98 | void payloadfn(const void* payload, size_t len, void* user) 99 | { 100 | printf("[Payload] Length: %zu, ", len); 101 | 102 | for (size_t i = 0; i < len; i++) { 103 | printf("%c", static_cast(payload)[i]); 104 | } 105 | 106 | printf("\n"); 107 | } 108 | 109 | void gapfn(size_t len, void* user) 110 | { 111 | printf("[Gap] Length: %zu\n", len); 112 | } 113 | -------------------------------------------------------------------------------- /util/hash.cpp: -------------------------------------------------------------------------------- 1 | #include "util/hash.h" 2 | 3 | uint32_t util::hash::hashlittle(const void* key, 4 | size_t length, 5 | uint32_t initval) 6 | { 7 | uint32_t a, b, c; // Internal state. 8 | 9 | // Set up the internal state. 10 | a = b = c = hash_initval + static_cast(length) + initval; 11 | 12 | const uint8_t* k = static_cast(key); 13 | 14 | // All but last block: aligned reads and affect 32 bits of (a, b, c). 15 | while (length > 12) { 16 | a += get_unaligned_cpu32(k); 17 | b += get_unaligned_cpu32(k + 4); 18 | c += get_unaligned_cpu32(k + 8); 19 | 20 | hash_mix(a, b, c); 21 | 22 | length -= 12; 23 | 24 | k += 12; 25 | } 26 | 27 | switch (length) { 28 | case 12: c += static_cast(k[11]) << 24; // Fall through. 29 | case 11: c += static_cast(k[10]) << 16; // Fall through. 30 | case 10: c += static_cast(k[9]) << 8; // Fall through. 31 | case 9: c += k[8]; // Fall through. 32 | case 8: c += static_cast(k[7]) << 24; // Fall through. 33 | case 7: c += static_cast(k[6]) << 16; // Fall through. 34 | case 6: c += static_cast(k[5]) << 8; // Fall through. 35 | case 5: c += k[4]; // Fall through. 36 | case 4: c += static_cast(k[3]) << 24; // Fall through. 37 | case 3: c += static_cast(k[2]) << 16; // Fall through. 38 | case 2: c += static_cast(k[1]) << 8; // Fall through. 39 | case 1: 40 | c += k[0]; 41 | 42 | hash_final(a, b, c); 43 | break; 44 | } 45 | 46 | return c; 47 | } 48 | -------------------------------------------------------------------------------- /util/hash.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_HASH_H 2 | #define UTIL_HASH_H 3 | 4 | #include 5 | #include 6 | 7 | namespace util { 8 | class hash { 9 | public: 10 | // Hash functions by Bob Jenkins: 11 | // http://burtleburtle.net/bob/c/lookup3.c 12 | 13 | // Hash 1 word. 14 | static uint32_t hash_1word(uint32_t a, uint32_t initval); 15 | 16 | // Hash 2 words. 17 | static uint32_t hash_2words(uint32_t a, uint32_t b, uint32_t initval); 18 | 19 | // Hash 3 words. 20 | static uint32_t hash_3words(uint32_t a, 21 | uint32_t b, 22 | uint32_t c, 23 | uint32_t initval); 24 | 25 | // Hash a variable-length key into a 32-bit value. 26 | static uint32_t hashlittle(const void* key, 27 | size_t length, 28 | uint32_t initval); 29 | 30 | private: 31 | static constexpr const uint32_t hash_initval = 0xdeadbeef; 32 | 33 | // Hash n words (n can be 1, 2 or 3). 34 | static uint32_t hash_nwords(uint32_t a, 35 | uint32_t b, 36 | uint32_t c, 37 | uint32_t initval); 38 | 39 | static uint32_t rol32(uint32_t x, uint32_t k); 40 | static uint32_t get_unaligned_cpu32(const void* p); 41 | }; 42 | 43 | #define hash_mix(a, b, c) { \ 44 | a -= c; a ^= rol32(c, 4); c += b; \ 45 | b -= a; b ^= rol32(a, 6); a += c; \ 46 | c -= b; c ^= rol32(b, 8); b += a; \ 47 | a -= c; a ^= rol32(c, 16); c += b; \ 48 | b -= a; b ^= rol32(a, 19); a += c; \ 49 | c -= b; c ^= rol32(b, 4); b += a; \ 50 | } 51 | 52 | #define hash_final(a, b, c) { \ 53 | c ^= b; c -= rol32(b, 14); \ 54 | a ^= c; a -= rol32(c, 11); \ 55 | b ^= a; b -= rol32(a, 25); \ 56 | c ^= b; c -= rol32(b, 16); \ 57 | a ^= c; a -= rol32(c, 4); \ 58 | b ^= a; b -= rol32(a, 14); \ 59 | c ^= b; c -= rol32(b, 24); \ 60 | } 61 | 62 | inline uint32_t hash::hash_1word(uint32_t a, uint32_t initval) 63 | { 64 | return hash_nwords(a, 0, 0, initval + hash_initval + (1 << 2)); 65 | } 66 | 67 | inline uint32_t hash::hash_2words(uint32_t a, uint32_t b, uint32_t initval) 68 | { 69 | return hash_nwords(a, b, 0, initval + hash_initval + (2 << 2)); 70 | } 71 | 72 | inline uint32_t hash::hash_3words(uint32_t a, 73 | uint32_t b, 74 | uint32_t c, 75 | uint32_t initval) 76 | { 77 | return hash_nwords(a, b, c, initval + hash_initval + (3 << 2)); 78 | } 79 | 80 | inline uint32_t hash::hash_nwords(uint32_t a, 81 | uint32_t b, 82 | uint32_t c, 83 | uint32_t initval) 84 | { 85 | a += initval; 86 | b += initval; 87 | c += initval; 88 | 89 | hash_final(a, b, c); 90 | 91 | return c; 92 | } 93 | 94 | inline uint32_t hash::rol32(uint32_t x, uint32_t k) 95 | { 96 | return ((x << k) | (x >> ((-k) & 31))); 97 | } 98 | 99 | inline uint32_t hash::get_unaligned_cpu32(const void* p) 100 | { 101 | struct __una_u32 { 102 | uint32_t x; 103 | } __attribute__((packed)); 104 | 105 | return static_cast(p)->x; 106 | } 107 | } 108 | 109 | #endif // UTIL_HASH_H 110 | -------------------------------------------------------------------------------- /util/node.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_NODE_H 2 | #define UTIL_NODE_H 3 | 4 | namespace util { 5 | struct node { 6 | struct node* prev; 7 | struct node* next; 8 | }; 9 | } 10 | 11 | #endif // UTIL_NODE_H 12 | -------------------------------------------------------------------------------- /util/parser/number.cpp: -------------------------------------------------------------------------------- 1 | #include "util/parser/number.h" 2 | 3 | bool util::parser::number::parse_view(const char* s, 4 | size_t len, 5 | uint64_t& n, 6 | uint64_t min, 7 | uint64_t max) 8 | { 9 | if (len > 0) { 10 | uint64_t res = 0; 11 | 12 | for (size_t i = 0; i < len; i++) { 13 | uint64_t tmp; 14 | if ((s[i] >= '0') && 15 | (s[i] <= '9') && 16 | ((tmp = (res * 10) + (s[i] - '0')) >= res) && 17 | (tmp <= max)) { 18 | res = tmp; 19 | } else { 20 | return false; 21 | } 22 | } 23 | 24 | if (res >= min) { 25 | n = res; 26 | return true; 27 | } 28 | } 29 | 30 | return false; 31 | } 32 | -------------------------------------------------------------------------------- /util/parser/number.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_PARSER_NUMBER_H 2 | #define UTIL_PARSER_NUMBER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace util { 9 | namespace parser { 10 | class number { 11 | public: 12 | // Parse number. 13 | static bool parse(const char* s, 14 | uint64_t& n, 15 | uint64_t min = 0, 16 | uint64_t max = ULLONG_MAX); 17 | 18 | static bool parse_view(const char* s, 19 | size_t len, 20 | uint64_t& n, 21 | uint64_t min = 0, 22 | uint64_t max = ULLONG_MAX); 23 | }; 24 | 25 | inline bool number::parse(const char* s, 26 | uint64_t& n, 27 | uint64_t min, 28 | uint64_t max) 29 | { 30 | return parse_view(s, strlen(s), n, min, max); 31 | } 32 | } 33 | } 34 | 35 | #endif // UTIL_PARSER_NUMBER_H 36 | -------------------------------------------------------------------------------- /util/parser/size.cpp: -------------------------------------------------------------------------------- 1 | #include "util/parser/size.h" 2 | 3 | bool util::parser::size::parse_view(const char* s, 4 | size_t len, 5 | uint64_t& n, 6 | uint64_t min, 7 | uint64_t max) 8 | { 9 | if (len > 0) { 10 | uint64_t res = 0; 11 | 12 | for (size_t i = 0; i < len; i++) { 13 | uint64_t tmp; 14 | if ((s[i] >= '0') && (s[i] <= '9')) { 15 | if ((tmp = (res * 10) + (s[i] - '0')) >= res) { 16 | res = tmp; 17 | } else { 18 | // Overflow. 19 | return false; 20 | } 21 | } else if ((i > 0) && (i + 1 == len)) { 22 | uint64_t mul; 23 | 24 | switch (s[i]) { 25 | case 'G': // GiB. 26 | mul = static_cast(1) << 30; 27 | break; 28 | case 'M': // MiB. 29 | mul = static_cast(1) << 20; 30 | break; 31 | case 'K': // KiB. 32 | mul = static_cast(1) << 10; 33 | break; 34 | case 'B': // Bytes. 35 | mul = 1; 36 | break; 37 | default: 38 | return false; 39 | } 40 | 41 | if (res > 0) { 42 | if (((tmp = res * mul) >= res) && (tmp >= mul)) { 43 | res = tmp; 44 | } else { 45 | // Overflow. 46 | return false; 47 | } 48 | } 49 | 50 | break; 51 | } else { 52 | return false; 53 | } 54 | } 55 | 56 | if ((res >= min) && (res <= max)) { 57 | n = res; 58 | return true; 59 | } 60 | } 61 | 62 | return false; 63 | } 64 | -------------------------------------------------------------------------------- /util/parser/size.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_PARSER_SIZE_H 2 | #define UTIL_PARSER_SIZE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace util { 10 | namespace parser { 11 | class size { 12 | public: 13 | // Parse size. 14 | static bool parse(const char* s, 15 | uint64_t& n, 16 | uint64_t min = 0, 17 | uint64_t max = ULLONG_MAX); 18 | 19 | static bool parse_view(const char* s, 20 | size_t len, 21 | uint64_t& n, 22 | uint64_t min = 0, 23 | uint64_t max = ULLONG_MAX); 24 | 25 | #if __WORDSIZE == 32 26 | // Parse size. 27 | static bool parse(const char* s, 28 | size_t& n, 29 | size_t min = 0, 30 | size_t max = ULONG_MAX); 31 | 32 | static bool parse_view(const char* s, 33 | size_t len, 34 | size_t& n, 35 | size_t min = 0, 36 | size_t max = ULONG_MAX); 37 | #endif // __WORDSIZE == 32 38 | }; 39 | 40 | inline bool size::parse(const char* s, 41 | uint64_t& n, 42 | uint64_t min, 43 | uint64_t max) 44 | { 45 | return parse_view(s, strlen(s), n, min, max); 46 | } 47 | 48 | #if __WORDSIZE == 32 49 | inline bool size::parse(const char* s, size_t& n, size_t min, size_t max) 50 | { 51 | uint64_t res; 52 | if (parse(s, 53 | res, 54 | static_cast(min), 55 | static_cast(max))) { 56 | n = static_cast(res); 57 | return true; 58 | } 59 | 60 | return false; 61 | } 62 | 63 | inline bool size::parse_view(const char* s, 64 | size_t len, 65 | size_t& n, 66 | size_t min, 67 | size_t max) 68 | { 69 | uint64_t res; 70 | if (parse_view(s, 71 | len, 72 | res, 73 | static_cast(min), 74 | static_cast(max))) { 75 | n = static_cast(res); 76 | return true; 77 | } 78 | 79 | return false; 80 | } 81 | #endif // __WORDSIZE == 32 82 | } 83 | } 84 | 85 | #endif // UTIL_PARSER_SIZE_H 86 | --------------------------------------------------------------------------------