You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

244 lines
7.4 KiB

/* Copyright 2016 Alex 'AdUser' Z (ad_user@runbox.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "common.h"
#include "buf.h"
#include "commands.h"
struct cmd_desc {
enum f2b_command_type type;
const short int argc;
const short int tokenc;
const char *help;
const char *tokens[CMD_TOKENS_MAXCOUNT];
} commands[] = {
{
.type = CMD_HELP,
.argc = 0, .tokenc = 1,
.tokens = { "help", NULL },
.help = "Show available commands",
}, {
.type = CMD_AUTH,
.argc = 2, .tokenc = 3,
.tokens = { "auth", "<type>", "<password>", NULL },
.help = "Check authorization (available types is: plain, challenge)",
}, {
.type = CMD_STATUS,
.argc = 0, .tokenc = 1,
.tokens = { "status", NULL },
.help = "Show general stats and jails list",
}, {
.type = CMD_RELOAD,
.argc = 0, .tokenc = 1,
.tokens = { "reload", NULL },
.help = "Reload own config, all jails will be reset.",
}, {
.type = CMD_SHUTDOWN,
.argc = 0, .tokenc = 1,
.tokens = { "shutdown", NULL },
.help = "Gracefully terminate f2b daemon",
}, {
.type = CMD_LOG_ROTATE,
.argc = 0, .tokenc = 2,
.tokens = { "log", "rotate", NULL },
.help = "Reopen daemon's own log file",
}, {
.type = CMD_LOG_LEVEL,
.argc = 1, .tokenc = 3,
.tokens = { "log", "level", "<level>", NULL },
.help = "Change maximum level of logged messages",
}, {
.type = CMD_LOG_EVENTS,
.argc = 1, .tokenc = 3,
.tokens = { "log", "events", "<bool>", NULL },
.help = "Enable/disable sending events to connected client",
}, {
.type = CMD_JAIL_STATUS,
.argc = 1, .tokenc = 3,
.tokens = { "jail", "<jailname>", "status", NULL },
.help = "Show status and stats of given jail",
}, {
.type = CMD_JAIL_SET,
.argc = 3, .tokenc = 5,
.tokens = { "jail", "<jailname>", "set", "<param>", "<value>", NULL },
.help = "Set parameter of given jail",
}, {
.type = CMD_JAIL_IP_STATUS,
.argc = 2, .tokenc = 5,
.tokens = { "jail", "<jailname>", "ip", "status", "<ip>", NULL },
.help = "Show ip status in given jail",
}, {
.type = CMD_JAIL_IP_BAN,
.argc = 2, .tokenc = 5,
.tokens = { "jail", "<jailname>", "ip", "ban", "<ip>", NULL },
.help = "Forcefully ban some ip in given jail",
}, {
.type = CMD_JAIL_IP_RELEASE,
.argc = 2, .tokenc = 5,
.tokens = { "jail", "<jailname>", "ip", "release", "<ip>", NULL },
.help = "Forcefully release some ip in given jail",
}, {
.type = CMD_JAIL_SOURCE_STATS,
.argc = 1, .tokenc = 4,
.tokens = { "jail", "<jailname>", "source", "stats", NULL },
.help = "Show source stats for jail",
}, {
.type = CMD_JAIL_FILTER_STATS,
.argc = 1, .tokenc = 4,
.tokens = { "jail", "<jailname>", "filter", "stats", NULL },
.help = "Show matches stats for jail regexps",
}, {
.type = CMD_JAIL_FILTER_RELOAD,
.argc = 1, .tokenc = 4,
.tokens = { "jail", "<jailname>", "filter", "reload", NULL },
.help = "Reload regexps for given jail",
}, {
.type = CMD_UNKNOWN,
.argc = 0, .tokenc = 0,
.tokens = { NULL },
.help = "",
}
};
static char *help = NULL;
const char *
f2b_cmd_help() {
f2b_buf_t buf;
const char **p = NULL;
if (help)
return help;
if (!f2b_buf_alloc(&buf, 8192))
return "internal error: can't allocate memory\n";
f2b_buf_append(&buf, "Available commands:\n\n", 0);
for (struct cmd_desc *cmd = commands; cmd->type != CMD_UNKNOWN; cmd++) {
for (p = cmd->tokens; *p != NULL; p++) {
f2b_buf_append(&buf, *p, 0);
f2b_buf_append(&buf, " ", 1);
}
f2b_buf_append(&buf, "\n\t", 2);
f2b_buf_append(&buf, cmd->help, 0);
f2b_buf_append(&buf, "\n\n", 2);
}
help = strndup(buf.data, buf.used);
f2b_buf_free(&buf);
return help;
}
f2b_cmd_t *
f2b_cmd_create(const char *line) {
f2b_cmd_t *cmd = NULL;
assert(line != NULL);
while (isspace(*line)) line++;
if (strlen(line) <= 0)
return NULL; /* empty string */
if ((cmd = calloc(1, sizeof(f2b_cmd_t))) == NULL)
return NULL;
if (f2b_cmd_parse(cmd, line))
return cmd;
free(cmd);
return NULL;
}
void
f2b_cmd_destroy(f2b_cmd_t *cmd) {
if (!cmd) return;
f2b_buf_free(&cmd->data);
free(cmd);
}
bool
f2b_cmd_parse(f2b_cmd_t *cmd, const char *src) {
char *p = NULL;
assert(cmd != NULL);
assert(src != NULL);
/* strip leading spaces */
while (isblank(*src))
src++;
if (strlen(src) == 0)
return false; /* empty string */
f2b_buf_alloc(&cmd->data, strlen(src) + 1);
f2b_buf_append(&cmd->data, src, 0);
/* simple commands without args */
cmd->argc = 1; /* we has at least one arg */
cmd->args[0] = cmd->data.data;
if (strcmp(src, "help") == 0) { cmd->type = CMD_HELP; return true; }
else if (strcmp(src, "status") == 0) { cmd->type = CMD_STATUS; return true; }
else if (strcmp(src, "reload") == 0) { cmd->type = CMD_RELOAD; return true; }
else if (strcmp(src, "shutdown") == 0) { cmd->type = CMD_SHUTDOWN; return true; }
/* split string to tokens */
p = cmd->data.data;
cmd->args[0] = strtok_r(cmd->data.data, " \t", &p);
for (size_t i = 1; i < CMD_TOKENS_MAXCOUNT; i++) {
cmd->args[i] = strtok_r(NULL, " \t", &p);
if (cmd->args[i] == NULL)
break;
cmd->argc++;
}
if (strcmp(cmd->args[0], "jail") == 0 && cmd->argc > 1) {
/* commands for jail */
if (cmd->argc == 3 && strcmp(cmd->args[2], "status") == 0) {
cmd->type = CMD_JAIL_STATUS; return true;
}
if (cmd->argc == 5 && strcmp(cmd->args[2], "set") == 0) {
cmd->type = CMD_JAIL_SET; return true;
}
if (cmd->argc == 5 && strcmp(cmd->args[2], "ip") == 0 && strcmp(cmd->args[3], "status") == 0) {
cmd->type = CMD_JAIL_IP_STATUS; return true;
}
if (cmd->argc == 5 && strcmp(cmd->args[2], "ip") == 0 && strcmp(cmd->args[3], "ban") == 0) {
cmd->type = CMD_JAIL_IP_BAN; return true;
}
if (cmd->argc == 5 && strcmp(cmd->args[2], "ip") == 0 && strcmp(cmd->args[3], "release") == 0) {
cmd->type = CMD_JAIL_IP_RELEASE; return true;
}
if (cmd->argc == 4 && strcmp(cmd->args[2], "source") == 0 && strcmp(cmd->args[3], "stats") == 0) {
cmd->type = CMD_JAIL_SOURCE_STATS; return true;
}
if (cmd->argc == 4 && strcmp(cmd->args[2], "filter") == 0 && strcmp(cmd->args[3], "stats") == 0) {
cmd->type = CMD_JAIL_FILTER_STATS; return true;
}
if (cmd->argc == 4 && strcmp(cmd->args[2], "filter") == 0 && strcmp(cmd->args[3], "reload") == 0) {
cmd->type = CMD_JAIL_FILTER_RELOAD; return true;
}
} else if (strcmp(cmd->args[0], "auth") == 0 && cmd->argc > 1) {
if (cmd->argc == 3 && strcmp(cmd->args[1], "plain") == 0) {
cmd->type = CMD_AUTH; return true;
}
if (cmd->argc == 3 && strcmp(cmd->args[1], "challenge") == 0) {
cmd->type = CMD_AUTH; return true;
}
} else if (strcmp(cmd->args[0], "log") == 0 && cmd->argc > 1) {
if (cmd->argc == 2 && strcmp(cmd->args[1], "rotate") == 0) {
cmd->type = CMD_LOG_ROTATE; return true;
}
if (cmd->argc == 3 && strcmp(cmd->args[1], "level") == 0) {
cmd->type = CMD_LOG_LEVEL; return true;
}
if (cmd->argc == 3 && strcmp(cmd->args[1], "events") == 0) {
cmd->type = CMD_LOG_EVENTS; return true;
}
}
cmd->type = CMD_UNKNOWN;
memset(cmd->args, 0x0, sizeof(cmd->args));
f2b_buf_free(&cmd->data);
return false;
}