1use std::io;
4use std::net::{TcpListener, TcpStream};
5
6use bitfield_struct::bitfield;
7
8use crate::setup::{setup_ulp, TlsCryptoInfoTx};
9use crate::tls::{AeadKey, ConnectionTrafficSecrets, ProtocolVersion};
10
11#[non_exhaustive]
12#[derive(Debug, Clone, Copy)]
13pub struct Compatibilities {
15 pub tls12: Compatibility,
17
18 pub tls13: Compatibility,
20}
21
22impl Compatibilities {
23 pub fn probe() -> io::Result<Option<Self>> {
43 let listener = TcpListener::bind("127.0.0.1:0")?;
44
45 let local_addr = listener.local_addr()?;
46
47 let mut tls12 = Compatibility::new();
48 let mut tls13 = Compatibility::new();
49
50 macro_rules! test {
51 ($ver:ident, $cipher:ident, $c:ident, $m:ident) => {{
52 let stream = TcpStream::connect(local_addr)?;
53
54 match setup_ulp(&stream) {
55 Ok(_) => {}
56 Err(err) if err.is_ktls_unsupported() => return Ok(None),
57 Err(err) => {
58 crate::error!(
59 "Failed to probe compatibility of {} {}",
60 stringify!($ver),
61 stringify!($cipher)
62 );
63
64 return Err(err.into());
65 }
66 }
67
68 if TlsCryptoInfoTx::new(
69 ProtocolVersion::$ver,
70 ConnectionTrafficSecrets::$cipher {
71 key: AeadKey::new(Default::default()),
72 iv: Default::default(),
73 salt: Default::default(),
74 },
75 0,
76 )
77 .unwrap()
78 .set(&stream)
79 .inspect_err(|_err| {
80 crate::trace!(
81 "{} {}: Not suitable: {}",
82 stringify!($ver),
83 stringify!($cipher),
84 _err
85 );
86 })
87 .is_ok()
88 {
89 $c.$m(true);
90 }
91 }};
92 }
93
94 test!(TLSv1_2, Aes128Gcm, tls12, set_aes_128_gcm);
95 test!(TLSv1_2, Aes256Gcm, tls12, set_aes_256_gcm);
96 test!(TLSv1_2, Chacha20Poly1305, tls12, set_chacha20_poly1305);
97 test!(TLSv1_2, Aes128Ccm, tls12, set_aes_128_ccm);
98 test!(TLSv1_2, Sm4Gcm, tls12, set_sm4_gcm);
99 test!(TLSv1_2, Sm4Ccm, tls12, set_sm4_ccm);
100 test!(TLSv1_2, Aria128Gcm, tls12, set_aria_128_gcm);
101 test!(TLSv1_2, Aria256Gcm, tls12, set_aria_256_gcm);
102
103 test!(TLSv1_3, Aes128Gcm, tls13, set_aes_128_gcm);
104 test!(TLSv1_3, Aes256Gcm, tls13, set_aes_256_gcm);
105 test!(TLSv1_3, Chacha20Poly1305, tls13, set_chacha20_poly1305);
106 test!(TLSv1_3, Aes128Ccm, tls13, set_aes_128_ccm);
107 test!(TLSv1_3, Sm4Gcm, tls13, set_sm4_gcm);
108 test!(TLSv1_3, Sm4Ccm, tls13, set_sm4_ccm);
109 test!(TLSv1_3, Aria128Gcm, tls13, set_aria_128_gcm);
110 test!(TLSv1_3, Aria256Gcm, tls13, set_aria_256_gcm);
111
112 if tls12.is_unsupported() && tls13.is_unsupported() {
113 crate::error!("All cipher suites are unsupported while kTLS seems to be supported");
114
115 return Ok(None);
116 }
117
118 let this = Self { tls12, tls13 };
119
120 crate::trace!("kTLS compatibilities probed: {:#?}", this);
121
122 Ok(Some(this))
123 }
124}
125
126#[bitfield(u8)]
127pub struct Compatibility {
129 pub aes_128_gcm: bool,
131
132 pub aes_256_gcm: bool,
134
135 pub chacha20_poly1305: bool,
137
138 pub aes_128_ccm: bool,
140
141 pub sm4_gcm: bool,
143
144 pub sm4_ccm: bool,
146
147 pub aria_128_gcm: bool,
149
150 pub aria_256_gcm: bool,
152}
153
154impl Compatibility {
155 #[must_use]
158 pub const fn is_unsupported(&self) -> bool {
159 self.0 == 0
160 }
161}