From 35a8aea05f0ae66b2f866ec524fa2087ac5451ab Mon Sep 17 00:00:00 2001 From: Dustin Lundquist Date: Mon, 14 Apr 2014 13:25:17 -0700 Subject: [PATCH 1/4] Add protocol specific data --- src/connection.c | 5 ++++- src/http.c | 4 ++-- src/listener.c | 2 ++ src/listener.h | 1 + src/protocol.h | 2 +- src/tls.c | 5 +++-- tests/http_test.c | 4 ++-- tests/tls_test.c | 6 +++--- 8 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/connection.c b/src/connection.c index 12771794..240444d1 100644 --- a/src/connection.c +++ b/src/connection.c @@ -337,7 +337,10 @@ parse_client_request(struct Connection *con) { ssize_t payload_len = buffer_coalesce(con->client.buffer, (const void **)&payload); char *hostname = NULL; - int result = con->listener->protocol->parse_packet(payload, payload_len, &hostname); + int result = con->listener->protocol->parse_packet( + con->listener->protocol_data, + payload, payload_len, + &hostname); if (result < 0) { char client[INET6_ADDRSTRLEN + 8]; diff --git a/src/http.c b/src/http.c index 36c7691f..5dd4c1f6 100644 --- a/src/http.c +++ b/src/http.c @@ -39,7 +39,7 @@ static const char http_503[] = "Connection: close\r\n\r\n" "Backend not available"; -static int parse_http_header(const char *, size_t, char **); +static int parse_http_header(void *, const char *, size_t, char **); static int get_header(const char *, const char *, int, char **); static int next_header(const char **, int *); @@ -66,7 +66,7 @@ const struct Protocol *const http_protocol = &http_protocol_st; * */ static int -parse_http_header(const char* data, size_t data_len, char **hostname) { +parse_http_header(void *unused __attribute__((unused)), const char* data, size_t data_len, char **hostname) { int result, i; if (hostname == NULL) diff --git a/src/listener.c b/src/listener.c index da74bbff..527ae56d 100644 --- a/src/listener.c +++ b/src/listener.c @@ -83,6 +83,7 @@ new_listener() { listener->fallback_address = NULL; listener->source_address = NULL; listener->protocol = tls_protocol; + listener->protocol_data = NULL; listener->access_log = NULL; listener->log_bad_requests = 0; @@ -396,6 +397,7 @@ free_listener(struct Listener *listener) { free(listener->address); free(listener->fallback_address); free(listener->source_address); + free(listener->protocol_data); free(listener->table_name); free_logger(listener->access_log); free(listener); diff --git a/src/listener.h b/src/listener.h index 026b035d..51508f98 100644 --- a/src/listener.h +++ b/src/listener.h @@ -37,6 +37,7 @@ struct Listener { /* Configuration fields */ struct Address *address, *fallback_address, *source_address; const struct Protocol *protocol; + void *protocol_data; char *table_name; struct Logger *access_log; int log_bad_requests; diff --git a/src/protocol.h b/src/protocol.h index 8340b8f5..168565d6 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -29,7 +29,7 @@ struct Protocol { const char *const name; const int default_port; - int (*const parse_packet)(const char*, size_t, char **); + int (*const parse_packet)(void *, const char*, size_t, char **); const char *const abort_message; const size_t abort_message_len; }; diff --git a/src/tls.c b/src/tls.c index 3d29c43e..5e660c9e 100644 --- a/src/tls.c +++ b/src/tls.c @@ -52,7 +52,7 @@ static const char tls_alert[] = { 0x02, 0x28, /* Fatal, handshake failure */ }; -static int parse_tls_header(const char *, size_t, char **); +static int parse_tls_header(void *, 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 **); @@ -80,7 +80,8 @@ const struct Protocol *const tls_protocol = &tls_protocol_st; * < -4 - Invalid TLS client hello */ static int -parse_tls_header(const char *data, size_t data_len, char **hostname) { +parse_tls_header(void *unused, const char *data, size_t data_len, char **hostname) { + char tls_content_type; char tls_version_major; char tls_version_minor; diff --git a/tests/http_test.c b/tests/http_test.c index d1cfdcde..6af52141 100644 --- a/tests/http_test.c +++ b/tests/http_test.c @@ -48,7 +48,7 @@ int main() { for (i = 0; i < sizeof(good) / sizeof(const char *); i++) { hostname = NULL; - result = http_protocol->parse_packet(good[i], strlen(good[i]), &hostname); + result = http_protocol->parse_packet(NULL, good[i], strlen(good[i]), &hostname); assert(result == 9); @@ -62,7 +62,7 @@ int main() { for (i = 0; i < sizeof(bad) / sizeof(const char *); i++) { hostname = NULL; - result = http_protocol->parse_packet(bad[i], strlen(bad[i]), &hostname); + result = http_protocol->parse_packet(NULL, bad[i], strlen(bad[i]), &hostname); assert(result < 0); diff --git a/tests/tls_test.c b/tests/tls_test.c index c327496d..0f0bc7a4 100644 --- a/tests/tls_test.c +++ b/tests/tls_test.c @@ -317,7 +317,7 @@ int main() { for (i = 0; i < sizeof(good) / sizeof(struct test_packet); i++) { hostname = NULL; - result = tls_protocol->parse_packet(good[i].packet, good[i].len, &hostname); + result = tls_protocol->parse_packet(NULL, good[i].packet, good[i].len, &hostname); assert(result == 9); @@ -328,13 +328,13 @@ int main() { free(hostname); } - result = tls_protocol->parse_packet(good[0].packet, good[0].len, NULL); + result = tls_protocol->parse_packet(NULL, good[0].packet, good[0].len, NULL); assert(result == -3); for (i = 0; i < sizeof(bad) / sizeof(struct test_packet); i++) { hostname = NULL; - result = tls_protocol->parse_packet(bad[i].packet, bad[i].len, &hostname); + result = tls_protocol->parse_packet(NULL, bad[i].packet, bad[i].len, &hostname); // parse failure or not "localhost" assert(result < 0 || From 377276f91fffdde3e615325b1913b5e3c6ff3fd5 Mon Sep 17 00:00:00 2001 From: Dustin Lundquist Date: Thu, 27 Feb 2014 22:19:23 -0800 Subject: [PATCH 2/4] Rework Nikos Mavrogiannopoulos's ALPN support Use protocol data functionality to hold configure ALPN protocols. Since the complexity increased and there wasn't a clear use case, support only a single TLS extension at a time per listener: TLS or ALPN. Complex configurations involving both ALPN and SNI can be accomplished by using configuring SNIProxy to proxy to another of its own listeners over a UNIX socket to examine the other TLS extension. Use an additional protocol argument toggle between SNI and ALPN TLS extensions. --- sniproxy.conf | 9 ++- src/listener.c | 52 +++++++++--- src/tls.c | 183 +++++++++++++++++++++++++++++++++++++----- src/tls.h | 11 +++ tests/tls_test.c | 202 +++++++++++++++++++++++++++++++++++++++++------ 5 files changed, 404 insertions(+), 53 deletions(-) diff --git a/sniproxy.conf b/sniproxy.conf index 2c1fafc1..37090e98 100644 --- a/sniproxy.conf +++ b/sniproxy.conf @@ -59,7 +59,8 @@ listen [2001:0db8::10]:80 { } listen unix:/var/run/proxy.sock { - protocol http + protocol tls alpn + table alpn_protocol_hosts # this will use default table } @@ -102,3 +103,9 @@ table { example.com 192.0.2.10 example.net 192.0.2.20 } + +table alpn_protocol_hosts { + http/1.1 192.0.2.31 + http/2.0 192.0.2.32 + spdy/3 192.0.2.33 +} diff --git a/src/listener.c b/src/listener.c index 527ae56d..11c60b24 100644 --- a/src/listener.c +++ b/src/listener.c @@ -82,7 +82,7 @@ new_listener() { listener->address = NULL; listener->fallback_address = NULL; listener->source_address = NULL; - listener->protocol = tls_protocol; + listener->protocol = NULL; listener->protocol_data = NULL; listener->access_log = NULL; listener->log_bad_requests = 0; @@ -131,15 +131,33 @@ accept_listener_table_name(struct Listener *listener, char *table_name) { int accept_listener_protocol(struct Listener *listener, char *protocol) { - if (strncasecmp(protocol, http_protocol->name, strlen(protocol)) == 0) + size_t protocol_len = strlen(protocol); + + if (listener->protocol == NULL + && strncasecmp(protocol, http_protocol->name, protocol_len) == 0) { listener->protocol = http_protocol; - else + + return 1; + } + + if (listener->protocol == NULL + && strncasecmp(protocol, tls_protocol->name, protocol_len) == 0) { listener->protocol = tls_protocol; + listener->protocol_data = new_tls_data(); - if (address_port(listener->address) == 0) - address_set_port(listener->address, listener->protocol->default_port); + return 1; + } - return 1; + if (listener->protocol == tls_protocol + && strncasecmp(protocol, "alpn", protocol_len) == 0) { + listener->protocol_data = + tls_data_use_alpn(listener->protocol_data, 1); + + return 1; + } + + fprintf(stderr, "unexpected additional argument on listener protocol: %s", protocol); + return -1; } int @@ -262,8 +280,14 @@ valid_listener(const struct Listener *listener) { int init_listener(struct Listener *listener, const struct Table_head *tables) { - int sockfd; - int on = 1; + /* Default protocol to TLS if not set */ + if (listener->protocol == NULL) { + listener->protocol = tls_protocol; + listener->protocol_data = new_tls_data(); + } + + if (address_port(listener->address) == 0) + address_set_port(listener->address, listener->protocol->default_port); listener->table = table_lookup(tables, listener->table_name); if (listener->table == NULL) { @@ -272,6 +296,15 @@ init_listener(struct Listener *listener, const struct Table_head *tables) { } init_table(listener->table); + if (listener->protocol == tls_protocol + && tls_data_alpn(listener->protocol_data)) { + struct Backend *iter; + STAILQ_FOREACH(iter, &listener->table->backends, entries) { + listener->protocol_data = + tls_data_append_alpn_protocol(listener->protocol_data, iter->name, strlen(iter->name)); + } + } + /* If no port was specified on the fallback address, inherit the address * from the listening address */ if (listener->fallback_address && @@ -279,13 +312,14 @@ init_listener(struct Listener *listener, const struct Table_head *tables) { address_set_port(listener->fallback_address, address_port(listener->address)); - sockfd = socket(address_sa(listener->address)->sa_family, SOCK_STREAM, 0); + int sockfd = socket(address_sa(listener->address)->sa_family, SOCK_STREAM, 0); if (sockfd < 0) { err("socket failed: %s", strerror(errno)); return -2; } /* set SO_REUSEADDR on server socket to facilitate restart */ + int on = 1; setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (bind(sockfd, address_sa(listener->address), diff --git a/src/tls.c b/src/tls.c index 5e660c9e..2133254b 100644 --- a/src/tls.c +++ b/src/tls.c @@ -45,6 +45,22 @@ #define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) #endif + +struct TLSProtocol { + int use_alpn; + size_t alpn_protocol_count; + char alpn_protocols[]; +}; + + +static int parse_tls_header(struct TLSProtocol *, const char *, size_t, char **); +static int parse_extensions(const struct TLSProtocol *, const char *, size_t, char **); +static int parse_server_name_extension(const char *, size_t, char **); +static int parse_alpn_extension(const struct TLSProtocol *, const char *, size_t , char **); +static size_t tls_data_size(const struct TLSProtocol *); +static int is_alpn_proto_known(const struct TLSProtocol *, const char *, size_t); + + static const char tls_alert[] = { 0x15, /* TLS Alert */ 0x03, 0x01, /* TLS version */ @@ -52,14 +68,10 @@ static const char tls_alert[] = { 0x02, 0x28, /* Fatal, handshake failure */ }; -static int parse_tls_header(void *, 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 struct Protocol tls_protocol_st = { .name = "tls", .default_port = 443, - .parse_packet = &parse_tls_header, + .parse_packet = (int (*)(void *, const char *, size_t, char **))&parse_tls_header, .abort_message = tls_alert, .abort_message_len = sizeof(tls_alert) }; @@ -80,8 +92,7 @@ const struct Protocol *const tls_protocol = &tls_protocol_st; * < -4 - Invalid TLS client hello */ static int -parse_tls_header(void *unused, const char *data, size_t data_len, char **hostname) { - +parse_tls_header(struct TLSProtocol *tls_data, const char *data, size_t data_len, char **hostname) { char tls_content_type; char tls_version_major; char tls_version_minor; @@ -171,30 +182,42 @@ parse_tls_header(void *unused, const char *data, size_t data_len, char **hostnam if (pos + len > data_len) return -5; - return parse_extensions(data + pos, len, hostname); + return parse_extensions(tls_data, data + pos, len, hostname); } static int -parse_extensions(const char *data, size_t data_len, char **hostname) { +parse_extensions(const struct TLSProtocol *tls_data, const char *data, size_t data_len, char **hostname) { size_t pos = 0; size_t len; + if (tls_data == NULL) + return -3; + /* 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]; + if (pos + 4 + len > data_len) + return -5; + + size_t extension_type = ((unsigned char)data[pos] << 8) + + (unsigned char)data[pos + 1]; + + /* 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; + /* There can be only one extension of each type, so we break + our state and move pos to beginning of the extension here */ + if (extension_type == 0x00 && tls_data->use_alpn == 0) /* Server Name */ return parse_server_name_extension(data + pos + 4, len, hostname); - } + + if (extension_type == 0x10 && tls_data->use_alpn == 1) /* ALPN */ + return parse_alpn_extension(tls_data, 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; @@ -207,6 +230,7 @@ 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; + char *result = NULL; while (pos + 3 < data_len) { len = ((unsigned char)data[pos + 1] << 8) + @@ -217,16 +241,17 @@ parse_server_name_extension(const char *data, size_t data_len, switch (data[pos]) { /* name type */ case 0x00: /* host_name */ - *hostname = malloc(len + 1); - if (*hostname == NULL) { + result = malloc(len + 1); + if (result == NULL) { err("malloc() failure"); return -4; } - strncpy(*hostname, data + pos + 3, len); + strncpy(result, data + pos + 3, len); - (*hostname)[len] = '\0'; + result[len] = '\0'; + *hostname = result; return len; default: debug("Unknown server name extension name type: %d", @@ -240,3 +265,123 @@ parse_server_name_extension(const char *data, size_t data_len, return -2; } + +static int +parse_alpn_extension(const struct TLSProtocol *tls_data, const char *data, size_t data_len, char **hostname) { + size_t pos = 2; + size_t len; + char *result = NULL; + + while (pos + 1 < data_len) { + len = (unsigned char)data[pos]; + + if (pos + 1 + len > data_len) + return -5; + + if (len > 0 && is_alpn_proto_known(tls_data, data + pos + 1, len)) { + result = malloc(len + 1); + if (result == NULL) { + err("malloc() failure"); + return -4; + } + + memcpy(result, data + pos + 1, len); + result[len] = '\0'; + + *hostname = result; + return len; + } else if (len > 0) { + debug("Unknown ALPN name: %.*s", (int)len, data + pos + 2); + } + pos += 1 + len; + } + /* Check we ended where we expected to */ + if (pos != data_len) + return -5; + + return -2; +} + +static size_t +tls_data_size(const struct TLSProtocol *tls_data) { + size_t size = 0; + + + for (size_t i = 0; i < tls_data->alpn_protocol_count; i++) { + size_t alpn_protocol_len = (unsigned char)tls_data->alpn_protocols[size++]; + size += alpn_protocol_len; + } + + return sizeof(struct TLSProtocol) + size; +} + +struct TLSProtocol * +new_tls_data() { + struct TLSProtocol *tls_data = malloc(sizeof(struct TLSProtocol)); + if (tls_data != NULL) { + tls_data->use_alpn = 0; + tls_data->alpn_protocol_count = 0; + } + + return tls_data; +} + +struct TLSProtocol * +tls_data_append_alpn_protocol(struct TLSProtocol *old_tls_data, const char *name, size_t name_len) { + if (name_len > 255) { + err("%s: ALPN protocol too long (%ld bytes), skipping", __func__, name_len); + return old_tls_data; + } + + if (is_alpn_proto_known(old_tls_data, name, name_len)) { + warn("%s: duplicate ALPN protocol: %.*s", __func__, (int)name_len, name); + return old_tls_data; + } + + size_t old_size = tls_data_size(old_tls_data); + size_t new_size = old_size + name_len + 1; + + struct TLSProtocol *new_tls_data = realloc(old_tls_data, new_size); + if (new_tls_data == NULL) { + err("%s: malloc", __func__); + return old_tls_data; + } + + size_t pos = 0; + for (size_t i = 0; i < new_tls_data->alpn_protocol_count; i++) { + size_t alpn_protocol_len = (unsigned char)new_tls_data->alpn_protocols[pos]; + pos += alpn_protocol_len + 1; + } + + new_tls_data->alpn_protocols[pos++] = name_len; + memcpy(new_tls_data->alpn_protocols + pos, name, name_len); + new_tls_data->alpn_protocol_count++; + + return new_tls_data; +} + +struct TLSProtocol * +tls_data_use_alpn(struct TLSProtocol *tls_data, int use_alpn) { + tls_data->use_alpn = use_alpn; + + return tls_data; +} + +int +tls_data_alpn(const struct TLSProtocol *tls_data) { + return tls_data->use_alpn; +} + +static int +is_alpn_proto_known(const struct TLSProtocol *tls_data, const char* name, size_t name_len) { + size_t pos = 0; + for (size_t i = 0; i < tls_data->alpn_protocol_count; i++) { + size_t alpn_protocol_len = (unsigned char)tls_data->alpn_protocols[pos++]; + if (name_len == alpn_protocol_len + && strncmp(tls_data->alpn_protocols + pos, name, name_len)) + return 1; + + pos += alpn_protocol_len; + } + return 0; +} diff --git a/src/tls.h b/src/tls.h index 9b3b1c4d..1f621cae 100644 --- a/src/tls.h +++ b/src/tls.h @@ -30,4 +30,15 @@ const struct Protocol *const tls_protocol; +struct TLSProtocol; + +struct TLSProtocol *new_tls_data(); +/** + * Returns a new TLSProtocol structure pointer with the specified protocol added + * frees the provided TLSProtocol structure + */ +struct TLSProtocol *tls_data_append_alpn_protocol(struct TLSProtocol *, const char *, size_t); +struct TLSProtocol *tls_data_use_alpn(struct TLSProtocol *, int); +int tls_data_alpn(const struct TLSProtocol *); + #endif diff --git a/tests/tls_test.c b/tests/tls_test.c index 0f0bc7a4..263203b1 100644 --- a/tests/tls_test.c +++ b/tests/tls_test.c @@ -4,11 +4,17 @@ #include #include "tls.h" -struct test_packet { + +struct Test { const char *packet; - int len; + int packet_len; + struct TLSProtocol **tls_data_ptr; + const char *expected_name; }; +struct TLSProtocol *tls_sni_data; +struct TLSProtocol *tls_alpn_data; + const unsigned char good_data_1[] = { // TLS record 0x16, // Content Type: Handshake @@ -163,6 +169,134 @@ const unsigned char good_data_4[] = { 0x00, 0x00, // Length }; +const unsigned char alpn_good_data_1[] = { + // TLS record + 0x16, // Content Type: Handshake + 0x03, 0x00, // Version: SSL 3.0 + 0x01, 0x16, // Length + // Handshake + 0x01, // Handshake Type: Client Hello + 0x00, 0x01, 0x12, // Length + 0x03, 0x03, // Version: TLS 1.2 + // Random + 0x53, 0x03, 0x59, 0x03, 0xa8, 0xb2, 0xa9, 0x36, + 0x4c, 0x2d, 0x04, 0x72, 0x4f, 0xea, 0x98, 0xd5, + 0xb5, 0xbb, 0xea, 0x07, 0x4f, 0x00, 0x83, 0x1c, + 0xfa, 0xa0, 0x01, 0xcc, 0x7d, 0x2f, 0x4f, 0x6f, + 0x00, // Session ID Length + 0x00, 0x84, // Cipher Suites Length + 0xc0, 0x2b, + 0xc0, 0x2c, + 0xc0, 0x86, + 0xc0, 0x87, + 0xc0, 0x09, + 0xc0, 0x23, + 0xc0, 0x0a, + 0xc0, 0x24, + 0xc0, 0x72, + 0xc0, 0x73, + 0xc0, 0x08, + 0xc0, 0x07, + 0xc0, 0x2f, + 0xc0, 0x30, + 0xc0, 0x8a, + 0xc0, 0x8b, + 0xc0, 0x13, + 0xc0, 0x27, + 0xc0, 0x14, + 0xc0, 0x28, + 0xc0, 0x76, + 0xc0, 0x77, + 0xc0, 0x12, + 0xc0, 0x11, + 0x00, 0x9c, + 0x00, 0x9d, + 0xc0, 0x7a, + 0xc0, 0x7b, + 0x00, 0x2f, + 0x00, 0x3c, + 0x00, 0x35, + 0x00, 0x3d, + 0x00, 0x41, + 0x00, 0xba, + 0x00, 0x84, + 0x00, 0xc0, + 0x00, 0x0a, + 0x00, 0x05, + 0x00, 0x04, + 0x00, 0x9e, + 0x00, 0x9f, + 0xc0, 0x7c, + 0xc0, 0x7d, + 0x00, 0x33, + 0x00, 0x67, + 0x00, 0x39, + 0x00, 0x6b, + 0x00, 0x45, + 0x00, 0xbe, + 0x00, 0x88, + 0x00, 0xc4, + 0x00, 0x16, + 0x00, 0xa2, + 0x00, 0xa3, + 0xc0, 0x80, + 0xc0, 0x81, + 0x00, 0x32, + 0x00, 0x40, + 0x00, 0x38, + 0x00, 0x6a, + 0x00, 0x44, + 0x00, 0xbd, + 0x00, 0x87, + 0x00, 0xc3, + 0x00, 0x13, + 0x00, 0x66, + 0x01, // Compression Methods + 0x00, // NULL + 0x00, 0x65, // Extensions Length + // Extension + 0x00, 0x05, + 0x00, 0x05, + 0x01, 0x00, 0x00, 0x00, 0x00, + // Extension + 0x00, 0x00, // Extension Type: Server Name + 0x00, 0x0e, // Length + 0x00, 0x0c, // Server Name Indication Length + 0x00, // Server Name Type: host_name + 0x00, 0x09, // Length + // "localhost" + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, + // Extension + 0xff, 0x01, + 0x00, 0x01, + 0x00, + // Extension + 0x00, 0x23, + 0x00, 0x00, + // Extension + 0x00, 0x0a, + 0x00, 0x08, + 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, + // Extension + 0x00, 0x0b, + 0x00, 0x02, + 0x01, 0x00, + // Extension + 0x00, 0x0d, + 0x00, 0x1c, + 0x00, 0x1a, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, + 0x05, 0x01, 0x05, 0x03, 0x06, 0x01, 0x06, 0x03, + 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x02, 0x03, + // Extension + 0x00, 0x10, // Extension Type: ALPN + 0x00, 0x0b, + 0x00, 0x09, + 0x08, // Length + // "http/2.0" + 0x68, 0x74, 0x74, 0x70, 0x2f, 0x32, 0x2e, 0x30 +}; + const unsigned char ssl30_request[] = { // TLS record 0x16, // Content Type: Handshake @@ -295,46 +429,63 @@ const unsigned char bad_data_4[] = { 0x00, 0x01, // Length 0x01 // Mode: Peer allows to send requests }; -static struct test_packet good[] = { - { (char *)good_data_1, sizeof(good_data_1) }, - { (char *)good_data_2, sizeof(good_data_2) }, - { (char *)good_data_3, sizeof(good_data_3) }, - { (char *)good_data_4, sizeof(good_data_4) } + +static struct Test good[] = { + { (char *)good_data_1, sizeof(good_data_1), &tls_sni_data, "localhost" }, + { (char *)good_data_2, sizeof(good_data_2), &tls_sni_data, "localhost" }, + { (char *)good_data_3, sizeof(good_data_3), &tls_sni_data, "localhost" }, + { (char *)good_data_4, sizeof(good_data_4), &tls_sni_data, "localhost" }, + { (char *)alpn_good_data_1, sizeof(alpn_good_data_1), &tls_alpn_data, "http/2.0" } }; -static struct test_packet bad[] = { - { (char *)ssl30_request, sizeof(ssl30_request) }, - { (char *)bad_data_1, sizeof(bad_data_1) }, - { (char *)bad_data_2, sizeof(bad_data_2) }, - { (char *)bad_data_3, sizeof(bad_data_3) } +static struct Test bad[] = { + { (char *)ssl30_request, sizeof(ssl30_request), NULL }, + { (char *)bad_data_1, sizeof(bad_data_1), NULL }, + { (char *)bad_data_2, sizeof(bad_data_2), NULL }, + { (char *)bad_data_3, sizeof(bad_data_3), NULL } }; int main() { - unsigned int i; - int result; - char *hostname; + tls_sni_data = new_tls_data(); + assert(tls_sni_data != NULL); + tls_alpn_data = new_tls_data(); + assert(tls_alpn_data != NULL); + tls_alpn_data = tls_data_append_alpn_protocol(tls_alpn_data, "http/1.1", 8); + assert(tls_alpn_data != NULL); + tls_alpn_data = tls_data_append_alpn_protocol(tls_alpn_data, "http/2.0", 8); + assert(tls_alpn_data != NULL); + tls_alpn_data = tls_data_append_alpn_protocol(tls_alpn_data, "spdy/3", 6); + assert(tls_alpn_data != NULL); + tls_alpn_data = tls_data_use_alpn(tls_alpn_data, 1); - for (i = 0; i < sizeof(good) / sizeof(struct test_packet); i++) { - hostname = NULL; + for (struct Test *test = good; test < good + sizeof(good) / sizeof(struct Test); test++) { + char *hostname = NULL; - result = tls_protocol->parse_packet(NULL, good[i].packet, good[i].len, &hostname); + int result = tls_protocol->parse_packet(*test->tls_data_ptr, test->packet, test->packet_len, &hostname); - assert(result == 9); + assert(result == strlen(test->expected_name)); assert(NULL != hostname); - assert(0 == strcmp("localhost", hostname)); + if (strcmp(test->expected_name, hostname) != 0) { + fprintf(stderr, "test received \"%s\", expected \"%s\"\n", hostname, test->expected_name); + assert(0); + } free(hostname); } - result = tls_protocol->parse_packet(NULL, good[0].packet, good[0].len, NULL); + int result = tls_protocol->parse_packet(tls_sni_data, good[0].packet, good[0].packet_len, NULL); + assert(result == -3); + + char *hostname = NULL; + result = tls_protocol->parse_packet(NULL, good[0].packet, good[0].packet_len, &hostname); assert(result == -3); - for (i = 0; i < sizeof(bad) / sizeof(struct test_packet); i++) { - hostname = NULL; + for (struct Test *test = bad; test < bad + sizeof(bad) / sizeof(struct Test); test++) { + char *hostname = NULL; - result = tls_protocol->parse_packet(NULL, bad[i].packet, bad[i].len, &hostname); + int result = tls_protocol->parse_packet(tls_sni_data, test->packet, test->packet_len, &hostname); // parse failure or not "localhost" assert(result < 0 || @@ -344,6 +495,9 @@ int main() { free(hostname); } + free(tls_sni_data); + free(tls_alpn_data); + return 0; } From 9e595f05fc34e4c818e5f95cb38eeaf94c2315c2 Mon Sep 17 00:00:00 2001 From: Dustin Lundquist Date: Thu, 22 May 2014 09:03:01 -0700 Subject: [PATCH 3/4] Remove ALPN from TODO --- TODO | 1 - 1 file changed, 1 deletion(-) diff --git a/TODO b/TODO index 05fc96ad..858aeb06 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,3 @@ -* ALPN support * Reimplement configuration reloading * Improved table backend lookup, currently this is a linear search ** Considering splitting hostname at label boundaries and search backwards from TLD From 4aaf2ba085e0d22d93abc9228435571dfb82db04 Mon Sep 17 00:00:00 2001 From: Dustin Lundquist Date: Sun, 25 May 2014 12:37:17 -0700 Subject: [PATCH 4/4] Correct comments in example configuration --- sniproxy.conf | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/sniproxy.conf b/sniproxy.conf index 37090e98..93b07014 100644 --- a/sniproxy.conf +++ b/sniproxy.conf @@ -61,16 +61,11 @@ listen [2001:0db8::10]:80 { listen unix:/var/run/proxy.sock { protocol tls alpn table alpn_protocol_hosts - # this will use default table } # named tables are defined with the table directive table http_hosts { - example.com 192.0.2.10:8001 - example.net 192.0.2.10:8002 - example.org 192.0.2.10:8003 - -# Each table entry is composed of three parts: +# Each table entry is composed of two parts: # # pattern: # valid Perl-compatible Regular Expression that matches the @@ -86,13 +81,16 @@ table http_hosts { # pattern target #.*\.itunes\.apple\.com$ *:443 #.* 127.0.0.1:4443 + example.com 192.0.2.10:8001 + example.net 192.0.2.10:8002 + example.org 192.0.2.10:8003 } # named tables are defined with the table directive table https_hosts { # When proxying to local sockets you should use different tables since the - # local socket server most likely will not autodetect which protocol is - # being used + # local socket server most likely will not detect which protocol is being + # used example.org unix:/var/run/server.sock }