mirror of
https://github.com/neovim/neovim.git
synced 2025-09-27 21:48:35 +00:00
Merge commit 'a302c65dc65896776d6cb9e2c89a6ccc77ada530' as 'third-party/libuv'
This commit is contained in:
21
third-party/libuv/samples/socks5-proxy/.gitignore
vendored
Normal file
21
third-party/libuv/samples/socks5-proxy/.gitignore
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Copyright StrongLoop, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
/build/
|
53
third-party/libuv/samples/socks5-proxy/LICENSE
vendored
Normal file
53
third-party/libuv/samples/socks5-proxy/LICENSE
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
Files: *
|
||||
========
|
||||
|
||||
Copyright StrongLoop, Inc. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
|
||||
|
||||
Files: getopt.c
|
||||
===============
|
||||
|
||||
Copyright (c) 1987, 1993, 1994
|
||||
The Regents of the University of California. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the University nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
46
third-party/libuv/samples/socks5-proxy/Makefile
vendored
Normal file
46
third-party/libuv/samples/socks5-proxy/Makefile
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
# Copyright StrongLoop, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
BUILDTYPE ?= Debug
|
||||
BUILDDIR ?= build
|
||||
GYP ?= gyp
|
||||
V ?=
|
||||
|
||||
SOURCES := client.c defs.h getopt.c main.c s5.c s5.h server.c util.c
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(BUILDDIR)/$(BUILDTYPE)/s5-proxy
|
||||
|
||||
clean:
|
||||
$(RM) $(BUILDDIR)
|
||||
|
||||
$(BUILDDIR)/$(BUILDTYPE)/s5-proxy: $(BUILDDIR)/Makefile $(SOURCES)
|
||||
$(MAKE) -C $(BUILDDIR) V=$(V)
|
||||
|
||||
$(BUILDDIR)/Makefile: ../../common.gypi build.gyp
|
||||
$(GYP) \
|
||||
-Dlibrary=static_library \
|
||||
-Goutput_dir=. \
|
||||
-I../../common.gypi \
|
||||
-f make \
|
||||
--depth=. \
|
||||
--generator-output=$(BUILDDIR) \
|
||||
build.gyp
|
46
third-party/libuv/samples/socks5-proxy/build.gyp
vendored
Normal file
46
third-party/libuv/samples/socks5-proxy/build.gyp
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
# Copyright StrongLoop, Inc. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
{
|
||||
'targets': [
|
||||
{
|
||||
'dependencies': ['../../uv.gyp:libuv'],
|
||||
'target_name': 's5-proxy',
|
||||
'type': 'executable',
|
||||
'sources': [
|
||||
'client.c',
|
||||
'defs.h',
|
||||
'main.c',
|
||||
's5.c',
|
||||
's5.h',
|
||||
'server.c',
|
||||
'util.c',
|
||||
],
|
||||
'conditions': [
|
||||
['OS=="win"', {
|
||||
'defines': ['HAVE_UNISTD_H=0'],
|
||||
'sources': ['getopt.c']
|
||||
}, {
|
||||
'defines': ['HAVE_UNISTD_H=1']
|
||||
}]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
737
third-party/libuv/samples/socks5-proxy/client.c
vendored
Normal file
737
third-party/libuv/samples/socks5-proxy/client.c
vendored
Normal file
@@ -0,0 +1,737 @@
|
||||
/* Copyright StrongLoop, Inc. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* A connection is modeled as an abstraction on top of two simple state
|
||||
* machines, one for reading and one for writing. Either state machine
|
||||
* is, when active, in one of three states: busy, done or stop; the fourth
|
||||
* and final state, dead, is an end state and only relevant when shutting
|
||||
* down the connection. A short overview:
|
||||
*
|
||||
* busy done stop
|
||||
* ----------|---------------------------|--------------------|------|
|
||||
* readable | waiting for incoming data | have incoming data | idle |
|
||||
* writable | busy writing out data | completed write | idle |
|
||||
*
|
||||
* We could remove the done state from the writable state machine. For our
|
||||
* purposes, it's functionally equivalent to the stop state.
|
||||
*
|
||||
* When the connection with upstream has been established, the client_ctx
|
||||
* moves into a state where incoming data from the client is sent upstream
|
||||
* and vice versa, incoming data from upstream is sent to the client. In
|
||||
* other words, we're just piping data back and forth. See conn_cycle()
|
||||
* for details.
|
||||
*
|
||||
* An interesting deviation from libuv's I/O model is that reads are discrete
|
||||
* rather than continuous events. In layman's terms, when a read operation
|
||||
* completes, the connection stops reading until further notice.
|
||||
*
|
||||
* The rationale for this approach is that we have to wait until the data
|
||||
* has been sent out again before we can reuse the read buffer.
|
||||
*
|
||||
* It also pleasingly unifies with the request model that libuv uses for
|
||||
* writes and everything else; libuv may switch to a request model for
|
||||
* reads in the future.
|
||||
*/
|
||||
enum conn_state {
|
||||
c_busy, /* Busy; waiting for incoming data or for a write to complete. */
|
||||
c_done, /* Done; read incoming data or write finished. */
|
||||
c_stop, /* Stopped. */
|
||||
c_dead
|
||||
};
|
||||
|
||||
/* Session states. */
|
||||
enum sess_state {
|
||||
s_handshake, /* Wait for client handshake. */
|
||||
s_handshake_auth, /* Wait for client authentication data. */
|
||||
s_req_start, /* Start waiting for request data. */
|
||||
s_req_parse, /* Wait for request data. */
|
||||
s_req_lookup, /* Wait for upstream hostname DNS lookup to complete. */
|
||||
s_req_connect, /* Wait for uv_tcp_connect() to complete. */
|
||||
s_proxy_start, /* Connected. Start piping data. */
|
||||
s_proxy, /* Connected. Pipe data back and forth. */
|
||||
s_kill, /* Tear down session. */
|
||||
s_almost_dead_0, /* Waiting for finalizers to complete. */
|
||||
s_almost_dead_1, /* Waiting for finalizers to complete. */
|
||||
s_almost_dead_2, /* Waiting for finalizers to complete. */
|
||||
s_almost_dead_3, /* Waiting for finalizers to complete. */
|
||||
s_almost_dead_4, /* Waiting for finalizers to complete. */
|
||||
s_dead /* Dead. Safe to free now. */
|
||||
};
|
||||
|
||||
static void do_next(client_ctx *cx);
|
||||
static int do_handshake(client_ctx *cx);
|
||||
static int do_handshake_auth(client_ctx *cx);
|
||||
static int do_req_start(client_ctx *cx);
|
||||
static int do_req_parse(client_ctx *cx);
|
||||
static int do_req_lookup(client_ctx *cx);
|
||||
static int do_req_connect_start(client_ctx *cx);
|
||||
static int do_req_connect(client_ctx *cx);
|
||||
static int do_proxy_start(client_ctx *cx);
|
||||
static int do_proxy(client_ctx *cx);
|
||||
static int do_kill(client_ctx *cx);
|
||||
static int do_almost_dead(client_ctx *cx);
|
||||
static int conn_cycle(const char *who, conn *a, conn *b);
|
||||
static void conn_timer_reset(conn *c);
|
||||
static void conn_timer_expire(uv_timer_t *handle, int status);
|
||||
static void conn_getaddrinfo(conn *c, const char *hostname);
|
||||
static void conn_getaddrinfo_done(uv_getaddrinfo_t *req,
|
||||
int status,
|
||||
struct addrinfo *ai);
|
||||
static int conn_connect(conn *c);
|
||||
static void conn_connect_done(uv_connect_t *req, int status);
|
||||
static void conn_read(conn *c);
|
||||
static void conn_read_done(uv_stream_t *handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t *buf);
|
||||
static void conn_alloc(uv_handle_t *handle, size_t size, uv_buf_t *buf);
|
||||
static void conn_write(conn *c, const void *data, unsigned int len);
|
||||
static void conn_write_done(uv_write_t *req, int status);
|
||||
static void conn_close(conn *c);
|
||||
static void conn_close_done(uv_handle_t *handle);
|
||||
|
||||
/* |incoming| has been initialized by server.c when this is called. */
|
||||
void client_finish_init(server_ctx *sx, client_ctx *cx) {
|
||||
conn *incoming;
|
||||
conn *outgoing;
|
||||
|
||||
cx->sx = sx;
|
||||
cx->state = s_handshake;
|
||||
s5_init(&cx->parser);
|
||||
|
||||
incoming = &cx->incoming;
|
||||
incoming->client = cx;
|
||||
incoming->result = 0;
|
||||
incoming->rdstate = c_stop;
|
||||
incoming->wrstate = c_stop;
|
||||
incoming->idle_timeout = sx->idle_timeout;
|
||||
CHECK(0 == uv_timer_init(sx->loop, &incoming->timer_handle));
|
||||
|
||||
outgoing = &cx->outgoing;
|
||||
outgoing->client = cx;
|
||||
outgoing->result = 0;
|
||||
outgoing->rdstate = c_stop;
|
||||
outgoing->wrstate = c_stop;
|
||||
outgoing->idle_timeout = sx->idle_timeout;
|
||||
CHECK(0 == uv_tcp_init(cx->sx->loop, &outgoing->handle.tcp));
|
||||
CHECK(0 == uv_timer_init(cx->sx->loop, &outgoing->timer_handle));
|
||||
|
||||
/* Wait for the initial packet. */
|
||||
conn_read(incoming);
|
||||
}
|
||||
|
||||
/* This is the core state machine that drives the client <-> upstream proxy.
|
||||
* We move through the initial handshake and authentication steps first and
|
||||
* end up (if all goes well) in the proxy state where we're just proxying
|
||||
* data between the client and upstream.
|
||||
*/
|
||||
static void do_next(client_ctx *cx) {
|
||||
int new_state;
|
||||
|
||||
ASSERT(cx->state != s_dead);
|
||||
switch (cx->state) {
|
||||
case s_handshake:
|
||||
new_state = do_handshake(cx);
|
||||
break;
|
||||
case s_handshake_auth:
|
||||
new_state = do_handshake_auth(cx);
|
||||
break;
|
||||
case s_req_start:
|
||||
new_state = do_req_start(cx);
|
||||
break;
|
||||
case s_req_parse:
|
||||
new_state = do_req_parse(cx);
|
||||
break;
|
||||
case s_req_lookup:
|
||||
new_state = do_req_lookup(cx);
|
||||
break;
|
||||
case s_req_connect:
|
||||
new_state = do_req_connect(cx);
|
||||
break;
|
||||
case s_proxy_start:
|
||||
new_state = do_proxy_start(cx);
|
||||
break;
|
||||
case s_proxy:
|
||||
new_state = do_proxy(cx);
|
||||
break;
|
||||
case s_kill:
|
||||
new_state = do_kill(cx);
|
||||
break;
|
||||
case s_almost_dead_0:
|
||||
case s_almost_dead_1:
|
||||
case s_almost_dead_2:
|
||||
case s_almost_dead_3:
|
||||
case s_almost_dead_4:
|
||||
new_state = do_almost_dead(cx);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
cx->state = new_state;
|
||||
|
||||
if (cx->state == s_dead) {
|
||||
if (DEBUG_CHECKS) {
|
||||
memset(cx, -1, sizeof(*cx));
|
||||
}
|
||||
free(cx);
|
||||
}
|
||||
}
|
||||
|
||||
static int do_handshake(client_ctx *cx) {
|
||||
unsigned int methods;
|
||||
conn *incoming;
|
||||
s5_ctx *parser;
|
||||
uint8_t *data;
|
||||
size_t size;
|
||||
int err;
|
||||
|
||||
parser = &cx->parser;
|
||||
incoming = &cx->incoming;
|
||||
ASSERT(incoming->rdstate == c_done);
|
||||
ASSERT(incoming->wrstate == c_stop);
|
||||
incoming->rdstate = c_stop;
|
||||
|
||||
if (incoming->result < 0) {
|
||||
pr_err("read error: %s", uv_strerror(incoming->result));
|
||||
return do_kill(cx);
|
||||
}
|
||||
|
||||
data = (uint8_t *) incoming->t.buf;
|
||||
size = (size_t) incoming->result;
|
||||
err = s5_parse(parser, &data, &size);
|
||||
if (err == s5_ok) {
|
||||
conn_read(incoming);
|
||||
return s_handshake; /* Need more data. */
|
||||
}
|
||||
|
||||
if (size != 0) {
|
||||
/* Could allow a round-trip saving shortcut here if the requested auth
|
||||
* method is S5_AUTH_NONE (provided unauthenticated traffic is allowed.)
|
||||
* Requires client support however.
|
||||
*/
|
||||
pr_err("junk in handshake");
|
||||
return do_kill(cx);
|
||||
}
|
||||
|
||||
if (err != s5_auth_select) {
|
||||
pr_err("handshake error: %s", s5_strerror(err));
|
||||
return do_kill(cx);
|
||||
}
|
||||
|
||||
methods = s5_auth_methods(parser);
|
||||
if ((methods & S5_AUTH_NONE) && can_auth_none(cx->sx, cx)) {
|
||||
s5_select_auth(parser, S5_AUTH_NONE);
|
||||
conn_write(incoming, "\5\0", 2); /* No auth required. */
|
||||
return s_req_start;
|
||||
}
|
||||
|
||||
if ((methods & S5_AUTH_PASSWD) && can_auth_passwd(cx->sx, cx)) {
|
||||
/* TODO(bnoordhuis) Implement username/password auth. */
|
||||
}
|
||||
|
||||
conn_write(incoming, "\5\377", 2); /* No acceptable auth. */
|
||||
return s_kill;
|
||||
}
|
||||
|
||||
/* TODO(bnoordhuis) Implement username/password auth. */
|
||||
static int do_handshake_auth(client_ctx *cx) {
|
||||
UNREACHABLE();
|
||||
return do_kill(cx);
|
||||
}
|
||||
|
||||
static int do_req_start(client_ctx *cx) {
|
||||
conn *incoming;
|
||||
|
||||
incoming = &cx->incoming;
|
||||
ASSERT(incoming->rdstate == c_stop);
|
||||
ASSERT(incoming->wrstate == c_done);
|
||||
incoming->wrstate = c_stop;
|
||||
|
||||
if (incoming->result < 0) {
|
||||
pr_err("write error: %s", uv_strerror(incoming->result));
|
||||
return do_kill(cx);
|
||||
}
|
||||
|
||||
conn_read(incoming);
|
||||
return s_req_parse;
|
||||
}
|
||||
|
||||
static int do_req_parse(client_ctx *cx) {
|
||||
conn *incoming;
|
||||
conn *outgoing;
|
||||
s5_ctx *parser;
|
||||
uint8_t *data;
|
||||
size_t size;
|
||||
int err;
|
||||
|
||||
parser = &cx->parser;
|
||||
incoming = &cx->incoming;
|
||||
outgoing = &cx->outgoing;
|
||||
ASSERT(incoming->rdstate == c_done);
|
||||
ASSERT(incoming->wrstate == c_stop);
|
||||
ASSERT(outgoing->rdstate == c_stop);
|
||||
ASSERT(outgoing->wrstate == c_stop);
|
||||
incoming->rdstate = c_stop;
|
||||
|
||||
if (incoming->result < 0) {
|
||||
pr_err("read error: %s", uv_strerror(incoming->result));
|
||||
return do_kill(cx);
|
||||
}
|
||||
|
||||
data = (uint8_t *) incoming->t.buf;
|
||||
size = (size_t) incoming->result;
|
||||
err = s5_parse(parser, &data, &size);
|
||||
if (err == s5_ok) {
|
||||
conn_read(incoming);
|
||||
return s_req_parse; /* Need more data. */
|
||||
}
|
||||
|
||||
if (size != 0) {
|
||||
pr_err("junk in request %u", (unsigned) size);
|
||||
return do_kill(cx);
|
||||
}
|
||||
|
||||
if (err != s5_exec_cmd) {
|
||||
pr_err("request error: %s", s5_strerror(err));
|
||||
return do_kill(cx);
|
||||
}
|
||||
|
||||
if (parser->cmd == s5_cmd_tcp_bind) {
|
||||
/* Not supported but relatively straightforward to implement. */
|
||||
pr_warn("BIND requests are not supported.");
|
||||
return do_kill(cx);
|
||||
}
|
||||
|
||||
if (parser->cmd == s5_cmd_udp_assoc) {
|
||||
/* Not supported. Might be hard to implement because libuv has no
|
||||
* functionality for detecting the MTU size which the RFC mandates.
|
||||
*/
|
||||
pr_warn("UDP ASSOC requests are not supported.");
|
||||
return do_kill(cx);
|
||||
}
|
||||
ASSERT(parser->cmd == s5_cmd_tcp_connect);
|
||||
|
||||
if (parser->atyp == s5_atyp_host) {
|
||||
conn_getaddrinfo(outgoing, (const char *) parser->daddr);
|
||||
return s_req_lookup;
|
||||
}
|
||||
|
||||
if (parser->atyp == s5_atyp_ipv4) {
|
||||
memset(&outgoing->t.addr4, 0, sizeof(outgoing->t.addr4));
|
||||
outgoing->t.addr4.sin_family = AF_INET;
|
||||
outgoing->t.addr4.sin_port = htons(parser->dport);
|
||||
memcpy(&outgoing->t.addr4.sin_addr,
|
||||
parser->daddr,
|
||||
sizeof(outgoing->t.addr4.sin_addr));
|
||||
} else if (parser->atyp == s5_atyp_ipv6) {
|
||||
memset(&outgoing->t.addr6, 0, sizeof(outgoing->t.addr6));
|
||||
outgoing->t.addr6.sin6_family = AF_INET6;
|
||||
outgoing->t.addr6.sin6_port = htons(parser->dport);
|
||||
memcpy(&outgoing->t.addr6.sin6_addr,
|
||||
parser->daddr,
|
||||
sizeof(outgoing->t.addr6.sin6_addr));
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
return do_req_connect_start(cx);
|
||||
}
|
||||
|
||||
static int do_req_lookup(client_ctx *cx) {
|
||||
s5_ctx *parser;
|
||||
conn *incoming;
|
||||
conn *outgoing;
|
||||
|
||||
parser = &cx->parser;
|
||||
incoming = &cx->incoming;
|
||||
outgoing = &cx->outgoing;
|
||||
ASSERT(incoming->rdstate == c_stop);
|
||||
ASSERT(incoming->wrstate == c_stop);
|
||||
ASSERT(outgoing->rdstate == c_stop);
|
||||
ASSERT(outgoing->wrstate == c_stop);
|
||||
|
||||
if (outgoing->result < 0) {
|
||||
/* TODO(bnoordhuis) Escape control characters in parser->daddr. */
|
||||
pr_err("lookup error for \"%s\": %s",
|
||||
parser->daddr,
|
||||
uv_strerror(outgoing->result));
|
||||
/* Send back a 'Host unreachable' reply. */
|
||||
conn_write(incoming, "\5\4\0\1\0\0\0\0\0\0", 10);
|
||||
return s_kill;
|
||||
}
|
||||
|
||||
/* Don't make assumptions about the offset of sin_port/sin6_port. */
|
||||
switch (outgoing->t.addr.sa_family) {
|
||||
case AF_INET:
|
||||
outgoing->t.addr4.sin_port = htons(parser->dport);
|
||||
break;
|
||||
case AF_INET6:
|
||||
outgoing->t.addr6.sin6_port = htons(parser->dport);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
return do_req_connect_start(cx);
|
||||
}
|
||||
|
||||
/* Assumes that cx->outgoing.t.sa contains a valid AF_INET/AF_INET6 address. */
|
||||
static int do_req_connect_start(client_ctx *cx) {
|
||||
conn *incoming;
|
||||
conn *outgoing;
|
||||
int err;
|
||||
|
||||
incoming = &cx->incoming;
|
||||
outgoing = &cx->outgoing;
|
||||
ASSERT(incoming->rdstate == c_stop);
|
||||
ASSERT(incoming->wrstate == c_stop);
|
||||
ASSERT(outgoing->rdstate == c_stop);
|
||||
ASSERT(outgoing->wrstate == c_stop);
|
||||
|
||||
if (!can_access(cx->sx, cx, &outgoing->t.addr)) {
|
||||
pr_warn("connection not allowed by ruleset");
|
||||
/* Send a 'Connection not allowed by ruleset' reply. */
|
||||
conn_write(incoming, "\5\2\0\1\0\0\0\0\0\0", 10);
|
||||
return s_kill;
|
||||
}
|
||||
|
||||
err = conn_connect(outgoing);
|
||||
if (err != 0) {
|
||||
pr_err("connect error: %s\n", uv_strerror(err));
|
||||
return do_kill(cx);
|
||||
}
|
||||
|
||||
return s_req_connect;
|
||||
}
|
||||
|
||||
static int do_req_connect(client_ctx *cx) {
|
||||
const struct sockaddr_in6 *in6;
|
||||
const struct sockaddr_in *in;
|
||||
char addr_storage[sizeof(*in6)];
|
||||
conn *incoming;
|
||||
conn *outgoing;
|
||||
uint8_t *buf;
|
||||
int addrlen;
|
||||
|
||||
incoming = &cx->incoming;
|
||||
outgoing = &cx->outgoing;
|
||||
ASSERT(incoming->rdstate == c_stop);
|
||||
ASSERT(incoming->wrstate == c_stop);
|
||||
ASSERT(outgoing->rdstate == c_stop);
|
||||
ASSERT(outgoing->wrstate == c_stop);
|
||||
|
||||
/* Build and send the reply. Not very pretty but gets the job done. */
|
||||
buf = (uint8_t *) incoming->t.buf;
|
||||
if (outgoing->result == 0) {
|
||||
/* The RFC mandates that the SOCKS server must include the local port
|
||||
* and address in the reply. So that's what we do.
|
||||
*/
|
||||
addrlen = sizeof(addr_storage);
|
||||
CHECK(0 == uv_tcp_getsockname(&outgoing->handle.tcp,
|
||||
(struct sockaddr *) addr_storage,
|
||||
&addrlen));
|
||||
buf[0] = 5; /* Version. */
|
||||
buf[1] = 0; /* Success. */
|
||||
buf[2] = 0; /* Reserved. */
|
||||
if (addrlen == sizeof(*in)) {
|
||||
buf[3] = 1; /* IPv4. */
|
||||
in = (const struct sockaddr_in *) &addr_storage;
|
||||
memcpy(buf + 4, &in->sin_addr, 4);
|
||||
memcpy(buf + 8, &in->sin_port, 2);
|
||||
conn_write(incoming, buf, 10);
|
||||
} else if (addrlen == sizeof(*in6)) {
|
||||
buf[3] = 4; /* IPv6. */
|
||||
in6 = (const struct sockaddr_in6 *) &addr_storage;
|
||||
memcpy(buf + 4, &in6->sin6_addr, 16);
|
||||
memcpy(buf + 20, &in6->sin6_port, 2);
|
||||
conn_write(incoming, buf, 22);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
return s_proxy_start;
|
||||
} else {
|
||||
pr_err("upstream connection error: %s\n", uv_strerror(outgoing->result));
|
||||
/* Send a 'Connection refused' reply. */
|
||||
conn_write(incoming, "\5\5\0\1\0\0\0\0\0\0", 10);
|
||||
return s_kill;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return s_kill;
|
||||
}
|
||||
|
||||
static int do_proxy_start(client_ctx *cx) {
|
||||
conn *incoming;
|
||||
conn *outgoing;
|
||||
|
||||
incoming = &cx->incoming;
|
||||
outgoing = &cx->outgoing;
|
||||
ASSERT(incoming->rdstate == c_stop);
|
||||
ASSERT(incoming->wrstate == c_done);
|
||||
ASSERT(outgoing->rdstate == c_stop);
|
||||
ASSERT(outgoing->wrstate == c_stop);
|
||||
incoming->wrstate = c_stop;
|
||||
|
||||
if (incoming->result < 0) {
|
||||
pr_err("write error: %s", uv_strerror(incoming->result));
|
||||
return do_kill(cx);
|
||||
}
|
||||
|
||||
conn_read(incoming);
|
||||
conn_read(outgoing);
|
||||
return s_proxy;
|
||||
}
|
||||
|
||||
/* Proxy incoming data back and forth. */
|
||||
static int do_proxy(client_ctx *cx) {
|
||||
if (conn_cycle("client", &cx->incoming, &cx->outgoing)) {
|
||||
return do_kill(cx);
|
||||
}
|
||||
|
||||
if (conn_cycle("upstream", &cx->outgoing, &cx->incoming)) {
|
||||
return do_kill(cx);
|
||||
}
|
||||
|
||||
return s_proxy;
|
||||
}
|
||||
|
||||
static int do_kill(client_ctx *cx) {
|
||||
int new_state;
|
||||
|
||||
if (cx->state >= s_almost_dead_0) {
|
||||
return cx->state;
|
||||
}
|
||||
|
||||
/* Try to cancel the request. The callback still runs but if the
|
||||
* cancellation succeeded, it gets called with status=UV_ECANCELED.
|
||||
*/
|
||||
new_state = s_almost_dead_1;
|
||||
if (cx->state == s_req_lookup) {
|
||||
new_state = s_almost_dead_0;
|
||||
uv_cancel(&cx->outgoing.t.req);
|
||||
}
|
||||
|
||||
conn_close(&cx->incoming);
|
||||
conn_close(&cx->outgoing);
|
||||
return new_state;
|
||||
}
|
||||
|
||||
static int do_almost_dead(client_ctx *cx) {
|
||||
ASSERT(cx->state >= s_almost_dead_0);
|
||||
return cx->state + 1; /* Another finalizer completed. */
|
||||
}
|
||||
|
||||
static int conn_cycle(const char *who, conn *a, conn *b) {
|
||||
if (a->result < 0) {
|
||||
if (a->result != UV_EOF) {
|
||||
pr_err("%s error: %s", who, uv_strerror(a->result));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (b->result < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (a->wrstate == c_done) {
|
||||
a->wrstate = c_stop;
|
||||
}
|
||||
|
||||
/* The logic is as follows: read when we don't write and write when we don't
|
||||
* read. That gives us back-pressure handling for free because if the peer
|
||||
* sends data faster than we consume it, TCP congestion control kicks in.
|
||||
*/
|
||||
if (a->wrstate == c_stop) {
|
||||
if (b->rdstate == c_stop) {
|
||||
conn_read(b);
|
||||
} else if (b->rdstate == c_done) {
|
||||
conn_write(a, b->t.buf, b->result);
|
||||
b->rdstate = c_stop; /* Triggers the call to conn_read() above. */
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void conn_timer_reset(conn *c) {
|
||||
CHECK(0 == uv_timer_start(&c->timer_handle,
|
||||
conn_timer_expire,
|
||||
c->idle_timeout,
|
||||
0));
|
||||
}
|
||||
|
||||
static void conn_timer_expire(uv_timer_t *handle, int status) {
|
||||
conn *c;
|
||||
|
||||
CHECK(0 == status);
|
||||
c = CONTAINER_OF(handle, conn, timer_handle);
|
||||
c->result = UV_ETIMEDOUT;
|
||||
do_next(c->client);
|
||||
}
|
||||
|
||||
static void conn_getaddrinfo(conn *c, const char *hostname) {
|
||||
struct addrinfo hints;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
CHECK(0 == uv_getaddrinfo(c->client->sx->loop,
|
||||
&c->t.addrinfo_req,
|
||||
conn_getaddrinfo_done,
|
||||
hostname,
|
||||
NULL,
|
||||
&hints));
|
||||
conn_timer_reset(c);
|
||||
}
|
||||
|
||||
static void conn_getaddrinfo_done(uv_getaddrinfo_t *req,
|
||||
int status,
|
||||
struct addrinfo *ai) {
|
||||
conn *c;
|
||||
|
||||
c = CONTAINER_OF(req, conn, t.addrinfo_req);
|
||||
c->result = status;
|
||||
|
||||
if (status == 0) {
|
||||
/* FIXME(bnoordhuis) Should try all addresses. */
|
||||
if (ai->ai_family == AF_INET) {
|
||||
c->t.addr4 = *(const struct sockaddr_in *) ai->ai_addr;
|
||||
} else if (ai->ai_family == AF_INET6) {
|
||||
c->t.addr6 = *(const struct sockaddr_in6 *) ai->ai_addr;
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
uv_freeaddrinfo(ai);
|
||||
do_next(c->client);
|
||||
}
|
||||
|
||||
/* Assumes that c->t.sa contains a valid AF_INET or AF_INET6 address. */
|
||||
static int conn_connect(conn *c) {
|
||||
ASSERT(c->t.addr.sa_family == AF_INET ||
|
||||
c->t.addr.sa_family == AF_INET6);
|
||||
conn_timer_reset(c);
|
||||
return uv_tcp_connect(&c->t.connect_req,
|
||||
&c->handle.tcp,
|
||||
&c->t.addr,
|
||||
conn_connect_done);
|
||||
}
|
||||
|
||||
static void conn_connect_done(uv_connect_t *req, int status) {
|
||||
conn *c;
|
||||
|
||||
if (status == UV_ECANCELED) {
|
||||
return; /* Handle has been closed. */
|
||||
}
|
||||
|
||||
c = CONTAINER_OF(req, conn, t.connect_req);
|
||||
c->result = status;
|
||||
do_next(c->client);
|
||||
}
|
||||
|
||||
static void conn_read(conn *c) {
|
||||
ASSERT(c->rdstate == c_stop);
|
||||
CHECK(0 == uv_read_start(&c->handle.stream, conn_alloc, conn_read_done));
|
||||
c->rdstate = c_busy;
|
||||
conn_timer_reset(c);
|
||||
}
|
||||
|
||||
static void conn_read_done(uv_stream_t *handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t *buf) {
|
||||
conn *c;
|
||||
|
||||
c = CONTAINER_OF(handle, conn, handle);
|
||||
ASSERT(c->t.buf == buf->base);
|
||||
ASSERT(c->rdstate == c_busy);
|
||||
c->rdstate = c_done;
|
||||
c->result = nread;
|
||||
|
||||
uv_read_stop(&c->handle.stream);
|
||||
do_next(c->client);
|
||||
}
|
||||
|
||||
static void conn_alloc(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
|
||||
conn *c;
|
||||
|
||||
c = CONTAINER_OF(handle, conn, handle);
|
||||
ASSERT(c->rdstate == c_busy);
|
||||
buf->base = c->t.buf;
|
||||
buf->len = sizeof(c->t.buf);
|
||||
}
|
||||
|
||||
static void conn_write(conn *c, const void *data, unsigned int len) {
|
||||
uv_buf_t buf;
|
||||
|
||||
ASSERT(c->wrstate == c_stop || c->wrstate == c_done);
|
||||
c->wrstate = c_busy;
|
||||
|
||||
/* It's okay to cast away constness here, uv_write() won't modify the
|
||||
* memory.
|
||||
*/
|
||||
buf.base = (char *) data;
|
||||
buf.len = len;
|
||||
|
||||
CHECK(0 == uv_write(&c->write_req,
|
||||
&c->handle.stream,
|
||||
&buf,
|
||||
1,
|
||||
conn_write_done));
|
||||
conn_timer_reset(c);
|
||||
}
|
||||
|
||||
static void conn_write_done(uv_write_t *req, int status) {
|
||||
conn *c;
|
||||
|
||||
if (status == UV_ECANCELED) {
|
||||
return; /* Handle has been closed. */
|
||||
}
|
||||
|
||||
c = CONTAINER_OF(req, conn, write_req);
|
||||
ASSERT(c->wrstate == c_busy);
|
||||
c->wrstate = c_done;
|
||||
c->result = status;
|
||||
do_next(c->client);
|
||||
}
|
||||
|
||||
static void conn_close(conn *c) {
|
||||
ASSERT(c->rdstate != c_dead);
|
||||
ASSERT(c->wrstate != c_dead);
|
||||
c->rdstate = c_dead;
|
||||
c->wrstate = c_dead;
|
||||
c->timer_handle.data = c;
|
||||
c->handle.handle.data = c;
|
||||
uv_close(&c->handle.handle, conn_close_done);
|
||||
uv_close((uv_handle_t *) &c->timer_handle, conn_close_done);
|
||||
}
|
||||
|
||||
static void conn_close_done(uv_handle_t *handle) {
|
||||
conn *c;
|
||||
|
||||
c = handle->data;
|
||||
do_next(c->client);
|
||||
}
|
139
third-party/libuv/samples/socks5-proxy/defs.h
vendored
Normal file
139
third-party/libuv/samples/socks5-proxy/defs.h
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
/* Copyright StrongLoop, Inc. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DEFS_H_
|
||||
#define DEFS_H_
|
||||
|
||||
#include "s5.h"
|
||||
#include "uv.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <netinet/in.h> /* sockaddr_in, sockaddr_in6 */
|
||||
#include <stddef.h> /* size_t, ssize_t */
|
||||
#include <stdint.h>
|
||||
#include <sys/socket.h> /* sockaddr */
|
||||
|
||||
struct client_ctx;
|
||||
|
||||
typedef struct {
|
||||
const char *bind_host;
|
||||
unsigned short bind_port;
|
||||
unsigned int idle_timeout;
|
||||
} server_config;
|
||||
|
||||
typedef struct {
|
||||
unsigned int idle_timeout; /* Connection idle timeout in ms. */
|
||||
uv_tcp_t tcp_handle;
|
||||
uv_loop_t *loop;
|
||||
} server_ctx;
|
||||
|
||||
typedef struct {
|
||||
unsigned char rdstate;
|
||||
unsigned char wrstate;
|
||||
unsigned int idle_timeout;
|
||||
struct client_ctx *client; /* Backlink to owning client context. */
|
||||
ssize_t result;
|
||||
union {
|
||||
uv_handle_t handle;
|
||||
uv_stream_t stream;
|
||||
uv_tcp_t tcp;
|
||||
uv_udp_t udp;
|
||||
} handle;
|
||||
uv_timer_t timer_handle; /* For detecting timeouts. */
|
||||
uv_write_t write_req;
|
||||
/* We only need one of these at a time so make them share memory. */
|
||||
union {
|
||||
uv_getaddrinfo_t addrinfo_req;
|
||||
uv_connect_t connect_req;
|
||||
uv_req_t req;
|
||||
struct sockaddr_in6 addr6;
|
||||
struct sockaddr_in addr4;
|
||||
struct sockaddr addr;
|
||||
char buf[2048]; /* Scratch space. Used to read data into. */
|
||||
} t;
|
||||
} conn;
|
||||
|
||||
typedef struct client_ctx {
|
||||
unsigned int state;
|
||||
server_ctx *sx; /* Backlink to owning server context. */
|
||||
s5_ctx parser; /* The SOCKS protocol parser. */
|
||||
conn incoming; /* Connection with the SOCKS client. */
|
||||
conn outgoing; /* Connection with upstream. */
|
||||
} client_ctx;
|
||||
|
||||
/* server.c */
|
||||
int server_run(const server_config *cf, uv_loop_t *loop);
|
||||
int can_auth_none(const server_ctx *sx, const client_ctx *cx);
|
||||
int can_auth_passwd(const server_ctx *sx, const client_ctx *cx);
|
||||
int can_access(const server_ctx *sx,
|
||||
const client_ctx *cx,
|
||||
const struct sockaddr *addr);
|
||||
|
||||
/* client.c */
|
||||
void client_finish_init(server_ctx *sx, client_ctx *cx);
|
||||
|
||||
/* util.c */
|
||||
#if defined(__GNUC__)
|
||||
# define ATTRIBUTE_FORMAT_PRINTF(a, b) __attribute__((format(printf, a, b)))
|
||||
#else
|
||||
# define ATTRIBUTE_FORMAT_PRINTF(a, b)
|
||||
#endif
|
||||
void pr_info(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2);
|
||||
void pr_warn(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2);
|
||||
void pr_err(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2);
|
||||
void *xmalloc(size_t size);
|
||||
|
||||
/* main.c */
|
||||
const char *_getprogname(void);
|
||||
|
||||
/* getopt.c */
|
||||
#if !HAVE_UNISTD_H
|
||||
extern char *optarg;
|
||||
int getopt(int argc, char **argv, const char *options);
|
||||
#endif
|
||||
|
||||
/* ASSERT() is for debug checks, CHECK() for run-time sanity checks.
|
||||
* DEBUG_CHECKS is for expensive debug checks that we only want to
|
||||
* enable in debug builds but still want type-checked by the compiler
|
||||
* in release builds.
|
||||
*/
|
||||
#if defined(NDEBUG)
|
||||
# define ASSERT(exp)
|
||||
# define CHECK(exp) do { if (!(exp)) abort(); } while (0)
|
||||
# define DEBUG_CHECKS (0)
|
||||
#else
|
||||
# define ASSERT(exp) assert(exp)
|
||||
# define CHECK(exp) assert(exp)
|
||||
# define DEBUG_CHECKS (1)
|
||||
#endif
|
||||
|
||||
#define UNREACHABLE() CHECK(!"Unreachable code reached.")
|
||||
|
||||
/* This macro looks complicated but it's not: it calculates the address
|
||||
* of the embedding struct through the address of the embedded struct.
|
||||
* In other words, if struct A embeds struct B, then we can obtain
|
||||
* the address of A by taking the address of B and subtracting the
|
||||
* field offset of B in A.
|
||||
*/
|
||||
#define CONTAINER_OF(ptr, type, field) \
|
||||
((type *) ((char *) (ptr) - ((char *) &((type *) 0)->field)))
|
||||
|
||||
#endif /* DEFS_H_ */
|
131
third-party/libuv/samples/socks5-proxy/getopt.c
vendored
Normal file
131
third-party/libuv/samples/socks5-proxy/getopt.c
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
/* $NetBSD: getopt.c,v 1.26 2003/08/07 16:43:40 agc Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1987, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern const char *_getprogname(void);
|
||||
|
||||
int opterr = 1, /* if error message should be printed */
|
||||
optind = 1, /* index into parent argv vector */
|
||||
optopt, /* character checked for validity */
|
||||
optreset; /* reset getopt */
|
||||
char *optarg; /* argument associated with option */
|
||||
|
||||
#define BADCH (int)'?'
|
||||
#define BADARG (int)':'
|
||||
#define EMSG ""
|
||||
|
||||
/*
|
||||
* getopt --
|
||||
* Parse argc/argv argument vector.
|
||||
*/
|
||||
int
|
||||
getopt(nargc, nargv, ostr)
|
||||
int nargc;
|
||||
char * const nargv[];
|
||||
const char *ostr;
|
||||
{
|
||||
static char *place = EMSG; /* option letter processing */
|
||||
char *oli; /* option letter list index */
|
||||
|
||||
if (optreset || *place == 0) { /* update scanning pointer */
|
||||
optreset = 0;
|
||||
place = nargv[optind];
|
||||
if (optind >= nargc || *place++ != '-') {
|
||||
/* Argument is absent or is not an option */
|
||||
place = EMSG;
|
||||
return (-1);
|
||||
}
|
||||
optopt = *place++;
|
||||
if (optopt == '-' && *place == 0) {
|
||||
/* "--" => end of options */
|
||||
++optind;
|
||||
place = EMSG;
|
||||
return (-1);
|
||||
}
|
||||
if (optopt == 0) {
|
||||
/* Solitary '-', treat as a '-' option
|
||||
if the program (eg su) is looking for it. */
|
||||
place = EMSG;
|
||||
if (strchr(ostr, '-') == NULL)
|
||||
return (-1);
|
||||
optopt = '-';
|
||||
}
|
||||
} else
|
||||
optopt = *place++;
|
||||
|
||||
/* See if option letter is one the caller wanted... */
|
||||
if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
|
||||
if (*place == 0)
|
||||
++optind;
|
||||
if (opterr && *ostr != ':')
|
||||
(void)fprintf(stderr,
|
||||
"%s: illegal option -- %c\n", _getprogname(),
|
||||
optopt);
|
||||
return (BADCH);
|
||||
}
|
||||
|
||||
/* Does this option need an argument? */
|
||||
if (oli[1] != ':') {
|
||||
/* don't need argument */
|
||||
optarg = NULL;
|
||||
if (*place == 0)
|
||||
++optind;
|
||||
} else {
|
||||
/* Option-argument is either the rest of this argument or the
|
||||
entire next argument. */
|
||||
if (*place)
|
||||
optarg = place;
|
||||
else if (nargc > ++optind)
|
||||
optarg = nargv[optind];
|
||||
else {
|
||||
/* option-argument absent */
|
||||
place = EMSG;
|
||||
if (*ostr == ':')
|
||||
return (BADARG);
|
||||
if (opterr)
|
||||
(void)fprintf(stderr,
|
||||
"%s: option requires an argument -- %c\n",
|
||||
_getprogname(), optopt);
|
||||
return (BADCH);
|
||||
}
|
||||
place = EMSG;
|
||||
++optind;
|
||||
}
|
||||
return (optopt); /* return option letter */
|
||||
}
|
99
third-party/libuv/samples/socks5-proxy/main.c
vendored
Normal file
99
third-party/libuv/samples/socks5-proxy/main.c
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
/* Copyright StrongLoop, Inc. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h> /* getopt */
|
||||
#endif
|
||||
|
||||
#define DEFAULT_BIND_HOST "127.0.0.1"
|
||||
#define DEFAULT_BIND_PORT 1080
|
||||
#define DEFAULT_IDLE_TIMEOUT (60 * 1000)
|
||||
|
||||
static void parse_opts(server_config *cf, int argc, char **argv);
|
||||
static void usage(void);
|
||||
|
||||
static const char *progname = __FILE__; /* Reset in main(). */
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
server_config config;
|
||||
int err;
|
||||
|
||||
progname = argv[0];
|
||||
memset(&config, 0, sizeof(config));
|
||||
config.bind_host = DEFAULT_BIND_HOST;
|
||||
config.bind_port = DEFAULT_BIND_PORT;
|
||||
config.idle_timeout = DEFAULT_IDLE_TIMEOUT;
|
||||
parse_opts(&config, argc, argv);
|
||||
|
||||
err = server_run(&config, uv_default_loop());
|
||||
if (err) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *_getprogname(void) {
|
||||
return progname;
|
||||
}
|
||||
|
||||
static void parse_opts(server_config *cf, int argc, char **argv) {
|
||||
int opt;
|
||||
|
||||
while (-1 != (opt = getopt(argc, argv, "H:hp:"))) {
|
||||
switch (opt) {
|
||||
case 'H':
|
||||
cf->bind_host = optarg;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
if (1 != sscanf(optarg, "%hu", &cf->bind_port)) {
|
||||
pr_err("bad port number: %s", optarg);
|
||||
usage();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void usage(void) {
|
||||
printf("Usage:\n"
|
||||
"\n"
|
||||
" %s [-b <address> [-h] [-p <port>]\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
"\n"
|
||||
" -b <hostname|address> Bind to this address or hostname.\n"
|
||||
" Default: \"127.0.0.1\"\n"
|
||||
" -h Show this help message.\n"
|
||||
" -p <port> Bind to this port number. Default: 1080\n"
|
||||
"",
|
||||
progname);
|
||||
exit(1);
|
||||
}
|
271
third-party/libuv/samples/socks5-proxy/s5.c
vendored
Normal file
271
third-party/libuv/samples/socks5-proxy/s5.c
vendored
Normal file
@@ -0,0 +1,271 @@
|
||||
/* Copyright StrongLoop, Inc. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "s5.h"
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h> /* abort() */
|
||||
#include <string.h> /* memset() */
|
||||
|
||||
enum {
|
||||
s5_version,
|
||||
s5_nmethods,
|
||||
s5_methods,
|
||||
s5_auth_pw_version,
|
||||
s5_auth_pw_userlen,
|
||||
s5_auth_pw_username,
|
||||
s5_auth_pw_passlen,
|
||||
s5_auth_pw_password,
|
||||
s5_req_version,
|
||||
s5_req_cmd,
|
||||
s5_req_reserved,
|
||||
s5_req_atyp,
|
||||
s5_req_atyp_host,
|
||||
s5_req_daddr,
|
||||
s5_req_dport0,
|
||||
s5_req_dport1,
|
||||
s5_dead
|
||||
};
|
||||
|
||||
void s5_init(s5_ctx *cx) {
|
||||
memset(cx, 0, sizeof(*cx));
|
||||
cx->state = s5_version;
|
||||
}
|
||||
|
||||
s5_err s5_parse(s5_ctx *cx, uint8_t **data, size_t *size) {
|
||||
s5_err err;
|
||||
uint8_t *p;
|
||||
uint8_t c;
|
||||
size_t i;
|
||||
size_t n;
|
||||
|
||||
p = *data;
|
||||
n = *size;
|
||||
i = 0;
|
||||
|
||||
while (i < n) {
|
||||
c = p[i];
|
||||
i += 1;
|
||||
switch (cx->state) {
|
||||
case s5_version:
|
||||
if (c != 5) {
|
||||
err = s5_bad_version;
|
||||
goto out;
|
||||
}
|
||||
cx->state = s5_nmethods;
|
||||
break;
|
||||
|
||||
case s5_nmethods:
|
||||
cx->arg0 = 0;
|
||||
cx->arg1 = c; /* Number of bytes to read. */
|
||||
cx->state = s5_methods;
|
||||
break;
|
||||
|
||||
case s5_methods:
|
||||
if (cx->arg0 < cx->arg1) {
|
||||
switch (c) {
|
||||
case 0:
|
||||
cx->methods |= S5_AUTH_NONE;
|
||||
break;
|
||||
case 1:
|
||||
cx->methods |= S5_AUTH_GSSAPI;
|
||||
break;
|
||||
case 2:
|
||||
cx->methods |= S5_AUTH_PASSWD;
|
||||
break;
|
||||
/* Ignore everything we don't understand. */
|
||||
}
|
||||
cx->arg0 += 1;
|
||||
}
|
||||
if (cx->arg0 == cx->arg1) {
|
||||
err = s5_auth_select;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
case s5_auth_pw_version:
|
||||
if (c != 1) {
|
||||
err = s5_bad_version;
|
||||
goto out;
|
||||
}
|
||||
cx->state = s5_auth_pw_userlen;
|
||||
break;
|
||||
|
||||
case s5_auth_pw_userlen:
|
||||
cx->arg0 = 0;
|
||||
cx->userlen = c;
|
||||
cx->state = s5_auth_pw_username;
|
||||
break;
|
||||
|
||||
case s5_auth_pw_username:
|
||||
if (cx->arg0 < cx->userlen) {
|
||||
cx->username[cx->arg0] = c;
|
||||
cx->arg0 += 1;
|
||||
}
|
||||
if (cx->arg0 == cx->userlen) {
|
||||
cx->username[cx->userlen] = '\0';
|
||||
cx->state = s5_auth_pw_passlen;
|
||||
}
|
||||
break;
|
||||
|
||||
case s5_auth_pw_passlen:
|
||||
cx->arg0 = 0;
|
||||
cx->passlen = c;
|
||||
cx->state = s5_auth_pw_password;
|
||||
break;
|
||||
|
||||
case s5_auth_pw_password:
|
||||
if (cx->arg0 < cx->passlen) {
|
||||
cx->password[cx->arg0] = c;
|
||||
cx->arg0 += 1;
|
||||
}
|
||||
if (cx->arg0 == cx->passlen) {
|
||||
cx->password[cx->passlen] = '\0';
|
||||
cx->state = s5_req_version;
|
||||
err = s5_auth_verify;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
case s5_req_version:
|
||||
if (c != 5) {
|
||||
err = s5_bad_version;
|
||||
goto out;
|
||||
}
|
||||
cx->state = s5_req_cmd;
|
||||
break;
|
||||
|
||||
case s5_req_cmd:
|
||||
switch (c) {
|
||||
case 1: /* TCP connect */
|
||||
cx->cmd = s5_cmd_tcp_connect;
|
||||
break;
|
||||
case 3: /* UDP associate */
|
||||
cx->cmd = s5_cmd_udp_assoc;
|
||||
break;
|
||||
default:
|
||||
err = s5_bad_cmd;
|
||||
goto out;
|
||||
}
|
||||
cx->state = s5_req_reserved;
|
||||
break;
|
||||
|
||||
case s5_req_reserved:
|
||||
cx->state = s5_req_atyp;
|
||||
break;
|
||||
|
||||
case s5_req_atyp:
|
||||
cx->arg0 = 0;
|
||||
switch (c) {
|
||||
case 1: /* IPv4, four octets. */
|
||||
cx->state = s5_req_daddr;
|
||||
cx->atyp = s5_atyp_ipv4;
|
||||
cx->arg1 = 4;
|
||||
break;
|
||||
case 3: /* Hostname. First byte is length. */
|
||||
cx->state = s5_req_atyp_host;
|
||||
cx->atyp = s5_atyp_host;
|
||||
cx->arg1 = 0;
|
||||
break;
|
||||
case 4: /* IPv6, sixteen octets. */
|
||||
cx->state = s5_req_daddr;
|
||||
cx->atyp = s5_atyp_ipv6;
|
||||
cx->arg1 = 16;
|
||||
break;
|
||||
default:
|
||||
err = s5_bad_atyp;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
case s5_req_atyp_host:
|
||||
cx->arg1 = c;
|
||||
cx->state = s5_req_daddr;
|
||||
break;
|
||||
|
||||
case s5_req_daddr:
|
||||
if (cx->arg0 < cx->arg1) {
|
||||
cx->daddr[cx->arg0] = c;
|
||||
cx->arg0 += 1;
|
||||
}
|
||||
if (cx->arg0 == cx->arg1) {
|
||||
cx->daddr[cx->arg1] = '\0';
|
||||
cx->state = s5_req_dport0;
|
||||
}
|
||||
break;
|
||||
|
||||
case s5_req_dport0:
|
||||
cx->dport = c << 8;
|
||||
cx->state = s5_req_dport1;
|
||||
break;
|
||||
|
||||
case s5_req_dport1:
|
||||
cx->dport |= c;
|
||||
cx->state = s5_dead;
|
||||
err = s5_exec_cmd;
|
||||
goto out;
|
||||
|
||||
case s5_dead:
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
err = s5_ok;
|
||||
|
||||
out:
|
||||
*data = p + i;
|
||||
*size = n - i;
|
||||
return err;
|
||||
}
|
||||
|
||||
unsigned int s5_auth_methods(const s5_ctx *cx) {
|
||||
return cx->methods;
|
||||
}
|
||||
|
||||
int s5_select_auth(s5_ctx *cx, s5_auth_method method) {
|
||||
int err;
|
||||
|
||||
err = 0;
|
||||
switch (method) {
|
||||
case S5_AUTH_NONE:
|
||||
cx->state = s5_req_version;
|
||||
break;
|
||||
case S5_AUTH_PASSWD:
|
||||
cx->state = s5_auth_pw_version;
|
||||
break;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
const char *s5_strerror(s5_err err) {
|
||||
#define S5_ERR_GEN(_, name, errmsg) case s5_ ## name: return errmsg;
|
||||
switch (err) {
|
||||
S5_ERR_MAP(S5_ERR_GEN)
|
||||
default: ; /* Silence s5_max_errors -Wswitch warning. */
|
||||
}
|
||||
#undef S5_ERR_GEN
|
||||
return "Unknown error.";
|
||||
}
|
94
third-party/libuv/samples/socks5-proxy/s5.h
vendored
Normal file
94
third-party/libuv/samples/socks5-proxy/s5.h
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
/* Copyright StrongLoop, Inc. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef S5_H_
|
||||
#define S5_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define S5_ERR_MAP(V) \
|
||||
V(-1, bad_version, "Bad protocol version.") \
|
||||
V(-2, bad_cmd, "Bad protocol command.") \
|
||||
V(-3, bad_atyp, "Bad address type.") \
|
||||
V(0, ok, "No error.") \
|
||||
V(1, auth_select, "Select authentication method.") \
|
||||
V(2, auth_verify, "Verify authentication.") \
|
||||
V(3, exec_cmd, "Execute command.") \
|
||||
|
||||
typedef enum {
|
||||
#define S5_ERR_GEN(code, name, _) s5_ ## name = code,
|
||||
S5_ERR_MAP(S5_ERR_GEN)
|
||||
#undef S5_ERR_GEN
|
||||
s5_max_errors
|
||||
} s5_err;
|
||||
|
||||
typedef enum {
|
||||
S5_AUTH_NONE = 1 << 0,
|
||||
S5_AUTH_GSSAPI = 1 << 1,
|
||||
S5_AUTH_PASSWD = 1 << 2
|
||||
} s5_auth_method;
|
||||
|
||||
typedef enum {
|
||||
s5_auth_allow,
|
||||
s5_auth_deny
|
||||
} s5_auth_result;
|
||||
|
||||
typedef enum {
|
||||
s5_atyp_ipv4,
|
||||
s5_atyp_ipv6,
|
||||
s5_atyp_host
|
||||
} s5_atyp;
|
||||
|
||||
typedef enum {
|
||||
s5_cmd_tcp_connect,
|
||||
s5_cmd_tcp_bind,
|
||||
s5_cmd_udp_assoc
|
||||
} s5_cmd;
|
||||
|
||||
typedef struct {
|
||||
uint32_t arg0; /* Scratch space for the state machine. */
|
||||
uint32_t arg1; /* Scratch space for the state machine. */
|
||||
uint8_t state;
|
||||
uint8_t methods;
|
||||
uint8_t cmd;
|
||||
uint8_t atyp;
|
||||
uint8_t userlen;
|
||||
uint8_t passlen;
|
||||
uint16_t dport;
|
||||
uint8_t username[257];
|
||||
uint8_t password[257];
|
||||
uint8_t daddr[257]; /* TODO(bnoordhuis) Merge with username/password. */
|
||||
} s5_ctx;
|
||||
|
||||
void s5_init(s5_ctx *ctx);
|
||||
|
||||
s5_err s5_parse(s5_ctx *cx, uint8_t **data, size_t *size);
|
||||
|
||||
/* Only call after s5_parse() has returned s5_want_auth_method. */
|
||||
unsigned int s5_auth_methods(const s5_ctx *cx);
|
||||
|
||||
/* Call after s5_parse() has returned s5_want_auth_method. */
|
||||
int s5_select_auth(s5_ctx *cx, s5_auth_method method);
|
||||
|
||||
const char *s5_strerror(s5_err err);
|
||||
|
||||
#endif /* S5_H_ */
|
241
third-party/libuv/samples/socks5-proxy/server.c
vendored
Normal file
241
third-party/libuv/samples/socks5-proxy/server.c
vendored
Normal file
@@ -0,0 +1,241 @@
|
||||
/* Copyright StrongLoop, Inc. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include <netinet/in.h> /* INET6_ADDRSTRLEN */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef INET6_ADDRSTRLEN
|
||||
# define INET6_ADDRSTRLEN 63
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uv_getaddrinfo_t getaddrinfo_req;
|
||||
server_config config;
|
||||
server_ctx *servers;
|
||||
uv_loop_t *loop;
|
||||
} server_state;
|
||||
|
||||
static void do_bind(uv_getaddrinfo_t *req, int status, struct addrinfo *ai);
|
||||
static void on_connection(uv_stream_t *server, int status);
|
||||
|
||||
int server_run(const server_config *cf, uv_loop_t *loop) {
|
||||
struct addrinfo hints;
|
||||
server_state state;
|
||||
int err;
|
||||
|
||||
memset(&state, 0, sizeof(state));
|
||||
state.servers = NULL;
|
||||
state.config = *cf;
|
||||
state.loop = loop;
|
||||
|
||||
/* Resolve the address of the interface that we should bind to.
|
||||
* The getaddrinfo callback starts the server and everything else.
|
||||
*/
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
err = uv_getaddrinfo(loop,
|
||||
&state.getaddrinfo_req,
|
||||
do_bind,
|
||||
cf->bind_host,
|
||||
NULL,
|
||||
&hints);
|
||||
if (err != 0) {
|
||||
pr_err("getaddrinfo: %s", uv_strerror(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Start the event loop. Control continues in do_bind(). */
|
||||
if (uv_run(loop, UV_RUN_DEFAULT)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Please Valgrind. */
|
||||
uv_loop_delete(loop);
|
||||
free(state.servers);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Bind a server to each address that getaddrinfo() reported. */
|
||||
static void do_bind(uv_getaddrinfo_t *req, int status, struct addrinfo *addrs) {
|
||||
char addrbuf[INET6_ADDRSTRLEN + 1];
|
||||
unsigned int ipv4_naddrs;
|
||||
unsigned int ipv6_naddrs;
|
||||
server_state *state;
|
||||
server_config *cf;
|
||||
struct addrinfo *ai;
|
||||
const void *addrv;
|
||||
const char *what;
|
||||
uv_loop_t *loop;
|
||||
server_ctx *sx;
|
||||
unsigned int n;
|
||||
int err;
|
||||
union {
|
||||
struct sockaddr addr;
|
||||
struct sockaddr_in addr4;
|
||||
struct sockaddr_in6 addr6;
|
||||
} s;
|
||||
|
||||
state = CONTAINER_OF(req, server_state, getaddrinfo_req);
|
||||
loop = state->loop;
|
||||
cf = &state->config;
|
||||
|
||||
if (status < 0) {
|
||||
pr_err("getaddrinfo(\"%s\"): %s", cf->bind_host, uv_strerror(status));
|
||||
uv_freeaddrinfo(addrs);
|
||||
return;
|
||||
}
|
||||
|
||||
ipv4_naddrs = 0;
|
||||
ipv6_naddrs = 0;
|
||||
for (ai = addrs; ai != NULL; ai = ai->ai_next) {
|
||||
if (ai->ai_family == AF_INET) {
|
||||
ipv4_naddrs += 1;
|
||||
} else if (ai->ai_family == AF_INET6) {
|
||||
ipv6_naddrs += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ipv4_naddrs == 0 && ipv6_naddrs == 0) {
|
||||
pr_err("%s has no IPv4/6 addresses", cf->bind_host);
|
||||
uv_freeaddrinfo(addrs);
|
||||
return;
|
||||
}
|
||||
|
||||
state->servers =
|
||||
xmalloc((ipv4_naddrs + ipv6_naddrs) * sizeof(state->servers[0]));
|
||||
|
||||
n = 0;
|
||||
for (ai = addrs; ai != NULL; ai = ai->ai_next) {
|
||||
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ai->ai_family == AF_INET) {
|
||||
s.addr4 = *(const struct sockaddr_in *) ai->ai_addr;
|
||||
s.addr4.sin_port = htons(cf->bind_port);
|
||||
addrv = &s.addr4.sin_addr;
|
||||
} else if (ai->ai_family == AF_INET6) {
|
||||
s.addr6 = *(const struct sockaddr_in6 *) ai->ai_addr;
|
||||
s.addr6.sin6_port = htons(cf->bind_port);
|
||||
addrv = &s.addr6.sin6_addr;
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
if (uv_inet_ntop(s.addr.sa_family, addrv, addrbuf, sizeof(addrbuf))) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
sx = state->servers + n;
|
||||
sx->loop = loop;
|
||||
sx->idle_timeout = state->config.idle_timeout;
|
||||
CHECK(0 == uv_tcp_init(loop, &sx->tcp_handle));
|
||||
|
||||
what = "uv_tcp_bind";
|
||||
err = uv_tcp_bind(&sx->tcp_handle, &s.addr, 0);
|
||||
if (err == 0) {
|
||||
what = "uv_listen";
|
||||
err = uv_listen((uv_stream_t *) &sx->tcp_handle, 128, on_connection);
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
pr_err("%s(\"%s:%hu\"): %s",
|
||||
what,
|
||||
addrbuf,
|
||||
cf->bind_port,
|
||||
uv_strerror(err));
|
||||
while (n > 0) {
|
||||
n -= 1;
|
||||
uv_close((uv_handle_t *) (state->servers + n), NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
pr_info("listening on %s:%hu", addrbuf, cf->bind_port);
|
||||
n += 1;
|
||||
}
|
||||
|
||||
uv_freeaddrinfo(addrs);
|
||||
}
|
||||
|
||||
static void on_connection(uv_stream_t *server, int status) {
|
||||
server_ctx *sx;
|
||||
client_ctx *cx;
|
||||
|
||||
CHECK(status == 0);
|
||||
sx = CONTAINER_OF(server, server_ctx, tcp_handle);
|
||||
cx = xmalloc(sizeof(*cx));
|
||||
CHECK(0 == uv_tcp_init(sx->loop, &cx->incoming.handle.tcp));
|
||||
CHECK(0 == uv_accept(server, &cx->incoming.handle.stream));
|
||||
client_finish_init(sx, cx);
|
||||
}
|
||||
|
||||
int can_auth_none(const server_ctx *sx, const client_ctx *cx) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int can_auth_passwd(const server_ctx *sx, const client_ctx *cx) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int can_access(const server_ctx *sx,
|
||||
const client_ctx *cx,
|
||||
const struct sockaddr *addr) {
|
||||
const struct sockaddr_in6 *addr6;
|
||||
const struct sockaddr_in *addr4;
|
||||
const uint32_t *p;
|
||||
uint32_t a;
|
||||
uint32_t b;
|
||||
uint32_t c;
|
||||
uint32_t d;
|
||||
|
||||
/* TODO(bnoordhuis) Implement proper access checks. For now, just reject
|
||||
* traffic to localhost.
|
||||
*/
|
||||
if (addr->sa_family == AF_INET) {
|
||||
addr4 = (const struct sockaddr_in *) addr;
|
||||
d = ntohl(addr4->sin_addr.s_addr);
|
||||
return (d >> 24) != 0x7F;
|
||||
}
|
||||
|
||||
if (addr->sa_family == AF_INET6) {
|
||||
addr6 = (const struct sockaddr_in6 *) addr;
|
||||
p = (const uint32_t *) &addr6->sin6_addr.s6_addr;
|
||||
a = ntohl(p[0]);
|
||||
b = ntohl(p[1]);
|
||||
c = ntohl(p[2]);
|
||||
d = ntohl(p[3]);
|
||||
if (a == 0 && b == 0 && c == 0 && d == 1) {
|
||||
return 0; /* "::1" style address. */
|
||||
}
|
||||
if (a == 0 && b == 0 && c == 0xFFFF && (d >> 24) == 0x7F) {
|
||||
return 0; /* "::ffff:127.x.x.x" style address. */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
72
third-party/libuv/samples/socks5-proxy/util.c
vendored
Normal file
72
third-party/libuv/samples/socks5-proxy/util.c
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
/* Copyright StrongLoop, Inc. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void pr_do(FILE *stream,
|
||||
const char *label,
|
||||
const char *fmt,
|
||||
va_list ap);
|
||||
|
||||
void *xmalloc(size_t size) {
|
||||
void *ptr;
|
||||
|
||||
ptr = malloc(size);
|
||||
if (ptr == NULL) {
|
||||
pr_err("out of memory, need %lu bytes", (unsigned long) size);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void pr_info(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
pr_do(stdout, "info", fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void pr_warn(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
pr_do(stderr, "warn", fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void pr_err(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
pr_do(stderr, "error", fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static void pr_do(FILE *stream,
|
||||
const char *label,
|
||||
const char *fmt,
|
||||
va_list ap) {
|
||||
char fmtbuf[1024];
|
||||
vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, ap);
|
||||
fprintf(stream, "%s:%s: %s\n", _getprogname(), label, fmtbuf);
|
||||
}
|
Reference in New Issue
Block a user