1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
//! Tunnel management API DTOs.
//!
//! Wire types for the tunnel management endpoints.
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
/// Request to create a new tunnel token
#[derive(Debug, Deserialize, ToSchema)]
pub struct CreateTunnelRequest {
/// Name for this tunnel (for identification)
pub name: String,
/// Optional list of services this tunnel is allowed to expose
#[serde(default)]
pub services: Vec<String>,
/// Time-to-live in seconds (default: 24 hours)
#[serde(default = "default_ttl")]
pub ttl_secs: u64,
}
fn default_ttl() -> u64 {
86400 // 24 hours
}
/// Response after creating a tunnel token
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct CreateTunnelResponse {
/// Unique tunnel identifier
pub id: String,
/// Name of the tunnel
pub name: String,
/// The tunnel token to use for authentication
pub token: String,
/// Services this tunnel can expose
pub services: Vec<String>,
/// When the token expires (Unix timestamp)
pub expires_at: u64,
/// When the tunnel was created (Unix timestamp)
pub created_at: u64,
}
/// Tunnel summary for list operations
#[derive(Debug, Serialize, Deserialize, Clone, ToSchema)]
pub struct TunnelSummary {
/// Unique tunnel identifier
pub id: String,
/// Name of the tunnel
pub name: String,
/// Current status (active, disconnected, expired)
pub status: String,
/// Services this tunnel can expose
pub services: Vec<String>,
/// When the tunnel was created (Unix timestamp)
pub created_at: u64,
/// When the token expires (Unix timestamp)
pub expires_at: u64,
/// Last time the tunnel connected (Unix timestamp, if ever)
pub last_connected: Option<u64>,
}
/// Detailed tunnel status
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct TunnelStatus {
/// Unique tunnel identifier
pub id: String,
/// Name of the tunnel
pub name: String,
/// Current status (active, disconnected, expired)
pub status: String,
/// Services this tunnel can expose
pub allowed_services: Vec<String>,
/// Currently registered services
pub registered_services: Vec<RegisteredServiceInfo>,
/// When the tunnel was created (Unix timestamp)
pub created_at: u64,
/// When the token expires (Unix timestamp)
pub expires_at: u64,
/// Last time the tunnel connected (Unix timestamp, if ever)
pub last_connected: Option<u64>,
/// Client IP address (if connected)
pub client_addr: Option<String>,
/// Number of active connections
pub active_connections: u32,
}
/// Information about a registered service in a tunnel
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct RegisteredServiceInfo {
/// Service name
pub name: String,
/// Service ID
pub service_id: String,
/// Protocol (tcp or udp)
pub protocol: String,
/// Local port on the client
pub local_port: u16,
/// Remote port exposed on the server
pub remote_port: u16,
/// Current status
pub status: String,
}
/// Request to create a node-to-node tunnel
#[derive(Debug, Deserialize, ToSchema)]
pub struct CreateNodeTunnelRequest {
/// Name for this tunnel
pub name: String,
/// Source node ID
pub from_node: String,
/// Destination node ID
pub to_node: String,
/// Local port on the source node
pub local_port: u16,
/// Remote port on the destination node
pub remote_port: u16,
/// Exposure level (public, internal)
#[serde(default = "default_expose")]
pub expose: String,
}
fn default_expose() -> String {
"internal".to_string()
}
/// Response after creating a node-to-node tunnel
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct CreateNodeTunnelResponse {
/// Tunnel name
pub name: String,
/// Source node ID
pub from_node: String,
/// Destination node ID
pub to_node: String,
/// Local port
pub local_port: u16,
/// Remote port
pub remote_port: u16,
/// Exposure level
pub expose: String,
/// Current status
pub status: String,
}
/// Generic success response
#[derive(Debug, Serialize, ToSchema)]
pub struct SuccessResponse {
/// Success message
pub message: String,
}
/// Request to create a temporary access session for an existing tunneled service.
///
/// Used by `zlayer tunnel access <endpoint>` to ask the daemon to bind a local
/// TCP listener that proxies to a remote service. The daemon returns the local
/// address so the CLI can either connect directly (when the daemon and CLI
/// share a host) or open a second hop forwarder.
#[derive(Debug, Deserialize, ToSchema)]
pub struct CreateAccessSessionRequest {
/// Service endpoint to access (e.g. "postgres.service.zlayer" or
/// "host:port"). The daemon resolves this through the overlay network
/// when configured.
pub endpoint: String,
/// Time-to-live in seconds for the session. After this expires the
/// listener is torn down.
#[serde(default = "default_access_ttl")]
pub ttl_secs: u64,
/// Optional local port for the daemon to bind. `None` (or `0`) lets the
/// daemon auto-assign an ephemeral port.
#[serde(default)]
pub local_port: Option<u16>,
}
fn default_access_ttl() -> u64 {
3600
}
/// Response after creating a temporary access session.
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct CreateAccessSessionResponse {
/// Unique session identifier (UUID).
pub session_id: String,
/// Local address the daemon bound for this session, e.g. `127.0.0.1:30042`.
pub local_addr: String,
/// Original endpoint requested.
pub endpoint: String,
/// Unix timestamp at which the session expires.
pub expires_at: u64,
}