Coverage Report

Created: 2024-12-17 06:15

/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
}