Coverage Report

Created: 2026-03-28 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ztunnel/src/proxyfactory.rs
Line
Count
Source
1
// Copyright Istio Authors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
use crate::config;
16
use crate::identity::SecretManager;
17
use crate::state::{DemandProxyState, WorkloadInfo};
18
use crate::tls;
19
use std::sync::Arc;
20
use tracing::error;
21
22
use crate::dns;
23
use crate::drain::DrainWatcher;
24
25
use crate::proxy::connection_manager::ConnectionManager;
26
use crate::proxy::{DefaultSocketFactory, Proxy, inbound::Inbound};
27
use crate::proxy::{Error, LocalWorkloadInformation, Metrics};
28
29
// Proxy factory creates ztunnel proxies using a socket factory.
30
// this allows us to create our proxies the same way in regular mode and in inpod mode.
31
pub struct ProxyFactory {
32
    config: Arc<config::Config>,
33
    state: DemandProxyState,
34
    cert_manager: Arc<SecretManager>,
35
    proxy_metrics: Arc<Metrics>,
36
    dns_metrics: Option<Arc<dns::Metrics>>,
37
    drain: DrainWatcher,
38
    crl_manager: Option<Arc<tls::crl::CrlManager>>,
39
}
40
41
impl ProxyFactory {
42
0
    pub fn new(
43
0
        config: Arc<config::Config>,
44
0
        state: DemandProxyState,
45
0
        cert_manager: Arc<SecretManager>,
46
0
        proxy_metrics: Arc<Metrics>,
47
0
        dns_metrics: Option<dns::Metrics>,
48
0
        drain: DrainWatcher,
49
0
    ) -> std::io::Result<Self> {
50
0
        let dns_metrics = match dns_metrics {
51
0
            Some(metrics) => Some(Arc::new(metrics)),
52
            None => {
53
0
                if config.dns_proxy {
54
0
                    error!("dns proxy configured but no dns metrics provided")
55
0
                }
56
0
                None
57
            }
58
        };
59
60
        // Initialize CRL manager if crl_path is set
61
0
        let crl_manager = if let Some(crl_path) = &config.crl_path {
62
0
            match tls::crl::CrlManager::new(crl_path.clone()) {
63
0
                Ok(manager) => {
64
0
                    let manager_arc = Arc::new(manager);
65
66
0
                    if let Err(e) = manager_arc.start_file_watcher() {
67
0
                        tracing::warn!(
68
0
                            "crl file watcher could not be started: {}. \
69
0
                            crl validation will continue with current file, but \
70
0
                            crl updates will require restarting ztunnel.",
71
                            e
72
                        );
73
0
                    }
74
75
0
                    Some(manager_arc)
76
                }
77
0
                Err(e) => {
78
0
                    tracing::warn!(
79
                        path = ?crl_path,
80
                        error = %e,
81
0
                        "failed to initialize crl manager"
82
                    );
83
0
                    None
84
                }
85
            }
86
        } else {
87
0
            None
88
        };
89
90
0
        Ok(ProxyFactory {
91
0
            config,
92
0
            state,
93
0
            cert_manager,
94
0
            proxy_metrics,
95
0
            dns_metrics,
96
0
            drain,
97
0
            crl_manager,
98
0
        })
99
0
    }
100
101
0
    pub async fn new_proxies_for_dedicated(
102
0
        &self,
103
0
        proxy_workload_info: WorkloadInfo,
104
0
    ) -> Result<ProxyResult, Error> {
105
0
        let base = crate::proxy::DefaultSocketFactory(self.config.socket_config);
106
0
        let factory: Arc<dyn crate::proxy::SocketFactory + Send + Sync> =
107
0
            if let Some(mark) = self.config.packet_mark {
108
0
                Arc::new(crate::proxy::MarkSocketFactory { inner: base, mark })
109
            } else {
110
0
                Arc::new(base)
111
            };
112
0
        self.new_proxies_from_factory(None, proxy_workload_info, factory)
113
0
            .await
114
0
    }
115
116
0
    pub async fn new_proxies_from_factory(
117
0
        &self,
118
0
        proxy_drain: Option<DrainWatcher>,
119
0
        proxy_workload_info: WorkloadInfo,
120
0
        socket_factory: Arc<dyn crate::proxy::SocketFactory + Send + Sync>,
121
0
    ) -> Result<ProxyResult, Error> {
122
0
        let mut result: ProxyResult = Default::default();
123
0
        let drain = proxy_drain.unwrap_or_else(|| self.drain.clone());
124
125
0
        let mut resolver = None;
126
127
0
        let local_workload_information = Arc::new(LocalWorkloadInformation::new(
128
0
            Arc::new(proxy_workload_info),
129
0
            self.state.clone(),
130
0
            self.cert_manager.clone(),
131
        ));
132
133
        // Optionally create the DNS proxy.
134
0
        if self.config.dns_proxy {
135
0
            let server = dns::Server::new(
136
0
                self.config.cluster_domain.clone(),
137
0
                self.config.dns_proxy_addr,
138
0
                self.state.clone(),
139
0
                dns::forwarder_for_mode(
140
0
                    self.config.proxy_mode,
141
0
                    self.config.cluster_domain.clone(),
142
0
                    socket_factory.clone(),
143
0
                )?,
144
0
                self.dns_metrics.clone().unwrap(),
145
0
                drain.clone(),
146
0
                socket_factory.as_ref(),
147
0
                local_workload_information.as_fetcher(),
148
0
                self.config.prefered_service_namespace.clone(),
149
0
                self.config.ipv6_enabled,
150
            )
151
0
            .await?;
152
0
            resolver = Some(server.resolver());
153
0
            result.dns_proxy = Some(server);
154
0
        }
155
156
        // Optionally create the HBONE proxy.
157
0
        if self.config.proxy {
158
0
            let cm = ConnectionManager::default();
159
0
            let pi = crate::proxy::ProxyInputs::new(
160
0
                self.config.clone(),
161
0
                cm.clone(),
162
0
                self.state.clone(),
163
0
                self.proxy_metrics.clone(),
164
0
                socket_factory.clone(),
165
0
                resolver,
166
0
                local_workload_information,
167
                false,
168
0
                self.crl_manager.clone(),
169
            );
170
0
            result.connection_manager = Some(cm);
171
0
            result.proxy = Some(Proxy::from_inputs(pi, drain).await?);
172
0
        }
173
174
0
        Ok(result)
175
0
    }
176
177
    /// Creates an inbound listener specifically for ztunnel's own internal endpoints (metrics).
178
    /// This allows ztunnel to act as its own workload, enforcing policies on traffic directed to itself.
179
    /// This is distinct from the main inbound listener which handles traffic for other workloads proxied by ztunnel.
180
0
    pub async fn create_ztunnel_self_proxy_listener(
181
0
        &self,
182
0
    ) -> Result<Option<crate::proxy::inbound::Inbound>, Error> {
183
0
        if self.config.proxy_mode != config::ProxyMode::Shared {
184
0
            return Ok(None);
185
0
        }
186
187
0
        if let (Some(ztunnel_identity), Some(ztunnel_workload)) =
188
0
            (&self.config.ztunnel_identity, &self.config.ztunnel_workload)
189
        {
190
0
            tracing::info!(
191
0
                "creating ztunnel self-proxy listener with identity: {:?}",
192
                ztunnel_identity
193
            );
194
195
0
            let local_workload_information = Arc::new(LocalWorkloadInformation::new(
196
0
                Arc::new(ztunnel_workload.clone()),
197
0
                self.state.clone(),
198
0
                self.cert_manager.clone(),
199
            ));
200
201
0
            let socket_factory = Arc::new(DefaultSocketFactory(self.config.socket_config));
202
203
0
            let cm = ConnectionManager::default();
204
205
0
            let pi = crate::proxy::ProxyInputs::new(
206
0
                self.config.clone(),
207
0
                cm.clone(),
208
0
                self.state.clone(),
209
0
                self.proxy_metrics.clone(),
210
0
                socket_factory,
211
0
                None,
212
0
                local_workload_information,
213
                true,
214
0
                self.crl_manager.clone(),
215
            );
216
217
0
            let inbound = Inbound::new(pi, self.drain.clone()).await?;
218
0
            Ok(Some(inbound))
219
        } else {
220
0
            Ok(None)
221
        }
222
0
    }
223
}
224
225
#[derive(Default)]
226
pub struct ProxyResult {
227
    pub proxy: Option<Proxy>,
228
    pub dns_proxy: Option<dns::Server>,
229
    pub connection_manager: Option<ConnectionManager>,
230
}