static int dns_interpolate_inaddr_arpa(char *buff, int len, const char *key, const char *ip) { const char *b, *e; char *o; unsigned char dn[DNS_MAXDN]; int il; struct { struct in_addr addr; struct in6_addr addr6; } a; /* This function takes a dot delimited string as input and * reverses the parts split on dot. */ (void)key; if (dns_pton(AF_INET, ip, &a.addr) > 0) { dns_a4todn(&a.addr, 0, dn, sizeof(dn)); dns_dntop(dn,buff,len); return strlen(buff); } else if (dns_pton(AF_INET6, ip, &a.addr6) > 0) { dns_a6todn(&a.addr6, 0, dn, sizeof(dn)); dns_dntop(dn,buff,len); return strlen(buff); } o = buff; il = strlen(ip); if(len <= il) { /* not enough room for ip and '\0' */ if(len > 0) buff[0] = '\0'; return 0; } e = ip + il; b = e - 1; while(b >= ip) { const char *term; while(b >= ip && *b != '.') b--; /* Rewind to previous part */ term = b + 1; /* term is one ahead, we went past it */ if(term != e) memcpy(o, term, e - term); /* no sense in copying nothing */ o += e - term; /* advance the term length */ e = b; b = e - 1; if(e >= ip) *o++ = '.'; /* we must be at . */ } *o = '\0'; assert((o - buff) == il); return o - buff; }
static int submit(struct ipcheck *ipc) { struct in_addr addr; if (dns_pton(AF_INET, ipc->name, &addr) > 0) { submit_a_queries(ipc, 1, &addr); ipc->name = NULL; } else if (!dns_submit_a4(0, ipc->name, 0, namecb, ipc)) { error(0, "unable to submit name query for %s: %s\n", ipc->name, dns_strerror(dns_status(0))); ++failures; } return 0; }
int bind_to_address(int socket_fd, const char *host) { if (host != NULL) { struct cork_ip ip; struct sockaddr_storage storage; memset(&storage, 0, sizeof(storage)); if (cork_ip_init(&ip, host) != -1) { if (ip.version == 4) { struct sockaddr_in *addr = (struct sockaddr_in *)&storage; dns_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; dns_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; }
void ape_gethostbyname(char *name, void (*callback)(char *, void *, acetables *), void *data, acetables *g_ape) { struct in_addr addr; struct query *q; unsigned char dn[DNS_MAXDN]; int abs = 0; enum dns_type l_qtyp = 0; if (dns_pton(AF_INET, name, &addr) > 0) { /* We have an IP */ callback(xstrdup(name), data, g_ape); return; } else if (!dns_ptodn(name, strlen(name), dn, sizeof(dn), &abs)) { /* We have an invalid domain name */ return; } else { l_qtyp = DNS_T_A; } q = query_new(name, dn, l_qtyp); q->data = data; q->callback = callback; q->g_ape = g_ape; if (abs) { abs = DNS_NOSRCH; } if (!dns_submit_dn(NULL, dn, qcls, l_qtyp, abs, 0, dnscb, q)) { query_free(q); return; } dns_timeouts(NULL, -1, 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); }
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; }
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"); }
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; }
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); } } } }
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"); }
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); } } } }
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"); }
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); }