-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
431 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
first: main.c | ||
gcc -o tuninetd main.c -lpthread -lpcap |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,44 @@ | ||
# tuninetd | ||
# Tuninetd | ||
|
||
**tuninetd** - is a simple daemon for tun/tap devices, similar to classic inetd by its logic, but for mentioned interfaceces, instead of a ports. | ||
|
||
#### How it works: | ||
First, you create and configure tun/tap device, then run **tuninetd**. It start listening on that interface, until network packet will be received. | ||
Next, interface will be released and certain command is executed. From now on, daemon in monitoring state. | ||
After N seconds of interface idle, tuninetd send "stop" command by path, that you define, and start listening interface by its own again. | ||
|
||
Since, **tuninetd** based on **libpcap**, you can specify filter to trigging "start" event and monitoring iddle (i.e. cutoff unwanted traffic). | ||
To test/debug filters rules - use tcpdump, because it built upon the same library. | ||
|
||
**tuninetd** allows you deploy "VPN by demand" or any other "by demand" services, which is the main idea of the project. | ||
|
||
#### Installation: | ||
To build tuninetd, you need to have libpcap-dev library (Debian)<br/> | ||
Download all files and: | ||
```sh | ||
# cd /folder/with/sourcefiles | ||
# make | ||
``` | ||
|
||
#### Usage: | ||
|
||
tuninetd -i \<ifname> -c \<path> [-m \<iftype>] [-f <filter>] [-t \<ttl>] [-d] | ||
|
||
**-i \<ifname>**: interface to use (tun or tap). Must be up and configured.<br/> | ||
**-c \<path>**: will be executed with 'start' and 'stop' parameter.<br/> | ||
**-m \<iftype>**: 'tun' or 'tap' mode. By default 'tun', should be set properly.<br/> | ||
**-f \<filter>**: specify pcap filter, similar to tcpdump<br/> | ||
**-t \<ttl>**: seconds of interface idle, before 'stop' command (default is 600).<br/> | ||
**-d**: demonize process<br/> | ||
**-h**: prints this help text | ||
|
||
#### Example: | ||
```sh | ||
# tuninetd -i tun0 -c /test/runtunnel.sh -f "! host 1.2.3.4" -t 3600 -d | ||
``` | ||
|
||
### License: | ||
MIT | ||
### Author: | ||
Paul aka root4root \<root4root at gmail dot com><br/> | ||
**Any suggestions will be appreciated.** |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
//Author: root4root@gmail.com | ||
|
||
#include <fcntl.h> | ||
#include <pthread.h> | ||
#include <pcap.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <net/if.h> | ||
#include <linux/if_tun.h> | ||
#include <sys/ioctl.h> | ||
#include <stdarg.h> | ||
#include <syslog.h> | ||
#include <unistd.h> | ||
|
||
#define BUFSIZE 2000 | ||
|
||
int debug = 0; | ||
int status = 0; | ||
long ts = 0; | ||
long curts = 0; | ||
|
||
char progname[] = "tuninetd"; | ||
|
||
struct globcfg_t { | ||
int isdaemon; | ||
pid_t pid; | ||
char *cmd_path; | ||
char *cmd_path_start; | ||
char *cmd_path_stop; | ||
char *pcap_filter; | ||
char *dev_name; | ||
int dev_mode; | ||
int ttl; | ||
} globcfg; | ||
|
||
#include "utils.c" | ||
#include "tun.c" | ||
#include "pcap.c" | ||
|
||
int main(int argc, char *argv[]) | ||
{ | ||
int x, y, opt=0; | ||
|
||
static const char *optString = "i:t:c:f:m:dh"; | ||
|
||
curts = time(NULL); | ||
|
||
globcfg.isdaemon = 0; | ||
globcfg.pid = 0; | ||
globcfg.cmd_path = NULL; | ||
globcfg.ttl = 600; | ||
globcfg.dev_mode = IFF_TUN; | ||
|
||
opt = getopt( argc, argv, optString); | ||
|
||
while( opt != -1 ) { | ||
switch( opt ) { | ||
case 'i': | ||
globcfg.dev_name = optarg; | ||
break; | ||
case 't': | ||
globcfg.ttl = atoi(optarg); | ||
break; | ||
case 'c': | ||
globcfg.cmd_path = optarg; | ||
|
||
globcfg.cmd_path_start = malloc(strlen(optarg) + 23); | ||
strcpy(globcfg.cmd_path_start, optarg); | ||
strcat(globcfg.cmd_path_start, " start > /dev/null 2>&1"); | ||
|
||
globcfg.cmd_path_stop = malloc(strlen(optarg) + 22); | ||
strcpy(globcfg.cmd_path_stop, optarg); | ||
strcat(globcfg.cmd_path_stop, " stop > /dev/null 2>&1"); | ||
break; | ||
|
||
case 'f': | ||
globcfg.pcap_filter = optarg; | ||
break; | ||
case 'm': | ||
if (strcmp("tap", optarg)== 0) { | ||
globcfg.dev_mode = IFF_TAP; | ||
} | ||
break; | ||
case 'd': | ||
globcfg.isdaemon = 1; | ||
break; | ||
case 'h': /* намеренный проход в следующий case-блок */ | ||
case '?': | ||
usage(); | ||
break; | ||
default: | ||
exit(1); | ||
break; | ||
} | ||
|
||
opt = getopt( argc, argv, optString ); | ||
} | ||
|
||
if (globcfg.dev_name == NULL) { | ||
my_err("tun/tap device must be specified with proper type (-m by default tun)."); | ||
usage(); | ||
exit(1); | ||
} | ||
|
||
if (globcfg.cmd_path == NULL) { | ||
my_err("Executable path must be specified"); | ||
usage(); | ||
exit(1); | ||
} | ||
|
||
if (globcfg.isdaemon == 1) { | ||
globcfg.pid = fork(); | ||
|
||
if (globcfg.pid < 0) { | ||
my_err("Can't fork process. Abort."); | ||
exit(1); | ||
} | ||
|
||
if (globcfg.pid > 0) { | ||
my_info("---"); | ||
my_info("Success! tuninetd has been started with pid: %i", globcfg.pid); | ||
exit(0); | ||
} | ||
|
||
chdir("/"); | ||
|
||
setsid(); | ||
|
||
close(STDIN_FILENO); | ||
close(STDOUT_FILENO); | ||
close(STDERR_FILENO); | ||
} | ||
|
||
pthread_t inc_x_thread; | ||
pthread_t tun_x_thread; | ||
|
||
pthread_attr_t attr; | ||
|
||
pthread_attr_init(&attr); | ||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); | ||
|
||
pthread_create(&inc_x_thread, &attr, inc_x, &x); | ||
pthread_create(&tun_x_thread, &attr, tun_x, &y); | ||
|
||
while (1) { | ||
usleep(1000000); | ||
curts = time(NULL); | ||
|
||
if (ts != 0 && status == 1 && ((curts - ts) >= globcfg.ttl) ) { | ||
status = 0; | ||
my_info("Executing STOP command... Binding again to interface %s", globcfg.dev_name); | ||
|
||
if (system(globcfg.cmd_path_stop) != 0) { | ||
my_err("Warning! Executable command doesn't return 0 (%s)", globcfg.cmd_path_stop); | ||
} | ||
|
||
pthread_create(&tun_x_thread, &attr, tun_x, &y); | ||
} | ||
} | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
//Author: root4root@gmail.com | ||
|
||
void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) | ||
{ | ||
ts = header->ts.tv_sec; | ||
} | ||
|
||
|
||
void *inc_x(void *x_void_ptr) | ||
{ | ||
struct bpf_program filter; | ||
|
||
char errbuf[PCAP_ERRBUF_SIZE]; | ||
pcap_t *handle; | ||
|
||
handle = pcap_open_live(globcfg.dev_name, BUFSIZ, 0, 10, errbuf); | ||
|
||
if (handle == NULL) { | ||
my_err("Pcap: unable to open interface. %s", errbuf); | ||
exit(1); | ||
} | ||
|
||
if (globcfg.pcap_filter != NULL) { | ||
if (pcap_compile(handle, &filter, globcfg.pcap_filter, 0, PCAP_NETMASK_UNKNOWN) != 0) { | ||
my_err("Wrong libpcap filter: \"%s\"", globcfg.pcap_filter); | ||
exit(1); | ||
} | ||
|
||
pcap_setfilter(handle, &filter); | ||
} | ||
|
||
pcap_loop(handle, -1, got_packet, NULL); | ||
|
||
pcap_close(handle); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
#!/bin/bash | ||
|
||
#This is just example of how executable script, which run from tuninetd, may looks like. | ||
#Accepts 'start' or 'stop' parameter. | ||
#Author: root4root@gmail.com | ||
|
||
controlFile='/var/run/ssh-myvpn-tunnel-control' | ||
remoteHost='1.2.3.4' | ||
|
||
function up() | ||
{ | ||
if [ ! -S $controlFile ] | ||
then | ||
/usr/bin/ssh -S $controlFile -M -f -w 0:0 $remoteHost ifconfig tun0 10.10.10.1/30 pointopoint 10.10.10.2 | ||
exit 0 | ||
else | ||
echo 'Tunnel already up!' | ||
exit 1 | ||
fi | ||
} | ||
|
||
function down() | ||
{ | ||
if [ -S $controlFile ] | ||
then | ||
/usr/bin/ssh -S $controlFile -O exit $remoteHost | ||
exit 0 | ||
else | ||
echo 'Tunnel already down!' | ||
exit 1 | ||
fi | ||
} | ||
|
||
case $1 in | ||
'start') | ||
up | ||
;; | ||
'stop' ) | ||
down | ||
;; | ||
*) | ||
echo 'Usage: start|stop' | ||
;; | ||
esac | ||
|
||
exit 1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
//Author: root4root@gmail.com | ||
|
||
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 ) { | ||
my_err("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; | ||
} | ||
|
||
int cread(int fd, char *buf, int n) | ||
{ | ||
int nread; | ||
|
||
if ((nread = read(fd, buf, n)) < 0) { | ||
my_err("Error, while reading data. Abort."); | ||
exit(1); | ||
} | ||
|
||
return nread; | ||
} | ||
|
||
void *tun_x(void *x_void_ptr) | ||
{ | ||
int tap_fd; | ||
int nread; | ||
char buffer[BUFSIZE]; | ||
|
||
|
||
if ( (tap_fd = tun_alloc(globcfg.dev_name, globcfg.dev_mode | IFF_NO_PI)) < 0 ) { | ||
my_err("Error connecting to tun/tap interface %s. Abort.", globcfg.dev_name); | ||
exit(1); | ||
} | ||
|
||
while(1) { | ||
nread = cread(tap_fd, buffer, BUFSIZE); | ||
|
||
if (globcfg.pcap_filter != NULL) { | ||
usleep(15000); //Wait for libpcap time out. | ||
if ( (curts - ts) < 2 ) { | ||
do_debug("Read %d bytes from the tap interface\n", nread); | ||
break; | ||
} | ||
} else { | ||
break; | ||
} | ||
} | ||
|
||
ts = time(NULL); | ||
|
||
status = 1; | ||
|
||
close(tap_fd); | ||
|
||
my_info("Executing START command..."); | ||
|
||
if (system(globcfg.cmd_path_start) != 0) { | ||
my_err("Warning! Executable command doesn't return 0 (%s)", globcfg.cmd_path_start); | ||
} | ||
|
||
return 0; | ||
} |
Oops, something went wrong.