diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..ee4c50d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +* text=auto +*.c text=text +*.h text=text +Makefile text eol=cr diff --git a/.gitignore b/.gitignore index c6127b3..a3cf4dc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,9 @@ # Prerequisites *.d +.idea +depend +port-open +port-close # Object files *.o diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5c4e678 --- /dev/null +++ b/Makefile @@ -0,0 +1,63 @@ +# Generic MinGW makefile (C source only) +# Modify variables/macros to fit your program + +INSTALL_DIR=/usr/local +SBIN_DIR=$(INSTALL_DIR)/sbin + +# make / make all | will compile your program. +# make clean | deletes all compiled object and executable files. +# make depend | rebuilds the dependancy list +# make run | compiles (if needed) and runs your program + +# Compiler command +CC = gcc + +# Linker command +LD = gcc + +# Flags to pass to the compiler - add "-g" to include debug information +CFLAGS = -Wall + +# Flags to pass to the linker +LDFLAGS = + +# Command used to delete files +RM = rm + +# List your object files here +OBJS = port-open.o + +# List your source files here +SRCS = port-open.c + +# Define your compile target here. +PROG = port-open + +# Compile everything. +all: $(PROG) + +# Link the program +$(PROG): $(OBJS) + $(LD) $(LDFLAGS) $(OBJS) -s -o $(PROG) + +# All .o files depend on their corresponding .c file +%.o: %.c + $(CC) $(CFLAGS) -c $< + +install: + cp -a port-open $(SBIN_DIR)/ + cd $(SBIN_DIR) && ln -fs port-open port-close + +clean: + $(RM) -f $(PROG) + $(RM) -f *.o port-close + +distclean: clean + $(RM) -f depend + + +depend: + $(CC) $(CFLAGS) -MM $(SRCS) > depend + + +include depend diff --git a/README.md b/README.md index 506c1bc..6fe2934 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,52 @@ # knockd-tools Tools to use with Judd Vinet's knockd + +## ABOUT + +This set of tools to use with [Judd Vinet's knockd](https://zeroflux.org/projects/knock) port-knocking server/client. +The same functionality can be accomplished with a small script, but port-close which will stay in ram for hours and +maybe days uses very little ram. + +## INSTALL + +To install the tools in /usr/local/sbin run: + + $ make + $ sudo make install + +If you want other directories, edit Makefile and change: + + INSTALL_DIR=/usr/local + SBIN_DIR=$(INSTALL_DIR)/sbin + +Or simply copy port-open to whatever dir you want and make a sym or hard link port-close pointing to port-open + +## EXAMPLE + +First you need to create **iptables** rules: + + iptables -N knock + iptables -I INPUT -j knock + +For example configuration check `knockd-example.conf` + +## TEST + +To test your installation you can run: + + iptables -N knock + port-open 8.8.8.8 80 20 + watch iptables -xvnL knock + +You should see a rule accepting connections from 8.8.8.8 on port 80. After after 20 seconds the rule should disappear. + + + Chain knock (1 references) + pkts bytes target prot opt in out source destination + 0 0 ACCEPT tcp -- * * 8.8.8.8 0.0.0.0/0 tcp dpt:80 + + +## LINKS + + * [Judd Vinet's knockd](https://zeroflux.org/projects/knock) + diff --git a/knockd-example.conf b/knockd-example.conf new file mode 100644 index 0000000..e9db00e --- /dev/null +++ b/knockd-example.conf @@ -0,0 +1,31 @@ +[options] + logfile = /var/log/knockd.log + Interface = eth1 +# Interface = eth0 + + +[openSSH] + sequence = 1,2,3,4 + seq_timeout = 10 + command = /usr/local/sbin/port-open %IP% 22 18000 + tcpflags = syn + +[openSSH2d] + sequence = 5,6,7,8 + seq_timeout = 10 +# timeout = 3600*24*2 + command = /usr/local/sbin/port-open %IP% 22 172800 + tcpflags = syn + +[closeSSH] + sequence = 4,3,2,1 + seq_timeout = 5 + command = /usr/local/sbin/port-close %IP% 22 + tcpflags = syn + +[beep] + sequence = 2000,3000,4000 + seq_timeout = 10 + command = echo "beep" >> /tmp/beep.log + tcpflags = syn + diff --git a/port-open.c b/port-open.c new file mode 100644 index 0000000..8c82aca --- /dev/null +++ b/port-open.c @@ -0,0 +1,206 @@ +/** + * Compile: + * gcc -s -o port-open port-open.c + * cp -a port-open /usr/local/sbin + * cd /usr/local/sbin + * ln -sf port-open port-close + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define IPTABLES_OPEN_CMD "/sbin/iptables -A knock -s %s -p tcp --dport %d -j ACCEPT >/dev/null" +#define IPTABLES_CLOSE_CMD "/sbin/iptables -D knock -s %s -p tcp --dport %d -j ACCEPT >/dev/null 2>&1" + +#define PROG_PORT_OPEN 1 +#define PROG_PORT_CLOSE 2 + +char *name; +char progPath[1026]; +bool hasDir = false; +int program = 1; +long timeout = 0; + +bool verifyIp(const char *ip); +bool verifyPort(long port); + +void usageOpen(){ + printf("Adds ACCEPT rule for a given IP and port using iptables. If timeout is grater than 0 starts port-close with the same parameters:\n"); + printf("Usage:\n"); + printf(" %s [timeout=0]\n", name); +} + +void usageClose(){ + printf("Removes the iptables ACCEPT rule, previously added with port-open after timeout seconds.\n"); + printf("Usage:\n"); + printf(" %s [timeout=0]\n", name); +} + +void usage() { + switch(program){ + case PROG_PORT_OPEN: + usageOpen(); + break; + case PROG_PORT_CLOSE: + usageClose(); + break; + } +} + +int portOpen(int argc, char **argv){ + long tmp; + char **endPtr = NULL; + + if(argc < 3){ + usageOpen(); + return 1; + } + + const char *ip = argv[1]; + if(!verifyIp(ip)) + return 1; + + tmp = strtol(argv[2], endPtr, 10); + const int port = (int) tmp; + if(!verifyPort(port)) + return 1; + + if(argc > 3){ + timeout=strtol(argv[3], endPtr, 10); + } + + char *cmd = malloc(1500); + sprintf(cmd, IPTABLES_OPEN_CMD, ip, (int)port); +// printf("running cmd: %s\n", cmd); + system(cmd); + + if(timeout > 0) { + sprintf(cmd, "%sport-close %s %d %d", progPath, ip, (int)port, (int)timeout); +// printf("port close cmd: %s\n", cmd); + system(cmd); + } + free(cmd); + + return 0; +} + +int portClose(int argc, char **argv){ + long tmp; + char **endPtr = NULL; + + //printf("%d\n", argc); + if(argc < 3){ + usageClose(); + return 1; + } + + const char *ip = argv[1]; + if(!verifyIp(ip)) + return 1; + + tmp = strtol(argv[2], endPtr, 10); + const int port = (int) tmp; + if(!verifyPort(port)) + return 1; + + if(argc > 3){ + timeout=strtol(argv[3], endPtr, 10); + } + + //printf("%d\n", timeout); + if(timeout > 0) { + // drop stdout and stderr + close(STDOUT_FILENO); + close(STDERR_FILENO); + if(fork() != 0) { + // parent + return 0; + } + + sleep(timeout); + } + char *cmd = malloc(1500); + sprintf(cmd, IPTABLES_CLOSE_CMD, ip, port); +// printf("running cmd: %s\n", cmd); + system(cmd); + free(cmd); + return 0; +} + +bool verifyIp(const char *ip){ + if(strlen(ip)<7){ + printf("IP should be least 7 characters\n"); + usage(); + return false; + } + if(strlen(ip)>15){ + printf("IP should be max 15 characters\n"); + usage(); + return false; + } + return true; +} + +bool verifyPort(long port) { + if(port<0) { + printf("port cannot be negative"); + usage(); + return false; + } + if(port>65535) { + printf("port must be less than 65535"); + usage(); + return false; + } + if(port==0) { + printf("Port must be grater than 0"); + usage(); + return false; + } + return true; +} + +int main(int argc, char **argv){ + + if(argc<1){ + printf("argc < 1 !!!\n"); + } + name = basename(argv[0]); + if(strcmp(name, "port-open") == 0){ + program = PROG_PORT_OPEN; + }else if(strcmp(name, "port-close") == 0) { + program = PROG_PORT_CLOSE; + } + + char *dirTemp = dirname(argv[0]); + if (strlen(dirTemp) > 1024) { + printf("Can't work with paths longer than 1024 chars\n"); + return 1; + } + if(strchr(argv[0], '/') == NULL) { + progPath[0] = 0; + }else { + strncpy(progPath, dirTemp, 1024); + int len = strlen(progPath); + progPath[len-1] = '/'; + progPath[len] = 0; + } + + switch(program){ + case PROG_PORT_OPEN: + portOpen(argc, argv); + break; + case PROG_PORT_CLOSE: + portClose(argc, argv); + break; + } + + return 0; +} +