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