diff --git a/src/Makefile.am b/src/Makefile.am index 4b45c678..ac677fad 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -45,6 +45,7 @@ ss_server_SOURCES = utils.c \ encrypt.c \ udprelay.c \ cache.c \ + acl.c \ resolv.c \ server.c diff --git a/src/acl.c b/src/acl.c index 6a5fc1de..3a9c7577 100644 --- a/src/acl.c +++ b/src/acl.c @@ -21,14 +21,13 @@ */ #include -#include #include "utils.h" -static struct ip_set acl_ip_set; -static struct cork_string_array acl_domain_array; +static struct ip_set acl_ipv4_set; +static struct ip_set acl_ipv6_set; -static void parse_addr_cidr(const char *str, char **host, int *cidr) +static void parse_addr_cidr(const char *str, char *host, int *cidr) { int ret = -1, n = 0; char *pch; @@ -39,17 +38,13 @@ static void parse_addr_cidr(const char *str, char **host, int *cidr) ret = pch - str; pch = strchr(pch + 1, '/'); } - if (n > 1) { - if (strcmp(str + ret, "]") != 0) { - ret = -1; - } - } if (ret == -1) { - *host = strdup(str); + strcpy(host, str); *cidr = -1; } else { - *host = ss_strndup(str, ret); - *cidr = atoi(strdup(str + ret + 1)); + memcpy(host, str, ret); + host[ret] = '\0'; + *cidr = atoi(str + ret + 1); } } @@ -57,10 +52,8 @@ int init_acl(const char *path) { // initialize ipset ipset_init_library(); - ipset_init(&acl_ip_set); - - // initialize array - cork_string_array_init(&acl_domain_array); + ipset_init(&acl_ipv4_set); + ipset_init(&acl_ipv6_set); FILE *f = fopen(path, "r"); if (f == NULL) { @@ -77,27 +70,27 @@ int init_acl(const char *path) line[len - 1] = '\0'; } - char *host = NULL; + char host[256]; int cidr; - parse_addr_cidr(line, &host, &cidr); - - if (cidr == -1) { - cork_string_array_append(&acl_domain_array, host); - } else { - struct cork_ipv4 addr; - int err = cork_ipv4_init(&addr, host); - if (!err) { + parse_addr_cidr(line, host, &cidr); + + struct cork_ip addr; + int err = cork_ip_init(&addr, host); + if (!err) { + if (addr.version == 4) { + if (cidr >= 0) { + ipset_ipv4_add_network(&acl_ipv4_set, &(addr.ip.v4), cidr); + } else { + ipset_ipv4_add(&acl_ipv4_set, &(addr.ip.v4)); + } + } else if (addr.version == 6) { if (cidr >= 0) { - ipset_ipv4_add_network(&acl_ip_set, &addr, cidr); + ipset_ipv6_add_network(&acl_ipv6_set, &(addr.ip.v6), cidr); } else { - ipset_ipv4_add(&acl_ip_set, &addr); + ipset_ipv6_add(&acl_ipv6_set, &(addr.ip.v6)); } } } - - if (host != NULL) { - free(host); - } } } @@ -108,48 +101,23 @@ int init_acl(const char *path) void free_acl(void) { - ipset_done(&acl_ip_set); -} - -int acl_contains_domain(const char * domain) -{ - const char **list = acl_domain_array.items; - const int size = acl_domain_array.size; - const int domain_len = strlen(domain); - int i, offset; - - for (i = 0; i < size; i++) { - const char *acl_domain = list[i]; - const int acl_domain_len = strlen(acl_domain); - if (acl_domain_len > domain_len) { - continue; - } - int match = true; - for (offset = 1; offset <= acl_domain_len; offset++) { - if (domain[domain_len - offset] != - acl_domain[acl_domain_len - offset]) { - match = false; - break; - } - } - if (match) { - return 1; - } - } - - - return 0; + ipset_done(&acl_ipv4_set); + ipset_done(&acl_ipv6_set); } int acl_contains_ip(const char * host) { - struct cork_ipv4 addr; - int err = cork_ipv4_init(&addr, host); + struct cork_ip addr; + int err = cork_ip_init(&addr, host); if (err) { return 0; } - struct cork_ip ip; - cork_ip_from_ipv4(&ip, &addr); - return ipset_contains_ip(&acl_ip_set, &ip); + if (addr.version == 4) { + return ipset_contains_ipv4(&acl_ipv4_set, &(addr.ip.v4)); + } else if (addr.version == 6) { + return ipset_contains_ipv6(&acl_ipv6_set, &(addr.ip.v6)); + } + + return 0; } diff --git a/src/acl.h b/src/acl.h index f51346b8..8643f510 100644 --- a/src/acl.h +++ b/src/acl.h @@ -27,6 +27,5 @@ int init_acl(const char *path); void free_acl(void); int acl_contains_ip(const char * ip); -int acl_contains_domain(const char * domain); #endif // _ACL_H diff --git a/src/server.c b/src/server.c index 9ce74008..de7e17ed 100644 --- a/src/server.c +++ b/src/server.c @@ -59,6 +59,7 @@ #endif #include "utils.h" +#include "acl.h" #include "server.h" #ifndef EAGAIN @@ -97,6 +98,7 @@ static void close_and_free_server(EV_P_ struct server *server); static void server_resolve_cb(struct sockaddr *addr, void *data); +int acl = 0; int verbose = 0; int udprelay = 0; static int fast_open = 0; @@ -517,6 +519,14 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) return; } + if (acl && (atyp == 1 || atyp == 4) && acl_contains_ip(host)) { + if (verbose) { + LOGI("Access denied to %s", host); + } + close_and_free_server(EV_A_ server); + return; + } + port = (*(uint16_t *)(server->buf + offset)); offset += 2; @@ -652,6 +662,25 @@ static void server_resolve_cb(struct sockaddr *addr, void *data) LOGI("udns resolved"); } + if (acl) { + char host[INET6_ADDRSTRLEN] = {0}; + if (addr->sa_family == AF_INET) { + struct sockaddr_in *s = (struct sockaddr_in *)&addr; + dns_ntop(AF_INET, &s->sin_addr, host, INET_ADDRSTRLEN); + } else if (addr->sa_family == AF_INET6) { + struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr; + dns_ntop(AF_INET6, &s->sin6_addr, host, INET6_ADDRSTRLEN); + } + + if (acl_contains_ip(host)) { + if (verbose) { + LOGI("Access denied to %s", host); + } + close_and_free_server(EV_A_ server); + return; + } + } + if (addr == NULL) { LOGE("unable to resolve"); close_and_free_server(EV_A_ server); @@ -1047,6 +1076,7 @@ int main(int argc, char **argv) static struct option long_options[] = { { "fast-open", no_argument, 0, 0 }, + { "acl", required_argument, 0, 0 }, { 0, 0, 0, 0 } }; @@ -1058,6 +1088,9 @@ int main(int argc, char **argv) case 0: if (option_index == 0) { fast_open = 1; + } else if (option_index == 1) { + LOGI("initialize acl..."); + acl = !init_acl(optarg); } break; case 's':