Example #1
0
END_TEST


START_TEST(test_ip_address)
{
    DESCRIBE_TEST;
    struct cork_ip  addr;

#define GOOD(str, normalized) \
    { \
        struct cork_ip  addr; \
        fail_if_error(cork_ip_init(&addr, str)); \
        char  actual[CORK_IP_STRING_LENGTH]; \
        cork_ip_to_raw_string(&addr, actual); \
        fail_unless(strcmp(actual, normalized) == 0, \
                    "Unexpected string representation: " \
                    "got \"%s\", expected \"%s\"", \
                    actual, normalized); \
        \
        struct cork_ip  addr2; \
        cork_ip_init(&addr2, normalized); \
        fail_unless(cork_ip_equal(&addr, &addr2), \
                    "IP instances should be equal"); \
    }

#define BAD(str, unused) \
    { \
        struct cork_ip  addr; \
        fail_unless_error \
            (cork_ip_init(&addr, str), \
             "Shouldn't be able to initialize IP address from \"%s\"", \
             str); \
    }

    IPV4_TESTS(GOOD, BAD);
    IPV6_TESTS(GOOD, BAD);

#undef GOOD
#undef BAD

    struct cork_ipv4  addr4;
    struct cork_ipv6  addr6;

    fprintf(stderr, "Testing IP address versions\n");
    cork_ip_init(&addr, "192.168.1.1");
    cork_ipv4_init(&addr4, "192.168.1.1");
    fail_unless(addr.version == 4,
                "Unexpected IP address version (expected 4, got %u)",
                addr.version);
    fail_unless(cork_ipv4_equal(&addr.ip.v4, &addr4),
                "IP addresses should be equal");

    cork_ip_init(&addr, "fe80::1");
    cork_ipv6_init(&addr6, "fe80::1");
    fail_unless(addr.version == 6,
                "Unexpected IP address version (expected 6, got %u)",
                addr.version);
    fail_unless(cork_ipv6_equal(&addr.ip.v6, &addr6),
                "IP addresses should be equal");
}
Example #2
0
END_TEST


START_TEST(test_generic_ip_iterate_02)
{
    struct ip_set  set;
    ipset_init(&set);

    /*
     * These addresses are carefully constructed so that the same BDD
     * variable assignments are used to store both, apart from the
     * IPv4/v6 discriminator variable.  The goal is get a BDD that has
     * EITHER in the assignment for variable 0, but isn't simply the
     * empty or full set.
     */

    struct cork_ip  ip1;
    cork_ip_init(&ip1, "192.168.0.1"); /* 0xc0a80001 */

    struct cork_ip  ip2;
    cork_ip_init(&ip2, "c0a8:0001::");

    fail_if(ipset_ip_add(&set, &ip1),
            "Element should not be present");
    fail_if(ipset_ip_add_network(&set, &ip2, 32),
            "Element should not be present");

    struct ipset_iterator  *it = ipset_iterate_networks(&set, true);
    fail_if(it == NULL,
            "IP set iterator is NULL");

    fail_if(it->finished,
            "IP set shouldn't be empty");
    fail_unless(cork_ip_equal(&ip1, &it->addr),
                "IP address 0 doesn't match");
    fail_unless(it->cidr_prefix == 32,
                "IP CIDR prefix 0 doesn't match");

    ipset_iterator_advance(it);
    fail_if(it->finished,
            "IP set should have more than 1 element");
    fail_unless(cork_ip_equal(&ip2, &it->addr),
                "IP address 1 doesn't match");
    fail_unless(it->cidr_prefix == 32,
                "IP CIDR prefix 1 doesn't match");

    ipset_iterator_advance(it);
    fail_unless(it->finished,
                "IP set should contain 2 elements");

    ipset_iterator_free(it);

    ipset_done(&set);
}
Example #3
0
int
bind_to_address(int socket_fd, const char *host)
{
    static struct sockaddr_storage storage = { 0 };
    if (storage.ss_family == AF_INET) {
        return bind(socket_fd, (struct sockaddr *)&storage, sizeof(struct sockaddr_in));
    } else if (storage.ss_family == AF_INET6) {
        return bind(socket_fd, (struct sockaddr *)&storage, sizeof(struct sockaddr_in6));
    } else if (host != NULL) {
        struct cork_ip ip;
        if (cork_ip_init(&ip, host) != -1) {
            if (ip.version == 4) {
                struct sockaddr_in *addr = (struct sockaddr_in *)&storage;
                inet_pton(AF_INET, host, &addr->sin_addr);
                addr->sin_family = AF_INET;
                return bind(socket_fd, (struct sockaddr *)addr, sizeof(struct sockaddr_in));
            } else if (ip.version == 6) {
                struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&storage;
                inet_pton(AF_INET6, host, &addr->sin6_addr);
                addr->sin6_family = AF_INET6;
                return bind(socket_fd, (struct sockaddr *)addr, sizeof(struct sockaddr_in6));
            }
        }
    }
    return -1;
}
Example #4
0
static int
set_firewall_rule(char *addr, int add)
{
    char cli[256];
    struct cork_ip ip;

    if (getuid() != 0)
        return -1;

    if (cork_ip_init(&ip, addr))
        return -1;

    if (add) {
        if (mode == IPTABLES_MODE)
            sprintf(cli, ip.version == 4 ? iptables_add_rule : ip6tables_add_rule,
                    chain_name, addr);
        else if (mode == FIREWALLD_MODE)
            sprintf(cli, ip.version == 4 ? firewalld_add_rule : firewalld6_add_rule,
                    chain_name, addr);
        return run_cmd(cli);
    } else {
        if (mode == IPTABLES_MODE)
            sprintf(cli, ip.version == 4 ? iptables_remove_rule : ip6tables_remove_rule,
                    chain_name, addr);
        else if (mode == FIREWALLD_MODE)
            sprintf(cli, ip.version == 4 ? firewalld_remove_rule : firewalld6_remove_rule,
                    chain_name, addr);
        return run_cmd(cli);
    }

    return 0;
}
Example #5
0
/*
 * Return 0,  if not match.
 * Return 1,  if match black list.
 * Return -1, if match white list.
 */
int
acl_match_host(const char *host)
{
    struct cork_ip addr;
    int ret = 0;
    int err = cork_ip_init(&addr, host);

    if (err) {
        int host_len = strlen(host);
        if (lookup_rule(&black_list_rules, host, host_len) != NULL)
            ret = 1;
        else if (lookup_rule(&white_list_rules, host, host_len) != NULL)
            ret = -1;
        return ret;
    }

    if (addr.version == 4) {
        if (ipset_contains_ipv4(&black_list_ipv4, &(addr.ip.v4)))
            ret = 1;
        else if (ipset_contains_ipv4(&white_list_ipv4, &(addr.ip.v4)))
            ret = -1;
    } else if (addr.version == 6) {
        if (ipset_contains_ipv6(&black_list_ipv6, &(addr.ip.v6)))
            ret = 1;
        else if (ipset_contains_ipv6(&white_list_ipv6, &(addr.ip.v6)))
            ret = -1;
    }

    return ret;
}
Example #6
0
END_TEST


START_TEST(test_ipv4_iterate_network_01)
{
    struct ip_set  set;
    ipset_init(&set);

    struct cork_ip  ip1;
    cork_ip_init(&ip1, "192.168.0.0");

    fail_if(ipset_ip_add_network(&set, &ip1, 31),
            "Element should not be present");

    struct ipset_iterator  *it = ipset_iterate_networks(&set, true);
    fail_if(it == NULL,
            "IP set iterator is NULL");

    fail_if(it->finished,
            "IP set shouldn't be empty");
    fail_unless(cork_ip_equal(&ip1, &it->addr),
                "IP address 0 doesn't match");
    fail_unless(it->cidr_prefix == 31,
                "IP CIDR prefix 0 doesn't match");

    ipset_iterator_advance(it);
    fail_unless(it->finished,
                "IP set should contain 1 elements");

    ipset_iterator_free(it);

    ipset_done(&set);
}
Example #7
0
END_TEST


START_TEST(test_ipv6_iterate_01)
{
    struct ip_set  set;
    ipset_init(&set);

    struct cork_ip  ip1;
    cork_ip_init(&ip1, "fe80::1");

    fail_if(ipset_ip_add(&set, &ip1),
            "Element should not be present");

    struct ipset_iterator  *it = ipset_iterate(&set, true);
    fail_if(it == NULL,
            "IP set iterator is NULL");

    fail_if(it->finished,
            "IP set shouldn't be empty");
    fail_unless(cork_ip_equal(&ip1, &it->addr),
                "IP address 0 doesn't match");
    fail_unless(it->cidr_prefix == IPV6_BIT_SIZE,
                "IP CIDR prefix 0 doesn't match");

    ipset_iterator_advance(it);
    fail_unless(it->finished,
                "IP set should contain 1 element");

    ipset_iterator_free(it);

    ipset_done(&set);
}
Example #8
0
END_TEST


START_TEST(test_ipv6_iterate_network_03)
{
    struct ip_set  set;
    ipset_init(&set);

    /*
     * If we add all of the IP addresses in a network individually, we
     * should still get the network as a whole from the iterator.
     */

    struct cork_ip  ip1;
    cork_ip_init(&ip1, "fe80::");

    struct cork_ip  ip2;
    cork_ip_init(&ip2, "fe80::1");

    fail_if(ipset_ip_add(&set, &ip1),
            "Element should not be present");

    fail_if(ipset_ip_add(&set, &ip2),
            "Element should not be present");

    struct ipset_iterator  *it = ipset_iterate_networks(&set, true);
    fail_if(it == NULL,
            "IP set iterator is NULL");

    fail_if(it->finished,
            "IP set shouldn't be empty");
    fail_unless(cork_ip_equal(&ip1, &it->addr),
                "IP address 0 doesn't match");
    fail_unless(it->cidr_prefix == 127,
                "IP CIDR prefix 0 doesn't match");

    ipset_iterator_advance(it);
    fail_unless(it->finished,
                "IP set should contain 1 elements");

    ipset_iterator_free(it);

    ipset_done(&set);
}
Example #9
0
END_TEST


