Skip to content

Commit

Permalink
both: shadowsocks over tls
Browse files Browse the repository at this point in the history
  • Loading branch information
liudongmiao committed Mar 25, 2024
1 parent e51c34c commit e7b7f36
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 5 deletions.
38 changes: 38 additions & 0 deletions common.c
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,44 @@ void tunnel_wss(struct bufferevent *raw, struct evhttp_connection *wss) {
bufferevent_setcb(raw, raw_forward_cb, NULL, raw_event_cb_wss, wss);
}

static void wss_event_cb_ss(struct bufferevent *tev, short event, void *raw) {
uint16_t port;
struct evhttp_connection *wss;
(void) tev;
if (event & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {
bufferevent_getcb(raw, NULL, NULL, NULL, (void **) &wss);
#ifdef WSS_PROXY_CLIENT
port = get_peer_port(raw);
#endif
#ifdef WSS_PROXY_SERVER
port = get_http_port(wss);
#endif
LOGD("connection %u closing from wss %p (won't send close), event: 0x%02x", port, wss, event);
bufferevent_free(raw);
evhttp_connection_free(wss);
}
}

static void raw_forward_cb_ss(struct bufferevent *raw, void *wss) {
struct evbuffer *src;
struct evbuffer *dst;

src = bufferevent_get_input(raw);
dst = bufferevent_get_output(evhttp_connection_get_bufferevent(wss));
evbuffer_add_buffer(dst, src);
}

void tunnel_ss(struct bufferevent *raw, struct evhttp_connection *wss) {
struct bufferevent *tev;

tev = evhttp_connection_get_bufferevent(wss);
bufferevent_enable(tev, EV_READ | EV_WRITE);
bufferevent_setcb(tev, wss_forward_cb, NULL, wss_event_cb_ss, raw);

bufferevent_enable(raw, EV_READ | EV_WRITE);
bufferevent_setcb(raw, raw_forward_cb_ss, NULL, raw_event_cb, wss);
}

#ifdef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK
void ssl_keylog_callback(const SSL *ssl, const char *line) {
char *keylog_file_name;
Expand Down
5 changes: 5 additions & 0 deletions common.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ void tunnel_wss(struct bufferevent *raw, struct evhttp_connection *wss);
*/
int send_close(struct bufferevent *raw, uint16_t reason);

#define X_UPGRADE "X-Upgrade"
#define SHADOWSOCKS "shadowsocks"
#define IS_SHADOWSOCKS(x) (x != NULL && !evutil_ascii_strcasecmp(x, SHADOWSOCKS))
void tunnel_ss(struct bufferevent *raw, struct evhttp_connection *wss);

#ifdef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK
void ssl_keylog_callback(const SSL *ssl, const char *line);
#endif
Expand Down
12 changes: 12 additions & 0 deletions run-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,15 @@ fi

echo "cleaning..."
sleep 1
kill $lpid
sleep 1
echo wss-proxy client - wss-proxy server - ss
ss-local -l $lport -s 127.0.0.1 -p $sport -m chacha20-ietf-poly1305 -k sip003 --plugin ./wss-proxy-client --plugin-opts "mux=0;ws=0" &
lpid=$!
sleep 1
if ! check; then
exit 1
fi

echo "cleaning..."
sleep 1
38 changes: 34 additions & 4 deletions wss-proxy-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
#include "common.h"

struct wss_server_info {
uint8_t tls;
uint8_t tls: 1;
uint8_t ws: 1;
uint16_t port;
const char *addr;
const char *host;
Expand Down Expand Up @@ -60,6 +61,7 @@ static int init_wss_addr(struct wss_server_info *server) {
int port;
char *end;
int mux = 1;
char *wss;
const char *loglevel;
const char *remote_host = getenv("SS_REMOTE_HOST");
const char *remote_port = getenv("SS_REMOTE_PORT");
Expand Down Expand Up @@ -124,6 +126,14 @@ static int init_wss_addr(struct wss_server_info *server) {
mux = (int) strtol(end, NULL, 10);
}

// wss
if ((end = strstr(options, "ws=")) != NULL) {
end += 3;
server->ws = (int) strtol(end, NULL, 10);
} else {
server->ws = 1;
}

// strip
if ((end = strstr(server->host, ";")) != NULL) {
*end = '\0';
Expand All @@ -132,8 +142,21 @@ static int init_wss_addr(struct wss_server_info *server) {
*end = '\0';
}

LOGI("wss client %s:%d (%s://%s%s)", remote_host, port, server->tls ? "wss" : "ws", server->host, server->path);
if (mux) {
if (server->ws) {
if (server->tls) {
wss = "wss";
} else {
wss = "ws";
}
} else {
if (server->tls) {
wss = "sss";
} else {
wss = "ss";
}
}
LOGI("wss client %s:%d (%s://%s%s)", remote_host, port, wss, server->host, server->path);
if (server->ws && mux) {
LOGW("mux %d is unsupported", mux);
}
return 0;
Expand All @@ -159,7 +182,11 @@ static void http_request_cb(struct evhttp_request *req, void *raw) {
int status = req == NULL ? -1 : evhttp_request_get_response_code(req);
bufferevent_getcb(raw, NULL, NULL, NULL, (void **) &wss);
if (status == 101 && is_websocket_handshake(req)) {
tunnel_wss(raw, wss);
if (IS_SHADOWSOCKS(evhttp_find_header(evhttp_request_get_input_headers(req), X_UPGRADE))) {
tunnel_ss(raw, wss);
} else {
tunnel_wss(raw, wss);
}
} else {
LOGE("wss fail for peer %d, status: %d", get_peer_port(raw), status);
bufferevent_free(raw);
Expand Down Expand Up @@ -240,6 +267,9 @@ static struct evhttp_connection *connect_wss(struct wss_proxy_context *context,
#endif
evhttp_add_header(output_headers, "Sec-WebSocket-Version", "13");
evhttp_add_header(output_headers, "User-Agent", context->user_agent);
if (!context->server.ws) {
evhttp_add_header(output_headers, X_UPGRADE, SHADOWSOCKS);
}

if (evhttp_make_request(wss, req, EVHTTP_REQ_GET, context->server.path)) {
LOGE("cannot make http request for peer %d", port);
Expand Down
11 changes: 10 additions & 1 deletion wss-proxy-server.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ static void generic_request_handler(struct evhttp_request *req, void *ctx) {
struct raw_server_info *raw_server_info = ctx;
char sec_websocket_accept[29];
struct evkeyvalq *headers = evhttp_request_get_output_headers(req);
int ss;

if (!do_websocket_handshake(req, sec_websocket_accept)) {
goto error;
Expand All @@ -120,9 +121,17 @@ static void generic_request_handler(struct evhttp_request *req, void *ctx) {
evhttp_add_header(headers, "Upgrade", "websocket");
evhttp_add_header(headers, "Connection", "Upgrade");
evhttp_add_header(headers, "Sec-WebSocket-Accept", (char *) sec_websocket_accept);
ss = IS_SHADOWSOCKS(evhttp_find_header(evhttp_request_get_input_headers(req), X_UPGRADE));
if (ss) {
evhttp_add_header(headers, X_UPGRADE, SHADOWSOCKS);
}
evhttp_send_reply(req, 101, "Switching Protocols", NULL);

tunnel_wss(raw, wss);
if (ss) {
tunnel_ss(raw, wss);
} else {
tunnel_wss(raw, wss);
}
return;
error:
evhttp_send_error(req, HTTP_BADREQUEST, "Bad Request");
Expand Down

0 comments on commit e7b7f36

Please sign in to comment.