Alex 'AdUser' Z
4 years ago
5 changed files with 0 additions and 502 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); |
|
||||||
} |
|
@ -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); |
|
||||||
} |
|
Loading…
Reference in new issue