Skip to content

Commit

Permalink
Merge pull request #3 from limithit/limithit-patch-ipset
Browse files Browse the repository at this point in the history
Add ipset support
  • Loading branch information
limithit authored Apr 8, 2019
2 parents e3483f7 + 3c458f2 commit 543f031
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 90 deletions.
8 changes: 3 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@

# find the OS
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')

# Compile flags for linux / osx
ifeq ($(uname_S),Linux)
SHOBJ_CFLAGS ?= -W -Wall -fno-common -g -ggdb -std=c99 -O2
SHOBJ_CFLAGS ?= -W -Wall -fno-common -g -ggdb -std=c99 -O2
SHOBJ_LDFLAGS ?= -shared
else
SHOBJ_CFLAGS ?= -W -Wall -dynamic -fno-common -g -ggdb -std=c99 -O2
SHOBJ_CFLAGS ?= -W -Wall -dynamic -fno-common -g -ggdb -std=c99 -O2
SHOBJ_LDFLAGS ?= -bundle -undefined dynamic_lookup
endif

Expand All @@ -16,7 +14,7 @@ endif
all: iptablespush.so ttl_iptables

ttl_iptables: ttl_iptables.c
$(CC) ttl_iptables.c -o $@ -I/usr/local/include/hiredis -lhiredis
$(CC) ttl_iptables.c -o $@ -I/usr/local/include/hiredis -lhiredis $(CFLAGS)