START_TEST(test_generic_ip_iterate_01)
{
    struct ip_set  set;
    ipset_init(&set);

    struct cork_ip  ip1;
    cork_ip_init(&ip1, "0.0.0.0");

    struct cork_ip  ip2;
    cork_ip_init(&ip2, "::");

    struct ipset_iterator  *it = ipset_iterate_networks(&set, false);
    fail_if(it == NULL,
            "IP set iterator is NULL");

    fail_if(it->finished,
            "IP set shouldn't be empty");
    fail_unless(cork_ip_equal(&ip1, &it->addr),
                "IP address 0 doesn't match");
    fail_unless(it->cidr_prefix == 0,
                "IP CIDR prefix 0 doesn't match");

    ipset_iterator_advance(it);
    fail_if(it->finished,
            "IP set should have more than 1 element");
    fail_unless(cork_ip_equal(&ip2, &it->addr),
                "IP address 1 doesn't match");
    fail_unless(it->cidr_prefix == 0,
                "IP CIDR prefix 1 doesn't match");

    ipset_iterator_advance(it);
    fail_unless(it->finished,
                "IP set should contain 2 elements");

    ipset_iterator_free(it);

    ipset_done(&set);
}
Example #10
0
int init_acl(const char *path, int mode)
{
    acl_mode = mode;

    // initialize ipset
    ipset_init_library();
    ipset_init(&acl_ipv4_set);
    ipset_init(&acl_ipv6_set);

    FILE *f = fopen(path, "r");
    if (f == NULL) {
        LOGE("Invalid acl path.");
        return -1;
    }

    char line[256];
    while (!feof(f))
        if (fgets(line, 256, f)) {
            // Trim the newline
            int len = strlen(line);
            if (len > 0 && line[len - 1] == '\n') {
                line[len - 1] = '\0';
            }

            char host[256];
            int cidr;
            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_ipv6_add_network(&acl_ipv6_set, &(addr.ip.v6), cidr);
                    } else {
                        ipset_ipv6_add(&acl_ipv6_set, &(addr.ip.v6));
                    }
                }
            }
        }

    fclose(f);

    return 0;
}
Example #11
0
int
is_ipv6only(ss_addr_t *servers, size_t server_num)
{
    struct cork_ip ip;
    int i;
    for (i = 0; i < server_num; i++)
    {
        if (cork_ip_init(&ip, servers[i].host) != -1) {
            if (ip.version != 6) {
                return 0;
            }
        }
    }
    return 1;
}
Example #12
0
int acl_remove_ip(const char *ip)
{
    struct cork_ip addr;
    int err = cork_ip_init(&addr, ip);
    if (err) {
        return -1;
    }

    if (addr.version == 4) {
        ipset_ipv4_remove(&acl_ipv4_set, &(addr.ip.v4));
    } else if (addr.version == 6) {
        ipset_ipv6_remove(&acl_ipv6_set, &(addr.ip.v6));
    }

    return 0;
}
Example #13
0
File: acl.c Project: 52M/xSocks
int
acl_contains_ip(const char * host) {
    struct cork_ip addr;
    int err = cork_ip_init(&addr, host);
    if (err) {
        return 0;
    }

    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;
}
Example #14
0
int
acl_add_ip(const char *ip)
{
    struct cork_ip addr;
    int err = cork_ip_init(&addr, ip);
    if (err) {
        return -1;
    }

    if (addr.version == 4) {
        ipset_ipv4_add(&black_list_ipv4, &(addr.ip.v4));
    } else if (addr.version == 6) {
        ipset_ipv6_add(&black_list_ipv6, &(addr.ip.v6));
    }

    return 0;
}
Example #15
0
void
parse_addr(const char *str, ss_addr_t *addr)
{
    int ipv6 = 0, ret = -1, n = 0;
    char *pch;

    struct cork_ip ip;
    if (cork_ip_init(&ip, str) != -1) {
        addr->host = strdup(str);
        addr->port = NULL;
        return;
    }

    pch = strchr(str, ':');
    while (pch != NULL) {
        n++;
        ret = pch - str;
        pch = strchr(pch + 1, ':');
    }
    if (n > 1) {
        ipv6 = 1;
        if (str[ret - 1] != ']') {
            ret = -1;
        }
    }

    if (ret == -1) {
        if (ipv6) {
            addr->host = ss_strndup(str + 1, strlen(str) - 2);
        } else {
            addr->host = strdup(str);
        }
        addr->port = NULL;
    } else {
        if (ipv6) {
            addr->host = ss_strndup(str + 1, ret - 2);
        } else {
            addr->host = ss_strndup(str, ret);
        }
        addr->port = strdup(str + ret + 1);
    }
}
Example #16
0
int acl_match_ip(const char *ip)
{
    struct cork_ip addr;
    int ret = cork_ip_init(&addr, ip);
    if (ret) {
        return 0;
    }

    if (addr.version == 4) {
        ret = ipset_contains_ipv4(&acl_ipv4_set, &(addr.ip.v4));
    } else if (addr.version == 6) {
        ret = ipset_contains_ipv6(&acl_ipv6_set, &(addr.ip.v6));
    }

    if (acl_mode == WHITE_LIST) {
        ret = !ret;
    }

    return ret;
}
Example #17
0
static void
server_recv_cb(EV_P_ ev_io *w, int revents)
{
    server_ctx_t *server_ctx = (server_ctx_t *)w;
    struct sockaddr_storage src_addr;
    memset(&src_addr, 0, sizeof(struct sockaddr_storage));

    buffer_t *buf = ss_malloc(sizeof(buffer_t));
    balloc(buf, buf_size);

    socklen_t src_addr_len = sizeof(struct sockaddr_storage);
    unsigned int offset    = 0;

#ifdef MODULE_REDIR
    char control_buffer[64] = { 0 };
    struct msghdr msg;
    memset(&msg, 0, sizeof(struct msghdr));
    struct iovec iov[1];
    struct sockaddr_storage dst_addr;
    memset(&dst_addr, 0, sizeof(struct sockaddr_storage));

    msg.msg_name       = &src_addr;
    msg.msg_namelen    = src_addr_len;
    msg.msg_control    = control_buffer;
    msg.msg_controllen = sizeof(control_buffer);

    iov[0].iov_base = buf->data;
    iov[0].iov_len  = buf_size;
    msg.msg_iov     = iov;
    msg.msg_iovlen  = 1;

    buf->len = recvmsg(server_ctx->fd, &msg, 0);
    if (buf->len == -1) {
        ERROR("[udp] server_recvmsg");
        goto CLEAN_UP;
    } else if (buf->len > packet_size) {
        if (verbose) {
            LOGI("[udp] UDP server_recv_recvmsg fragmentation");
        }
    }

    if (get_dstaddr(&msg, &dst_addr)) {
        LOGE("[udp] unable to get dest addr");
        goto CLEAN_UP;
    }

    src_addr_len = msg.msg_namelen;
#else
    ssize_t r;
    r = recvfrom(server_ctx->fd, buf->data, buf_size,
                 0, (struct sockaddr *)&src_addr, &src_addr_len);

    if (r == -1) {
        // error on recv
        // simply drop that packet
        ERROR("[udp] server_recv_recvfrom");
        goto CLEAN_UP;
    } else if (r > packet_size) {
        if (verbose) {
            LOGI("[udp] server_recv_recvfrom fragmentation");
        }
    }

    buf->len = r;
#endif

    if (verbose) {
        LOGI("[udp] server receive a packet");
    }

#ifdef MODULE_REMOTE
    tx += buf->len;

    int err = server_ctx->crypto->decrypt_all(buf, server_ctx->crypto->cipher, buf_size);
    if (err) {
        // drop the packet silently
        goto CLEAN_UP;
    }
#endif

#ifdef MODULE_LOCAL
#if !defined(MODULE_TUNNEL) && !defined(MODULE_REDIR)
#ifdef __ANDROID__
    tx += buf->len;
#endif
    uint8_t frag = *(uint8_t *)(buf->data + 2);
    offset += 3;
#endif
#endif

    /*
     *
     * SOCKS5 UDP Request
     * +----+------+------+----------+----------+----------+
     * |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
     * +----+------+------+----------+----------+----------+
     * | 2  |  1   |  1   | Variable |    2     | Variable |
     * +----+------+------+----------+----------+----------+
     *
     * SOCKS5 UDP Response
     * +----+------+------+----------+----------+----------+
     * |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
     * +----+------+------+----------+----------+----------+
     * | 2  |  1   |  1   | Variable |    2     | Variable |
     * +----+------+------+----------+----------+----------+
     *
     * shadowsocks UDP Request (before encrypted)
     * +------+----------+----------+----------+
     * | ATYP | DST.ADDR | DST.PORT |   DATA   |
     * +------+----------+----------+----------+
     * |  1   | Variable |    2     | Variable |
     * +------+----------+----------+----------+
     *
     * shadowsocks UDP Response (before encrypted)
     * +------+----------+----------+----------+
     * | ATYP | DST.ADDR | DST.PORT |   DATA   |
     * +------+----------+----------+----------+
     * |  1   | Variable |    2     | Variable |
     * +------+----------+----------+----------+
     *
     * shadowsocks UDP Request and Response (after encrypted)
     * +-------+--------------+
     * |   IV  |    PAYLOAD   |
     * +-------+--------------+
     * | Fixed |   Variable   |
     * +-------+--------------+
     *
     */

#ifdef MODULE_REDIR
    char addr_header[512] = { 0 };
    int addr_header_len   = construct_udprelay_header(&dst_addr, addr_header);

    if (addr_header_len == 0) {
        LOGE("[udp] failed to parse tproxy addr");
        goto CLEAN_UP;
    }

    // reconstruct the buffer
    brealloc(buf, buf->len + addr_header_len, buf_size);
    memmove(buf->data + addr_header_len, buf->data, buf->len);
    memcpy(buf->data, addr_header, addr_header_len);
    buf->len += addr_header_len;

#elif MODULE_TUNNEL

    char addr_header[512] = { 0 };
    char *host            = server_ctx->tunnel_addr.host;
    char *port            = server_ctx->tunnel_addr.port;
    uint16_t port_num     = (uint16_t)atoi(port);
    uint16_t port_net_num = htons(port_num);
    int addr_header_len   = 0;

    struct cork_ip ip;
    if (cork_ip_init(&ip, host) != -1) {
        if (ip.version == 4) {
            // send as IPv4
            struct in_addr host_addr;
            memset(&host_addr, 0, sizeof(struct in_addr));
            int host_len = sizeof(struct in_addr);

            if (dns_pton(AF_INET, host, &host_addr) == -1) {
                FATAL("IP parser error");
            }
            addr_header[addr_header_len++] = 1;
            memcpy(addr_header + addr_header_len, &host_addr, host_len);
            addr_header_len += host_len;
        } else if (ip.version == 6) {
            // send as IPv6
            struct in6_addr host_addr;
            memset(&host_addr, 0, sizeof(struct in6_addr));
            int host_len = sizeof(struct in6_addr);

            if (dns_pton(AF_INET6, host, &host_addr) == -1) {
                FATAL("IP parser error");
            }
            addr_header[addr_header_len++] = 4;
            memcpy(addr_header + addr_header_len, &host_addr, host_len);
            addr_header_len += host_len;
        } else {
            FATAL("IP parser error");
        }
    } else {
        // send as domain
        int host_len = strlen(host);

        addr_header[addr_header_len++] = 3;
        addr_header[addr_header_len++] = host_len;
        memcpy(addr_header + addr_header_len, host, host_len);
        addr_header_len += host_len;
    }
    memcpy(addr_header + addr_header_len, &port_net_num, 2);
    addr_header_len += 2;

    // reconstruct the buffer
    brealloc(buf, buf->len + addr_header_len, buf_size);
    memmove(buf->data + addr_header_len, buf->data, buf->len);
    memcpy(buf->data, addr_header, addr_header_len);
    buf->len += addr_header_len;

#else

    char host[257] = { 0 };
    char port[64]  = { 0 };
    struct sockaddr_storage dst_addr;
    memset(&dst_addr, 0, sizeof(struct sockaddr_storage));

    int addr_header_len = parse_udprelay_header(buf->data + offset, buf->len - offset,
                                                host, port, &dst_addr);
    if (addr_header_len == 0) {
        // error in parse header
        goto CLEAN_UP;
    }

    char *addr_header = buf->data + offset;
#endif

#ifdef MODULE_LOCAL
    char *key = hash_key(server_ctx->remote_addr->sa_family, &src_addr);
#else
    char *key = hash_key(dst_addr.ss_family, &src_addr);
#endif

    struct cache *conn_cache = server_ctx->conn_cache;

    remote_ctx_t *remote_ctx = NULL;
    cache_lookup(conn_cache, key, HASH_KEY_LEN, (void *)&remote_ctx);

    if (remote_ctx != NULL) {
        if (sockaddr_cmp(&src_addr, &remote_ctx->src_addr, sizeof(src_addr))) {
            remote_ctx = NULL;
        }
    }

    // reset the timer
    if (remote_ctx != NULL) {
        ev_timer_again(EV_A_ & remote_ctx->watcher);
    }

    if (remote_ctx == NULL) {
        if (verbose) {
#ifdef MODULE_REDIR
            char src[SS_ADDRSTRLEN];
            char dst[SS_ADDRSTRLEN];
            strcpy(src, get_addr_str((struct sockaddr *)&src_addr));
            strcpy(dst, get_addr_str((struct sockaddr *)&dst_addr));
            LOGI("[udp] cache miss: %s <-> %s", dst, src);
#else
            LOGI("[udp] cache miss: %s:%s <-> %s", host, port,
                 get_addr_str((struct sockaddr *)&src_addr));
#endif
        }
    } else {
        if (verbose) {
#ifdef MODULE_REDIR
            char src[SS_ADDRSTRLEN];
            char dst[SS_ADDRSTRLEN];
            strcpy(src, get_addr_str((struct sockaddr *)&src_addr));
            strcpy(dst, get_addr_str((struct sockaddr *)&dst_addr));
            LOGI("[udp] cache hit: %s <-> %s", dst, src);
#else
            LOGI("[udp] cache hit: %s:%s <-> %s", host, port,
                 get_addr_str((struct sockaddr *)&src_addr));
#endif
        }
    }

#ifdef MODULE_LOCAL

#if !defined(MODULE_TUNNEL) && !defined(MODULE_REDIR)
    if (frag) {
        LOGE("[udp] drop a message since frag is not 0, but %d", frag);
        goto CLEAN_UP;
    }
#endif

    const struct sockaddr *remote_addr = server_ctx->remote_addr;
    const int remote_addr_len          = server_ctx->remote_addr_len;

    if (remote_ctx == NULL) {
        // Bind to any port
        int remotefd = create_remote_socket(remote_addr->sa_family == AF_INET6);
        if (remotefd < 0) {
            ERROR("[udp] udprelay bind() error");
            goto CLEAN_UP;
        }
        setnonblocking(remotefd);

#ifdef SO_NOSIGPIPE
        set_nosigpipe(remotefd);
#endif
#ifdef IP_TOS
        // Set QoS flag
        int tos = 46;
        setsockopt(remotefd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
#endif
#ifdef SET_INTERFACE
        if (server_ctx->iface) {
            if (setinterface(remotefd, server_ctx->iface) == -1)
                ERROR("setinterface");
        }
#endif

#ifdef __ANDROID__
        if (vpn) {
            if (protect_socket(remotefd) == -1) {
                ERROR("protect_socket");
                close(remotefd);
                goto CLEAN_UP;
            }
        }
#endif

        // Init remote_ctx
        remote_ctx                  = new_remote(remotefd, server_ctx);
        remote_ctx->src_addr        = src_addr;
        remote_ctx->af              = remote_addr->sa_family;
        remote_ctx->addr_header_len = addr_header_len;
        memcpy(remote_ctx->addr_header, addr_header, addr_header_len);

        // Add to conn cache
        cache_insert(conn_cache, key, HASH_KEY_LEN, (void *)remote_ctx);

        // Start remote io
        ev_io_start(EV_A_ & remote_ctx->io);
        ev_timer_start(EV_A_ & remote_ctx->watcher);
    }

    if (offset > 0) {
        buf->len -= offset;
        memmove(buf->data, buf->data + offset, buf->len);
    }

    int err = server_ctx->crypto->encrypt_all(buf, server_ctx->crypto->cipher, buf_size);

    if (err) {
        // drop the packet silently
        goto CLEAN_UP;
    }

    if (buf->len > packet_size) {
        if (verbose) {
            LOGI("[udp] server_recv_sendto fragmentation");
        }
    }

    int s = sendto(remote_ctx->fd, buf->data, buf->len, 0, remote_addr, remote_addr_len);

    if (s == -1) {
        ERROR("[udp] server_recv_sendto");
    }

#else

    int cache_hit  = 0;
    int need_query = 0;

    if (buf->len - addr_header_len > packet_size) {
        if (verbose) {
            LOGI("[udp] server_recv_sendto fragmentation");
        }
    }

    if (remote_ctx != NULL) {
        cache_hit = 1;
        // detect destination mismatch
        if (remote_ctx->addr_header_len != addr_header_len
            || memcmp(addr_header, remote_ctx->addr_header, addr_header_len) != 0) {
            if (dst_addr.ss_family != AF_INET && dst_addr.ss_family != AF_INET6) {
                need_query = 1;
            }
        } else {
            memcpy(&dst_addr, &remote_ctx->dst_addr, sizeof(struct sockaddr_storage));
        }
    } else {
        if (dst_addr.ss_family == AF_INET || dst_addr.ss_family == AF_INET6) {
            int remotefd = create_remote_socket(dst_addr.ss_family == AF_INET6);
            if (remotefd != -1) {
                setnonblocking(remotefd);
#ifdef SO_BROADCAST
                set_broadcast(remotefd);
#endif
#ifdef SO_NOSIGPIPE
                set_nosigpipe(remotefd);
#endif
#ifdef IP_TOS
                // Set QoS flag
                int tos = 46;
                setsockopt(remotefd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
#endif
#ifdef SET_INTERFACE
                if (server_ctx->iface) {
                    if (setinterface(remotefd, server_ctx->iface) == -1)
                        ERROR("setinterface");
                }
#endif
                remote_ctx                  = new_remote(remotefd, server_ctx);
                remote_ctx->src_addr        = src_addr;
                remote_ctx->server_ctx      = server_ctx;
                remote_ctx->addr_header_len = addr_header_len;
                memcpy(remote_ctx->addr_header, addr_header, addr_header_len);
                memcpy(&remote_ctx->dst_addr, &dst_addr, sizeof(struct sockaddr_storage));
            } else {
                ERROR("[udp] bind() error");
                goto CLEAN_UP;
            }
        }
    }

    if (remote_ctx != NULL && !need_query) {
        size_t addr_len = get_sockaddr_len((struct sockaddr *)&dst_addr);
        int s           = sendto(remote_ctx->fd, buf->data + addr_header_len,
                                 buf->len - addr_header_len, 0,
                                 (struct sockaddr *)&dst_addr, addr_len);

        if (s == -1) {
            ERROR("[udp] sendto_remote");
            if (!cache_hit) {
                close_and_free_remote(EV_A_ remote_ctx);
            }
        } else {
            if (!cache_hit) {
                // Add to conn cache
                remote_ctx->af = dst_addr.ss_family;
                char *key = hash_key(remote_ctx->af, &remote_ctx->src_addr);
                cache_insert(server_ctx->conn_cache, key, HASH_KEY_LEN, (void *)remote_ctx);

                ev_io_start(EV_A_ & remote_ctx->io);
                ev_timer_start(EV_A_ & remote_ctx->watcher);
            }
        }
    } else {
        struct addrinfo hints;
        memset(&hints, 0, sizeof(struct addrinfo));
        hints.ai_family   = AF_UNSPEC;
        hints.ai_socktype = SOCK_DGRAM;
        hints.ai_protocol = IPPROTO_UDP;

        struct query_ctx *query_ctx = new_query_ctx(buf->data + addr_header_len,
                                                    buf->len - addr_header_len);
        query_ctx->server_ctx      = server_ctx;
        query_ctx->addr_header_len = addr_header_len;
        query_ctx->src_addr        = src_addr;
        memcpy(query_ctx->addr_header, addr_header, addr_header_len);

        if (need_query) {
            query_ctx->remote_ctx = remote_ctx;
        }

        struct ResolvQuery *query = resolv_query(host, query_resolve_cb,
                                                 NULL, query_ctx, htons(atoi(port)));
        if (query == NULL) {
            ERROR("[udp] unable to create DNS query");
            close_and_free_query(EV_A_ query_ctx);
            goto CLEAN_UP;
        }
        query_ctx->query = query;
    }
#endif

CLEAN_UP:
    bfree(buf);
    ss_free(buf);
}
Example #18
0
static void server_recv_cb(EV_P_ ev_io *w, int revents)
{
    struct server_ctx *server_recv_ctx = (struct server_ctx *)w;
    struct server *server = server_recv_ctx->server;
    struct remote *remote = NULL;

    int len = server->buf_len;
    char **buf = &server->buf;

    ev_timer_again(EV_A_ & server->recv_ctx->watcher);

    if (server->stage != 0) {
        remote = server->remote;
        buf = &remote->buf;
        len = 0;
    }

    ssize_t r = recv(server->fd, *buf + len, BUF_SIZE - len, 0);

    if (r == 0) {
        // connection closed
        if (verbose) {
            LOGI("server_recv close the connection");
        }
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    } else if (r == -1) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            // no data
            // continue to wait for recv
            return;
        } else {
            ERROR("server recv");
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        }
    }

    // handle incomplete header
    if (server->stage == 0) {
        r += server->buf_len;
        if (r <= enc_get_iv_len()) {
            // wait for more
            if (verbose) {
#ifdef __MINGW32__
                LOGI("imcomplete header: %u", r);
#else
                LOGI("imcomplete header: %zu", r);
#endif
            }
            server->buf_len = r;
            return;
        } else {
            server->buf_len = 0;
        }
    }

    *buf = ss_decrypt(BUF_SIZE, *buf, &r, server->d_ctx);

    if (*buf == NULL) {
        LOGE("invalid password or cipher");
        report_addr(server->fd);
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    }

    // handshake and transmit data
    if (server->stage == 5) {
        int s = send(remote->fd, remote->buf, r, 0);
        if (s == -1) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                // no data, wait for send
                remote->buf_len = r;
                remote->buf_idx = 0;
                ev_io_stop(EV_A_ & server_recv_ctx->io);
                ev_io_start(EV_A_ & remote->send_ctx->io);
            } else {
                ERROR("server_recv_send");
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
            }
        } else if (s < r) {
            remote->buf_len = r - s;
            remote->buf_idx = s;
            ev_io_stop(EV_A_ & server_recv_ctx->io);
            ev_io_start(EV_A_ & remote->send_ctx->io);
        }
        return;

    } else if (server->stage == 0) {

        /*
         * Shadowsocks Protocol:
         *
         *    +------+----------+----------+
         *    | ATYP | DST.ADDR | DST.PORT |
         *    +------+----------+----------+
         *    |  1   | Variable |    2     |
         *    +------+----------+----------+
         */

        int offset = 1;
        int need_query = 0;
        char atyp = server->buf[0] & 0x0F;
#ifdef USE_CRYPTO_OPENSSL
        char atyp_btc = (server->buf[0] & 0x10) == 0x10 ? 1 : 0;
#endif
        char host[256] = { 0 };
        uint16_t port = 0;
        struct addrinfo info;
        struct sockaddr_storage storage;
        memset(&info, 0, sizeof(struct addrinfo));
        memset(&storage, 0, sizeof(struct sockaddr_storage));

        // get remote addr and port
        if (atyp == 1) {
            // IP V4
            struct sockaddr_in *addr = (struct sockaddr_in *)&storage;
            size_t in_addr_len = sizeof(struct in_addr);
            addr->sin_family = AF_INET;
            if (r > in_addr_len) {
                addr->sin_addr = *(struct in_addr *)(server->buf + offset);
                dns_ntop(AF_INET, (const void *)(server->buf + offset),
                         host, INET_ADDRSTRLEN);
                offset += in_addr_len;
            } else {
                LOGE("invalid header with addr type %d", atyp);
                report_addr(server->fd);
                close_and_free_server(EV_A_ server);
                return;
            }
            addr->sin_port = *(uint16_t *)(server->buf + offset);
            info.ai_family = AF_INET;
            info.ai_socktype = SOCK_STREAM;
            info.ai_protocol = IPPROTO_TCP;
            info.ai_addrlen = sizeof(struct sockaddr_in);
            info.ai_addr = (struct sockaddr *)addr;
        } else if (atyp == 3) {
            // Domain name
            uint8_t name_len = *(uint8_t *)(server->buf + offset);
            if (name_len < r && name_len < 255 && name_len > 0) {
                memcpy(host, server->buf + offset + 1, name_len);
                offset += name_len + 1;
            }
            struct cork_ip ip;
            if (cork_ip_init(&ip, host) != -1) {
                info.ai_socktype = SOCK_STREAM;
                info.ai_protocol = IPPROTO_TCP;
                if (ip.version == 4) {
                    struct sockaddr_in *addr = (struct sockaddr_in *)&storage;
                    dns_pton(AF_INET, host, &(addr->sin_addr));
                    addr->sin_port = *(uint16_t *)(server->buf + offset);
                    addr->sin_family = AF_INET;
                    info.ai_family = AF_INET;
                    info.ai_addrlen = sizeof(struct sockaddr_in);
                    info.ai_addr = (struct sockaddr *)addr;
                } else if (ip.version == 6) {
                    struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&storage;
                    dns_pton(AF_INET6, host, &(addr->sin6_addr));
                    addr->sin6_port = *(uint16_t *)(server->buf + offset);
                    addr->sin6_family = AF_INET6;
                    info.ai_family = AF_INET6;
                    info.ai_addrlen = sizeof(struct sockaddr_in6);
                    info.ai_addr = (struct sockaddr *)addr;
                }
            } else {
                need_query = 1;
            }
        } else if (atyp == 4) {
            // IP V6
            struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&storage;
            size_t in6_addr_len = sizeof(struct in6_addr);
            addr->sin6_family = AF_INET6;
            if (r > in6_addr_len) {
                addr->sin6_addr = *(struct in6_addr *)(server->buf + offset);
                dns_ntop(AF_INET6, (const void *)(server->buf + offset),
                         host, INET6_ADDRSTRLEN);
                offset += in6_addr_len;
            } else {
                LOGE("invalid header with addr type %d", atyp);
                report_addr(server->fd);
                close_and_free_server(EV_A_ server);
                return;
            }
            addr->sin6_port = *(uint16_t *)(server->buf + offset);
            info.ai_family = AF_INET6;
            info.ai_socktype = SOCK_STREAM;
            info.ai_protocol = IPPROTO_TCP;
            info.ai_addrlen = sizeof(struct sockaddr_in6);
            info.ai_addr = (struct sockaddr *)addr;
        }

        if (offset == 1) {
            LOGE("invalid header with addr type %d", atyp);
            report_addr(server->fd);
            close_and_free_server(EV_A_ server);
            return;
        }

        if (acl && !need_query && 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;

        if (verbose) {
            LOGI("connect to: %s:%d", host, ntohs(port));
        }

#ifdef USE_CRYPTO_OPENSSL
        if (bitcoin_list != NULL) {
            if (atyp_btc == 0) {
                if (verbose) {
                    LOGE("client should carry with bitcoin information");
                }
                close_and_free_server(EV_A_ server);
                return;
            }
            /*
             * bitcoin information:
             *    +-----------+-----------+----------+
             *    | Signature | Timestamp |  Address |
             *    +-----------+-----------+----------+
             *    |    65     |     4     |  String  |
             *    +-----------+-----------+----------+
             */
            char *signature = server->buf + offset;
            uint8_t *t = (uint8_t *)server->buf + offset + 65;
            uint32_t ts = ((uint32_t)*(t + 0) << 24) + ((uint32_t)*(t + 1) << 16)
                          + ((uint32_t)*(t + 2) << 8) + ((uint32_t)*(t + 3) << 0);
            char *address = server->buf + offset + 65 + 4;
            int64_t ts_offset = (int64_t)time(NULL) - (int64_t)ts;
            if (labs(ts_offset) > 60 * 30) {
                if (verbose) {
                    LOGE("invalid timestamp: %u, offset too large: %d",
                         ts, (int32_t)ts_offset);
                }
                close_and_free_server(EV_A_ server);
                return;
            }
            if (!bitcoin_verify_message(address, (uint8_t *)signature, t, 4)) {
                if (verbose) {
                    LOGE("invalid signature, address: %s", address);
                }
                close_and_free_server(EV_A_ server);
                return;
            }
            if (bitcoin_check_address(bitcoin_list, address) == 0) {
                if (verbose) {
                    LOGE("address \"%s\" is NOT in list", address);
                }
                close_and_free_server(EV_A_ server);
                return;
            }
            offset += 65 + 4 + strlen(address) + 1;

            if (verbose) {
                LOGI("bitcoin address: %s, time offset: %d",
                     address, (int32_t)ts_offset);
            }
        }
#endif

        // XXX: should handle buffer carefully
        if (r > offset) {
            server->buf_len = r - offset;
            server->buf_idx = offset;
        }

        if (!need_query) {
            struct remote *remote = connect_to_remote(&info, server);

            if (remote == NULL) {
                LOGE("connect error");
                close_and_free_server(EV_A_ server);
                return;
            } else {
                server->remote = remote;
                remote->server = server;

                // XXX: should handle buffer carefully
                if (server->buf_len > 0) {
                    memcpy(remote->buf, server->buf + server->buf_idx,
                           server->buf_len);
                    remote->buf_len = server->buf_len;
                    remote->buf_idx = 0;
                    server->buf_len = 0;
                    server->buf_idx = 0;
                }

                server->stage = 4;

                // listen to remote connected event
                ev_io_stop(EV_A_ & server_recv_ctx->io);
                ev_io_start(EV_A_ & remote->send_ctx->io);
            }
        } else {
            server->stage = 4;
            server->query = resolv_query(host, server_resolve_cb, NULL, server,
                                         port);

            ev_io_stop(EV_A_ & server_recv_ctx->io);
        }

        return;
    }
    // should not reach here
    FATAL("server context error");
}
Example #19
0
static void server_recv_cb(EV_P_ ev_io *w, int revents)
{
    struct server_ctx *server_recv_ctx = (struct server_ctx *)w;
    struct server *server = server_recv_ctx->server;
    struct remote *remote = NULL;

    int len = server->buf_len;
    char **buf = &server->buf;

    ev_timer_again(EV_A_ & server->recv_ctx->watcher);

    if (server->stage != 0) {
        remote = server->remote;
        buf = &remote->buf;
        len = 0;
    }

    ssize_t r = recv(server->fd, *buf + len, BUF_SIZE - len, 0);

    if (r == 0) {
        // connection closed
        if (verbose) {
            LOGI("server_recv close the connection");
        }
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    } else if (r == -1) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            // no data
            // continue to wait for recv
            return;
        } else {
            ERROR("server recv");
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        }
    }

    tx += r;

    // handle incomplete header
    if (server->stage == 0) {
        r += server->buf_len;
        if (r <= enc_get_iv_len()) {
            // wait for more
            if (verbose) {
#ifdef __MINGW32__
                LOGI("imcomplete header: %u", r);
#else
                LOGI("imcomplete header: %zu", r);
#endif
            }
            server->buf_len = r;
            return;
        } else {
            server->buf_len = 0;
        }
    }

    *buf = ss_decrypt(BUF_SIZE, *buf, &r, server->d_ctx);

    if (*buf == NULL) {
        LOGE("invalid password or cipher");
        report_addr(server->fd);
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    }

    // handshake and transmit data
    if (server->stage == 5) {
        int s = send(remote->fd, remote->buf, r, 0);
        if (s == -1) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                // no data, wait for send
                remote->buf_len = r;
                remote->buf_idx = 0;
                ev_io_stop(EV_A_ & server_recv_ctx->io);
                ev_io_start(EV_A_ & remote->send_ctx->io);
            } else {
                ERROR("server_recv_send");
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
            }
        } else if (s < r) {
            remote->buf_len = r - s;
            remote->buf_idx = s;
            ev_io_stop(EV_A_ & server_recv_ctx->io);
            ev_io_start(EV_A_ & remote->send_ctx->io);
        }
        return;

    } else if (server->stage == 0) {

        /*
         * Shadowsocks Protocol:
         *
         *    +------+----------+----------+
         *    | ATYP | DST.ADDR | DST.PORT |
         *    +------+----------+----------+
         *    |  1   | Variable |    2     |
         *    +------+----------+----------+
         */

        int offset = 0;
        int need_query = 0;
        char atyp = server->buf[offset++];
        char host[256] = { 0 };
        uint16_t port = 0;
        struct addrinfo info;
        struct sockaddr_storage storage;
        memset(&info, 0, sizeof(struct addrinfo));
        memset(&storage, 0, sizeof(struct sockaddr_storage));

        // get remote addr and port
        if (atyp == 1) {
            // IP V4
            struct sockaddr_in *addr = (struct sockaddr_in *)&storage;
            size_t in_addr_len = sizeof(struct in_addr);
            addr->sin_family = AF_INET;
            if (r > in_addr_len) {
                addr->sin_addr = *(struct in_addr *)(server->buf + offset);
                dns_ntop(AF_INET, (const void *)(server->buf + offset),
                         host, INET_ADDRSTRLEN);
                offset += in_addr_len;
            } else {
                LOGE("invalid header with addr type %d", atyp);
                report_addr(server->fd);
                close_and_free_server(EV_A_ server);
                return;
            }
            addr->sin_port = *(uint16_t *)(server->buf + offset);
            info.ai_family = AF_INET;
            info.ai_socktype = SOCK_STREAM;
            info.ai_protocol = IPPROTO_TCP;
            info.ai_addrlen = sizeof(struct sockaddr_in);
            info.ai_addr = (struct sockaddr *)addr;
        } else if (atyp == 3) {
            // Domain name
            uint8_t name_len = *(uint8_t *)(server->buf + offset);
            if (name_len < r) {
                memcpy(host, server->buf + offset + 1, name_len);
                offset += name_len + 1;
            } else {
                LOGE("invalid name length: %d", name_len);
                report_addr(server->fd);
                close_and_free_server(EV_A_ server);
                return;
            }
            struct cork_ip ip;
            if (cork_ip_init(&ip, host) != -1) {
                info.ai_socktype = SOCK_STREAM;
                info.ai_protocol = IPPROTO_TCP;
                if (ip.version == 4) {
                    struct sockaddr_in *addr = (struct sockaddr_in *)&storage;
                    dns_pton(AF_INET, host, &(addr->sin_addr));
                    addr->sin_port = *(uint16_t *)(server->buf + offset);
                    addr->sin_family = AF_INET;
                    info.ai_family = AF_INET;
                    info.ai_addrlen = sizeof(struct sockaddr_in);
                    info.ai_addr = (struct sockaddr *)addr;
                } else if (ip.version == 6) {
                    struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&storage;
                    dns_pton(AF_INET6, host, &(addr->sin6_addr));
                    addr->sin6_port = *(uint16_t *)(server->buf + offset);
                    addr->sin6_family = AF_INET6;
                    info.ai_family = AF_INET6;
                    info.ai_addrlen = sizeof(struct sockaddr_in6);
                    info.ai_addr = (struct sockaddr *)addr;
                }
            } else {
                need_query = 1;
            }
        } else if (atyp == 4) {
            // IP V6
            struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&storage;
            size_t in6_addr_len = sizeof(struct in6_addr);
            addr->sin6_family = AF_INET6;
            if (r > in6_addr_len) {
                addr->sin6_addr = *(struct in6_addr *)(server->buf + offset);
                dns_ntop(AF_INET6, (const void *)(server->buf + offset),
                         host, INET6_ADDRSTRLEN);
                offset += in6_addr_len;
            } else {
                LOGE("invalid header with addr type %d", atyp);
                report_addr(server->fd);
                close_and_free_server(EV_A_ server);
                return;
            }
            addr->sin6_port = *(uint16_t *)(server->buf + offset);
            info.ai_family = AF_INET6;
            info.ai_socktype = SOCK_STREAM;
            info.ai_protocol = IPPROTO_TCP;
            info.ai_addrlen = sizeof(struct sockaddr_in6);
            info.ai_addr = (struct sockaddr *)addr;
        }

        if (offset == 1) {
            LOGE("invalid header with addr type %d", atyp);
            report_addr(server->fd);
            close_and_free_server(EV_A_ server);
            return;
        }

        if (acl && !need_query && 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;

        if (verbose) {
            LOGI("connect to: %s:%d", host, ntohs(port));
        }

        // XXX: should handle buffer carefully
        if (r > offset) {
            server->buf_len = r - offset;
            server->buf_idx = offset;
        }

        if (!need_query) {
            struct remote *remote = connect_to_remote(&info, server);

            if (remote == NULL) {
                LOGE("connect error");
                close_and_free_server(EV_A_ server);
                return;
            } else {
                server->remote = remote;
                remote->server = server;

                // XXX: should handle buffer carefully
                if (server->buf_len > 0) {
                    memcpy(remote->buf, server->buf + server->buf_idx,
                           server->buf_len);
                    remote->buf_len = server->buf_len;
                    remote->buf_idx = 0;
                    server->buf_len = 0;
                    server->buf_idx = 0;
                }

                server->stage = 4;

                // listen to remote connected event
                ev_io_stop(EV_A_ & server_recv_ctx->io);
                ev_io_start(EV_A_ & remote->send_ctx->io);
            }
        } else {
            server->stage = 4;
            server->query = resolv_query(host, server_resolve_cb, NULL, server,
                                         port);

            ev_io_stop(EV_A_ & server_recv_ctx->io);
        }

        return;
    }
    // should not reach here
    FATAL("server context error");
}
Example #20
0
static int
parse_udprelay_header(const char *buf, const size_t buf_len,
                      char *host, char *port, struct sockaddr_storage *storage)
{
    const uint8_t atyp = *(uint8_t *)buf;
    int offset         = 1;

    // get remote addr and port
    if ((atyp & ADDRTYPE_MASK) == 1) {
        // IP V4
        size_t in_addr_len = sizeof(struct in_addr);
        if (buf_len >= in_addr_len + 3) {
            if (storage != NULL) {
                struct sockaddr_in *addr = (struct sockaddr_in *)storage;
                addr->sin_family = AF_INET;
                addr->sin_addr   = *(struct in_addr *)(buf + offset);
                addr->sin_port   = *(uint16_t *)(buf + offset + in_addr_len);
            }
            if (host != NULL) {
                dns_ntop(AF_INET, (const void *)(buf + offset),
                         host, INET_ADDRSTRLEN);
            }
            offset += in_addr_len;
        }
    } else if ((atyp & ADDRTYPE_MASK) == 3) {
        // Domain name
        uint8_t name_len = *(uint8_t *)(buf + offset);
        if (name_len + 4 <= buf_len) {
            if (storage != NULL) {
                char tmp[257] = { 0 };
                struct cork_ip ip;
                memcpy(tmp, buf + offset + 1, name_len);
                if (cork_ip_init(&ip, tmp) != -1) {
                    if (ip.version == 4) {
                        struct sockaddr_in *addr = (struct sockaddr_in *)storage;
                        dns_pton(AF_INET, tmp, &(addr->sin_addr));
                        addr->sin_port   = *(uint16_t *)(buf + offset + 1 + name_len);
                        addr->sin_family = AF_INET;
                    } else if (ip.version == 6) {
                        struct sockaddr_in6 *addr = (struct sockaddr_in6 *)storage;
                        dns_pton(AF_INET, tmp, &(addr->sin6_addr));
                        addr->sin6_port   = *(uint16_t *)(buf + offset + 1 + name_len);
                        addr->sin6_family = AF_INET6;
                    }
                }
            }
            if (host != NULL) {
                memcpy(host, buf + offset + 1, name_len);
            }
            offset += 1 + name_len;
        }
    } else if ((atyp & ADDRTYPE_MASK) == 4) {
        // IP V6
        size_t in6_addr_len = sizeof(struct in6_addr);
        if (buf_len >= in6_addr_len + 3) {
            if (storage != NULL) {
                struct sockaddr_in6 *addr = (struct sockaddr_in6 *)storage;
                addr->sin6_family = AF_INET6;
                addr->sin6_addr   = *(struct in6_addr *)(buf + offset);
                addr->sin6_port   = *(uint16_t *)(buf + offset + in6_addr_len);
            }
            if (host != NULL) {
                dns_ntop(AF_INET6, (const void *)(buf + offset),
                         host, INET6_ADDRSTRLEN);
            }
            offset += in6_addr_len;
        }
    }

    if (offset == 1) {
        LOGE("[udp] invalid header with addr type %d", atyp);
        return 0;
    }

    if (port != NULL) {
        sprintf(port, "%d", ntohs(*(uint16_t *)(buf + offset)));
    }
    offset += 2;

    return offset;
}
Example #21
0
static void server_recv_cb(EV_P_ ev_io *w, int revents)
{
    struct server_ctx *server_recv_ctx = (struct server_ctx *)w;
    struct server *server = server_recv_ctx->server;
    struct remote *remote = NULL;

    int len = server->buf_len;
    char **buf = &server->buf;

    ev_timer_again(EV_A_ & server->recv_ctx->watcher);

    if (server->stage != 0) {
        remote = server->remote;
        buf = &remote->buf;
        len = 0;
    }

    ssize_t r = recv(server->fd, *buf + len, BUF_SIZE - len, 0);

    if (r == 0) {
        // connection closed
        if (verbose) {
            LOGI("server_recv close the connection");
        }
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    } else if (r == -1) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            // no data
            // continue to wait for recv
            return;
        } else {
            ERROR("server recv");
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        }
    }

    tx += r;

    // handle incomplete header
    if (server->stage == 0) {
        r += server->buf_len;
        if (r <= enc_get_iv_len()) {
            // wait for more
            if (verbose) {
#ifdef __MINGW32__
                LOGI("imcomplete header: %u", r);
#else
                LOGI("imcomplete header: %zu", r);
#endif
            }
            server->buf_len = r;
            return;
        } else {
            server->buf_len = 0;
        }
    }

    *buf = ss_decrypt(BUF_SIZE, *buf, &r, server->d_ctx);

    if (*buf == NULL) {
        LOGE("invalid password or cipher");
        report_addr(server->fd);
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    }

    // handshake and transmit data
    if (server->stage == 5) {
        if (server->auth && !ss_check_hash(&remote->buf, &r, server->chunk, server->d_ctx, BUF_SIZE)) {
            LOGE("hash error");
            report_addr(server->fd);
            close_and_free_server(EV_A_ server);
            close_and_free_remote(EV_A_ remote);
            return;
        }
        int s = send(remote->fd, remote->buf, r, 0);
        if (s == -1) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                // no data, wait for send
                remote->buf_len = r;
                remote->buf_idx = 0;
                ev_io_stop(EV_A_ & server_recv_ctx->io);
                ev_io_start(EV_A_ & remote->send_ctx->io);
            } else {
                ERROR("server_recv_send");
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
            }
        } else if (s < r) {
            remote->buf_len = r - s;
            remote->buf_idx = s;
            ev_io_stop(EV_A_ & server_recv_ctx->io);
            ev_io_start(EV_A_ & remote->send_ctx->io);
        }
        return;

    } else if (server->stage == 0) {

        /*
         * Shadowsocks TCP Relay Header:
         *
         *    +------+----------+----------+----------------+
         *    | ATYP | DST.ADDR | DST.PORT |    HMAC-SHA1   |
         *    +------+----------+----------+----------------+
         *    |  1   | Variable |    2     |      10        |
         *    +------+----------+----------+----------------+
         *
         *    If ATYP & ONETIMEAUTH_FLAG(0x10) == 1, Authentication (HMAC-SHA1) is enabled.
         *
         *    The key of HMAC-SHA1 is (IV + KEY) and the input is the whole header.
         *    The output of HMAC-SHA is truncated to 10 bytes (leftmost bits).
         */

        /*
         * Shadowsocks TCP Request's Chunk Authentication (Optional, no hash check for response's payload):
         *
         *    +------+-----------+-------------+------+
         *    | LEN  | HMAC-SHA1 |    DATA     |      ...
         *    +------+-----------+-------------+------+
         *    |  2   |    10     |  Variable   |      ...
         *    +------+-----------+-------------+------+
         *
         *    The key of HMAC-SHA1 is (IV + CHUNK ID)
         *    The output of HMAC-SHA is truncated to 10 bytes (leftmost bits).
         */

        int offset = 0;
        int need_query = 0;
        char atyp = server->buf[offset++];
        char host[256] = { 0 };
        uint16_t port = 0;
        struct addrinfo info;
        struct sockaddr_storage storage;
        memset(&info, 0, sizeof(struct addrinfo));
        memset(&storage, 0, sizeof(struct sockaddr_storage));

        // get remote addr and port
        if ((atyp & ADDRTYPE_MASK) == 1) {
            // IP V4
            struct sockaddr_in *addr = (struct sockaddr_in *)&storage;
            size_t in_addr_len = sizeof(struct in_addr);
            addr->sin_family = AF_INET;
            if (r > in_addr_len) {
                addr->sin_addr = *(struct in_addr *)(server->buf + offset);
                dns_ntop(AF_INET, (const void *)(server->buf + offset),
                         host, INET_ADDRSTRLEN);
                offset += in_addr_len;
            } else {
                LOGE("invalid header with addr type %d", atyp);
                report_addr(server->fd);
                close_and_free_server(EV_A_ server);
                return;
            }
            addr->sin_port = *(uint16_t *)(server->buf + offset);
            info.ai_family = AF_INET;
            info.ai_socktype = SOCK_STREAM;
            info.ai_protocol = IPPROTO_TCP;
            info.ai_addrlen = sizeof(struct sockaddr_in);
            info.ai_addr = (struct sockaddr *)addr;
        } else if ((atyp & ADDRTYPE_MASK) == 3) {
            // Domain name
            uint8_t name_len = *(uint8_t *)(server->buf + offset);
            if (name_len < r) {
                memcpy(host, server->buf + offset + 1, name_len);
                offset += name_len + 1;
            } else {
                LOGE("invalid name length: %d", name_len);
                report_addr(server->fd);
                close_and_free_server(EV_A_ server);
                return;
            }
            struct cork_ip ip;
            if (cork_ip_init(&ip, host) != -1) {
                info.ai_socktype = SOCK_STREAM;
                info.ai_protocol = IPPROTO_TCP;
                if (ip.version == 4) {
                    struct sockaddr_in *addr = (struct sockaddr_in *)&storage;
                    dns_pton(AF_INET, host, &(addr->sin_addr));
                    addr->sin_port = *(uint16_t *)(server->buf + offset);
                    addr->sin_family = AF_INET;
                    info.ai_family = AF_INET;
                    info.ai_addrlen = sizeof(struct sockaddr_in);
                    info.ai_addr = (struct sockaddr *)addr;
                } else if (ip.version == 6) {
                    struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&storage;
                    dns_pton(AF_INET6, host, &(addr->sin6_addr));
                    addr->sin6_port = *(uint16_t *)(server->buf + offset);
                    addr->sin6_family = AF_INET6;
                    info.ai_family = AF_INET6;
                    info.ai_addrlen = sizeof(struct sockaddr_in6);
                    info.ai_addr = (struct sockaddr *)addr;
                }
            } else {
                need_query = 1;
            }
        } else if ((atyp & ADDRTYPE_MASK) == 4) {
            // IP V6
            struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&storage;
            size_t in6_addr_len = sizeof(struct in6_addr);
            addr->sin6_family = AF_INET6;
            if (r > in6_addr_len) {
                addr->sin6_addr = *(struct in6_addr *)(server->buf + offset);
                dns_ntop(AF_INET6, (const void *)(server->buf + offset),
                         host, INET6_ADDRSTRLEN);
                offset += in6_addr_len;
            } else {
                LOGE("invalid header with addr type %d", atyp);
                report_addr(server->fd);
                close_and_free_server(EV_A_ server);
                return;
            }
            addr->sin6_port = *(uint16_t *)(server->buf + offset);
            info.ai_family = AF_INET6;
            info.ai_socktype = SOCK_STREAM;
            info.ai_protocol = IPPROTO_TCP;
            info.ai_addrlen = sizeof(struct sockaddr_in6);
            info.ai_addr = (struct sockaddr *)addr;
        }

        if (offset == 1) {
            LOGE("invalid header with addr type %d", atyp);
            report_addr(server->fd);
            close_and_free_server(EV_A_ server);
            return;
        }

        if (acl && !need_query && 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;

        if (auth || (atyp & ONETIMEAUTH_FLAG)) {
            if (ss_onetimeauth_verify(server->buf + offset, server->buf, offset, server->d_ctx->evp.iv)) {
                LOGE("authentication error %d", atyp);
                report_addr(server->fd);
                close_and_free_server(EV_A_ server);
                return;
            };
            offset += ONETIMEAUTH_BYTES;
            server->auth = 1;
        }

        if (verbose) {
            LOGI("connect to: %s:%d", host, ntohs(port));
        }

        // XXX: should handle buffer carefully
        if (r > offset) {
            server->buf_len = r - offset;
            memmove(server->buf, server->buf + offset, server->buf_len);
        }

        if (server->auth && !ss_check_hash(&server->buf, &server->buf_len, server->chunk, server->d_ctx, BUF_SIZE)) {
            LOGE("hash error");
            report_addr(server->fd);
            close_and_free_server(EV_A_ server);
            return;
        }

        if (!need_query) {
            struct remote *remote = connect_to_remote(&info, server);

            if (remote == NULL) {
                LOGE("connect error");
                close_and_free_server(EV_A_ server);
                return;
            } else {
                server->remote = remote;
                remote->server = server;

                // XXX: should handle buffer carefully
                if (server->buf_len > 0) {
                    memcpy(remote->buf, server->buf + server->buf_idx, server->buf_len);
                    remote->buf_len = server->buf_len;
                    remote->buf_idx = 0;
                    server->buf_len = 0;
                    server->buf_idx = 0;
                }

                server->stage = 4;

                // listen to remote connected event
                ev_io_stop(EV_A_ & server_recv_ctx->io);
                ev_io_start(EV_A_ & remote->send_ctx->io);
            }
        } else {
            server->stage = 4;
            server->query = resolv_query(host, server_resolve_cb, NULL, server,
                                         port);

            ev_io_stop(EV_A_ & server_recv_ctx->io);
        }

        return;
    }
    // should not reach here
    FATAL("server context error");
}
Example #22
0
static void server_recv_cb(EV_P_ ev_io *w, int revents)
{
    struct server_ctx *server_ctx = (struct server_ctx *)w;
    struct sockaddr_storage src_addr;
    memset(&src_addr, 0, sizeof(struct sockaddr_storage));
    char *buf = malloc(BUF_SIZE);

    socklen_t src_addr_len = sizeof(struct sockaddr_storage);
    unsigned int offset = 0;

#ifdef UDPRELAY_REDIR
    char control_buffer[64] = { 0 };
    struct msghdr msg;
    struct iovec iov[1];
    struct sockaddr_storage dst_addr;
    memset(&dst_addr, 0, sizeof(struct sockaddr_storage));

    msg.msg_name = &src_addr;
    msg.msg_namelen = src_addr_len;
    msg.msg_control = control_buffer;
    msg.msg_controllen = sizeof(control_buffer);

    iov[0].iov_base = buf;
    iov[0].iov_len = BUF_SIZE;
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;

    ssize_t buf_len = recvmsg(server_ctx->fd, &msg, 0);
    if (buf_len == -1) {
        ERROR("[udp] server_recvmsg");
        goto CLEAN_UP;
    }

    if (get_dstaddr(&msg, &dst_addr)) {
        LOGE("[udp] unable to get dest addr");
        goto CLEAN_UP;
    }

    src_addr_len = msg.msg_namelen;
#else
    ssize_t buf_len =
        recvfrom(server_ctx->fd, buf, BUF_SIZE, 0, (struct sockaddr *)&src_addr,
                 &src_addr_len);

    if (buf_len == -1) {
        // error on recv
        // simply drop that packet
        ERROR("[udp] server_recvfrom");
        goto CLEAN_UP;
    }
#endif

    if (verbose) {
        LOGI("[udp] server receive a packet");
    }

#ifdef UDPRELAY_REMOTE

    tx += buf_len;

    buf = ss_decrypt_all(BUF_SIZE, buf, &buf_len, server_ctx->method, server_ctx->auth);
    if (buf == NULL) {
        ERROR("[udp] server_ss_decrypt_all");
        goto CLEAN_UP;
    }
#endif

#ifdef UDPRELAY_LOCAL
#if !defined(UDPRELAY_TUNNEL) && !defined(UDPRELAY_REDIR)
    uint8_t frag = *(uint8_t *)(buf + 2);
    offset += 3;
#endif
#endif

    // packet size > default MTU
    if (verbose && buf_len > MTU) {
        LOGE("[udp] possible ip fragment, size: %d", (int)buf_len);
    }

    /*
     *
     * SOCKS5 UDP Request
     * +----+------+------+----------+----------+----------+
     * |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
     * +----+------+------+----------+----------+----------+
     * | 2  |  1   |  1   | Variable |    2     | Variable |
     * +----+------+------+----------+----------+----------+
     *
     * SOCKS5 UDP Response
     * +----+------+------+----------+----------+----------+
     * |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
     * +----+------+------+----------+----------+----------+
     * | 2  |  1   |  1   | Variable |    2     | Variable |
     * +----+------+------+----------+----------+----------+
     *
     * shadowsocks UDP Request (before encrypted)
     * +------+----------+----------+----------+-------------+
     * | ATYP | DST.ADDR | DST.PORT |   DATA   |  HMAC-SHA1  |
     * +------+----------+----------+----------+-------------+
     * |  1   | Variable |    2     | Variable |     10      |
     * +------+----------+----------+----------+-------------+
     *
     * If ATYP & ONETIMEAUTH_FLAG(0x10) == 1, Authentication (HMAC-SHA1) is enabled.
     *
     * The key of HMAC-SHA1 is (IV + KEY) and the input is the whole packet.
     * The output of HMAC-SHA is truncated to 10 bytes (leftmost bits).
     *
     * shadowsocks UDP Response (before encrypted)
     * +------+----------+----------+----------+
     * | ATYP | DST.ADDR | DST.PORT |   DATA   |
     * +------+----------+----------+----------+
     * |  1   | Variable |    2     | Variable |
     * +------+----------+----------+----------+
     *
     * shadowsocks UDP Request and Response (after encrypted)
     * +-------+--------------+
     * |   IV  |    PAYLOAD   |
     * +-------+--------------+
     * | Fixed |   Variable   |
     * +-------+--------------+
     *
     */

#ifdef UDPRELAY_REDIR
    char addr_header[256] = { 0 };
    int addr_header_len = construct_udprealy_header(&dst_addr, addr_header);

    if (addr_header_len == 0) {
        LOGE("[udp] failed to parse tproxy addr");
        goto CLEAN_UP;
    }

    // reconstruct the buffer
    if (BUF_SIZE < buf_len + addr_header_len) {
        buf = realloc(buf, buf_len + addr_header_len);
    }
    memmove(buf + addr_header_len, buf, buf_len);
    memcpy(buf, addr_header, addr_header_len);
    buf_len += addr_header_len;

    char *key = hash_key(dst_addr.ss_family, &src_addr);

#elif UDPRELAY_TUNNEL

    char addr_header[256] = { 0 };
    char *host = server_ctx->tunnel_addr.host;
    char *port = server_ctx->tunnel_addr.port;
    uint16_t port_num = (uint16_t)atoi(port);
    uint16_t port_net_num = htons(port_num);
    int addr_header_len = 0;

    struct cork_ip ip;
    if (cork_ip_init(&ip, host) != -1) {
        if (ip.version == 4) {
            // send as IPv4
            struct in_addr host_addr;
            int host_len = sizeof(struct in_addr);

            if (dns_pton(AF_INET, host, &host_addr) == -1) {
                FATAL("IP parser error");
            }
            addr_header[addr_header_len++] = 1;
            memcpy(addr_header + addr_header_len, &host_addr, host_len);
            addr_header_len += host_len;
        } else if (ip.version == 6) {
            // send as IPv6
            struct in6_addr host_addr;
            int host_len = sizeof(struct in6_addr);

            if (dns_pton(AF_INET6, host, &host_addr) == -1) {
                FATAL("IP parser error");
            }
            addr_header[addr_header_len++] = 4;
            memcpy(addr_header + addr_header_len, &host_addr, host_len);
            addr_header_len += host_len;
        } else {
            FATAL("IP parser error");
        }
    } else {
        // send as domain
        int host_len = strlen(host);

        addr_header[addr_header_len++] = 3;
        addr_header[addr_header_len++] = host_len;
        memcpy(addr_header + addr_header_len, host, host_len);
        addr_header_len += host_len;
    }
    memcpy(addr_header + addr_header_len, &port_net_num, 2);
    addr_header_len += 2;

    // reconstruct the buffer
    if (BUF_SIZE < buf_len + addr_header_len) {
        buf = realloc(buf, buf_len + addr_header_len);
    }
    memmove(buf + addr_header_len, buf, buf_len);
    memcpy(buf, addr_header, addr_header_len);
    buf_len += addr_header_len;

    char *key = hash_key(ip.version == 4 ? AF_INET : AF_INET6, &src_addr);

#else

    char host[256] = { 0 };
    char port[64] = { 0 };
    struct sockaddr_storage dst_addr;
    memset(&dst_addr, 0, sizeof(struct sockaddr_storage));

    int addr_header_len = parse_udprealy_header(buf + offset, buf_len - offset,
                                                &server_ctx->auth, host, port,
                                                &dst_addr);
    if (addr_header_len == 0) {
        // error in parse header
        goto CLEAN_UP;
    }
    char *addr_header = buf + offset;

    char *key = hash_key(dst_addr.ss_family, &src_addr);
#endif

    struct cache *conn_cache = server_ctx->conn_cache;

    struct remote_ctx *remote_ctx = NULL;
    cache_lookup(conn_cache, key, HASH_KEY_LEN, (void *)&remote_ctx);

    if (remote_ctx != NULL) {
        if (memcmp(&src_addr, &remote_ctx->src_addr, sizeof(src_addr))) {
            remote_ctx = NULL;
        }
    }

    // reset the timer
    if (remote_ctx != NULL) {
        ev_timer_again(EV_A_ & remote_ctx->watcher);
    }

    if (remote_ctx == NULL) {
        if (verbose) {
#ifdef UDPRELAY_REDIR
            char src[SS_ADDRSTRLEN];
            char dst[SS_ADDRSTRLEN];
            strcpy(src, get_addr_str((struct sockaddr *)&src_addr));
            strcpy(dst, get_addr_str((struct sockaddr *)&dst_addr));
            LOGI("[udp] cache miss: %s <-> %s", dst, src);
#else
            LOGI("[udp] cache miss: %s:%s <-> %s", host, port,
                 get_addr_str((struct sockaddr *)&src_addr));
#endif
        }
    } else {
        if (verbose) {
#ifdef UDPRELAY_REDIR
            char src[SS_ADDRSTRLEN];
            char dst[SS_ADDRSTRLEN];
            strcpy(src, get_addr_str((struct sockaddr *)&src_addr));
            strcpy(dst, get_addr_str((struct sockaddr *)&dst_addr));
            LOGI("[udp] cache hit: %s <-> %s", dst, src);
#else
            LOGI("[udp] cache hit: %s:%s <-> %s", host, port,
                 get_addr_str((struct sockaddr *)&src_addr));
#endif
        }
    }

#ifdef UDPRELAY_LOCAL

#if !defined(UDPRELAY_TUNNEL) && !defined(UDPRELAY_REDIR)
    if (frag) {
        LOGE("[udp] drop a message since frag is not 0, but %d", frag);
        goto CLEAN_UP;
    }
#endif

    const struct sockaddr *remote_addr = server_ctx->remote_addr;
    const int remote_addr_len = server_ctx->remote_addr_len;

    if (remote_ctx == NULL) {
        // Bind to any port
        int remotefd = create_remote_socket(remote_addr->sa_family == AF_INET6);
        if (remotefd < 0) {
            ERROR("[udp] udprelay bind() error");
            goto CLEAN_UP;
        }
        setnonblocking(remotefd);

#ifdef SO_NOSIGPIPE
        set_nosigpipe(remotefd);
#endif
#ifdef SET_INTERFACE
        if (server_ctx->iface) {
            setinterface(remotefd, server_ctx->iface);
        }
#endif

#ifdef ANDROID
        if (vpn) {
            if (protect_socket(remotefd) == -1) {
                ERROR("protect_socket");
                close(remotefd);
                goto CLEAN_UP;
            }
        }
#endif

        // Init remote_ctx
        remote_ctx = new_remote(remotefd, server_ctx);
        remote_ctx->src_addr = src_addr;
        remote_ctx->af = remote_addr->sa_family;
        remote_ctx->addr_header_len = addr_header_len;
        memcpy(remote_ctx->addr_header, addr_header, addr_header_len);

        // Add to conn cache
        cache_insert(conn_cache, key, HASH_KEY_LEN, (void *)remote_ctx);

        // Start remote io
        ev_io_start(EV_A_ & remote_ctx->io);
        ev_timer_start(EV_A_ & remote_ctx->watcher);

    }

    if (offset > 0) {
        buf_len -= offset;
        memmove(buf, buf + offset, buf_len);
    }

    if (server_ctx->auth) {
        buf[0] |= ONETIMEAUTH_FLAG;
    }

    buf = ss_encrypt_all(BUF_SIZE, buf, &buf_len, server_ctx->method, server_ctx->auth);

    int s = sendto(remote_ctx->fd, buf, buf_len, 0, remote_addr, remote_addr_len);

    if (s == -1) {
        ERROR("[udp] sendto_remote");
    }

#else

    int cache_hit = 0;
    int need_query = 0;

    if (remote_ctx != NULL) {
        cache_hit = 1;
        // detect destination mismatch
        if (remote_ctx->addr_header_len != addr_header_len
                || memcmp(addr_header, remote_ctx->addr_header, addr_header_len) != 0) {
            if (dst_addr.ss_family != AF_INET && dst_addr.ss_family != AF_INET6) {
                need_query = 1;
            }
        }
    } else {
        if (dst_addr.ss_family == AF_INET || dst_addr.ss_family == AF_INET6) {
            int remotefd = create_remote_socket(dst_addr.ss_family == AF_INET6);
            if (remotefd != -1) {
                setnonblocking(remotefd);
#ifdef SO_BROADCAST
                set_broadcast(remotefd);
#endif
#ifdef SO_NOSIGPIPE
                set_nosigpipe(remotefd);
#endif
#ifdef SET_INTERFACE
                if (server_ctx->iface) {
                    setinterface(remotefd, server_ctx->iface);
                }
#endif
                remote_ctx = new_remote(remotefd, server_ctx);
                remote_ctx->src_addr = src_addr;
                remote_ctx->server_ctx = server_ctx;
                remote_ctx->addr_header_len = addr_header_len;
                memcpy(remote_ctx->addr_header, addr_header, addr_header_len);
            } else {
                ERROR("[udp] bind() error");
                goto CLEAN_UP;
            }
        }
    }

    if (remote_ctx != NULL && !need_query) {
        size_t addr_len = get_sockaddr_len((struct sockaddr *)&dst_addr);
        int s = sendto(remote_ctx->fd, buf + addr_header_len,
                buf_len - addr_header_len, 0,
                (struct sockaddr *)&dst_addr, addr_len);

        if (s == -1) {
            ERROR("[udp] sendto_remote");
            if (!cache_hit) {
                close_and_free_remote(EV_A_ remote_ctx);
            }
        } else {
            if (!cache_hit) {
                // Add to conn cache
                remote_ctx->af = dst_addr.ss_family;
                char *key = hash_key(remote_ctx->af, &remote_ctx->src_addr);
                cache_insert(server_ctx->conn_cache, key, HASH_KEY_LEN, (void *)remote_ctx);

                ev_io_start(EV_A_ & remote_ctx->io);
                ev_timer_start(EV_A_ & remote_ctx->watcher);
            }
        }
    } else {
        struct addrinfo hints;
        memset(&hints, 0, sizeof(hints));
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_DGRAM;
        hints.ai_protocol = IPPROTO_UDP;

        struct query_ctx *query_ctx = new_query_ctx(buf + addr_header_len,
                buf_len -
                addr_header_len);
        query_ctx->server_ctx = server_ctx;
        query_ctx->addr_header_len = addr_header_len;
        query_ctx->src_addr = src_addr;
        memcpy(query_ctx->addr_header, addr_header, addr_header_len);

        if (need_query) {
            query_ctx->remote_ctx = remote_ctx;
        }

        struct ResolvQuery *query = resolv_query(host, query_resolve_cb,
                NULL, query_ctx, htons(atoi(port)));
        if (query == NULL) {
            ERROR("[udp] unable to create DNS query");
            close_and_free_query(EV_A_ query_ctx);
            goto CLEAN_UP;
        }
        query_ctx->query = query;
    }
#endif

 CLEAN_UP:
    free(buf);
}
Example #23
0
int
init_acl(const char *path)
{
    // initialize ipset
    ipset_init_library();

    ipset_init(&white_list_ipv4);
    ipset_init(&white_list_ipv6);
    ipset_init(&black_list_ipv4);
    ipset_init(&black_list_ipv6);
    ipset_init(&outbound_block_list_ipv4);
    ipset_init(&outbound_block_list_ipv6);

    cork_dllist_init(&black_list_rules);
    cork_dllist_init(&white_list_rules);
    cork_dllist_init(&outbound_block_list_rules);

    struct ip_set *list_ipv4  = &black_list_ipv4;
    struct ip_set *list_ipv6  = &black_list_ipv6;
    struct cork_dllist *rules = &black_list_rules;

    FILE *f = fopen(path, "r");
    if (f == NULL) {
        LOGE("Invalid acl path.");
        return -1;
    }

    char buf[257];
    while (!feof(f))
        if (fgets(buf, 256, f)) {
            // Trim the newline
            int len = strlen(buf);
            if (len > 0 && buf[len - 1] == '\n') {
                buf[len - 1] = '\0';
            }

            char *comment = strchr(buf, '#');
            if (comment) {
                *comment = '\0';
            }

            char *line = trimwhitespace(buf);
            if (strlen(line) == 0) {
                continue;
            }

            if (strcmp(line, "[outbound_block_list]") == 0) {
                list_ipv4 = &outbound_block_list_ipv4;
                list_ipv6 = &outbound_block_list_ipv6;
                rules     = &outbound_block_list_rules;
                continue;
            } else if (strcmp(line, "[black_list]") == 0
                       || strcmp(line, "[bypass_list]") == 0) {
                list_ipv4 = &black_list_ipv4;
                list_ipv6 = &black_list_ipv6;
                rules     = &black_list_rules;
                continue;
            } else if (strcmp(line, "[white_list]") == 0
                       || strcmp(line, "[proxy_list]") == 0) {
                list_ipv4 = &white_list_ipv4;
                list_ipv6 = &white_list_ipv6;
                rules     = &white_list_rules;
                continue;
            } else if (strcmp(line, "[reject_all]") == 0
                       || strcmp(line, "[bypass_all]") == 0) {
                acl_mode = WHITE_LIST;
                continue;
            } else if (strcmp(line, "[accept_all]") == 0
                       || strcmp(line, "[proxy_all]") == 0) {
                acl_mode = BLACK_LIST;
                continue;
            } else if (strcmp(line, "[remote_dns]") == 0) {
                continue;
            }

            char host[257];
            int cidr;
            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(list_ipv4, &(addr.ip.v4), cidr);
                    } else {
                        ipset_ipv4_add(list_ipv4, &(addr.ip.v4));
                    }
                } else if (addr.version == 6) {
                    if (cidr >= 0) {
                        ipset_ipv6_add_network(list_ipv6, &(addr.ip.v6), cidr);
                    } else {
                        ipset_ipv6_add(list_ipv6, &(addr.ip.v6));
                    }
                }
            } else {
                rule_t *rule = new_rule();
                accept_rule_arg(rule, line);
                init_rule(rule);
                add_rule(rules, rule);
            }
        }

    fclose(f);

    return 0;
}
Example #24
0
static void
remote_send_cb(EV_P_ ev_io *w, int revents)
{
    remote_ctx_t *remote_send_ctx = (remote_ctx_t *)w;
    remote_t *remote              = remote_send_ctx->remote;
    server_t *server              = remote->server;

    if (!remote_send_ctx->connected) {
        struct sockaddr_storage addr;
        socklen_t len = sizeof addr;

        int r = getpeername(remote->fd, (struct sockaddr *)&addr, &len);
        if (r == 0) {
            remote_send_ctx->connected = 1;
            ev_io_stop(EV_A_ & remote_send_ctx->io);
            ev_timer_stop(EV_A_ & remote_send_ctx->watcher);

            buffer_t ss_addr_to_send;
            buffer_t *abuf = &ss_addr_to_send;
            balloc(abuf, BUF_SIZE);

            ss_addr_t *sa = &server->destaddr;
            struct cork_ip ip;
            if (cork_ip_init(&ip, sa->host) != -1) {
                if (ip.version == 4) {
                    // send as IPv4
                    struct in_addr host;
                    int host_len = sizeof(struct in_addr);

                    if (dns_pton(AF_INET, sa->host, &host) == -1) {
                        FATAL("IP parser error");
                    }
                    abuf->array[abuf->len++] = 1;
                    memcpy(abuf->array + abuf->len, &host, host_len);
                    abuf->len += host_len;
                } else if (ip.version == 6) {
                    // send as IPv6
                    struct in6_addr host;
                    int host_len = sizeof(struct in6_addr);

                    if (dns_pton(AF_INET6, sa->host, &host) == -1) {
                        FATAL("IP parser error");
                    }
                    abuf->array[abuf->len++] = 4;
                    memcpy(abuf->array + abuf->len, &host, host_len);
                    abuf->len += host_len;
                } else {
                    FATAL("IP parser error");
                }
            } else {
                // send as domain
                int host_len = strlen(sa->host);

                abuf->array[abuf->len++] = 3;
                abuf->array[abuf->len++] = host_len;
                memcpy(abuf->array + abuf->len, sa->host, host_len);
                abuf->len += host_len;
            }

            uint16_t port = htons(atoi(sa->port));
            memcpy(abuf->array + abuf->len, &port, 2);
            abuf->len += 2;

            if (auth) {
                abuf->array[0] |= ONETIMEAUTH_FLAG;
                ss_onetimeauth(abuf, server->e_ctx->evp.iv, BUF_SIZE);
            }

            int err = ss_encrypt(abuf, server->e_ctx, BUF_SIZE);
            if (err) {
                bfree(abuf);
                LOGE("invalid password or cipher");
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
                return;
            }

            int s = send(remote->fd, abuf->array, abuf->len, 0);

            bfree(abuf);

            if (s < abuf->len) {
                LOGE("failed to send addr");
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
                return;
            }

            ev_io_start(EV_A_ & remote->recv_ctx->io);
            ev_io_start(EV_A_ & server->recv_ctx->io);

            return;
        } else {
            ERROR("getpeername");
            // not connected
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        }
    } else {
        if (remote->buf->len == 0) {
            // close and free
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        } else {
            // has data to send
            ssize_t s = send(remote->fd, remote->buf->array + remote->buf->idx,
                             remote->buf->len, 0);
            if (s == -1) {
                if (errno != EAGAIN && errno != EWOULDBLOCK) {
                    ERROR("send");
                    // close and free
                    close_and_free_remote(EV_A_ remote);
                    close_and_free_server(EV_A_ server);
                }
                return;
            } else if (s < remote->buf->len) {
                // partly sent, move memory, wait for the next time to send
                remote->buf->len -= s;
                remote->buf->idx += s;
                return;
            } else {
                // all sent out, wait for reading
                remote->buf->len = 0;
                remote->buf->idx = 0;
                ev_io_stop(EV_A_ & remote_send_ctx->io);
                ev_io_start(EV_A_ & server->recv_ctx->io);
            }
        }
    }
}
Example #25
0
ssize_t
get_sockaddr(char *host, char *port,
             struct sockaddr_storage *storage, int block,
             int ipv6first)
{
    struct cork_ip ip;
    if (cork_ip_init(&ip, host) != -1) {
        if (ip.version == 4) {
            struct sockaddr_in *addr = (struct sockaddr_in *)storage;
            addr->sin_family = AF_INET;
            dns_pton(AF_INET, host, &(addr->sin_addr));
            if (port != NULL) {
                addr->sin_port = htons(atoi(port));
            }
        } else if (ip.version == 6) {
            struct sockaddr_in6 *addr = (struct sockaddr_in6 *)storage;
            addr->sin6_family = AF_INET6;
            dns_pton(AF_INET6, host, &(addr->sin6_addr));
            if (port != NULL) {
                addr->sin6_port = htons(atoi(port));
            }
        }
        return 0;
    } else {
        struct addrinfo hints;
        struct addrinfo *result, *rp;

        memset(&hints, 0, sizeof(struct addrinfo));
        hints.ai_family   = AF_UNSPEC;   /* Return IPv4 and IPv6 choices */
        hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */

        int err, i;

        for (i = 1; i < 8; i++) {
            err = getaddrinfo(host, port, &hints, &result);
#if defined(MODULE_LOCAL)
            if (!keep_resolving)
                break;
#endif
            if ((!block || !err)) {
                break;
            } else {
                sleep(pow(2, i));
                LOGE("failed to resolve server name, wait %.0f seconds", pow(2, i));
            }
        }

        if (err != 0) {
            LOGE("getaddrinfo: %s", gai_strerror(err));
            return -1;
        }

        int prefer_af = ipv6first ? AF_INET6 : AF_INET;
        for (rp = result; rp != NULL; rp = rp->ai_next)
            if (rp->ai_family == prefer_af) {
                if (rp->ai_family == AF_INET)
                    memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in));
                else if (rp->ai_family == AF_INET6)
                    memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in6));
                break;
            }

        if (rp == NULL) {
            for (rp = result; rp != NULL; rp = rp->ai_next) {
                if (rp->ai_family == AF_INET)
                    memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in));
                else if (rp->ai_family == AF_INET6)
                    memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in6));
                break;
            }
        }

        if (rp == NULL) {
            LOGE("failed to resolve remote addr");
            return -1;
        }

        freeaddrinfo(result);
        return 0;
    }

    return -1;
}
Example #26
0
static void remote_send_cb(EV_P_ ev_io *w, int revents)
{
    struct remote_ctx *remote_send_ctx = (struct remote_ctx *)w;
    struct remote *remote = remote_send_ctx->remote;
    struct server *server = remote->server;

    if (!remote_send_ctx->connected) {
        struct sockaddr_storage addr;
        socklen_t len = sizeof addr;

        int r = getpeername(remote->fd, (struct sockaddr *)&addr, &len);
        if (r == 0) {
            remote_send_ctx->connected = 1;
            ev_io_stop(EV_A_ & remote_send_ctx->io);
            ev_timer_stop(EV_A_ & remote_send_ctx->watcher);
            char *ss_addr_to_send = malloc(BUF_SIZE);
            ssize_t addr_len = 0;

            ss_addr_t *sa = &server->destaddr;
            struct cork_ip ip;
            if (cork_ip_init(&ip, sa->host) != -1) {
                if (ip.version == 4) {
                    // send as IPv4
                    struct in_addr host;
                    int host_len = sizeof(struct in_addr);

                    if (dns_pton(AF_INET, sa->host, &host) == -1) {
                        FATAL("IP parser error");
                    }
                    ss_addr_to_send[addr_len++] = 1;
                    memcpy(ss_addr_to_send + addr_len, &host, host_len);
                    addr_len += host_len;
                } else if (ip.version == 6) {
                    // send as IPv6
                    struct in6_addr host;
                    int host_len = sizeof(struct in6_addr);

                    if (dns_pton(AF_INET6, sa->host, &host) == -1) {
                        FATAL("IP parser error");
                    }
                    ss_addr_to_send[addr_len++] = 4;
                    memcpy(ss_addr_to_send + addr_len, &host, host_len);
                    addr_len += host_len;
                } else {
                    FATAL("IP parser error");
                }
            } else {
                // send as domain
                int host_len = strlen(sa->host);

                ss_addr_to_send[addr_len++] = 3;
                ss_addr_to_send[addr_len++] = host_len;
                memcpy(ss_addr_to_send + addr_len, sa->host, host_len);
                addr_len += host_len;
            }

            uint16_t port = htons(atoi(sa->port));
            memcpy(ss_addr_to_send + addr_len, &port, 2);
            addr_len += 2;

            ss_addr_to_send = ss_encrypt(BUF_SIZE, ss_addr_to_send, &addr_len,
                                         server->e_ctx);
            if (ss_addr_to_send == NULL) {
                LOGE("invalid password or cipher");
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
                return;
            }

            int s = send(remote->fd, ss_addr_to_send, addr_len, 0);
            free(ss_addr_to_send);

            if (s < addr_len) {
                LOGE("failed to send addr");
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
                return;
            }

            ev_io_start(EV_A_ & remote->recv_ctx->io);
            ev_io_start(EV_A_ & server->recv_ctx->io);

            return;
        } else {
            ERROR("getpeername");
            // not connected
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        }
    } else {
        if (remote->buf_len == 0) {
            // close and free
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        } else {
            // has data to send
            ssize_t s = send(remote->fd, remote->buf + remote->buf_idx,
                             remote->buf_len, 0);
            if (s < 0) {
                if (errno != EAGAIN && errno != EWOULDBLOCK) {
                    ERROR("send");
                    // close and free
                    close_and_free_remote(EV_A_ remote);
                    close_and_free_server(EV_A_ server);
                }
                return;
            } else if (s < remote->buf_len) {
                // partly sent, move memory, wait for the next time to send
                remote->buf_len -= s;
                remote->buf_idx += s;
                return;
            } else {
                // all sent out, wait for reading
                remote->buf_len = 0;
                remote->buf_idx = 0;
                ev_io_stop(EV_A_ & remote_send_ctx->io);
                ev_io_start(EV_A_ & server->recv_ctx->io);
            }
        }

    }
}
Example #27
0
ssize_t
get_sockaddr(char *host, char *port,
             struct sockaddr_storage *storage, int block,
             int ipv6first)
{
    struct cork_ip ip;
    if (cork_ip_init(&ip, host) != -1) {
        if (ip.version == 4) {
            struct sockaddr_in *addr = (struct sockaddr_in *)storage;
            addr->sin_family = AF_INET;
            inet_pton(AF_INET, host, &(addr->sin_addr));
            if (port != NULL) {
                addr->sin_port = htons(atoi(port));
            }
        } else if (ip.version == 6) {
            struct sockaddr_in6 *addr = (struct sockaddr_in6 *)storage;
            addr->sin6_family = AF_INET6;
            inet_pton(AF_INET6, host, &(addr->sin6_addr));
            if (port != NULL) {
                addr->sin6_port = htons(atoi(port));
            }
        }
        return 0;
    } else {
#ifdef __ANDROID__
        extern int vpn;
        assert(!vpn);   // protecting DNS packets isn't supported yet
#endif
        struct addrinfo hints;
        struct addrinfo *result, *rp;

        memset(&hints, 0, sizeof(struct addrinfo));
        hints.ai_family   = AF_UNSPEC;   /* Return IPv4 and IPv6 choices */
        hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */

        int err = getaddrinfo(host, port, &hints, &result);

        if (err != 0) {
            LOGE("getaddrinfo: %s", gai_strerror(err));
            return -1;
        }

        int prefer_af = ipv6first ? AF_INET6 : AF_INET;
        for (rp = result; rp != NULL; rp = rp->ai_next)
            if (rp->ai_family == prefer_af) {
                if (rp->ai_family == AF_INET)
                    memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in));
                else if (rp->ai_family == AF_INET6)
                    memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in6));
                break;
            }

        if (rp == NULL) {
            for (rp = result; rp != NULL; rp = rp->ai_next) {
                if (rp->ai_family == AF_INET)
                    memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in));
                else if (rp->ai_family == AF_INET6)
                    memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in6));
                break;
            }
        }

        if (rp == NULL) {
            LOGE("failed to resolve remote addr");
            return -1;
        }

        freeaddrinfo(result);
        return 0;
    }

    return -1;
}