Skip to content

Commit e7b7f36

Browse files
committed
both: shadowsocks over tls
1 parent e51c34c commit e7b7f36

File tree

5 files changed

+99
-5
lines changed

5 files changed

+99
-5
lines changed

common.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,44 @@ void tunnel_wss(struct bufferevent *raw, struct evhttp_connection *wss) {
591591
bufferevent_setcb(raw, raw_forward_cb, NULL, raw_event_cb_wss, wss);
592592
}
593593

594+
static void wss_event_cb_ss(struct bufferevent *tev, short event, void *raw) {
595+
uint16_t port;
596+
struct evhttp_connection *wss;
597+
(void) tev;
598+
if (event & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {
599+
bufferevent_getcb(raw, NULL, NULL, NULL, (void **) &wss);
600+
#ifdef WSS_PROXY_CLIENT
601+
port = get_peer_port(raw);
602+
#endif
603+
#ifdef WSS_PROXY_SERVER
604+
port = get_http_port(wss);
605+
#endif
606+
LOGD("connection %u closing from wss %p (won't send close), event: 0x%02x", port, wss, event);
607+
bufferevent_free(raw);
608+
evhttp_connection_free(wss);
609+
}
610+
}
611+
612+
static void raw_forward_cb_ss(struct bufferevent *raw, void *wss) {
613+
struct evbuffer *src;
614+
struct evbuffer *dst;
615+
616+
src = bufferevent_get_input(raw);
617+
dst = bufferevent_get_output(evhttp_connection_get_bufferevent(wss));
618+
evbuffer_add_buffer(dst, src);
619+
}
620+
621+
void tunnel_ss(struct bufferevent *raw, struct evhttp_connection *wss) {
622+
struct bufferevent *tev;
623+
624+
tev = evhttp_connection_get_bufferevent(wss);
625+
bufferevent_enable(tev, EV_READ | EV_WRITE);
626+
bufferevent_setcb(tev, wss_forward_cb, NULL, wss_event_cb_ss, raw);
627+
628+
bufferevent_enable(raw, EV_READ | EV_WRITE);
629+
bufferevent_setcb(raw, raw_forward_cb_ss, NULL, raw_event_cb, wss);
630+
}
631+
594632
#ifdef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK
595633
void ssl_keylog_callback(const SSL *ssl, const char *line) {
596634
char *keylog_file_name;

common.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ void tunnel_wss(struct bufferevent *raw, struct evhttp_connection *wss);
9494
*/
9595
int send_close(struct bufferevent *raw, uint16_t reason);
9696

97+
#define X_UPGRADE "X-Upgrade"
98+
#define SHADOWSOCKS "shadowsocks"
99+
#define IS_SHADOWSOCKS(x) (x != NULL && !evutil_ascii_strcasecmp(x, SHADOWSOCKS))
100+
void tunnel_ss(struct bufferevent *raw, struct evhttp_connection *wss);
101+
97102
#ifdef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK
98103
void ssl_keylog_callback(const SSL *ssl, const char *line);
99104
#endif

run-test.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,15 @@ fi
9595

9696
echo "cleaning..."
9797
sleep 1
98+
kill $lpid
99+
sleep 1
100+
echo wss-proxy client - wss-proxy server - ss
101+
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" &
102+
lpid=$!
103+
sleep 1
104+
if ! check; then
105+
exit 1
106+
fi
107+
108+
echo "cleaning..."
109+
sleep 1

wss-proxy-client.c

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
#include "common.h"
1212

1313
struct wss_server_info {
14-
uint8_t tls;
14+
uint8_t tls: 1;
15+
uint8_t ws: 1;
1516
uint16_t port;
1617
const char *addr;
1718
const char *host;
@@ -60,6 +61,7 @@ static int init_wss_addr(struct wss_server_info *server) {
6061
int port;
6162
char *end;
6263
int mux = 1;
64+
char *wss;
6365
const char *loglevel;
6466
const char *remote_host = getenv("SS_REMOTE_HOST");
6567
const char *remote_port = getenv("SS_REMOTE_PORT");
@@ -124,6 +126,14 @@ static int init_wss_addr(struct wss_server_info *server) {
124126
mux = (int) strtol(end, NULL, 10);
125127
}
126128

129+
// wss
130+
if ((end = strstr(options, "ws=")) != NULL) {
131+
end += 3;
132+
server->ws = (int) strtol(end, NULL, 10);
133+
} else {
134+
server->ws = 1;
135+
}
136+
127137
// strip
128138
if ((end = strstr(server->host, ";")) != NULL) {
129139
*end = '\0';
@@ -132,8 +142,21 @@ static int init_wss_addr(struct wss_server_info *server) {
132142
*end = '\0';
133143
}
134144

135-
LOGI("wss client %s:%d (%s://%s%s)", remote_host, port, server->tls ? "wss" : "ws", server->host, server->path);
136-
if (mux) {
145+
if (server->ws) {
146+
if (server->tls) {
147+
wss = "wss";
148+
} else {
149+
wss = "ws";
150+
}
151+
} else {
152+
if (server->tls) {
153+
wss = "sss";
154+
} else {
155+
wss = "ss";
156+
}
157+
}
158+
LOGI("wss client %s:%d (%s://%s%s)", remote_host, port, wss, server->host, server->path);
159+
if (server->ws && mux) {
137160
LOGW("mux %d is unsupported", mux);
138161
}
139162
return 0;
@@ -159,7 +182,11 @@ static void http_request_cb(struct evhttp_request *req, void *raw) {
159182
int status = req == NULL ? -1 : evhttp_request_get_response_code(req);
160183
bufferevent_getcb(raw, NULL, NULL, NULL, (void **) &wss);
161184
if (status == 101 && is_websocket_handshake(req)) {
162-
tunnel_wss(raw, wss);
185+
if (IS_SHADOWSOCKS(evhttp_find_header(evhttp_request_get_input_headers(req), X_UPGRADE))) {
186+
tunnel_ss(raw, wss);
187+
} else {
188+
tunnel_wss(raw, wss);
189+
}
163190
} else {
164191
LOGE("wss fail for peer %d, status: %d", get_peer_port(raw), status);
165192
bufferevent_free(raw);
@@ -240,6 +267,9 @@ static struct evhttp_connection *connect_wss(struct wss_proxy_context *context,
240267
#endif
241268
evhttp_add_header(output_headers, "Sec-WebSocket-Version", "13");
242269
evhttp_add_header(output_headers, "User-Agent", context->user_agent);
270+
if (!context->server.ws) {
271+
evhttp_add_header(output_headers, X_UPGRADE, SHADOWSOCKS);
272+
}
243273

244274
if (evhttp_make_request(wss, req, EVHTTP_REQ_GET, context->server.path)) {
245275
LOGE("cannot make http request for peer %d", port);

wss-proxy-server.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ static void generic_request_handler(struct evhttp_request *req, void *ctx) {
9999
struct raw_server_info *raw_server_info = ctx;
100100
char sec_websocket_accept[29];
101101
struct evkeyvalq *headers = evhttp_request_get_output_headers(req);
102+
int ss;
102103

103104
if (!do_websocket_handshake(req, sec_websocket_accept)) {
104105
goto error;
@@ -120,9 +121,17 @@ static void generic_request_handler(struct evhttp_request *req, void *ctx) {
120121
evhttp_add_header(headers, "Upgrade", "websocket");
121122
evhttp_add_header(headers, "Connection", "Upgrade");
122123
evhttp_add_header(headers, "Sec-WebSocket-Accept", (char *) sec_websocket_accept);
124+
ss = IS_SHADOWSOCKS(evhttp_find_header(evhttp_request_get_input_headers(req), X_UPGRADE));
125+
if (ss) {
126+
evhttp_add_header(headers, X_UPGRADE, SHADOWSOCKS);
127+
}
123128
evhttp_send_reply(req, 101, "Switching Protocols", NULL);
124129

125-
tunnel_wss(raw, wss);
130+
if (ss) {
131+
tunnel_ss(raw, wss);
132+
} else {
133+
tunnel_wss(raw, wss);
134+
}
126135
return;
127136
error:
128137
evhttp_send_error(req, HTTP_BADREQUEST, "Bad Request");

0 commit comments

Comments
 (0)