Browse Source
Add HTTP/SNI parser (#809)
Add HTTP/SNI parser (#809)
* WiP: add HTTP/SNI parser * WiP: replace hostname with HTTP/SNI header * WiP: add ACL * Fix white list * Replace free() with ss_free() * Refine sockaddr handling * Add HTTP/SNI support to redirpull/814/head
committed by
GitHub
33 changed files with 4146 additions and 255 deletions
Split View
Diff Options
-
21Makefile.in
-
1283aclocal.m4
-
0auto/config.rpath
-
3config.h.in
-
1572configure
-
12configure.ac
-
9doc/Makefile.in
-
18libcork/Makefile.am
-
27libcork/Makefile.in
-
9libev/Makefile.in
-
18libipset/Makefile.am
-
27libipset/Makefile.in
-
19libudns/Makefile.am
-
27libudns/Makefile.in
-
16src/Makefile.am
-
224src/Makefile.in
-
121src/acl.c
-
8src/acl.h
-
140src/http.c
-
34src/http.h
-
2src/jconf.c
-
222src/local.c
-
4src/local.h
-
26src/manager.c
-
34src/protocol.h
-
58src/redir.c
-
3src/redir.h
-
122src/rule.c
-
53src/rule.h
-
12src/server.c
-
1src/shadowsocks.h
-
243src/tls.c
-
33src/tls.h
1283
aclocal.m4
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
1572
configure
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,25 +1,8 @@ |
|||
# This file is part of libasyncns.
|
|||
#
|
|||
# Copyright 2005-2008 Lennart Poettering
|
|||
#
|
|||
# libasyncns is free software; you can redistribute it and/or modify
|
|||
# it under the terms of the GNU Lesser General Public License as
|
|||
# published by the Free Software Foundation, either version 2.1 of the
|
|||
# License, or (at your option) any later version.
|
|||
#
|
|||
# libasyncns is distributed in the hope that it will be useful, but
|
|||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|||
# Lesser General Public License for more details.
|
|||
#
|
|||
# You should have received a copy of the GNU Lesser General Public
|
|||
# License along with libasyncns. If not, see
|
|||
# <http://www.gnu.org/licenses/>.
|
|||
|
|||
SRCS = udns_dn.c udns_dntosp.c udns_parse.c udns_resolver.c udns_init.c \
|
|||
udns_misc.c udns_XtoX.c \
|
|||
udns_rr_a.c udns_rr_ptr.c udns_rr_mx.c udns_rr_txt.c udns_bl.c \
|
|||
udns_rr_srv.c udns_rr_naptr.c udns_codes.c udns_jran.c |
|||
|
|||
noinst_LTLIBRARIES=libudns.la |
|||
libudns_la_SOURCES= ${SRCS} |
|||
libudns_la_LDFLAGS= -static |
@ -0,0 +1,140 @@ |
|||
/* |
|||
* 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. |
|||
*/ |
|||
#include <stdio.h> |
|||
#include <stdlib.h> /* malloc() */ |
|||
#include <string.h> /* strncpy() */ |
|||
#include <strings.h> /* strncasecmp() */ |
|||
#include <ctype.h> /* isblank() */ |
|||
#include "http.h" |
|||
#include "protocol.h" |
|||
|
|||
#define SERVER_NAME_LEN 256 |
|||
|
|||
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; |
|||
|
|||
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 |
|||
* so we trim off port portion |
|||
*/ |
|||
for (i = result - 1; i >= 0; i--) |
|||
if ((*hostname)[i] == ':') { |
|||
(*hostname)[i] = '\0'; |
|||
result = 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(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; |
|||
} |
@ -0,0 +1,34 @@ |
|||
/* |
|||
* 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 |
@ -0,0 +1,34 @@ |
|||
/* |
|||
* 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 |
|||
|
|||
typedef struct protocol { |
|||
const int default_port; |
|||
int (*const parse_packet)(const char*, size_t, char **); |
|||
} protocol_t; |
|||
|
|||
#endif |
@ -0,0 +1,122 @@ |
|||
/* |
|||
* Copyright (c) 2011 and 2012, Dustin Lundquist <dustin@null-ptr.net> |
|||
* Copyright (c) 2011 Manuel Kasper <mk@neon1.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. |
|||
*/ |
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
#include <sys/queue.h> |
|||
#include <pcre.h> |
|||
|
|||
#include "rule.h" |
|||
#include "utils.h" |
|||
|
|||
static void free_rule(rule_t *); |
|||
|
|||
rule_t * |
|||
new_rule() { |
|||
rule_t *rule; |
|||
|
|||
rule = calloc(1, sizeof(rule_t)); |
|||
if (rule == NULL) { |
|||
ERROR("malloc"); |
|||
return NULL; |
|||
} |
|||
|
|||
return rule; |
|||
} |
|||
|
|||
int |
|||
accept_rule_arg(rule_t *rule, const char *arg) { |
|||
if (rule->pattern == NULL) { |
|||
rule->pattern = strdup(arg); |
|||
if (rule->pattern == NULL) { |
|||
ERROR("strdup failed"); |
|||
return -1; |
|||
} |
|||
} else { |
|||
LOGE("Unexpected table rule argument: %s", arg); |
|||
return -1; |
|||
} |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
void |
|||
add_rule(rule_head_t *rules, rule_t *rule) { |
|||
STAILQ_INSERT_TAIL(rules, rule, entries); |
|||
} |
|||
|
|||
int |
|||
init_rule(rule_t *rule) { |
|||
if (rule->pattern_re == NULL) { |
|||
const char *reerr; |
|||
int reerroffset; |
|||
|
|||
rule->pattern_re = |
|||
pcre_compile(rule->pattern, 0, &reerr, &reerroffset, NULL); |
|||
if (rule->pattern_re == NULL) { |
|||
LOGE("Regex compilation of \"%s\" failed: %s, offset %d", |
|||
rule->pattern, reerr, reerroffset); |
|||
return 0; |
|||
} |
|||
} |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
rule_t * |
|||
lookup_rule(const rule_head_t *head, const char *name, size_t name_len) { |
|||
rule_t *iter; |
|||
|
|||
if (name == NULL) { |
|||
name = ""; |
|||
name_len = 0; |
|||
} |
|||
|
|||
STAILQ_FOREACH(iter, head, entries) { |
|||
if (pcre_exec(iter->pattern_re, NULL, |
|||
name, name_len, 0, 0, NULL, 0) >= 0) |
|||
return iter; |
|||
} |
|||
|
|||
return NULL; |
|||
} |
|||
|
|||
void |
|||
remove_rule(rule_head_t *head, rule_t *rule) { |
|||
STAILQ_REMOVE(head, rule, rule, entries); |
|||
free_rule(rule); |
|||
} |
|||
|
|||
static void |
|||
free_rule(rule_t *rule) { |
|||
if (rule == NULL) |
|||
return; |
|||
|
|||
ss_free(rule->pattern); |
|||
if (rule->pattern_re != NULL) |
|||
pcre_free(rule->pattern_re); |
|||
ss_free(rule); |
|||
} |
@ -0,0 +1,53 @@ |
|||
/* |
|||
* Copyright (c) 2011 and 2012, Dustin Lundquist <dustin@null-ptr.net> |
|||
* Copyright (c) 2011 Manuel Kasper <mk@neon1.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 BACKEND_H |
|||
#define BACKEND_H |
|||
|
|||
#include <sys/queue.h> |
|||
#include <pcre.h> |
|||
|
|||
STAILQ_HEAD(rule_head, rule); |
|||
|
|||
typedef struct rule_head rule_head_t; |
|||
|
|||
typedef struct rule { |
|||
char *pattern; |
|||
|
|||
/* Runtime fields */ |
|||
pcre *pattern_re; |
|||
STAILQ_ENTRY(rule) entries; |
|||
} rule_t; |
|||
|
|||
void add_rule(rule_head_t *, rule_t *); |
|||
int init_rule(rule_t *); |
|||
rule_t *lookup_rule(const rule_head_t *, const char *, size_t); |
|||
void remove_rule(rule_head_t *, rule_t *); |
|||
rule_t *new_rule(); |
|||
int accept_rule_arg(rule_t *, const char *); |
|||
|
|||
|
|||
#endif |
@ -0,0 +1,243 @@ |
|||
/* |
|||
* 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. |
|||
*/ |
|||
#include <stdio.h> |
|||
#include <stdlib.h> /* malloc() */ |
|||
#include <string.h> /* strncpy() */ |
|||
#include <sys/socket.h> |
|||
|
|||
#include "tls.h" |
|||
#include "protocol.h" |
|||
#include "utils.h" |
|||
|
|||
#define SERVER_NAME_LEN 256 |
|||
#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 |
|||
|
|||
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) { |
|||
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) { |
|||
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) { |
|||
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) { |
|||
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) { |
|||
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: |
|||
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; |
|||
} |
@ -0,0 +1,33 @@ |
|||
/* |
|||
* 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 |
Write
Preview
Loading…
Cancel
Save