Alex 'AdUser' Z
4 years ago
26 changed files with 827 additions and 1248 deletions
@ -1,217 +0,0 @@
|
||||
/* 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 <assert.h> |
||||
#include <errno.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <stdbool.h> |
||||
#include <stdint.h> |
||||
#include <stdlib.h> |
||||
#include <sys/types.h> |
||||
#include <unistd.h> |
||||
#include <netinet/in.h> |
||||
#include <arpa/inet.h> |
||||
#include <net/if.h> |
||||
#include <netdb.h> |
||||
|
||||
#include "../strlcpy.h" |
||||
#include "../commands.h" |
||||
#include "../cmsg.h" |
||||
#include "../csocket.h" |
||||
|
||||
#include "backend.h" |
||||
#include "shared.c" |
||||
|
||||
#define DEFAULT_MCAST_ADDR "239.255.186.1" |
||||
#define DEFAULT_MCAST_PORT "3370" |
||||
|
||||
struct _config { |
||||
char name[ID_MAX + 1]; |
||||
char error[256]; |
||||
bool shared; |
||||
char maddr[INET_ADDRSTRLEN]; /**< multicast address */ |
||||
char mport[6]; /**< multicast port */ |
||||
char iface[IF_NAMESIZE]; /**< bind interface */ |
||||
int sock; |
||||
struct sockaddr_storage sa; |
||||
socklen_t sa_len; |
||||
}; |
||||
|
||||
cfg_t * |
||||
create(const char *id) { |
||||
cfg_t *cfg = NULL; |
||||
|
||||
assert(id != NULL); |
||||
|
||||
if ((cfg = calloc(1, sizeof(cfg_t))) == NULL) |
||||
return NULL; |
||||
strlcpy(cfg->name, id, sizeof(cfg->name)); |
||||
strlcpy(cfg->maddr, DEFAULT_MCAST_ADDR, sizeof(cfg->maddr)); |
||||
strlcpy(cfg->mport, DEFAULT_MCAST_PORT, sizeof(cfg->mport)); |
||||
|
||||
return cfg; |
||||
} |
||||
|
||||
bool |
||||
config(cfg_t *cfg, const char *key, const char *value) { |
||||
assert(cfg != NULL); |
||||
assert(key != NULL); |
||||
assert(value != NULL); |
||||
|
||||
if (strcmp(key, "group") == 0) { |
||||
if (strncmp(value, "239.255.", 8) != 0) { |
||||
strlcpy(cfg->error, "mcast group address should be inside 239.255.0.0/16 block", sizeof(cfg->error)); |
||||
return false; |
||||
} |
||||
strlcpy(cfg->maddr, value, sizeof(cfg->maddr)); |
||||
return true; |
||||
} |
||||
if (strcmp(key, "port") == 0) { |
||||
strlcpy(cfg->mport, value, sizeof(cfg->mport)); |
||||
return true; |
||||
} |
||||
if (strcmp(key, "iface") == 0) { |
||||
strlcpy(cfg->iface, value, sizeof(cfg->iface)); |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
bool |
||||
ready(cfg_t *cfg) { |
||||
assert(cfg != NULL); |
||||
|
||||
if (cfg->maddr[0] && cfg->mport[0]) |
||||
return true; |
||||
|
||||
return false; |
||||
} |
||||
|
||||
char * |
||||
error(cfg_t *cfg) { |
||||
assert(cfg != NULL); |
||||
|
||||
return cfg->error; |
||||
} |
||||
|
||||
bool |
||||
start(cfg_t *cfg) { |
||||
struct addrinfo hints; |
||||
struct addrinfo *result; |
||||
assert(cfg != NULL); |
||||
int ret, sock = -1; |
||||
|
||||
if (cfg->shared && usage_inc(cfg->name) > 1) |
||||
return true; |
||||
|
||||
memset(&hints, 0, sizeof(struct addrinfo)); |
||||
hints.ai_family = AF_INET; |
||||
hints.ai_socktype = SOCK_DGRAM; |
||||
hints.ai_protocol = 0; |
||||
|
||||
if ((ret = getaddrinfo(cfg->maddr, cfg->mport, &hints, &result)) < 0) { |
||||
snprintf(cfg->error, sizeof(cfg->error), "can't create socket: %s", gai_strerror(ret)); |
||||
return false; |
||||
} |
||||
|
||||
for (struct addrinfo *rp = result; rp != NULL; rp = rp->ai_next) { |
||||
if (sock >= 0) { |
||||
close(sock); /* from prev iteration */ |
||||
sock = -1; |
||||
} |
||||
if ((sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0) { |
||||
snprintf(cfg->error, sizeof(cfg->error), "can't create socket: %s", strerror(errno)); |
||||
continue; |
||||
} |
||||
memcpy(&cfg->sa, rp->ai_addr, rp->ai_addrlen); |
||||
cfg->sa_len = rp->ai_addrlen; |
||||
break; |
||||
} |
||||
freeaddrinfo(result); |
||||
|
||||
if (sock < 0) |
||||
return false; |
||||
|
||||
cfg->sock = sock; |
||||
return true; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool |
||||
stop(cfg_t *cfg) { |
||||
assert(cfg != NULL); |
||||
|
||||
if (cfg->shared && usage_dec(cfg->name) > 0) |
||||
return true; |
||||
|
||||
close(cfg->sock); |
||||
cfg->sock = -1; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool |
||||
ban(cfg_t *cfg, const char *ip) { |
||||
f2b_cmsg_t cmsg; |
||||
int ret; |
||||
|
||||
assert(cfg != NULL); |
||||
|
||||
memset(&cmsg, 0x0, sizeof(cmsg)); |
||||
|
||||
strncpy(cmsg.magic, "F2B", sizeof(cmsg.magic)); |
||||
cmsg.version = F2B_PROTO_VER; |
||||
cmsg.type = CMD_JAIL_IP_BAN; |
||||
f2b_cmd_append_arg(cmsg.data, sizeof(cmsg.data), cfg->name); |
||||
f2b_cmd_append_arg(cmsg.data, sizeof(cmsg.data), ip); |
||||
cmsg.size = strlen(cmsg.data); |
||||
cmsg.data[cmsg.size] = '\0'; |
||||
f2b_cmsg_convert_args(&cmsg); |
||||
|
||||
ret = f2b_csocket_send(cfg->sock, &cmsg, &cfg->sa, &cfg->sa_len); |
||||
if (ret <= 0) { |
||||
strlcpy(cfg->error, f2b_csocket_error(ret), sizeof(cfg->error)); |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool |
||||
unban(cfg_t *cfg, const char *ip) { |
||||
assert(cfg != NULL); |
||||
|
||||
(void)(cfg); /* suppress warning for unused variable 'cfg' */ |
||||
(void)(ip); /* suppress warning for unused variable 'ip' */ |
||||
return true; |
||||
} |
||||
|
||||
bool |
||||
check(cfg_t *cfg, const char *ip) { |
||||
assert(cfg != NULL); |
||||
|
||||
(void)(cfg); /* suppress warning for unused variable 'cfg' */ |
||||
(void)(ip); /* suppress warning for unused variable 'ip' */ |
||||
return false; |
||||
} |
||||
|
||||
bool |
||||
ping(cfg_t *cfg) { |
||||
assert(cfg != NULL); |
||||
|
||||
(void)(cfg); /* silence warning about unused variable */ |
||||
return true; |
||||
} |
||||
|
||||
void |
||||
destroy(cfg_t *cfg) { |
||||
assert(cfg != NULL); |
||||
|
||||
free(cfg); |
||||
} |
@ -0,0 +1,88 @@
|
||||
#include "common.h" |
||||
#include "buf.h" |
||||
|
||||
bool |
||||
f2b_buf_alloc(f2b_buf_t *buf, size_t size) { |
||||
assert(buf != NULL); |
||||
assert(size > 0); |
||||
|
||||
memset(buf, 0x0, sizeof(f2b_buf_t)); |
||||
if ((buf->data = malloc(size)) == NULL) |
||||
return false; /* can't allocate memory */ |
||||
|
||||
buf->size = size; |
||||
return true; |
||||
} |
||||
|
||||
void |
||||
f2b_buf_free(f2b_buf_t *buf) { |
||||
assert(buf != NULL); |
||||
|
||||
free(buf->data); |
||||
memset(buf, 0x0, sizeof(f2b_buf_t)); |
||||
} |
||||
|
||||
size_t |
||||
f2b_buf_append(f2b_buf_t *buf, const char *str, size_t len) { |
||||
assert(buf != NULL); |
||||
assert(str != NULL); |
||||
|
||||
if (len == 0) |
||||
len = strlen(str); |
||||
if ((buf->used + len) > buf->size) { |
||||
/* not enough space, append as much as possible */ |
||||
len = buf->size - buf->used; |
||||
} |
||||
|
||||
memcpy(&buf->data[buf->used], str, len); |
||||
buf->used += len; |
||||
buf->data[buf->used] = '\0'; |
||||
return len; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Extracts line terminated by delimiter |
||||
* @return Pointer to extracted string on success or NULL otherwise |
||||
* @note Use only with 'read' buffer type |
||||
*/ |
||||
char * |
||||
f2b_buf_extract(f2b_buf_t *buf, const char *end) { |
||||
char *s = NULL; |
||||
size_t len = 0; |
||||
|
||||
assert(buf != NULL); |
||||
assert(end != NULL); |
||||
|
||||
if (buf->data == NULL || buf->used == 0) |
||||
return NULL; /* no data */ |
||||
|
||||
if ((s = strstr(buf->data, end)) == NULL) |
||||
return NULL; /* not found */ |
||||
|
||||
/* copy the data before modifying buffer */ |
||||
len = s - buf->data; |
||||
if ((s = strndup(buf->data, len)) == NULL) |
||||
return NULL; /* malloc error */ |
||||
|
||||
/* shift data inside buffer */ |
||||
len += strlen(end); |
||||
f2b_buf_splice(buf, len); |
||||
|
||||
return s; |
||||
} |
||||
|
||||
size_t |
||||
f2b_buf_splice(f2b_buf_t *buf, size_t len) { |
||||
assert(buf != NULL); |
||||
|
||||
if (len == 0) |
||||
return len; |
||||
|
||||
if (buf->used <= len) |
||||
len = buf->used; |
||||
|
||||
buf->used -= len, |
||||
memmove(buf->data, &buf->data[len], buf->used); |
||||
buf->data[buf->used] = '\0'; |
||||
return len; |
||||
} |
@ -0,0 +1,16 @@
|
||||
#ifndef F2B_BUF_H_ |
||||
#define F2B_BUF_H_ |
||||
|
||||
typedef struct f2b_buf_t { |
||||
size_t used; /**< bytes used in buffer */ |
||||
size_t size; /**< available size in data */ |
||||
char *data; /**< allocated buffer */ |
||||
} f2b_buf_t; |
||||
|
||||
bool f2b_buf_alloc(f2b_buf_t *buf, size_t max); |
||||
void f2b_buf_free(f2b_buf_t *buf); |
||||
size_t f2b_buf_append(f2b_buf_t *buf, const char *str, size_t size); |
||||
char * f2b_buf_extract(f2b_buf_t *buf, const char *end); |
||||
size_t f2b_buf_splice(f2b_buf_t *buf, size_t len); |
||||
|
||||
#endif /* F2B_BUF_H_ */ |
@ -1,42 +0,0 @@
|
||||
#include "common.h" |
||||
#include "commands.h" |
||||
#include "cmsg.h" |
||||
|
||||
#include <sys/uio.h> |
||||
|
||||
void |
||||
f2b_cmsg_convert_args(f2b_cmsg_t *msg) { |
||||
assert(msg != NULL); |
||||
|
||||
for (size_t i = 0; i < msg->size && i < sizeof(msg->data); i++) { |
||||
if (msg->data[i] == '\n') |
||||
msg->data[i] = '\0'; |
||||
} |
||||
} |
||||
|
||||
int |
||||
f2b_cmsg_extract_args(const f2b_cmsg_t *msg, const char **argv) { |
||||
char prev = '\0'; |
||||
size_t argc = 0; |
||||
|
||||
assert(msg != NULL); |
||||
assert(argv != NULL); |
||||
|
||||
if (msg->size == 0) |
||||
return 0; /* no args */ |
||||
|
||||
if (msg->data[msg->size - 1] != '\0') |
||||
return -1; /* message data not null-terminated */ |
||||
|
||||
for (size_t i = 0; i < msg->size; i++) { |
||||
if (prev == '\0' && msg->data[i] != '\0') |
||||
argv[argc] = &msg->data[i], argc++; |
||||
if (argc >= DATA_ARGS_MAX) { |
||||
argc = -1; |
||||
break; |
||||
} |
||||
prev = msg->data[i]; |
||||
} |
||||
|
||||
return argc; |
||||
} |
@ -1,68 +0,0 @@
|
||||
#ifndef F2B_CMSG_H_ |
||||
#define F2B_CMSG_H_ |
||||
|
||||
/**
|
||||
* @file |
||||
* This header contains definitions of control messages format and routines |
||||
*/ |
||||
|
||||
/**
|
||||
* @def DATA_LEN_MAX |
||||
* Maximum length of data in packet |
||||
*/ |
||||
#define DATA_LEN_MAX 1476 /* 1500 - (16 bytes of cmsg header + 8 bytes of udp) */ |
||||
/**
|
||||
* @def DATA_ARGS_MAX |
||||
* Maximum count of data pieces in packet |
||||
*/ |
||||
#define DATA_ARGS_MAX 6 /* number of args in data */ |
||||
/**
|
||||
* @def F2B_PROTO_VER |
||||
* Protocol version of control message |
||||
*/ |
||||
#define F2B_PROTO_VER 1 |
||||
|
||||
/**
|
||||
* @def CMSG_FLAG_NEED_REPLY |
||||
* Server should reply to this control message |
||||
*/ |
||||
#define CMSG_FLAG_NEED_REPLY 0x01 |
||||
/**
|
||||
* @def CMSG_FLAG_AUTH_PASS |
||||
* This control message contains password |
||||
*/ |
||||
#define CMSG_FLAG_AUTH_PASS 0x02 |
||||
|
||||
/**
|
||||
* f2b control message |
||||
* @note Use sendmsg/recvmsg and iovec structs to pack/unpack |
||||
*/ |
||||
typedef struct f2b_cmsg_t { |
||||
char magic[3]; /**< magic string "F2B" */ |
||||
uint8_t version; /**< protocol version */ |
||||
/* 4 bytes */ |
||||
uint8_t type; /**< command type, cast from enum f2b_cmd_type */ |
||||
uint8_t flags; /**< CMSG_FLAG_* */ |
||||
uint16_t size; /**< payload length */ |
||||
/* 8 bytes */ |
||||
char pass[8]; /**< auth data */ |
||||
/* 16 bytes */ |
||||
/* end of header */ |
||||
char data[DATA_LEN_MAX]; /**< set of "\n"-terminated strings */ |
||||
/* end of data */ |
||||
} f2b_cmsg_t; |
||||
|
||||
/**
|
||||
* @brief Convert every '\n' in data to '\0' |
||||
* @param msg Pointer to control message |
||||
*/ |
||||
void f2b_cmsg_convert_args(f2b_cmsg_t *msg); |
||||
/**
|
||||
* @brief Fill @a argv array with pointers to found data pieces |
||||
* @param msg Pointer to control message |
||||
* @param argv Array of pointers |
||||
* @returns Number of found args |
||||
*/ |
||||
int f2b_cmsg_extract_args(const f2b_cmsg_t *msg, const char **argv); |
||||
|
||||
#endif /* F2B_CMSG_H_ */ |
@ -0,0 +1,42 @@
|
||||
#include "common.h" |
||||
#include "buf.h" |
||||
#include "log.h" |
||||
#include "commands.h" |
||||
#include "csocket.h" |
||||
|
||||
static int run = 1; |
||||
|
||||
void |
||||
cmd_handler(const f2b_cmd_t *cmd, f2b_buf_t *res) { |
||||
fprintf(stdout, "[handler] received cmd with type %d and %d args:\n", cmd->type, cmd->argc); |
||||
for (int i = 0; i < cmd->argc; i++) { |
||||
fprintf(stdout, "[handler] arg %d : %s\n", i + 1, cmd->args[i]); |
||||
} |
||||
UNUSED(res); |
||||
return; |
||||
} |
||||
|
||||
int main(int argc, const char **argv) { |
||||
f2b_csock_t *csock = NULL; |
||||
|
||||
if (argc < 2) { |
||||
puts("Usage: csocket-test <path>"); |
||||
exit(EXIT_FAILURE); |
||||
} |
||||
|
||||
f2b_log_set_level("debug"); |
||||
f2b_log_to_stderr(); |
||||
|
||||
if ((csock = f2b_csocket_create(argv[1])) == NULL) { |
||||
perror("f2b_csocket_create()"); |
||||
exit(EXIT_FAILURE); |
||||
} |
||||
|
||||
while (run) { |
||||
f2b_csocket_poll(csock, cmd_handler); |
||||
sleep(1); |
||||
} |
||||
f2b_csocket_destroy(csock); |
||||
|
||||
return 0; |
||||
} |
@ -1,271 +0,0 @@
|
||||
/* 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 "source.h" |
||||
|
||||
#include <sys/types.h> |
||||
#include <fcntl.h> |
||||
#include <sys/socket.h> |
||||
#include <netinet/in.h> |
||||
#include <arpa/inet.h> |
||||
#include <net/if.h> |
||||
#include <netdb.h> |
||||
|
||||
#include "../commands.h" |
||||
#include "../cmsg.h" |
||||
#include "../csocket.h" |
||||
|
||||
#define DEFAULT_BIND_ADDR "0.0.0.0" |
||||
#define DEFAULT_MCAST_ADDR "239.255.186.1" |
||||
#define DEFAULT_MCAST_PORT "3370" |
||||
|
||||
#if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP) |
||||
/* bsd-derivatives */ |
||||
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP |
||||
#endif |
||||
|
||||
struct _config { |
||||
char name[32]; |
||||
char error[256]; |
||||
void (*errcb)(const char *errstr); |
||||
char baddr[INET6_ADDRSTRLEN]; /**< bind address */ |
||||
char maddr[INET6_ADDRSTRLEN]; /**< multicast address */ |
||||
char mport[6]; /**< multicast port */ |
||||
char iface[IF_NAMESIZE]; /**< bind interface */ |
||||
int sock; |
||||
}; |
||||
|
||||
static void |
||||
errcb_stub(const char *str) { |
||||
assert(str != NULL); |
||||
(void)(str); |
||||
} |
||||
|
||||
cfg_t * |
||||
create(const char *init) { |
||||
cfg_t *cfg = NULL; |
||||
assert(init != NULL); |
||||
if ((cfg = calloc(1, sizeof(cfg_t))) == NULL) |
||||
return NULL; |
||||
strlcpy(cfg->name, init, sizeof(cfg->name)); |
||||
strlcpy(cfg->baddr, DEFAULT_BIND_ADDR, sizeof(cfg->baddr)); |
||||
strlcpy(cfg->maddr, DEFAULT_MCAST_ADDR, sizeof(cfg->maddr)); |
||||
strlcpy(cfg->mport, DEFAULT_MCAST_PORT, sizeof(cfg->mport)); |
||||
cfg->errcb = &errcb_stub; |
||||
return cfg; |
||||
} |
||||
|
||||
bool |
||||
config(cfg_t *cfg, const char *key, const char *value) { |
||||
assert(cfg != NULL); |
||||
assert(key != NULL); |
||||
assert(value != NULL); |
||||
|
||||
if (strcmp(key, "group") == 0) { |
||||
if (strncmp(value, "239.255.", 8) != 0) { |
||||
strlcpy(cfg->error, "mcast group address should be inside 239.255.0.0/16 block", sizeof(cfg->error)); |
||||
return false; |
||||
} |
||||
strlcpy(cfg->maddr, value, sizeof(cfg->maddr)); |
||||
return true; |
||||
} |
||||
if (strcmp(key, "address") == 0) { |
||||
strlcpy(cfg->baddr, value, sizeof(cfg->baddr)); |
||||
return true; |
||||
} |
||||
if (strcmp(key, "port") == 0) { |
||||
strlcpy(cfg->mport, value, sizeof(cfg->mport)); |
||||
return true; |
||||
} |
||||
if (strcmp(key, "iface") == 0) { |
||||
strlcpy(cfg->iface, value, sizeof(cfg->iface)); |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
bool |
||||
ready(cfg_t *cfg) { |
||||
assert(cfg != NULL); |
||||
|
||||
if (cfg->maddr[0] && (cfg->iface[0] || cfg->baddr[0])) |
||||
return true; |
||||
|
||||
return false; |
||||
} |
||||
|
||||
char * |
||||
error(cfg_t *cfg) { |
||||
assert(cfg != NULL); |
||||
|
||||
return cfg->error; |
||||
} |
||||
|
||||
void |
||||
errcb(cfg_t *cfg, void (*cb)(const char *errstr)) { |
||||
assert(cfg != NULL); |
||||
assert(cb != NULL); |
||||
|
||||
cfg->errcb = cb; |
||||
} |
||||
|
||||
bool |
||||
start(cfg_t *cfg) { |
||||
struct addrinfo hints; |
||||
struct addrinfo *maddr, *laddr; |
||||
int opt, ret, sock = -1; |
||||
|
||||
assert(cfg != NULL); |
||||
|
||||
memset(&hints, 0, sizeof(struct addrinfo)); |
||||
hints.ai_family = AF_UNSPEC; |
||||
hints.ai_flags = AI_NUMERICHOST; |
||||
hints.ai_socktype = SOCK_DGRAM; |
||||
hints.ai_protocol = 0; |
||||
|
||||
if ((ret = getaddrinfo(cfg->maddr, cfg->mport, &hints, &maddr)) < 0) { |
||||
snprintf(cfg->error, sizeof(cfg->error), "can't resolve mcast addr: %s", gai_strerror(ret)); |
||||
return false; |
||||
} |
||||
|
||||
hints.ai_family = maddr->ai_family; |
||||
hints.ai_flags = AI_PASSIVE; |
||||
hints.ai_socktype = SOCK_DGRAM; |
||||
|
||||
if ((ret = getaddrinfo(cfg->baddr[0] != '\0' ? cfg->baddr : NULL, cfg->mport, &hints, &laddr)) < 0) { |
||||
snprintf(cfg->error, sizeof(cfg->error), "can't resolve local addr: %s", gai_strerror(ret)); |
||||
freeaddrinfo(maddr); |
||||
return false; |
||||
} |
||||
|
||||
do { |
||||
cfg->sock = -1; |
||||
/* create socket */ |
||||
if ((sock = socket(laddr->ai_family, laddr->ai_socktype, laddr->ai_protocol)) < 0) { |
||||
snprintf(cfg->error, sizeof(cfg->error), "can't create socket: %s", strerror(errno)); |
||||
continue; |
||||
} |
||||
/* set non-blocking mode */ |
||||
if ((opt = fcntl(sock, F_GETFL, 0)) < 0) { |
||||
continue; |
||||
} |
||||
fcntl(sock, F_SETFL, opt | O_NONBLOCK); |
||||
/* reuse address */ |
||||
opt = 1; |
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); |
||||
/* bind to given address */ |
||||
if (bind(sock, laddr->ai_addr, laddr->ai_addrlen) < 0) { |
||||
snprintf(cfg->error, sizeof(cfg->error), "can't bind socket to addr %s: %s", |
||||
cfg->baddr, strerror(errno)); |
||||
continue; |
||||
} |
||||
/* IP_MULTICAST_LOOP -- default: yes */ |
||||
/* IP_MULTICAST_TTL -- default: 1 */ |
||||
/* join mcast group */ |
||||
if (maddr->ai_family == AF_INET) { |
||||
struct ip_mreq mreq; |
||||
struct in_addr *addr = NULL; |
||||
memset(&mreq, 0x0, sizeof(mreq)); |
||||
addr = &((struct sockaddr_in *)(maddr->ai_addr))->sin_addr; |
||||
memcpy(&mreq.imr_multiaddr, addr, sizeof(mreq.imr_multiaddr)); |
||||
addr = &((struct sockaddr_in *)(laddr->ai_addr))->sin_addr; |
||||
memcpy(&mreq.imr_interface, addr, sizeof(mreq.imr_interface)); |
||||
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { |
||||
snprintf(cfg->error, sizeof(cfg->error), "can't join mcast group: %s", |
||||
strerror(errno)); |
||||
continue; |
||||
} |
||||
} else if (maddr->ai_family == AF_INET6) { |
||||
struct ipv6_mreq mreq; |
||||
struct in6_addr *addr = NULL; |
||||
memset(&mreq, 0x0, sizeof(mreq)); |
||||
addr = &((struct sockaddr_in6 *)(maddr->ai_addr))->sin6_addr; |
||||
memcpy(&mreq.ipv6mr_multiaddr, addr, sizeof(mreq.ipv6mr_multiaddr)); |
||||
if (cfg->iface[0] != '\0') { |
||||
mreq.ipv6mr_interface = if_nametoindex(cfg->iface); |
||||
} |
||||
if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { |
||||
snprintf(cfg->error, sizeof(cfg->error), "can't join mcast group: %s", |
||||
strerror(errno)); |
||||
continue; |
||||
} |
||||
} else { |
||||
snprintf(cfg->error, sizeof(cfg->error), "unknown family for mcast addr: %d", laddr->ai_family); |
||||
continue; |
||||
} |
||||
/* all ok */ |
||||
cfg->sock = sock; |
||||
sock = -1; |
||||
} while (0); |
||||
|
||||
freeaddrinfo(maddr); |
||||
freeaddrinfo(laddr); |
||||
|
||||
if (cfg->sock < 0) |
||||
return false; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool |
||||
stop(cfg_t *cfg) { |
||||
assert(cfg != NULL); |
||||
|
||||
/* mcast group will be leaved automatically */ |
||||
close(cfg->sock); |
||||
cfg->sock = -1; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool |
||||
next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) { |
||||
const char *args[DATA_ARGS_MAX]; |
||||
struct sockaddr_storage addr; |
||||
socklen_t socklen; |
||||
f2b_cmsg_t cmsg; |
||||
int ret; |
||||
|
||||
(void)(reset); |
||||
assert(cfg != NULL); |
||||
assert(buf != NULL); |
||||
assert(bufsize > 0); |
||||
|
||||
memset(&cmsg, 0x0, sizeof(cmsg)); |
||||
memset(&addr, 0x0, sizeof(addr)); |
||||
|
||||
while (1) { |
||||
ret = f2b_csocket_recv(cfg->sock, &cmsg, &addr, &socklen); |
||||
if (ret == 0) |
||||
break; /* no messages */ |
||||
if (ret < 0) { |
||||
cfg->errcb(f2b_csocket_error(ret)); |
||||
continue; |
||||
} |
||||
/* ret > 0 */ |
||||
if (cmsg.type != CMD_JAIL_IP_BAN) |
||||
continue; |
||||
ret = f2b_cmsg_extract_args(&cmsg, args); |
||||
if (!f2b_cmd_check_argc(cmsg.type, ret)) { |
||||
cfg->errcb("received cmsg with wrong args count"); |
||||
continue; |
||||
} |
||||
if (strcmp(cfg->name, args[0]) != 0) |
||||
continue; /* wrong group */ |
||||
strlcpy(buf, args[1], bufsize); |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
void |
||||
destroy(cfg_t *cfg) { |
||||
assert(cfg != NULL); |
||||
|
||||
free(cfg); |
||||
} |
@ -0,0 +1,68 @@
|
||||
#include "../src/common.h" |
||||
#include "../src/buf.h" |
||||
|
||||
int main() { |
||||
f2b_buf_t buf; |
||||
char *line; |
||||
bool ret; |
||||
int len; |
||||
|
||||
memset(&buf, 0x0, sizeof(buf)); |
||||
|
||||
ret = f2b_buf_alloc(&buf, 512); |
||||
assert(ret = true); |
||||
assert(buf.used == 0); |
||||
assert(buf.size == 512); |
||||
|
||||
ret = f2b_buf_append(&buf, "test ", 0); |
||||
assert(ret == true); |
||||
assert(buf.used == 5); |
||||
|
||||
line = f2b_buf_extract(&buf, "\n"); |
||||
assert(line == NULL); |
||||
|
||||
ret = f2b_buf_append(&buf, "test2\n", 0); |
||||
assert(ret == true); |
||||
assert(buf.used == 11); |
||||
|
||||
ret = f2b_buf_append(&buf, "test3\n", 0); |
||||
assert(ret == true); |
||||
assert(buf.used == 17); |
||||
|
||||
line = f2b_buf_extract(&buf, "\n"); |
||||
assert(line != NULL); |
||||
assert(strcmp(line, "test test2") == 0); |
||||
assert(buf.used == 6); |
||||
free(line); |
||||
|
||||
line = f2b_buf_extract(&buf, "\n"); |
||||
assert(line != NULL); |
||||
assert(buf.used == 0); |
||||
free(line); |
||||
|
||||
f2b_buf_append(&buf, "test4\n\n", 6); |
||||
assert(buf.used == 6); |
||||
assert(strcmp(buf.data, "test4\n") == 0); |
||||
|
||||
len = f2b_buf_splice(&buf, 0); |
||||
assert(len == 0); |
||||
assert(buf.used == 6); |
||||
assert(strcmp(buf.data, "test4\n") == 0); |
||||
|
||||
len = f2b_buf_splice(&buf, 2); |
||||
assert(len == 2); |
||||
assert(buf.used == 4); |
||||
assert(strcmp(buf.data, "st4\n") == 0); |
||||
|
||||
len = f2b_buf_splice(&buf, 6); |
||||
assert(len == 4); |
||||
assert(buf.used == 0); |
||||
assert(buf.data[0] == '\0'); |
||||
|
||||
f2b_buf_free(&buf); |
||||
assert(buf.used == 0); |
||||
assert(buf.size == 0); |
||||
assert(buf.data == NULL); |
||||
|
||||
return 0; |
||||
} |
@ -1,34 +1,41 @@
|
||||
#include "../src/common.h" |
||||
#include "../src/buf.h" |
||||
#include "../src/commands.h" |
||||
|
||||
int main() { |
||||
char buf[1024]; |
||||
const char *line; |
||||
|
||||
UNUSED(line); |
||||
|
||||
buf[0] = '\0'; |
||||
f2b_cmd_append_arg(buf, sizeof(buf), "42"); |
||||
assert(strcmp(buf, "42\n") == 0); |
||||
|
||||
line = "status"; |
||||
assert(f2b_cmd_parse(buf, sizeof(buf), line) == CMD_STATUS); |
||||
|
||||
line = "statu"; /* no such command */ |
||||
assert(f2b_cmd_parse(buf, sizeof(buf), line) == CMD_NONE); |
||||
|
||||
line = "jail test"; /* incomplete command */ |
||||
assert(f2b_cmd_parse(buf, sizeof(buf), line) == CMD_NONE); |
||||
|
||||
buf[0] = '\0'; |
||||
line = "jail test status"; |
||||
assert(f2b_cmd_parse(buf, sizeof(buf), line) == CMD_JAIL_STATUS); |
||||
assert(strcmp(buf, "test\n") == 0); |
||||
|
||||
buf[0] = '\0'; |
||||
line = "jail test set bantime 7200"; |
||||
assert(f2b_cmd_parse(buf, sizeof(buf), line) == CMD_JAIL_SET); |
||||
assert(strcmp(buf, "test\nbantime\n7200\n") == 0); |
||||
f2b_cmd_t cmd; |
||||
|
||||
assert(f2b_cmd_parse(&cmd, "status") == true); |
||||
assert(cmd.type = CMD_STATUS); |
||||
assert(cmd.argc == 1); |
||||
assert(strcmp(cmd.args[0], "status") == 0); |
||||
assert(cmd.data.used == 6); /* "status" */ |
||||
f2b_buf_free(&cmd.data); |
||||
|
||||
assert(f2b_cmd_parse(&cmd, "stat") == false); /* no such command */ |
||||
assert(cmd.type == CMD_UNKNOWN); |
||||
|
||||
assert(f2b_cmd_parse(&cmd, "jail test") == false); /* incomplete command */ |
||||
assert(cmd.type == CMD_UNKNOWN); |
||||
|
||||
assert(f2b_cmd_parse(&cmd, "jail test status") == true); |
||||
assert(cmd.type == CMD_JAIL_STATUS); |
||||
assert(cmd.argc == 3); |
||||
assert(strcmp(cmd.args[0], "jail") == 0); |
||||
assert(strcmp(cmd.args[1], "test") == 0); |
||||
assert(strcmp(cmd.args[2], "status") == 0); |
||||
assert(cmd.data.used == 16); /* "jail\0test\0status" */ |
||||
f2b_buf_free(&cmd.data); |
||||
|
||||
assert(f2b_cmd_parse(&cmd, "jail test set bantime 7200") == true); |
||||
assert(cmd.type == CMD_JAIL_SET); |
||||
assert(cmd.argc == 5); |
||||
assert(strcmp(cmd.args[0], "jail") == 0); |
||||
assert(strcmp(cmd.args[1], "test") == 0); |
||||
assert(strcmp(cmd.args[2], "set") == 0); |
||||
assert(strcmp(cmd.args[3], "bantime") == 0); |
||||
assert(strcmp(cmd.args[4], "7200") == 0); |
||||
f2b_buf_free(&cmd.data); |
||||
|
||||
return EXIT_SUCCESS; |
||||
} |
||||
|
@ -1,32 +0,0 @@
|
||||
#include "../src/common.h" |
||||
#include "../src/cmsg.h" |
||||
|
||||
int main() { |
||||
const char *argv[DATA_ARGS_MAX]; |
||||
f2b_cmsg_t msg; |
||||
|
||||
memset(&msg, 0x0, sizeof(msg)); |
||||
memset(argv, 0x0, sizeof(argv)); |
||||
|
||||
snprintf(msg.data, sizeof(msg.data), "test1\ntest2\n"); |
||||
msg.size = strlen(msg.data); |
||||
|
||||
f2b_cmsg_convert_args(&msg); |
||||
assert(memcmp(msg.data, "test1\0test2\0", 12) == 0); |
||||
|
||||
f2b_cmsg_extract_args(&msg, argv); |
||||
assert(argv[0] == msg.data + 0); |
||||
assert(argv[1] == msg.data + 6); |
||||
assert(memcmp(argv[0], "test1\0", 6) == 0); |
||||
assert(memcmp(argv[1], "test2\0", 6) == 0); |
||||
|
||||
/* data not null-terminated */ |
||||
msg.size = 10; |
||||
memcpy(msg.data, "test1\0test2\n", 10); |
||||
assert(f2b_cmsg_extract_args(&msg, argv) == -1); |
||||
|
||||
msg.size = 0; |
||||
assert(f2b_cmsg_extract_args(&msg, argv) == 0); |
||||
|
||||
return EXIT_SUCCESS; |
||||
} |
Loading…
Reference in new issue