From cf1109e5045f53692a20d90d2760bdfa28c890bb Mon Sep 17 00:00:00 2001 From: root4root Date: Sun, 5 Nov 2023 01:18:27 +0300 Subject: [PATCH] Version 1.4.0 --- CHANGELOG.md | 7 + README.md | 143 ++++++++------- deb-packages/tuninetd_1.4.0_amd64.deb | Bin 0 -> 12756 bytes src/Makefile | 31 ++-- src/common.h | 48 ++--- src/logger.c | 43 +++++ src/logger.h | 12 ++ src/main.h | 10 -- src/net.c | 184 +++++++++++++++++++ src/net.h | 70 ++++++++ src/thread.c | 20 ++- src/{main.c => tuninetd.c} | 100 +++++++++-- src/tuninetd.h | 21 +++ src/tuntapd.c | 248 ++++++++++++++++++++++++++ src/tuntapd.h | 30 ++++ src/utils.c | 113 ------------ src/xnflog.c | 58 ++++-- src/xnflog.h | 7 + src/xpcap.c | 75 +++++++- src/xpcap.h | 6 + src/xtun.c | 83 --------- 21 files changed, 954 insertions(+), 355 deletions(-) create mode 100644 CHANGELOG.md mode change 100755 => 100644 README.md create mode 100755 deb-packages/tuninetd_1.4.0_amd64.deb mode change 100755 => 100644 src/Makefile create mode 100644 src/logger.c create mode 100644 src/logger.h delete mode 100755 src/main.h create mode 100644 src/net.c create mode 100644 src/net.h mode change 100755 => 100644 src/thread.c rename src/{main.c => tuninetd.c} (50%) mode change 100755 => 100644 create mode 100644 src/tuninetd.h create mode 100644 src/tuntapd.c create mode 100644 src/tuntapd.h delete mode 100755 src/utils.c mode change 100755 => 100644 src/xnflog.c create mode 100644 src/xnflog.h mode change 100755 => 100644 src/xpcap.c create mode 100644 src/xpcap.h delete mode 100755 src/xtun.c diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..6dfc5cf --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +tuninetd changelog +-------- +**1.4.0** +* protocol decoder for IPv4, IPv6, Ethernet, 802.1Q and combinations (README section 5) +* tun/tap listener is a separate daemon now, named *tuntapd* (README section 6) +* *pcap* sensor not hard-coupled with tun/tap interface anymore, could be used on any +* *nflog* and *pcap* sensors can work simultaneously diff --git a/README.md b/README.md old mode 100755 new mode 100644 index 4a818d6..e3b0b19 --- a/README.md +++ b/README.md @@ -1,109 +1,132 @@ # tuninetd -Simple yet powerful event emitter by **tun/tap** (with/without **pcap** filter) or **nflog** source. +Network event emitter with **pcap** and **nflog** sensors. -Could be used as: VPN dispatcher, simplified detection system, by demand service handler, tricky lock etc... +Could be used as VPN dispatcher, by demand service handler, remote launcher etc... -### 1. How it works: -#### 1.1. tun/tap + pcap mode: -You should create and configure tun/tap device first, then run **tuninetd**. It starts listening on this interface, until network traffic will be detected. After that, interface immediately releasing and specified command (with -c) will execute. From now on, daemon in monitoring state. ---- ->For example: +### 1. How it works + +There are two events which **tuninetd** emits. "start", when network activity is detected, and "stop" if sensors no receive packets for certain amount of time. Both of events processed by external executable written on language whatever you like. + +#### 1.1. pcap sensor +You should configure network device first, then run **tuninetd** with **-i** flag and **-f** for filter (optional). It starts listening on the interface, until network traffic will be detected. After that command defined with **-c** will be executed. + ```sh -# tuninetd -i tun0 -c /path/to/launcher +# tuninetd -i tun0 -f "! host 1.2.3.4" -c /path/to/launcher -t 3600 ``` >then "start" command from **tuninetd** will be: ```sh # /path/to/launcher start > /dev/null 2>&1 ``` ->"stop" command in the same manner. ---- -After -t seconds of interface idle (no packets through), tuninetd send "stop" command by path that defined with -c, and start listening interface by itself again. +After **-t** seconds of idle (no packets), **tuninetd** runs "stop" command and wait for activity again to start process over. -Since **tuninetd** based on **libpcap**, you can specify capture filter. To test pcap rules might use tcpdump which is based on the same library. +Since **tuninetd** based on **libpcap**, it's a good idea to play with filters using **tcpdump** first, which is based on the same library. ->**! Notice !** *Modern Linux distributions periodically send 'icmpv6 router solicitation' packets, which cause tuninetd keep or change state. This situation appears in tun/tap mode without pcap filter applied.* +>**! Notice !** *Modern Linux distributions periodically send 'icmpv6 router solicitation' packets and other broadcast messages, which force tuninetd keep or change its state. So, using filters highly recommended to prevent unexpected behavior even on **tun** devices* -#### 1.2. nflog mode: +#### 1.2. nflog sensor -In general, behavior the same as tun/tap in part of start/stop. You could simply use netfilter nfgroup (*iptables **NFLOG** target*) to reading packets from. No binding to tun/tap device nor libpcap sensor. This is more lightweight mode and, because of that, - more reliable. +In general, behavior the same as pcap in terms of start/stop events. You could simply use netfilter nfgroup (*iptables **NFLOG** target*) to capture packets from, and "filter" already in nflog rule(s). No binding to certain network interface required. This is preferable mode since straightforward, lightweight and flexible + +```sh +# tuninetd -n 1 -c /path/to/launcher +``` +#### 1.3. pcap + nflog +You could use both sensors at the same time. In this case, event will be triggered from first sensor which receive a network packets. And yes, both sensors should be idle for **-t** seconds, before "stop" event fired +```sh +# tuninetd -i enp3s0 -f "arp and host 4.3.2.1" -n 1 -c /path/to/executable/toggletunnel.sh +``` ### 2. Installation: -If you're using Debian/Ubuntu please check deb-packages folder. Choose appropriate architecture, then run following command with root privileges: +If you're using Debian/Ubuntu, please check deb-packages folder. Run following with root privileges: ```sh # dpkg -i tuninetd_ver_arch.deb # apt-get -f install ``` -To install from sources download src folder. In case Debian/Ubuntu, you should also install **build-essential**, **libpcap-dev** and **libnetfilter-log-dev** packages first. To build tuninetd just run:
+To install from sources, please download src folder. In case Debian/Ubuntu, don't forget to install **build-essential**, **libpcap-dev** and **libnetfilter-log-dev** packages first.
```sh # cd /download/folder/src # make ``` -Congrats! Tuninend ready to use. Check ./bin folder. +Congrats! Tuninend ready to use, check ./bin folder. -### 3. Usage: -#### 3.1. Launch: +### 3. Usage +#### 3.1. Launch -```sh -# tuninetd {-i | -n } -c [-m ] [-f ] [-t ] [-d] +``` +tuninetd -i -c [-f ] [-n ] [-t ] [-d] +tuninetd -n -c [-i [-f ]] [-t ] [-d] + +-i : network interface to use with pcap. Must be up and configured. +-c : to executable, will be run with 'start' and 'stop' parameter accordingly. +-n : netfilter nflog group number (0 - 65535) +-f : specify pcap filter if needed, similar to tcpdump. Default none (all packets) +-t : seconds of interface idle before 'stop' command will be run. Default 600. +-d: daemonize process. Check for errors before use. + +-h: print help +-v: print version ``` -**-i \**: interface to use (tun or tap). Must be up and configured.
-**-n \**: iptables NFLOG group ('-i', '-m' and '-f' will be ignored).
-**-c \**: will execute with 'start' and 'stop' parameter.
-**-m \**: 'tun' or 'tap' mode. By default 'tun', should be set properly.
-**-f \**: specify pcap filter, similar to tcpdump
-**-t \**: seconds since last packet before 'stop' command (default is 600).
-**-d**: daemonize process
-**-h**: print this help - ---- - -#### 3.2. Signals: -SIGHUP (-1): switch tuninetd to standby mode (deadlock resolving)
-SIGUSR1 (-10): write to syslog current state (debug information) - - +#### 3.2. Signals +SIGHUP (-1): don't wait ttl, jump to "stop" event right now
+SIGUSR1 (-10): write to syslog current configuration and state -### 4. Examples: +### 4. Examples Before launching as a daemon make sure there is no errors. In daemon mode tuninetd write status messages and errors to syslog. ```sh -# tuninetd -i tun0 -c /test/runtunnel.sh -f "! host 1.2.3.4" -t 3600 -d -# tuninetd -n 2 -c /test/runtunnel.sh -t 3600 -d +# tuninetd -n 1 -c /path/to/executable/toggletunnel.sh +# tuninetd -i tap0 -c /path/to/executable/toggleservice.sh +# tuninetd -i tun0 -f "! host 1.2.3.4" -c /path/to/executable/somebinary -t 3600 -d +# tuninetd -i enp3s0 -f "arp and host 4.3.2.1" -n 1 -c /path/to/executable/run.py ``` -Check ```example``` folder to find some shell scripts. +Check ```example``` folder to find some scripts. -To create and bring up ```tun``` device could be used following commands: -```sh -# ip tuntap add dev tun0 mode tun -# ip link set tun0 up -``` +### 5. Logging -For more information about routing and configuring network devices, I strongly suggest LARTC how-to. +Here some syslog example with brief packet info which caused "start" event: +``` +Nov 1 21:32:14 router1 tuninetd: Success! Tuninetd has been started with PID: 23686 +Nov 1 21:32:14 router1 tuninetd: Binding to interface enp3s0 +Nov 1 21:32:14 router1 tuninetd: Start listening nflog-group 1 +Nov 1 21:32:14 router1 tuninetd: NFLOG: adjust nfnl_rcvbufsiz to 300000 +Nov 1 21:48:34 router1 tuninetd: NFLOG: executing START command... +Nov 1 21:48:35 router1 tuninetd: |- IPv4 192.168.1.1 > 13.107.42.14, NXT_HDR: 0x06 (TCP) +Nov 1 21:48:35 router1 tuninetd: |- MAC: 1b:1c:0d:45:a9:e1, DevIndex: 2 +Nov 1 22:08:59 router1 tuninetd: CORE: executing STOP command... +Nov 1 22:36:07 router1 tuninetd: PCAP: executing START command... +Nov 1 22:36:08 router1 tuninetd: |- IPv6 fe80::f66d:4ff:fe64:1124 > ff02::2, NXT_HDR: 0x3A (IPv6-ICMP) +Nov 1 22:36:08 router1 tuninetd: |- MAC: f4:6d:04:64:11:24 > 33:33:00:00:00:02, 802.1Q VID: 3, EtherType: 0x86DD (IPv6) -
+``` ---- ```sh # killall -10 tuninetd ``` -syslog:
->Oct 20 18:42:20 router1 tuninetd: SIGUSR1 caught:
->Oct 20 18:42:20 router1 tuninetd: - Capture engine: nflog group 1
->Oct 20 18:42:20 router1 tuninetd: - cmd_path = /etc/tuninetd/toggletunnel.sh
->Oct 20 18:42:20 router1 tuninetd: - TTL = 600 sec.
->Oct 20 18:42:20 router1 tuninetd: - Current status: up (ON), time since last captured packet: 2 sec. ---- +``` +Nov 1 22:42:17 router1 tuninetd: SIGUSR1 caught: +Nov 1 22:42:17 router1 tuninetd: - Capture engine: pcap, enp3s0 +Nov 1 22:42:17 router1 tuninetd: -- Pcap filter: "ip6" +Nov 1 22:42:17 router1 tuninetd: - Capture engine: nflog group 1 +Nov 1 22:42:17 router1 tuninetd: - cmd_path = /etc/tuninetd/toggletunnel.sh +Nov 1 22:42:17 router1 tuninetd: - TTL = 600 sec. +Nov 1 22:42:17 router1 tuninetd: - Current status: up (ON), time since last captured packet: 127 sec. + +``` + +### 6. Tuntapd +I've found **tuntapd** in this package, what this for? +Well, if you're about to use tun/tap device with pcap sensor, you need some program binded to the interface, or pcap can't capture any packets. In some cases, network services release tun/tap when shutting down. Tuntapd could be used to keep device alive for pcap. Start tuntapd from your executable by "stop" event handler, after desired service go down and vise-versa. -### License: +### License MIT -### Author: +### Author Paul aka root4root \
-**Any comment/suggestions are welcomed.** +**Any comments and suggestions are welcomed.** diff --git a/deb-packages/tuninetd_1.4.0_amd64.deb b/deb-packages/tuninetd_1.4.0_amd64.deb new file mode 100755 index 0000000000000000000000000000000000000000..d6f38902ed76f9af13c4d3979d291cad070ba741 GIT binary patch literal 12756 zcmai)Q;aVF&*sOrZQHi(Gq!Ep{Euzhwr$%!W9y9e{T5$#ueNELG|h9)gM$QbL-v56+D>uh~>%Td@HMN0&z|PiMB)|ryKmwJBfiZyoSD?TX zY#vbl0*mMYVZ!#{`2nX6;L8Yjp%2Ya6zgMCo{B~`{NPN(8y@zB4G!ggIyJpUqtaL2 zaR7^co-n5smr`G$uaG_)wM-EM&AJV_$rmN}gSG%SIO#-!D$KaXCGoqdP%{pc(cpo5 z*7c)fyRBhi7a`UmXui84UtcjUKDC;G9-JzSHmD1`Ev^rYz2&K0wuZUZq{p_geTRX5 zfDK3m1gLNgld@M}X@Lq!vg^wdt;dHmu1>1b6>k0Z^0k36Z)t2ebtb>~mOxEgqQl5W z8!I?AmaEljtPQ>_XMJCUu|>!xnr3h+d^SM`GbGykT2^zgCXHu&ITrQFBQGSjlLu;jbHFT;@C)&AABjmxce2a~W)5!m!%Xui zN@iIBp!G`pItg|@1wSgbi15gtY&Y(gD0m$ZW@miBemir5aT^e+)4~cf@=7o*-Iabd zvhV9WEZOpfj&ihT>(=S*&%;0i5AfPMM^YFV)xzinDGgaTyVO+Qjp!3vEE`|8u$G03 z27iQZ8d&W6xa`+B|1^OtD04I3(m?1*_y1ar>?rV0$V``NC{?Eg>Gy&!h2_&AtBH-) zLUV(Q%6zT?9shcN$Qk)=0diEYdyd2@9I(ieG9I4JE`j%BJg=35WiS^;2rr>*3mYbX z4e7l~+X2?fu{{ zkkbBSmZH~mrLtLnriCFi+n|H9$a;8lgPZNqO5j6wD9%qRcufHZL#zO|J)0(KUwZ2B zoon;I7heu;OtYnqxF|@gxi@NAxWSG3s$~=YxocnQE)dJgx=D26q=6A=&52L+p&FzN zUaJx76mk!xs;PHP?KJb?^CW4XgF*bT3#{r3(LgiEx1^PJ|51uNbXbfTjfEHCtOF9= zAU)vC2EB12iQc!O65?sy_wjPu9J2=A5;d2__kuLZ^J03E1=x~?^UvXZumH}GhZoY> z8fxfy8XcxK*R>LnN9vJ0c}PF4j>J4|@KcZkwP;SvY1L6_L(G7`8M62@I!f9VUAzfN zS3@|Ip-Gbe2Bvl3$g}gKioMcb&CTVot$Jzu9)6!-8*GSqx6~{oQ#lDFLIKt(?eU0Z8TFK_b&YX`(Q>hXzT<-Cq)MzyTo}cnb(355E zSK^&Rf9T#NKW5NgB*NlERbOGQsaeBlVYo1|&x4?>b&Wj4(YZ@lKGeQjyojXLB#Nc2 z+;F?w-H+-PA-?NjhFW@;Rv5^}147>D$Fzz-n2eHw)FOU5RhFQ=NXVf%bs`_(|Loh; znn{>hf;G#Ki9{KQutLpT#m%WoU4x$=XMVNSM zyOVqFV6rUwB^Ke-2K~$YYsnW9HZk-b?CJp55ws{Ob?jwk1zGPDhNS_z&QI8UEZ*UK zPPN|Bue<|H8|a$0p}vJlkx#zafwK~CZe7Xjsd^ZViAF-HF3}xT_83UVPKiaWMS7a_ zcDC$BL9XEUDC(&*tsznwM`t%qqUrQ6<14ej%z(T*wQs^Zq;kHpPqlvn$clRwfN~^W zIA@qsNKc|HCbk&m8}+%TVIJCE$gln~J3n#Vl-r70#`{V?qPv9M2LC7_b2(v)AHr<> zu5sv7eXr8YL|l?sciIPf-M&GFfzBzX!vq15Q8n{*vo6{)9`BDsKYW{v2UxcAl~1bn z^^ht*f_nSz>Xa?HrnY>`8rn=kvcW{q_v&s=kR~9Dam32)cn3h+z3nh{VdFm(_B{)&z~YGfgH(O)4@Qrc-Z0{Z)}k~#JOtBvm9 zNmUs)8IPDM!iG>u=}VWBYU@?b9J0Nw(ATH@d^7yMJ!F!CdD!D?x`-a}z97cYyE=HToe|d^c9gHvJu92(IoRZhnjOG`pt1Tt;i4MO!1FnH!H({bPR!*)h{k4$EqAqvPQ$KVap4UkK; zD5QWR89Kc6v2yV6Ib>9(ikGPds~lpFM)^yfYifd-XY{=7|K0Is34uYrlFVpk5L&T; zuEb{l`8HdQ_hH~w!DRb9BihaU2|q`?trB|5S1eL0XklHbB)}t@(jyr&16p$F{e^KJ zsvg5w=bd#K8Bg+PaHta53&4g-zaUhm&!SaAly+w~5sa&Q01@GauIFE|Xbf~vVQ?x# zar+8zw)@cyuiGS&?NM7T4`BK_nLal`e#0<>vELv_DYwt)&_%dx8hBVzj>IE6>)QM- z_`}BHY^M$CUW2{<>HQ#miDstP3C#!(5`w>|u2uF7^{v)ty`g&*PP8^$S4I#{*2igYt#%s;m88CNIFA5q!23|aYy;XS&^p6%2LymYh#cH$7pD# z0EUb%x^K1$G#scl!-fedhwXHnh((sZov~i2@OBb@rd#WE-~L72^T@ENco2=ce#3Ud zn`pYi6BmSR^2bbjJ^ovq=k`YyA}1HJ+Ts*10A%GIgQnOW{e5 z!bl>)bUmOlKIbbfen-wSIwEGZ|*Yx)|A1(&MKExlzw3Z`<0^4r%x*Kke4rNP0ws z*B2ShLNdu&D>|}^(jW1@84^mu=X4+72bVk~A8(6lF(r3!AVxCTcXV2!_Ik)wjJtHbL^mi#3Cpih=EO zRbZ)2OGFhoqZm2|E#&c_qGQ+Hx_i&!`zT4_&dHEeM$xDLfuCygqdue}_5nm$y+Ck=VHYQ_f7 zw#>d2FIPGYax7$z?sPWeYv3$K)o})0s}6BDH4xquqp=ffV*JRyEG9d+NliE9K0JQh zPC+)GkuE;7x3;Fj9zL*IqK%EdcrcvMy<~VrwyG=}TEa1N2;ZK1S{1Grq%amo#kL)Py>^qLsU zo7}{(C}!Q$>kBSC_@}td?8i?2OxfBK_XH->f!bLlpGH@FucyrSMBs)qtZ(ZHsG9i* zkm-UzF>F-#7m$*&@nN`nq_-SBd$5g-EsJX~^3)$&!7xq|qwX|pJ%*CJQ$|<346&@Oq+zhU*NwnuB}2L z!i$V>FUp5t-5^_bSKMSgbGcN zQ(D5oUGm1HiLDi#&MGoaEHti*{qPp`hqc(R>hulsUmEO7#m*lizO?t1^J9?frp%*5 zrGxT_8&H6kZcd4-_TU8RUw_;t(%qF`MC>1z3-izwj_5rT$Qw1J(hkO0i-$3uCLTXX zv4b83xi(w4JYu#IC-0DHXg{OKH;xQ!h(|kPIo}wn23Wj+9FluL8)_gwOba?Hfzt|3 zQ9XPX))Oz7h$;w>wwTA~CFb)jy!7b7AvCc8xo>?cH*Uz2YtyD7tG3C-jx=2lM&Ax^ z8C$;cn;AH;QnYhP6Py zEQis(JmKbz^_kWQRB>HV8DH~yk8f7p=!QO|nP2EmWV)b(=#qV}vx-|WV4%6N&y1G- z3J7Kst66WmFf7&#e=S;e$XAA4A>(vheLZ|*ae57aNRab1T@FooM>WKI=%JJ+R^I|r?Z5l6!_1Z~+&*b2ZDg7ac z#Sqz)Yt4g@pYMFO7-#pPLFLdP-FgXW)O@mgxQ+>E5v~cAThK268_TfM$%99bBW{tNsGfu_ogcb+?omAXD$oNEDGt!Y=jKG+HOkWi~)TWBf*ev&segA8@=JBs!!Sd7qKK~ zrni90R=xZ*q^aTzWr%Qso3IJk0u@zr!@wfEI%i$vfEv@&dL%EuX&5cqZ<$2Jn6!U0 z^P>SvA+Vk~Xb~0y2T8o83Zmq0vLr@t50w(tZ}I_?kPXGcRf3mYl9@^5i*%CyqukjZ zQ<{J5Xz=mT*E&R+QK7%(P@pGxxBikV-;q0jju$X=+OPMOR1iTaSX4m8?8mbZtp96jWVM~(Ow`h&>8ZlrJ#@4RDwhA`LLR=5$kj$u>eX4fdtWA>hxUq*l}#m&|Hz z(D>pzzug^1*je+bN1X%5`({~Ag2V5s7X@;2=xhP~JH+SJKEe-1*!ikY4$o#d^s|js zSwV8(xgaV0CEv-^9@=bXPx)$MlYY+$S5)HFb9E!;M_^Zv0G>Z3N24a|&|aCWoROEX ze+D>-xW>JDIF;;dVr+=!2r%?{Ya#QAmft{$zbHgvzP)&=BMSkt{`twu<;S;m<9@3? z>pY_3gK7oMKQb7@L|@&DytN~Em*aeB1_#HsbDIX&j$^U&Y6ZL^gov|zUFr{{sQRTV zLa;@Wlc9M<+17u~FWuXSWZ+pU{#TfIC>!xc12JB!0sW9$!^aHNt?Bnyxsa|L>N1wN z7gW&(&3BnjPeK%#UlkqN!?+sM>5r$6jLQdg=MIlv-F2FM@hNj&wrP4b`eb_w)0G5o ze@t~B$$l@+C`sD!AVS0D$j7#(o?$g;U zEcq4inJvl>oT3QXyZdK$ebsN%#wtmdMYmKXHh77Q$N5oyf0<3SxXoH$0CxgZ@pn~Z zAh?aRqr83-`1JG&KU+_c+L2J zdHvw5Sz5gUhg>SzMum*rAJ|?FMm{h)5QpCp4#3M)$x}NhK!ZzmEnO&=-Var6CZ1(A z*e1yJ4*`Xm@8eQse7p3w7b(pY6=pMD*`ZNS9`}N9s19C0eT~?8*HGrtSxB)GB%(ee ztzT#E#!Lgpxv{80KF8KRSsdc?WrmJ_-#W4ixTd zQYnaOuz06jlQmuFD5dj~-u-(j{|LR*ad_Q5s2j^&$znM+f8`=d9QeXaKW`%^Cc@0R z9FH8Amup=(TA{!dz1VBG@Y2M{aN%Q^kPEMk$&nA)dprbofH}%8n;Vpx3A)p% z=2<$$>mWwvO$&h}cH>fMNBUsNeR`|uqf)tdQJE7IHIiCkP#P15n1xLbi9~|=;n;+L zgFi*ykQDxh)ft#xjs#^gR-Y$rQIuzRtnJ8`P)H5KKrwIWH#WD-Ze(GZ;T@?*UY((F zg}Y}zMW-0jETRqcMb4L3sbs69{T?TCjw^if=fPE^9hKqPfj*iPWAB?rysJCoB!7)_ zvDv}=dffeOV^*|T*vZ@izz#&#p|+MVPYZoofD`f9#qULsVpKEWD2%*W>nW2#JoqT-~vz3i`t$6LkM@ilW- zT=*Bxg7xJn>iu9Thz{eG2(xvx_}*(z6gkObGfhkR;V`H!dAi9Ce3r~)EGlmVNVVkh zk482tRX*P1?H>gN*O4kr{K8v=v~%CrM@{Fv?hnF_r}+3ce5JYN3ffQG%dGsGD}myCA?7n-%34+rE>_ ziE*Vb{078{(qq<8Ml+GC8+5J2nB`F(OfHvsgLQ_V^YN?M*N1OTn@ZP!qC0#itxIHS zI9?h&zFcb%o$75R_dF!d-cFq;?f!1$5T(Pf;4|=JqnUOjj+#65w;D5OO`Ydmv`w#P zgmJd7?y{C@bhaAWd`z>!!>iSKTAyzW9qv1Rd7aDe2b{5acD;hF6AGJ-|td=)e{VcA^82lJ;Pe-B6s1RoOR_x)H>@I=#VqS=rKV zyQ)j!mbnNROWT`p8(5q~=U@W62M4*Bf7}GsWq>mDZyHbBmVA*ng>*do&D1yeCf`t? zGB$g-$3wNgL$4bf=?{wi6%~7Fy=5wr^B#9#N#W|lXGN=qlWZnd$UioLTZH#Yrw$Mi zSPsYo>J*YH&_85?Bp7N%w@DHLf4w0Kx&|{d0{yFW!Ubw~YWgC^n5i$BIXKd{)5x@( z79U&cg5xfAC}d!^I%nCQE$FEx;A-RdVUBOt+l*p_0oefy5fhNe=kGQZ`&=`6(2x29 znQ?=`T%EF@n$$efE+pm7Gu_t5r+A z6twM>(%WWZOkU#Jby92`GvQJ4&mIi5^`IYhsxDZ{K+NKR&D0C`X_m)(get3|Bx z_4j!*|EXFQjrW;L)Aq*=RD#eQ-71M_C&- zpE0lqwQhhv-R)KESe5KP7`F+)%i)YeM(<46z;NNb148nY9LI;PmMClbYjo5s=kK=! zAloN?N?bGlWj%P)5G0!v8jRB6KuPGBppSZeI}j4oN6{5GqQhk;`I~DBvtbKzRvgbf z+>OeOFm!yclkhR+?tRTW(7d&_HBCxa{u6Ie@n}CVWjd}J@-Hq3toVoZLI$Ir3QY!0RR;r6aM!*o$c^5D_ME+#~pKYG|qbw)~z_4u) z5$(=(>jvYpSrh8ytuSpkFC0D6YHW_cA(+`rW~3oudx_qP967>s`deX$aQJ(svwtJf z&qU!mR!B(WsK!O)r?C0dNju!Klq^=fi>2-{dhVDa^2v} zPuPAAu!PUJ*=O7bgL;cO$&4oRpP6jQ%n`5r$eJxUq9IJGmo7pU?YY|4t_CHD7AAl? zrG8yk6Aff_k+-=JczSXTb;O&E>YrY0d3@#ns{a{oaD)!m>&ePbXv*TyqrV&n`9T_wzO=4Znuwg3sa} z$9pfRd!}zP^FZ&Q9@Iq{0y(p;0-bYnLZeoMEuA3}(lZ6Ud>6eh7WUtL6>i`BcQD{q z?Q=+|+ERLmV&AB?Yjf~h&lVadB$E)4on_@LY#3{|tvtw?p?Smcl<41mh=ngUi1l3! zW85Ru>c9XvH&y_FiavohZapA&V(1i5IT#e&71X|xh4tTVc zcXwQX46LF?y!OYXUD>Py!3ypByh@&zZw^-cxGbroPOwIdpxfddAv@Z#{&W3fhr1=& zJD2_R?;&hIUGQ=lh>3i|JSU#sZMZijeH@J+lC(O(70lLjd0<>_!yZe~?32waW`Ff2 zjam{~>~Z**%=tn6Ik)8QqvB9jE3!DU`UF3?Aj?kjmt8zhdZT)oxbQzOZ#*U{mm*}E zlUjHjOSmyfD{yf>Vjhq`Yz5367S7-n*^V^18sH@$)zq#fxv##%s&|_KD2Mx^mx(+w za4oO!jw2gG<3>CEuS^vCd2Yj}fwcW#ZixN52ldl8Os@^mSPImqPuSQ(fwTh1Nf7wo zFF7muX@4@6j#>81L9(E?lfyyol9H&;-ijh%ETJbd{c!xZ@-iry{TMUtl(3i?83( zPT6X(2+W5ux!;US+>d%AdLm8l(Wbc${C|PMk;7BYcqe^+=`3{$vp{V#Oq)^EwQgor z+eW>7{Lb@0<()?E=h!=>%*qc$Y;xDA(QAy0T52I^ESr7%vWoK3MTGbJoMOwIySgTn zetFA6c^_qvxE;s1H)QUUF^LvUx-Y=ByOb#jMeW6APu=qpZS-NlLqNj@l2CP-n`9^I zjH-d28VVy7lNP$5lEt=VzuvJ@i{ozJ=y2lGFgx->_yM(wU`-xbV;B(=?}U?Kb%?>D zR}yjo?{6?*4pY21XO`anF!a-AVh%w8o?g zcqvO5H-^n&ugmRsh`rQUoB5UqoKM#TTBes3?Jl;TbRojF=m45rLnb0q@>;-=&g>^D zrL;W+t+_LOw_X017VsT4BuQhZZFO`meTm%jpd~I%PR+y9js+5gWFlD2{3Lj09wzq5 zA`aYvh^EiRw4+xVlEiE{EGy<;sWyWFbpO5Q+W~G!f!8e4Utm5kEp;Ewy=2hH>nx8( zT9#5QcTE2KFFF;wRLm0=s~NUT$bMV!l1nueGL`I|{2QdvX7!b+E;Xt;D*;<3wBBCk zo-SWl*g{6X)fHN)fH%&B~$P$F_e-S=u9J^ z4mRLpm1Pqe7n2gQj|O&D+1$LBbzeh{}wv;zsgrCex%=~YNt|gr?ezXGhc z_zP{Yf|D3Za;aJd3}QVnr)x6&FxbeEh0?aU%lR3^nfOiq3N-dfF%}$-4!kKVOQ_DH zp4`p8zPjF4S|7siXPcZZO^w$gOfF%)EwPcskW0XnAWcP-)*&ysq2 zo}IMS6(4K9liL-!QY^MNdOH{+s)rGjc*9dgj-Ek`G*3Q&w_(P%csn%1={I+Yp+Cc^Q3m4wV zA?kCvLiJ1CDfKW8H$j{sp*+&bH=;99J`+O;KfTx^dIAvcH#GmF0dy^>8qz)W0F5$<=7TSQ>f{y1gDt~YZ(>m zq9P1n!we}e1&krk<5$~R)8Us zj0O$d;QT#v{*XN56Eb^;cyyt>upu%E%km@xtYJN_Kvc_@0W)ydW{9>}r_olo@#1Gd zch44+@o}7a^VP`Io>g*x_zUQsmGvldKt3*cud10D+cGTfzxocOIJV?q^$^5_dlb3xv^ar9yHlxN-5w7~LtXc|AV` z(}2F=LSzBu8CeN7Q9u`Vk|IEsH3k^e5SUdiq;|z50qL-1#nut_UeTTyE%(DlF6b`g z37Ez~oqgJcjbkqH&uAG#{$le#FSbzA{t=Jfbv2r(38mVIhrMPqwC~2fQ}$Wz380=X zGbnhMKT!w%8gg1A2*lPx{MD00>{*_*YMP<=FBbT3Y>R-!W??Xn(2Q*aCtwf$DcIRWNpusfX$1k;#*zv?m} zKwpP{-Iic7NoxcKkD~gIMJMl-)J5F$Q{8^{jZl;&s3gg}Ddj)Y_h3a^JQB6lm2~Rl zV+45TK)u~sLscOlfP1vTObi}`XDuQJfCoJ=~2N-W|2!b`~a~TxW%`%Yo7ej6%yWdwtY%@|3*d_*)ptIUqYrFoP zaR|0eqCj&#PmQh_)FS84-_via31CavyH_hUz8j^w8mCgEMT;@kOTLhy`a81g=|YA! zP=e--#)NeHUn6T|xs|uU%938R=|(8HQVoPceJv4}O5nPm)i6g$KOt4DyV+iSg@#gt zL2r#%?~y6@ihanY0#m~z*?r#a`R5Ndz^zr zVAE|xGtt$;6bh{(v}bafL;jR1qu)&@W^c#fhdyYJ_a-xCo1QdAk8j0PtQ@}S?BLgl z7iy)l%FC7NO*EM88H$=OtYnd-Kl(R}Y3UTi*A#cBkp%UQ*EL(|f8{X-GN+bJd;#NpGR{!2z*JIKNqM%%*n{Y(hx1mep`w;`8y zwbrE^XCvtKD0jpX6AY(N9ExvX2@n{IJfyi3Q-Hvj3-7u3WKwdK$VFn-r6 z9U~#!j-Gr#`7Bn%l!t+rUuWp}!^!9#xTt{KYtwwX216?{>-vN5iHyde2I-HhUopnE8o!XK!ic z`VW8;+T(c4nKopmesoByou_mAdEY@~oayl>{C<4;z{m^s4b_BV}p^-h9IzsUy*g4l3LbHxO@|YBMNPOveEf>UdS*;xF z8H!eu9;JZg{8WWLb>6SsI95hoS@NmWxxBn=J#$qhFWWszN;`q}>jQWMEd!Gt;%{Dx zs0wn3r6=UCL-YiCq(R6y|9*dEacUEhl~}=1Ws+vNB0;5kHk0nOTAilhuc?<1oV=O9 z-0+o(_+#3xTc!AB(UtlETK9hDl9M_2oYZUN6gj9+_1nZ@2nAp8id1^zj7z*a|I$n; z9ddcP7l4n;##SH{a7RGRiguY7co4L0AAMYw%#1MA*cQ2W<_$9C6F8dL@$D}u`B=i) zsNEb(-RFfX(J<6aAkyN#e4a(aDu0^Qc9e~6I#zLMv-tCHdXr08aj7Dw3d3~qR+!uS z1{1=erN(E=+-t9Q7k(4#3JOkaS_H5EBK8YXiGndAUY4Mw)afrhZ^l)nk998gA)lem zq0C_FYULGkKg_m4+K8vET=$f)&Wy_DiLIqRNC0pQr36uy_uhajYaKc9M!ddPAgy2Z z36?7K_;h{ zvQD3)*Y7GU=UI1gL$fh_&H^GZsGJZX9J|1HyF=;*dj9R6B6A8E7(q~49WCbcvp!n~ zBTvspq0lX6RLvR{Jck~1@tgPGbVKiM9A3V`Q{rUNi-Vj)-4j(VMB1z}n%D{8Kf*8w zn%!W~pquVJHFk;w*t0jE1l~-?cowo@k}K!zlO80m>`2Xu%mExoJ(p1qGP$a=i4cb3 zkzT!XjC^Q$me5qRtrbYjZOpWFUXuej@bu5*LPd%eHAA?}yu(7c?7)4}ZRe@${5Rpp zZ~lto5ud~u4uT1_O5F~2SXw3`5k{N{%6Dyn;!SL|+mGrX74Dy33ug>!r`V=;>$4|8E`KEHQ%APgMj9Kz7mpFfiWIq-5Y&G) z;ep=tQiO)8h`z2luN(L6PP<#P>JoBzUX}n}f3A22cGm7z#Dyw?ai)YJyz7u_Q+X!z ztm|OjI&R={9QB?Ne_1?|=N_AUi(tk469FBCtB)XYH8Al1WJt1yaQ>bncbEAk`)d&ptwbQ!(f=TiNE|P(N&^uL) z*dioI_Aj7W7?8Y7pXn*RJHuCmS=ukcSry3gza0Ts&B2TopT!RTMF4xaqUcY+7TXPy z{s=wrfB1ei`dsU5Uh1sp*6TIO3X8(;S4&K#p8>}bX?PgB5=+Z7*me(W5~@HeZG5vq zUH?RNL8oP_V18wpDRT}0&k(;c&W3*<(k|~=pqqppd-S9A#0&1~GVE`Ix?aFy#21 z37%pfJ1P}QfPka({ndxrT*(>MVr`>-J4;h?3!hQRz5+L+u2I3cR!fU^BtDR+$kl?j zVSXntZ5!LW29@q!)m_=bErTH$QpZJgss4oz(zUWfr^aZ+NlLqyw?q3J=Bj5_z4S~I zt6vCdn16$(SukX=+OdOw!fT_XNz7L3pAe4X-^2H#7aX8CnC<{9 literal 0 HcmV?d00001 diff --git a/src/Makefile b/src/Makefile old mode 100755 new mode 100644 index a46390f..178cd33 --- a/src/Makefile +++ b/src/Makefile @@ -1,28 +1,35 @@ +COMPILER = gcc CFLAGS = -Wall -O2 -all: tuninetd +all: tuninetd tuntapd -tuninetd: main.o xnflog.o xpcap.o thread.o xtun.o utils.o +tuninetd: tuninetd.o xnflog.o xpcap.o thread.o logger.o net.o [ -d ./bin ] || mkdir -p ./bin - gcc main.o xnflog.o xpcap.o thread.o xtun.o utils.o -o ./bin/tuninetd -lpthread -lpcap -lnetfilter_log -lnfnetlink + $(COMPILER) tuninetd.o xnflog.o xpcap.o thread.o logger.o net.o -o ./bin/tuninetd -lpthread -lpcap -lnetfilter_log -lnfnetlink -main.o: main.c main.h common.h - gcc $(CFLAGS) -c main.c +tuninetd.o: tuninetd.c tuninetd.h common.h + $(COMPILER) $(CFLAGS) -c tuninetd.c xnflog.o: xnflog.c common.h - gcc $(CFLAGS) -c xnflog.c + $(COMPILER) $(CFLAGS) -c xnflog.c xpcap.o: xpcap.c common.h - gcc $(CFLAGS) -c xpcap.c + $(COMPILER) $(CFLAGS) -c xpcap.c thread.o: thread.c common.h - gcc $(CFLAGS) -c thread.c + $(COMPILER) $(CFLAGS) -c thread.c -xtun.o: xtun.c common.h - gcc $(CFLAGS) -c xtun.c +logger.o: logger.c logger.h + $(COMPILER) $(CFLAGS) -c logger.c -utils.o: utils.c common.h - gcc $(CFLAGS) -c utils.c +net.o: net.c net.h + $(COMPILER) $(CFLAGS) -c net.c + +tuntapd: tuntapd.o logger.o net.o + $(COMPILER) tuntapd.o logger.o net.o -o ./bin/tuntapd + +tuntapd.o: tuntapd.c tuntapd.h + $(COMPILER) $(CFLAGS) -c tuntapd.c clean: rm -f *.o diff --git a/src/common.h b/src/common.h index ed21bbe..b44ef11 100644 --- a/src/common.h +++ b/src/common.h @@ -1,30 +1,22 @@ -#ifndef H_TUNINETD_COMMON -#define H_TUNINETD_COMMON +#ifndef COMMON_H_ +#define COMMON_H_ -#include #include #include #include #include -#include -#include -#include #include #include +#include + +#include "logger.h" #define ON 1 #define OFF 0 -#define ERROR 0 -#define WARNING 1 -#define INFO 2 - -#define VERSION "\ntuninetd 1.3.1\n" - -//global vars. -extern short int debug; +//glob vars-- extern short int status; -extern unsigned long ts; +extern atomic_ulong ts; // @suppress("Type cannot be resolved") extern unsigned long curts; extern struct globcfg_t { @@ -38,27 +30,11 @@ extern struct globcfg_t { long nf_group; int dev_mode; long ttl; -} globcfg; - - -//from utils.c -void do_debug(const char *msg, ...); -void message(int, const char *msg, ...); - -void sighup_handler(int); -void sigusr_handler(int); -void sigterm_handler(int); -void usage(); -void version(); - -//from thread.c -void switch_guard(short action); -void thread_init(); - -void *tun_x(void *x_void_ptr); -void *nflog_x(void *x_void_ptr); -void *pcap_x(void *x_void_ptr); +} globcfg; //--glob vars -void xnflog_stop(); +//from thread.c-- +void switch_guard(short action); //Used: tuninetd.c, xnflog.c, xpcap.c +void thread_init(); //Used: tuninetd.c +//--from thread.c #endif diff --git a/src/logger.c b/src/logger.c new file mode 100644 index 0000000..abd1fb6 --- /dev/null +++ b/src/logger.c @@ -0,0 +1,43 @@ +#include +#include + +#include "common.h" + +#define DEBUG_MODE 0 + +void do_debug(const char *msg, ...) +{ + if (DEBUG_MODE) { + va_list argp; + va_start(argp, msg); + vfprintf(stderr, msg, argp); + va_end(argp); + } +} + +void message(int mylogpriority, const char *msg, ...) +{ + int syslogpriority; + + if (mylogpriority == ERROR) { + syslogpriority = LOG_ERR; + } else if (mylogpriority == WARNING) { + syslogpriority = LOG_WARNING; + } else { + syslogpriority = LOG_INFO; + } + + va_list argp; + va_start(argp, msg); + + if (globcfg.isdaemon == 0) { + vfprintf(stderr, msg, argp); + vfprintf(stderr, "\n", NULL); + } else { + openlog("tuninetd", 0, LOG_USER); + vsyslog(syslogpriority, msg, argp); + closelog(); + } + + va_end(argp); +} diff --git a/src/logger.h b/src/logger.h new file mode 100644 index 0000000..101e065 --- /dev/null +++ b/src/logger.h @@ -0,0 +1,12 @@ +#ifndef LOGGER_H_ +#define LOGGER_H_ + +#define ERROR 0 +#define WARNING 1 +#define INFO 2 + +void do_debug(const char *, ...); +void message(int, const char *, ...); + + +#endif /* LOGGER_H_ */ diff --git a/src/main.h b/src/main.h deleted file mode 100755 index 35876bf..0000000 --- a/src/main.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef H_TUNINETD_MAIN -#define H_TUNINETD_MAIN - -#include "common.h" -#include - -void build_config(int, char **); -void check_config_and_daemonize(); - -#endif diff --git a/src/net.c b/src/net.c new file mode 100644 index 0000000..9ea79db --- /dev/null +++ b/src/net.c @@ -0,0 +1,184 @@ +#include "net.h" + +/** + * @brief returns EtherType name + * + * @param type - Ethernet type ID + * @param order - NETWORK_ORDER or HOST_ORDER + * + * @return const string - Ethernet type name + */ +const char* ethertype_name(uint16_t type, uint8_t order) //HOST_ORDER +{ + if (order == NETWORK_ORDER) { + type = ntohs(type); + } + + switch (type) { + case 0x0800: return "IPv4"; + case 0x0806: return "ARP"; + case 0x86DD: return "IPv6"; + case 0x8100: return "802.1Q"; + case 0x0842: return "Wake-on-LAN"; + case 0x8035: return "RARP"; + case 0x809B: return "AppleTalk"; + case 0x80F3: return "AppleTalk ARP"; + case 0x8137: return "IPX"; + case 0x8808: return "Ethernet-Flowcontrol"; + case 0x8847: return "MPLS-unicast"; + case 0x8848: return "MPLS-multicast"; + case 0x8863: return "PPPoE-Discovery"; + case 0x8864: return "PPPoE-Session"; + case 0x88BF: return "MikroTik-RoMON"; + case 0x88CC: return "LLDP"; + } + + return "unresolved"; +} + +const char* proto_name(uint8_t proto) +{ + switch (proto) { + case 6: return "TCP"; + case 17: return "UDP"; + case 1: return "ICMP"; + case 58: return "IPv6-ICMP"; + case 47: return "GRE"; + case 4: return "IP-in-IP"; + case 115: return "L2TP"; + case 89: return "OSPF"; + case 88: return "EIGRP"; + case 2: return "IGMP"; + case 3: return "GGP"; + case 41: return "IPv6"; + case 43: return "IPv6-Route"; + case 44: return "IPv6-Frag"; + case 50: return "ESP"; + case 52: return "I-NLSP"; + case 55: return "MOBILE"; + case 56: return "TLSP"; + case 59: return "IPv6-NoNxt"; + case 60: return "IPv6-Opts"; + case 66: return "RVD"; + case 97: return "ETHERIP"; + case 98: return "ENCAP"; + case 108: return "IPComp"; + case 111: return "IPX-in-IP"; + case 124: return "IS-IS-over-IPv4"; + case 129: return "IPLT"; + case 132: return "SCTP"; + case 136: return "UDPLite"; + case 137: return "MPLS-in-IP"; + case 143: return "Ethernet"; + } + + return "unresolved"; +} + +/** + * @brief validate IPv4 header checksum + * + * @param packet - pointer to beginning of IPv4 packet + * + * @return 0 if checksum is valid + */ +uint16_t ipv4_header_checksum(const uint16_t *packet) +{ + //IPv4 header length in bytes + uint8_t hdr_length_b = (*packet & 0x0F) * 4; //IHL = number of 32-bit words. IHL * 32 / 8 = IHL * 4 + + uint32_t checksum = 0; + + for (uint8_t i = 0; i < hdr_length_b / 2; ++i) { + checksum += packet[i]; + } + + checksum = (checksum >> 16) + (checksum & 0x0000FFFF); + + return (uint16_t) ~checksum; +} + +/** + * @brief parse packet to respective headers + * + * @param hdrs - struct of founded headers + * @param pkt - pointer to beginning of some packet + * + * @return IP version, 0 if not discovered + */ +uint8_t protocol_recognition(headers *hdrs, const uint8_t *pkt) +{ + uint8_t ver = *pkt >> 4; + + if (ver == IPv4_VER) { + if (ipv4_header_checksum((uint16_t*)pkt) == 0) { + hdrs->ipv4 = (ipv4_h*)pkt; + return IPv4_VER; + } + } + + hdrs->ethernet = (ether_h*)pkt; + + if (hdrs->ethernet->etype == 0x0008) { //0x0800 (IPv4) - network order + if (ipv4_header_checksum((uint16_t*)(pkt + ETH_OFFSET)) == 0) { + hdrs->ipv4 = (ipv4_h*)(pkt + ETH_OFFSET); + return IPv4_VER; + } + } + + if (hdrs->ethernet->etype == 0xDD86) { //0x86DD (IPv6) - network order + if (pkt[ETH_OFFSET] >> 4 == IPv6_VER) { + hdrs->ipv6 = (ipv6_h*)(pkt + ETH_OFFSET); + return IPv6_VER; + } + } + + if (hdrs->ethernet->etype == 0x0081) { //0x8100 (802.1Q) - network order + + if (hdrs->ethernet->vlan_etype == 0x0008) { + if (ipv4_header_checksum((uint16_t*)(pkt + VLAN_OFFSET)) == 0) { + hdrs->ipv4 = (ipv4_h*)(pkt + VLAN_OFFSET); + return IPv4_VER; + } + } + + if (hdrs->ethernet->vlan_etype == 0xDD86) { + if (pkt[VLAN_OFFSET] >> 4 == IPv6_VER) { + hdrs->ipv6 = (ipv6_h*)(pkt + VLAN_OFFSET); + return IPv6_VER; + } + } + } + + + if (ver == IPv6_VER) { + + hdrs->ipv6 = (ipv6_h*)pkt; + + /* + * Since IPv6 header hasn't a checksum, the best what we can do + * is guessing based on common encapsulated protocol ID. + * + * Or implement full stack recognition with checksums verification on each layer, + * which is great amount of efforts (not for this project anyway) + * + * If you have any suggestions, please let me know + */ + switch (hdrs->ipv6->next_proto) { + case 41: //IPv6 + case 43: //IPv6-Route + case 59: //IPv6-NoNxt + case 60: //IPv6-Opts + case 58: //IPv6-ICMP + case 44: //IPv6-Frag + case 17: //UDP + case 6: //TCP + hdrs->ethernet = NULL; + return IPv6_VER; + default: + hdrs->ipv6 = NULL; + } + } + + return 0; +} diff --git a/src/net.h b/src/net.h new file mode 100644 index 0000000..55610fb --- /dev/null +++ b/src/net.h @@ -0,0 +1,70 @@ +#ifndef NET_H_ +#define NET_H_ + +#include +#include +#include + +#define ETH_OFFSET 14 // Ethernet II header offset +#define VLAN_OFFSET 18 // 802.1Q Ethernet + VLAN offset + +#define NETWORK_ORDER 1 +#define HOST_ORDER 2 + +#define IPv4_VER 4 // +#define IPv6_VER 6 // + +typedef struct Ethernet_ { + uint8_t dst_mac[6]; + uint8_t src_mac[6]; + union { + uint16_t vlan_h[2]; //[0] - TPID, [1] - :3 Priority + :1 CFI + :12 VID (if 802.1Q) + uint16_t etype; //Encapsulated protocol if not-802.1Q frame + }; + uint16_t vlan_etype; //If type is 802.1Q, this field represents encapsulated protocol number +} __attribute__((__packed__)) ether_h; + + +typedef struct IPV4_ { + uint8_t verhl; // :4 IP version + :4 header length (in 32-bit words) + uint8_t tos; // :6 DSCP + :2 ECN + uint16_t len; // Total Length + uint16_t id; // Identification + uint16_t frag; // :3 Flags + :13 Fragment Offset + uint8_t ttl; // Time To Live + uint8_t next_proto; // Encapsulated Protocol + uint16_t checksum; // Header Checksum + + uint8_t src[4]; // Src IP Address + uint8_t dst[4]; // Dst IP Address + //Options field begins here + +} __attribute__((__packed__)) ipv4_h; + + +typedef struct IPV6_ { + union { + uint8_t ver; // :4 Version + :4 of :8 MSB Traffic Class + uint32_t flow; // :4 Version + :8 Traffic class + :20 Flow label + }; + uint16_t plen; // Payload Length + uint8_t next_proto; // Encapsulated Protocol + uint8_t hlimit; // Hop limit + + uint16_t src[8]; // Src IP Address + uint16_t dst[8]; // Dst IP Address +} __attribute__((__packed__)) ipv6_h; + + +typedef struct Headers_ { + ether_h *ethernet; + ipv4_h *ipv4; + ipv6_h *ipv6; +} headers; + + +const char* proto_name(uint8_t); +uint16_t ipv4_header_checksum(const uint16_t *); +const char* ethertype_name(uint16_t, uint8_t); //HOST_ORDER | NETWORK_ORDER +uint8_t protocol_recognition(headers *, const uint8_t *); +#endif /* NET_H_ */ diff --git a/src/thread.c b/src/thread.c old mode 100755 new mode 100644 index 9db10da..9b05fa5 --- a/src/thread.c +++ b/src/thread.c @@ -1,8 +1,10 @@ -#include "common.h" #include +#include "common.h" +#include "xnflog.h" +#include "xpcap.h" + static pthread_t pcap_x_thread; -static pthread_t tun_x_thread; static pthread_t nflog_x_thread; static pthread_attr_t attr; @@ -20,25 +22,29 @@ void thread_init() pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - if (globcfg.nf_group < 0) { + if (globcfg.dev_name) { message(INFO, "Binding to interface %s", globcfg.dev_name); pthread_create(&pcap_x_thread, &attr, pcap_x, &x); - pthread_create(&tun_x_thread, &attr, tun_x, &y); - } else { + } + + if (globcfg.nf_group >= 0) { message(INFO, "Start listening nflog-group %i", globcfg.nf_group); pthread_create(&nflog_x_thread, &attr, nflog_x, &y); } + } void switch_state(short action) { if (status == action) { + message(INFO, "|- Event already fired, skipping... (multiple capture engines?)"); return; } ts = time(NULL); if (action == ON) { + if (system(globcfg.cmd_path_start) != 0) { message(WARNING, "Warning! Executable command doesn't return 0 code (%s)", globcfg.cmd_path_start); } @@ -46,15 +52,13 @@ void switch_state(short action) status = ON; } else { //action == OFF + if (system(globcfg.cmd_path_stop) != 0) { message(WARNING, "Warning! Executable command doesn't return 0 code (%s)", globcfg.cmd_path_stop); } status = OFF; - if (globcfg.nf_group < 0) { - pthread_create(&tun_x_thread, &attr, tun_x, &y); - } } } diff --git a/src/main.c b/src/tuninetd.c old mode 100755 new mode 100644 similarity index 50% rename from src/main.c rename to src/tuninetd.c index 1769e88..f762f1a --- a/src/main.c +++ b/src/tuninetd.c @@ -1,13 +1,14 @@ -#include "main.h" +#include "tuninetd.h" -//Global vars -- +//glob vars-- short int debug; short int status; -unsigned long ts; +atomic_ulong ts; // @suppress("Type cannot be resolved") unsigned long curts; +struct globcfg_t globcfg = {}; +//--glob vars -struct globcfg_t globcfg; -// -- Global vars +static char progname[] = "tuninetd"; int main(int argc, char *argv[]) { @@ -22,8 +23,6 @@ int main(int argc, char *argv[]) tim.tv_sec = 1; tim.tv_nsec = 0; - //debug = 1; - signal(SIGTERM, sigterm_handler); signal(SIGHUP, sighup_handler); signal(SIGUSR1, sigusr_handler); @@ -57,7 +56,6 @@ void build_config(int argc, char **argv) globcfg.pid = 0; globcfg.cmd_path = NULL; globcfg.ttl = 600; - globcfg.dev_mode = IFF_TUN; globcfg.nf_group = -1; opt = getopt( argc, argv, optString); @@ -88,18 +86,13 @@ void build_config(int argc, char **argv) case 'f': globcfg.pcap_filter = optarg; break; - case 'm': - if (strcmp("tap", optarg)== 0) { - globcfg.dev_mode = IFF_TAP; - } - break; case 'n': globcfg.nf_group = atoi(optarg); break; case 'd': globcfg.isdaemon = 1; break; - case 'h': //go to the next case, same behaviour. + case 'h': //go to the next case, same action case '?': usage(); break; @@ -115,7 +108,7 @@ void build_config(int argc, char **argv) void check_config_and_daemonize() { if (globcfg.dev_name == NULL && globcfg.nf_group < 0) { - message(ERROR, "tun/tap device OR nfgroup must be specified. Abort."); + message(ERROR, "Network device or nflog-group must be specified. Abort."); usage(); exit(1); } @@ -151,3 +144,80 @@ void check_config_and_daemonize() message(INFO, "Started with pid %d", getpid()); } } + +void version() { + fprintf(stderr, VERSION); +} + + +void sighup_handler(int signo) +{ + if (status == OFF) { + message(WARNING, "Warning! Tuninetd is already in standby mode."); + return; + } + + message(INFO, "SIGHUP caught, switch to standby mode."); + + switch_guard(OFF); +} + +void sigusr_handler(int signo) +{ + long delta = 0; + + message(INFO, "SIGUSR1 caught:"); + + if (globcfg.dev_name) { + message(INFO, "- Capture engine: pcap, %s", globcfg.dev_name); + if (globcfg.pcap_filter != NULL) { + message(INFO, "-- Pcap filter: \"%s\"", globcfg.pcap_filter); + } + } + + if (globcfg.nf_group >= 0) { + message(INFO, "- Capture engine: nflog group %ld", globcfg.nf_group); + } + + message(INFO, "- cmd_path = %s", globcfg.cmd_path); + message(INFO, "- TTL = %ld sec.", globcfg.ttl); + + if (status == OFF) { + message(INFO, "- Current status: standby (OFF)"); + } else { + delta = curts - ts; + message(INFO, "- Current status: up (ON), time since last captured packet: %ld sec.", delta < 0 ? 0 : delta); + } +} + +void sigterm_handler(int signo) +{ + if (globcfg.nf_group >= 0) { + xnflog_stop(); + } + + exit(0); +} + +void usage(void) { + fprintf(stderr, VERSION); + fprintf(stderr, "\nEvent emitter with pcap and nflog sensors which could be used at the same time\n"); + fprintf(stderr, "\nUsage: \t%s -i -c [-f ] [-n ] [-t ] [-d]\n", progname); + fprintf(stderr, "\t%s -n -c [-i [-f ]] [-t ] [-d]\n", progname); + fprintf(stderr, "\n\n"); + fprintf(stderr, "-i : network interface to use with pcap. Must be up and configured.\n"); + fprintf(stderr, "-c : to executable, will be run with 'start' and 'stop' parameter accordingly.\n"); + fprintf(stderr, "-n : netfilter nflog group number (0 - 65535)\n"); + fprintf(stderr, "-f : specify pcap filter if needed, similar to tcpdump. Default none (all packets)\n"); + fprintf(stderr, "-t : seconds of interface idle before 'stop' command will be run. Default 600.\n"); + fprintf(stderr, "-d: daemonize process. Check for errors before use.\n\n"); + fprintf(stderr, "-h: print this help\n\n"); + fprintf(stderr, "-v: print version\n\n"); + fprintf(stderr, "\nExamples:\n\n"); + fprintf(stderr, "# tuninetd -n 1 -c /path/to/executable/toggletunnel.sh\n"); + fprintf(stderr, "# tuninetd -i tap0 -c /path/to/executable/coolscript.sh\n"); + fprintf(stderr, "# tuninetd -i tun0 -f \"! host 1.2.3.4\" -c /path/to/executable/binary -t 3600 -d\n"); + fprintf(stderr, "# tuninetd -i enp3s0 -f \"arp and host 4.3.2.1\" -n 1 -c /path/to/executable/launcher.py\n\n"); + fprintf(stderr, "More information: https://github.com/root4root/tuninetd \n\n"); + exit(1); +} diff --git a/src/tuninetd.h b/src/tuninetd.h new file mode 100644 index 0000000..01d6100 --- /dev/null +++ b/src/tuninetd.h @@ -0,0 +1,21 @@ +#ifndef TUNINETD_H_ +#define TUNINETD_H_ + +#include + +#include "common.h" +#include "xnflog.h" + +#define VERSION "tuninetd 1.4.0\n" + +void build_config(int, char **); +void check_config_and_daemonize(); + +void sighup_handler(int); +void sigusr_handler(int); +void sigterm_handler(int); + +void version(); +void usage(); + +#endif diff --git a/src/tuntapd.c b/src/tuntapd.c new file mode 100644 index 0000000..c350958 --- /dev/null +++ b/src/tuntapd.c @@ -0,0 +1,248 @@ +#include "tuntapd.h" + +#define BUFSIZE 2000 + +struct globcfg_t globcfg; +static char progname[] = "tuntapd"; + +static void cread(int fd, char *buf, int n) +{ + int nread; + + if ((nread = read(fd, buf, n)) < 0) { + message(ERROR, "%s: error, while reading data. Abort.", progname); + exit(1); + } + + if (globcfg.isdaemon == 1) { + return; + } + + headers hdrs = {}; + uint8_t next_proto = 0; + uint8_t ver = protocol_recognition(&hdrs, (uint8_t*)buf); + + char src_ip[46] = {}; + char dst_ip[46] = {}; + + if (ver == IPv4_VER) { + inet_ntop(AF_INET, hdrs.ipv4->src, src_ip, 45); + inet_ntop(AF_INET, hdrs.ipv4->dst, dst_ip, 45); + next_proto = hdrs.ipv4->next_proto; + } + + if (ver == IPv6_VER) { + inet_ntop(AF_INET6, hdrs.ipv6->src, src_ip, 45); + inet_ntop(AF_INET6, hdrs.ipv6->dst, dst_ip, 45); + next_proto = hdrs.ipv6->next_proto; + } + + if (ver != 0) { + message(INFO, "|- IPv%u %s > %s, NXT_HDR: 0x%02X (%s)", ver, src_ip, dst_ip, next_proto, proto_name(next_proto)); + } else { + message(INFO, "|- Not IPv4/6 protocol, L3 info not available"); + } + + if (hdrs.ethernet == NULL) { + return; + } + + if (hdrs.ethernet->etype == 0x0081) { //VLAN 0x8100 NETWORK_ORDER + + uint16_t vid = ntohs(hdrs.ethernet->vlan_h[1]) & 0x0fff; + + message( + INFO, "|- MAC: %02x:%02x:%02x:%02x:%02x:%02x > %02x:%02x:%02x:%02x:%02x:%02x, 802.1Q VID: %u, EtherType: 0x%04X (%s)", + hdrs.ethernet->src_mac[0], hdrs.ethernet->src_mac[1], hdrs.ethernet->src_mac[2], + hdrs.ethernet->src_mac[3], hdrs.ethernet->src_mac[4], hdrs.ethernet->src_mac[5], + hdrs.ethernet->dst_mac[0], hdrs.ethernet->dst_mac[1], hdrs.ethernet->dst_mac[2], + hdrs.ethernet->dst_mac[3], hdrs.ethernet->dst_mac[4], hdrs.ethernet->dst_mac[5], + vid, + ntohs(hdrs.ethernet->vlan_etype), + ethertype_name(hdrs.ethernet->vlan_etype, NETWORK_ORDER) + ); + + return; + } + + message( + INFO, "|- MAC: %02x:%02x:%02x:%02x:%02x:%02x > %02x:%02x:%02x:%02x:%02x:%02x, EtherType: 0x%04X (%s)", + hdrs.ethernet->src_mac[0], hdrs.ethernet->src_mac[1], hdrs.ethernet->src_mac[2], + hdrs.ethernet->src_mac[3], hdrs.ethernet->src_mac[4], hdrs.ethernet->src_mac[5], + hdrs.ethernet->dst_mac[0], hdrs.ethernet->dst_mac[1], hdrs.ethernet->dst_mac[2], + hdrs.ethernet->dst_mac[3], hdrs.ethernet->dst_mac[4], hdrs.ethernet->dst_mac[5], + ntohs(hdrs.ethernet->etype), + ethertype_name(hdrs.ethernet->etype, NETWORK_ORDER) + ); + +} + +int main(int argc, char *argv[]) +{ + int tap_fd; + char buffer[BUFSIZE]; + + build_config(argc, argv); + check_config_and_daemonize(); + + signal(SIGTERM, sigterm_handler); + signal(SIGHUP, sighup_handler); + signal(SIGUSR1, sigusr_handler); + signal(SIGINT, sigterm_handler); + + + if ((tap_fd = tun_alloc(globcfg.dev_name, globcfg.dev_mode | IFF_NO_PI)) < 0) { + message(ERROR, "%s: mapping to tun/tap interface %s mode 0x%04x failed. Abort.", progname, globcfg.dev_name, globcfg.dev_mode); + exit(1); + } + + while (1) { + cread(tap_fd, buffer, BUFSIZE); + } + + close(tap_fd); + + return 0; +} + +static int tun_alloc(char *dev, int flags) +{ + struct ifreq ifr; + int fd, err; + char *clonedev = "/dev/net/tun"; + + if ( (fd = open(clonedev, O_RDWR)) < 0 ) { + message(ERROR, "%s: unable to open clonable device %s", progname, clonedev); + return fd; + } + + memset(&ifr, 0, sizeof(ifr)); + + ifr.ifr_flags = flags; + + if (*dev) { + strncpy(ifr.ifr_name, dev, IFNAMSIZ); + } + + if ( (err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0 ) { + close(fd); + return err; + } + + return fd; +} + +static void build_config(int argc, char **argv) +{ + int opt = 0; + static const char *optString = "i:m:dhv"; + + globcfg.isdaemon = 0; + globcfg.pid = 0; + globcfg.dev_mode = IFF_TUN; + + opt = getopt(argc, argv, optString); + + while (opt != -1) { + switch( opt ) { + case 'v': + version(); + exit(0); + case 'i': + globcfg.dev_name = optarg; + break; + case 'd': + globcfg.isdaemon = 1; + break; + case 'm': + if (strcmp("tap", optarg) == 0) { + globcfg.dev_mode = IFF_TAP; + } else if (strcmp("tun", optarg) == 0) { + globcfg.dev_mode = IFF_TUN; + } else { + globcfg.dev_mode = 0; + } + break; + case 'h': //go to the next case, same action + case '?': + usage(); + break; + default: + exit(1); + break; + } + + opt = getopt(argc, argv, optString); + } +} + +static void check_config_and_daemonize() +{ + if (globcfg.dev_name == NULL) { + message(ERROR, "%s: tun/tap device must be specified. Abort.", progname); + usage(); + exit(1); + } + + if (globcfg.dev_mode != IFF_TUN && globcfg.dev_mode != IFF_TAP) { + message(ERROR, "%s: device mode must be \"tun\" or \"tap\". Abort.", progname); + exit(1); + } + + if (globcfg.isdaemon == 1) { + globcfg.pid = fork(); + + if (globcfg.pid < 0) { + message(ERROR, "%s: can't fork process. Abort.", progname); + exit(1); + } + + if (globcfg.pid > 0) { + message(INFO, "---"); + message(INFO, "%s: success! Has been started with PID: %i", progname, globcfg.pid); + exit(0); + } + + chdir("/"); + + setsid(); + + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + } else { + message(INFO, "%s: started with pid %d", progname, getpid()); + } +} + +static void sighup_handler(int signo) +{ + message(WARNING, "%s: SIGHUP caught. NoOp.", progname); +} + +static void sigusr_handler(int signo) +{ + message(INFO, "%s: SIGUSR1 caught. Running on %s, mode 0x%04x", progname, globcfg.dev_name, globcfg.dev_mode); +} + +static void sigterm_handler(int signo) +{ + message(INFO, "%s: SIGTERM caught. Shutting down...", progname); + exit(0); +} + +static void usage(void) { + fprintf(stderr, VERSION); + fprintf(stderr, "\nStub for tun/tap device to keep it alive.\n"); + fprintf(stderr, "\nUsage: %s -i [-m ] [-d]\n\n", progname); + fprintf(stderr, "-i : interface to use with.\n"); + fprintf(stderr, "-m : 'tun' or 'tap'. Default is 'tun'. \n"); + fprintf(stderr, "-d: daemonize process. Check for errors before use.\n\n"); + fprintf(stderr, "-h: print this help\n"); + fprintf(stderr, "-v: print version\n\n"); + exit(1); +} + +static void version() { + fprintf(stderr, VERSION); +} diff --git a/src/tuntapd.h b/src/tuntapd.h new file mode 100644 index 0000000..5c3dbed --- /dev/null +++ b/src/tuntapd.h @@ -0,0 +1,30 @@ +#ifndef TUNTAPD_H_ +#define TUNTAPD_H_ + +#include +#include +#include +#include + +#include +#include +#include + +#include "common.h" +#include "net.h" + +#define VERSION "tuntapd 1.0.0\n" + +static int tun_alloc(char *, int); +static void cread(int, char *, int); + +static void build_config(int, char **); +static void check_config_and_daemonize(); + +static void sighup_handler(int); +static void sigusr_handler(int); +static void sigterm_handler(int); +static void usage(void); +static void version(); + +#endif /* TUNTAPD_H_ */ diff --git a/src/utils.c b/src/utils.c deleted file mode 100755 index 24e25bc..0000000 --- a/src/utils.c +++ /dev/null @@ -1,113 +0,0 @@ -#include "common.h" -#include -#include - -static char progname[] = "tuninetd"; - -void do_debug(const char *msg, ...) -{ - if(debug) { - va_list argp; - va_start(argp, msg); - vfprintf(stderr, msg, argp); - va_end(argp); - } -} - -void message(int mylogpriority, const char *msg, ...) -{ - int syslogpriority; - - if (mylogpriority == ERROR) { - syslogpriority = LOG_ERR; - } else if (mylogpriority == WARNING) { - syslogpriority = LOG_WARNING; - } else { - syslogpriority = LOG_INFO; - } - - va_list argp; - va_start(argp, msg); - - if (globcfg.isdaemon == 0) { - vfprintf(stderr, msg, argp); - vfprintf(stderr, "\n", NULL); - } else { - openlog("tuninetd", 0, LOG_USER); - vsyslog(syslogpriority, msg, argp); - closelog(); - } - - va_end(argp); -} - -void usage(void) { - fprintf(stderr, VERSION); - fprintf(stderr, "\nUsage:\n\n"); - fprintf(stderr, "%s {-i | -n } -c [-m ] [-f ] [-t ] [-d]\n", progname); - fprintf(stderr, "\n\n"); - fprintf(stderr, "-i : interface to use (tun or tap). Must be up and configured.\n"); - fprintf(stderr, "-c : will be executed with 'start' and 'stop' parameter accordingly.\n"); - fprintf(stderr, "-m : 'tun' or 'tap' mode. By default 'tun'. \n"); - fprintf(stderr, "-n : NFLOG group number ('-i', '-m' and '-f' will be ignored in this case.) \n"); - fprintf(stderr, "-f : specify pcap filter, similar to tcpdump.\n"); - fprintf(stderr, "-t : interface idling in seconds, before 'stop' command will be launched. 600 by default.\n"); - fprintf(stderr, "-d: daemonize process. Check for errors before use.\n\n"); - fprintf(stderr, "-h: print this help\n\n"); - fprintf(stderr, "-v: print version\n\n"); - fprintf(stderr, "\nExamples:\n\n"); - fprintf(stderr, "# tuninetd -i tun0 -c /test/runtunnel.sh -f \"! host 1.2.3.4\" -t 3600 -d\n"); - fprintf(stderr, "# tuninetd -n 1 -c /etc/tuninetd/toggletunnel.sh -d\n\n"); - exit(1); -} - -void version() { - fprintf(stderr, VERSION); -} - - -void sighup_handler(int signo) -{ - if (status == OFF) { - message(WARNING, "Warning! Tuninetd is already in standby mode."); - return; - } - - message(INFO, "SIGHUP caught, switch to standby mode."); - - switch_guard(OFF); -} - -void sigusr_handler(int signo) -{ - long delta = 0; - - message(INFO, "SIGUSR1 caught:"); - if (globcfg.nf_group < 0) { - message(INFO, "- Capture engine: pcap + tun/tap"); - if (globcfg.pcap_filter != NULL) { - message(INFO, "-- Pcap filter: \"%s\"", globcfg.pcap_filter); - } - } else { - message(INFO, "- Capture engine: nflog group %ld", globcfg.nf_group); - } - message(INFO, "- cmd_path = %s", globcfg.cmd_path); - message(INFO, "- TTL = %ld sec.", globcfg.ttl); - - if (status == OFF) { - message(INFO, "- Current status: standby (OFF)"); - } else { - delta = curts - ts; - message(INFO, "- Current status: up (ON), time since last captured packet: %ld sec.", delta < 0 ? 0 : delta); - } -} - -void sigterm_handler(int signo) -{ - if (globcfg.nf_group >= 0) { - xnflog_stop(); - } - - exit(0); - -} diff --git a/src/xnflog.c b/src/xnflog.c old mode 100755 new mode 100644 index 8b67bcf..1d494ae --- a/src/xnflog.c +++ b/src/xnflog.c @@ -1,7 +1,11 @@ -#include "common.h" #include #include #include +#include + +#include "common.h" +#include "net.h" +#include "xnflog.h" #define BUFSIZE 65536 #define NFNLBUFSIZ 150000 @@ -11,7 +15,6 @@ static struct nflog_handle *h; static struct nflog_g_handle *qh; static int fd; - static void setnlbufsiz(unsigned int size, struct nflog_handle *h) { //This function returns new buffer size @@ -26,7 +29,7 @@ static int callback(struct nflog_g_handle *gh, struct nfgenmsg *nfmsg, struct nf return 0; } - uint8_t *payload; + char *payload; int payload_fetch_result = nflog_get_payload(ldata, &payload); @@ -36,23 +39,49 @@ static int callback(struct nflog_g_handle *gh, struct nfgenmsg *nfmsg, struct nf message(INFO, "NFLOG: executing START command..."); - if (payload[0] >> 4 == 4) { //4 bit MSB IP version. IPv4 in this case. TODO: implement for IPv6 - message(INFO, "|- IPv4 SRC: %i.%i.%i.%i DST: %i.%i.%i.%i", payload[12], payload[13], payload[14], payload[15], payload[16], payload[17], payload[18], payload[19]); + switch_guard(ON); - struct nfulnl_msg_packet_hw *hw = nflog_get_packet_hw(ldata); + headers hdrs = {}; + uint8_t next_proto = 0; + uint8_t ver = protocol_recognition(&hdrs, (uint8_t*)payload); - if (hw) { //Hardware information only available on inbound or transit packets - message(INFO, "|- HWaddr: %02x:%02x:%02x:%02x:%02x:%02x, DevIndex: %u", hw->hw_addr[0], hw->hw_addr[1], hw->hw_addr[2], hw->hw_addr[3], hw->hw_addr[4], hw->hw_addr[5], nflog_get_indev(ldata)); - } + char src_ip[46] = {}; + char dst_ip[46] = {}; + + if (ver == IPv4_VER) { + inet_ntop(AF_INET, hdrs.ipv4->src, src_ip, 45); + inet_ntop(AF_INET, hdrs.ipv4->dst, dst_ip, 45); + next_proto = hdrs.ipv4->next_proto; } - switch_guard(ON); + if (ver == IPv6_VER) { + inet_ntop(AF_INET6, hdrs.ipv6->src, src_ip, 45); + inet_ntop(AF_INET6, hdrs.ipv6->dst, dst_ip, 45); + next_proto = hdrs.ipv6->next_proto; + } + + if (ver != 0) { + message(INFO, "|- IPv%u %s > %s, NXT_HDR: 0x%02X (%s)", ver, src_ip, dst_ip, next_proto, proto_name(next_proto)); + } else { + message(INFO, "|- Not IPv4/6 protocol, L3 info not available"); + } + + struct nfulnl_msg_packet_hw *hw = nflog_get_packet_hw(ldata); + + if (hw) { + message( + INFO, "|- MAC: %02x:%02x:%02x:%02x:%02x:%02x, DevIndex: %u", + hw->hw_addr[0], hw->hw_addr[1], hw->hw_addr[2], + hw->hw_addr[3], hw->hw_addr[4], hw->hw_addr[5], + nflog_get_indev(ldata) + ); + } return 0; } -void xnflog_start() +static void xnflog_start() { buf = calloc(BUFSIZE, sizeof(char)); @@ -79,7 +108,7 @@ void xnflog_start() qh = nflog_bind_group(h, globcfg.nf_group); if (!qh) { - message(ERROR, "NFLOG: no handle for group %i, can't bind, errno: %i. Abort.", globcfg.nf_group, errno); + message(ERROR, "NFLOG: no handle for group %li, can't bind, errno: %i. Abort.", globcfg.nf_group, errno); exit(1); } @@ -91,13 +120,13 @@ void xnflog_start() nflog_callback_register(qh, &callback, NULL); fd = nflog_fd(h); - } void xnflog_stop() { message(INFO, "NFLOG: Shutting down..."); shutdown(fd, SHUT_RD); + //close(fd); nflog_unbind_group(qh); nflog_unbind_pf(h, AF_INET); nflog_unbind_pf(h, AF_INET6); @@ -113,8 +142,7 @@ void *nflog_x(void *x_void_ptr) ssize_t rv; - while ((rv = recv(fd, (void *)buf, BUFSIZE, 0))) { - + while ((rv = recv(fd, (void *)buf, BUFSIZE - 1, 0))) { if (rv >= 0) { nflog_handle_packet(h, buf, rv); } else if (errno == ENOBUFS) { diff --git a/src/xnflog.h b/src/xnflog.h new file mode 100644 index 0000000..c1dab2a --- /dev/null +++ b/src/xnflog.h @@ -0,0 +1,7 @@ +#ifndef XNFLOG_H_ +#define XNFLOG_H_ + +void xnflog_stop(); +void *nflog_x(void *); + +#endif /* XNFLOG_H_ */ diff --git a/src/xpcap.c b/src/xpcap.c old mode 100755 new mode 100644 index 862197a..8c0b1b9 --- a/src/xpcap.c +++ b/src/xpcap.c @@ -1,10 +1,79 @@ -#include "common.h" #include +#include + +#include "common.h" +#include "net.h" +#include "xpcap.h" static void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) { ts = header->ts.tv_sec; - //do_debug("Packet timestamp %lu ...\n", ts); + + if (status == ON) { + return; + } + + message(INFO, "PCAP: executing START command..."); + + switch_guard(ON); + + headers hdrs = {}; + uint8_t next_proto = 0; + uint8_t ver = protocol_recognition(&hdrs, packet); + + char src_ip[46] = {}; + char dst_ip[46] = {}; + + if (ver == IPv4_VER) { + inet_ntop(AF_INET, hdrs.ipv4->src, src_ip, 45); + inet_ntop(AF_INET, hdrs.ipv4->dst, dst_ip, 45); + next_proto = hdrs.ipv4->next_proto; + } + + if (ver == IPv6_VER) { + inet_ntop(AF_INET6, hdrs.ipv6->src, src_ip, 45); + inet_ntop(AF_INET6, hdrs.ipv6->dst, dst_ip, 45); + next_proto = hdrs.ipv6->next_proto; + } + + if (ver != 0) { + message(INFO, "|- IPv%u %s > %s, NXT_HDR: 0x%02X (%s)", ver, src_ip, dst_ip, next_proto, proto_name(next_proto)); + } else { + message(INFO, "|- Not IPv4/6 protocol, L3 info not available"); + } + + if (hdrs.ethernet == NULL) { + return; + } + + if (hdrs.ethernet->etype == 0x0081) { //VLAN 0x8100 NETWORK_ORDER + + uint16_t vid = ntohs(hdrs.ethernet->vlan_h[1]) & 0x0fff; + + message( + INFO, "|- MAC: %02x:%02x:%02x:%02x:%02x:%02x > %02x:%02x:%02x:%02x:%02x:%02x, 802.1Q VID: %u, EtherType: 0x%04X (%s)", + hdrs.ethernet->src_mac[0], hdrs.ethernet->src_mac[1], hdrs.ethernet->src_mac[2], + hdrs.ethernet->src_mac[3], hdrs.ethernet->src_mac[4], hdrs.ethernet->src_mac[5], + hdrs.ethernet->dst_mac[0], hdrs.ethernet->dst_mac[1], hdrs.ethernet->dst_mac[2], + hdrs.ethernet->dst_mac[3], hdrs.ethernet->dst_mac[4], hdrs.ethernet->dst_mac[5], + vid, + ntohs(hdrs.ethernet->vlan_etype), + ethertype_name(hdrs.ethernet->vlan_etype, NETWORK_ORDER) + ); + + return; + } + + message( + INFO, "|- MAC: %02x:%02x:%02x:%02x:%02x:%02x > %02x:%02x:%02x:%02x:%02x:%02x, EtherType: 0x%04X (%s)", + hdrs.ethernet->src_mac[0], hdrs.ethernet->src_mac[1], hdrs.ethernet->src_mac[2], + hdrs.ethernet->src_mac[3], hdrs.ethernet->src_mac[4], hdrs.ethernet->src_mac[5], + hdrs.ethernet->dst_mac[0], hdrs.ethernet->dst_mac[1], hdrs.ethernet->dst_mac[2], + hdrs.ethernet->dst_mac[3], hdrs.ethernet->dst_mac[4], hdrs.ethernet->dst_mac[5], + ntohs(hdrs.ethernet->etype), + ethertype_name(hdrs.ethernet->etype, NETWORK_ORDER) + ); + } void *pcap_x(void *x_void_ptr) @@ -16,7 +85,7 @@ void *pcap_x(void *x_void_ptr) short int loop_status = 0; - handle = pcap_open_live(globcfg.dev_name, BUFSIZ, 0, 10, errbuf); + handle = pcap_open_live(globcfg.dev_name, BUFSIZ, 0, 10, errbuf); //!!!! if (handle == NULL) { message(ERROR, "Pcap: unable to open interface %s. Abort.", errbuf); diff --git a/src/xpcap.h b/src/xpcap.h new file mode 100644 index 0000000..2029e4e --- /dev/null +++ b/src/xpcap.h @@ -0,0 +1,6 @@ +#ifndef XPCAP_H_ +#define XPCAP_H_ + +void *pcap_x(void *); + +#endif /* XPCAP_H_ */ diff --git a/src/xtun.c b/src/xtun.c deleted file mode 100755 index 2479016..0000000 --- a/src/xtun.c +++ /dev/null @@ -1,83 +0,0 @@ -#include "common.h" - -#define BUFSIZE 2000 - -static int tun_alloc(char *dev, int flags) -{ - struct ifreq ifr; - int fd, err; - char *clonedev = "/dev/net/tun"; - - if ( (fd = open(clonedev, O_RDWR)) < 0 ) { - message(ERROR, "Tun: unable to open clonable device %s", clonedev); - return fd; - } - - memset(&ifr, 0, sizeof(ifr)); - - ifr.ifr_flags = flags; - - if (*dev) { - strncpy(ifr.ifr_name, dev, IFNAMSIZ); - } - - if ( (err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0 ) { - close(fd); - return err; - } - - return fd; -} - -static int cread(int fd, char *buf, int n) -{ - int nread; - - if ((nread = read(fd, buf, n)) < 0) { - message(ERROR, "Tun: error, while reading data. Abort."); - exit(1); - } - - return nread; -} - -void *tun_x(void *x_void_ptr) -{ - int tap_fd; - int nread; - char buffer[BUFSIZE]; - - struct timespec tim; - - tim.tv_sec = 0; - tim.tv_nsec = 20000000; - - if ( (tap_fd = tun_alloc(globcfg.dev_name, globcfg.dev_mode | IFF_NO_PI)) < 0 ) { - message(ERROR, "Tun: connection to tun/tap interface %s failed. Abort.", globcfg.dev_name); - exit(1); - } - - while (1) { - nread = cread(tap_fd, buffer, BUFSIZE); - - if (globcfg.pcap_filter != NULL) { - nanosleep(&tim, NULL); - if ( (long)(curts - ts) < 2 ) { - do_debug("Read %d bytes from the tap interface\n", nread); - break; - } else { - do_debug("Delta is not small enough...\n"); - } - } else { - break; - } - } - - close(tap_fd); - - message(INFO, "TUN/TAP module: executing START command..."); - - switch_guard(ON); - - return 0; -}