Skip to content

Commit 5b8e0fb

Browse files
committed
Bug fix with tun/tap thread "on" action.
1 parent 8977bbd commit 5b8e0fb

File tree

10 files changed

+179
-112
lines changed

10 files changed

+179
-112
lines changed

README.md

100644100755
Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,34 @@
11
# tuninetd
22

3-
Simple yet powerful tun/tap event emitter. Could be used like VPN dispatcher...
3+
Simple yet powerful event emitter by **tun/tap** (with/without **pcap** filter) or **nflog** source. Could be used as: VPN dispatcher, simplified detection system, by demand services handler, etc...
44

5-
### How it works:
6-
You should create and configure tun/tap device, then run **tuninetd**. It starts listening on that interface until network traffic will be detected. After that, interface will be released and certain command executed. From now on daemon is in monitoring state.
7-
After N seconds of interface idle, tuninetd send "stop" command by path that you define and start listening interface by its own again.
8-
9-
Since **tuninetd** based on **libpcap**, you can specify filter to trigging "start" and monitoring iddle (i.e. cutoff unwanted traffic). To test/debug pcap rules you might use tcpdump which is based on the same library.
5+
### 1. How it works.
6+
#### tun/tap device: ####
7+
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.
108

11-
**! OR !**
9+
---
10+
>For example:
11+
```sh
12+
# tuninetd -i tun0 -c /path/to/launcher
13+
```
14+
>then "start" command from **tuninetd** will be:
15+
```sh
16+
# /path/to/launcher start > /dev/null 2>&1
17+
```
18+
>"stop" command in the same manner.
19+
---
1220

13-
You can simply use netfilter nfgroup (*iptables NFLOG target*), for reading packets from. No need binding to tun/tap interface nor heavy libpcap sensor. This is more lightweight mode and because of that - more reliable. Option available since v1.1.0.
21+
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.
1422

23+
Since **tuninetd** based on **libpcap**, you can specify capture filter. To test pcap rules might use tcpdump which is based on the same library.
1524

16-
**tuninetd** allows deploy "VPN by demand" or any other "by demand" services, which is the main idea of the project.
25+
>**! 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.*
1726
18-
### Installation:
27+
#### NFLOG: ####
28+
29+
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.
30+
31+
### 2. Installation:
1932
If you're using Debian/Ubuntu please check deb-packages folder. Choose appropriate architecture, then run following command with root privileges:
2033
```sh
2134
# dpkg -i tuninetd_ver_arch.deb
@@ -27,9 +40,9 @@ To install from sources download src folder. In case Debian/Ubuntu, you should a
2740
# make
2841
```
2942

30-
Congrats! Tuninend is ready to use. Check ./bin folder. :)
43+
Congrats! Tuninend ready to use. Check ./bin folder.
3144

32-
### Usage:
45+
### 3. Usage:
3346

3447
tuninetd {-i \<ifname> | -n \<nflog-group>} -c \<path> [-m \<iftype>] [-f \<filter>] [-t \<ttl>] [-d]
3548

