1 /*
2  * Copyright (c) 2014-2021 Joris Vink <joris@coders.se>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <sys/param.h>
18 #include <sys/types.h>
19 
20 #include <openssl/sha.h>
21 
22 #include <limits.h>
23 #include <string.h>
24 
25 #include "kore.h"
26 #include "http.h"
27 
28 #define WEBSOCKET_FRAME_HDR		2
29 #define WEBSOCKET_MASK_LEN		4
30 #define WEBSOCKET_FRAME_MAXLEN		16384
31 #define WEBSOCKET_PAYLOAD_SINGLE	125
32 #define WEBSOCKET_PAYLOAD_EXTEND_1	126
33 #define WEBSOCKET_PAYLOAD_EXTEND_2	127
34 #define WEBSOCKET_OPCODE_MASK		0x0f
35 #define WEBSOCKET_FRAME_LENGTH(x)	((x) & ~(1 << 7))
36 #define WEBSOCKET_HAS_MASK(x)		((x) & (1 << 7))
37 #define WEBSOCKET_HAS_FINFLAG(x)	((x) & (1 << 7))
38 #define WEBSOCKET_RSV(x, i)		((x) & (1 << (7 - i)))
39 
40 #define WEBSOCKET_SERVER_RESPONSE	"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
41 
42 
43 u_int64_t	kore_websocket_timeout = 120000;
44 u_int64_t	kore_websocket_maxframe = 16384;
45 
46 static int	websocket_recv_frame(struct netbuf *);
47 static int	websocket_recv_opcode(struct netbuf *);
48 static void	websocket_disconnect(struct connection *);
49 static void	websocket_frame_build(struct kore_buf *, u_int8_t,
50 		    const void *, size_t);
51 
52 void
kore_websocket_handshake(struct http_request * req,const char * onconnect,const char * onmessage,const char * ondisconnect)53 kore_websocket_handshake(struct http_request *req, const char *onconnect,
54     const char *onmessage, const char *ondisconnect)
55 {
56 	SHA_CTX			sctx;
57 	struct kore_buf		*buf;
58 	char			*base64;
59 	const char		*key, *version;
60 	u_int8_t		digest[SHA_DIGEST_LENGTH];
61 
62 	if (!http_request_header(req, "sec-websocket-key", &key)) {
63 		http_response(req, HTTP_STATUS_BAD_REQUEST, NULL, 0);
64 		return;
65 	}
66 
67 	if (!http_request_header(req, "sec-websocket-version", &version)) {
68 		http_response_header(req, "sec-websocket-version", "13");
69 		http_response(req, HTTP_STATUS_BAD_REQUEST, NULL, 0);
70 		return;
71 	}
72 
73 	if (strcmp(version, "13")) {
74 		http_response_header(req, "sec-websocket-version", "13");
75 		http_response(req, HTTP_STATUS_BAD_REQUEST, NULL, 0);
76 		return;
77 	}
78 
79 	buf = kore_buf_alloc(128);
80 	kore_buf_appendf(buf, "%s%s", key, WEBSOCKET_SERVER_RESPONSE);
81 
82 	(void)SHA1_Init(&sctx);
83 	(void)SHA1_Update(&sctx, buf->data, buf->offset);
84 	(void)SHA1_Final(digest, &sctx);
85 
86 	kore_buf_free(buf);
87 
88 	if (!kore_base64_encode(digest, sizeof(digest), &base64)) {
89 		kore_debug("failed to base64 encode digest");
90 		http_response(req, HTTP_STATUS_INTERNAL_ERROR, NULL, 0);
91 		return;
92 	}
93 
94 	http_response_header(req, "upgrade", "websocket");
95 	http_response_header(req, "connection", "upgrade");
96 	http_response_header(req, "sec-websocket-accept", base64);
97 	kore_free(base64);
98 
99 	kore_debug("%p: new websocket connection", req->owner);
100 
101 	req->owner->proto = CONN_PROTO_WEBSOCKET;
102 	http_response(req, HTTP_STATUS_SWITCHING_PROTOCOLS, NULL, 0);
103 	net_recv_reset(req->owner, WEBSOCKET_FRAME_HDR, websocket_recv_opcode);
104 
105 	req->owner->disconnect = websocket_disconnect;
106 	req->owner->rnb->flags &= ~NETBUF_CALL_CB_ALWAYS;
107 
108 	req->owner->http_timeout = 0;
109 	req->owner->idle_timer.start = kore_time_ms();
110 	req->owner->idle_timer.length = kore_websocket_timeout;
111 
112 	if (onconnect != NULL) {
113 		req->owner->ws_connect = kore_runtime_getcall(onconnect);
114 		if (req->owner->ws_connect == NULL)
115 			fatal("no symbol '%s' for ws_connect", onconnect);
116 	} else {
117 		req->owner->ws_connect = NULL;
118 	}
119 
120 	if (onmessage != NULL) {
121 		req->owner->ws_message = kore_runtime_getcall(onmessage);
122 		if (req->owner->ws_message == NULL)
123 			fatal("no symbol '%s' for ws_message", onmessage);
124 	} else {
125 		req->owner->ws_message = NULL;
126 	}
127 
128 	if (ondisconnect != NULL) {
129 		req->owner->ws_disconnect = kore_runtime_getcall(ondisconnect);
130 		if (req->owner->ws_disconnect == NULL)
131 			fatal("no symbol '%s' for ws_disconnect", ondisconnect);
132 	} else {
133 		req->owner->ws_disconnect = NULL;
134 	}
135 
136 	if (req->owner->ws_connect != NULL)
137 		kore_runtime_wsconnect(req->owner->ws_connect, req->owner);
138 }
139 
140 int
kore_websocket_send_clean(struct netbuf * nb)141 kore_websocket_send_clean(struct netbuf *nb)
142 {
143 	kore_free(nb->buf);
144 	return (0);
145 }
146 
147 void
kore_websocket_send(struct connection * c,u_int8_t op,const void * data,size_t len)148 kore_websocket_send(struct connection *c, u_int8_t op, const void *data,
149     size_t len)
150 {
151 	struct kore_buf		frame;
152 
153 	kore_buf_init(&frame, len);
154 	websocket_frame_build(&frame, op, data, len);
155 	net_send_stream(c, frame.data, frame.offset,
156 	    kore_websocket_send_clean, NULL);
157 
158 	/* net_send_stream() takes over the buffer data pointer. */
159 	frame.data = NULL;
160 	kore_buf_cleanup(&frame);
161 
162 	net_send_flush(c);
163 }
164 
165 void
kore_websocket_broadcast(struct connection * src,u_int8_t op,const void * data,size_t len,int scope)166 kore_websocket_broadcast(struct connection *src, u_int8_t op, const void *data,
167     size_t len, int scope)
168 {
169 	struct connection	*c;
170 	struct kore_buf		*frame;
171 
172 	frame = kore_buf_alloc(len);
173 	websocket_frame_build(frame, op, data, len);
174 
175 	TAILQ_FOREACH(c, &connections, list) {
176 		if (c != src && c->proto == CONN_PROTO_WEBSOCKET) {
177 			net_send_queue(c, frame->data, frame->offset);
178 			net_send_flush(c);
179 		}
180 	}
181 
182 	if (scope == WEBSOCKET_BROADCAST_GLOBAL) {
183 		kore_msg_send(KORE_MSG_WORKER_ALL,
184 		    KORE_MSG_WEBSOCKET, frame->data, frame->offset);
185 	}
186 
187 	kore_buf_free(frame);
188 }
189 
190 static void
websocket_frame_build(struct kore_buf * frame,u_int8_t op,const void * data,size_t len)191 websocket_frame_build(struct kore_buf *frame, u_int8_t op, const void *data,
192     size_t len)
193 {
194 	u_int8_t		len_1;
195 	u_int16_t		len16;
196 	u_int64_t		len64;
197 
198 	if (len > WEBSOCKET_PAYLOAD_SINGLE) {
199 		if (len <= USHRT_MAX)
200 			len_1 = WEBSOCKET_PAYLOAD_EXTEND_1;
201 		else
202 			len_1 = WEBSOCKET_PAYLOAD_EXTEND_2;
203 	} else {
204 		len_1 = len;
205 	}
206 
207 	op |= (1 << 7);
208 	kore_buf_append(frame, &op, sizeof(op));
209 
210 	len_1 &= ~(1 << 7);
211 	kore_buf_append(frame, &len_1, sizeof(len_1));
212 
213 	if (len_1 > WEBSOCKET_PAYLOAD_SINGLE) {
214 		switch (len_1) {
215 		case WEBSOCKET_PAYLOAD_EXTEND_1:
216 			net_write16((u_int8_t *)&len16, len);
217 			kore_buf_append(frame, &len16, sizeof(len16));
218 			break;
219 		case WEBSOCKET_PAYLOAD_EXTEND_2:
220 			net_write64((u_int8_t *)&len64, len);
221 			kore_buf_append(frame, &len64, sizeof(len64));
222 			break;
223 		}
224 	}
225 
226 	if (data != NULL && len > 0)
227 		kore_buf_append(frame, data, len);
228 }
229 
230 static int
websocket_recv_opcode(struct netbuf * nb)231 websocket_recv_opcode(struct netbuf *nb)
232 {
233 	u_int8_t		op, len;
234 	struct connection	*c = nb->owner;
235 
236 	if (!WEBSOCKET_HAS_MASK(nb->buf[1])) {
237 		kore_debug("%p: frame did not have a mask set", c);
238 		return (KORE_RESULT_ERROR);
239 	}
240 
241 	if (WEBSOCKET_RSV(nb->buf[0], 1) || WEBSOCKET_RSV(nb->buf[0], 2) ||
242 	    WEBSOCKET_RSV(nb->buf[0], 3)) {
243 		kore_debug("%p: RSV bits are not zero", c);
244 		return (KORE_RESULT_ERROR);
245 	}
246 
247 	len = WEBSOCKET_FRAME_LENGTH(nb->buf[1]);
248 
249 	op = nb->buf[0] & WEBSOCKET_OPCODE_MASK;
250 	switch (op) {
251 	case WEBSOCKET_OP_CONT:
252 	case WEBSOCKET_OP_TEXT:
253 	case WEBSOCKET_OP_BINARY:
254 		break;
255 	case WEBSOCKET_OP_CLOSE:
256 	case WEBSOCKET_OP_PING:
257 	case WEBSOCKET_OP_PONG:
258 		if (len > WEBSOCKET_PAYLOAD_SINGLE ||
259 		    !WEBSOCKET_HAS_FINFLAG(nb->buf[0])) {
260 			kore_debug("%p: large or fragmented control frame", c);
261 			return (KORE_RESULT_ERROR);
262 		}
263 		break;
264 	default:
265 		kore_debug("%p: bad websocket op %d", c, op);
266 		return (KORE_RESULT_ERROR);
267 	}
268 
269 	switch (len) {
270 	case WEBSOCKET_PAYLOAD_EXTEND_1:
271 		len += sizeof(u_int16_t);
272 		break;
273 	case WEBSOCKET_PAYLOAD_EXTEND_2:
274 		len += sizeof(u_int64_t);
275 		break;
276 	}
277 
278 	len += WEBSOCKET_MASK_LEN;
279 	net_recv_expand(c, len, websocket_recv_frame);
280 
281 	return (KORE_RESULT_OK);
282 }
283 
284 static int
websocket_recv_frame(struct netbuf * nb)285 websocket_recv_frame(struct netbuf *nb)
286 {
287 	struct connection	*c;
288 	int			ret;
289 	u_int64_t		len, i, total;
290 	u_int8_t		op, moff, extra;
291 
292 	c = nb->owner;
293 	op = nb->buf[0] & WEBSOCKET_OPCODE_MASK;
294 	len = WEBSOCKET_FRAME_LENGTH(nb->buf[1]);
295 
296 	switch (len) {
297 	case WEBSOCKET_PAYLOAD_EXTEND_1:
298 		moff = 4;
299 		extra = sizeof(u_int16_t);
300 		len = net_read16(&nb->buf[2]);
301 		break;
302 	case WEBSOCKET_PAYLOAD_EXTEND_2:
303 		moff = 10;
304 		extra = sizeof(u_int64_t);
305 		len = net_read64(&nb->buf[2]);
306 		break;
307 	default:
308 		extra = 0;
309 		moff = 2;
310 		break;
311 	}
312 
313 	if (len > kore_websocket_maxframe) {
314 		kore_debug("%p: frame too big", c);
315 		return (KORE_RESULT_ERROR);
316 	}
317 
318 	extra += WEBSOCKET_FRAME_HDR;
319 	total = len + extra + WEBSOCKET_MASK_LEN;
320 	if (total > nb->b_len) {
321 		total -= nb->b_len;
322 		net_recv_expand(c, total, websocket_recv_frame);
323 		return (KORE_RESULT_OK);
324 	}
325 
326 	if (total != nb->b_len)
327 		return (KORE_RESULT_ERROR);
328 
329 	for (i = 0; i < len; i++)
330 		nb->buf[moff + 4 + i] ^= nb->buf[moff + (i % 4)];
331 
332 	ret = KORE_RESULT_OK;
333 	switch (op) {
334 	case WEBSOCKET_OP_PONG:
335 		break;
336 	case WEBSOCKET_OP_CONT:
337 		ret = KORE_RESULT_ERROR;
338 		kore_log(LOG_ERR,
339 		    "%p: we do not support op 0x%02x yet", (void *)c, op);
340 		break;
341 	case WEBSOCKET_OP_TEXT:
342 	case WEBSOCKET_OP_BINARY:
343 		if (c->ws_message != NULL) {
344 			kore_runtime_wsmessage(c->ws_message,
345 			    c, op, &nb->buf[moff + 4], len);
346 		}
347 		break;
348 	case WEBSOCKET_OP_CLOSE:
349 		c->evt.flags &= ~KORE_EVENT_READ;
350 		if (!(c->flags & CONN_WS_CLOSE_SENT)) {
351 			c->flags |= CONN_WS_CLOSE_SENT;
352 			kore_websocket_send(c, WEBSOCKET_OP_CLOSE, NULL, 0);
353 		}
354 		kore_connection_disconnect(c);
355 		break;
356 	case WEBSOCKET_OP_PING:
357 		kore_websocket_send(c, WEBSOCKET_OP_PONG,
358 		    &nb->buf[moff + 4], len);
359 		break;
360 	default:
361 		kore_debug("%p: bad websocket op %d", c, op);
362 		return (KORE_RESULT_ERROR);
363 	}
364 
365 	net_recv_reset(c, WEBSOCKET_FRAME_HDR, websocket_recv_opcode);
366 
367 	return (ret);
368 }
369 
370 static void
websocket_disconnect(struct connection * c)371 websocket_disconnect(struct connection *c)
372 {
373 	if (c->ws_disconnect != NULL)
374 		kore_runtime_wsdisconnect(c->ws_disconnect, c);
375 
376 	if (!(c->flags & CONN_WS_CLOSE_SENT)) {
377 		c->flags |= CONN_WS_CLOSE_SENT;
378 		c->evt.flags &= ~KORE_EVENT_READ;
379 		kore_websocket_send(c, WEBSOCKET_OP_CLOSE, NULL, 0);
380 	}
381 }
382