Source-Tag: v1.0.3 Manifest-SHA256: b7b09bf48f9e092ed8ad82f99c0319d6c3837d0a1549bd0cc4a374276c0f3896
187 lines
6.8 KiB
C
187 lines
6.8 KiB
C
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <unistd.h>
|
|
#include <weechat/weechat-plugin.h>
|
|
|
|
WEECHAT_PLUGIN_NAME("neoguard")
|
|
WEECHAT_PLUGIN_DESCRIPTION("NeoGuard abuse-control buffer")
|
|
WEECHAT_PLUGIN_AUTHOR("{{PRODUCT_NAME}}")
|
|
WEECHAT_PLUGIN_VERSION("1.1")
|
|
WEECHAT_PLUGIN_LICENSE("GPL3")
|
|
|
|
struct t_weechat_plugin *weechat_plugin;
|
|
static struct t_gui_buffer *guard_buffer;
|
|
static struct t_hook *fd_hook;
|
|
static int agent_fd = -1;
|
|
static char receive_buffer[16384];
|
|
static size_t receive_length;
|
|
|
|
static void print_line(const char *line)
|
|
{
|
|
const char *color = "chat";
|
|
if (strncmp(line, "EVENT\tBAN", 9) == 0 || strncmp(line, "EVENT\tPERM", 10) == 0)
|
|
color = "lightred";
|
|
else if (strncmp(line, "EVENT\tWARN", 10) == 0)
|
|
color = "yellow";
|
|
else if (strncmp(line, "ERROR\t", 6) == 0)
|
|
color = "red";
|
|
weechat_printf(guard_buffer, "%s%s", weechat_color(color), line);
|
|
}
|
|
|
|
static void disconnect_agent(void)
|
|
{
|
|
if (fd_hook) { weechat_unhook(fd_hook); fd_hook = NULL; }
|
|
if (agent_fd >= 0) close(agent_fd);
|
|
agent_fd = -1;
|
|
receive_length = 0;
|
|
}
|
|
|
|
static int agent_read_cb(const void *pointer, void *data, int fd)
|
|
{
|
|
(void)pointer; (void)data; (void)fd;
|
|
ssize_t count = read(agent_fd, receive_buffer + receive_length,
|
|
sizeof(receive_buffer) - receive_length - 1);
|
|
if (count <= 0) { disconnect_agent(); return WEECHAT_RC_OK; }
|
|
receive_length += (size_t)count;
|
|
receive_buffer[receive_length] = '\0';
|
|
char *start = receive_buffer;
|
|
char *newline;
|
|
while ((newline = strchr(start, '\n'))) {
|
|
*newline = '\0';
|
|
print_line(start);
|
|
start = newline + 1;
|
|
}
|
|
receive_length = strlen(start);
|
|
memmove(receive_buffer, start, receive_length);
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
static int connect_agent(void)
|
|
{
|
|
struct sockaddr_un address;
|
|
if (agent_fd >= 0) return 1;
|
|
agent_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
if (agent_fd < 0) return 0;
|
|
memset(&address, 0, sizeof(address));
|
|
address.sun_family = AF_UNIX;
|
|
snprintf(address.sun_path, sizeof(address.sun_path), "%s", "{{NEOGUARD_CONTROL_SOCKET_PATH}}");
|
|
if (connect(agent_fd, (struct sockaddr *)&address, sizeof(address)) != 0) {
|
|
close(agent_fd); agent_fd = -1; return 0;
|
|
}
|
|
fd_hook = weechat_hook_fd(agent_fd, 1, 0, 0, &agent_read_cb, NULL, NULL);
|
|
return 1;
|
|
}
|
|
|
|
static void send_agent(const char *kind, const char *first, const char *second)
|
|
{
|
|
char message[4096];
|
|
if (!connect_agent()) return;
|
|
snprintf(message, sizeof(message), "%s\t%s%s%s\n", kind, first,
|
|
second ? "\t" : "", second ? second : "");
|
|
if (write(agent_fd, message, strlen(message)) < 0) disconnect_agent();
|
|
}
|
|
|
|
static void send_attempt(const char *address, int port, const char *detail)
|
|
{
|
|
char message[4096];
|
|
if (!connect_agent()) return;
|
|
if (port >= 1 && port <= 65535)
|
|
snprintf(message, sizeof(message), "ATTEMPT\t%s\t%d\t%s\n", address, port, detail);
|
|
else
|
|
snprintf(message, sizeof(message), "ATTEMPT\t%s\t%s\n", address, detail);
|
|
if (write(agent_fd, message, strlen(message)) < 0) disconnect_agent();
|
|
}
|
|
|
|
static int reconnect_cb(const void *pointer, void *data, int remaining_calls)
|
|
{
|
|
(void)pointer; (void)data; (void)remaining_calls;
|
|
connect_agent();
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
static int input_cb(const void *pointer, void *data, struct t_gui_buffer *buffer, const char *input)
|
|
{
|
|
(void)pointer; (void)data; (void)buffer;
|
|
if (input && input[0]) send_agent("COMMAND", input, NULL);
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
static int close_cb(const void *pointer, void *data, struct t_gui_buffer *buffer)
|
|
{
|
|
(void)pointer; (void)data; (void)buffer;
|
|
guard_buffer = NULL;
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
static int ensure_buffer(void)
|
|
{
|
|
if (!guard_buffer)
|
|
guard_buffer = weechat_buffer_search("neoguard", "control");
|
|
if (!guard_buffer)
|
|
guard_buffer = weechat_buffer_new("control", &input_cb, NULL, NULL, &close_cb, NULL, NULL);
|
|
if (!guard_buffer) return 0;
|
|
weechat_buffer_set_pointer(guard_buffer, "input_callback", &input_cb);
|
|
weechat_buffer_set_pointer(guard_buffer, "close_callback", &close_cb);
|
|
weechat_buffer_set(guard_buffer, "short_name", "NeoGuard");
|
|
weechat_buffer_set(guard_buffer, "title", "NeoGuard | status/list | show/add/remove/extend IP | action IP redirect|message");
|
|
weechat_buffer_set(guard_buffer, "hidden", "0");
|
|
weechat_buffer_set(guard_buffer, "notify", "3");
|
|
weechat_buffer_set(guard_buffer, "localvar_set_no_log", "1");
|
|
weechat_buffer_set(guard_buffer, "localvar_set_pinned", "true");
|
|
weechat_buffer_set(guard_buffer, "localvar_set_type", "other");
|
|
return 1;
|
|
}
|
|
|
|
static int command_cb(const void *pointer, void *data, struct t_gui_buffer *buffer,
|
|
int argc, char **argv, char **argv_eol)
|
|
{
|
|
(void)pointer; (void)data; (void)buffer; (void)argc; (void)argv;
|
|
if (ensure_buffer()) {
|
|
weechat_buffer_set(guard_buffer, "display", "1");
|
|
if (argv_eol[1] && argv_eol[1][0]) send_agent("COMMAND", argv_eol[1], NULL);
|
|
}
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
static int relay_failure_cb(const void *pointer, void *data, const char *signal,
|
|
const char *type_data, void *signal_data)
|
|
{
|
|
(void)pointer; (void)data; (void)signal; (void)type_data;
|
|
struct t_infolist *list = weechat_infolist_get("relay", signal_data, NULL);
|
|
if (list && weechat_infolist_next(list)) {
|
|
const char *real_ip = weechat_infolist_string(list, "real_ip");
|
|
const char *address = weechat_infolist_string(list, "address");
|
|
int port = weechat_infolist_integer(list, "server_port");
|
|
send_attempt((real_ip && real_ip[0]) ? real_ip : address, port,
|
|
"relay authentication failed");
|
|
}
|
|
if (list) weechat_infolist_free(list);
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
int weechat_plugin_init(struct t_weechat_plugin *plugin, int argc, char *argv[])
|
|
{
|
|
(void)argc; (void)argv;
|
|
weechat_plugin = plugin;
|
|
weechat_hook_command("neoguard", "open/control NeoGuard",
|
|
"list || status || show <ip> || add <ip> [<duration>] || remove <ip> || extend <ip> <duration> || action <ip> redirect <https-url> || action <ip> message <text>",
|
|
"Inspect and control NeoGuard bans and per-address actions",
|
|
"list|status|show|add|remove|extend|action",
|
|
&command_cb, NULL, NULL);
|
|
weechat_hook_signal("relay_client_auth_failed", &relay_failure_cb, NULL, NULL);
|
|
weechat_hook_timer(5000, 0, 0, &reconnect_cb, NULL, NULL);
|
|
command_cb(NULL, NULL, NULL, 0, NULL, (char *[]){"", "status"});
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
int weechat_plugin_end(struct t_weechat_plugin *plugin)
|
|
{
|
|
(void)plugin;
|
|
disconnect_agent();
|
|
return WEECHAT_RC_OK;
|
|
}
|