.c.xo:
$(CC) -I. $(CFLAGS) $(SHOBJ_CFLAGS) -fPIC -c $< -o $@
Expand Down
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,18 @@ ACCEPT all -- 192.168.188.8 0.0.0.0/0
#2: git clone https://github.com/limithit/RedisPushIptables.git
cd RedisPushIptables
make
make #OR make CFLAGS=-DWITH_IPSET
make install
```
If you need to enable ipset, you must configure the following settings
```
#ipset create block_ip hash:ip timeout 60 hashsize 4096 maxelem 10000000
#iptables -I INPUT -m set --match-set block_ip src -j DROP
#ipset create allow_ip hash:ip timeout 60 hashsize 4096 maxelem 10000000
#iptables -I INPUT -m set --match-set allow_ip src -j ACCEPT
```
The parameter `timeout` has the same effect as `ttl.drop.insert`. If `timeout` is configured, ipset is used to implement periodic deletion. If the `timeout` is not configured, it is periodically removed using `ttl.drop.insert`.

## HOWTOs
In theory, except for the C language native support API call, the corresponding library before the other language API calls must be re-encapsulated because the third-party modules are not supported by other languages. Only C, Python, Bash, Lua are shown here, and the principles of other languages are the same.

Expand Down
195 changes: 112 additions & 83 deletions iptablespush.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,44 +12,37 @@
#include <sys/types.h>
#include <sys/wait.h>

int redis_waitpid(pid_t pid)
{
int rc, status;
do
{
if (-1 == (rc = waitpid(pid, &status, WUNTRACED)))
{
int redis_waitpid(pid_t pid) {
int rc, status;
do {
if (-1 == (rc = waitpid(pid, &status, WUNTRACED))) {
goto exit;
}
}
while (!WIFEXITED(status) && !WIFSIGNALED(status));
exit:
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
exit:

return rc;
}

int execute_fork()
{
int execute_fork() {
fflush(stdout);
fflush(stderr);
return fork();
}

int execute_popen(pid_t *pid, const char *command)
{
int fd[2];
int execute_popen(pid_t *pid, const char *command) {
int fd[2];

if (-1 == pipe(fd))
return -1;

if (-1 == (*pid = execute_fork()))
{
if (-1 == (*pid = execute_fork())) {
close(fd[0]);
close(fd[1]);
return -1;
}

if (0 != *pid) /* parent process */
if (0 != *pid) /* parent process */
{
close(fd[1]);
return fd[0];
Expand All @@ -59,33 +52,42 @@ int execute_popen(pid_t *pid, const char *command)
dup2(fd[1], STDOUT_FILENO);
dup2(fd[1], STDERR_FILENO);
close(fd[1]);
if (-1 == setpgid(0, 0))
{
if (-1 == setpgid(0, 0)) {
exit(EXIT_SUCCESS);
}

execl("/bin/sh", "sh", "-c", command, NULL);
exit(EXIT_SUCCESS);
}

int DROP_Insert_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
int DROP_Insert_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (argc != 2)
return RedisModule_WrongArity(ctx);

RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1],
REDISMODULE_READ | REDISMODULE_WRITE);
pid_t pid;
int fd;
char tmp_buf[4096];

#ifdef WITH_IPSET
static char insert_command[256];
sprintf(insert_command, "ipset add block_ip %s",
RedisModule_StringPtrLen(argv[1], NULL));
#else
static char check_command[256], insert_command[256];
char tmp_buf[4096];
sprintf(check_command, "iptables -C INPUT -s %s -j DROP",
RedisModule_StringPtrLen(argv[1], NULL));
sprintf(insert_command, "iptables -I INPUT -s %s -j DROP",
RedisModule_StringPtrLen(argv[1], NULL));
#endif
printf("%s || %s\n", RedisModule_StringPtrLen(argv[0], NULL),
RedisModule_StringPtrLen(argv[1], NULL));
#ifdef WITH_IPSET
fd = execute_popen(&pid, insert_command);
redis_waitpid(pid);
close(fd);
#else
fd = execute_popen(&pid, check_command);
redis_waitpid(pid);
if (0 < read(fd, tmp_buf, sizeof(tmp_buf) - 1)) {
Expand All @@ -94,16 +96,15 @@ int DROP_Insert_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int
redis_waitpid(pid);
}
close(fd);

#endif
RedisModule_StringSet(key, argv[1]);
size_t newlen = RedisModule_ValueLength(key);
RedisModule_CloseKey(key);
RedisModule_ReplyWithLongLong(ctx, newlen);
return REDISMODULE_OK;
}

int DROP_Delete_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
int DROP_Delete_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (argc != 2)
return RedisModule_WrongArity(ctx);

Expand All @@ -112,9 +113,13 @@ int DROP_Delete_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int
pid_t pid;
int fd;
static char insert_command[256];

#ifdef WITH_IPSET
sprintf(insert_command, "ipset del block_ip %s",
RedisModule_StringPtrLen(argv[1], NULL));
#else
sprintf(insert_command, "iptables -D INPUT -s %s -j DROP",
RedisModule_StringPtrLen(argv[1], NULL));
#endif
printf("%s || %s\n", RedisModule_StringPtrLen(argv[0], NULL),
RedisModule_StringPtrLen(argv[1], NULL));

Expand All @@ -128,24 +133,34 @@ int DROP_Delete_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int
RedisModule_ReplyWithLongLong(ctx, newlen);
return REDISMODULE_OK;
}
int ACCEPT_Insert_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
int ACCEPT_Insert_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (argc != 2)
return RedisModule_WrongArity(ctx);

RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1],
REDISMODULE_READ | REDISMODULE_WRITE);
pid_t pid;
int fd;
char tmp_buf[4096];

#ifdef WITH_IPSET
static char insert_command[256];
sprintf(insert_command, "ipset add allow_ip %s",
RedisModule_StringPtrLen(argv[1], NULL));
#else
char tmp_buf[4096];
static char check_command[256], insert_command[256];
sprintf(check_command, "iptables -C INPUT -s %s -j ACCEPT",
RedisModule_StringPtrLen(argv[1], NULL));
sprintf(insert_command, "iptables -I INPUT -s %s -j ACCEPT",
RedisModule_StringPtrLen(argv[1], NULL));
#endif
printf("%s || %s\n", RedisModule_StringPtrLen(argv[0], NULL),
RedisModule_StringPtrLen(argv[1], NULL));
#ifdef WITH_IPSET
fd = execute_popen(&pid, insert_command);
redis_waitpid(pid);
close(fd);
#else
fd = execute_popen(&pid, check_command);
redis_waitpid(pid);
if (0 < read(fd, tmp_buf, sizeof(tmp_buf) - 1)) {
Expand All @@ -154,16 +169,15 @@ int ACCEPT_Insert_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, in
redis_waitpid(pid);
}
close(fd);

#endif
RedisModule_StringSet(key, argv[1]);

size_t newlen = RedisModule_ValueLength(key);
RedisModule_CloseKey(key);
RedisModule_ReplyWithLongLong(ctx, newlen);
return REDISMODULE_OK;
}
int ACCEPT_Delete_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
int ACCEPT_Delete_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (argc != 2)
return RedisModule_WrongArity(ctx);

Expand All @@ -172,12 +186,15 @@ int ACCEPT_Delete_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, in
pid_t pid;
int fd;
static char insert_command[256];

#ifdef WITH_IPSET
sprintf(insert_command, "ipset del allow_ip %s",
RedisModule_StringPtrLen(argv[1], NULL));
#else
sprintf(insert_command, "iptables -D INPUT -s %s -j ACCEPT",
RedisModule_StringPtrLen(argv[1], NULL));
#endif
printf("%s || %s\n", RedisModule_StringPtrLen(argv[0], NULL),
RedisModule_StringPtrLen(argv[1], NULL));

fd = execute_popen(&pid, insert_command);
redis_waitpid(pid);
close(fd);
Expand All @@ -189,71 +206,83 @@ int ACCEPT_Delete_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, in
return REDISMODULE_OK;
}

int TTL_DROP_Insert_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
int TTL_DROP_Insert_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (argc != 3)
return RedisModule_WrongArity(ctx);
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1],
REDISMODULE_READ | REDISMODULE_WRITE);
long long count;
if ((RedisModule_StringToLongLong(argv[2],&count) != REDISMODULE_OK) ||
(count < 0)) {
return RedisModule_ReplyWithError(ctx,"ERR invalid count");
}
pid_t pid;
int fd;
char tmp_buf[4096];
return RedisModule_WrongArity(ctx);
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1],
REDISMODULE_READ | REDISMODULE_WRITE);
long long count;
if ((RedisModule_StringToLongLong(argv[2], &count) != REDISMODULE_OK)
|| (count < 0)) {
return RedisModule_ReplyWithError(ctx, "ERR invalid count");
}
pid_t pid;
int fd;

static char check_command[256], insert_command[256];
sprintf(check_command, "iptables -C INPUT -s %s -j DROP",
RedisModule_StringPtrLen(argv[1], NULL));
sprintf(insert_command, "iptables -I INPUT -s %s -j DROP",
RedisModule_StringPtrLen(argv[1], NULL));
printf("%s || %s\n", RedisModule_StringPtrLen(argv[0], NULL),
RedisModule_StringPtrLen(argv[1], NULL));
fd = execute_popen(&pid, check_command);
redis_waitpid(pid);
if (0 < read(fd, tmp_buf, sizeof(tmp_buf) - 1)) {
close(fd);
execute_popen(&pid, insert_command);
redis_waitpid(pid);
}
close(fd);
RedisModule_StringSet(key, argv[1]);
RedisModule_SetExpire(key, count*1000);
size_t newlen = RedisModule_ValueLength(key);
RedisModule_CloseKey(key);
RedisModule_ReplyWithLongLong(ctx, newlen);
return REDISMODULE_OK;
#ifdef WITH_IPSET
static char insert_command[256];
sprintf(insert_command, "ipset add block_ip %s",
RedisModule_StringPtrLen(argv[1], NULL));
#else
static char check_command[256], insert_command[256];
char tmp_buf[4096];
sprintf(check_command, "iptables -C INPUT -s %s -j DROP",
RedisModule_StringPtrLen(argv[1], NULL));
sprintf(insert_command, "iptables -I INPUT -s %s -j DROP",
RedisModule_StringPtrLen(argv[1], NULL));
#endif
printf("%s || %s\n", RedisModule_StringPtrLen(argv[0], NULL),
RedisModule_StringPtrLen(argv[1], NULL));
#ifdef WITH_IPSET
fd = execute_popen(&pid, insert_command);
redis_waitpid(pid);
close(fd);
#else
fd = execute_popen(&pid, check_command);
redis_waitpid(pid);
if (0 < read(fd, tmp_buf, sizeof(tmp_buf) - 1)) {
close(fd);
execute_popen(&pid, insert_command);
redis_waitpid(pid);
}
close(fd);
#endif
RedisModule_StringSet(key, argv[1]);
RedisModule_SetExpire(key, count * 1000);
size_t newlen = RedisModule_ValueLength(key);
RedisModule_CloseKey(key);
RedisModule_ReplyWithLongLong(ctx, newlen);
return REDISMODULE_OK;
}

/* This function must be present on each Redis module. It is used in order to
* register the commands into the Redis server. */
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (RedisModule_Init(ctx,"iptables-input-filter",1,REDISMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR;
if (RedisModule_Init(ctx, "iptables-input-filter", 1,
REDISMODULE_APIVER_1) == REDISMODULE_ERR)
return REDISMODULE_ERR;

/* Log the list of parameters passing loading the module. */
for (int j = 0; j < argc; j++) {
const char *s = RedisModule_StringPtrLen(argv[j],NULL);
const char *s = RedisModule_StringPtrLen(argv[j], NULL);
printf("Module loaded with ARGV[%d] = %s\n", j, s);
}

if (RedisModule_CreateCommand(ctx, "drop.insert",
DROP_Insert_RedisCommand, "write deny-oom", 1, 1, 1) == REDISMODULE_ERR)
if (RedisModule_CreateCommand(ctx, "drop.insert", DROP_Insert_RedisCommand,
"write deny-oom", 1, 1, 1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "drop.delete", DROP_Delete_RedisCommand,
"write deny-oom", 1, 1, 1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "drop.delete",
DROP_Delete_RedisCommand, "write deny-oom", 1, 1, 1) == REDISMODULE_ERR)
if (RedisModule_CreateCommand(ctx, "accept.insert", ACCEPT_Insert_RedisCommand,
"write deny-oom", 1, 1, 1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "accept.insert",
ACCEPT_Insert_RedisCommand, "write deny-oom", 1, 1, 1) == REDISMODULE_ERR)
if (RedisModule_CreateCommand(ctx, "accept.delete", ACCEPT_Delete_RedisCommand,
"write deny-oom", 1, 1, 1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "accept.delete",
ACCEPT_Delete_RedisCommand, "write deny-oom", 1, 1, 1) == REDISMODULE_ERR)
if (RedisModule_CreateCommand(ctx, "ttl.drop.insert", TTL_DROP_Insert_RedisCommand,
"write deny-oom", 1, 1, 1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "ttl.drop.insert",
TTL_DROP_Insert_RedisCommand, "write deny-oom", 1, 1, 1) == REDISMODULE_ERR)
return REDISMODULE_ERR;

return REDISMODULE_OK;
}
Loading

0 comments on commit 543f031

Please sign in to comment.