@@ -40,12 +53,12 @@ tuninetd {-i \<ifname> | -n \<nflog-group>} -c \<path> [-m \<iftype>] [-f \<filt
4053
**-f \<filter>**: specify pcap filter, similar to tcpdump<br/>
4154
**-t \<ttl>**: seconds of interface (traffic) idle, before 'stop' command (default is 600).<br/>
4255
**-d**: demonize process<br/>
43-
**-h**: prints this help
56+
**-h**: print this help
4457

4558
`--- If tuninetd stuck in start condition for any reason, you can reset to "standby" (i.e. stop state) with SIGHUP. ---`
4659

47-
### Examples:
48-
Before launching as daemon make sure there is no errors occurs. In daemon mode tuninetd write status messages and errors to syslog.
60+
### 4. Examples:
61+
Before launching as a daemon make sure there is no errors. In daemon mode tuninetd write status messages and errors to syslog.
4962

5063
```sh
5164
# tuninetd -i tun0 -c /test/runtunnel.sh -f "! host 1.2.3.4" -t 3600 -d
@@ -56,13 +69,11 @@ Check ```example``` folder to find some shell scripts.
5669

5770
To create and bring up ```tun``` device, could be used following commands:
5871
```sh
59-
# ip tuntap add name tun0 mode tun
72+
# ip tuntap add dev tun0 mode tun
6073
# ip link set tun0 up
6174
```
6275

63-
For more information about routing and configuring net devices, I strongly suggest LARCT how-to.
64-
65-
*! Notice ! Modern Linux distributions periodically send 'icmpv6 router solicitation' packets, which cause tuninetd keep or change its status (calling 'start' script for example). This situation appears in tun/tap mode without pcap filter applied.*
76+
For more information about routing and configuring network devices, I strongly suggest LARCT how-to.
6677

6778
### License:
6879
MIT
7.25 KB
Binary file not shown.

src/Makefile

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,26 @@
1-
all: default
2-
default: main.c
1+
all: tuninetd
2+
tuninetd: main.o nflog.o pcap.o thread.o tun.o utils.o
33
[ -d ./bin ] || mkdir -p ./bin
4-
gcc -o ./bin/tuninetd main.c -lpthread -lpcap -lnetfilter_log
4+
gcc main.o nflog.o pcap.o thread.o tun.o utils.o -o ./bin/tuninetd -lpthread -lpcap -lnetfilter_log
5+
6+
main.o: main.c main.h
7+
gcc -c main.c
8+
9+
nflog.o: nflog.c main.h
10+
gcc -c nflog.c
11+
12+
pcap.o: pcap.c main.h
13+
gcc -c pcap.c
14+
15+
thread.o: thread.c main.h
16+
gcc -c thread.c
17+
18+
tun.o: tun.c main.h
19+
gcc -c tun.c
20+
21+
utils.o: utils.c main.h
22+
gcc -c utils.c
23+
524
clean:
25+
rm -f *.o tuninetd
626
rm -rf ./bin

src/main.c

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ int main(int argc, char *argv[])
66

77
struct timespec tim;
88

9+
//debug = 1;
10+
911
tim.tv_sec = 1;
1012
tim.tv_nsec = 0;
1113

12-
static const char *optString = "i:t:c:f:m:n:dh";
14+
static const char *optString = "i:t:c:f:m:n:dhv";
1315

1416
curts = time(NULL);
1517

@@ -24,6 +26,9 @@ int main(int argc, char *argv[])
2426

2527
while( opt != -1 ) {
2628
switch( opt ) {
29+
case 'v':
30+
version();
31+
exit(0);
2732
case 'i':
2833
globcfg.dev_name = optarg;
2934
break;
@@ -56,7 +61,7 @@ int main(int argc, char *argv[])
5661
case 'd':
5762
globcfg.isdaemon = 1;
5863
break;
59-
case 'h': /* намеренный проход в следующий case-блок */
64+
case 'h': //go to the next case, same behaviour.
6065
case '?':
6166
usage();
6267
break;
@@ -80,11 +85,6 @@ int main(int argc, char *argv[])
8085
exit(1);
8186
}
8287

83-
if (pthread_mutex_init(&lock, NULL) != 0)
84-
{
85-
my_err("Mutex init failed. Abort.");
86-
exit(1);
87-
}
8888

8989
if (globcfg.isdaemon == 1) {
9090
globcfg.pid = fork();
@@ -110,28 +110,18 @@ int main(int argc, char *argv[])
110110
} else
111111
my_info("Started with pid %d", getpid());
112112

113-
114-
pthread_attr_init(&attr);
115-
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
116-
117-
if (globcfg.nf_group < 0) {
118-
my_info("Binding to interface %s", globcfg.dev_name);
119-
pthread_create(&pcap_x_thread, &attr, pcap_x, &x);
120-
pthread_create(&tun_x_thread, &attr, tun_x, &y);
121-
} else {
122-
my_info("Start listening nflog-group %i", globcfg.nf_group);
123-
pthread_create(&nflog_x_thread, &attr, nflog_x, &y);
124-
}
113+
thread_init(); //Initialization our workers (thread.c)
125114

126115
if (signal(SIGHUP, sig_handler) == SIG_ERR)
127116
my_info("Can't catch SIGHUP\n");
128117

129118

130119
while (1) {
131120

132-
nanosleep(&tim, NULL);
121+
nanosleep(&tim, NULL); //Tick
133122

134123
curts = time(NULL);
124+
//do_debug("Tick %lu ...\n", curts);//
135125

136126
if (ts != 0 && status == 1 && ((curts - ts) >= globcfg.ttl) ) {
137127
my_info("CORE: executing STOP command...");

src/main.h

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,27 @@
1+
#ifndef H_TUNINETD_MAIN
2+
#define H_TUNINETD_MAIN
3+
14
#include <fcntl.h>
2-
#include <pthread.h>
3-
#include <pcap.h>
45
#include <stdio.h>
56
#include <stdlib.h>
67
#include <string.h>
8+
#include <sys/ioctl.h>
79
#include <net/if.h>
810
#include <linux/if_tun.h>
9-
#include <sys/ioctl.h>
10-
#include <stdarg.h>
11-
#include <syslog.h>
1211
#include <unistd.h>
1312
#include <signal.h>
1413
#include <time.h>
1514

16-
#include <libnetfilter_log/libnetfilter_log.h>
17-
18-
1915
#define BUFSIZE 2000
2016
#define ON 1
2117
#define OFF 0
18+
#define VERSION "\ntuninetd 1.2.1\n"
2219

23-
int x, y;
24-
25-
short int debug = 0;
26-
short int status = 0;
27-
unsigned long ts = 0;
28-
unsigned long curts = 0;
29-
30-
char progname[] = "tuninetd";
20+
//global vars.
21+
short int debug;
22+
short int status;
23+
unsigned long ts;
24+
unsigned long curts;
3125

3226
struct globcfg_t {
3327
short int isdaemon;
@@ -42,24 +36,21 @@ struct globcfg_t {
4236
int ttl;
4337
} globcfg;
4438

45-
pthread_t pcap_x_thread;
46-
pthread_t tun_x_thread;
47-
pthread_t nflog_x_thread;
4839

49-
pthread_attr_t attr;
50-
pthread_mutex_t lock;
51-
40+
//from utils.c
5241
void do_debug(char *msg, ...);
5342
void my_err(char *msg, ...);
5443
void my_info(char *msg, ...);
55-
void switch_state(short action);
44+
void sig_handler(int signo);
45+
void usage();
46+
void version();
47+
48+
//from thread.c
5649
void switch_guard(short action);
50+
void thread_init();
5751

5852
void *tun_x(void *x_void_ptr);
5953
void *nflog_x(void *x_void_ptr);
6054
void *pcap_x(void *x_void_ptr);
6155

62-
#include "utils.c"
63-
#include "tun.c"
64-
#include "pcap.c"
65-
#include "nflog.c"
56+
#endif

src/nflog.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#include "main.h"
2+
#include <libnetfilter_log/libnetfilter_log.h>
3+
14
static int callback(struct nflog_g_handle *gh, struct nfgenmsg *nfmsg, struct nflog_data *ldata, void *data)
25
{
36
if (status == OFF) {

src/pcap.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
#include "main.h"
2+
#include <pcap.h>
3+
14
static void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
25
{
36
ts = header->ts.tv_sec;
7+
//do_debug("Packet timestamp %lu ...\n", ts);
48
}
59

610
void *pcap_x(void *x_void_ptr)

src/thread.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#include "main.h"
2+
#include <pthread.h>
3+
4+
static pthread_t pcap_x_thread;
5+
static pthread_t tun_x_thread;
6+
static pthread_t nflog_x_thread;
7+
8+
static pthread_attr_t attr;
9+
static pthread_mutex_t lock;
10+
11+
static int x, y;
12+
13+
void thread_init()
14+
{
15+
if (pthread_mutex_init(&lock, NULL) != 0) {
16+
my_err("Mutex init failed. Abort.");
17+
exit(1);
18+
}
19+
20+
pthread_attr_init(&attr);
21+
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
22+
23+
if (globcfg.nf_group < 0) {
24+
my_info("Binding to interface %s", globcfg.dev_name);
25+
pthread_create(&pcap_x_thread, &attr, pcap_x, &x);
26+
pthread_create(&tun_x_thread, &attr, tun_x, &y);
27+
} else {
28+
my_info("Start listening nflog-group %i", globcfg.nf_group);
29+
pthread_create(&nflog_x_thread, &attr, nflog_x, &y);
30+
}
31+
}
32+
33+
void switch_state(short action)
34+
{
35+
if (status == action) {
36+
return;
37+
}
38+
39+
ts = time(NULL);
40+
41+
if (action == ON) {
42+
if (system(globcfg.cmd_path_start) != 0)
43+
my_err("Warning! Executable command doesn't return 0 (%s)", globcfg.cmd_path_start);
44+
45+
status = ON;
46+
47+
} else {
48+
if (system(globcfg.cmd_path_stop) != 0)
49+
my_err("Warning! Executable command doesn't return 0 (%s)", globcfg.cmd_path_stop);
50+
51+
status = OFF;
52+
53+
if (globcfg.nf_group < 0)
54+
pthread_create(&tun_x_thread, &attr, tun_x, &y);
55+
56+
}
57+
}
58+
59+
void switch_guard(short action)
60+
{
61+
pthread_mutex_lock(&lock);
62+
switch_state(action);
63+
pthread_mutex_unlock(&lock);
64+
}

src/tun.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#include "main.h"
2+
13
static int tun_alloc(char *dev, int flags)
24
{
35
struct ifreq ifr;
@@ -46,7 +48,7 @@ void *tun_x(void *x_void_ptr)
4648
struct timespec tim;
4749

4850
tim.tv_sec = 0;
49-
tim.tv_nsec = 15000000;
51+
tim.tv_nsec = 20000000;
5052

5153

5254
if ( (tap_fd = tun_alloc(globcfg.dev_name, globcfg.dev_mode | IFF_NO_PI)) < 0 ) {
@@ -59,9 +61,11 @@ void *tun_x(void *x_void_ptr)
5961

6062
if (globcfg.pcap_filter != NULL) {
6163
nanosleep(&tim, NULL);
62-
if ( (curts - ts) < 2 ) {
63-
do_debug("Read %d bytes from the tap interface\n", nread);
64+
if ( (long)(curts - ts) < 2 ) {
65+
//do_debug("Read %d bytes from the tap interface\n", nread);
6466
break;
67+
} else {
68+
//do_debug("Delta is not small enough...\n");
6569
}
6670
} else {
6771
break;

0 commit comments

Comments
 (0)