mirror of
https://github.com/shadowsocks/shadowsocks-libev.git
synced 2026-10-28 10:44:43 +08:00
Remove sniparser
This commit is contained in:
1 parent
bb12209941
commit
301fea635b
11 files changed
+8
-587
No files matched your search
Vendored
+1
-1
@@ -49,7 +49,7 @@ Files: src/json.c src/json.h
|
||||
Copyright: 2012-2014, James McLaughlin et al.
|
||||
License: BSD-2-clause
|
||||
|
||||
Files: src/http.c src/http.h src/protocol.h src/resolv.c src/resolv.h src/tls.c src/tls.h
|
||||
Files: src/resolv.c src/resolv.h
|
||||
Copyright: 2011-2014, Dustin Lundquist <dustin@null-ptr.net>
|
||||
License: BSD-2-clause
|
||||
|
||||
|
||||
@@ -6,11 +6,6 @@ else ()
|
||||
endif ()
|
||||
|
||||
|
||||
set(SS_SNI_SOURCE
|
||||
http.c
|
||||
tls.c
|
||||
)
|
||||
|
||||
set(SS_ACL_SOURCE
|
||||
acl.c
|
||||
rule.c
|
||||
@@ -42,7 +37,6 @@ set(LIBSHADOWSOCKS_LIBEV_SOURCE
|
||||
local.c
|
||||
${SS_CRYPTO_SOURCE}
|
||||
${SS_PLUGIN_SOURCE}
|
||||
${SS_SNI_SOURCE}
|
||||
${SS_ACL_SOURCE}
|
||||
)
|
||||
|
||||
@@ -68,7 +62,6 @@ set(SS_SERVER_SOURCE
|
||||
server.c
|
||||
${SS_CRYPTO_SOURCE}
|
||||
${SS_PLUGIN_SOURCE}
|
||||
${SS_SNI_SOURCE}
|
||||
${SS_ACL_SOURCE}
|
||||
)
|
||||
|
||||
|
||||
@@ -24,9 +24,6 @@ if !BUILD_WINCOMPAT
|
||||
bin_PROGRAMS += ss-manager
|
||||
endif
|
||||
|
||||
sni_src = http.c \
|
||||
tls.c
|
||||
|
||||
acl_src = rule.c \
|
||||
acl.c
|
||||
|
||||
@@ -53,7 +50,6 @@ ss_local_SOURCES = local.c \
|
||||
$(common_src) \
|
||||
$(crypto_src) \
|
||||
$(plugin_src) \
|
||||
$(sni_src) \
|
||||
$(acl_src)
|
||||
|
||||
ss_tunnel_SOURCES = tunnel.c \
|
||||
@@ -66,7 +62,6 @@ ss_server_SOURCES = resolv.c \
|
||||
$(common_src) \
|
||||
$(crypto_src) \
|
||||
$(plugin_src) \
|
||||
$(sni_src) \
|
||||
${acl_src}
|
||||
|
||||
ss_manager_SOURCES = utils.c \
|
||||
|
||||
@@ -51,7 +51,6 @@ int send_traffic_stat(uint64_t tx, uint64_t rx);
|
||||
#define STAGE_ERROR -1 /* Error detected */
|
||||
#define STAGE_INIT 0 /* Initial stage */
|
||||
#define STAGE_HANDSHAKE 1 /* Handshake with client */
|
||||
#define STAGE_SNI 3 /* Parse HTTP/SNI header */
|
||||
#define STAGE_RESOLVE 4 /* Resolve the hostname */
|
||||
#define STAGE_STREAM 5 /* Stream between client and server */
|
||||
#define STAGE_STOP 6 /* Server stop to response */
|
||||
|
||||
-153
@@ -1,153 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011 and 2012, Dustin Lundquist <dustin@null-ptr.net>
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* malloc() */
|
||||
#include <string.h> /* strncpy() */
|
||||
#include <strings.h> /* strncasecmp() */
|
||||
#include <ctype.h> /* isblank(), isdigit() */
|
||||
|
||||
#include "http.h"
|
||||
#include "protocol.h"
|
||||
|
||||
static int parse_http_header(const char *, size_t, char **);
|
||||
static int get_header(const char *, const char *, int, char **);
|
||||
static int next_header(const char **, int *);
|
||||
|
||||
static const protocol_t http_protocol_st = {
|
||||
.default_port = 80,
|
||||
.parse_packet = &parse_http_header,
|
||||
};
|
||||
const protocol_t *const http_protocol = &http_protocol_st;
|
||||
|
||||
/*
|
||||
* Parses a HTTP request for the Host: header
|
||||
*
|
||||
* Returns:
|
||||
* >=0 - length of the hostname and updates *hostname
|
||||
* caller is responsible for freeing *hostname
|
||||
* -1 - Incomplete request
|
||||
* -2 - No Host header included in this request
|
||||
* -3 - Invalid hostname pointer
|
||||
* -4 - malloc failure
|
||||
* < -4 - Invalid HTTP request
|
||||
*
|
||||
*/
|
||||
static int
|
||||
parse_http_header(const char *data, size_t data_len, char **hostname)
|
||||
{
|
||||
int result, i;
|
||||
|
||||
if (hostname == NULL)
|
||||
return -3;
|
||||
|
||||
if (data_len == 0)
|
||||
return -1;
|
||||
|
||||
result = get_header("Host:", data, data_len, hostname);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
/*
|
||||
* if the user specifies the port in the request, it is included here.
|
||||
* Host: example.com:80
|
||||
* Host: [2001:db8::1]:8080
|
||||
* so we trim off port portion
|
||||
*/
|
||||
for (i = result - 1; i >= 0; i--)
|
||||
if ((*hostname)[i] == ':') {
|
||||
(*hostname)[i] = '\0';
|
||||
result = i;
|
||||
break;
|
||||
} else if (!isdigit((*hostname)[i])) {
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
get_header(const char *header, const char *data, int data_len, char **value)
|
||||
{
|
||||
int len, header_len;
|
||||
|
||||
header_len = strlen(header);
|
||||
|
||||
/* loop through headers stopping at first blank line */
|
||||
while ((len = next_header(&data, &data_len)) != 0)
|
||||
if (len > header_len && strncasecmp(header, data, header_len) == 0) {
|
||||
/* Eat leading whitespace */
|
||||
while (header_len < len && isblank((unsigned char)data[header_len]))
|
||||
header_len++;
|
||||
|
||||
*value = malloc(len - header_len + 1);
|
||||
if (*value == NULL)
|
||||
return -4;
|
||||
|
||||
strncpy(*value, data + header_len, len - header_len);
|
||||
(*value)[len - header_len] = '\0';
|
||||
|
||||
return len - header_len;
|
||||
}
|
||||
|
||||
/* If there is no data left after reading all the headers then we do not
|
||||
* have a complete HTTP request, there must be a blank line */
|
||||
if (data_len == 0)
|
||||
return -1;
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
static int
|
||||
next_header(const char **data, int *len)
|
||||
{
|
||||
int header_len;
|
||||
|
||||
/* perhaps we can optimize this to reuse the value of header_len, rather
|
||||
* than scanning twice.
|
||||
* Walk our data stream until the end of the header */
|
||||
while (*len > 2 && (*data)[0] != '\r' && (*data)[1] != '\n') {
|
||||
(*len)--;
|
||||
(*data)++;
|
||||
}
|
||||
|
||||
/* advanced past the <CR><LF> pair */
|
||||
*data += 2;
|
||||
*len -= 2;
|
||||
|
||||
/* Find the length of the next header */
|
||||
header_len = 0;
|
||||
while (*len > header_len + 1
|
||||
&& (*data)[header_len] != '\r'
|
||||
&& (*data)[header_len + 1] != '\n')
|
||||
header_len++;
|
||||
|
||||
return header_len;
|
||||
}
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011 and 2012, Dustin Lundquist <dustin@null-ptr.net>
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
#ifndef HTTP_H
|
||||
#define HTTP_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "protocol.h"
|
||||
|
||||
const protocol_t *const http_protocol;
|
||||
|
||||
#endif
|
||||
+7
-57
@@ -55,8 +55,6 @@
|
||||
#include "utils.h"
|
||||
#include "socks5.h"
|
||||
#include "acl.h"
|
||||
#include "http.h"
|
||||
#include "tls.h"
|
||||
#include "plugin.h"
|
||||
#include "local.h"
|
||||
#include "winsock.h"
|
||||
@@ -431,48 +429,17 @@ server_handshake(EV_P_ ev_io *w, buffer_t *buf)
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t abuf_len = abuf->len;
|
||||
int sni_detected = 0;
|
||||
int hostname_len = 0;
|
||||
|
||||
char *hostname;
|
||||
uint16_t dst_port = load16_be(abuf->data + abuf->len - 2);
|
||||
|
||||
if (atyp == SOCKS5_ATYP_IPV4 || atyp == SOCKS5_ATYP_IPV6) {
|
||||
if (dst_port == http_protocol->default_port)
|
||||
hostname_len = http_protocol->parse_packet(buf->data + 3 + abuf->len,
|
||||
buf->len - 3 - abuf->len, &hostname);
|
||||
else if (dst_port == tls_protocol->default_port)
|
||||
hostname_len = tls_protocol->parse_packet(buf->data + 3 + abuf->len,
|
||||
buf->len - 3 - abuf->len, &hostname);
|
||||
if (hostname_len == -1 && buf->len < SOCKET_BUF_SIZE && server->stage != STAGE_SNI) {
|
||||
if (server_handshake_reply(EV_A_ w, 0, &response) < 0)
|
||||
return -1;
|
||||
server->stage = STAGE_SNI;
|
||||
ev_timer_start(EV_A_ & server->delayed_connect_watcher);
|
||||
return -1;
|
||||
} else if (hostname_len > 0) {
|
||||
sni_detected = 1;
|
||||
if (acl || verbose) {
|
||||
hostname_len = hostname_len > MAX_HOSTNAME_LEN ? MAX_HOSTNAME_LEN : hostname_len;
|
||||
memcpy(host, hostname, hostname_len);
|
||||
host[hostname_len] = '\0';
|
||||
}
|
||||
ss_free(hostname);
|
||||
}
|
||||
}
|
||||
|
||||
if (server_handshake_reply(EV_A_ w, 0, &response) < 0)
|
||||
return -1;
|
||||
server->stage = STAGE_STREAM;
|
||||
|
||||
buf->len -= (3 + abuf_len);
|
||||
buf->len -= (3 + abuf->len);
|
||||
if (buf->len > 0) {
|
||||
memmove(buf->data, buf->data + 3 + abuf_len, buf->len);
|
||||
memmove(buf->data, buf->data + 3 + abuf->len, buf->len);
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
if (sni_detected || atyp == SOCKS5_ATYP_DOMAIN)
|
||||
if (atyp == SOCKS5_ATYP_DOMAIN)
|
||||
LOGI("connect to %s:%s", host, port);
|
||||
else if (atyp == SOCKS5_ATYP_IPV4)
|
||||
LOGI("connect to %s:%s", ip, port);
|
||||
@@ -492,7 +459,7 @@ server_handshake(EV_P_ ev_io *w, buffer_t *buf)
|
||||
int err;
|
||||
|
||||
int host_match = 0;
|
||||
if (sni_detected || atyp == SOCKS5_ATYP_DOMAIN)
|
||||
if (atyp == SOCKS5_ATYP_DOMAIN)
|
||||
host_match = acl_match_host(host);
|
||||
|
||||
if (host_match > 0)
|
||||
@@ -546,7 +513,7 @@ server_handshake(EV_P_ ev_io *w, buffer_t *buf)
|
||||
|
||||
if (bypass) {
|
||||
if (verbose) {
|
||||
if (sni_detected || atyp == SOCKS5_ATYP_DOMAIN)
|
||||
if (atyp == SOCKS5_ATYP_DOMAIN)
|
||||
LOGI("bypass %s:%s", host, port);
|
||||
else if (atyp == 1)
|
||||
LOGI("bypass %s:%s", ip, port);
|
||||
@@ -572,22 +539,6 @@ not_bypass:
|
||||
// Not bypass
|
||||
if (remote == NULL) {
|
||||
remote = create_remote(server->listener, NULL, 0);
|
||||
|
||||
if (sni_detected && acl
|
||||
#ifdef __ANDROID__
|
||||
&& is_remote_dns
|
||||
#endif
|
||||
) {
|
||||
// Reconstruct address buffer
|
||||
abuf->len = 0;
|
||||
abuf->data[abuf->len++] = 3;
|
||||
abuf->data[abuf->len++] = hostname_len;
|
||||
memcpy(abuf->data + abuf->len, host, hostname_len);
|
||||
abuf->len += hostname_len;
|
||||
dst_port = htons(dst_port);
|
||||
memcpy(abuf->data + abuf->len, &dst_port, 2);
|
||||
abuf->len += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (remote == NULL) {
|
||||
@@ -614,7 +565,7 @@ not_bypass:
|
||||
server->remote = remote;
|
||||
remote->server = server;
|
||||
|
||||
if (buf->len > 0 || sni_detected) {
|
||||
if (buf->len > 0) {
|
||||
return 0;
|
||||
} else {
|
||||
ev_timer_start(EV_A_ & server->delayed_connect_watcher);
|
||||
@@ -924,8 +875,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
|
||||
buf->len = 0;
|
||||
return;
|
||||
} else if (server->stage == STAGE_HANDSHAKE ||
|
||||
server->stage == STAGE_SNI) {
|
||||
} else if (server->stage == STAGE_HANDSHAKE) {
|
||||
int ret = server_handshake(EV_A_ w, buf);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Dustin Lundquist <dustin@null-ptr.net>
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
#ifndef PROTOCOL_H
|
||||
#define PROTOCOL_H
|
||||
|
||||
#define MAX_HOSTNAME_LEN 256
|
||||
|
||||
typedef struct protocol {
|
||||
const int default_port;
|
||||
int(*const parse_packet) (const char *, size_t, char **);
|
||||
} protocol_t;
|
||||
|
||||
#endif
|
||||
@@ -38,7 +38,6 @@
|
||||
|
||||
#include "crypto.h"
|
||||
#include "jconf.h"
|
||||
#include "resolv.h"
|
||||
#include "netutils.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
@@ -1,259 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011 and 2012, Dustin Lundquist <dustin@null-ptr.net>
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
/*
|
||||
* This is a minimal TLS implementation intended only to parse the server name
|
||||
* extension. This was created based primarily on Wireshark dissection of a
|
||||
* TLS handshake and RFC4366.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* malloc() */
|
||||
#include <string.h> /* strncpy() */
|
||||
#ifndef __MINGW32__
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#include "tls.h"
|
||||
#include "protocol.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define TLS_HEADER_LEN 5
|
||||
#define TLS_HANDSHAKE_CONTENT_TYPE 0x16
|
||||
#define TLS_HANDSHAKE_TYPE_CLIENT_HELLO 0x01
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
|
||||
#endif
|
||||
|
||||
extern int verbose;
|
||||
|
||||
static int parse_tls_header(const char *, size_t, char **);
|
||||
static int parse_extensions(const char *, size_t, char **);
|
||||
static int parse_server_name_extension(const char *, size_t, char **);
|
||||
|
||||
static const protocol_t tls_protocol_st = {
|
||||
.default_port = 443,
|
||||
.parse_packet = &parse_tls_header,
|
||||
};
|
||||
const protocol_t *const tls_protocol = &tls_protocol_st;
|
||||
|
||||
/* Parse a TLS packet for the Server Name Indication extension in the client
|
||||
* hello handshake, returning the first servername found (pointer to static
|
||||
* array)
|
||||
*
|
||||
* Returns:
|
||||
* >=0 - length of the hostname and updates *hostname
|
||||
* caller is responsible for freeing *hostname
|
||||
* -1 - Incomplete request
|
||||
* -2 - No Host header included in this request
|
||||
* -3 - Invalid hostname pointer
|
||||
* -4 - malloc failure
|
||||
* < -4 - Invalid TLS client hello
|
||||
*/
|
||||
static int
|
||||
parse_tls_header(const char *data, size_t data_len, char **hostname)
|
||||
{
|
||||
char tls_content_type;
|
||||
char tls_version_major;
|
||||
char tls_version_minor;
|
||||
size_t pos = TLS_HEADER_LEN;
|
||||
size_t len;
|
||||
|
||||
if (hostname == NULL)
|
||||
return -3;
|
||||
|
||||
/* Check that our TCP payload is at least large enough for a TLS header */
|
||||
if (data_len < TLS_HEADER_LEN)
|
||||
return -1;
|
||||
|
||||
/* SSL 2.0 compatible Client Hello
|
||||
*
|
||||
* High bit of first byte (length) and content type is Client Hello
|
||||
*
|
||||
* See RFC5246 Appendix E.2
|
||||
*/
|
||||
if (data[0] & 0x80 && data[2] == 1) {
|
||||
if (verbose)
|
||||
LOGI("Received SSL 2.0 Client Hello which can not support SNI.");
|
||||
return -2;
|
||||
}
|
||||
|
||||
tls_content_type = data[0];
|
||||
if (tls_content_type != TLS_HANDSHAKE_CONTENT_TYPE) {
|
||||
if (verbose)
|
||||
LOGI("Request did not begin with TLS handshake.");
|
||||
return -5;
|
||||
}
|
||||
|
||||
tls_version_major = data[1];
|
||||
tls_version_minor = data[2];
|
||||
if (tls_version_major < 3) {
|
||||
if (verbose)
|
||||
LOGI("Received SSL %d.%d handshake which can not support SNI.",
|
||||
tls_version_major, tls_version_minor);
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* TLS record length */
|
||||
len = ((unsigned char)data[3] << 8) +
|
||||
(unsigned char)data[4] + TLS_HEADER_LEN;
|
||||
data_len = MIN(data_len, len);
|
||||
|
||||
/* Check we received entire TLS record length */
|
||||
if (data_len < len)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Handshake
|
||||
*/
|
||||
if (pos + 1 > data_len) {
|
||||
return -5;
|
||||
}
|
||||
if (data[pos] != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
|
||||
if (verbose)
|
||||
LOGI("Not a client hello");
|
||||
|
||||
return -5;
|
||||
}
|
||||
|
||||
/* Skip past fixed length records:
|
||||
* 1 Handshake Type
|
||||
* 3 Length
|
||||
* 2 Version (again)
|
||||
* 32 Random
|
||||
* to Session ID Length
|
||||
*/
|
||||
pos += 38;
|
||||
|
||||
/* Session ID */
|
||||
if (pos + 1 > data_len)
|
||||
return -5;
|
||||
len = (unsigned char)data[pos];
|
||||
pos += 1 + len;
|
||||
|
||||
/* Cipher Suites */
|
||||
if (pos + 2 > data_len)
|
||||
return -5;
|
||||
len = ((unsigned char)data[pos] << 8) + (unsigned char)data[pos + 1];
|
||||
pos += 2 + len;
|
||||
|
||||
/* Compression Methods */
|
||||
if (pos + 1 > data_len)
|
||||
return -5;
|
||||
len = (unsigned char)data[pos];
|
||||
pos += 1 + len;
|
||||
|
||||
if (pos == data_len && tls_version_major == 3 && tls_version_minor == 0) {
|
||||
if (verbose)
|
||||
LOGI("Received SSL 3.0 handshake without extensions");
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Extensions */
|
||||
if (pos + 2 > data_len)
|
||||
return -5;
|
||||
len = ((unsigned char)data[pos] << 8) + (unsigned char)data[pos + 1];
|
||||
pos += 2;
|
||||
|
||||
if (pos + len > data_len)
|
||||
return -5;
|
||||
return parse_extensions(data + pos, len, hostname);
|
||||
}
|
||||
|
||||
static int
|
||||
parse_extensions(const char *data, size_t data_len, char **hostname)
|
||||
{
|
||||
size_t pos = 0;
|
||||
size_t len;
|
||||
|
||||
/* Parse each 4 bytes for the extension header */
|
||||
while (pos + 4 <= data_len) {
|
||||
/* Extension Length */
|
||||
len = ((unsigned char)data[pos + 2] << 8) +
|
||||
(unsigned char)data[pos + 3];
|
||||
|
||||
/* Check if it's a server name extension */
|
||||
if (data[pos] == 0x00 && data[pos + 1] == 0x00) {
|
||||
/* There can be only one extension of each type, so we break
|
||||
* our state and move p to beinnging of the extension here */
|
||||
if (pos + 4 + len > data_len)
|
||||
return -5;
|
||||
return parse_server_name_extension(data + pos + 4, len, hostname);
|
||||
}
|
||||
pos += 4 + len; /* Advance to the next extension header */
|
||||
}
|
||||
/* Check we ended where we expected to */
|
||||
if (pos != data_len)
|
||||
return -5;
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_server_name_extension(const char *data, size_t data_len,
|
||||
char **hostname)
|
||||
{
|
||||
size_t pos = 2; /* skip server name list length */
|
||||
size_t len;
|
||||
|
||||
while (pos + 3 < data_len) {
|
||||
len = ((unsigned char)data[pos + 1] << 8) +
|
||||
(unsigned char)data[pos + 2];
|
||||
|
||||
if (pos + 3 + len > data_len)
|
||||
return -5;
|
||||
|
||||
switch (data[pos]) { /* name type */
|
||||
case 0x00: /* host_name */
|
||||
*hostname = malloc(len + 1);
|
||||
if (*hostname == NULL) {
|
||||
ERROR("malloc() failure");
|
||||
return -4;
|
||||
}
|
||||
|
||||
strncpy(*hostname, data + pos + 3, len);
|
||||
|
||||
(*hostname)[len] = '\0';
|
||||
|
||||
return len;
|
||||
default:
|
||||
if (verbose)
|
||||
LOGI("Unknown server name extension name type: %d",
|
||||
data[pos]);
|
||||
}
|
||||
pos += 3 + len;
|
||||
}
|
||||
/* Check we ended where we expected to */
|
||||
if (pos != data_len)
|
||||
return -5;
|
||||
|
||||
return -2;
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011 and 2012, Dustin Lundquist <dustin@null-ptr.net>
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
#ifndef TLS_H
|
||||
#define TLS_H
|
||||
|
||||
#include "protocol.h"
|
||||
|
||||
const protocol_t *const tls_protocol;
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user