├── .gitignore ├── README ├── archlinux └── hone-git │ ├── PKGBUILD │ ├── hone-sensor-dkms.install │ └── hone-sensor.install.in ├── hone-pcapng.txt ├── logging ├── .gitignore ├── Makefile ├── README ├── hone.logrotate ├── hone.service └── honeread.c └── src ├── .gitignore ├── DISCLAIMER ├── LICENSE ├── Makefile ├── README ├── VERSION ├── debian ├── changelog ├── compat ├── control ├── copyright ├── docs ├── install.in └── rules ├── defsyms.mk ├── hone.spec.in ├── hone_notify.h ├── hone_notify_imp.c ├── honeevent.h ├── honeevent_imp.c ├── mmutil.c ├── mmutil.h ├── packet_notify.c ├── packet_notify.h ├── pcapng.c ├── pcapng.h ├── process_notify.c ├── process_notify.h ├── rhel6.patch ├── ringbuf.c ├── ringbuf.h ├── socket_lookup.h ├── socket_notify.c ├── socket_notify.h └── udev.rules /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | cscope.* 3 | *.o 4 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | src/README -------------------------------------------------------------------------------- /archlinux/hone-git/PKGBUILD: -------------------------------------------------------------------------------- 1 | 2 | [[ -f hone-sensor.install ]] || touch hone-sensor.install 3 | 4 | pkgbase=hone-git 5 | pkgname=(hone-sensor-dkms-git hone-sensor-git hone-reader-git hone-reader-dkms-git) 6 | pkgver=20140116 7 | pkgrel=1 8 | pkgdesc="Correlate captured packets to processes" 9 | url="https://github.com/HoneProject/Linux-Sensor" 10 | license=(GPL2) 11 | arch=(i686 x86_64) 12 | makedepends=(git linux-headers) 13 | if [[ -n "$LOCAL_BUILD" ]]; then 14 | echo "Cloning from local filesystem" 15 | _giturl="$pkgbase::git+file://`realpath $PWD/../..`" 16 | else 17 | _giturl="$pkgbase::git+https://github.com/HoneProject/Linux-Sensor.git" 18 | fi 19 | source=("$_giturl" 20 | hone-sensor.install.in) 21 | md5sums=(SKIP 22 | 0ed6996461d6a2779ad3d6587a5598ca) 23 | 24 | 25 | dosub() { 26 | for _pkg in ${pkgname[@]}; do 27 | if [[ `type -t $1_$_pkg` == function ]]; then 28 | msg "Starting %s()..." "$1_$_pkg" 29 | $1_$_pkg 30 | fi 31 | done 32 | } 33 | 34 | prepare() { 35 | cd "$pkgbase" 36 | 37 | local _gitver=`git rev-parse --short HEAD` 38 | echo "$pkgver-$_gitver" > "$srcdir/$pkgbase/src/VERSION" 39 | 40 | dosub prepare 41 | } 42 | 43 | build() { 44 | dosub build 45 | } 46 | 47 | 48 | ### hone-sensor-dkms-git 49 | 50 | package_hone-sensor-dkms-git() { 51 | install=hone-sensor-dkms.install 52 | backup=(etc/udev/rules.d/60-hone.rules) 53 | depends=(dkms) 54 | optdepends=('hone-reader-dkms: capture log files on system start') 55 | conflicts=(hone-sensor hone-sensor-dkms hone-sensor-git hone-reader hone-reader-git) 56 | provides=(hone-sensor-dkms) 57 | options=('!strip') 58 | 59 | cd "$startdir/$pkgbase" 60 | 61 | _gitver=`git rev-parse --short HEAD` 62 | git archive HEAD src | tar -xC "$pkgdir" --xform 's@^src@usr/src/'"hone-sensor-$pkgver"'@' 63 | 64 | cd "$pkgdir/usr/src/hone-sensor-$pkgver" 65 | 66 | install -d "$pkgdir/etc/udev/rules.d" 67 | install -m 0644 udev.rules "$pkgdir/etc/udev/rules.d/60-hone.rules" 68 | rm -rf .gitignore debian hone.spec.in rhel6.patch udev.rules 69 | make dkms.conf DKMSNAME=hone-sensor DKMSVER=$pkgver 70 | sed -i -rf- dkms.conf <<"EOF" 71 | /^AUTOINSTALL/a MAKE[0]="'make' System.map all KVER=$kernelver" \ 72 | CLEAN="make clean; rm -f System.map" 73 | EOF 74 | } 75 | 76 | 77 | ### hone-sensor-git 78 | 79 | prepare_hone-sensor-git() { 80 | cd "$startdir" 81 | 82 | local _extramodules="$(readlink -f "/usr/lib/modules/${_kernver:-$(uname -r)}/extramodules")" 83 | sed -r 's@^(extramodules=).*$@\1'"$_extramodules"'@' hone-sensor.install.in > hone-sensor.install 84 | } 85 | 86 | build_hone-sensor-git() { 87 | cd "$srcdir/$pkgbase/src" 88 | 89 | local _modules="/usr/lib/modules/${_kernver:-$(uname -r)}" 90 | 91 | nm "$_modules/build/vmlinux" > System.map 92 | make KSRC="$_modules/build" SYSMAP="$PWD/System.map" 93 | } 94 | 95 | package_hone-sensor-git() { 96 | install=hone-sensor.install 97 | backup=(etc/udev/rules.d/60-hone.rules) 98 | depends=(linux) 99 | optdepends=('hone-reader: capture log files on system start') 100 | conflicts=(hone-sensor hone-sensor-dkms hone-sensor-dkms-git hone-reader-dkms hone-reader-dkms-git) 101 | provides=(hone-sensor) 102 | options=('!strip') 103 | 104 | cd "$srcdir/$pkgbase/src" 105 | 106 | local _modules="/usr/lib/modules/${_kernver:-$(uname -r)}" 107 | 108 | make KSRC="$_modules/build" SYSMAP="$PWD/System.map" INSTALL_MOD_PATH="$pkgdir/usr" modules_install 109 | 110 | mv "$pkgdir$_modules/"{extra,$(readlink $_modules/extramodules)} 111 | rmdir $pkgdir$_modules 112 | 113 | install -d "$pkgdir/etc/udev/rules.d" 114 | install -d "$pkgdir/usr/share/doc/hone" 115 | install -m 0644 udev.rules "$pkgdir/etc/udev/rules.d/60-hone.rules" 116 | install -m 0444 README "$pkgdir/usr/share/doc/hone/README" 117 | } 118 | 119 | 120 | ### hone-reader-git 121 | 122 | build_hone-reader-git() { 123 | cd "$srcdir/$pkgbase/logging" 124 | 125 | make 126 | } 127 | 128 | _package_hone-reader() { 129 | cd "$srcdir/$pkgbase/logging" 130 | 131 | make install DESTDIR="$pkgdir" PREFIX="/usr/bin" 132 | install -Dm 0644 hone.logrotate "$pkgdir/etc/logrotate.d/hone" 133 | install -Dm 0644 hone.service "$pkgdir/usr/lib/systemd/system/hone.service" 134 | } 135 | 136 | package_hone-reader-git() { 137 | depends=(hone-sensor) 138 | optdepends=('systemd: start hone captures on system startup' 139 | 'logrotate: rotate capture files') 140 | conflicts=(hone-reader hone-reader-dkms hone-reader-dkms-git) 141 | provides=(hone-reader) 142 | 143 | _package_hone-reader 144 | } 145 | 146 | 147 | ### hone-reader-dkms-git 148 | 149 | build_hone-reader-dkms-git() { 150 | build_hone-reader-git 151 | } 152 | 153 | package_hone-reader-dkms-git() { 154 | depends=(hone-sensor-dkms) 155 | optdepends=('systemd: start hone captures on system startup' 156 | 'logrotate: rotate capture files') 157 | conflicts=(hone-reader hone-reader-dkms hone-reader-git) 158 | provides=(hone-reader-dkms) 159 | 160 | _package_hone-reader 161 | sed -i -r '/^#(After|Conflicts)=/{s/^#//;b};/^Conflicts=/s/^/#/' "$pkgdir/usr/lib/systemd/system/hone.service" 162 | } 163 | 164 | # vim:set sts=2 ts=2 sw=2 et: 165 | -------------------------------------------------------------------------------- /archlinux/hone-git/hone-sensor-dkms.install: -------------------------------------------------------------------------------- 1 | 2 | dkms_install() { 3 | dkms install hone-sensor/${1%-*} 4 | } 5 | 6 | post_install() { 7 | getent group hone >/dev/null || groupadd --system hone 8 | dkms_install "$1" 9 | } 10 | 11 | pre_upgrade() { 12 | pre_remove "$2" 13 | } 14 | 15 | post_upgrade() { 16 | dkms_install "$1" 17 | } 18 | 19 | pre_remove() { 20 | if [[ -z "$1" ]]; then 21 | set -- $(pacman -Q hone-sensor-dkms-git | cut -d' ' -f2) 22 | fi 23 | [[ -n "${1%-*}" ]] && dkms remove hone-sensor/${1%-*} --all >/dev/null || true 24 | } 25 | 26 | post_remove() { 27 | if getent group hone >/dev/null; then 28 | echo "==> 'hone' group was not removed." 29 | fi 30 | } 31 | 32 | # vim:set ts=2 sw=2 et: 33 | -------------------------------------------------------------------------------- /archlinux/hone-git/hone-sensor.install.in: -------------------------------------------------------------------------------- 1 | extramodules=/usr/lib/modules/$(uname -r)/extramodules 2 | 3 | post_install() { 4 | post_upgrade 5 | getent group hone >/dev/null || groupadd --system hone 6 | } 7 | 8 | post_upgrade() { 9 | depmod $(< $extramodules/version) &>/dev/null 10 | } 11 | 12 | post_remove() { 13 | post_upgrade 14 | if getent group hone >/dev/null; then 15 | echo "==> 'hone' group was not removed." 16 | fi 17 | } 18 | 19 | # vim:set ts=2 sw=2 et: 20 | -------------------------------------------------------------------------------- /hone-pcapng.txt: -------------------------------------------------------------------------------- 1 | Hone Augmented PCAP Next Generation Dump File Format 2 | 3 | Table of Contents 4 | 5 | 1. Introduction 6 | 2. Section Information 7 | 3. Process Information 8 | 3.1. Process Event Block 9 | 4. Connection Information (Optional) 10 | 4.1. Connection Event Block 11 | 5. Packet Information 12 | 6. References 13 | 14 | 15 | 1. Introduction 16 | 17 | The PCAP format has become the standard format for dumping captured packets in 18 | the free and open-source software community. Hone strives to adhere to this 19 | format as much as possible to help achieve acceptance within the networking 20 | community and to allow interoperability with other software. The original PCAP 21 | format, however, is deficient in describing anything except packets. Luckily, 22 | there is a new PCAP format, PCAP-NG (PCAP Next Generation), on the horizon with 23 | initial support in libpcap, wireshark, and other analysis software. 24 | 25 | PCAP-NG allows for nearly any type of data to be dumped, in addition to 26 | packets, using a generic block format. Applications that lack support for a 27 | particular block type may just ignore it and continue processing blocks they do 28 | support. This provides an opportunity to utilize this new format to include 29 | process information along with packets while remaining compatible with 30 | applications that are lacking process support. 31 | 32 | There are a minimum of two pieces of data that must be captured to perform 33 | packet-process correlation and a third that while optional provides additional 34 | information and simplifies the capture in the Linux kernel. The most obvious 35 | data that must be captured is the packet data. This data is already well 36 | defined but requires an additional piece of information to correlate packets: 37 | the process identifier. This leads to the second piece of data we must collect: 38 | process information. The third and optional piece is connection information. 39 | While collecting connection information doesn't necessarily help correlate 40 | packets to processes, it does give additional information that may be 41 | impossible to glean from the packet data, such as determining when a socket was 42 | created and destroyed. 43 | 44 | Below is a description of how the PCAP-NG format is extended to support the 45 | data required by Hone. Please see the PCAP-NG draft specification [1] for more 46 | information as the sections below build on ideas and terminology from that 47 | document. 48 | 49 | An HTML version of this document is available on GitHub [2] and will likely be 50 | more up-to-date. 51 | 52 | 53 | 2. Section Information 54 | 55 | Hone utilizes the Section Header Block defined in section 3.1 [1] with the 56 | addition of Hone-specific options. In addition to the options defined in 57 | section 3.1 [1] (Section Header Block Options), the following options are valid 58 | within this block: 59 | 60 | +======+==========+==========================================================+ 61 | | Code | Length | Description | 62 | +======+==========+==========================================================+ 63 | | 257 | 16 | GUID which uniquely identifies the machine. | 64 | +------+----------+----------------------------------------------------------+ 65 | 66 | 67 | 3. Process Information 68 | 69 | Process information requires a new PCAP-NG block type as defined below. 70 | 71 | 72 | 3.1. Process Event Block 73 | 74 | 0 1 2 3 75 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 76 | +---------------------------------------------------------------+ 77 | 0 | Block Type = 0x00000101 | 78 | +---------------------------------------------------------------+ 79 | 4 | Block Total Length | 80 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 81 | 8 | Process ID | 82 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 83 | 12 | Timestamp (High) | 84 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 85 | 16 | Timestamp (Low) | 86 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 87 | / / 88 | / Options (variable) / 89 | / / 90 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 91 | | Block Total Length | 92 | +---------------------------------------------------------------+ 93 | 94 | The meaning of the fields is: 95 | 96 | * Block Type: the block type of the Process Event Block is 257. 97 | * Block Total Length: total size of this block, as described in section 2.1 98 | [1] (General Block Structure). 99 | * Process ID: the process ID (PID) as given by the OS. 100 | * Timestamp (High) and Timestamp (Low): high and low 32-bits of a 64-bit 101 | quantity representing the timestamp, as described in section 3.3 [1] 102 | (Enhanced Packet Block). 103 | * Options: optionally, a list of options (formatted according to the rules 104 | defined in section 2.5 [1] (Options)) can be present. 105 | 106 | In addition to the options defined in section 2.5 [1] (Options), the following 107 | options are valid within this block: 108 | 109 | +======+==========+======================================+===================+ 110 | | Code | Length | Description | Example(s) | 111 | +======+==========+======================================+===================+ 112 | | 2 | 4 | A value describing the state of the | | 113 | | | | process: see below | | 114 | +------+----------+--------------------------------------+-------------------+ 115 | | 3 | Variable | A UTF-8 string containing the full | | 116 | | | | path to the executable. | "/usr/bin/bash" | 117 | +------+----------+--------------------------------------+-------------------+ 118 | | 4 | Variable | Zero terminated UTF-8 strings | | 119 | | | | containing the argv components. | "bash\0--login\0" | 120 | +------+----------+--------------------------------------+-------------------+ 121 | | 5 | 4 | Process ID (PID) of parent. | 1 | 122 | +------+----------+--------------------------------------+-------------------+ 123 | | 6 | 4 | Effective user ID. | 1000 | 124 | +------+----------+--------------------------------------+-------------------+ 125 | | 7 | 4 | Effective group ID. | 100 | 126 | +------+----------+--------------------------------------+-------------------+ 127 | | 8 | Variable | Effective user name. | "jdoe" | 128 | +------+----------+--------------------------------------+-------------------+ 129 | | 9 | Variable | Effective group name. | "users" | 130 | +------+----------+--------------------------------------+-------------------+ 131 | 132 | If the proc_event option is not included, it is considered to be equal to start 133 | (0x00). 134 | 135 | Some systems may allow paths and command-line parameters to exceed 65536 136 | characters. Those options (proc_path and proc_argv) may be used multiple times 137 | within the same block with the value spread across multiple entries of the same 138 | option type which, when read, should be concatenated to form the actual option 139 | value. 140 | 141 | List of proc_event values: 142 | 143 | * 0x00000000 - process started (includes exec and post-CreateProcess) 144 | * 0x00000001 - child process spawned (includes fork and CreateProcess) 145 | * 0xFFFFFFFF - process ended 146 | 147 | 148 | 4. Connection Information (Optional) 149 | 150 | Connection information requires a new PCAP-NG block type as defined below. 151 | 152 | 153 | 4.1. Connection Event Block 154 | 155 | 0 1 2 3 156 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 157 | +---------------------------------------------------------------+ 158 | 0 | Block Type = 0x00000102 | 159 | +---------------------------------------------------------------+ 160 | 4 | Block Total Length | 161 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 162 | 8 | Connection ID | 163 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 164 | 12 | Process ID | 165 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 166 | 16 | Timestamp (High) | 167 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 168 | 20 | Timestamp (Low) | 169 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 170 | / / 171 | / Options (variable) / 172 | / / 173 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 174 | | Block Total Length | 175 | +---------------------------------------------------------------+ 176 | 177 | The meaning of the fields is: 178 | 179 | * Block Type: the block type of the Connection Event Block is 258. Block 180 | * Total Length: total size of this block, as described in section 2.1 [1] 181 | (General Block Structure). 182 | * Connection ID: the connection ID of the 183 | connection. This ID is unique only over the lifetime of the connection. 184 | * Process ID: the process ID (PID) of the process. Timestamp (High) and 185 | * Timestamp (Low): high and low 32-bits of a 64-bit quantity representing the 186 | timestamp, as described in section 3.3 [1] (Enhanced Packet Block). 187 | * Options: optionally, a list of options (formatted according to the rules 188 | defined in section 2.5 [1] (Options)) can be present. 189 | 190 | In addition to the options defined in section 2.5 [1] (Options), the following 191 | options are valid within this block: 192 | 193 | +======+==========+==========================================================+ 194 | | Code | Length | Description | 195 | +======+==========+==========================================================+ 196 | | 2 | 4 | Value describing the event: 0x00 = open, | 197 | | | | 0xFFFFFFFF = close (others?). | 198 | +------+----------+----------------------------------------------------------+ 199 | 200 | If conn_event is not specified, it is assumed to be open (0x00). 201 | 202 | 203 | 5. Packet Information 204 | 205 | Packet information utilizes the Enhanced Packet Block defined in section 3.3 206 | [1] with the addition of Hone-specific options. In addition to the options 207 | defined in section 3.3 [1] (Enhanced Packet Block Options), the following 208 | options are valid within this block: 209 | 210 | +======+==========+==========================================================+ 211 | | Code | Length | Description | 212 | +======+==========+==========================================================+ 213 | | 257 | 4 | Connection ID of connection associated with the packet. | 214 | +------+----------+----------------------------------------------------------+ 215 | | 258 | 4 | Process ID of process associated with the packet. | 216 | +------+----------+----------------------------------------------------------+ 217 | 218 | 219 | 6. References 220 | 221 | [1] PCAP Next Generation Dump File Format. 222 | http://www.winpcap.org/ntar/draft/PCAP-DumpFileFormat.html 223 | 224 | [2] Hone Augmented PCAP Next Generation Dump File Format 225 | https://github.com/HoneProject/Linux-Sensor/wiki/Augmented-PCAP-Next-Generation-Dump-File-Format 226 | 227 | -------------------------------------------------------------------------------- /logging/.gitignore: -------------------------------------------------------------------------------- 1 | honelogd 2 | -------------------------------------------------------------------------------- /logging/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2011 Battelle Memorial Institute 3 | # 4 | # Licensed under the GNU General Public License Version 2. 5 | # See ../src/LICENSE for the full text of the license. 6 | # See ../src/DISCLAIMER for additional disclaimers. 7 | # 8 | # Author: Brandon Carpenter 9 | # 10 | 11 | PREFIX ?= /usr/local/bin 12 | DESTDIR ?= "" 13 | HONEDIR ?= ../src 14 | 15 | all: honeread 16 | 17 | clean: 18 | -rm -f honeread 19 | 20 | honeread: honeread.c 21 | gcc -Wall -O2 $(CFLAGS) -I$(HONEDIR) -o $@ $< 22 | 23 | install: honeread 24 | install -Dm 0755 $^ "$(DESTDIR)$(PREFIX)/$^" 25 | 26 | uninstall: 27 | rm -f "$(DESTDIR)$(PREFIX)/honeread" 28 | 29 | -------------------------------------------------------------------------------- /logging/README: -------------------------------------------------------------------------------- 1 | 2 | INTRODUCTION 3 | 4 | honeread is an example reader/logger for the Hone Linux sensor. It 5 | demonstrates reading from /dev/hone using both read(2)/write(2) and splice(2) 6 | as well as using ioctl(3p) to set the snaplen and to notify the sensor to 7 | terminate the file. honeread can also be used to read /dev/honet. 8 | 9 | 10 | DOWNLOADING 11 | 12 | You can get the source code by cloning the repository or by downloading a zip 13 | file from Github: 14 | 15 | https://github.com/HoneProject/Linux-Sensor 16 | 17 | 18 | BUILDING 19 | 20 | From within the Hone sensor source tree, just run make. If building out of 21 | tree, set HONEDIR to the full path where honeevent.h is found. 22 | 23 | 24 | USAGE 25 | 26 | After building, run `./honeread --help` for advanced usage. Basic usage is to 27 | run honeread with one argument, the file where the output should be written. 28 | The output will be written to standard out (stdout) by default, which is 29 | probably not a great idea when reading from /dev/hone since it is a binary 30 | file, but it allows one to easily pipe the output into another program. 31 | 32 | The Hone sensor kernel driver must be loaded before attempting to log with 33 | honeread as it attaches to the device implemented in the driver. 34 | 35 | 36 | LICENSE 37 | 38 | honeread is covered under the same license as the sensor, GPL version 2. 39 | 40 | 41 | BUGS 42 | 43 | Please use the Github issue tracker to report bugs: 44 | 45 | https://github.com/HoneProject/Linux-Sensor/issues 46 | 47 | -------------------------------------------------------------------------------- /logging/hone.logrotate: -------------------------------------------------------------------------------- 1 | 2 | # /etc/logrotate.d/hone 3 | # logrotate script for honeread. 4 | # Use with Hone systemd unit and logrotate. 5 | 6 | /var/log/hone.pcapng { 7 | compress 8 | delaycompress 9 | daily 10 | maxsize 1G 11 | notifempty 12 | rotate 20 13 | postrotate 14 | /usr/bin/systemctl reload-or-try-restart hone.service 15 | endscript 16 | } 17 | 18 | -------------------------------------------------------------------------------- /logging/hone.service: -------------------------------------------------------------------------------- 1 | # Hone logging service for systemd 2 | 3 | [Unit] 4 | Description=Hone Packet-process Logging Daemon 5 | ## If using dkms to build hone, the following lines should be uncommented 6 | #Conflicts=hone.service 7 | #After=dkms.service 8 | ## and the following line should be commented. 9 | Conflicts=hone-dkms.service 10 | Before=network.target 11 | 12 | [Service] 13 | UMask=0027 14 | ExecStartPre=/usr/bin/modprobe hone 15 | ExecStart=/usr/bin/honeread -a -s 96 /var/log/hone.pcapng 16 | ExecReload=/bin/kill -HUP $MAINPID 17 | KillMode=process 18 | Restart=always 19 | 20 | [Install] 21 | WantedBy=multi-user.target 22 | 23 | -------------------------------------------------------------------------------- /logging/honeread.c: -------------------------------------------------------------------------------- 1 | /* 2 | * honeread - Example reader for hone character device 3 | * 4 | * Copyright (C) 2011 Battelle Memorial Institute 5 | * 6 | * Licensed under the GNU General Public License Version 2. 7 | * See ../src/LICENSE for the full text of the license. 8 | * See ../src/DISCLAIMER for additional disclaimers. 9 | * 10 | * Author: Brandon Carpenter 11 | * 12 | * honeread is a rewrite of honelogd. The SysV daemon features were 13 | * removed in favor of new-style daemon behavior used in systemd. Those 14 | * requiring SysV behavior should use honeread with start-stop-daemon. 15 | */ 16 | 17 | #define _FILE_OFFSET_BITS 64 18 | #define _GNU_SOURCE 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "honeevent.h" 37 | 38 | 39 | #define DEV_PATH "/dev/hone" 40 | 41 | 42 | static sig_atomic_t done = 0; 43 | static sig_atomic_t restart = 0; 44 | 45 | 46 | static void sighandler(int signum) 47 | { 48 | switch(signum) { 49 | case SIGHUP: 50 | if (!restart) 51 | restart = 1; 52 | break; 53 | case SIGINT: case SIGTERM: 54 | done++; 55 | if (done > 3) 56 | exit(EX_OK); 57 | break; 58 | default: 59 | break; 60 | } 61 | } 62 | 63 | 64 | static int log_stderr(const char *format, ...) 65 | { 66 | int result; 67 | va_list args; 68 | 69 | va_start(args, format); 70 | result = vdprintf(STDERR_FILENO, format, args); 71 | va_end(args); 72 | return result; 73 | } 74 | 75 | 76 | static int nolog(const char *format, ...) 77 | { 78 | return 0; 79 | } 80 | 81 | 82 | static int (*verbose1)(const char *format, ...) = nolog; 83 | static int (*verbose2)(const char *format, ...) = nolog; 84 | static int (*verbose3)(const char *format, ...) = nolog; 85 | 86 | 87 | static int parse_unsigned_int(unsigned int *value, const char *str) 88 | { 89 | unsigned long tmp; 90 | char *end; 91 | 92 | tmp = strtoul(str, &end, 10); 93 | if (!*str || *end || (tmp > UINT32_MAX && tmp != -1)) 94 | return -1; 95 | *value = tmp == -1 ? UINT32_MAX : (unsigned int) tmp; 96 | return 0; 97 | } 98 | 99 | 100 | const char *argp_program_version = "honeread 0.9"; 101 | const char *argp_program_bug_address = 102 | "Brandon Carpenter "; 103 | 104 | 105 | int main(int argc, char *argv[]) 106 | { 107 | int out_fd = -1, use_splice = 1, truncate = O_TRUNC, verboseness = 0; 108 | char *buf = NULL, *dev_path = DEV_PATH, *out_path = NULL; 109 | int restart_requested, dev_fd, pipe_in, pipe_out, pipe_fd[2]; 110 | ssize_t n, m; 111 | unsigned int snaplen = 0, buflen = 8192; 112 | ssize_t (*read_dev)(void); 113 | ssize_t (*write_out)(void); 114 | 115 | struct argp_option options[] = { 116 | {"append", 'a', 0, 0, "append new records instead of overwriting"}, 117 | {"device", 'd', "DEVICE", 0, "read events from DEVICE (default: " DEV_PATH ")"}, 118 | {"buflen", 'l', "BYTES", 0, "set buffer length; implies -n (default: 8192)"}, 119 | {"no-splice", 'n', 0, 0, "use read()/write() instead of splice"}, 120 | {"quiet", 'q', 0, 0, "decrease verboseness of debug output"}, 121 | {"snaplen", 's', "BYTES", 0, "set maximum packet capture size to BYTES bytes"}, 122 | {"verbose", 'v', 0, 0, "increase verboseness of debug output"}, 123 | {0}, 124 | }; 125 | 126 | error_t parse_opt(int key, char *arg, struct argp_state *state) 127 | { 128 | switch (key) { 129 | case 'a': 130 | truncate = 0; 131 | break; 132 | case 'd': 133 | dev_path = arg; 134 | break; 135 | case 'l': 136 | if (parse_unsigned_int(&buflen, arg)) 137 | argp_error(state, "invalid buflen: %s\n", arg); 138 | use_splice = 0; 139 | break; 140 | case 'n': 141 | use_splice = 0; 142 | break; 143 | case 'q': 144 | verboseness--; 145 | break; 146 | case 's': 147 | if (parse_unsigned_int(&snaplen, arg)) 148 | argp_error(state, "invalid snaplen: %s\n", arg); 149 | break; 150 | case 'v': 151 | verboseness++; 152 | break; 153 | case ARGP_KEY_ARG: 154 | if (!state->arg_num) 155 | out_path = arg; 156 | else 157 | return ARGP_ERR_UNKNOWN; 158 | break; 159 | default: 160 | return ARGP_ERR_UNKNOWN; 161 | } 162 | return 0; 163 | } 164 | 165 | struct argp argp = {options, parse_opt, "[OUTPUT_FILE]", 166 | "Read Hone events and write to a file or standard output.", 167 | NULL, NULL, NULL}; 168 | 169 | if (argp_parse(&argp, argc, argv, 0, NULL, NULL)) 170 | err(EX_OSERR, "argp_parse() failed"); 171 | 172 | if (verboseness > 0) 173 | verbose1 = log_stderr; 174 | if (verboseness > 1) 175 | verbose2 = log_stderr; 176 | if (verboseness > 2) 177 | verbose3 = log_stderr; 178 | 179 | verbose2("Options:\n"); 180 | verbose2(" buffer size: "); 181 | if (use_splice) 182 | verbose2("unused\n"); 183 | else 184 | verbose2("%u\n", buflen); 185 | verbose2(" input device: %s\n", dev_path); 186 | verbose2(" output file: %s\n", out_path ?: ""); 187 | verbose2(" snaplen: %u\n", snaplen); 188 | verbose2(" use splice: %s\n", use_splice ? "yes" : "no"); 189 | verbose2(" verbosity level: %d\n", verboseness); 190 | 191 | if (verboseness > 3) 192 | err(EX_USAGE, "verboseness limit exceeded"); 193 | 194 | signal(SIGHUP, sighandler); 195 | signal(SIGINT, sighandler); 196 | signal(SIGTERM, sighandler); 197 | 198 | ssize_t splice_read(void) 199 | { 200 | return splice(dev_fd, NULL, pipe_in, NULL, 65536, 0); 201 | } 202 | 203 | ssize_t splice_write(void) 204 | { 205 | return splice(pipe_out, NULL, out_fd, NULL, n, 0); 206 | } 207 | 208 | ssize_t conventional_read(void) 209 | { 210 | return read(dev_fd, buf, buflen); 211 | } 212 | 213 | ssize_t conventional_write(void) 214 | { 215 | return write(out_fd, buf, n); 216 | } 217 | 218 | if (use_splice) { 219 | if (pipe(pipe_fd)) 220 | err(EX_OSERR, "pipe() failed"); 221 | pipe_out = pipe_fd[0]; 222 | pipe_in = pipe_fd[1]; 223 | read_dev = splice_read; 224 | write_out = splice_write; 225 | } else { 226 | if (!(buf = (typeof(buf)) malloc(buflen))) 227 | err(EX_OSERR, "malloc() failed"); 228 | read_dev = conventional_read; 229 | write_out = conventional_write; 230 | } 231 | 232 | if ((dev_fd = open(dev_path, O_RDONLY, 0)) == -1) 233 | err(EX_NOINPUT, "open() failed on %s", dev_path); 234 | if (snaplen && ioctl(dev_fd, HEIO_SET_SNAPLEN, snaplen) == -1) 235 | err(EX_IOERR, "set snaplen ioctl() failed"); 236 | 237 | void close_out(void) 238 | { 239 | if (close(out_fd)) 240 | err(EX_OSERR, "close() failed on %s", out_path); 241 | out_fd = -1; 242 | } 243 | 244 | restart: 245 | restart = 0; 246 | restart_requested = 0; 247 | 248 | if (out_fd != -1) 249 | close_out(); 250 | if (!out_path || !strcmp(out_path, "-")) { 251 | if ((out_fd = dup(STDOUT_FILENO)) == -1) 252 | err(EX_CANTCREAT, "dup() failed on stdout"); 253 | } else { 254 | if ((out_fd = open(out_path, 255 | O_WRONLY | O_CREAT | O_LARGEFILE | truncate, 00664)) == -1) 256 | err(EX_CANTCREAT, "open() failed on %s", out_path); 257 | if (!truncate && lseek(out_fd, 0, SEEK_END) == (off_t) -1) 258 | err(EX_OSERR, "error seeking to end of output file"); 259 | } 260 | 261 | if (use_splice) { 262 | int is_fifo = 0; 263 | struct stat st; 264 | 265 | if (fstat(out_fd, &st)) 266 | warn("fstat() failed"); 267 | else 268 | is_fifo = S_ISFIFO(st.st_mode); 269 | pipe_in = is_fifo ? out_fd : pipe_fd[1]; 270 | 271 | verbose2("output file is%s a FIFO\n", is_fifo ? "" : " not"); 272 | } 273 | 274 | for (;;) { 275 | if ((restart || done) && !restart_requested) { 276 | if (ioctl(dev_fd, HEIO_RESTART) == -1) 277 | err(EX_OSERR, "reset ioctl() failed"); 278 | verbose1("Requesting device restart.\n"); 279 | restart_requested = 1; 280 | } 281 | 282 | if ((n = read_dev()) == -1) { 283 | if (errno != EINTR && errno != EAGAIN) 284 | err(EX_OSERR, "reading from device failed"); 285 | continue; 286 | } 287 | 288 | if (!n) { 289 | verbose1("Device restarted.\n"); 290 | if (done || ioctl(dev_fd, HEIO_GET_AT_HEAD) <= 0) 291 | break; 292 | verbose1("Reopening output file.\n"); 293 | goto restart; 294 | } 295 | 296 | verbose3("Read %ld bytes\n", n); 297 | if (out_fd == pipe_in) /* spliced directly to FIFO */ 298 | continue; 299 | 300 | while (n > 0) { 301 | if ((m = write_out()) == -1) { 302 | if (errno != EINTR && errno != EAGAIN) 303 | err(EX_OSERR, "writing to output failed"); 304 | continue; 305 | } 306 | verbose3("Wrote %ld bytes\n", m); 307 | n -= m; 308 | } 309 | } 310 | 311 | close_out(); 312 | close(dev_fd); 313 | close(pipe_fd[0]); 314 | close(pipe_fd[1]); 315 | free(buf); 316 | 317 | exit(EX_OK); 318 | } 319 | 320 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | .*.cmd 2 | *.defsyms 3 | *.ko 4 | *.mod.c 5 | *.symvers 6 | .System.map.md5 7 | .tmp_versions 8 | System.map 9 | modules.order 10 | ioctl-list.c 11 | ioctl-list 12 | version.h 13 | dkms.conf 14 | hone.spec 15 | tags 16 | TAGS 17 | -------------------------------------------------------------------------------- /src/DISCLAIMER: -------------------------------------------------------------------------------- 1 | This material was prepared as an account of work sponsored by an agency of 2 | the United States Government. Neither the United States Government nor the 3 | United States Department of Energy, nor the Contractor, nor any or their 4 | employees, nor any jurisdiction or organization that has cooperated in the 5 | development of these materials, MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR 6 | ASSUMES ANY LEGAL LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, 7 | COMPLETENESS, OR USEFULNESS OR ANY INFORMATION, APPARATUS, PRODUCT, 8 | SOFTWARE, OR PROCESS DISCLOSED, OR REPRESENTS THAT ITS USE WOULD NOT 9 | INFRINGE PRIVATELY OWNED RIGHTS. 10 | 11 | Reference herein to any specific commercial product, process, or service by 12 | trade name, trademark, manufacturer, or otherwise does not necessarily 13 | constitute or imply its endorsement, recommendation, or favoring by the 14 | United States Government or any agency thereof, or Battelle Memorial 15 | Institute. The views and opinions of authors expressed herein do not 16 | necessarily state or reflect those of the United States Government or any 17 | agency thereof. 18 | 19 | PACIFIC NORTHWEST NATIONAL LABORATORY operated by BATTELLE for the UNITED 20 | STATES DEPARTMENT OF ENERGY under Contract DE-AC05-76RL01830 21 | -------------------------------------------------------------------------------- /src/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (C) 2011 Battelle Memorial Institute 3 | 4 | 5 | 6 | GNU GENERAL PUBLIC LICENSE 7 | Version 2, June 1991 8 | 9 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 10 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 11 | Everyone is permitted to copy and distribute verbatim copies 12 | of this license document, but changing it is not allowed. 13 | 14 | Preamble 15 | 16 | The licenses for most software are designed to take away your 17 | freedom to share and change it. By contrast, the GNU General Public 18 | License is intended to guarantee your freedom to share and change free 19 | software--to make sure the software is free for all its users. This 20 | General Public License applies to most of the Free Software 21 | Foundation's software and to any other program whose authors commit to 22 | using it. (Some other Free Software Foundation software is covered by 23 | the GNU Lesser General Public License instead.) You can apply it to 24 | your programs, too. 25 | 26 | When we speak of free software, we are referring to freedom, not 27 | price. Our General Public Licenses are designed to make sure that you 28 | have the freedom to distribute copies of free software (and charge for 29 | this service if you wish), that you receive source code or can get it 30 | if you want it, that you can change the software or use pieces of it 31 | in new free programs; and that you know you can do these things. 32 | 33 | To protect your rights, we need to make restrictions that forbid 34 | anyone to deny you these rights or to ask you to surrender the rights. 35 | These restrictions translate to certain responsibilities for you if you 36 | distribute copies of the software, or if you modify it. 37 | 38 | For example, if you distribute copies of such a program, whether 39 | gratis or for a fee, you must give the recipients all the rights that 40 | you have. You must make sure that they, too, receive or can get the 41 | source code. And you must show them these terms so they know their 42 | rights. 43 | 44 | We protect your rights with two steps: (1) copyright the software, and 45 | (2) offer you this license which gives you legal permission to copy, 46 | distribute and/or modify the software. 47 | 48 | Also, for each author's protection and ours, we want to make certain 49 | that everyone understands that there is no warranty for this free 50 | software. If the software is modified by someone else and passed on, we 51 | want its recipients to know that what they have is not the original, so 52 | that any problems introduced by others will not reflect on the original 53 | authors' reputations. 54 | 55 | Finally, any free program is threatened constantly by software 56 | patents. We wish to avoid the danger that redistributors of a free 57 | program will individually obtain patent licenses, in effect making the 58 | program proprietary. To prevent this, we have made it clear that any 59 | patent must be licensed for everyone's free use or not licensed at all. 60 | 61 | The precise terms and conditions for copying, distribution and 62 | modification follow. 63 | 64 | GNU GENERAL PUBLIC LICENSE 65 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 66 | 67 | 0. This License applies to any program or other work which contains 68 | a notice placed by the copyright holder saying it may be distributed 69 | under the terms of this General Public License. The "Program", below, 70 | refers to any such program or work, and a "work based on the Program" 71 | means either the Program or any derivative work under copyright law: 72 | that is to say, a work containing the Program or a portion of it, 73 | either verbatim or with modifications and/or translated into another 74 | language. (Hereinafter, translation is included without limitation in 75 | the term "modification".) Each licensee is addressed as "you". 76 | 77 | Activities other than copying, distribution and modification are not 78 | covered by this License; they are outside its scope. The act of 79 | running the Program is not restricted, and the output from the Program 80 | is covered only if its contents constitute a work based on the 81 | Program (independent of having been made by running the Program). 82 | Whether that is true depends on what the Program does. 83 | 84 | 1. You may copy and distribute verbatim copies of the Program's 85 | source code as you receive it, in any medium, provided that you 86 | conspicuously and appropriately publish on each copy an appropriate 87 | copyright notice and disclaimer of warranty; keep intact all the 88 | notices that refer to this License and to the absence of any warranty; 89 | and give any other recipients of the Program a copy of this License 90 | along with the Program. 91 | 92 | You may charge a fee for the physical act of transferring a copy, and 93 | you may at your option offer warranty protection in exchange for a fee. 94 | 95 | 2. You may modify your copy or copies of the Program or any portion 96 | of it, thus forming a work based on the Program, and copy and 97 | distribute such modifications or work under the terms of Section 1 98 | above, provided that you also meet all of these conditions: 99 | 100 | a) You must cause the modified files to carry prominent notices 101 | stating that you changed the files and the date of any change. 102 | 103 | b) You must cause any work that you distribute or publish, that in 104 | whole or in part contains or is derived from the Program or any 105 | part thereof, to be licensed as a whole at no charge to all third 106 | parties under the terms of this License. 107 | 108 | c) If the modified program normally reads commands interactively 109 | when run, you must cause it, when started running for such 110 | interactive use in the most ordinary way, to print or display an 111 | announcement including an appropriate copyright notice and a 112 | notice that there is no warranty (or else, saying that you provide 113 | a warranty) and that users may redistribute the program under 114 | these conditions, and telling the user how to view a copy of this 115 | License. (Exception: if the Program itself is interactive but 116 | does not normally print such an announcement, your work based on 117 | the Program is not required to print an announcement.) 118 | 119 | These requirements apply to the modified work as a whole. If 120 | identifiable sections of that work are not derived from the Program, 121 | and can be reasonably considered independent and separate works in 122 | themselves, then this License, and its terms, do not apply to those 123 | sections when you distribute them as separate works. But when you 124 | distribute the same sections as part of a whole which is a work based 125 | on the Program, the distribution of the whole must be on the terms of 126 | this License, whose permissions for other licensees extend to the 127 | entire whole, and thus to each and every part regardless of who wrote it. 128 | 129 | Thus, it is not the intent of this section to claim rights or contest 130 | your rights to work written entirely by you; rather, the intent is to 131 | exercise the right to control the distribution of derivative or 132 | collective works based on the Program. 133 | 134 | In addition, mere aggregation of another work not based on the Program 135 | with the Program (or with a work based on the Program) on a volume of 136 | a storage or distribution medium does not bring the other work under 137 | the scope of this License. 138 | 139 | 3. You may copy and distribute the Program (or a work based on it, 140 | under Section 2) in object code or executable form under the terms of 141 | Sections 1 and 2 above provided that you also do one of the following: 142 | 143 | a) Accompany it with the complete corresponding machine-readable 144 | source code, which must be distributed under the terms of Sections 145 | 1 and 2 above on a medium customarily used for software interchange; or, 146 | 147 | b) Accompany it with a written offer, valid for at least three 148 | years, to give any third party, for a charge no more than your 149 | cost of physically performing source distribution, a complete 150 | machine-readable copy of the corresponding source code, to be 151 | distributed under the terms of Sections 1 and 2 above on a medium 152 | customarily used for software interchange; or, 153 | 154 | c) Accompany it with the information you received as to the offer 155 | to distribute corresponding source code. (This alternative is 156 | allowed only for noncommercial distribution and only if you 157 | received the program in object code or executable form with such 158 | an offer, in accord with Subsection b above.) 159 | 160 | The source code for a work means the preferred form of the work for 161 | making modifications to it. For an executable work, complete source 162 | code means all the source code for all modules it contains, plus any 163 | associated interface definition files, plus the scripts used to 164 | control compilation and installation of the executable. However, as a 165 | special exception, the source code distributed need not include 166 | anything that is normally distributed (in either source or binary 167 | form) with the major components (compiler, kernel, and so on) of the 168 | operating system on which the executable runs, unless that component 169 | itself accompanies the executable. 170 | 171 | If distribution of executable or object code is made by offering 172 | access to copy from a designated place, then offering equivalent 173 | access to copy the source code from the same place counts as 174 | distribution of the source code, even though third parties are not 175 | compelled to copy the source along with the object code. 176 | 177 | 4. You may not copy, modify, sublicense, or distribute the Program 178 | except as expressly provided under this License. Any attempt 179 | otherwise to copy, modify, sublicense or distribute the Program is 180 | void, and will automatically terminate your rights under this License. 181 | However, parties who have received copies, or rights, from you under 182 | this License will not have their licenses terminated so long as such 183 | parties remain in full compliance. 184 | 185 | 5. You are not required to accept this License, since you have not 186 | signed it. However, nothing else grants you permission to modify or 187 | distribute the Program or its derivative works. These actions are 188 | prohibited by law if you do not accept this License. Therefore, by 189 | modifying or distributing the Program (or any work based on the 190 | Program), you indicate your acceptance of this License to do so, and 191 | all its terms and conditions for copying, distributing or modifying 192 | the Program or works based on it. 193 | 194 | 6. Each time you redistribute the Program (or any work based on the 195 | Program), the recipient automatically receives a license from the 196 | original licensor to copy, distribute or modify the Program subject to 197 | these terms and conditions. You may not impose any further 198 | restrictions on the recipients' exercise of the rights granted herein. 199 | You are not responsible for enforcing compliance by third parties to 200 | this License. 201 | 202 | 7. If, as a consequence of a court judgment or allegation of patent 203 | infringement or for any other reason (not limited to patent issues), 204 | conditions are imposed on you (whether by court order, agreement or 205 | otherwise) that contradict the conditions of this License, they do not 206 | excuse you from the conditions of this License. If you cannot 207 | distribute so as to satisfy simultaneously your obligations under this 208 | License and any other pertinent obligations, then as a consequence you 209 | may not distribute the Program at all. For example, if a patent 210 | license would not permit royalty-free redistribution of the Program by 211 | all those who receive copies directly or indirectly through you, then 212 | the only way you could satisfy both it and this License would be to 213 | refrain entirely from distribution of the Program. 214 | 215 | If any portion of this section is held invalid or unenforceable under 216 | any particular circumstance, the balance of the section is intended to 217 | apply and the section as a whole is intended to apply in other 218 | circumstances. 219 | 220 | It is not the purpose of this section to induce you to infringe any 221 | patents or other property right claims or to contest validity of any 222 | such claims; this section has the sole purpose of protecting the 223 | integrity of the free software distribution system, which is 224 | implemented by public license practices. Many people have made 225 | generous contributions to the wide range of software distributed 226 | through that system in reliance on consistent application of that 227 | system; it is up to the author/donor to decide if he or she is willing 228 | to distribute software through any other system and a licensee cannot 229 | impose that choice. 230 | 231 | This section is intended to make thoroughly clear what is believed to 232 | be a consequence of the rest of this License. 233 | 234 | 8. If the distribution and/or use of the Program is restricted in 235 | certain countries either by patents or by copyrighted interfaces, the 236 | original copyright holder who places the Program under this License 237 | may add an explicit geographical distribution limitation excluding 238 | those countries, so that distribution is permitted only in or among 239 | countries not thus excluded. In such case, this License incorporates 240 | the limitation as if written in the body of this License. 241 | 242 | 9. The Free Software Foundation may publish revised and/or new versions 243 | of the General Public License from time to time. Such new versions will 244 | be similar in spirit to the present version, but may differ in detail to 245 | address new problems or concerns. 246 | 247 | Each version is given a distinguishing version number. If the Program 248 | specifies a version number of this License which applies to it and "any 249 | later version", you have the option of following the terms and conditions 250 | either of that version or of any later version published by the Free 251 | Software Foundation. If the Program does not specify a version number of 252 | this License, you may choose any version ever published by the Free Software 253 | Foundation. 254 | 255 | 10. If you wish to incorporate parts of the Program into other free 256 | programs whose distribution conditions are different, write to the author 257 | to ask for permission. For software which is copyrighted by the Free 258 | Software Foundation, write to the Free Software Foundation; we sometimes 259 | make exceptions for this. Our decision will be guided by the two goals 260 | of preserving the free status of all derivatives of our free software and 261 | of promoting the sharing and reuse of software generally. 262 | 263 | NO WARRANTY 264 | 265 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 266 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 267 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 268 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 269 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 270 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 271 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 272 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 273 | REPAIR OR CORRECTION. 274 | 275 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 276 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 277 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 278 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 279 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 280 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 281 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 282 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 283 | POSSIBILITY OF SUCH DAMAGES. 284 | 285 | END OF TERMS AND CONDITIONS 286 | 287 | How to Apply These Terms to Your New Programs 288 | 289 | If you develop a new program, and you want it to be of the greatest 290 | possible use to the public, the best way to achieve this is to make it 291 | free software which everyone can redistribute and change under these terms. 292 | 293 | To do so, attach the following notices to the program. It is safest 294 | to attach them to the start of each source file to most effectively 295 | convey the exclusion of warranty; and each file should have at least 296 | the "copyright" line and a pointer to where the full notice is found. 297 | 298 | 299 | Copyright (C) 300 | 301 | This program is free software; you can redistribute it and/or modify 302 | it under the terms of the GNU General Public License as published by 303 | the Free Software Foundation; either version 2 of the License, or 304 | (at your option) any later version. 305 | 306 | This program is distributed in the hope that it will be useful, 307 | but WITHOUT ANY WARRANTY; without even the implied warranty of 308 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 309 | GNU General Public License for more details. 310 | 311 | You should have received a copy of the GNU General Public License along 312 | with this program; if not, write to the Free Software Foundation, Inc., 313 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 314 | 315 | Also add information on how to contact you by electronic and paper mail. 316 | 317 | If the program is interactive, make it output a short notice like this 318 | when it starts in an interactive mode: 319 | 320 | Gnomovision version 69, Copyright (C) year name of author 321 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 322 | This is free software, and you are welcome to redistribute it 323 | under certain conditions; type `show c' for details. 324 | 325 | The hypothetical commands `show w' and `show c' should show the appropriate 326 | parts of the General Public License. Of course, the commands you use may 327 | be called something other than `show w' and `show c'; they could even be 328 | mouse-clicks or menu items--whatever suits your program. 329 | 330 | You should also get your employer (if you work as a programmer) or your 331 | school, if any, to sign a "copyright disclaimer" for the program, if 332 | necessary. Here is a sample; alter the names: 333 | 334 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 335 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 336 | 337 | , 1 April 1989 338 | Ty Coon, President of Vice 339 | 340 | This General Public License does not permit incorporating your program into 341 | proprietary programs. If your program is a subroutine library, you may 342 | consider it more useful to permit linking proprietary applications with the 343 | library. If this is what you want to do, use the GNU Lesser General 344 | Public License instead of this License. 345 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2011 Battelle Memorial Institute 3 | # 4 | # Licensed under the GNU General Public License Version 2. 5 | # See LICENSE for the full text of the license. 6 | # See DISCLAIMER for additional disclaimers. 7 | # 8 | # Author: Brandon Carpenter 9 | # 10 | 11 | # Each of the *_NOTIFY variables below can take one of three values: 12 | # c - Combine the module with the dependent rather than build separate 13 | # m - Build as a separate module 14 | # n - Do not build the module at all (will likely break things) 15 | # 16 | # Dependencies: 17 | # honeevent 18 | # +-- hone_notify 19 | # +-- process_notify 20 | # +-- socket_notify 21 | # +-- packet_notify 22 | 23 | CONFIG_SOCKET_NOTIFY ?= c 24 | CONFIG_PACKET_NOTIFY ?= c 25 | CONFIG_PROCESS_NOTIFY ?= c 26 | CONFIG_HONE_NOTIFY ?= m 27 | CONFIG_HONEEVENT ?= m 28 | 29 | HONE_MODULES ?= $(foreach m,socket_notify packet_notify process_notify hone_notify honeevent,$(if $(filter m,$(value CONFIG_$(shell echo '$(m)' | tr '[[:lower:]]' '[[:upper:]]'))),$(m))) 30 | 31 | ifneq ($(KERNELRELEASE),) 32 | # This is the kernel build (Kbuild) section. 33 | 34 | # Because hone is being built out of tree, the CONFIG_* variables are not set. 35 | # The following lines set the variables via the compiler command-line. 36 | CONFIG = $(if $(filter-out n,$(CONFIG_$(1))),-DCONFIG_$(1)$(or \ 37 | $(if $(filter m,$(CONFIG_$(1))),_MODULE), \ 38 | $(if $(filter c,$(CONFIG_$(1))),_COMBINED))) 39 | EXTRA_CFLAGS := $(call CONFIG,SOCKET_NOTIFY) \ 40 | $(call CONFIG,PACKET_NOTIFY) \ 41 | $(call CONFIG,PROCESS_NOTIFY) \ 42 | $(call CONFIG,HONE_NOTIFY) \ 43 | $(call CONFIG,HONEEVENT) 44 | 45 | # Used to conditionally include files when doing a combined build. 46 | COMBINE = $(if $(filter-out c,$(CONFIG_$(1))),,$(2)) 47 | 48 | obj-$(CONFIG_SOCKET_NOTIFY) += socket_notify.o 49 | socket_notify-defsyms := inet_family_ops inet6_family_ops 50 | 51 | obj-$(CONFIG_PACKET_NOTIFY) += packet_notify.o 52 | packet_notify-defsyms := __udp6_lib_lookup 53 | 54 | obj-$(CONFIG_PROCESS_NOTIFY) += process_notify.o 55 | process_notify-defsyms := copy_process compat_do_execve do_execve do_execve_common do_execveat_common 56 | 57 | obj-$(CONFIG_HONE_NOTIFY) += hone_notify.o 58 | hone_notify-y := hone_notify_imp.o \ 59 | $(call COMBINE,PROCESS_NOTIFY,process_notify.o) \ 60 | $(call COMBINE,SOCKET_NOTIFY,socket_notify.o) \ 61 | $(call COMBINE,PACKET_NOTIFY,packet_notify.o) 62 | # Leave this empty so hone_notify.defsyms is created when combined. 63 | hone_notify-defsyms := 64 | 65 | obj-$(CONFIG_HONEEVENT) += honeevent.o 66 | honeevent-y := honeevent_imp.o mmutil.o pcapng.o ringbuf.o \ 67 | $(call COMBINE,HONE_NOTIFY,$(hone_notify-y)) 68 | honeevent-defsyms := uts_sem socket_file_ops get_files_struct put_files_struct 69 | 70 | # Handle all the *-defsyms magic. 71 | include $(src)/defsyms.mk 72 | 73 | else 74 | # This is the main Makefile. 75 | 76 | SVNVER := $(shell svnversion 2>/dev/null | grep -o '^[0-9]\+[A-Z]\?') 77 | GITVER := $(shell git log -1 --pretty=format:"%h" 2>/dev/null) 78 | BASEVER := $(shell [ -f VERSION ] && cat VERSION || date '+%y.%m') 79 | VERSION := $(BASEVER)$(if $(SVNVER),+$(SVNVER),$(if $(GITVER),+$(GITVER))) 80 | version-name := hone-$(VERSION) 81 | tarball-name := $(version-name).tar.gz 82 | 83 | # Allow overriding the kernel version and path being built against. 84 | KVER ?= $(shell uname -r) 85 | KSRC ?= /lib/modules/$(KVER)/build 86 | 87 | hone-source = Makefile defsyms.mk $(filter-out %.mod.c,$(wildcard *.[ch])) 88 | pkg-source = dkms.conf DISCLAIMER LICENSE README VERSION debian/* hone.spec.in hone.spec version.h 89 | clean-files = dkms.conf hone.spec ioctl-list.c version.h 90 | 91 | all: prereq_check modules 92 | 93 | tags: $(filter %.c,$(hone-source)) $(filter %.h,$(hone-source)) 94 | ctags $^ 95 | 96 | TAGS: $(filter %.c,$(hone-source)) $(filter %.h,$(hone-source)) 97 | etags $^ 98 | 99 | VER_NUMBER := $(firstword $(subst -, ,$(BASEVER))) 100 | VER_EXTRA := $(subst $(VER_NUMBER),,$(BASEVER)) 101 | VER_SPLIT := $(subst ., ,$(VER_NUMBER)) 102 | VER_MAJOR := $(word 1,$(VER_SPLIT)) 103 | VER_MINOR := $(word 2,$(VER_SPLIT)) 104 | VER_MICRO := $(word 3,$(VER_SPLIT)) 105 | VER_BUILD := $(word 4,$(VER_SPLIT)) 106 | 107 | bump-version: 108 | $(MAKE) -B VERSION 109 | 110 | VERSION: 111 | @eval `date '+YEAR=%y MONTH=%m DAY=%d'`; \ 112 | VERSION="$$YEAR.$$MONTH"; \ 113 | if [ "$$VERSION" == "$(VER_MAJOR).$(VER_MINOR)" ]; then \ 114 | VERSION="$$VERSION.$$DAY"; \ 115 | if [ "$$DAY" == "$(VER_MICRO)" ]; then \ 116 | VERSION="$$VERSION.$$(( $(VER_BUILD) + 1 ))"; \ 117 | fi; \ 118 | fi; \ 119 | echo $${VERSION}$(VER_EXTRA) > $@ 120 | 121 | version.h: VERSION 122 | @echo '#ifndef __VERSION_H__' > $@ 123 | @echo '#define __VERSION_H__' >> $@ 124 | @echo '#define HONE_VERSION "$(BASEVER)"' >> $@ 125 | @echo '#endif' >> $@ 126 | 127 | prereq_check: 128 | @ if [ ! -f $(KSRC)/include/linux/version.h ] && \ 129 | [ ! -f $(KSRC)/include/generated/uapi/linux/version.h ]; then \ 130 | echo "Kernel source was not found. Aborting."; \ 131 | exit 1; \ 132 | fi 133 | 134 | help: 135 | $(MAKE) -C $(KSRC) M=$(CURDIR) help 136 | 137 | modules: version.h 138 | $(MAKE) -C $(KSRC) M=$(CURDIR) modules 139 | 140 | modules_install install: modules 141 | $(MAKE) -C $(KSRC) M=$(CURDIR) modules_install 142 | 143 | clean: 144 | -rm -f *.[aos] *.ko .*.cmd *.mod.c *.defsyms .System.map.md5 \ 145 | defsyms.symvers Module.symvers modules.order ioctl-list 146 | -rm -rf .tmp_versions 147 | 148 | distclean: clean 149 | -rm -f $(clean-files) 150 | 151 | debian/dkms: dkms.conf 152 | @cp $< $@ 153 | 154 | debian/install: debian/install.in VERSION 155 | @sed -r 's/__VERSION__/$(BASEVER)/' $< > $@ 156 | 157 | debian/changelog: VERSION 158 | @ echo "hone ($(BASEVER)) unstable; urgency=low" > $@.new; \ 159 | echo "" >> $@.new; \ 160 | echo " * New snapshot release." >> $@.new; \ 161 | echo "" >> $@.new; \ 162 | echo " -- $${DEBFULLNAME:-$$USER} <$${DEBEMAIL:-$$USER@$$HOSTNAME}> `date -R`" >> debian/changelog.new; \ 163 | echo "" >> $@.new; \ 164 | cat debian/changelog >> $@.new; \ 165 | mv -f $@.new $@; \ 166 | 167 | packages: deb rpm tarball 168 | 169 | deb: $(tarball-name) 170 | -rm -rf deb-build/$(version-name) 171 | [ -d deb-build ] || mkdir deb-build 172 | tar xzf $(tarball-name) -C deb-build 173 | cd deb-build/$(version-name) && dpkg-buildpackage -tc -uc -us 174 | rm -rf deb-build/$(version-name) 175 | 176 | rpm: $(tarball-name) 177 | [ -d rpm-build ] || mkdir rpm-build 178 | rpmbuild --define='_topdir $(CURDIR)/rpm-build' --clean -ta ./$(tarball-name) 179 | 180 | tarball: $(tarball-name) 181 | 182 | $(tarball-name): $(hone-source) $(pkg-source) 183 | tar czf $@ --transform 's@^@hone-$(VERSION)/@' --exclude .svn --exclude '.*.swp' $(hone-source) $(pkg-source) 184 | 185 | hone.spec: hone.spec.in VERSION 186 | @sed -r 's/^(Version: ).*$$/\1$(BASEVER)/' $< > $@ 187 | 188 | dkms.conf: VERSION 189 | @echo 'PACKAGE_VERSION="$(or $(DKMSVER),$(BASEVER))"' > $@ 190 | @echo 'PACKAGE_NAME="$(or $(DKMSNAME),hone)"' >> $@ 191 | @echo 'AUTOINSTALL="yes"' >> $@ 192 | @echo 'BUILD_EXCLUSIVE_KERNEL="^2.6.3[0-9]|3.*"' >> $@ 193 | @i=0; for m in $(HONE_MODULES); do \ 194 | echo "" >> $@; \ 195 | echo "BUILT_MODULE_NAME[$$i]=\"$$m\"" >> $@; \ 196 | echo "DEST_MODULE_LOCATION[$$i]=\"/extra\"" >> $@; \ 197 | i=$$((i+1)); \ 198 | done 199 | 200 | ioctl-list.c: honeevent.h 201 | @echo '#include ' > $@ 202 | @echo '#include ' >> $@ 203 | @echo '#include "honeevent.h"' >> $@ 204 | @echo 'int main(int argc, char *argv)' >> $@ 205 | @echo '{' >> $@ 206 | @sed -r 's/^\s*#\s*define\s+(\w+)\s+_IO.*$$/\tprintf("\1 = 0x%08x\\n", \1);/;t;d' honeevent.h >> $@ 207 | @echo ' return 0;' >> $@ 208 | @echo '}' >> $@ 209 | 210 | ioctl-list: ioctl-list.c 211 | gcc -o $@ $< 212 | 213 | load: 214 | @(( $$UID )) && SU=sudo || unset SU; \ 215 | for mod in $(HONE_MODULES); do $$SU insmod $$mod.ko; done 216 | 217 | unload: 218 | @(( $$UID )) && SU=sudo || unset SU; \ 219 | for mod in $(HONE_MODULES); do echo $$mod; done | tac | xargs $$SU rmmod 220 | 221 | System.map: $(KSRC)/vmlinux 222 | nm $< > $@ 223 | 224 | PHONY: all prereq_check help modules modules_install install clean distclean \ 225 | packages deb rpm tarball bump-version load unload 226 | 227 | endif 228 | -------------------------------------------------------------------------------- /src/README: -------------------------------------------------------------------------------- 1 | Copyright (C) 2011 Battelle Memorial Institute 2 | 3 | Licensed under the GNU General Public License Version 2. 4 | See LICENSE for the full text of the license. 5 | See DISCLAIMER for additional disclaimers. 6 | 7 | Author: Brandon Carpenter 8 | Contributors: Alex Malozemoff and Glenn Fink 9 | 10 | 11 | 12 | H H OOO N N EEEEE 13 | H H O O NN N E 14 | HHHHH O O N N N EEEE 15 | H H O O N NN E 16 | H H OOO N N EEEEE 17 | 18 | 19 | Hone is a unique tool for correlating packets to processes to bridge the 20 | HOst-NEtwork divide. 21 | 22 | 23 | INTRODUCTION 24 | ============ 25 | 26 | When diagnosing anomalous behavior on a network, a system administrator 27 | has two separate areas to focus on: the packets traveling over the 28 | network (i.e., the network view), and the information contained on the 29 | individual hosts connected to the network (i.e., the host view). The 30 | network view provides a glimpse into the overall communication activity 31 | of the network, but it does not reveal what processes are causing this 32 | activity. On the other hand, the host view contains details on the 33 | processes producing the network traffic, but it does not contain 34 | information on which packets are associated with which process. This 35 | inability to correlate packets with their associated process is a 36 | fundamental (although intentional) shortcoming of the modern network 37 | stack. To bridge this gap we introduce the Hone (Host-network) 38 | correlator, an open-source tool that correlates packets to processes to 39 | diagnose problems seen on a network. 40 | 41 | While the idea of correlating packets to processes is a simple one, the 42 | implementation requires kernel modifications that alter the way the 43 | network stack works. Perhaps this complication is responsible for the 44 | fact that no other tool takes this approach. While there have been 45 | several tools that have come close to the packet-process correlation 46 | approach taken here, they differ from Hone in fundamental ways. 47 | Discussions of these tools and their differences from Hone can be found 48 | in: 49 | 50 | FINK, G., DUGGIRALA, V., CORREA, R., AND NORTH, C. Bridging the 51 | host-network divide: survey, taxonomy, and solution. In 52 | Proceedings of the 20th Large Installation System 53 | Administration Conference (2006), pp. 247–262. 54 | 55 | We plan to publish a follow-on paper on this work soon. 56 | 57 | 58 | HOW IT WORKS 59 | ============ 60 | 61 | The Linux Hone correlator uses the netfilter framework, which provides 62 | hooks for packet capture and modification at various places in the Linux 63 | network stack. Hone registers callbacks with the INPUT and OUTPUT chains 64 | of the filter table, providing notification of packets destined for and 65 | leaving the local system. 66 | 67 | Packets are correlated with a specific connection based on the socket 68 | associated with the given packet. Outgoing packets already contain a 69 | pointer to the originating socket, whereas incoming packets require 70 | protocol-specific lookup functions from the transport layer to determine 71 | the destination socket. 72 | 73 | Packet and socket structures do not contain any information linking them 74 | to a particular process. The owning process is determined by taking 75 | advantage of the fact that sockets are created in the context of the 76 | owning process. By hooking the socket creation routines, the creating 77 | process is reported along with a socket identifier for later lookup. 78 | Unfortunately, a problem arises when one performs a fork() or other 79 | socket-duplicating operation, as it is currently not possible to tell 80 | which process actually receives a given packet under these conditions. 81 | We are currently investigating a solution to this problem. 82 | 83 | The Linux correlator is comprised of multiple loadable kernel modules: 84 | process_notify, socket_notify, packet_notify, hone_notify and honeevent. 85 | The process_notify, socket_notify and packet_notify modules provide 86 | notification routines to notify registrants of process, socket and 87 | packet events. The hone_notify module registers for to receive all 88 | three event types and provides hone event notifications to the honeevent 89 | module. The honeevent module provides a character special device to 90 | provide hone events to userspace in plain text or PCAP-NG format. 91 | 92 | Process events are collected by hooking copy_process(), do_execve(), 93 | compat_do_execve() and do_exit() kernel routines using kprobes. This 94 | approach has drawbacks, but does allows the Hone driver to be used 95 | without modifying the kernel. 96 | 97 | 98 | PREREQUISITES 99 | ============= 100 | 101 | Building the Hone sensor kernel modules requires a few prerequisites: 102 | 103 | 1. Build tools, such as the gcc tool chain and GNU make 104 | 2. Kernel source header files for the target distribution 105 | 3. Kernel configuration (.config, typically included with the header files) 106 | 4. System map file from kernel build 107 | 5. Kernel with kprobes support (CONFIG_KPROBES) (would like to eliminate 108 | this requirement) 109 | 110 | If you can't build a Linux kernel, then you likely don't have the tools 111 | to build a kernel module. Be sure to install the recommended tools for 112 | your distribution. For instance, on Debian, install the build-essential 113 | package. 114 | 115 | By default, the build process will look for the kernel header files and 116 | the configuration file in /lib/modules/$(KVER)/build (default for KSRC), 117 | where KVER defaults to `uname -r`. If you wish to build for a different 118 | kernel version installed on the system, set KVER to the appropriate 119 | version number when running make. If the kernel headers live elsewhere, 120 | you can tell make about it via the KSRC variable. 121 | 122 | Some of the Hone modules use symbols that are not exported. Therefore, 123 | their address must be mapped statically using the system map file. Make 124 | will search for the appropriate map file in the following order: 125 | 126 | 1. $(PWD)/System.map 127 | 2. /boot/System.map-$(KERNELRELEASE) 128 | 3. /lib/modules/$(KERNELRELEASE)/build/System.map 129 | 4. /proc/kallsyms (only if the running and target versions are the same) 130 | 5. $(sys)/System.map 131 | 132 | You can override this search by setting the SYSMAP variable to the path 133 | of the appropriate system map when calling make. 134 | 135 | 136 | BUILDING 137 | ======== 138 | 139 | Assuming the above prerequisites are met, building the modules is a 140 | trivial process. Just change to the Hone source directory and execute 141 | make. Here are a few examples: 142 | 143 | Basic build: 144 | 145 | $ make 146 | 147 | OR 148 | 149 | $ make all 150 | 151 | If for some reason the prereq_check target fails, you can try skipping it: 152 | 153 | $ make modules 154 | 155 | Building for a different version than the running kernel: 156 | 157 | $ make KVER=2.6.38 158 | 159 | Building for a kernel that is not installed 160 | 161 | $ make KSRC=/usr/src/linux-2.6.38 SYSMAP=/usr/src/linux-2.6.38/System.map 162 | 163 | 164 | INSTALLING 165 | ========== 166 | 167 | To install the modules, just change to the Hone source directory and 168 | execute `make install`. If you set KVER, KSRC, SYSMAP, ARCH, or any 169 | other make variables, you should set them for install as well. 170 | 171 | If the modules are built outside the kernel tree, it may be necessary to 172 | run depmod manually. If, after installing the modules using `make 173 | install`, you cannot use modprobe to insert the modules, try running 174 | depmod. 175 | 176 | Running depmod for the currently running kernel 177 | 178 | # /sbin/depmod -a 179 | 180 | Check out the depmod(8) man page if you wish to do something fancier, 181 | like depmod against a specific System.map file. 182 | 183 | 184 | BUILDING PACKAGES 185 | ================= 186 | 187 | There are three package types included in the Hone Makefile: tarball, 188 | deb and rpm. You can build all three by using the packages target or 189 | build them individually using the tarball, deb, or rpm targets. The deb 190 | and rpm packages depend on dkms. 191 | 192 | 193 | USAGE 194 | ===== 195 | 196 | After installing the Hone sensor, the kernel module can be loaded using 197 | modprobe: 198 | 199 | # modprobe honeevent 200 | 201 | If for some reason modprobe fails (i.e. depmod failed or was not run), 202 | the modules can be loaded manually using insmod: 203 | 204 | # insmod process_notify.ko 205 | # insmod socket_notify.ko 206 | # insmod packet_notify.ko 207 | # insmod hone_notify.ko 208 | # insmod honeevent.ko 209 | 210 | This will load a character special device driver. udev should 211 | automatically create two devices in /dev: /dev/hone and /dev/honet. 212 | /dev/hone provides PCAP-NG output while /dev/honet provides plain text 213 | output, one record per line. 214 | 215 | If udev is not being used, the devices can be created using mknod. The 216 | files can be created on any filesystem without the "nodev" mount option, 217 | however, they are normally made in /dev. Use the following command 218 | replacing $MAJOR and $MINOR with the device major and minor numbers (see 219 | the next paragraph). 220 | 221 | # mknod /dev/hone c $MAJOR $MINOR 222 | 223 | The major number is dynamically assigned when the module is loaded. It 224 | can be determined by reading /sys/module/honeevent/parameters/major or 225 | by locating the insertion message in syslog. For PCAP-NG output, use 226 | minor number 0. For plain text, use minor number 1. 227 | 228 | There are several module parameters that can be passed to the module at 229 | load time: 230 | 231 | devname - optional base name to give the device in sysfs; default is 232 | hone 233 | major - optional major number to assign the device; default is 0 234 | meaning assigned automatically by the kernel 235 | hostid - optional GUID to include in the section header block used 236 | to identify the system on which the capture occurred. 237 | comment - optional comment to include in the section header block; 238 | spaces may be encoded as \040 or \x20 239 | snaplen - set the maximum packet capture length; default is 0 meaning full 240 | packet capture 241 | pageorder - set the pageorder value used when allocating pages for 242 | the ring buffer where buffer size = PAGE_SIZE * pow(2, pageorder); 243 | default is 1 (2 pages) for 32-bit systems and 2 (4 pages) on 244 | 64-bit systems 245 | 246 | -------------------------------------------------------------------------------- /src/VERSION: -------------------------------------------------------------------------------- 1 | 15.07 2 | -------------------------------------------------------------------------------- /src/debian/changelog: -------------------------------------------------------------------------------- 1 | hone (15.07) unstable; urgency=low 2 | 3 | * New snapshot release. 4 | 5 | -- brandon Wed, 01 Jul 2015 13:40:56 -0700 6 | 7 | hone (14.03) unstable; urgency=low 8 | 9 | * New snapshot release. 10 | 11 | -- Brandon Carpenter Wed, 05 Mar 2014 11:32:01 -0800 12 | 13 | hone (13.12.19) unstable; urgency=low 14 | 15 | * Bug fix release. 16 | 17 | -- Brandon Carpenter Thu, 19 Dec 2013 09:41:55 -0800 18 | 19 | hone (13.12) unstable; urgency=low 20 | 21 | * Bug fix release. 22 | 23 | -- Brandon Carpenter Tue, 17 Dec 2013 09:11:27 -0800 24 | 25 | hone (13.09) unstable; urgency=low 26 | 27 | * New snapshot release. 28 | 29 | -- brandon Fri, 20 Sep 2013 10:01:58 -0700 30 | 31 | hone (13.08) unstable; urgency=low 32 | 33 | * New snapshot release. 34 | 35 | -- brandon Tue, 30 Jul 2013 11:48:41 -0700 36 | 37 | hone (13.06.24) unstable; urgency=low 38 | 39 | * New snapshot release. 40 | 41 | -- Brandon Carpenter Mon, 24 Jun 2013 12:16:04 -0700 42 | 43 | hone (13.06) unstable; urgency=low 44 | 45 | * New snapshot release. 46 | 47 | -- Brandon Carpenter Mon, 17 Jun 2013 10:54:15 -0700 48 | 49 | hone (13.04) unstable; urgency=low 50 | 51 | * New snapshot release. 52 | 53 | -- Brandon Carpenter Tue, 16 Apr 2013 09:24:34 -0700 54 | 55 | hone (13.02) unstable; urgency=low 56 | 57 | * New snapshot release. 58 | 59 | -- Brandon Carpenter Fri, 15 Feb 2013 10:44:18 -0800 60 | 61 | hone (0.3) unstable; urgency=low 62 | 63 | * Initial release. 64 | 65 | -- Brandon Carpenter Thu, 29 Dec 2011 13:23:07 -0800 66 | 67 | -------------------------------------------------------------------------------- /src/debian/compat: -------------------------------------------------------------------------------- 1 | 7 2 | -------------------------------------------------------------------------------- /src/debian/control: -------------------------------------------------------------------------------- 1 | Source: hone 2 | Section: kernel 3 | Priority: extra 4 | Maintainer: Brandon Carpenter 5 | Build-Depends: debhelper (>= 7), dkms (>= 2.1.0.0) 6 | Standards-Version: 3.8.0 7 | 8 | Package: hone-dkms 9 | Architecture: all 10 | Depends: ${misc:Depends}, dkms (>= 2.1.0.0) 11 | Description: DKMS support for Hone packet-process correlation kernel module 12 | Linux loadable kernel modules for peforming packet-to-process correlation. 13 | -------------------------------------------------------------------------------- /src/debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://dep.debian.net/deps/dep5 2 | Name: hone 3 | Author: Brandon Carpenter 4 | Maintainer: Brandon Carpenter 5 | Source: http://github.com/HoneProject 6 | 7 | Copyright: 2011, Battelle Memorial Institute 8 | License: GPL-2 9 | This package has additional disclaimers found in 10 | /usr/share/doc/hone/DISCLAIMER. 11 | . 12 | This package is free software; you can redistribute it and/or modify 13 | it under the terms of the GNU General Public License version 2 as 14 | published by the Free Software Foundation. 15 | . 16 | This package is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | . 21 | You should have received a copy of the GNU General Public License 22 | along with this program. If not, see 23 | . 24 | On Debian systems, the complete text of the GNU General 25 | Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". 26 | 27 | -------------------------------------------------------------------------------- /src/debian/docs: -------------------------------------------------------------------------------- 1 | DISCLAIMER 2 | README 3 | -------------------------------------------------------------------------------- /src/debian/install.in: -------------------------------------------------------------------------------- 1 | Makefile defsyms.mk *.[ch] usr/src/hone-__VERSION__ 2 | -------------------------------------------------------------------------------- /src/debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | 4 | # Uncomment this to turn on verbose mode. 5 | #export DH_VERBOSE=1 6 | 7 | %: 8 | dh $@ --with dkms 9 | 10 | override_dh_auto_build: 11 | make debian/dkms debian/install debian/changelog 12 | 13 | override_dh_auto_install: 14 | 15 | override_dh_install: 16 | dh_install --exclude .svn --exclude .git 17 | 18 | override_dh_auto_clean: 19 | rm -f debian/install 20 | rm -f debian/dkms 21 | 22 | -------------------------------------------------------------------------------- /src/defsyms.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2011 Battelle Memorial Institute 3 | # 4 | # Licensed under the GNU General Public License Version 2. 5 | # See LICENSE for the full text of the license. 6 | # See DISCLAIMER for additional disclaimers. 7 | # 8 | # Author: Brandon Carpenter 9 | # 10 | 11 | defsyms-names := $(foreach N,$(basename $(obj-m) $(obj-c)),$(if $(filter file,$(origin $N-defsyms)),$N)) 12 | 13 | ifneq ($(defsyms-names),) 14 | 15 | # Should check if defsyms are in Module.symvers before getting an address. 16 | # It would be nice to use modpost. 17 | # SYMVERS ?= $(or $(realpath $(CURDIR)/Module.symvers), $(src)/Module.symvers) 18 | 19 | SYSMAP ?= $(or $(realpath $(CURDIR)/System.map), \ 20 | $(realpath /boot/System.map-$(KERNELRELEASE)), \ 21 | $(realpath /lib/modules/$(KERNELRELEASE)/build/System.map), \ 22 | $(realpath $(src)/System.map)) 23 | SYSMAP := $(SYSMAP) 24 | 25 | # Hack to replace space character in cmd_defsyms 26 | SP := 27 | SP += 28 | 29 | quiet_cmd_defsyms = DEFSYMS $@ 30 | cmd_defsyms = SYMBOLS="$(subst $(SP),|,$(strip $($*-defsyms) $(foreach N,$(patsubst %.o,%-defsyms,$($*-y)),$(value $N))))" && [ -n "$$SYMBOLS" ] && awk '$$3 ~ /^('"$$SYMBOLS"')(.[a-z]+.[0-9]+)?$$/ {gsub(".[a-z]+.[0-9]+$$", "", $$3); print $$3 " = 0x" $$1 ";"}' $(SYSMAP) > $@ || echo "$$SYMBOLS" > $@ 31 | quiet_cmd_md5 = MD5SUM $3 32 | cmd_md5 = md5sum $2 > $3 33 | quiet_cmd_symvers = SYMVERS $@ 34 | cmd_symvers = sed -r 's/^\s*(\w+)\s*=\s*0x\S*(\S{8})\s*;\s*$$/0x\2\t\1\tvmlinux/;t;d' $(defsyms-lds) > $@ 35 | 36 | defsyms-roots := $(addprefix $(obj)/,$(defsyms-names)) 37 | defsyms-obj := $(addsuffix .o,$(defsyms-roots)) 38 | defsyms-m := $(addsuffix .ko,$(defsyms-roots)) 39 | defsyms-lds := $(addsuffix .defsyms,$(defsyms-roots)) 40 | clean-files += $(defsyms-m) $(defsyms-lds) .System.map.md5 defsyms.symvers 41 | 42 | ifeq ($(SYSMAP),) 43 | $(obj)/.System.map.md5: FORCE 44 | $(error System.map not found. Try setting the SYSMAP variable to the full path of System.map. If needed, a System.map file can be generated using nm (e.g. nm /lib/modules/`uname -r`/build/vmlinux > System.map)) 45 | else 46 | $(obj)/.System.map.md5: $(shell [ -f $(obj)/.System.map.md5 ] && md5sum $(SYSMAP) | cmp $(obj)/.System.map.md5 -s - || echo FORCE) 47 | $(call cmd,md5,$(SYSMAP),$@) 48 | endif 49 | 50 | $(defsyms-obj): $(obj)/defsyms.symvers 51 | 52 | $(obj)/defsyms.symvers: $(defsyms-lds) 53 | $(call cmd,symvers) 54 | 55 | KBUILD_EXTRA_SYMBOLS += $(obj)/defsyms.symvers 56 | LDFLAGS_MODULE += $(DEFSYMS_LDFLAGS_$(notdir $@)) 57 | 58 | $(foreach N,$(defsyms-names),$(eval DEFSYMS_LDFLAGS_$(N).ko = -T $(obj)/$(N).defsyms)) 59 | 60 | $(defsyms-lds): $(obj)/%.defsyms: $(obj)/.System.map.md5 61 | $(call cmd,defsyms) 62 | 63 | endif 64 | -------------------------------------------------------------------------------- /src/hone.spec.in: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2011 Battelle Memorial Institute 3 | # 4 | # Licensed under the GNU General Public License Version 2. 5 | # See LICENSE for the full text of the license. 6 | # See DISCLAIMER for additional disclaimers. 7 | # 8 | # Author: Brandon Carpenter 9 | # 10 | 11 | %define package hone 12 | 13 | Name: hone-dkms 14 | Summary: DKMS support for Hone packet-process correlation kernel module 15 | Version: __VERSION__ 16 | Release: 1 17 | License: GPL2 18 | Group: Utilities/Internet 19 | BuildArch: noarch 20 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root 21 | Requires: dkms >= 2.1.0.0, bash, gcc 22 | Packager: Brandon Carpenter 23 | Source0: %{package}-%{version}.tar.gz 24 | 25 | %description 26 | Linux loadable kernel modules for peforming packet-to-process correlation. 27 | 28 | %prep 29 | %setup -q -n %{package}-%{version} 30 | 31 | %install 32 | if [ "%{buildroot}" != "/" ]; then 33 | rm -rf %{buildroot} 34 | fi 35 | mkdir -p %{buildroot}/usr/src/%{package}-%{version} 36 | rm -rf debian hone.spec hone.spec.in dkms.conf.in 37 | cp -rf * %{buildroot}/usr/src/%{package}-%{version} 38 | 39 | %clean 40 | if [ "%{buildroot}" != "/" ]; then 41 | rm -rf %{buildroot} 42 | fi 43 | 44 | %files 45 | %attr(-,root,root) /usr/src/%{package}-%{version}/ 46 | 47 | %post 48 | dkms add -m %{package} -v %{version} --rpm_safe_upgrade && 49 | dkms build -m %{package} -v %{version} && 50 | dkms install -m %{package} -v %{version} 51 | 52 | %preun 53 | dkms remove -m %{package} -v %{version} --all 54 | -------------------------------------------------------------------------------- /src/hone_notify.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Battelle Memorial Institute 3 | * 4 | * Licensed under the GNU General Public License Version 2. 5 | * See LICENSE for the full text of the license. 6 | * See DISCLAIMER for additional disclaimers. 7 | * 8 | * Author: Brandon Carpenter 9 | */ 10 | 11 | #ifndef _HONE_NOTIFY_H 12 | #define _HONE_NOTIFY_H 13 | 14 | #define pr_line() printk(KERN_DEBUG "%s: %s:%d %s\n", THIS_MODULE->name, __FILE__, __LINE__, __FUNCTION__) 15 | 16 | #define HONE_PROCESS 1 17 | #define HONE_SOCKET 2 18 | #define HONE_PACKET 3 19 | #define HONE_USER 0x8000 20 | 21 | struct process_event { 22 | union { 23 | struct mm_struct *mm; 24 | char *comm; 25 | }; 26 | int event; 27 | pid_t pid; 28 | pid_t ppid; 29 | pid_t tgid; 30 | uid_t uid; 31 | gid_t gid; 32 | }; 33 | 34 | struct socket_event { 35 | unsigned long sock; 36 | int event; 37 | pid_t pid; 38 | pid_t ppid; 39 | pid_t tgid; 40 | uid_t uid; 41 | gid_t gid; 42 | }; 43 | 44 | struct packet_event { 45 | unsigned long sock; 46 | int dir; 47 | pid_t pid; 48 | struct sk_buff *skb; 49 | }; 50 | 51 | struct hone_event; 52 | 53 | struct user_event { 54 | void *data; 55 | }; 56 | 57 | struct hone_event { 58 | int type; 59 | union { 60 | atomic_t users; 61 | struct hone_event *next; 62 | }; 63 | struct timespec ts; 64 | union { 65 | struct process_event process; 66 | struct socket_event socket; 67 | struct packet_event packet; 68 | struct user_event user; 69 | }; 70 | }; 71 | 72 | #ifdef __KERNEL__ 73 | 74 | struct statistics { 75 | atomic64_t process; 76 | atomic64_t socket; 77 | atomic64_t packet; 78 | }; 79 | 80 | #define STATISTICS_INIT {ATOMIC64_INIT(0), ATOMIC64_INIT(0), ATOMIC64_INIT(0)} 81 | #define DEFINE_STATISTICS(name) struct statistics name = STATISTICS_INIT 82 | 83 | static inline void init_statistics(struct statistics *stats) 84 | { 85 | atomic64_set(&stats->process, 0); 86 | atomic64_set(&stats->socket, 0); 87 | atomic64_set(&stats->packet, 0); 88 | } 89 | 90 | extern void get_hone_statistics(struct statistics *received, 91 | struct statistics *dropped, struct timespec *ts); 92 | extern int hone_notifier_register(struct notifier_block *nb); 93 | extern int hone_notifier_unregister(struct notifier_block *nb); 94 | 95 | extern struct hone_event *alloc_hone_event(unsigned int type, gfp_t flags); 96 | extern void free_hone_event(struct hone_event *event); 97 | extern struct hone_event *__alloc_process_event( 98 | struct task_struct *task, int type, gfp_t flags); 99 | extern struct hone_event *__alloc_socket_event(unsigned long sock, int type, 100 | struct task_struct *task, gfp_t flags); 101 | 102 | static inline void get_hone_event(struct hone_event *event) 103 | { 104 | BUG_ON(unlikely(!atomic_read(&event->users))); 105 | atomic_inc(&event->users); 106 | } 107 | 108 | static inline void put_hone_event(struct hone_event *event) 109 | { 110 | BUG_ON(unlikely(!atomic_read(&event->users))); 111 | if (atomic_dec_and_test(&event->users)) 112 | free_hone_event(event); 113 | } 114 | 115 | 116 | #endif /* __KERNEL__ */ 117 | 118 | #endif /* _HONE_NOTIFY_H */ 119 | 120 | -------------------------------------------------------------------------------- /src/hone_notify_imp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Battelle Memorial Institute 3 | * 4 | * Licensed under the GNU General Public License Version 2. 5 | * See LICENSE for the full text of the license. 6 | * See DISCLAIMER for additional disclaimers. 7 | * 8 | * Author: Brandon Carpenter 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) 20 | #include 21 | #else 22 | #define __kuid_val(_uid) _uid 23 | #define __kgid_val(_gid) _gid 24 | #endif 25 | 26 | #include 27 | 28 | #include "process_notify.h" 29 | #include "socket_notify.h" 30 | #include "packet_notify.h" 31 | #include "hone_notify.h" 32 | #include "version.h" 33 | 34 | static struct kmem_cache *hone_cache; 35 | static RAW_NOTIFIER_HEAD(notifier_list); 36 | static DEFINE_RWLOCK(notifier_lock); 37 | 38 | static struct timespec start_time; 39 | static DEFINE_STATISTICS(hone_received); 40 | static DEFINE_STATISTICS(hone_dropped); 41 | 42 | #define copy_atomic64(dst, src) atomic64_set(&(dst), atomic64_read(&(src))) 43 | 44 | static void copy_statistics(const struct statistics *src, struct statistics *dst) 45 | { 46 | copy_atomic64(dst->process, src->process); 47 | copy_atomic64(dst->socket, src->socket); 48 | copy_atomic64(dst->packet, src->packet); 49 | } 50 | 51 | void get_hone_statistics(struct statistics *received, 52 | struct statistics *dropped, struct timespec *ts) 53 | { 54 | if (received) 55 | copy_statistics(&hone_received, received); 56 | if (dropped) 57 | copy_statistics(&hone_dropped, dropped); 58 | if (ts) 59 | *ts = start_time; 60 | } 61 | 62 | #ifndef rcu_dereference_raw 63 | #define notifier_call_chain_empty() (rcu_dereference(notifier_list.head) == NULL) 64 | #else 65 | #define notifier_call_chain_empty() (rcu_dereference_raw(notifier_list.head) == NULL) 66 | #endif 67 | 68 | static void register_notifiers(void); 69 | static void unregister_notifiers(void); 70 | 71 | int hone_notifier_register(struct notifier_block *nb) 72 | { 73 | int result; 74 | unsigned long flags; 75 | 76 | write_lock_irqsave(¬ifier_lock, flags); 77 | if (notifier_call_chain_empty()) 78 | register_notifiers(); 79 | result = raw_notifier_chain_register(¬ifier_list, nb); 80 | write_unlock_irqrestore(¬ifier_lock, flags); 81 | return result; 82 | } 83 | 84 | int hone_notifier_unregister(struct notifier_block *nb) 85 | { 86 | int result; 87 | unsigned long flags; 88 | 89 | write_lock_irqsave(¬ifier_lock, flags); 90 | result = raw_notifier_chain_unregister(¬ifier_list, nb); 91 | if (notifier_call_chain_empty()) 92 | unregister_notifiers(); 93 | write_unlock_irqrestore(¬ifier_lock, flags); 94 | return result; 95 | } 96 | 97 | static inline int hone_notifier_notify(struct hone_event *event) 98 | { 99 | int result; 100 | unsigned long flags; 101 | 102 | read_lock_irqsave(¬ifier_lock, flags); 103 | result = raw_notifier_call_chain(¬ifier_list, 0, event); 104 | read_unlock_irqrestore(¬ifier_lock, flags); 105 | return result; 106 | } 107 | 108 | void free_hone_event(struct hone_event *event) 109 | { 110 | if (event->type == HONE_PACKET) { 111 | if (event->packet.skb) 112 | kfree_skb(event->packet.skb); 113 | } else if (event->type == HONE_PROCESS) { 114 | if (event->process.mm) { 115 | if (event->process.event == PROC_KTHD) 116 | kfree(event->process.comm); 117 | else 118 | mmput(event->process.mm); 119 | event->process.mm = NULL; 120 | } 121 | } 122 | kmem_cache_free(hone_cache, event); 123 | } 124 | 125 | struct hone_event *alloc_hone_event(unsigned int type, gfp_t flags) 126 | { 127 | struct hone_event *event; 128 | 129 | if (!(event = kmem_cache_zalloc(hone_cache, flags))) 130 | return NULL; 131 | event->type = type; 132 | ktime_get_ts(&event->ts); 133 | atomic_set(&event->users, 1); 134 | return event; 135 | } 136 | 137 | 138 | static struct mm_struct *task_mm(struct task_struct *task) 139 | { 140 | struct mm_struct *mm; 141 | unsigned long flags; 142 | 143 | spin_lock_irqsave(&task->alloc_lock, flags); 144 | mm = task->mm; 145 | if (mm) { 146 | if (task->flags & PF_KTHREAD) 147 | mm = NULL; 148 | else 149 | atomic_inc(&mm->mm_users); 150 | } 151 | spin_unlock_irqrestore(&task->alloc_lock, flags); 152 | return mm; 153 | } 154 | 155 | struct hone_event *__alloc_process_event( 156 | struct task_struct *task, int type, gfp_t flags) 157 | { 158 | struct hone_event *event; 159 | 160 | if ((event = alloc_hone_event(HONE_PROCESS, flags))) { 161 | struct process_event *pev = &event->process; 162 | const struct cred *cred; 163 | pev->event = (type != PROC_EXIT && task->flags & PF_KTHREAD) ? PROC_KTHD : type; 164 | pev->pid = task->pid; 165 | pev->ppid = task->real_parent->pid; 166 | pev->tgid = task->tgid; 167 | if (pev->event == PROC_KTHD) 168 | pev->comm = kstrndup(task->comm, sizeof(task->comm), flags); 169 | else if (type == PROC_EXEC || (type == PROC_FORK && pev->ppid == 1)) 170 | pev->mm = task_mm(task); 171 | rcu_read_lock(); 172 | cred = __task_cred(task); 173 | pev->uid = __kuid_val(cred->euid); 174 | pev->gid = __kgid_val(cred->egid); 175 | rcu_read_unlock(); 176 | } 177 | return event; 178 | } 179 | 180 | 181 | #if defined(CONFIG_PROCESS_NOTIFY) || \ 182 | defined(CONFIG_PROCESS_NOTIFY_MODULE) || \ 183 | defined(CONFIG_PROCESS_NOTIFY_COMBINED) 184 | 185 | static int process_event_handler(struct notifier_block *nb, 186 | unsigned long val, void *v) 187 | { 188 | struct hone_event *event; 189 | 190 | if (notifier_call_chain_empty()) 191 | return 0; 192 | if ((event = __alloc_process_event(v, val, GFP_ATOMIC))) { 193 | atomic64_inc(&hone_received.process); 194 | hone_notifier_notify(event); 195 | put_hone_event(event); 196 | } else { 197 | atomic64_inc(&hone_dropped.process); 198 | } 199 | return 0; 200 | } 201 | 202 | static struct notifier_block process_notifier_block = { 203 | .notifier_call = process_event_handler, 204 | }; 205 | 206 | # define register_process() process_notifier_register(&process_notifier_block) 207 | # define unregister_process() process_notifier_unregister(&process_notifier_block) 208 | #else 209 | # define register_process() 210 | # define unregister_process() 211 | #endif // CONFIG_PROCESS_NOTIFY* 212 | 213 | #ifdef CONFIG_PROCESS_NOTIFY_COMBINED 214 | extern int process_notify_init(void) __init; 215 | extern void process_notify_remove(void); 216 | #else 217 | # define process_notify_init() (0) 218 | # define process_notify_remove() 219 | #endif // CONFIG_PROCESS_NOTIFY_COMBINED 220 | 221 | 222 | struct hone_event *__alloc_socket_event(unsigned long sock, int type, 223 | struct task_struct *task, gfp_t flags) 224 | { 225 | struct hone_event *event; 226 | 227 | if ((event = alloc_hone_event(HONE_SOCKET, flags))) { 228 | struct socket_event *sockev = &event->socket; 229 | const struct cred *cred; 230 | sockev->sock = sock; 231 | sockev->event = type; 232 | sockev->pid = task->pid; 233 | sockev->ppid = task->real_parent->pid; 234 | sockev->tgid = task->tgid; 235 | rcu_read_lock(); 236 | cred = __task_cred(task); 237 | sockev->uid = __kuid_val(cred->euid); 238 | sockev->gid = __kgid_val(cred->egid); 239 | rcu_read_unlock(); 240 | } 241 | return event; 242 | } 243 | 244 | 245 | #if defined(CONFIG_SOCKET_NOTIFY) || \ 246 | defined(CONFIG_SOCKET_NOTIFY_MODULE) || \ 247 | defined(CONFIG_SOCKET_NOTIFY_COMBINED) 248 | 249 | static int socket_event_handler(struct notifier_block *nb, 250 | unsigned long val, void *v) 251 | { 252 | struct hone_event *event; 253 | 254 | if (notifier_call_chain_empty()) 255 | return 0; 256 | if ((event = __alloc_socket_event((unsigned long) v, val, current, GFP_ATOMIC))) { 257 | atomic64_inc(&hone_received.socket); 258 | hone_notifier_notify(event); 259 | put_hone_event(event); 260 | } else { 261 | atomic64_inc(&hone_dropped.socket); 262 | } 263 | return 0; 264 | } 265 | 266 | static struct notifier_block socket_notifier_block = { 267 | .notifier_call = socket_event_handler, 268 | }; 269 | 270 | # define register_socket() sock_notifier_register(&socket_notifier_block) 271 | # define unregister_socket() sock_notifier_unregister(&socket_notifier_block) 272 | #else 273 | # define register_socket() 274 | # define unregister_socket() 275 | #endif // CONFIG_SOCKET_NOTIFY* 276 | 277 | #ifdef CONFIG_SOCKET_NOTIFY_COMBINED 278 | extern int socket_notify_init(void) __init; 279 | extern void socket_notify_remove(void); 280 | #else 281 | # define socket_notify_init() (0) 282 | # define socket_notify_remove() 283 | #endif // CONFIG_SOCKET_NOTIFY_COMBINED 284 | 285 | 286 | #if defined(CONFIG_PACKET_NOTIFY) || \ 287 | defined(CONFIG_PACKET_NOTIFY_MODULE) || \ 288 | defined(CONFIG_PACKET_NOTIFY_COMBINED) 289 | 290 | static int packet_event_handler(struct notifier_block *nb, 291 | unsigned long val, void *v) 292 | { 293 | struct hone_event *event; 294 | 295 | if (notifier_call_chain_empty()) 296 | return 0; 297 | if ((event = alloc_hone_event(HONE_PACKET, GFP_ATOMIC))) { 298 | struct packet_args *args = (typeof(args)) v; 299 | event->packet.sock = (unsigned long) args->sk; 300 | event->packet.pid = (unsigned long) (args->sk ? args->sk->sk_protinfo : 0); 301 | event->packet.skb = skb_clone(args->skb, GFP_ATOMIC); 302 | event->packet.dir = (val == PKTNOT_PACKET_IN); 303 | atomic64_inc(&hone_received.packet); 304 | hone_notifier_notify(event); 305 | put_hone_event(event); 306 | } else { 307 | atomic64_inc(&hone_dropped.packet); 308 | } 309 | return 0; 310 | } 311 | 312 | static struct notifier_block packet_notifier_block = { 313 | .notifier_call = packet_event_handler, 314 | }; 315 | 316 | # define register_packet() packet_notifier_register(&packet_notifier_block) 317 | # define unregister_packet() packet_notifier_unregister(&packet_notifier_block) 318 | #else 319 | # define register_packet() 320 | # define unregister_packet() 321 | #endif // CONFIG_PACKET_NOTIFY* 322 | 323 | #ifdef CONFIG_PACKET_NOTIFY_COMBINED 324 | extern int packet_notify_init(void) __init; 325 | extern void packet_notify_remove(void); 326 | #else 327 | # define packet_notify_init() (0) 328 | # define packet_notify_remove() 329 | #endif // CONFIG_PACKET_NOTIFY_COMBINED 330 | 331 | 332 | static void register_notifiers(void) 333 | { 334 | register_process(); 335 | register_socket(); 336 | register_packet(); 337 | } 338 | 339 | static void unregister_notifiers(void) 340 | { 341 | unregister_packet(); 342 | unregister_socket(); 343 | unregister_process(); 344 | } 345 | 346 | #ifdef CONFIG_HONE_NOTIFY_COMBINED 347 | # define _STATIC 348 | #else 349 | # define _STATIC static 350 | #endif 351 | 352 | _STATIC int __init hone_notify_init(void) 353 | { 354 | int err = 0; 355 | 356 | if ((err = process_notify_init())) 357 | goto out_process_notify; 358 | if ((err = socket_notify_init())) 359 | goto out_socket_notify; 360 | if ((err = packet_notify_init())) 361 | goto out_packet_notify; 362 | 363 | if (!(hone_cache = kmem_cache_create("hone_event", 364 | sizeof(struct hone_event), 0, 0, NULL))) { 365 | printk(KERN_ERR "%s: kmem_cache_create() failed\n", THIS_MODULE->name); 366 | err = -ENOMEM; 367 | goto out; 368 | } 369 | ktime_get_ts(&start_time); 370 | 371 | return 0; 372 | 373 | out: 374 | packet_notify_remove(); 375 | out_packet_notify: 376 | socket_notify_remove(); 377 | out_socket_notify: 378 | process_notify_remove(); 379 | out_process_notify: 380 | return err; 381 | } 382 | 383 | _STATIC void hone_notify_release(void) 384 | { 385 | packet_notify_remove(); 386 | socket_notify_remove(); 387 | process_notify_remove(); 388 | kmem_cache_destroy(hone_cache); 389 | } 390 | 391 | #ifndef CONFIG_HONE_NOTIFY_COMBINED 392 | 393 | static char version[] __initdata = HONE_VERSION; 394 | 395 | static int __init hone_notify_module_init(void) 396 | { 397 | if (hone_notify_init()) 398 | return -1; 399 | printk("%s: v%s module successfully loaded\n", THIS_MODULE->name, version); 400 | return 0; 401 | } 402 | 403 | static void __exit hone_notify_module_exit(void) 404 | { 405 | hone_notify_release(); 406 | printk("%s: module successfully unloaded\n", THIS_MODULE->name); 407 | } 408 | 409 | module_init(hone_notify_module_init); 410 | module_exit(hone_notify_module_exit); 411 | 412 | MODULE_DESCRIPTION("Hone event notifier module."); 413 | MODULE_AUTHOR("Brandon Carpenter"); 414 | MODULE_LICENSE("GPL v2"); 415 | MODULE_VERSION(HONE_VERSION); 416 | 417 | EXPORT_SYMBOL(get_hone_statistics); 418 | EXPORT_SYMBOL(hone_notifier_register); 419 | EXPORT_SYMBOL(hone_notifier_unregister); 420 | EXPORT_SYMBOL(alloc_hone_event); 421 | EXPORT_SYMBOL(__alloc_process_event); 422 | EXPORT_SYMBOL(__alloc_socket_event); 423 | EXPORT_SYMBOL(free_hone_event); 424 | 425 | #endif // CONFIG_HONE_NOTIFY_COMBINED 426 | 427 | -------------------------------------------------------------------------------- /src/honeevent.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Battelle Memorial Institute 3 | * 4 | * Licensed under the GNU General Public License Version 2. 5 | * See LICENSE for the full text of the license. 6 | * See DISCLAIMER for additional disclaimers. 7 | * 8 | * Author: Brandon Carpenter 9 | */ 10 | 11 | #ifndef _HONEEVENT_H 12 | #define _HONEEVENT_H 13 | 14 | #define HEIO_RESTART _IO(0xE0, 0x01) 15 | #define HEIO_GET_AT_HEAD _IO(0xE0, 0x03) 16 | #define HEIO_GET_SNAPLEN _IOR(0xE0, 0x04, int) 17 | #define HEIO_SET_SNAPLEN _IOW(0xE0, 0x05, int) 18 | #define HEIO_SET_FILTER_SOCK _IOW(0xE0, 0x06, int) 19 | 20 | #endif /* _HONEEVENT_H */ 21 | -------------------------------------------------------------------------------- /src/honeevent_imp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Battelle Memorial Institute 3 | * 4 | * Licensed under the GNU General Public License Version 2. 5 | * See LICENSE for the full text of the license. 6 | * See DISCLAIMER for additional disclaimers. 7 | * 8 | * Author: Brandon Carpenter 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #include "process_notify.h" 27 | #include "hone_notify.h" 28 | #include "honeevent.h" 29 | #include "mmutil.h" 30 | #include "ringbuf.h" 31 | #include "pcapng.h" 32 | #include "version.h" 33 | 34 | MODULE_DESCRIPTION("Hone event character device."); 35 | MODULE_AUTHOR("Brandon Carpenter"); 36 | MODULE_LICENSE("GPL v2"); 37 | MODULE_VERSION(HONE_VERSION); 38 | MODULE_ALIAS("hone"); 39 | 40 | static char version[] __initdata = HONE_VERSION; 41 | 42 | static char *devname = "hone"; 43 | module_param(devname, charp, S_IRUGO); 44 | MODULE_PARM_DESC(devname, "The name to give the device in sysfs (default: hone)."); 45 | 46 | static int major = 0; 47 | module_param(major, int, S_IRUGO); 48 | MODULE_PARM_DESC(major, "The major number to give the device. " 49 | "If 0 (the default), the major number is automatically assigned by the kernel."); 50 | 51 | static char hostid_type = 0; 52 | module_param(hostid_type, byte, S_IRUGO); 53 | MODULE_PARM_DESC(hostid_type, 54 | "An integer describing how to interpret the value of hostid. 0 (the " 55 | "default) means hostid is a string while 1 means it is a GUID."); 56 | 57 | static char *hostid = ""; 58 | module_param(hostid, charp, S_IRUGO); 59 | MODULE_PARM_DESC(hostid, 60 | "A GUID which, if given, will be included in the output."); 61 | 62 | static char *comment = ""; 63 | module_param(comment, charp, S_IRUGO); 64 | MODULE_PARM_DESC(comment, "If given, will be included in the comment option " 65 | "of the section header block. Spaces can be encoded as \\040 or \\x20."); 66 | 67 | #ifndef CONFIG_HONE_DEFAULT_PAGEORDER 68 | #ifdef CONFIG_64BIT 69 | #define CONFIG_HONE_DEFAULT_PAGEORDER 3 70 | #else 71 | #define CONFIG_HONE_DEFAULT_PAGEORDER 2 72 | #endif 73 | #endif 74 | 75 | static unsigned int pageorder = CONFIG_HONE_DEFAULT_PAGEORDER; 76 | module_param(pageorder, uint, S_IWUSR|S_IRUGO); 77 | MODULE_PARM_DESC(pageorder, 78 | "Specifies the page order to use when allocating the ring buffer " 79 | "(default: " __stringify(CONFIG_HONE_DEFAULT_PAGEORDER) "). The buffer " 80 | "size is computed as PAGE_SIZE * (1 << pageorder)."); 81 | 82 | static struct class *class_hone; 83 | 84 | 85 | #define printm(level, fmt, ...) printk(level "%s: %s:%d: " fmt, mod_name, __FILE__, __LINE__, ##__VA_ARGS__) 86 | #define mod_name (THIS_MODULE->name) 87 | 88 | #define size_of_pages(order) (PAGE_SIZE << (order)) 89 | #define READ_BUFFER_PAGE_ORDER 5 90 | #define READ_BUFFER_SIZE size_of_pages(READ_BUFFER_PAGE_ORDER) 91 | 92 | #define READER_HEAD 0x00000001 93 | #define READER_INIT 0x00000002 94 | #define READER_TAIL 0x00000004 95 | #define READER_FINISH 0x00000008 96 | #define READER_RESTART 0x0000000F 97 | #define READER_FILTER_PID 0x00000100 98 | 99 | static struct device_info devinfo = { 100 | .comment = NULL, 101 | .host_id = NULL, 102 | .host_guid_is_set = false 103 | }; 104 | 105 | struct hone_reader { 106 | struct semaphore sem; 107 | struct ring_buf ringbuf; 108 | struct notifier_block nb; 109 | unsigned int (*format)(const struct device_info *, 110 | const struct reader_info *, struct hone_event *, char *, unsigned int); 111 | struct reader_info info; 112 | atomic_t flags; 113 | struct sock *filter_sk; 114 | struct hone_event *event; 115 | wait_queue_head_t event_wait_queue; 116 | size_t length, offset; 117 | char *buf; 118 | }; 119 | 120 | static struct hone_event head_event = {HONE_USER_HEAD, {ATOMIC_INIT(1)}}; 121 | static struct hone_event tail_event = {HONE_USER_TAIL, {ATOMIC_INIT(1)}}; 122 | 123 | #define reader_will_block(rdr) (ring_is_empty(&(rdr)->ringbuf) && \ 124 | !(rdr)->event && !(atomic_read(&(rdr)->flags) & READER_RESTART)) 125 | 126 | static unsigned int format_as_text( 127 | const struct device_info *devinfo, const struct reader_info *info, 128 | struct hone_event *event, char *buf, unsigned int buflen) 129 | { 130 | static const char *event_names[] = {"????", "FORK", "EXEC", "EXIT", "KTHD"}; 131 | unsigned int n = 0; 132 | 133 | #define printbuf(fmt, ...) ({ if ((n += snprintf(buf + n, buflen - n, fmt, ##__VA_ARGS__)) >= buflen) { goto out_long; }; n; }) 134 | 135 | switch (event->type) { 136 | case HONE_PROCESS: 137 | { 138 | struct process_event *pev = &event->process; 139 | printbuf("%lu.%09lu %s %d %d %d %d\n", 140 | event->ts.tv_sec, event->ts.tv_nsec, event_names[pev->event], 141 | pev->pid, pev->ppid, pev->uid, pev->gid); 142 | if (pev->mm) { 143 | n--; 144 | if (pev->event == PROC_KTHD) 145 | printbuf(" [%s]", pev->comm); 146 | else { 147 | char *path, *argv; 148 | printbuf(" \""); 149 | if ((path = mm_path(pev->mm, buf + n, buflen -n - 3))) { 150 | int pathlen = strlen(path); 151 | memmove(buf + n, path, pathlen); 152 | n += pathlen; 153 | } 154 | printbuf("\" "); 155 | argv = buf + n; 156 | n += mm_argv(pev->mm, buf + n, buflen - n - 1); 157 | for ( ; argv < buf + n; argv++) { 158 | if (*argv == '\0') 159 | *argv = ' '; 160 | } 161 | } 162 | printbuf("\n"); 163 | } 164 | break; 165 | } 166 | case HONE_SOCKET: 167 | { 168 | struct socket_event *sockev = &event->socket; 169 | printbuf("%lu.%09lu SOCK %c %d %d %d %d %08lx\n", 170 | event->ts.tv_sec, event->ts.tv_nsec, sockev->event ? 'C' : 'O', 171 | sockev->pid, sockev->ppid, sockev->uid, sockev->gid, 172 | sockev->sock & 0xFFFFFFFF); 173 | break; 174 | } 175 | case HONE_PACKET: 176 | { 177 | struct iphdr _iph, *iph = 178 | skb_header_pointer(event->packet.skb, 0, sizeof(_iph), &_iph); 179 | printbuf("%lu.%09lu PAKT %c %08lx %u", event->ts.tv_sec, 180 | event->ts.tv_nsec, event->packet.dir ? 'I' : 'O', 181 | event->packet.sock & 0xFFFFFFFF, event->packet.pid); 182 | if (!iph) 183 | printbuf(" ? ? -> ?"); 184 | else if (iph->version == 4) { 185 | if (iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP) { 186 | struct udphdr _uh, *uh; 187 | if ((uh = skb_header_pointer(event->packet.skb, 188 | iph->ihl << 2, sizeof(_uh), &_uh))) { 189 | printbuf(" %sv4 %pI4:%d -> %pI4:%d", 190 | iph->protocol == IPPROTO_TCP ? "TCP" : "UDP", 191 | &iph->saddr, ntohs(uh->source), 192 | &iph->daddr, ntohs(uh->dest)); 193 | } else { 194 | printbuf(" %sv4 ? -> ?", 195 | iph->protocol == IPPROTO_TCP ? "TCP" : "UDP"); 196 | } 197 | } else { 198 | printbuf(" %u %pI4 -> %pI4", iph->protocol, 199 | &iph->saddr, &iph->daddr); 200 | } 201 | } else if (iph->version == 6) { 202 | struct ipv6hdr _iph6, *iph6 = 203 | skb_header_pointer(event->packet.skb, 0, sizeof(_iph6), &_iph6); 204 | if (iph6->nexthdr == IPPROTO_TCP || iph6->nexthdr == IPPROTO_UDP) { 205 | struct udphdr _uh, *uh; 206 | if ((uh = skb_header_pointer(event->packet.skb, 207 | sizeof(struct ipv6hdr), sizeof(_uh), &_uh))) { 208 | printbuf(" %sv6 %pI6:%d -> %pI6:%d", 209 | iph6->nexthdr == IPPROTO_TCP ? "TCP" : "UDP", 210 | &iph6->saddr, ntohs(uh->source), 211 | &iph6->daddr, ntohs(uh->dest)); 212 | } else { 213 | printbuf(" %sv6 ? -> ?", 214 | iph6->nexthdr == IPPROTO_TCP ? "TCP" : "UDP"); 215 | } 216 | } else { 217 | printbuf(" %u %pI6 -> %pI6", iph6->nexthdr, 218 | &iph6->saddr, &iph6->daddr); 219 | } 220 | } else { 221 | printbuf(" ?.%d ? -> ?", iph->version); 222 | } 223 | /* 224 | { 225 | int i; 226 | for (i = 0; i < pkt->caplen; i += sizeof(int)) 227 | printbuf(" %08x", htonl(*((int *) (pkt->data + i)))); 228 | } 229 | */ 230 | printbuf(" %u\n", event->packet.skb->len); 231 | break; 232 | } 233 | case HONE_USER_HEAD: 234 | if (devinfo->host_guid_is_set) 235 | printbuf("%lu.%09lu HEAD %lu.%09lu {" GUID_FMT "}\n", 236 | info->start_time.tv_sec, info->start_time.tv_nsec, 237 | info->boot_time.tv_sec, info->boot_time.tv_nsec, 238 | GUID_TUPLE(&devinfo->host_guid)); 239 | else 240 | printbuf("%lu.%09lu HEAD %lu.%09lu\n", 241 | info->start_time.tv_sec, info->start_time.tv_nsec, 242 | info->boot_time.tv_sec, info->boot_time.tv_nsec); 243 | break; 244 | case HONE_USER_TAIL: 245 | printbuf("%lu.%09lu TAIL\n", 246 | info->start_time.tv_sec, info->start_time.tv_nsec); 247 | break; 248 | default: 249 | printbuf("%lu.%09lu ???? %d\n", 250 | event->ts.tv_sec, event->ts.tv_nsec, event->type); 251 | break; 252 | } 253 | #undef printbuf 254 | 255 | return n; 256 | 257 | out_long: 258 | snprintf(buf + buflen - 5, 5, "...\n"); 259 | return buflen; 260 | } 261 | 262 | static void inc_stats_counter(struct statistics *stats, int type) 263 | { 264 | atomic64_t *counter; 265 | 266 | switch(type) { 267 | case HONE_PROCESS: 268 | counter = &stats->process; 269 | break; 270 | case HONE_SOCKET: 271 | counter = &stats->socket; 272 | break; 273 | case HONE_PACKET: 274 | counter = &stats->packet; 275 | break; 276 | default: 277 | return; 278 | } 279 | atomic64_inc(counter); 280 | } 281 | 282 | static int inline enqueue_event(struct hone_reader *reader, 283 | struct hone_event *event) 284 | { 285 | // Ignore threads for now 286 | if (event->type == HONE_PROCESS && event->process.pid != event->process.tgid) 287 | return 0; 288 | // Filter out packets for local socket, if set 289 | if (event->type == HONE_PACKET && reader->filter_sk && 290 | event->packet.sock == (unsigned long) reader->filter_sk) { 291 | atomic64_inc(&reader->info.filtered); 292 | return 0; 293 | } 294 | get_hone_event(event); 295 | if (ring_append(&reader->ringbuf, event)) { 296 | inc_stats_counter(&reader->info.dropped, event->type); 297 | put_hone_event(event); 298 | return 0; 299 | } 300 | return 1; 301 | } 302 | 303 | static int hone_event_handler(struct notifier_block *nb, unsigned long val, void *v) 304 | { 305 | struct hone_reader *reader = 306 | container_of(nb, struct hone_reader, nb); 307 | 308 | if (enqueue_event(reader, v)) 309 | wake_up_interruptible_all(&reader->event_wait_queue); 310 | 311 | return 0; 312 | } 313 | 314 | static void free_hone_reader(struct hone_reader *reader) 315 | { 316 | if (reader) { 317 | if (reader->ringbuf.data) { 318 | free_pages((unsigned long) (reader->ringbuf.data), reader->ringbuf.pageorder); 319 | reader->ringbuf.data = NULL; 320 | } 321 | if (reader->buf) { 322 | free_pages((unsigned long) (reader->buf), READ_BUFFER_PAGE_ORDER); 323 | reader->buf = NULL; 324 | } 325 | kfree(reader); 326 | } 327 | } 328 | 329 | static struct hone_reader *alloc_hone_reader(void) 330 | { 331 | struct hone_reader *reader; 332 | struct ring_buf *ring; 333 | 334 | if (!(reader = kzalloc(sizeof(*reader), GFP_KERNEL))) 335 | goto alloc_failed; 336 | if (!(reader->buf = (typeof(reader->buf)) 337 | __get_free_pages(GFP_KERNEL | __GFP_ZERO, READ_BUFFER_PAGE_ORDER))) 338 | goto alloc_failed; 339 | ring = &reader->ringbuf; 340 | ring->pageorder = pageorder; 341 | if (!(ring->data = (typeof(ring->data)) 342 | __get_free_pages(GFP_KERNEL | __GFP_ZERO, ring->pageorder))) 343 | goto alloc_failed; 344 | ring->length = size_of_pages(ring->pageorder) / sizeof(*(ring->data)); 345 | //reader->format = format_as_text; 346 | reader->format = format_as_pcapng; 347 | atomic_set(&reader->flags, READER_HEAD | READER_INIT); 348 | sema_init(&reader->sem, 1); 349 | init_waitqueue_head(&reader->event_wait_queue); 350 | return reader; 351 | 352 | alloc_failed: 353 | free_hone_reader(reader); 354 | return NULL; 355 | } 356 | 357 | 358 | extern const struct file_operations socket_file_ops; 359 | 360 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0) 361 | #define OPEN_FDS open_fds 362 | #else 363 | #define OPEN_FDS open_fds->fds_bits 364 | #endif 365 | 366 | static struct hone_event *__add_files(struct hone_reader *reader, 367 | struct hone_event *event, struct task_struct *task) 368 | { 369 | struct hone_event *sk_event; 370 | struct files_struct *files; 371 | struct file *file; 372 | struct fdtable *fdt; 373 | struct socket *sock; 374 | struct sock *sk; 375 | unsigned long flags, set; 376 | int i, fd; 377 | 378 | if (!(files = get_files_struct(task))) 379 | return event; 380 | spin_lock_irqsave(&files->file_lock, flags); 381 | if (!(fdt = files_fdtable(files))) 382 | goto out; 383 | for (i = 0; (fd = i * BITS_PER_LONG) < fdt->max_fds; i++) { 384 | for (set = fdt->OPEN_FDS[i]; set; set >>= 1, fd++) { 385 | if (!(set & 1)) 386 | continue; 387 | file = fdt->fd[fd]; 388 | if (!file || file->f_op != &socket_file_ops || !file->private_data) 389 | continue; 390 | sock = file->private_data; 391 | sk = sock->sk; 392 | if (!sk || (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)) 393 | continue; 394 | 395 | if ((sk_event = __alloc_socket_event((unsigned long) sk, 396 | 0, task, GFP_ATOMIC))) { 397 | sk_event->next = event; 398 | event = sk_event; 399 | memcpy(&event->ts, &task->start_time, sizeof(event->ts)); 400 | } else { 401 | atomic64_inc(&reader->info.dropped.socket); 402 | } 403 | } 404 | } 405 | out: 406 | spin_unlock_irqrestore(&files->file_lock, flags); 407 | put_files_struct(files); 408 | return event; 409 | } 410 | 411 | 412 | #define prev_task(p) \ 413 | list_entry_rcu((p)->tasks.prev, struct task_struct, tasks) 414 | 415 | static struct hone_event *add_current_tasks( 416 | struct hone_reader *reader, struct hone_event *event) 417 | { 418 | struct hone_event *proc_event; 419 | struct task_struct *task; 420 | 421 | rcu_read_lock(); 422 | for (task = &init_task; (task = prev_task(task)) != &init_task; ) { 423 | if (task->flags & PF_EXITING) 424 | continue; 425 | event = __add_files(reader, event, task); 426 | if ((proc_event = __alloc_process_event(task, 427 | task->flags & PF_FORKNOEXEC ? PROC_FORK : PROC_EXEC, 428 | GFP_ATOMIC))) { 429 | proc_event->next = event; 430 | event = proc_event; 431 | memcpy(&event->ts, &task->start_time, sizeof(event->ts)); 432 | } else { 433 | atomic64_inc(&reader->info.dropped.process); 434 | } 435 | } 436 | rcu_read_unlock(); 437 | return event; 438 | } 439 | 440 | static void free_initial_events(struct hone_reader *reader) 441 | { 442 | struct hone_event *event, *next; 443 | 444 | for (event = reader->event; event; event = next) { 445 | next = event->next; 446 | free_hone_event(event); 447 | } 448 | reader->event = NULL; 449 | } 450 | 451 | static void add_initial_events(struct hone_reader *reader) 452 | { 453 | free_initial_events(reader); 454 | reader->event = add_current_tasks(reader, NULL); 455 | } 456 | 457 | static int hone_open(struct inode *inode, struct file *file) 458 | { 459 | struct hone_reader *reader; 460 | int err = -ENOMEM; 461 | 462 | if ((file->f_flags & O_ACCMODE) != O_RDONLY) 463 | return -EINVAL; 464 | if (!(reader = alloc_hone_reader())) 465 | goto reader_failed; 466 | if (iminor(inode) == 1) 467 | reader->format = format_as_text; 468 | file->private_data = reader; 469 | getboottime(&reader->info.boot_time); 470 | ktime_get_ts(&reader->info.start_time); 471 | init_statistics(&reader->info.delivered); 472 | init_statistics(&reader->info.dropped); 473 | reader->nb.notifier_call = hone_event_handler; 474 | if ((err = hone_notifier_register(&reader->nb))) { 475 | printm(KERN_ERR, "hone_notifier_register() failed with error %d\n", err); 476 | goto register_failed; 477 | } 478 | __module_get(THIS_MODULE); 479 | return 0; 480 | 481 | register_failed: 482 | free_hone_reader(reader); 483 | reader_failed: 484 | return err; 485 | } 486 | 487 | static int hone_release(struct inode *inode, struct file *file) 488 | { 489 | struct hone_reader *reader = file->private_data; 490 | struct hone_event *event; 491 | 492 | hone_notifier_unregister(&reader->nb); 493 | file->private_data = NULL; 494 | while ((event = ring_pop(&reader->ringbuf))) 495 | put_hone_event(event); 496 | if (reader->filter_sk) { 497 | sock_put(reader->filter_sk); 498 | reader->filter_sk = NULL; 499 | } 500 | free_initial_events(reader); 501 | free_hone_reader(reader); 502 | module_put(THIS_MODULE); 503 | 504 | return 0; 505 | } 506 | 507 | static ssize_t hone_read(struct file *file, char __user *buffer, 508 | size_t length, loff_t *offset) 509 | { 510 | struct hone_reader *reader = file->private_data; 511 | size_t n, copied = 0; 512 | 513 | if (!length) 514 | return 0; 515 | 516 | do { 517 | while (!reader->offset && reader_will_block(reader)) { 518 | if (file->f_flags & O_NONBLOCK) 519 | return -EAGAIN; 520 | if (wait_event_interruptible(reader->event_wait_queue, 521 | !reader_will_block(reader))) 522 | return -EINTR; 523 | } 524 | 525 | if (file->f_flags & O_NONBLOCK) { 526 | if (down_trylock(&reader->sem)) 527 | return -EAGAIN; 528 | } else if (down_interruptible(&reader->sem)) { 529 | return -EINTR; 530 | } 531 | 532 | while (copied < length) { 533 | if (!reader->offset) { 534 | int flags; 535 | struct hone_event *event; 536 | void (*free_event)(struct hone_event *); 537 | 538 | flags = atomic_read(&reader->flags); 539 | if (flags & READER_TAIL) { 540 | atomic_clear_mask(READER_TAIL, &reader->flags); 541 | event = &tail_event; 542 | free_event = NULL; 543 | } else if (flags & READER_FINISH) { 544 | if (!copied) 545 | atomic_clear_mask(READER_FINISH, &reader->flags); 546 | up(&reader->sem); 547 | return copied; 548 | } else if (flags & READER_HEAD) { 549 | atomic_clear_mask(READER_HEAD, &reader->flags); 550 | event = &head_event; 551 | free_event = NULL; 552 | } else if (flags & READER_INIT) { 553 | atomic_clear_mask(READER_INIT, &reader->flags); 554 | add_initial_events(reader); 555 | continue; 556 | } else if (reader->event) { 557 | if ((event = reader->event)) 558 | reader->event = event->next; 559 | free_event = free_hone_event; 560 | } else { 561 | event = ring_pop(&reader->ringbuf); 562 | free_event = put_hone_event; 563 | } 564 | 565 | if (!event) 566 | break; 567 | reader->length = reader->format(&devinfo, &reader->info, 568 | event, reader->buf, READ_BUFFER_SIZE); 569 | inc_stats_counter(&reader->info.delivered, event->type); 570 | if (free_event) 571 | free_event(event); 572 | } 573 | n = min(reader->length - reader->offset, length - copied); 574 | if (copy_to_user(buffer + copied, reader->buf + reader->offset, n)) { 575 | up(&reader->sem); 576 | return -EFAULT; 577 | } 578 | copied += n; 579 | reader->offset += n; 580 | if (reader->offset >= reader->length) 581 | reader->offset = 0; 582 | } 583 | up(&reader->sem); 584 | } while (!copied); 585 | return copied; 586 | } 587 | 588 | extern void fput(struct file *); 589 | 590 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11) 591 | static long hone_ioctl(struct file *file, unsigned int num, 592 | unsigned long param) 593 | #else 594 | static int hone_ioctl(struct inode *inode, struct file *file, 595 | unsigned int num, unsigned long param) 596 | #endif 597 | { 598 | struct hone_reader *reader = file->private_data; 599 | int err; 600 | 601 | if (_IOC_TYPE(num) != 0xE0) 602 | return -EINVAL; 603 | 604 | switch (num) { 605 | case HEIO_RESTART: 606 | atomic_set_mask(READER_RESTART, &reader->flags); 607 | wake_up_interruptible_all(&reader->event_wait_queue); 608 | return 0; 609 | case HEIO_GET_AT_HEAD: 610 | return atomic_read(&reader->flags) & READER_HEAD ? 1 : 0; 611 | case HEIO_GET_SNAPLEN: 612 | return put_user(reader->info.snaplen, (unsigned int __user *) param); 613 | case HEIO_SET_SNAPLEN: 614 | reader->info.snaplen = (unsigned int) param; 615 | atomic_set_mask(READER_HEAD, &reader->flags); 616 | return 0; 617 | case HEIO_SET_FILTER_SOCK: 618 | { 619 | int fd = (int) param; 620 | struct sock *sk; 621 | if (fd != -1) { 622 | struct socket *sock; 623 | if (!(sock = sockfd_lookup(fd, &err))) 624 | return err; 625 | sk = sock->sk; 626 | sock_hold(sk); 627 | fput(sock->file); 628 | } else { 629 | sk = NULL; 630 | } 631 | for (;;) { 632 | struct sock *old_sk = reader->filter_sk; 633 | if (cmpxchg(&reader->filter_sk, old_sk, sk) == old_sk) { 634 | if (old_sk) 635 | sock_put(old_sk); 636 | break; 637 | } 638 | } 639 | return 0; 640 | } 641 | } 642 | 643 | return -EINVAL; 644 | } 645 | 646 | static unsigned int hone_poll(struct file *file, 647 | struct poll_table_struct *wait) 648 | { 649 | struct hone_reader *reader = file->private_data; 650 | 651 | poll_wait(file, &reader->event_wait_queue, wait); 652 | if (!reader_will_block(reader)) 653 | return POLLIN | POLLRDNORM; 654 | return 0; 655 | } 656 | 657 | static const struct file_operations device_ops = { 658 | .read = hone_read, 659 | .open = hone_open, 660 | .release = hone_release, 661 | .unlocked_ioctl = hone_ioctl, 662 | .compat_ioctl = hone_ioctl, 663 | .poll = hone_poll, 664 | }; 665 | 666 | #ifdef CONFIG_HONE_NOTIFY_COMBINED 667 | int hone_notify_init(void) __init; 668 | void hone_notify_release(void); 669 | #else 670 | # define hone_notify_init() (0) 671 | # define hone_notify_release() 672 | #endif 673 | 674 | static int __init honeevent_init(void) 675 | { 676 | int err; 677 | 678 | if (hostid && *hostid) { 679 | if (!hostid_type) 680 | devinfo.host_id = hostid; 681 | else if (hostid_type == 1) { 682 | if (parse_guid(&devinfo.host_guid, hostid)) { 683 | printm(KERN_ERR, "invalid host GUID: %s\n", hostid); 684 | return -1; 685 | } 686 | printm(KERN_DEBUG, "using host GUID {" GUID_FMT "}\n", 687 | GUID_TUPLE(&devinfo.host_guid)); 688 | devinfo.host_guid_is_set = true; 689 | } else { 690 | printm(KERN_ERR, "invalid hostid_type: %d\n", hostid_type); 691 | return -1; 692 | } 693 | } 694 | if (comment && *comment) 695 | devinfo.comment = comment; 696 | if ((err = hone_notify_init())) 697 | return -1; 698 | if ((err = register_chrdev(major, devname, &device_ops)) < 0) { 699 | printm(KERN_ERR, "character device registration returned error %d\n", err); 700 | hone_notify_release(); 701 | return -1; 702 | } 703 | if (!major) 704 | major = err; 705 | 706 | class_hone = class_create(THIS_MODULE, devname); 707 | if (IS_ERR(class_hone)) { 708 | printm(KERN_ERR, "class_create failed\n"); 709 | return PTR_ERR(class_hone); 710 | } 711 | 712 | device_create(class_hone, NULL, MKDEV(major, 0), NULL, "%s", devname); 713 | device_create(class_hone, NULL, MKDEV(major, 1), NULL, "%st", devname); 714 | 715 | printk(KERN_INFO "%s: v%s module successfully loaded with major number %d\n", 716 | mod_name, version, major); 717 | return 0; 718 | } 719 | 720 | static void __exit honeevent_exit(void) 721 | { 722 | device_destroy(class_hone, MKDEV(major, 0)); 723 | device_destroy(class_hone, MKDEV(major, 1)); 724 | class_destroy(class_hone); 725 | unregister_chrdev(major, devname); 726 | hone_notify_release(); 727 | 728 | printk(KERN_INFO "%s: module successfully unloaded\n", mod_name); 729 | } 730 | 731 | module_init(honeevent_init); 732 | module_exit(honeevent_exit); 733 | 734 | -------------------------------------------------------------------------------- /src/mmutil.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Battelle Memorial Institute 3 | * 4 | * Licensed under the GNU General Public License Version 2. 5 | * See LICENSE for the full text of the license. 6 | * See DISCLAIMER for additional disclaimers. 7 | * 8 | * Author: Brandon Carpenter 9 | * 10 | * Much of the code below is based on procfs code. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25) 20 | #define D_PATH(mnt, dentry, buf, size) \ 21 | ({ struct path _p = {(mnt), (dentry)}; d_path(&_p, (buf), (size)); }) 22 | #else 23 | #define D_PATH d_path 24 | #endif 25 | 26 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) 27 | #define __get_exe_file(mm) ((mm)->exe_file) 28 | #else 29 | static struct file *__get_exe_file(struct mm_struct *mm) 30 | { 31 | struct vm_area_struct *vma; 32 | 33 | for (vma = mm->mmap; vma; vma = vma->vm_next) { 34 | if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) 35 | return vma->vm_file; 36 | } 37 | return NULL; 38 | } 39 | #endif 40 | 41 | static char *__exe_path(struct mm_struct *mm, char *buf, int buflen) 42 | { 43 | struct file *exe_file; 44 | char *path = NULL; 45 | 46 | if ((exe_file = __get_exe_file(mm))) { 47 | struct vfsmount *mnt; 48 | struct dentry *dentry; 49 | 50 | mnt = mntget(exe_file->f_path.mnt); 51 | dentry = dget(exe_file->f_path.dentry); 52 | 53 | if (mnt && dentry) { 54 | path = D_PATH(mnt, dentry, buf, buflen); 55 | dput(dentry); 56 | mntput(mnt); 57 | } 58 | } 59 | 60 | return path; 61 | } 62 | 63 | static int __mm_argv(struct mm_struct *mm, char *buf, int buflen) 64 | { 65 | char *pos; 66 | unsigned long addr, size; 67 | 68 | if (!buflen) 69 | return 0; 70 | 71 | pos = buf; 72 | addr = mm->arg_start; 73 | size = mm->arg_end - mm->arg_start; 74 | if (size > buflen) 75 | size = buflen; 76 | while (size) { 77 | struct page *page; 78 | int bytes, offset; 79 | void *maddr; 80 | 81 | if (get_user_pages(NULL, mm, addr, 1, 0, 0, &page, NULL) <= 0) 82 | break; 83 | 84 | bytes = size; 85 | offset = addr & (PAGE_SIZE - 1); 86 | if (bytes > (PAGE_SIZE - offset)) 87 | bytes = PAGE_SIZE - offset; 88 | 89 | maddr = kmap(page); 90 | memcpy(pos, maddr + offset, bytes); 91 | kunmap(page); 92 | put_page(page); 93 | 94 | size -= bytes; 95 | pos += bytes; 96 | addr += bytes; 97 | } 98 | 99 | if (pos == buf) { 100 | *pos = '\0'; 101 | pos++; 102 | } else if (*(pos - 1)) 103 | *(pos - 1) = '\0'; 104 | return pos - buf; 105 | } 106 | 107 | char *mm_path(struct mm_struct *mm, char *buf, int buflen) 108 | { 109 | char *path; 110 | 111 | down_read(&mm->mmap_sem); 112 | path = __exe_path(mm, buf, buflen); 113 | up_read(&mm->mmap_sem); 114 | return path; 115 | } 116 | 117 | int mm_argv(struct mm_struct *mm, char *buf, int buflen) 118 | { 119 | int argvlen; 120 | 121 | down_read(&mm->mmap_sem); 122 | argvlen = __mm_argv(mm, buf, buflen - 1); 123 | up_read(&mm->mmap_sem); 124 | buf[argvlen] = '\0'; 125 | return argvlen; 126 | } 127 | 128 | -------------------------------------------------------------------------------- /src/mmutil.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Battelle Memorial Institute 3 | * 4 | * Licensed under the GNU General Public License Version 2. 5 | * See LICENSE for the full text of the license. 6 | * See DISCLAIMER for additional disclaimers. 7 | * 8 | * Author: Brandon Carpenter 9 | */ 10 | 11 | #ifndef _MMUTIL_H 12 | #define _MMUTIL_H 13 | 14 | #include 15 | 16 | char *mm_path(struct mm_struct *mm, char *buf, int buflen); 17 | int mm_argv(struct mm_struct *mm, char *buf, int buflen); 18 | 19 | #endif /* _MMUTIL_H */ 20 | 21 | -------------------------------------------------------------------------------- /src/packet_notify.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Battelle Memorial Institute 3 | * 4 | * Licensed under the GNU General Public License Version 2. 5 | * See LICENSE for the full text of the license. 6 | * See DISCLAIMER for additional disclaimers. 7 | * 8 | * Author: Brandon Carpenter 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #if !defined(CONFIG_KPROBES) || !defined(CONFIG_KALLSYMS) 19 | #error packet_notify module requires kprobes support (CONFIG_KPROBES and CONFIG_KALLSYMS) 20 | #endif 21 | 22 | #include "socket_lookup.h" 23 | #include "packet_notify.h" 24 | #include "version.h" 25 | 26 | static RAW_NOTIFIER_HEAD(notifier_list); 27 | static DEFINE_RWLOCK(notifier_lock); 28 | 29 | int packet_notifier_register(struct notifier_block *nb) 30 | { 31 | int result; 32 | unsigned long flags; 33 | 34 | write_lock_irqsave(¬ifier_lock, flags); 35 | result = raw_notifier_chain_register(¬ifier_list, nb); 36 | write_unlock_irqrestore(¬ifier_lock, flags); 37 | return result; 38 | } 39 | 40 | int packet_notifier_unregister(struct notifier_block *nb) 41 | { 42 | int result; 43 | unsigned long flags; 44 | 45 | write_lock_irqsave(¬ifier_lock, flags); 46 | result = raw_notifier_chain_unregister(¬ifier_list, nb); 47 | write_unlock_irqrestore(¬ifier_lock, flags); 48 | return result; 49 | } 50 | 51 | static inline int packet_notifier_notify( 52 | unsigned long event, struct packet_args *pargs) 53 | { 54 | int result; 55 | unsigned long flags; 56 | 57 | read_lock_irqsave(¬ifier_lock, flags); 58 | result = raw_notifier_call_chain(¬ifier_list, event, pargs); 59 | read_unlock_irqrestore(¬ifier_lock, flags); 60 | return result; 61 | } 62 | 63 | static int packet_rcv_handler(struct sock *sk, struct sk_buff *skb) 64 | { 65 | struct packet_args pargs = {sk, skb}; 66 | packet_notifier_notify(PKTNOT_PACKET_IN, &pargs); 67 | jprobe_return(); 68 | return 0; 69 | } 70 | 71 | static int fault_handler(struct kprobe *p, struct pt_regs *regs, int trapnr) 72 | { 73 | printk(KERN_WARNING "%s: fault %d occured in kprobe for %s\n", 74 | THIS_MODULE->name, trapnr, p->symbol_name); 75 | return 0; 76 | } 77 | 78 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,13,0) 79 | typedef const struct nf_hook_ops * nf_hook_type; 80 | #else 81 | typedef unsigned int nf_hook_type; 82 | #endif 83 | 84 | static unsigned int nf_hook_v4_in(nf_hook_type hook, struct sk_buff *skb, 85 | const struct net_device *indev, const struct net_device *outdev, 86 | int (*okfn)(struct sk_buff *)) 87 | { 88 | struct sock *sk = lookup_v4_sock(skb, indev); 89 | struct packet_args pargs = {sk, skb}; 90 | packet_notifier_notify(PKTNOT_PACKET_IN, &pargs); 91 | if (sk) 92 | put_sock(sk); 93 | return NF_ACCEPT; 94 | } 95 | 96 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 97 | static unsigned int nf_hook_v6_in(nf_hook_type hook, struct sk_buff *skb, 98 | const struct net_device *indev, const struct net_device *outdev, 99 | int (*okfn)(struct sk_buff *)) 100 | { 101 | struct sock *sk = lookup_v6_sock(skb, indev); 102 | struct packet_args pargs = {sk, skb}; 103 | packet_notifier_notify(PKTNOT_PACKET_IN, &pargs); 104 | if (sk) 105 | put_sock(sk); 106 | return NF_ACCEPT; 107 | } 108 | #endif 109 | 110 | static unsigned int nf_hook_out(nf_hook_type hook, struct sk_buff *skb, 111 | const struct net_device *indev, 112 | const struct net_device *outdev, 113 | int (*okfn)(struct sk_buff *)) 114 | { 115 | struct packet_args pargs = {skb->sk, skb}; 116 | packet_notifier_notify(PKTNOT_PACKET_OUT, &pargs); 117 | return NF_ACCEPT; 118 | } 119 | 120 | static struct jprobe raw4_jprobe = { 121 | .kp.symbol_name = "raw_rcv", 122 | .kp.fault_handler = fault_handler, 123 | .entry = packet_rcv_handler, 124 | }; 125 | 126 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 127 | static struct jprobe raw6_jprobe = { 128 | .kp.symbol_name = "rawv6_rcv", 129 | .kp.fault_handler = fault_handler, 130 | .entry = packet_rcv_handler, 131 | }; 132 | #endif // CONFIG_IPV6 133 | 134 | static struct jprobe *inet_jprobes[] = { 135 | &raw4_jprobe, 136 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 137 | &raw6_jprobe, 138 | #endif // CONFIG_IPV6 139 | }; 140 | 141 | static struct nf_hook_ops nf_inet_hooks[] = { 142 | { 143 | .list = {NULL, NULL}, 144 | .hook = nf_hook_v4_in, 145 | .owner = THIS_MODULE, 146 | .pf = PF_INET, 147 | .hooknum = NF_INET_LOCAL_IN, 148 | .priority = INT_MAX, 149 | }, 150 | { 151 | .list = {NULL, NULL}, 152 | .hook = nf_hook_out, 153 | .owner = THIS_MODULE, 154 | .pf = PF_INET, 155 | .hooknum = NF_INET_LOCAL_OUT, 156 | .priority = INT_MAX, 157 | }, 158 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 159 | { 160 | .list = {NULL, NULL}, 161 | .hook = nf_hook_v6_in, 162 | .owner = THIS_MODULE, 163 | .pf = PF_INET6, 164 | .hooknum = NF_INET_LOCAL_IN, 165 | .priority = INT_MAX, 166 | }, 167 | { 168 | .list = {NULL, NULL}, 169 | .hook = nf_hook_out, 170 | .owner = THIS_MODULE, 171 | .pf = PF_INET6, 172 | .hooknum = NF_INET_LOCAL_OUT, 173 | .priority = INT_MAX, 174 | }, 175 | #endif // CONFIG_IPV6 176 | }; 177 | 178 | #ifdef CONFIG_PACKET_NOTIFY_COMBINED 179 | # define _STATIC 180 | #else 181 | # define _STATIC static 182 | #endif 183 | 184 | _STATIC int __init packet_notify_init(void) 185 | { 186 | int err; 187 | 188 | if ((err = register_jprobes(inet_jprobes, ARRAY_SIZE(inet_jprobes)))) { 189 | printk(KERN_ERR "%s: jprobes registration failed (error %d)\n", 190 | THIS_MODULE->name, err); 191 | return -1; 192 | } 193 | if ((err = nf_register_hooks(nf_inet_hooks, ARRAY_SIZE(nf_inet_hooks)))) { 194 | printk(KERN_ERR "%s: netfilter hook registration failed (error %d)\n", 195 | THIS_MODULE->name, err); 196 | unregister_jprobes(inet_jprobes, ARRAY_SIZE(inet_jprobes)); 197 | return -1; 198 | } 199 | return 0; 200 | } 201 | 202 | _STATIC void packet_notify_remove(void) 203 | { 204 | unregister_jprobes(inet_jprobes, ARRAY_SIZE(inet_jprobes)); 205 | nf_unregister_hooks(nf_inet_hooks, ARRAY_SIZE(nf_inet_hooks)); 206 | } 207 | 208 | #ifndef CONFIG_PACKET_NOTIFY_COMBINED 209 | 210 | static char version[] __initdata = HONE_VERSION; 211 | 212 | static int __init packet_notify_module_init(void) 213 | { 214 | int err; 215 | 216 | if ((err = packet_notify_init())) { 217 | printk(KERN_ERR "packet_notify_init() failed with error %d\n", err); 218 | return -1; 219 | } 220 | printk(KERN_INFO "%s: v%s module loaded successfully\n", 221 | THIS_MODULE->name, version); 222 | return 0; 223 | } 224 | 225 | static void __exit packet_notify_module_exit(void) 226 | { 227 | packet_notify_remove(); 228 | printk(KERN_INFO "%s: module unloaded successfully\n", THIS_MODULE->name); 229 | } 230 | 231 | module_init(packet_notify_module_init); 232 | module_exit(packet_notify_module_exit); 233 | 234 | MODULE_DESCRIPTION("Internet protocol packet event notification module."); 235 | MODULE_AUTHOR("Brandon Carpenter"); 236 | MODULE_LICENSE("GPL v2"); 237 | MODULE_VERSION(HONE_VERSION); 238 | 239 | EXPORT_SYMBOL(packet_notifier_register); 240 | EXPORT_SYMBOL(packet_notifier_unregister); 241 | 242 | #endif // CONFIG_PACKET_NOTIFY_COMBINED 243 | 244 | -------------------------------------------------------------------------------- /src/packet_notify.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Battelle Memorial Institute 3 | * 4 | * Licensed under the GNU General Public License Version 2. 5 | * See LICENSE for the full text of the license. 6 | * See DISCLAIMER for additional disclaimers. 7 | * 8 | * Author: Brandon Carpenter 9 | */ 10 | 11 | #ifndef _PACKET_NOTIFY_H 12 | #define _PACKET_NOTIFY_H 13 | 14 | #define PKTNOT_PACKET_IN 1 15 | #define PKTNOT_PACKET_OUT 2 16 | 17 | struct packet_args { 18 | struct sock *sk; 19 | struct sk_buff *skb; 20 | }; 21 | 22 | #ifdef __KERNEL__ 23 | extern int packet_notifier_register(struct notifier_block *nb); 24 | extern int packet_notifier_unregister(struct notifier_block *nb); 25 | #endif /* __KERNEL__ */ 26 | 27 | #endif /* _PACKET_NOTIFY_H */ 28 | 29 | -------------------------------------------------------------------------------- /src/pcapng.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Battelle Memorial Institute 3 | * 4 | * Licensed under the GNU General Public License Version 2. 5 | * See LICENSE for the full text of the license. 6 | * See DISCLAIMER for additional disclaimers. 7 | * 8 | * Author: Brandon Carpenter 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "process_notify.h" 21 | #include "hone_notify.h" 22 | #include "pcapng.h" 23 | #include "mmutil.h" 24 | #include "version.h" 25 | 26 | #define PADLEN(x) (((x) & 0x3) ? 4 - ((x) & 3) : 0) 27 | #define OPT_SIZE(x) (((x) & 0x3) ? ((((x) >> 2) + 1) << 2) : x) 28 | #define block_set(BUF, TYPE, VAL) \ 29 | ({ *((TYPE *) (BUF)) = (VAL); sizeof(TYPE); }) 30 | 31 | static unsigned int block_opt_ptr(char *buf, 32 | uint16_t code, const void * ptr, unsigned int length) 33 | { 34 | char *pos = buf; 35 | unsigned int padlen = PADLEN(length); 36 | 37 | pos += block_set(pos, uint16_t, code); 38 | pos += block_set(pos, uint16_t, length); 39 | if (ptr) 40 | memcpy(pos, ptr, length); 41 | pos += length; 42 | memset(pos, 0, padlen); 43 | pos += padlen; 44 | return (unsigned int) (pos - buf); 45 | } 46 | 47 | #define block_opt_t(BUF, CODE, TYPE, VAL) ({ \ 48 | TYPE _value = (VAL); \ 49 | unsigned int _length = block_opt_ptr(BUF, CODE, &_value, sizeof(_value)); \ 50 | _length; }) 51 | #define block_opt(BUF, CODE, VAL) block_opt_t(BUF, CODE, typeof(VAL), VAL) 52 | #define block_end_opt(BUF) block_opt_ptr(BUF, 0, NULL, 0) 53 | 54 | struct timestamp { 55 | uint32_t ts_high; 56 | uint32_t ts_low; 57 | }; 58 | 59 | static void timespec_to_tstamp(struct timestamp *tstamp, struct timespec *ts) 60 | { 61 | uint64_t val = (((uint64_t) ts->tv_sec) * 1000000LL) + ts->tv_nsec / 1000; 62 | tstamp->ts_high = val >> 32; 63 | tstamp->ts_low = val & 0xFFFFFFFF; 64 | } 65 | 66 | /* Section Header Block {{{ 67 | 0 1 2 3 68 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 69 | +---------------------------------------------------------------+ 70 | 0 | Block Type = 0x0A0D0D0A | 71 | +---------------------------------------------------------------+ 72 | 4 | Block Total Length | 73 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 74 | 8 | Byte-Order Magic | 75 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 76 | 12 | Major Version | Minor Version | 77 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 78 | 16 | | 79 | | Section Length | 80 | | | 81 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 82 | 24 / / 83 | / Options (variable) / 84 | / / 85 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 86 | | Block Total Length | 87 | +---------------------------------------------------------------+ 88 | }}} */ 89 | static unsigned int format_sechdr_block(const struct device_info *devinfo, 90 | char *buf, unsigned int buflen) 91 | { 92 | static const char *user_app = "Hone " HONE_VERSION; 93 | char *pos = buf; 94 | unsigned int *length_top, *length_end; 95 | int n; 96 | 97 | // Be sure to update this value if fields are added below. 98 | #define SECHDR_BLOCK_MIN_LEN 56 99 | if (buflen < SECHDR_BLOCK_MIN_LEN) 100 | return 0; 101 | pos += block_set(pos, uint32_t, 0x0A0D0D0A); // block type 102 | length_top = (typeof(length_top)) pos; 103 | pos += block_set(pos, uint32_t, 0); // block length 104 | pos += block_set(pos, uint32_t, 0x1A2B3C4D); // byte-order magic 105 | pos += block_set(pos, uint16_t, 1); // major version 106 | pos += block_set(pos, uint16_t, 0); // minor version 107 | pos += block_set(pos, uint64_t, -1); // section length 108 | if (devinfo->host_id && (n = buflen - (pos - buf) - 16) > 0) { 109 | snprintf(pos + 4, n, "%c%s", 0, devinfo->host_id); 110 | pos += block_opt_ptr(pos, 257, NULL, strlen(pos + 5) + 1); 111 | } else if (devinfo->host_guid_is_set) { 112 | memcpy(pos + 4, "\x01\x00\x00\x00", 4); 113 | memcpy(pos + 8, &devinfo->host_guid, sizeof(devinfo->host_guid)); 114 | pos += block_opt_ptr(pos, 257, NULL, 20); 115 | } 116 | if ((n = buflen - (pos - buf) - 16) > 0) { 117 | struct new_utsname *uname; 118 | down_read(&uts_sem); 119 | uname = utsname(); 120 | snprintf(pos + 4, n, "%s %s %s %s %s", 121 | uname->sysname, uname->nodename, uname->release, 122 | uname->version, uname->machine); 123 | up_read(&uts_sem); 124 | pos[n] = '\0'; 125 | pos += block_opt_ptr(pos, 3, NULL, strlen(pos + 4)); 126 | } 127 | if ((n = buflen - (pos - buf) - 16) > 0) 128 | pos += block_opt_ptr(pos, 4, user_app, min(n, (typeof(n)) strlen(user_app))); 129 | if (devinfo->comment && (n = buflen - (pos - buf) - 16) > 0) { 130 | unsigned int i, j; 131 | for (i = 0, j = 4; devinfo->comment[i] && j < n; i++, j++) { 132 | if (devinfo->comment[i] == '\\' && 133 | (!strncmp(devinfo->comment + i + 1, "040", 3) || 134 | !strncmp(devinfo->comment + i + 1, "x20", 3))) { 135 | pos[j] = ' '; 136 | i += 3; 137 | } else 138 | pos[j] = devinfo->comment[i]; 139 | } 140 | if ((n = j - 4)) 141 | pos += block_opt_ptr(pos, 1, NULL, n); 142 | } 143 | pos += block_end_opt(pos); 144 | length_end = (typeof(length_end)) pos; 145 | pos += block_set(pos, uint32_t, 0); 146 | *length_top = *length_end = (unsigned int) (pos - buf); 147 | return *length_top; 148 | } 149 | 150 | /* Interface Description Block {{{ 151 | 0 1 2 3 152 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 153 | +---------------------------------------------------------------+ 154 | 0 | Block Type = 0x00000001 | 155 | +---------------------------------------------------------------+ 156 | 4 | Block Total Length | 157 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 158 | 8 | LinkType | Reserved | 159 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 160 | 12 | SnapLen | 161 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 162 | 16 / / 163 | / Options (variable) / 164 | / / 165 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 166 | | Block Total Length | 167 | +---------------------------------------------------------------+ 168 | }}} */ 169 | static unsigned int format_ifdesc_block(const struct reader_info *info, 170 | char *buf, int buflen) 171 | { 172 | static const char *if_desc = "Hone Capture Pseudo-device"; 173 | char *pos = buf; 174 | unsigned int *length_top, *length_end; 175 | 176 | // Be sure to update this value if fields are added below. 177 | #define IFDESC_BLOCK_MIN_LEN 56 178 | if (buflen < IFDESC_BLOCK_MIN_LEN) 179 | return 0; 180 | pos += block_set(pos, uint32_t, 0x00000001); // block type 181 | length_top = (typeof(length_top)) pos; 182 | pos += block_set(pos, uint32_t, 0); // block length 183 | pos += block_set(pos, uint16_t, 101); // link type 184 | pos += block_set(pos, uint16_t, 0); // reserved 185 | pos += block_set(pos, uint32_t, info->snaplen); // snaplen 186 | pos += block_opt_ptr(pos, 3, if_desc, strlen(if_desc)); // if_description 187 | pos += block_end_opt(pos); 188 | length_end = (typeof(length_end)) pos; 189 | pos += block_set(pos, uint32_t, 0); 190 | *length_top = *length_end = (unsigned int) (pos - buf); 191 | return *length_top; 192 | } 193 | 194 | /* Interface Statistics Block {{{ 195 | 0 1 2 3 196 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 197 | +---------------------------------------------------------------+ 198 | 0 | Block Type = 0x00000005 | 199 | +---------------------------------------------------------------+ 200 | 4 | Block Total Length | 201 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 202 | 8 | Interface ID | 203 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 204 | 12 | Timestamp (High) | 205 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 206 | 16 | Timestamp (Low) | 207 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 208 | 20 / / 209 | / Options (variable) / 210 | / / 211 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 212 | | Block Total Length | 213 | +---------------------------------------------------------------+ 214 | }}} */ 215 | static unsigned int format_ifstats_block(const struct reader_info *info, 216 | char *buf, int buflen) 217 | { 218 | char *pos = buf; 219 | unsigned int *length_top, *length_end; 220 | struct timespec ts; 221 | struct timestamp tstamp, start_time; 222 | struct statistics received, dropped; 223 | 224 | get_hone_statistics(&received, &dropped, &ts); 225 | set_normalized_timespec(&ts, info->boot_time.tv_sec + ts.tv_sec, 226 | info->boot_time.tv_nsec + ts.tv_nsec); 227 | timespec_to_tstamp(&start_time, &ts); 228 | ktime_get_ts(&ts); 229 | set_normalized_timespec(&ts, info->boot_time.tv_sec + ts.tv_sec, 230 | info->boot_time.tv_nsec + ts.tv_nsec); 231 | timespec_to_tstamp(&tstamp, &ts); 232 | // Be sure to update this value if fields are added below. 233 | #define IFSTATS_BLOCK_MIN_LEN 196 234 | if (buflen < IFSTATS_BLOCK_MIN_LEN) 235 | return 0; 236 | pos += block_set(pos, uint32_t, 0x00000005); // block type 237 | length_top = (typeof(length_top)) pos; 238 | pos += block_set(pos, uint32_t, 0); // block length 239 | pos += block_set(pos, uint32_t, 0); // interface ID 240 | pos += block_set(pos, struct timestamp, tstamp); // timestamp 241 | pos += block_opt_t(pos, 2, struct timestamp, start_time); // start time 242 | pos += block_opt_t(pos, 4, uint64_t, atomic64_read(&received.packet)); 243 | pos += block_opt_t(pos, 5, uint64_t, atomic64_read(&dropped.packet)); 244 | pos += block_opt_t(pos, 6, uint64_t, atomic64_read(&info->filtered)); 245 | pos += block_opt_t(pos, 7, uint64_t, atomic64_read(&info->dropped.packet)); 246 | pos += block_opt_t(pos, 8, uint64_t, atomic64_read(&info->delivered.packet)); 247 | pos += block_opt_t(pos, 257, uint64_t, atomic64_read(&received.process)); 248 | pos += block_opt_t(pos, 258, uint64_t, atomic64_read(&dropped.process)); 249 | pos += block_opt_t(pos, 259, uint64_t, atomic64_read(&info->dropped.process)); 250 | pos += block_opt_t(pos, 260, uint64_t, atomic64_read(&info->delivered.process)); 251 | pos += block_opt_t(pos, 261, uint64_t, atomic64_read(&received.socket)); 252 | pos += block_opt_t(pos, 262, uint64_t, atomic64_read(&dropped.socket)); 253 | pos += block_opt_t(pos, 263, uint64_t, atomic64_read(&info->dropped.socket)); 254 | pos += block_opt_t(pos, 264, uint64_t, atomic64_read(&info->delivered.socket)); 255 | pos += block_end_opt(pos); 256 | length_end = (typeof(length_end)) pos; 257 | pos += block_set(pos, uint32_t, 0); 258 | *length_top = *length_end = (unsigned int) (pos - buf); 259 | return *length_top; 260 | } 261 | 262 | static inline unsigned int maxoptlen(int buflen, unsigned int length) 263 | { 264 | unsigned int alignlen = ((buflen - 16) >> 2) << 2; 265 | if (unlikely(buflen < 0)) 266 | return 0; 267 | return alignlen < length ? alignlen : length; 268 | } 269 | 270 | /* Process Event Block {{{ 271 | 0 1 2 3 272 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 273 | +---------------------------------------------------------------+ 274 | 0 | Block Type = 0x00000101 | 275 | +---------------------------------------------------------------+ 276 | 4 | Block Total Length | 277 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 278 | 8 | Process ID | 279 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 280 | 12 | Timestamp (High) | 281 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 282 | 16 | Timestamp (Low) | 283 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 284 | 20 / / 285 | / Options (variable) / 286 | / / 287 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 288 | | Block Total Length | 289 | +---------------------------------------------------------------+ 290 | }}} */ 291 | static size_t format_process_block(struct process_event *event, 292 | struct timestamp *tstamp, char *buf, size_t buflen) 293 | { 294 | static const uint32_t event_map[] = {0, 1, 0, -1, 2}; 295 | char *pos = buf; 296 | unsigned int *length_top, *length_end; //, length; 297 | 298 | // Be sure to update this value if fields are added below. 299 | #define PROCESS_BLOCK_MIN_LEN 56 300 | if (buflen < PROCESS_BLOCK_MIN_LEN) 301 | return 0; 302 | pos += block_set(pos, uint32_t, 0x00000101); // block type 303 | length_top = (typeof(length_top)) pos; 304 | pos += block_set(pos, uint32_t, 0); // block length 305 | pos += block_set(pos, uint32_t, event->tgid); // PID 306 | pos += block_set(pos, struct timestamp, *tstamp); // timestamp 307 | if (event->event != PROC_EXEC) 308 | pos += block_opt_t(pos, 2, uint32_t, event_map[event->event]); 309 | pos += block_opt_t(pos, 5, uint32_t, event->ppid); 310 | pos += block_opt_t(pos, 6, uint32_t, event->uid); 311 | pos += block_opt_t(pos, 7, uint32_t, event->gid); 312 | if (event->mm) { 313 | char *tmp, *ptr; 314 | unsigned int n, length; 315 | ptr = pos + 4; 316 | length = buflen - (pos - buf) - 16; 317 | if (event->event == PROC_KTHD) { 318 | if ((length = maxoptlen(length, (n = strlen(event->comm)) + 2))) { 319 | ptr[0] = '['; 320 | if (length > 1) 321 | memcpy(ptr + 1, event->comm, length - 1); 322 | if (length > n + 1) 323 | ptr[length - 1] = ']'; 324 | pos += block_opt_ptr(pos, 3, NULL, length); 325 | } 326 | } else { 327 | if (length > 0 && (tmp = mm_path(event->mm, ptr, length))) { 328 | if ((length = maxoptlen(length, strlen(tmp)))) { 329 | memmove(ptr, tmp, length); 330 | pos += block_opt_ptr(pos, 3, NULL, length); 331 | } 332 | } 333 | ptr = pos + 4; 334 | length = buflen - (pos - buf) - 16; 335 | if (length > 0 && (n = mm_argv(event->mm, ptr, length))) 336 | pos += block_opt_ptr(pos, 4, NULL, maxoptlen(length, n)); 337 | } 338 | } 339 | pos += block_end_opt(pos); 340 | length_end = (typeof(length_end)) pos; 341 | pos += block_set(pos, uint32_t, 0); 342 | *length_top = *length_end = (unsigned int) (pos - buf); 343 | return *length_top; 344 | } 345 | 346 | /* Connection Event Block {{{ 347 | 0 1 2 3 348 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 349 | +---------------------------------------------------------------+ 350 | 0 | Block Type = 0x00000102 | 351 | +---------------------------------------------------------------+ 352 | 4 | Block Total Length | 353 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 354 | 8 | Connection ID | 355 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 356 | 12 | Process ID | 357 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 358 | 16 | Timestamp (High) | 359 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 360 | 20 | Timestamp (Low) | 361 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 362 | 24 / / 363 | / Options (variable) / 364 | / / 365 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 366 | | Block Total Length | 367 | +---------------------------------------------------------------+ 368 | }}} */ 369 | static size_t format_connection_block(struct socket_event *event, 370 | struct timestamp *tstamp, char *buf, size_t buflen) 371 | { 372 | char *pos = buf; 373 | unsigned int *length_top, *length_end; 374 | 375 | // Be sure to update this value if fields are added below. 376 | #define CONNECTION_BLOCK_MIN_LEN 40 377 | if (buflen < CONNECTION_BLOCK_MIN_LEN) 378 | return 0; 379 | pos += block_set(pos, uint32_t, 0x00000102); // block type 380 | length_top = (typeof(length_top)) pos; 381 | pos += block_set(pos, uint32_t, 0); // block length 382 | pos += block_set(pos, uint32_t, event->sock & 0xFFFFFFFF); // connection id 383 | pos += block_set(pos, uint32_t, event->tgid); // PID 384 | pos += block_set(pos, struct timestamp, *tstamp); // timestamp 385 | if (event->event) { 386 | pos += block_opt_t(pos, 2, uint32_t, -1); 387 | pos += block_end_opt(pos); 388 | } 389 | length_end = (typeof(length_end)) pos; 390 | pos += block_set(pos, uint32_t, 0); 391 | *length_top = *length_end = (unsigned int) (pos - buf); 392 | return *length_top; 393 | } 394 | 395 | /* Enhanced Packet Block {{{ 396 | 0 1 2 3 397 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 398 | +---------------------------------------------------------------+ 399 | 0 | Block Type = 0x00000006 | 400 | +---------------------------------------------------------------+ 401 | 4 | Block Total Length | 402 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 403 | 8 | Interface ID | 404 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 405 | 12 | Timestamp (High) | 406 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 407 | 16 | Timestamp (Low) | 408 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 409 | 20 | Captured Len | 410 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 411 | 24 | Packet Len | 412 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 413 | 28 / / 414 | / Packet Data / 415 | / ( variable length, aligned to 32 bits ) / 416 | / / 417 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 418 | / / 419 | / Options (variable) / 420 | / / 421 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 422 | | Block Total Length | 423 | +---------------------------------------------------------------+ 424 | }}} */ 425 | static size_t format_packet_block(struct packet_event *event, 426 | unsigned int snaplen, struct timestamp *tstamp, char *buf, size_t buflen) 427 | { 428 | char *pos = buf; 429 | int offset; 430 | unsigned int *length_top, *length_end, *length_cap; 431 | struct sk_buff *skb = event->skb; 432 | 433 | // Be sure to update this value if fields are added below. 434 | #define PACKET_BLOCK_MIN_LEN 52 435 | if (buflen < PACKET_BLOCK_MIN_LEN) 436 | return 0; 437 | pos += block_set(pos, uint32_t, 0x00000006); // block type 438 | length_top = (typeof(length_top)) pos; 439 | pos += block_set(pos, uint32_t, 0); // block length 440 | pos += block_set(pos, uint32_t, 0); // interface ID 441 | pos += block_set(pos, struct timestamp, *tstamp); // timestamp 442 | length_cap = (typeof(length_cap)) pos; 443 | pos += block_set(pos, uint32_t, 0); // captured length 444 | pos += block_set(pos, uint32_t, skb->len); // packet length 445 | 446 | // packet data 447 | offset = skb_network_header(skb) - skb->data; // offset should be <= 0 448 | if ((*length_cap = maxoptlen(buflen - (pos - buf), 449 | (snaplen ? min(skb->len - offset, snaplen) : skb->len - offset)))) { 450 | unsigned int n = *length_cap & 3 ? 4 - (*length_cap & 3) : 0; 451 | if (skb_copy_bits(skb, offset, pos, *length_cap)) 452 | BUG(); 453 | pos += *length_cap; 454 | memset(pos, 0, n); 455 | pos += n; 456 | } 457 | 458 | // socket id 459 | if (event->sock) // Only add the option if we found a socket 460 | pos += block_opt_t(pos, 257, uint32_t, event->sock & 0xFFFFFFFF); 461 | // process id 462 | if (event->pid) 463 | pos += block_opt_t(pos, 258, uint32_t, event->pid); 464 | pos += block_opt_t(pos, 2, uint32_t, event->dir ? 1 : 2); 465 | pos += block_end_opt(pos); 466 | length_end = (typeof(length_end)) pos; 467 | pos += block_set(pos, uint32_t, 0); 468 | *length_top = *length_end = (unsigned int) (pos - buf); 469 | return *length_top; 470 | } 471 | 472 | static void normalize_ts(struct timestamp *tstamp, 473 | const struct timespec *boot_time, const struct timespec *event_time) 474 | { 475 | struct timespec ts; 476 | 477 | // The following is used instead of timespec_add() 478 | // because it doesn't exist in older kernel versions. 479 | set_normalized_timespec(&ts, boot_time->tv_sec + event_time->tv_sec, 480 | boot_time->tv_nsec + event_time->tv_nsec); 481 | timespec_to_tstamp(tstamp, &ts); 482 | } 483 | 484 | unsigned int format_as_pcapng( 485 | const struct device_info *devinfo, const struct reader_info *info, 486 | struct hone_event *event, char *buf, unsigned int buflen) 487 | { 488 | unsigned int n = 0; 489 | struct timestamp tstamp; 490 | 491 | switch (event->type) { 492 | case HONE_PACKET: 493 | normalize_ts(&tstamp, &info->boot_time, &event->ts); 494 | n = format_packet_block( 495 | &event->packet, info->snaplen, &tstamp, buf, buflen); 496 | break; 497 | case HONE_PROCESS: 498 | normalize_ts(&tstamp, &info->boot_time, &event->ts); 499 | n = format_process_block(&event->process, &tstamp, buf, buflen); 500 | break; 501 | case HONE_SOCKET: 502 | normalize_ts(&tstamp, &info->boot_time, &event->ts); 503 | n = format_connection_block(&event->socket, &tstamp, buf, buflen); 504 | break; 505 | case HONE_USER_HEAD: 506 | n = format_sechdr_block(devinfo, buf, buflen); 507 | n += format_ifdesc_block(info, buf + n, buflen - n); 508 | break; 509 | case HONE_USER_TAIL: 510 | n = format_ifstats_block(info, buf + n, buflen - n); 511 | break; 512 | } 513 | 514 | return n; 515 | } 516 | 517 | int parse_guid(struct guid_struct *guid, const char *input) 518 | { 519 | int i, val; 520 | const char *pos = input; 521 | char *buf = (typeof(buf)) guid; 522 | 523 | if (*pos == '{') 524 | pos++; 525 | for (i = 0; *pos && i < 32; pos++) { 526 | if (*pos == '-') { 527 | if (pos == input) 528 | return -1; 529 | continue; 530 | } 531 | if (*pos >= '0' && *pos <= '9') 532 | val = *pos - '0'; 533 | else if (*pos >= 'a' && *pos <= 'f') 534 | val = *pos - 'W'; 535 | else if (*pos >= 'A' && *pos <= 'F') 536 | val = *pos - '7'; 537 | else 538 | return -1; 539 | if (i % 2) { 540 | buf[i / 2] += val; 541 | i++; 542 | } else { 543 | buf[i / 2] = val << 4; 544 | i++; 545 | } 546 | } 547 | if (i < 32) 548 | return -1; 549 | if (*input == '{') { 550 | if (*pos != '}') 551 | return -1; 552 | pos++; 553 | } 554 | if (*pos) 555 | return -1; 556 | guid->data1 = ntohl(guid->data1); 557 | guid->data2 = ntohs(guid->data2); 558 | guid->data3 = ntohs(guid->data3); 559 | return 0; 560 | } 561 | 562 | -------------------------------------------------------------------------------- /src/pcapng.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Battelle Memorial Institute 3 | * 4 | * Licensed under the GNU General Public License Version 2. 5 | * See LICENSE for the full text of the license. 6 | * See DISCLAIMER for additional disclaimers. 7 | * 8 | * Author: Brandon Carpenter 9 | */ 10 | 11 | #ifndef _PCAPNG_H 12 | #define _PCAPNG_H 13 | 14 | #include 15 | #include 16 | 17 | #define HONE_USER_HEAD (HONE_USER | 1) 18 | #define HONE_USER_TAIL (HONE_USER | 2) 19 | 20 | #define GUID_FMT "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" 21 | #define GUID_TUPLE(G) (G)->data1, (G)->data2, (G)->data3, \ 22 | (G)->data4[0], (G)->data4[1], (G)->data4[2], (G)->data4[3], \ 23 | (G)->data4[4], (G)->data4[5], (G)->data4[6], (G)->data4[7] 24 | 25 | struct guid_struct { 26 | uint32_t data1; 27 | uint16_t data2; 28 | uint16_t data3; 29 | uint8_t data4[8]; 30 | }; 31 | 32 | struct device_info { 33 | struct guid_struct host_guid; 34 | bool host_guid_is_set; 35 | const char *host_id; 36 | const char *comment; 37 | }; 38 | 39 | struct reader_info { 40 | unsigned int snaplen; 41 | struct timespec boot_time; 42 | struct timespec start_time; 43 | struct statistics delivered; 44 | struct statistics dropped; 45 | atomic64_t filtered; 46 | }; 47 | 48 | unsigned int format_as_pcapng( 49 | const struct device_info *devinfo, const struct reader_info *info, 50 | struct hone_event *event, char *buf, unsigned int buflen); 51 | int parse_guid(struct guid_struct *guid, const char *input); 52 | 53 | #endif /* _PCAPNG_H */ 54 | 55 | -------------------------------------------------------------------------------- /src/process_notify.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Battelle Memorial Institute 3 | * 4 | * Licensed under the GNU General Public License Version 2. 5 | * See LICENSE for the full text of the license. 6 | * See DISCLAIMER for additional disclaimers. 7 | * 8 | * Author: Brandon Carpenter 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #if !defined(CONFIG_KPROBES) || !defined(CONFIG_KRETPROBES) || !defined(CONFIG_KALLSYMS) 18 | #error process_notify module requires kprobes support (CONFIG_KPROBES, CONFIG_KRETPROBES and CONFIG_KALLSYMS) 19 | #endif 20 | 21 | #include "process_notify.h" 22 | #include "version.h" 23 | 24 | static RAW_NOTIFIER_HEAD(notifier_list); 25 | static DEFINE_RWLOCK(notifier_lock); 26 | 27 | int process_notifier_register(struct notifier_block *nb) 28 | { 29 | int result; 30 | unsigned long flags; 31 | 32 | write_lock_irqsave(¬ifier_lock, flags); 33 | result = raw_notifier_chain_register(¬ifier_list, nb); 34 | write_unlock_irqrestore(¬ifier_lock, flags); 35 | return result; 36 | } 37 | 38 | int process_notifier_unregister(struct notifier_block *nb) 39 | { 40 | int result; 41 | unsigned long flags; 42 | 43 | write_lock_irqsave(¬ifier_lock, flags); 44 | result = raw_notifier_chain_unregister(¬ifier_list, nb); 45 | write_unlock_irqrestore(¬ifier_lock, flags); 46 | return result; 47 | } 48 | 49 | static inline int process_notifier_notify( 50 | unsigned long event, struct task_struct *task) 51 | { 52 | int result; 53 | unsigned long flags; 54 | 55 | read_lock_irqsave(¬ifier_lock, flags); 56 | result = raw_notifier_call_chain(¬ifier_list, event, task); 57 | read_unlock_irqrestore(¬ifier_lock, flags); 58 | return result; 59 | } 60 | 61 | static int fork_handler(struct kretprobe_instance *ri, struct pt_regs *regs) 62 | { 63 | struct task_struct *task = (struct task_struct *) regs_return_value(regs); 64 | 65 | if (!IS_ERR(task)) 66 | process_notifier_notify(PROC_FORK, task); 67 | return 0; 68 | } 69 | 70 | static int exec_handler(struct kretprobe_instance *ri, struct pt_regs *regs) 71 | { 72 | if (!(int) regs_return_value(regs)) 73 | process_notifier_notify(PROC_EXEC, current); 74 | return 0; 75 | } 76 | 77 | static int exit_handler(struct kprobe *kp, struct pt_regs *regs) 78 | { 79 | process_notifier_notify(PROC_EXIT, current); 80 | return 0; 81 | } 82 | 83 | extern void copy_process(void); 84 | static struct kretprobe fork_kretprobe = { 85 | //.kp.symbol_name = "copy_process", 86 | .kp.addr = (kprobe_opcode_t *) copy_process, 87 | .handler = fork_handler, 88 | }; 89 | 90 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,19,0) 91 | 92 | extern int do_execveat_common(void); 93 | static struct kretprobe exec_kretprobe = { 94 | //.kp.symbol_name = "do_execve", 95 | .kp.addr = (kprobe_opcode_t *) do_execveat_common, 96 | .handler = exec_handler, 97 | }; 98 | 99 | #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) 100 | 101 | extern int do_execve_common(void); 102 | static struct kretprobe exec_kretprobe = { 103 | //.kp.symbol_name = "do_execve", 104 | .kp.addr = (kprobe_opcode_t *) do_execve_common, 105 | .handler = exec_handler, 106 | }; 107 | 108 | #else 109 | 110 | static struct kretprobe exec_kretprobe = { 111 | //.kp.symbol_name = "do_execve", 112 | .kp.addr = (kprobe_opcode_t *) do_execve, 113 | .handler = exec_handler, 114 | }; 115 | 116 | #ifdef CONFIG_COMPAT 117 | #define PROBE_COMPAT_DO_EXECVE 118 | extern void compat_do_execve(void); 119 | static struct kretprobe compat_exec_kretprobe = { 120 | //.kp.symbol_name = "compat_do_execve", 121 | .kp.addr = (kprobe_opcode_t *) compat_do_execve, 122 | .handler = exec_handler, 123 | }; 124 | #endif 125 | 126 | #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,19,0) */ 127 | 128 | static struct kprobe exit_kprobe = { 129 | //.symbol_name = "do_exit", 130 | .addr = (kprobe_opcode_t *) do_exit, 131 | .pre_handler = exit_handler, 132 | }; 133 | 134 | #ifdef CONFIG_PROCESS_NOTIFY_COMBINED 135 | # define _STATIC 136 | #else 137 | # define _STATIC static 138 | #endif 139 | 140 | _STATIC int __init process_notify_init(void) 141 | { 142 | int err; 143 | 144 | if ((err = register_kprobe(&exit_kprobe))) { 145 | printk(KERN_ERR "%s: exit register_kprobe() failed with error %d\n", 146 | THIS_MODULE->name, err); 147 | goto exit_failed; 148 | } 149 | if ((err = register_kretprobe(&fork_kretprobe))) { 150 | printk(KERN_ERR "%s: fork register_kretprobe() failed with error %d\n", 151 | THIS_MODULE->name, err); 152 | goto fork_failed; 153 | } 154 | if ((err = register_kretprobe(&exec_kretprobe))) { 155 | printk(KERN_ERR "%s: exec register_kretprobe() failed with error %d\n", 156 | THIS_MODULE->name, err); 157 | goto exec_failed; 158 | } 159 | #ifdef PROBE_COMPAT_DO_EXECVE 160 | if ((err = register_kretprobe(&compat_exec_kretprobe))) { 161 | printk(KERN_ERR "%s: compat_exec register_kretprobe() failed with error %d\n", 162 | THIS_MODULE->name, err); 163 | if (err != -EINVAL) 164 | goto compat_exec_failed; 165 | } 166 | #endif 167 | return 0; 168 | 169 | #ifdef PROBE_COMPAT_DO_EXECVE 170 | compat_exec_failed: 171 | unregister_kretprobe(&exec_kretprobe); 172 | #endif 173 | exec_failed: 174 | unregister_kretprobe(&fork_kretprobe); 175 | fork_failed: 176 | unregister_kprobe(&exit_kprobe); 177 | exit_failed: 178 | return err; 179 | } 180 | 181 | _STATIC void process_notify_remove(void) 182 | { 183 | #ifdef PROBE_COMPAT_DO_EXECVE 184 | unregister_kretprobe(&compat_exec_kretprobe); 185 | #endif 186 | unregister_kretprobe(&exec_kretprobe); 187 | unregister_kretprobe(&fork_kretprobe); 188 | unregister_kprobe(&exit_kprobe); 189 | } 190 | 191 | #ifndef CONFIG_PROCESS_NOTIFY_COMBINED 192 | 193 | static char version[] __initdata = HONE_VERSION; 194 | 195 | static int __init process_notify_module_init(void) 196 | { 197 | if (process_notify_init()) 198 | return -1; 199 | printk("%s: v%s module successfully loaded\n", THIS_MODULE->name, version); 200 | return 0; 201 | } 202 | 203 | static void __exit process_notify_module_exit(void) 204 | { 205 | process_notify_remove(); 206 | printk("%s: module successfully unloaded\n", THIS_MODULE->name); 207 | } 208 | 209 | module_init(process_notify_module_init); 210 | module_exit(process_notify_module_exit); 211 | 212 | MODULE_DESCRIPTION("Process event notification module."); 213 | MODULE_AUTHOR("Brandon Carpenter"); 214 | MODULE_LICENSE("GPL v2"); 215 | MODULE_VERSION(HONE_VERSION); 216 | 217 | EXPORT_SYMBOL(process_notifier_register); 218 | EXPORT_SYMBOL(process_notifier_unregister); 219 | 220 | #endif // CONFIG_PROCESS_NOTIFY_COMBINED 221 | 222 | -------------------------------------------------------------------------------- /src/process_notify.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Battelle Memorial Institute 3 | * 4 | * Licensed under the GNU General Public License Version 2. 5 | * See LICENSE for the full text of the license. 6 | * See DISCLAIMER for additional disclaimers. 7 | * 8 | * Author: Brandon Carpenter 9 | */ 10 | 11 | #ifndef _PROCESS_NOTIFY_H 12 | #define _PROCESS_NOTIFY_H 13 | 14 | #define PROC_FORK 1 15 | #define PROC_EXEC 2 16 | #define PROC_EXIT 3 17 | #define PROC_KTHD 4 18 | 19 | #ifdef __KERNEL__ 20 | extern int process_notifier_register(struct notifier_block *nb); 21 | extern int process_notifier_unregister(struct notifier_block *nb); 22 | #endif /* __KERNEL__ */ 23 | 24 | #endif /* _PROCESS_NOTIFY_H */ 25 | 26 | -------------------------------------------------------------------------------- /src/rhel6.patch: -------------------------------------------------------------------------------- 1 | --- a/src/defsyms.mk 2 | +++ b/src/defsyms.mk 3 | @@ -62,6 +62,7 @@ KBUILD_EXTRA_SYMBOLS += $(obj)/defsyms.symvers 4 | LDFLAGS_MODULE += $(DEFSYMS_LDFLAGS_$(notdir $@)) 5 | 6 | $(foreach N,$(defsyms-names),$(eval DEFSYMS_LDFLAGS_$(N).ko = -T $(obj)/$(N).defsyms)) 7 | +$(foreach N,$(defsyms-names),$(eval DEFSYMS_LDFLAGS_$(N).ko.unsigned = -T $(obj)/$(N).defsyms)) 8 | 9 | $(defsyms-lds): $(obj)/%.defsyms: $(obj)/.System.map.md5 10 | $(call cmd,defsyms) 11 | --- a/src/socket_lookup.h 12 | +++ b/src/socket_lookup.h 13 | @@ -368,7 +368,7 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, 14 | return nexthdr; 15 | } 16 | 17 | -# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) 18 | +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) 19 | extern struct sock *__udp6_lib_lookup(struct net *net, 20 | struct in6_addr *saddr, __be16 sport, 21 | struct in6_addr *daddr, __be16 dport, 22 | --- a/src/socket_notify.c 23 | +++ b/src/socket_notify.c 24 | @@ -31,7 +31,7 @@ 25 | #warning Hone will not provide IPv6 packet/process correlation. 26 | #endif 27 | 28 | -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) 29 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) 30 | #define DECLARE_CREATE_HOOK(NAME) int NAME(struct net *net, struct socket *sock, int protocol, int kern) 31 | #define CALL_CREATE_HOOK(NAME) NAME(net, sock, protocol, kern) 32 | #else 33 | -------------------------------------------------------------------------------- /src/ringbuf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Battelle Memorial Institute 3 | * 4 | * Licensed under the GNU General Public License Version 2. 5 | * See LICENSE for the full text of the license. 6 | * See DISCLAIMER for additional disclaimers. 7 | * 8 | * Author: Brandon Carpenter 9 | * 10 | * Implementation of lock-free ring buffer. 11 | */ 12 | 13 | #include 14 | 15 | #include "ringbuf.h" 16 | 17 | int ring_append(struct ring_buf *ring, void *elem) 18 | { 19 | unsigned int back; 20 | 21 | for (;;) { 22 | back = ring_back(ring); 23 | if (back - ring_front(ring) >= ring->length) 24 | return -1; 25 | if ((unsigned int) atomic_cmpxchg(&ring->back, back, back + 1) == back) 26 | break; 27 | } 28 | ring->data[back % ring->length] = elem; 29 | return 0; 30 | } 31 | 32 | void *ring_pop(struct ring_buf *ring) 33 | { 34 | void *elem, **slot; 35 | unsigned int front; 36 | 37 | for (;;) { 38 | front = ring_front(ring); 39 | if (front == ring_back(ring)) 40 | return NULL; 41 | slot = ring->data + (front % ring->length); 42 | if (!(elem = *slot)) 43 | continue; 44 | if (cmpxchg(slot, elem, NULL) == elem) 45 | break; 46 | } 47 | atomic_inc(&ring->front); 48 | return elem; 49 | } 50 | -------------------------------------------------------------------------------- /src/ringbuf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Battelle Memorial Institute 3 | * 4 | * Licensed under the GNU General Public License Version 2. 5 | * See LICENSE for the full text of the license. 6 | * See DISCLAIMER for additional disclaimers. 7 | * 8 | * Author: Brandon Carpenter 9 | * 10 | * Implementation of lock-free ring buffer. 11 | */ 12 | 13 | #ifndef _RINGBUF_H 14 | #define _RINGBUF_H 15 | 16 | #include 17 | 18 | struct ring_buf { 19 | atomic_t front; 20 | atomic_t back; 21 | unsigned int length; 22 | unsigned int pageorder; 23 | void **data; 24 | }; 25 | 26 | #define ring_front(ring) ((unsigned int) atomic_read(&(ring)->front)) 27 | #define ring_back(ring) ((unsigned int) atomic_read(&(ring)->back)) 28 | #define ring_used(ring) (ring_back(ring) - ring_front(ring)) 29 | #define ring_is_empty(ring) (ring_front(ring) == ring_back(ring)) 30 | 31 | int ring_append(struct ring_buf *ring, void *elem); 32 | void *ring_pop(struct ring_buf *ring); 33 | 34 | #endif /* _RINGBUF_H */ 35 | 36 | -------------------------------------------------------------------------------- /src/socket_lookup.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Modifications copyright (C) 2011 Battelle Memorial Institute 3 | * 4 | * Licensed under the GNU General Public License Version 2. 5 | * See LICENSE for the full text of the license. 6 | * See DISCLAIMER for additional disclaimers. 7 | * 8 | * Author: Brandon Carpenter 9 | */ 10 | 11 | /* 12 | * The following code was conveniently borrowed form the xt_socket 13 | * iptables module and used with minor modifications. Thanks guys! 14 | * 15 | * Transparent proxy support for Linux/iptables 16 | * 17 | * Copyright (C) 2007-2008 BalaBit IT Ltd. 18 | * Author: Krisztian Kovacs 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 30 | #include 31 | #include 32 | #endif 33 | 34 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) 35 | #define XT_SOCKET_HAVE_CONNTRACK 1 36 | #include 37 | #endif 38 | 39 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33) 40 | #define inet_rcv_saddr rcv_saddr 41 | #endif 42 | 43 | static void put_sock(struct sock *sk) 44 | { 45 | if (sk->sk_state == TCP_TIME_WAIT) 46 | inet_twsk_put(inet_twsk(sk)); 47 | else 48 | sock_put(sk); 49 | } 50 | 51 | static int extract_icmp4_fields(const struct sk_buff *skb, u8 *protocol, 52 | __be32 *raddr, __be32 *laddr, __be16 *rport, __be16 *lport) 53 | { 54 | unsigned int outside_hdrlen = ip_hdrlen(skb); 55 | struct iphdr *inside_iph, _inside_iph; 56 | struct icmphdr *icmph, _icmph; 57 | __be16 *ports, _ports[2]; 58 | 59 | icmph = skb_header_pointer(skb, outside_hdrlen, 60 | sizeof(_icmph), &_icmph); 61 | if (icmph == NULL) 62 | return 1; 63 | 64 | switch (icmph->type) { 65 | case ICMP_DEST_UNREACH: 66 | case ICMP_SOURCE_QUENCH: 67 | case ICMP_REDIRECT: 68 | case ICMP_TIME_EXCEEDED: 69 | case ICMP_PARAMETERPROB: 70 | break; 71 | default: 72 | return 1; 73 | } 74 | 75 | inside_iph = skb_header_pointer(skb, outside_hdrlen + 76 | sizeof(struct icmphdr), 77 | sizeof(_inside_iph), &_inside_iph); 78 | if (inside_iph == NULL) 79 | return 1; 80 | 81 | if (inside_iph->protocol != IPPROTO_TCP && 82 | inside_iph->protocol != IPPROTO_UDP) 83 | return 1; 84 | 85 | ports = skb_header_pointer(skb, outside_hdrlen + 86 | sizeof(struct icmphdr) + 87 | (inside_iph->ihl << 2), 88 | sizeof(_ports), &_ports); 89 | if (ports == NULL) 90 | return 1; 91 | 92 | /* the inside IP packet is the one quoted from our side, thus 93 | * its saddr is the local address */ 94 | *protocol = inside_iph->protocol; 95 | *laddr = inside_iph->saddr; 96 | *lport = ports[0]; 97 | *raddr = inside_iph->daddr; 98 | *rport = ports[1]; 99 | 100 | return 0; 101 | } 102 | 103 | static struct sock *lookup_v4_sock(const struct sk_buff *skb, 104 | const struct net_device *indev) 105 | { 106 | struct iphdr *iph = ip_hdr(skb); 107 | struct sock *sk; 108 | __be32 daddr = 0, saddr = 0; 109 | __be16 dport = 0, sport = 0; 110 | u8 protocol = 0; 111 | 112 | if (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_TCP) { 113 | struct udphdr _hdr, *hp; 114 | 115 | if (!(hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr))) 116 | return NULL; 117 | 118 | protocol = iph->protocol; 119 | saddr = iph->saddr; 120 | sport = hp->source; 121 | daddr = iph->daddr; 122 | dport = hp->dest; 123 | 124 | } else if (iph->protocol == IPPROTO_ICMP) { 125 | if (extract_icmp4_fields(skb, &protocol, &saddr, &daddr, 126 | &sport, &dport)) 127 | return NULL; 128 | } else { 129 | return NULL; 130 | } 131 | 132 | #ifdef XT_SOCKET_HAVE_CONNTRACK 133 | /* Do the lookup with the original socket address in case this is a 134 | * reply packet of an established SNAT-ted connection. */ 135 | { 136 | enum ip_conntrack_info ctinfo; 137 | struct nf_conn const *ct = nf_ct_get(skb, &ctinfo); 138 | 139 | if (ct && 140 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) 141 | !nf_ct_is_untracked(ct) && 142 | #else 143 | (ct != &nf_conntrack_untracked) && 144 | #endif 145 | ((iph->protocol != IPPROTO_ICMP && 146 | ctinfo == IP_CT_IS_REPLY + IP_CT_ESTABLISHED) || 147 | (iph->protocol == IPPROTO_ICMP && 148 | ctinfo == IP_CT_IS_REPLY + IP_CT_RELATED)) && 149 | (ct->status & IPS_SRC_NAT_DONE)) { 150 | 151 | daddr = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; 152 | dport = (iph->protocol == IPPROTO_TCP) ? 153 | ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.tcp.port : 154 | ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port; 155 | } 156 | } 157 | #endif 158 | 159 | if (protocol == IPPROTO_TCP) 160 | sk = __inet_lookup(dev_net(skb->dev), &tcp_hashinfo, 161 | saddr, sport, daddr, dport, indev->ifindex); 162 | else 163 | sk = udp4_lib_lookup(dev_net(skb->dev), 164 | saddr, sport, daddr, dport, indev->ifindex); 165 | if (!sk) 166 | return NULL; 167 | 168 | /* Ignore sockets listening on INADDR_ANY */ 169 | if (sk->sk_state != TCP_TIME_WAIT && inet_sk(sk)->inet_rcv_saddr == 0) { 170 | put_sock(sk); 171 | return NULL; 172 | } 173 | return sk; 174 | } 175 | 176 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 177 | # if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,2) 178 | # define SKIPHDR(...) ({__be16 __offp; ipv6_skip_exthdr(__VA_ARGS__, &__offp);}) 179 | # else 180 | # define SKIPHDR ipv6_skip_exthdr 181 | # endif 182 | 183 | static int extract_icmp6_fields(const struct sk_buff *skb, 184 | unsigned int outside_hdrlen, int *protocol, struct in6_addr **raddr, 185 | struct in6_addr **laddr, __be16 *rport, __be16 *lport) 186 | { 187 | struct ipv6hdr *inside_iph, _inside_iph; 188 | struct icmp6hdr *icmph, _icmph; 189 | __be16 *ports, _ports[2]; 190 | u8 inside_nexthdr; 191 | int inside_hdrlen; 192 | 193 | if (!(icmph = skb_header_pointer(skb, outside_hdrlen, 194 | sizeof(_icmph), &_icmph))) 195 | return 1; 196 | if (icmph->icmp6_type & ICMPV6_INFOMSG_MASK) 197 | return 1; 198 | if (!(inside_iph = skb_header_pointer(skb, 199 | outside_hdrlen + sizeof(_icmph), sizeof(_inside_iph), &_inside_iph))) 200 | return 1; 201 | 202 | inside_nexthdr = inside_iph->nexthdr; 203 | if ((inside_hdrlen = SKIPHDR(skb, outside_hdrlen + 204 | sizeof(_icmph) + sizeof(_inside_iph), &inside_nexthdr)) < 0) 205 | return 1; /* hjm: Packet has no/incomplete transport layer headers. */ 206 | if (inside_nexthdr != IPPROTO_TCP && inside_nexthdr != IPPROTO_UDP) 207 | return 1; 208 | 209 | if (!(ports = skb_header_pointer(skb, inside_hdrlen, 210 | sizeof(_ports), &_ports))) 211 | return 1; 212 | 213 | /* the inside IP packet is the one quoted from our side, thus 214 | * its saddr is the local address */ 215 | *protocol = inside_nexthdr; 216 | *laddr = &inside_iph->saddr; 217 | *lport = ports[0]; 218 | *raddr = &inside_iph->daddr; 219 | *rport = ports[1]; 220 | 221 | return 0; 222 | } 223 | 224 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0) 225 | int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, 226 | int target, unsigned short *fragoff, int *fragflg) 227 | { 228 | unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr); 229 | u8 nexthdr = ipv6_hdr(skb)->nexthdr; 230 | unsigned int len = skb->len - start; 231 | 232 | if (fragoff) 233 | *fragoff = 0; 234 | 235 | while (nexthdr != target) { 236 | struct ipv6_opt_hdr _hdr, *hp; 237 | unsigned int hdrlen; 238 | 239 | if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) { 240 | if (target < 0) 241 | break; 242 | return -ENOENT; 243 | } 244 | 245 | if (!(hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr))) 246 | return -EBADMSG; 247 | if (nexthdr == NEXTHDR_FRAGMENT) { 248 | unsigned short _frag_off; 249 | __be16 *fp = skb_header_pointer(skb, start + offsetof( 250 | struct frag_hdr, frag_off), sizeof(_frag_off), &_frag_off); 251 | 252 | if (!fp) 253 | return -EBADMSG; 254 | 255 | _frag_off = ntohs(*fp) & ~0x7; 256 | if (_frag_off) { 257 | if (target < 0 && 258 | ((!ipv6_ext_hdr(hp->nexthdr)) || 259 | hp->nexthdr == NEXTHDR_NONE)) { 260 | if (fragoff) 261 | *fragoff = _frag_off; 262 | return hp->nexthdr; 263 | } 264 | return -ENOENT; 265 | } 266 | hdrlen = 8; 267 | } else if (nexthdr == NEXTHDR_AUTH) 268 | hdrlen = (hp->hdrlen + 2) << 2; 269 | else 270 | hdrlen = ipv6_optlen(hp); 271 | 272 | nexthdr = hp->nexthdr; 273 | len -= hdrlen; 274 | start += hdrlen; 275 | } 276 | 277 | *offset = start; 278 | return nexthdr; 279 | } 280 | #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0) */ 281 | 282 | # if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) 283 | extern struct sock *__udp6_lib_lookup(struct net *net, 284 | struct in6_addr *saddr, __be16 sport, 285 | struct in6_addr *daddr, __be16 dport, 286 | int dif, struct udp_table *udptable); 287 | 288 | #define udp6_lib_lookup(net, saddr, sport, daddr, dport, dif) \ 289 | __udp6_lib_lookup((net), (struct in6_addr *) (saddr), (sport), \ 290 | (struct in6_addr *) (daddr), (dport), (dif), &udp_table) 291 | # endif 292 | 293 | static struct sock *lookup_v6_sock(const struct sk_buff *skb, 294 | const struct net_device *indev) 295 | { 296 | struct sock *sk; 297 | struct in6_addr *daddr, *saddr; 298 | __be16 dport, sport; 299 | int thoff = 0, tproto; 300 | 301 | if ((tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL)) < 0) 302 | return NULL; // unable to find transport header in IPv6 packet 303 | 304 | if (tproto == IPPROTO_UDP || tproto == IPPROTO_TCP) { 305 | struct udphdr _hdr, *hp; 306 | struct ipv6hdr *iph; 307 | 308 | if (!(hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr))) 309 | return NULL; 310 | 311 | iph = ipv6_hdr(skb); 312 | saddr = &iph->saddr; 313 | sport = hp->source; 314 | daddr = &iph->daddr; 315 | dport = hp->dest; 316 | } else if (tproto == IPPROTO_ICMPV6) { 317 | if (extract_icmp6_fields(skb, thoff, &tproto, 318 | &saddr, &daddr, &sport, &dport)) 319 | return NULL; 320 | } else { 321 | return NULL; 322 | } 323 | 324 | if (tproto == IPPROTO_TCP) 325 | sk = inet6_lookup(dev_net(skb->dev), &tcp_hashinfo, 326 | saddr, sport, daddr, dport, indev->ifindex); 327 | else 328 | sk = udp6_lib_lookup(dev_net(skb->dev), 329 | saddr, sport, daddr, dport, indev->ifindex); 330 | 331 | /* Ignore sockets listening on INADDR_ANY */ 332 | if (sk && sk->sk_state != TCP_TIME_WAIT && !inet_sk(sk)->inet_rcv_saddr) { 333 | put_sock(sk); 334 | return NULL; 335 | } 336 | return sk; 337 | } 338 | #endif 339 | -------------------------------------------------------------------------------- /src/socket_notify.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Battelle Memorial Institute 3 | * 4 | * Licensed under the GNU General Public License Version 2. 5 | * See LICENSE for the full text of the license. 6 | * See DISCLAIMER for additional disclaimers. 7 | * 8 | * Author: Brandon Carpenter 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "socket_notify.h" 22 | #include "version.h" 23 | 24 | #if !defined(CONFIG_IPV6) && defined(CONFIG_IPV6_MODULE) 25 | #warning Hone does not support IPv6 when it is built as a module. 26 | #warning Hone will not provide IPv6 packet/process correlation. 27 | #endif 28 | 29 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) 30 | #define DECLARE_CREATE_HOOK(NAME) int NAME(struct net *net, struct socket *sock, int protocol, int kern) 31 | #define CALL_CREATE_HOOK(NAME) NAME(net, sock, protocol, kern) 32 | #else 33 | #define DECLARE_CREATE_HOOK(NAME) int NAME(struct net *net, struct socket *sock, int protocol) 34 | #define CALL_CREATE_HOOK(NAME) NAME(net, sock, protocol) 35 | #endif 36 | 37 | static RAW_NOTIFIER_HEAD(notifier_list); 38 | static DEFINE_RWLOCK(notifier_lock); 39 | 40 | #ifndef rcu_dereference_raw 41 | #define notifier_call_chain_empty() (rcu_dereference(notifier_list.head) == NULL) 42 | #else 43 | #define notifier_call_chain_empty() (rcu_dereference_raw(notifier_list.head) == NULL) 44 | #endif 45 | 46 | static DECLARE_CREATE_HOOK(inet_create_hook); 47 | extern const struct net_proto_family inet_family_ops; 48 | static const struct net_proto_family hooked_inet_family_ops = { 49 | .family = PF_INET, 50 | .create = inet_create_hook, 51 | .owner = THIS_MODULE, 52 | }; 53 | 54 | #if defined(CONFIG_IPV6) 55 | static DECLARE_CREATE_HOOK(inet6_create_hook); 56 | extern const struct net_proto_family inet6_family_ops; 57 | static const struct net_proto_family hooked_inet6_family_ops = { 58 | .family = PF_INET6, 59 | .create = inet6_create_hook, 60 | .owner = THIS_MODULE, 61 | }; 62 | #endif 63 | 64 | int sock_notifier_register(struct notifier_block *nb) 65 | { 66 | int result; 67 | unsigned long flags; 68 | 69 | write_lock_irqsave(¬ifier_lock, flags); 70 | result = raw_notifier_chain_register(¬ifier_list, nb); 71 | write_unlock_irqrestore(¬ifier_lock, flags); 72 | return result; 73 | } 74 | 75 | int sock_notifier_unregister(struct notifier_block *nb) 76 | { 77 | int result; 78 | unsigned long flags; 79 | 80 | write_lock_irqsave(¬ifier_lock, flags); 81 | result = raw_notifier_chain_unregister(¬ifier_list, nb); 82 | write_unlock_irqrestore(¬ifier_lock, flags); 83 | return result; 84 | } 85 | 86 | static inline int sock_notifier_notify(unsigned long event, struct sock *sk) 87 | { 88 | int result; 89 | unsigned long flags; 90 | 91 | read_lock_irqsave(¬ifier_lock, flags); 92 | result = raw_notifier_call_chain(¬ifier_list, event, sk); 93 | read_unlock_irqrestore(¬ifier_lock, flags); 94 | return result; 95 | } 96 | 97 | void inet_sock_destruct_hook(struct sock *sk) 98 | { 99 | sock_notifier_notify(0xFFFFFFFF, sk); 100 | sk->sk_destruct = inet_sock_destruct; 101 | inet_sock_destruct(sk); 102 | module_put(THIS_MODULE); 103 | } 104 | 105 | static inline void _finish_hook(struct sock *sk) 106 | { 107 | if (notifier_call_chain_empty()) 108 | return; 109 | BUG_ON(unlikely(sk->sk_destruct != inet_sock_destruct)); 110 | BUG_ON(unlikely(sk->sk_protinfo)); 111 | sk->sk_destruct = inet_sock_destruct_hook; 112 | sk->sk_protinfo = (void *) (unsigned long) 113 | (current->pid == current->tgid ? current->pid : current->tgid); 114 | __module_get(THIS_MODULE); 115 | sock_notifier_notify(0, sk); 116 | } 117 | 118 | static DECLARE_CREATE_HOOK(inet_create_hook) 119 | { 120 | int err; 121 | 122 | if (!(err = CALL_CREATE_HOOK(inet_family_ops.create))) 123 | _finish_hook(sock->sk); 124 | return err; 125 | } 126 | 127 | #if defined(CONFIG_IPV6) 128 | static DECLARE_CREATE_HOOK(inet6_create_hook) 129 | { 130 | int err; 131 | 132 | if (!(err = CALL_CREATE_HOOK(inet6_family_ops.create))) 133 | _finish_hook(sock->sk); 134 | return err; 135 | } 136 | #endif 137 | 138 | static int reinstall_family(const char *name, 139 | const struct net_proto_family *family_ops) 140 | { 141 | int err; 142 | 143 | if ((err = sock_register(family_ops))) { 144 | printk(KERN_ERR "%s: unable to re-register %s family (error %d); " 145 | "The system will probably require a reboot to fix networking.\n", 146 | THIS_MODULE->name, name, err); 147 | return err; 148 | } 149 | module_put(family_ops->owner); 150 | return 0; 151 | } 152 | 153 | static int install_hook(const char *name, 154 | const struct net_proto_family *family_ops, 155 | const struct net_proto_family *hooked_ops) 156 | { 157 | int err; 158 | 159 | if (family_ops->family != hooked_ops->family) 160 | return -EINVAL; 161 | if (try_module_get(family_ops->owner)) { 162 | sock_unregister(family_ops->family); 163 | if ((err = sock_register(hooked_ops))) { 164 | printk(KERN_ERR "%s: %s hook registration failed (error %d)\n", 165 | THIS_MODULE->name, name, err); 166 | reinstall_family(name, family_ops); 167 | return err; 168 | } 169 | } else { 170 | printk(KERN_ERR "%s: failed to get reference to %s family ops\n", 171 | THIS_MODULE->name, name); 172 | return -ENOENT; 173 | } 174 | return 0; 175 | } 176 | 177 | #ifdef CONFIG_SOCKET_NOTIFY_COMBINED 178 | # define _STATIC 179 | #else 180 | # define _STATIC static 181 | #endif 182 | 183 | _STATIC int __init socket_notify_init(void) 184 | { 185 | int err; 186 | 187 | if ((err = install_hook("IPv4", &inet_family_ops, &hooked_inet_family_ops))) 188 | return err; 189 | #if defined(CONFIG_IPV6) 190 | if ((err = install_hook("IPv6", &inet6_family_ops, &hooked_inet6_family_ops))) { 191 | sock_unregister(hooked_inet_family_ops.family); 192 | reinstall_family("IPv4", &inet_family_ops); 193 | return err; 194 | } 195 | #endif 196 | return 0; 197 | } 198 | 199 | _STATIC void socket_notify_remove(void) 200 | { 201 | #if defined(CONFIG_IPV6) 202 | sock_unregister(hooked_inet6_family_ops.family); 203 | reinstall_family("IPv6", &inet6_family_ops); 204 | #endif 205 | sock_unregister(hooked_inet_family_ops.family); 206 | reinstall_family("IPv4", &inet_family_ops); 207 | synchronize_net(); 208 | } 209 | 210 | #ifndef CONFIG_SOCKET_NOTIFY_COMBINED 211 | 212 | static char version[] __initdata = HONE_VERSION; 213 | 214 | static int __init socket_notify_module_init(void) 215 | { 216 | if (socket_notify_init()) 217 | return -1; 218 | printk("%s: v%s module successfully loaded\n", THIS_MODULE->name, version); 219 | return 0; 220 | } 221 | 222 | static void __exit socket_notify_module_exit(void) 223 | { 224 | socket_notify_remove(); 225 | printk("%s: module successfully unloaded\n", THIS_MODULE->name); 226 | } 227 | 228 | module_init(socket_notify_module_init); 229 | module_exit(socket_notify_module_exit); 230 | 231 | MODULE_DESCRIPTION("Socket event notification module."); 232 | MODULE_AUTHOR("Brandon Carpenter"); 233 | MODULE_LICENSE("GPL v2"); 234 | MODULE_VERSION(HONE_VERSION); 235 | 236 | EXPORT_SYMBOL(sock_notifier_register); 237 | EXPORT_SYMBOL(sock_notifier_unregister); 238 | 239 | #endif // CONFIG_SOCKET_NOTIFY_COMBINED 240 | -------------------------------------------------------------------------------- /src/socket_notify.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Battelle Memorial Institute 3 | * 4 | * Licensed under the GNU General Public License Version 2. 5 | * See LICENSE for the full text of the license. 6 | * See DISCLAIMER for additional disclaimers. 7 | * 8 | * Author: Brandon Carpenter 9 | */ 10 | 11 | #ifndef _SOCKET_NOTIFY_H 12 | #define _SOCKET_NOTIFY_H 13 | 14 | #ifdef __KERNEL__ 15 | extern int sock_notifier_register(struct notifier_block *nb); 16 | extern int sock_notifier_unregister(struct notifier_block *nb); 17 | #endif /* __KERNEL__ */ 18 | 19 | #endif /* _SOCKET_NOTIFY_H */ 20 | -------------------------------------------------------------------------------- /src/udev.rules: -------------------------------------------------------------------------------- 1 | SUBSYSTEM=="hone", GROUP="hone", MODE="0440" 2 | --------------------------------------------------------------------------------