]>
Commit | Line | Data |
---|---|---|
a2bcb413 MF |
1 | commit 0022167d80725513d95b38aaebc90086fc0b6938 (tag: refs/tags/M-staged-PR331, refs/remotes/origin/v4) |
2 | Author: Christos Tsantilas <christos@chtsanti.net> | |
3 | Date: 2018-11-14 15:17:06 +0000 | |
4 | ||
5 | The %>handshake logformat code (#331) | |
6 | ||
7 | Logging client "handshake" bytes is useful in at least two contexts: | |
8 | ||
9 | * Runtime traffic bypass and bumping/splicing decisions. Identifying | |
10 | popular clients like Skype for Business (that uses a TLS handshake but | |
11 | then may not speak TLS) is critical for handling their traffic | |
12 | correctly. Squid does not have enough ACLs to interrogate most TLS | |
13 | handshake aspects. Adding more ACLs may still be a good idea, but | |
14 | initial sketches for SfB handshakes showed rather complex | |
15 | ACLs/configurations, _and_ no reasonable ACLs would be able to handle | |
16 | non-TLS handshakes. An external ACL receiving the handshake is in a | |
17 | much better position to analyze/fingerprint it according to custom | |
18 | admin needs. | |
19 | ||
20 | * A logged handshake can be used to analyze new/unusual traffic or even | |
21 | trigger security-related alarms. | |
22 | ||
23 | The current support is limited to cases where Squid was saving handshake | |
24 | for other reasons. With enough demand, this initial support can be | |
25 | extended to all protocols and port configurations. | |
26 | ||
27 | This is a Measurement Factory project. | |
28 | ||
29 | diff --git a/src/cf.data.pre b/src/cf.data.pre | |
30 | index fa8af56..a8ca587 100644 | |
31 | --- a/src/cf.data.pre | |
32 | +++ b/src/cf.data.pre | |
33 | @@ -4394,6 +4394,37 @@ DOC_START | |
34 | <qos Server connection TOS/DSCP value set by Squid | |
35 | <nfmark Server connection netfilter mark set by Squid | |
36 | ||
37 | + >handshake Raw client handshake | |
38 | + Initial client bytes received by Squid on a newly | |
39 | + accepted TCP connection or inside a just established | |
40 | + CONNECT tunnel. Squid stops accumulating handshake | |
41 | + bytes as soon as the handshake parser succeeds or | |
42 | + fails (determining whether the client is using the | |
43 | + expected protocol). | |
44 | + | |
45 | + For HTTP clients, the handshake is the request line. | |
46 | + For TLS clients, the handshake consists of all TLS | |
47 | + records up to and including the TLS record that | |
48 | + contains the last byte of the first ClientHello | |
49 | + message. For clients using an unsupported protocol, | |
50 | + this field contains the bytes received by Squid at the | |
51 | + time of the handshake parsing failure. | |
52 | + | |
53 | + See the on_unsupported_protocol directive for more | |
54 | + information on Squid handshake traffic expectations. | |
55 | + | |
56 | + Current support is limited to these contexts: | |
57 | + - http_port connections, but only when the | |
58 | + on_unsupported_protocol directive is in use. | |
59 | + - https_port connections (and CONNECT tunnels) that | |
60 | + are subject to the ssl_bump peek or stare action. | |
61 | + | |
62 | + To protect binary handshake data, this field is always | |
63 | + base64-encoded (RFC 4648 Section 4). If logformat | |
64 | + field encoding is configured, that encoding is applied | |
65 | + on top of base64. Otherwise, the computed base64 value | |
66 | + is recorded as is. | |
67 | + | |
68 | Time related format codes: | |
69 | ||
70 | ts Seconds since epoch | |
71 | diff --git a/src/format/ByteCode.h b/src/format/ByteCode.h | |
72 | index ad230bb..a6f8fd9 100644 | |
73 | --- a/src/format/ByteCode.h | |
74 | +++ b/src/format/ByteCode.h | |
75 | @@ -46,6 +46,8 @@ typedef enum { | |
76 | LFT_CLIENT_LOCAL_TOS, | |
77 | LFT_CLIENT_LOCAL_NFMARK, | |
78 | ||
79 | + LFT_CLIENT_HANDSHAKE, | |
80 | + | |
81 | /* client connection local squid.conf details */ | |
82 | LFT_LOCAL_LISTENING_IP, | |
83 | LFT_LOCAL_LISTENING_PORT, | |
84 | diff --git a/src/format/Format.cc b/src/format/Format.cc | |
85 | index c1e19b4..8fd6720 100644 | |
86 | --- a/src/format/Format.cc | |
87 | +++ b/src/format/Format.cc | |
88 | @@ -8,6 +8,7 @@ | |
89 | ||
90 | #include "squid.h" | |
91 | #include "AccessLogEntry.h" | |
92 | +#include "base64.h" | |
93 | #include "client_side.h" | |
94 | #include "comm/Connection.h" | |
95 | #include "err_detail_type.h" | |
96 | @@ -547,6 +548,24 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS | |
97 | } | |
98 | break; | |
99 | ||
100 | + case LFT_CLIENT_HANDSHAKE: | |
101 | + if (al->request && al->request->clientConnectionManager.valid()) { | |
102 | + const auto &handshake = al->request->clientConnectionManager->preservedClientData; | |
103 | + if (const auto rawLength = handshake.length()) { | |
104 | + // add 1 byte to optimize the c_str() conversion below | |
105 | + char *buf = sb.rawAppendStart(base64_encode_len(rawLength) + 1); | |
106 | + | |
107 | + struct base64_encode_ctx ctx; | |
108 | + base64_encode_init(&ctx); | |
109 | + auto encLength = base64_encode_update(&ctx, buf, rawLength, reinterpret_cast<const uint8_t*>(handshake.rawContent())); | |
110 | + encLength += base64_encode_final(&ctx, buf + encLength); | |
111 | + | |
112 | + sb.rawAppendFinish(buf, encLength); | |
113 | + out = sb.c_str(); | |
114 | + } | |
115 | + } | |
116 | + break; | |
117 | + | |
118 | case LFT_TIME_SECONDS_SINCE_EPOCH: | |
119 | // some platforms store time in 32-bit, some 64-bit... | |
120 | outoff = static_cast<int64_t>(current_time.tv_sec); | |
121 | diff --git a/src/format/Token.cc b/src/format/Token.cc | |
122 | index 186ade5..06c60cf 100644 | |
123 | --- a/src/format/Token.cc | |
124 | +++ b/src/format/Token.cc | |
125 | @@ -141,6 +141,7 @@ static TokenTableEntry TokenTableMisc[] = { | |
126 | TokenTableEntry("<qos", LFT_SERVER_LOCAL_TOS), | |
127 | TokenTableEntry(">nfmark", LFT_CLIENT_LOCAL_NFMARK), | |
128 | TokenTableEntry("<nfmark", LFT_SERVER_LOCAL_NFMARK), | |
129 | + TokenTableEntry(">handshake", LFT_CLIENT_HANDSHAKE), | |
130 | TokenTableEntry("err_code", LFT_SQUID_ERROR ), | |
131 | TokenTableEntry("err_detail", LFT_SQUID_ERROR_DETAIL ), | |
132 | TokenTableEntry("note", LFT_NOTE ), |