Browse Source

Simplify the server auto blocking mechanism

pull/2390/head
Max Lv 5 years ago
parent
commit
a99c39c7dd
5 changed files with 32 additions and 158 deletions
  1. 65
      src/acl.c
  2. 13
      src/acl.h
  3. 1
      src/common.h
  4. 2
      src/jconf.h
  5. 109
      src/server.c

65
src/acl.c

@ -49,75 +49,10 @@ static struct cork_dllist white_list_rules;
static int acl_mode = BLACK_LIST;
static struct cache *block_list;
static struct ip_set outbound_block_list_ipv4;
static struct ip_set outbound_block_list_ipv6;
static struct cork_dllist outbound_block_list_rules;
void
init_block_list()
{
cache_create(&block_list, 256, NULL);
}
void
free_block_list()
{
cache_clear(block_list, 0); // Remove all items
}
int
remove_from_block_list(char *addr)
{
size_t addr_len = strlen(addr);
return cache_remove(block_list, addr, addr_len);
}
void
clear_block_list()
{
cache_clear(block_list, 3600); // Clear items older than 1 hour
}
int
check_block_list(char *addr)
{
size_t addr_len = strlen(addr);
if (cache_key_exist(block_list, addr, addr_len)) {
int *count = NULL;
cache_lookup(block_list, addr, addr_len, &count);
if (count != NULL && *count > MAX_TRIES)
return 1;
}
return 0;
}
int
update_block_list(char *addr, int err_level)
{
size_t addr_len = strlen(addr);
if (cache_key_exist(block_list, addr, addr_len)) {
int *count = NULL;
cache_lookup(block_list, addr, addr_len, &count);
if (count != NULL) {
if (*count > MAX_TRIES)
return 1;
(*count) += err_level;
}
} else if (err_level > 0) {
int *count = (int *)ss_malloc(sizeof(int));
*count = 1;
cache_insert(block_list, addr, addr_len, count);
}
return 0;
}
static void
parse_addr_cidr(const char *str, char *host, int *cidr)
{

13
src/acl.h

@ -26,15 +26,8 @@
#define BLACK_LIST 0
#define WHITE_LIST 1
#define MAX_TRIES 256
#define MALICIOUS 8
#define SUSPICIOUS 4
#define BAD 2
#define MALFORMED 1
int init_acl(const char *path);
void free_acl(void);
void clear_block_list(void);
int acl_match_host(const char *ip);
int acl_add_ip(const char *ip);
@ -42,12 +35,6 @@ int acl_remove_ip(const char *ip);
int get_acl_mode(void);
void init_block_list();
void free_block_list();
int check_block_list(char *addr);
int update_block_list(char *addr, int err_level);
int remove_from_block_list(char *addr);
int outbound_block_match_host(const char *host);
#endif // _ACL_H

1
src/common.h

@ -54,6 +54,7 @@ int send_traffic_stat(uint64_t tx, uint64_t rx);
#define STAGE_SNI 3 /* Parse HTTP/SNI header */
#define STAGE_RESOLVE 4 /* Resolve the hostname */
#define STAGE_STREAM 5 /* Stream between client and server */
#define STAGE_STOP 6 /* Server stop to response */
/* Vals for long options */
enum {

2
src/jconf.h

@ -27,7 +27,7 @@
#define MAX_DSCP_NUM 64
#define MAX_CONF_SIZE 128 * 1024
#define MAX_CONNECT_TIMEOUT 10
#define MAX_REQUEST_TIMEOUT 60
#define MAX_REQUEST_TIMEOUT 30
#define MIN_UDP_TIMEOUT 10
#define DSCP_EF 0x2E

109
src/server.c

@ -93,7 +93,6 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents);
static void remote_recv_cb(EV_P_ ev_io *w, int revents);
static void remote_send_cb(EV_P_ ev_io *w, int revents);
static void server_timeout_cb(EV_P_ ev_timer *watcher, int revents);
static void block_list_clear_cb(EV_P_ ev_timer *watcher, int revents);
static remote_t *new_remote(int fd);
static server_t *new_server(int fd, listen_ctx_t *listener);
@ -138,7 +137,6 @@ uint64_t rx = 0;
#ifndef __MINGW32__
ev_timer stat_update_watcher;
#endif
ev_timer block_list_watcher;
static struct ev_signal sigint_watcher;
static struct ev_signal sigterm_watcher;
@ -269,43 +267,19 @@ get_peer_name(int fd)
return peer_name;
}
#ifdef __linux__
static void
set_linger(int fd)
stop_server(EV_P_ server_t *server)
{
struct linger so_linger;
memset(&so_linger, 0, sizeof(struct linger));
so_linger.l_onoff = 1;
so_linger.l_linger = 0;
setsockopt(fd, SOL_SOCKET, SO_LINGER, &so_linger, sizeof so_linger);
}
#endif
static void
reset_addr(int fd)
{
char *peer_name;
peer_name = get_peer_name(fd);
if (peer_name != NULL) {
remove_from_block_list(peer_name);
}
server->stage = STAGE_STOP;
}
static void
report_addr(int fd, int err_level, const char *info)
report_addr(int fd, const char *info)
{
#ifdef __linux__
set_linger(fd);
#endif
char *peer_name;
peer_name = get_peer_name(fd);
if (peer_name != NULL) {
LOGE("failed to handshake with %s: %s", peer_name, info);
// Avoid block local plugins
if (strcmp(peer_name, "127.0.0.1") != 0)
update_block_list(peer_name, err_level);
}
}
@ -724,10 +698,16 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
buffer_t *buf = server->buf;
// Ignore any new packet if the server is stopped
if (server->stage == STAGE_STOP) {
return;
}
if (server->stage == STAGE_STREAM) {
remote = server->remote;
buf = remote->buf;
// Only timer the watcher if a valid connection is established
ev_timer_again(EV_A_ & server->recv_ctx->watcher);
}
@ -760,15 +740,13 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
int err = crypto->decrypt(buf, server->d_ctx, SOCKET_BUF_SIZE);
if (err == CRYPTO_ERROR) {
report_addr(server->fd, MALICIOUS, "authentication error");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
report_addr(server->fd, "authentication error");
stop_server(EV_A_ server);
return;
} else if (err == CRYPTO_NEED_MORE) {
if (server->stage != STAGE_STREAM && server->frag > MAX_FRAG) {
report_addr(server->fd, MALICIOUS, "malicious fragmentation");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
report_addr(server->fd, "malicious fragmentation");
stop_server(EV_A_ server);
return;
}
server->frag++;
@ -830,8 +808,8 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
host, INET_ADDRSTRLEN);
offset += in_addr_len;
} else {
report_addr(server->fd, MALFORMED, "invalid length for ipv4 address");
close_and_free_server(EV_A_ server);
report_addr(server->fd, "invalid length for ipv4 address");
stop_server(EV_A_ server);
return;
}
addr->sin_port = *(uint16_t *)(server->buf->data + offset);
@ -847,8 +825,8 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
memcpy(host, server->buf->data + offset + 1, name_len);
offset += name_len + 1;
} else {
report_addr(server->fd, MALFORMED, "invalid host name length");
close_and_free_server(EV_A_ server);
report_addr(server->fd, "invalid host name length");
stop_server(EV_A_ server);
return;
}
if (acl && outbound_block_match_host(host) == 1) {
@ -880,8 +858,8 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
}
} else {
if (!validate_hostname(host, name_len)) {
report_addr(server->fd, MALFORMED, "invalid host name");
close_and_free_server(EV_A_ server);
report_addr(server->fd, "invalid host name");
stop_server(EV_A_ server);
return;
}
need_query = 1;
@ -898,8 +876,8 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
offset += in6_addr_len;
} else {
LOGE("invalid header with addr type %d", atyp);
report_addr(server->fd, MALFORMED, "invalid length for ipv6 address");
close_and_free_server(EV_A_ server);
report_addr(server->fd, "invalid length for ipv6 address");
stop_server(EV_A_ server);
return;
}
addr->sin6_port = *(uint16_t *)(server->buf->data + offset);
@ -911,8 +889,8 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
}
if (offset == 1) {
report_addr(server->fd, MALFORMED, "invalid address type");
close_and_free_server(EV_A_ server);
report_addr(server->fd, "invalid address type");
stop_server(EV_A_ server);
return;
}
@ -921,8 +899,8 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
offset += 2;
if (server->buf->len < offset) {
report_addr(server->fd, MALFORMED, "invalid request length");
close_and_free_server(EV_A_ server);
report_addr(server->fd, "invalid request length");
stop_server(EV_A_ server);
return;
} else {
server->buf->len -= offset;
@ -1036,12 +1014,6 @@ server_send_cb(EV_P_ ev_io *w, int revents)
}
}
static void
block_list_clear_cb(EV_P_ ev_timer *watcher, int revents)
{
clear_block_list();
}
static void
server_timeout_cb(EV_P_ ev_timer *watcher, int revents)
{
@ -1135,6 +1107,11 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
remote_t *remote = remote_recv_ctx->remote;
server_t *server = remote->server;
// Ignore any new packet if the server is stopped
if (server->stage == STAGE_STOP) {
return;
}
if (server == NULL) {
LOGE("invalid server");
close_and_free_remote(EV_A_ remote);
@ -1266,9 +1243,6 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
}
remote_send_ctx->connected = 1;
// Clear the state of this address in the block list
reset_addr(server->fd);
if (remote->buf->len == 0) {
server->stage = STAGE_STREAM;
ev_io_stop(EV_A_ & remote_send_ctx->io);
@ -1554,26 +1528,14 @@ accept_cb(EV_P_ ev_io *w, int revents)
char *peer_name = get_peer_name(serverfd);
if (peer_name != NULL) {
int in_white_list = 0;
if (acl) {
if ((get_acl_mode() == BLACK_LIST && acl_match_host(peer_name) == 1)
|| (get_acl_mode() == WHITE_LIST && acl_match_host(peer_name) >= 0)) {
LOGE("Access denied from %s", peer_name);
close(serverfd);
return;
} else if (acl_match_host(peer_name) == -1) {
in_white_list = 1;
}
}
if (!in_white_list && plugin == NULL
&& check_block_list(peer_name)) {
LOGE("block all requests from %s", peer_name);
#ifdef __linux__
set_linger(serverfd);
#endif
close(serverfd);
return;
}
}
int opt = 1;
@ -2101,9 +2063,6 @@ main(int argc, char **argv)
}
#endif
ev_timer_init(&block_list_watcher, block_list_clear_cb, UPDATE_INTERVAL, UPDATE_INTERVAL);
ev_timer_start(EV_DEFAULT, &block_list_watcher);
#ifndef __MINGW32__
// setuid
if (user != NULL && !run_as(user)) {
@ -2115,9 +2074,6 @@ main(int argc, char **argv)
}
#endif
// init block list
init_block_list();
// Init connections
cork_dllist_init(&connections);
@ -2128,17 +2084,12 @@ main(int argc, char **argv)
LOGI("closed gracefully");
}
// Free block list
free_block_list();
#ifndef __MINGW32__
if (manager_addr != NULL) {
ev_timer_stop(EV_DEFAULT, &stat_update_watcher);
}
#endif
ev_timer_stop(EV_DEFAULT, &block_list_watcher);
if (plugin != NULL) {
stop_plugin();
}

Loading…
Cancel
Save