/src/linkerd2-proxy/linkerd/tls/src/server/client_hello.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use crate::ServerName; |
2 | | use linkerd_dns_name as dns; |
3 | | use tracing::trace; |
4 | | |
5 | | #[derive(Debug, Eq, PartialEq)] |
6 | | pub struct Incomplete; |
7 | | |
8 | | /// Determines whether the given `input` looks like the start of a TLS connection. |
9 | | /// |
10 | | /// The determination is made based on whether the input looks like (the start of) a valid |
11 | | /// ClientHello that a reasonable TLS client might send, and the SNI matches the given identity. |
12 | | /// |
13 | | /// XXX: Once the TLS record header is matched, the determination won't be made until the entire TLS |
14 | | /// record including the entire ClientHello handshake message is available. |
15 | | /// |
16 | | /// TODO: Reject non-matching inputs earlier. |
17 | | /// |
18 | | /// This assumes that the ClientHello is small and is sent in a single TLS record, which is what all |
19 | | /// reasonable implementations do. (If they were not to, they wouldn't interoperate with picky |
20 | | /// servers.) |
21 | 784 | pub fn parse_sni(input: &[u8]) -> Result<Option<ServerName>, Incomplete> { |
22 | 784 | let r = untrusted::Input::from(input).read_all(untrusted::EndOfInput, |input| { |
23 | 784 | let r = extract_sni(input); |
24 | 784 | input.skip_to_end(); // Ignore anything after what we parsed. |
25 | 784 | r |
26 | 784 | }); linkerd_tls::server::client_hello::parse_sni::{closure#0} Line | Count | Source | 22 | 784 | let r = untrusted::Input::from(input).read_all(untrusted::EndOfInput, |input| { | 23 | 784 | let r = extract_sni(input); | 24 | 784 | input.skip_to_end(); // Ignore anything after what we parsed. | 25 | 784 | r | 26 | 784 | }); |
Unexecuted instantiation: linkerd_tls::server::client_hello::parse_sni::{closure#0} |
27 | 318 | match r { |
28 | 130 | Ok(Some(sni)) => { |
29 | 130 | let sni = match std::str::from_utf8(sni.as_slice_less_safe()) |
30 | 130 | .ok() |
31 | 130 | .and_then(|n| n.parse::<dns::Name>().ok()) linkerd_tls::server::client_hello::parse_sni::{closure#1} Line | Count | Source | 31 | 128 | .and_then(|n| n.parse::<dns::Name>().ok()) |
Unexecuted instantiation: linkerd_tls::server::client_hello::parse_sni::{closure#1} |
32 | | { |
33 | 101 | Some(sni) => sni, |
34 | 29 | None => return Ok(None), |
35 | | }; |
36 | 101 | trace!(?sni, "parse_sni: parsed correctly up to SNI"); |
37 | 101 | Ok(Some(ServerName(sni))) |
38 | | } |
39 | | Ok(None) => { |
40 | 188 | trace!("parse_sni: failed to parse up to SNI"); |
41 | 188 | Ok(None) |
42 | | } |
43 | | Err(untrusted::EndOfInput) => { |
44 | 466 | trace!("parse_sni: needs more input"); |
45 | 466 | Err(Incomplete) |
46 | | } |
47 | | } |
48 | 784 | } linkerd_tls::server::client_hello::parse_sni Line | Count | Source | 21 | 784 | pub fn parse_sni(input: &[u8]) -> Result<Option<ServerName>, Incomplete> { | 22 | 784 | let r = untrusted::Input::from(input).read_all(untrusted::EndOfInput, |input| { | 23 | | let r = extract_sni(input); | 24 | | input.skip_to_end(); // Ignore anything after what we parsed. | 25 | | r | 26 | 784 | }); | 27 | 318 | match r { | 28 | 130 | Ok(Some(sni)) => { | 29 | 130 | let sni = match std::str::from_utf8(sni.as_slice_less_safe()) | 30 | 130 | .ok() | 31 | 130 | .and_then(|n| n.parse::<dns::Name>().ok()) | 32 | | { | 33 | 101 | Some(sni) => sni, | 34 | 29 | None => return Ok(None), | 35 | | }; | 36 | 101 | trace!(?sni, "parse_sni: parsed correctly up to SNI"); | 37 | 101 | Ok(Some(ServerName(sni))) | 38 | | } | 39 | | Ok(None) => { | 40 | 188 | trace!("parse_sni: failed to parse up to SNI"); | 41 | 188 | Ok(None) | 42 | | } | 43 | | Err(untrusted::EndOfInput) => { | 44 | 466 | trace!("parse_sni: needs more input"); | 45 | 466 | Err(Incomplete) | 46 | | } | 47 | | } | 48 | 784 | } |
Unexecuted instantiation: linkerd_tls::server::client_hello::parse_sni |
49 | | |
50 | | /// The result is `Ok(Some(hostname))` if the SNI extension was found, `Ok(None)` |
51 | | /// if we affirmatively rejected the input before we found the SNI extension, or |
52 | | /// `Err(EndOfInput)` if we don't have enough input to continue. |
53 | 784 | fn extract_sni<'a>( |
54 | 784 | input: &mut untrusted::Reader<'a>, |
55 | 784 | ) -> Result<Option<untrusted::Input<'a>>, untrusted::EndOfInput> { |
56 | 784 | // TLS ciphertext record header. |
57 | 784 | |
58 | 784 | if input.read_byte()? != 22 { |
59 | | // ContentType::handshake |
60 | 104 | return Ok(None); |
61 | 680 | } |
62 | 680 | if input.read_byte()? != 0x03 { |
63 | | // legacy_record_version.major is always 0x03. |
64 | 12 | return Ok(None); |
65 | 667 | } |
66 | | { |
67 | | // legacy_record_version.minor may be 0x01 or 0x03 according to |
68 | | // https://tools.ietf.org/html/draft-ietf-tls-tls13-28#section-5.1 |
69 | 667 | let minor = input.read_byte()?; |
70 | 666 | if minor != 0x01 && minor != 0x03 { |
71 | 15 | return Ok(None); |
72 | 651 | } |
73 | 651 | } |
74 | 651 | |
75 | 651 | // Treat the record length and its body as a vector<u16>. |
76 | 651 | let r = read_vector(input, |input| { |
77 | 600 | if input.read_byte()? != 1 { |
78 | | // HandshakeType::client_hello |
79 | 20 | return Ok(None); |
80 | 573 | } |
81 | 573 | // The length is a 24-bit big-endian value. Nobody (good) will never |
82 | 573 | // send a value larger than 0xffff so treat it as a 0x00 followed |
83 | 573 | // by vector<u16> |
84 | 573 | if input.read_byte()? != 0 { |
85 | | // Most significant byte of the length |
86 | 8 | return Ok(None); |
87 | 564 | } |
88 | 564 | read_vector(input, |input| { |
89 | 522 | // version{.major,.minor} == {0x3, 0x3} for TLS 1.2 and later. |
90 | 522 | if input.read_byte()? != 0x03 || input.read_byte()? != 0x03 { |
91 | 22 | return Ok(None); |
92 | 495 | } |
93 | 495 | |
94 | 495 | input.skip(32)?; // random |
95 | 484 | skip_vector_u8(input)?; // session_id |
96 | 473 | if !skip_vector(input)? { |
97 | | // cipher_suites |
98 | 11 | return Ok(None); |
99 | 423 | } |
100 | 423 | skip_vector_u8(input)?; // compression_methods |
101 | | |
102 | | // Look for the SNI extension as specified in |
103 | | // https://tools.ietf.org/html/rfc6066#section-1.1 |
104 | 408 | read_vector(input, |input| { |
105 | 3.60k | while !input.at_end() { |
106 | 3.57k | let extension_type = read_u16(input)?; |
107 | 3.55k | if extension_type != 0 { |
108 | | // ExtensionType::server_name |
109 | 3.30k | skip_vector(input)?; |
110 | 3.25k | continue; |
111 | 256 | } |
112 | 256 | |
113 | 256 | // Treat extension_length followed by extension_value as a |
114 | 256 | // vector<u16>. |
115 | 256 | let r = read_vector(input, |input| { |
116 | 209 | // server_name_list |
117 | 209 | read_vector(input, |input| { |
118 | 175 | // Nobody sends an SNI extension with anything |
119 | 175 | // other than a single `host_name` value. |
120 | 175 | if input.read_byte()? != 0 { |
121 | | // NameType::host_name |
122 | 6 | return Ok(None); |
123 | 168 | } |
124 | 168 | // Return the value of the `HostName`. |
125 | 168 | read_vector(input, |input| Ok(Some(input.read_bytes_to_end()))) linkerd_tls::server::client_hello::extract_sni::{closure#0}::{closure#0}::{closure#0}::{closure#0}::{closure#0}::{closure#0} Line | Count | Source | 125 | 136 | read_vector(input, |input| Ok(Some(input.read_bytes_to_end()))) |
Unexecuted instantiation: linkerd_tls::server::client_hello::extract_sni::{closure#0}::{closure#0}::{closure#0}::{closure#0}::{closure#0}::{closure#0} |
126 | 209 | }) linkerd_tls::server::client_hello::extract_sni::{closure#0}::{closure#0}::{closure#0}::{closure#0}::{closure#0} Line | Count | Source | 117 | 175 | read_vector(input, |input| { | 118 | 175 | // Nobody sends an SNI extension with anything | 119 | 175 | // other than a single `host_name` value. | 120 | 175 | if input.read_byte()? != 0 { | 121 | | // NameType::host_name | 122 | 6 | return Ok(None); | 123 | 168 | } | 124 | 168 | // Return the value of the `HostName`. | 125 | 168 | read_vector(input, |input| Ok(Some(input.read_bytes_to_end()))) | 126 | 175 | }) |
Unexecuted instantiation: linkerd_tls::server::client_hello::extract_sni::{closure#0}::{closure#0}::{closure#0}::{closure#0}::{closure#0} |
127 | 256 | }); linkerd_tls::server::client_hello::extract_sni::{closure#0}::{closure#0}::{closure#0}::{closure#0} Line | Count | Source | 115 | 209 | let r = read_vector(input, |input| { | 116 | 209 | // server_name_list | 117 | 209 | read_vector(input, |input| { | 118 | | // Nobody sends an SNI extension with anything | 119 | | // other than a single `host_name` value. | 120 | | if input.read_byte()? != 0 { | 121 | | // NameType::host_name | 122 | | return Ok(None); | 123 | | } | 124 | | // Return the value of the `HostName`. | 125 | | read_vector(input, |input| Ok(Some(input.read_bytes_to_end()))) | 126 | 209 | }) | 127 | 209 | }); |
Unexecuted instantiation: linkerd_tls::server::client_hello::extract_sni::{closure#0}::{closure#0}::{closure#0}::{closure#0} |
128 | 256 | |
129 | 256 | input.skip_to_end(); // Ignore stuff after SNI |
130 | 256 | return r; |
131 | | } |
132 | | |
133 | 31 | Ok(None) // No SNI extension. |
134 | 408 | }) linkerd_tls::server::client_hello::extract_sni::{closure#0}::{closure#0}::{closure#0} Line | Count | Source | 104 | 351 | read_vector(input, |input| { | 105 | 3.60k | while !input.at_end() { | 106 | 3.57k | let extension_type = read_u16(input)?; | 107 | 3.55k | if extension_type != 0 { | 108 | | // ExtensionType::server_name | 109 | 3.30k | skip_vector(input)?; | 110 | 3.25k | continue; | 111 | 256 | } | 112 | 256 | | 113 | 256 | // Treat extension_length followed by extension_value as a | 114 | 256 | // vector<u16>. | 115 | 256 | let r = read_vector(input, |input| { | 116 | | // server_name_list | 117 | | read_vector(input, |input| { | 118 | | // Nobody sends an SNI extension with anything | 119 | | // other than a single `host_name` value. | 120 | | if input.read_byte()? != 0 { | 121 | | // NameType::host_name | 122 | | return Ok(None); | 123 | | } | 124 | | // Return the value of the `HostName`. | 125 | | read_vector(input, |input| Ok(Some(input.read_bytes_to_end()))) | 126 | | }) | 127 | 256 | }); | 128 | 256 | | 129 | 256 | input.skip_to_end(); // Ignore stuff after SNI | 130 | 256 | return r; | 131 | | } | 132 | | | 133 | 31 | Ok(None) // No SNI extension. | 134 | 351 | }) |
Unexecuted instantiation: linkerd_tls::server::client_hello::extract_sni::{closure#0}::{closure#0}::{closure#0} |
135 | 564 | }) linkerd_tls::server::client_hello::extract_sni::{closure#0}::{closure#0} Line | Count | Source | 88 | 522 | read_vector(input, |input| { | 89 | 522 | // version{.major,.minor} == {0x3, 0x3} for TLS 1.2 and later. | 90 | 522 | if input.read_byte()? != 0x03 || input.read_byte()? != 0x03 { | 91 | 22 | return Ok(None); | 92 | 495 | } | 93 | 495 | | 94 | 495 | input.skip(32)?; // random | 95 | 484 | skip_vector_u8(input)?; // session_id | 96 | 473 | if !skip_vector(input)? { | 97 | | // cipher_suites | 98 | 11 | return Ok(None); | 99 | 423 | } | 100 | 423 | skip_vector_u8(input)?; // compression_methods | 101 | | | 102 | | // Look for the SNI extension as specified in | 103 | | // https://tools.ietf.org/html/rfc6066#section-1.1 | 104 | 408 | read_vector(input, |input| { | 105 | | while !input.at_end() { | 106 | | let extension_type = read_u16(input)?; | 107 | | if extension_type != 0 { | 108 | | // ExtensionType::server_name | 109 | | skip_vector(input)?; | 110 | | continue; | 111 | | } | 112 | | | 113 | | // Treat extension_length followed by extension_value as a | 114 | | // vector<u16>. | 115 | | let r = read_vector(input, |input| { | 116 | | // server_name_list | 117 | | read_vector(input, |input| { | 118 | | // Nobody sends an SNI extension with anything | 119 | | // other than a single `host_name` value. | 120 | | if input.read_byte()? != 0 { | 121 | | // NameType::host_name | 122 | | return Ok(None); | 123 | | } | 124 | | // Return the value of the `HostName`. | 125 | | read_vector(input, |input| Ok(Some(input.read_bytes_to_end()))) | 126 | | }) | 127 | | }); | 128 | | | 129 | | input.skip_to_end(); // Ignore stuff after SNI | 130 | | return r; | 131 | | } | 132 | | | 133 | | Ok(None) // No SNI extension. | 134 | 408 | }) | 135 | 522 | }) |
Unexecuted instantiation: linkerd_tls::server::client_hello::extract_sni::{closure#0}::{closure#0} |
136 | 651 | }); linkerd_tls::server::client_hello::extract_sni::{closure#0} Line | Count | Source | 76 | 600 | let r = read_vector(input, |input| { | 77 | 600 | if input.read_byte()? != 1 { | 78 | | // HandshakeType::client_hello | 79 | 20 | return Ok(None); | 80 | 573 | } | 81 | 573 | // The length is a 24-bit big-endian value. Nobody (good) will never | 82 | 573 | // send a value larger than 0xffff so treat it as a 0x00 followed | 83 | 573 | // by vector<u16> | 84 | 573 | if input.read_byte()? != 0 { | 85 | | // Most significant byte of the length | 86 | 8 | return Ok(None); | 87 | 564 | } | 88 | 564 | read_vector(input, |input| { | 89 | | // version{.major,.minor} == {0x3, 0x3} for TLS 1.2 and later. | 90 | | if input.read_byte()? != 0x03 || input.read_byte()? != 0x03 { | 91 | | return Ok(None); | 92 | | } | 93 | | | 94 | | input.skip(32)?; // random | 95 | | skip_vector_u8(input)?; // session_id | 96 | | if !skip_vector(input)? { | 97 | | // cipher_suites | 98 | | return Ok(None); | 99 | | } | 100 | | skip_vector_u8(input)?; // compression_methods | 101 | | | 102 | | // Look for the SNI extension as specified in | 103 | | // https://tools.ietf.org/html/rfc6066#section-1.1 | 104 | | read_vector(input, |input| { | 105 | | while !input.at_end() { | 106 | | let extension_type = read_u16(input)?; | 107 | | if extension_type != 0 { | 108 | | // ExtensionType::server_name | 109 | | skip_vector(input)?; | 110 | | continue; | 111 | | } | 112 | | | 113 | | // Treat extension_length followed by extension_value as a | 114 | | // vector<u16>. | 115 | | let r = read_vector(input, |input| { | 116 | | // server_name_list | 117 | | read_vector(input, |input| { | 118 | | // Nobody sends an SNI extension with anything | 119 | | // other than a single `host_name` value. | 120 | | if input.read_byte()? != 0 { | 121 | | // NameType::host_name | 122 | | return Ok(None); | 123 | | } | 124 | | // Return the value of the `HostName`. | 125 | | read_vector(input, |input| Ok(Some(input.read_bytes_to_end()))) | 126 | | }) | 127 | | }); | 128 | | | 129 | | input.skip_to_end(); // Ignore stuff after SNI | 130 | | return r; | 131 | | } | 132 | | | 133 | | Ok(None) // No SNI extension. | 134 | | }) | 135 | 564 | }) | 136 | 600 | }); |
Unexecuted instantiation: linkerd_tls::server::client_hello::extract_sni::{closure#0} |
137 | 651 | |
138 | 651 | // Ignore anything after the first handshake record. |
139 | 651 | input.skip_to_end(); |
140 | 651 | |
141 | 651 | r |
142 | 784 | } linkerd_tls::server::client_hello::extract_sni Line | Count | Source | 53 | 784 | fn extract_sni<'a>( | 54 | 784 | input: &mut untrusted::Reader<'a>, | 55 | 784 | ) -> Result<Option<untrusted::Input<'a>>, untrusted::EndOfInput> { | 56 | 784 | // TLS ciphertext record header. | 57 | 784 | | 58 | 784 | if input.read_byte()? != 22 { | 59 | | // ContentType::handshake | 60 | 104 | return Ok(None); | 61 | 680 | } | 62 | 680 | if input.read_byte()? != 0x03 { | 63 | | // legacy_record_version.major is always 0x03. | 64 | 12 | return Ok(None); | 65 | 667 | } | 66 | | { | 67 | | // legacy_record_version.minor may be 0x01 or 0x03 according to | 68 | | // https://tools.ietf.org/html/draft-ietf-tls-tls13-28#section-5.1 | 69 | 667 | let minor = input.read_byte()?; | 70 | 666 | if minor != 0x01 && minor != 0x03 { | 71 | 15 | return Ok(None); | 72 | 651 | } | 73 | 651 | } | 74 | 651 | | 75 | 651 | // Treat the record length and its body as a vector<u16>. | 76 | 651 | let r = read_vector(input, |input| { | 77 | | if input.read_byte()? != 1 { | 78 | | // HandshakeType::client_hello | 79 | | return Ok(None); | 80 | | } | 81 | | // The length is a 24-bit big-endian value. Nobody (good) will never | 82 | | // send a value larger than 0xffff so treat it as a 0x00 followed | 83 | | // by vector<u16> | 84 | | if input.read_byte()? != 0 { | 85 | | // Most significant byte of the length | 86 | | return Ok(None); | 87 | | } | 88 | | read_vector(input, |input| { | 89 | | // version{.major,.minor} == {0x3, 0x3} for TLS 1.2 and later. | 90 | | if input.read_byte()? != 0x03 || input.read_byte()? != 0x03 { | 91 | | return Ok(None); | 92 | | } | 93 | | | 94 | | input.skip(32)?; // random | 95 | | skip_vector_u8(input)?; // session_id | 96 | | if !skip_vector(input)? { | 97 | | // cipher_suites | 98 | | return Ok(None); | 99 | | } | 100 | | skip_vector_u8(input)?; // compression_methods | 101 | | | 102 | | // Look for the SNI extension as specified in | 103 | | // https://tools.ietf.org/html/rfc6066#section-1.1 | 104 | | read_vector(input, |input| { | 105 | | while !input.at_end() { | 106 | | let extension_type = read_u16(input)?; | 107 | | if extension_type != 0 { | 108 | | // ExtensionType::server_name | 109 | | skip_vector(input)?; | 110 | | continue; | 111 | | } | 112 | | | 113 | | // Treat extension_length followed by extension_value as a | 114 | | // vector<u16>. | 115 | | let r = read_vector(input, |input| { | 116 | | // server_name_list | 117 | | read_vector(input, |input| { | 118 | | // Nobody sends an SNI extension with anything | 119 | | // other than a single `host_name` value. | 120 | | if input.read_byte()? != 0 { | 121 | | // NameType::host_name | 122 | | return Ok(None); | 123 | | } | 124 | | // Return the value of the `HostName`. | 125 | | read_vector(input, |input| Ok(Some(input.read_bytes_to_end()))) | 126 | | }) | 127 | | }); | 128 | | | 129 | | input.skip_to_end(); // Ignore stuff after SNI | 130 | | return r; | 131 | | } | 132 | | | 133 | | Ok(None) // No SNI extension. | 134 | | }) | 135 | | }) | 136 | 651 | }); | 137 | 651 | | 138 | 651 | // Ignore anything after the first handshake record. | 139 | 651 | input.skip_to_end(); | 140 | 651 | | 141 | 651 | r | 142 | 784 | } |
Unexecuted instantiation: linkerd_tls::server::client_hello::extract_sni |
143 | | |
144 | | /// Reads a `u16` vector, which is formatted as a big-endian `u16` length |
145 | | /// followed by that many bytes. |
146 | 6.03k | fn read_vector<'a, F, T>( |
147 | 6.03k | input: &mut untrusted::Reader<'a>, |
148 | 6.03k | f: F, |
149 | 6.03k | ) -> Result<Option<T>, untrusted::EndOfInput> |
150 | 6.03k | where |
151 | 6.03k | F: Fn(&mut untrusted::Reader<'a>) -> Result<Option<T>, untrusted::EndOfInput>, |
152 | 6.03k | T: 'a, |
153 | 6.03k | { |
154 | 6.03k | let length = read_u16(input)?; |
155 | | |
156 | | // ClientHello has to be small for compatibility with many deployed |
157 | | // implementations, so if it is (relatively) huge, we might not be looking |
158 | | // at TLS traffic, and we're definitely not looking at proxy-terminated |
159 | | // traffic, so bail out early. |
160 | 5.99k | if length > 8192 { |
161 | 2.50k | return Ok(None); |
162 | 3.49k | } |
163 | 3.49k | let r = input.read_bytes(usize::from(length))?; |
164 | 3.23k | r.read_all(untrusted::EndOfInput, f) |
165 | 6.03k | } linkerd_tls::server::client_hello::read_vector::<linkerd_tls::server::client_hello::extract_sni::{closure#0}::{closure#0}::{closure#0}::{closure#0}::{closure#0}::{closure#0}, untrusted::input::Input> Line | Count | Source | 146 | 168 | fn read_vector<'a, F, T>( | 147 | 168 | input: &mut untrusted::Reader<'a>, | 148 | 168 | f: F, | 149 | 168 | ) -> Result<Option<T>, untrusted::EndOfInput> | 150 | 168 | where | 151 | 168 | F: Fn(&mut untrusted::Reader<'a>) -> Result<Option<T>, untrusted::EndOfInput>, | 152 | 168 | T: 'a, | 153 | 168 | { | 154 | 168 | let length = read_u16(input)?; | 155 | | | 156 | | // ClientHello has to be small for compatibility with many deployed | 157 | | // implementations, so if it is (relatively) huge, we might not be looking | 158 | | // at TLS traffic, and we're definitely not looking at proxy-terminated | 159 | | // traffic, so bail out early. | 160 | 165 | if length > 8192 { | 161 | 1 | return Ok(None); | 162 | 164 | } | 163 | 164 | let r = input.read_bytes(usize::from(length))?; | 164 | 136 | r.read_all(untrusted::EndOfInput, f) | 165 | 168 | } |
linkerd_tls::server::client_hello::read_vector::<linkerd_tls::server::client_hello::extract_sni::{closure#0}::{closure#0}::{closure#0}::{closure#0}::{closure#0}, untrusted::input::Input> Line | Count | Source | 146 | 209 | fn read_vector<'a, F, T>( | 147 | 209 | input: &mut untrusted::Reader<'a>, | 148 | 209 | f: F, | 149 | 209 | ) -> Result<Option<T>, untrusted::EndOfInput> | 150 | 209 | where | 151 | 209 | F: Fn(&mut untrusted::Reader<'a>) -> Result<Option<T>, untrusted::EndOfInput>, | 152 | 209 | T: 'a, | 153 | 209 | { | 154 | 209 | let length = read_u16(input)?; | 155 | | | 156 | | // ClientHello has to be small for compatibility with many deployed | 157 | | // implementations, so if it is (relatively) huge, we might not be looking | 158 | | // at TLS traffic, and we're definitely not looking at proxy-terminated | 159 | | // traffic, so bail out early. | 160 | 206 | if length > 8192 { | 161 | 7 | return Ok(None); | 162 | 199 | } | 163 | 199 | let r = input.read_bytes(usize::from(length))?; | 164 | 175 | r.read_all(untrusted::EndOfInput, f) | 165 | 209 | } |
linkerd_tls::server::client_hello::read_vector::<linkerd_tls::server::client_hello::extract_sni::{closure#0}::{closure#0}::{closure#0}::{closure#0}, untrusted::input::Input> Line | Count | Source | 146 | 256 | fn read_vector<'a, F, T>( | 147 | 256 | input: &mut untrusted::Reader<'a>, | 148 | 256 | f: F, | 149 | 256 | ) -> Result<Option<T>, untrusted::EndOfInput> | 150 | 256 | where | 151 | 256 | F: Fn(&mut untrusted::Reader<'a>) -> Result<Option<T>, untrusted::EndOfInput>, | 152 | 256 | T: 'a, | 153 | 256 | { | 154 | 256 | let length = read_u16(input)?; | 155 | | | 156 | | // ClientHello has to be small for compatibility with many deployed | 157 | | // implementations, so if it is (relatively) huge, we might not be looking | 158 | | // at TLS traffic, and we're definitely not looking at proxy-terminated | 159 | | // traffic, so bail out early. | 160 | 251 | if length > 8192 { | 161 | 10 | return Ok(None); | 162 | 241 | } | 163 | 241 | let r = input.read_bytes(usize::from(length))?; | 164 | 209 | r.read_all(untrusted::EndOfInput, f) | 165 | 256 | } |
linkerd_tls::server::client_hello::read_vector::<linkerd_tls::server::client_hello::extract_sni::{closure#0}::{closure#0}::{closure#0}, untrusted::input::Input> Line | Count | Source | 146 | 408 | fn read_vector<'a, F, T>( | 147 | 408 | input: &mut untrusted::Reader<'a>, | 148 | 408 | f: F, | 149 | 408 | ) -> Result<Option<T>, untrusted::EndOfInput> | 150 | 408 | where | 151 | 408 | F: Fn(&mut untrusted::Reader<'a>) -> Result<Option<T>, untrusted::EndOfInput>, | 152 | 408 | T: 'a, | 153 | 408 | { | 154 | 408 | let length = read_u16(input)?; | 155 | | | 156 | | // ClientHello has to be small for compatibility with many deployed | 157 | | // implementations, so if it is (relatively) huge, we might not be looking | 158 | | // at TLS traffic, and we're definitely not looking at proxy-terminated | 159 | | // traffic, so bail out early. | 160 | 403 | if length > 8192 { | 161 | 22 | return Ok(None); | 162 | 381 | } | 163 | 381 | let r = input.read_bytes(usize::from(length))?; | 164 | 351 | r.read_all(untrusted::EndOfInput, f) | 165 | 408 | } |
linkerd_tls::server::client_hello::read_vector::<linkerd_tls::server::client_hello::extract_sni::{closure#0}::{closure#0}, untrusted::input::Input> Line | Count | Source | 146 | 564 | fn read_vector<'a, F, T>( | 147 | 564 | input: &mut untrusted::Reader<'a>, | 148 | 564 | f: F, | 149 | 564 | ) -> Result<Option<T>, untrusted::EndOfInput> | 150 | 564 | where | 151 | 564 | F: Fn(&mut untrusted::Reader<'a>) -> Result<Option<T>, untrusted::EndOfInput>, | 152 | 564 | T: 'a, | 153 | 564 | { | 154 | 564 | let length = read_u16(input)?; | 155 | | | 156 | | // ClientHello has to be small for compatibility with many deployed | 157 | | // implementations, so if it is (relatively) huge, we might not be looking | 158 | | // at TLS traffic, and we're definitely not looking at proxy-terminated | 159 | | // traffic, so bail out early. | 160 | 561 | if length > 8192 { | 161 | 8 | return Ok(None); | 162 | 553 | } | 163 | 553 | let r = input.read_bytes(usize::from(length))?; | 164 | 522 | r.read_all(untrusted::EndOfInput, f) | 165 | 564 | } |
linkerd_tls::server::client_hello::read_vector::<linkerd_tls::server::client_hello::extract_sni::{closure#0}, untrusted::input::Input> Line | Count | Source | 146 | 651 | fn read_vector<'a, F, T>( | 147 | 651 | input: &mut untrusted::Reader<'a>, | 148 | 651 | f: F, | 149 | 651 | ) -> Result<Option<T>, untrusted::EndOfInput> | 150 | 651 | where | 151 | 651 | F: Fn(&mut untrusted::Reader<'a>) -> Result<Option<T>, untrusted::EndOfInput>, | 152 | 651 | T: 'a, | 153 | 651 | { | 154 | 651 | let length = read_u16(input)?; | 155 | | | 156 | | // ClientHello has to be small for compatibility with many deployed | 157 | | // implementations, so if it is (relatively) huge, we might not be looking | 158 | | // at TLS traffic, and we're definitely not looking at proxy-terminated | 159 | | // traffic, so bail out early. | 160 | 648 | if length > 8192 { | 161 | 7 | return Ok(None); | 162 | 641 | } | 163 | 641 | let r = input.read_bytes(usize::from(length))?; | 164 | 600 | r.read_all(untrusted::EndOfInput, f) | 165 | 651 | } |
linkerd_tls::server::client_hello::read_vector::<linkerd_tls::server::client_hello::skip_vector::{closure#0}, ()> Line | Count | Source | 146 | 3.77k | fn read_vector<'a, F, T>( | 147 | 3.77k | input: &mut untrusted::Reader<'a>, | 148 | 3.77k | f: F, | 149 | 3.77k | ) -> Result<Option<T>, untrusted::EndOfInput> | 150 | 3.77k | where | 151 | 3.77k | F: Fn(&mut untrusted::Reader<'a>) -> Result<Option<T>, untrusted::EndOfInput>, | 152 | 3.77k | T: 'a, | 153 | 3.77k | { | 154 | 3.77k | let length = read_u16(input)?; | 155 | | | 156 | | // ClientHello has to be small for compatibility with many deployed | 157 | | // implementations, so if it is (relatively) huge, we might not be looking | 158 | | // at TLS traffic, and we're definitely not looking at proxy-terminated | 159 | | // traffic, so bail out early. | 160 | 3.75k | if length > 8192 { | 161 | 2.44k | return Ok(None); | 162 | 1.31k | } | 163 | 1.31k | let r = input.read_bytes(usize::from(length))?; | 164 | 1.23k | r.read_all(untrusted::EndOfInput, f) | 165 | 3.77k | } |
Unexecuted instantiation: linkerd_tls::server::client_hello::read_vector::<linkerd_tls::server::client_hello::extract_sni::{closure#0}::{closure#0}::{closure#0}::{closure#0}::{closure#0}::{closure#0}, untrusted::input::Input> Unexecuted instantiation: linkerd_tls::server::client_hello::read_vector::<linkerd_tls::server::client_hello::extract_sni::{closure#0}::{closure#0}::{closure#0}::{closure#0}::{closure#0}, untrusted::input::Input> Unexecuted instantiation: linkerd_tls::server::client_hello::read_vector::<linkerd_tls::server::client_hello::extract_sni::{closure#0}::{closure#0}::{closure#0}::{closure#0}, untrusted::input::Input> Unexecuted instantiation: linkerd_tls::server::client_hello::read_vector::<linkerd_tls::server::client_hello::extract_sni::{closure#0}::{closure#0}::{closure#0}, untrusted::input::Input> Unexecuted instantiation: linkerd_tls::server::client_hello::read_vector::<linkerd_tls::server::client_hello::extract_sni::{closure#0}::{closure#0}, untrusted::input::Input> Unexecuted instantiation: linkerd_tls::server::client_hello::read_vector::<linkerd_tls::server::client_hello::extract_sni::{closure#0}, untrusted::input::Input> Unexecuted instantiation: linkerd_tls::server::client_hello::read_vector::<linkerd_tls::server::client_hello::skip_vector::{closure#0}, ()> |
166 | | |
167 | | /// Like `read_vector` except the contents are ignored. |
168 | 3.77k | fn skip_vector(input: &mut untrusted::Reader<'_>) -> Result<bool, untrusted::EndOfInput> { |
169 | 3.77k | let r = read_vector(input, |input| { |
170 | 1.23k | input.skip_to_end(); |
171 | 1.23k | Ok(Some(())) |
172 | 3.77k | }); linkerd_tls::server::client_hello::skip_vector::{closure#0} Line | Count | Source | 169 | 1.23k | let r = read_vector(input, |input| { | 170 | 1.23k | input.skip_to_end(); | 171 | 1.23k | Ok(Some(())) | 172 | 1.23k | }); |
Unexecuted instantiation: linkerd_tls::server::client_hello::skip_vector::{closure#0} |
173 | 3.77k | r.map(|r| r.is_some()) linkerd_tls::server::client_hello::skip_vector::{closure#1} Line | Count | Source | 173 | 3.68k | r.map(|r| r.is_some()) |
Unexecuted instantiation: linkerd_tls::server::client_hello::skip_vector::{closure#1} |
174 | 3.77k | } linkerd_tls::server::client_hello::skip_vector Line | Count | Source | 168 | 3.77k | fn skip_vector(input: &mut untrusted::Reader<'_>) -> Result<bool, untrusted::EndOfInput> { | 169 | 3.77k | let r = read_vector(input, |input| { | 170 | | input.skip_to_end(); | 171 | | Ok(Some(())) | 172 | 3.77k | }); | 173 | 3.77k | r.map(|r| r.is_some()) | 174 | 3.77k | } |
Unexecuted instantiation: linkerd_tls::server::client_hello::skip_vector |
175 | | |
176 | | /// Like `skip_vector` for vectors with `u8` lengths. |
177 | 907 | fn skip_vector_u8(input: &mut untrusted::Reader<'_>) -> Result<(), untrusted::EndOfInput> { |
178 | 907 | let length = input.read_byte()?; |
179 | 904 | input.skip(usize::from(length)) |
180 | 907 | } linkerd_tls::server::client_hello::skip_vector_u8 Line | Count | Source | 177 | 907 | fn skip_vector_u8(input: &mut untrusted::Reader<'_>) -> Result<(), untrusted::EndOfInput> { | 178 | 907 | let length = input.read_byte()?; | 179 | 904 | input.skip(usize::from(length)) | 180 | 907 | } |
Unexecuted instantiation: linkerd_tls::server::client_hello::skip_vector_u8 |
181 | | |
182 | | /// Read a big-endian-encoded `u16`. |
183 | 9.60k | fn read_u16(input: &mut untrusted::Reader<'_>) -> Result<u16, untrusted::EndOfInput> { |
184 | 9.60k | let hi = input.read_byte()?; |
185 | 9.58k | let lo = input.read_byte()?; |
186 | 9.54k | Ok(u16::from(hi) << 8 | u16::from(lo)) |
187 | 9.60k | } linkerd_tls::server::client_hello::read_u16 Line | Count | Source | 183 | 9.60k | fn read_u16(input: &mut untrusted::Reader<'_>) -> Result<u16, untrusted::EndOfInput> { | 184 | 9.60k | let hi = input.read_byte()?; | 185 | 9.58k | let lo = input.read_byte()?; | 186 | 9.54k | Ok(u16::from(hi) << 8 | u16::from(lo)) | 187 | 9.60k | } |
Unexecuted instantiation: linkerd_tls::server::client_hello::read_u16 |
188 | | |
189 | | #[cfg(test)] |
190 | | mod tests { |
191 | | use super::*; |
192 | | use std::str::FromStr; |
193 | | |
194 | | #[test] |
195 | | fn mismatch_http_1_0_request() { |
196 | | assert_eq!( |
197 | | Ok(None), |
198 | | parse_sni(b"GET /TheProject.html HTTP/1.0\r\n\r\n"), |
199 | | ); |
200 | | } |
201 | | |
202 | | #[test] |
203 | | fn check_all_prefixes() { |
204 | | let input = include_bytes!("testdata/example-com-client-hello.bin"); |
205 | | let identity = dns::Name::from_str("example.com").unwrap(); |
206 | | |
207 | | let mut i = 0; |
208 | | while let Err(Incomplete) = parse_sni(&input[..i]) { |
209 | | i += 1; |
210 | | } |
211 | | |
212 | | // The same result will be returned for all longer prefixes. |
213 | | for i in i..input.len() { |
214 | | assert_eq!( |
215 | | Ok(Some(ServerName(identity.clone()))), |
216 | | parse_sni(&input[..i]) |
217 | | ) |
218 | | } |
219 | | } |
220 | | } |