Implement opt-in overlay TUN runtime
This commit is contained in:
parent
c2dee50dae
commit
d9728a326d
15 changed files with 2315 additions and 84 deletions
|
|
@ -189,14 +189,25 @@ Current prototype commands:
|
|||
geth overlay plan home
|
||||
geth overlay plan home --cidr 172.22.0.0/24
|
||||
geth overlay join home --secret <resource-secret>
|
||||
geth overlay interface-plan home --platform linux
|
||||
geth overlay up home
|
||||
geth overlay down home
|
||||
geth overlay send home <node> --packet-base64 <ipv4-packet>
|
||||
geth overlay recv home
|
||||
geth overlay leave home
|
||||
|
||||
Current limits:
|
||||
- join/leave are planning stubs; no TUN/Wintun interface is created yet
|
||||
- host network changes must remain explicit opt-in in future versions
|
||||
- overlay up creates a real TUN/Wintun-style L3 device and usually needs
|
||||
privileges or host network entitlements
|
||||
- host network changes are explicit opt-in only
|
||||
- discovery can suggest peers, but never grants overlay access
|
||||
- overlay access must be resource-authorized with overlay.join/overlay.route
|
||||
- all overlay packets must be carried over Iroh, not SSH or another transport
|
||||
|
||||
Bearer invite flow:
|
||||
geth resource create overlay home
|
||||
geth secret bearer create resource:overlay:home --capability overlay.join
|
||||
geth overlay join home --secret <bearer-token>
|
||||
"#;
|
||||
|
||||
const GUIDE_SMOKE_TEST: &str = r#"Minimal smoke test:
|
||||
|
|
@ -540,6 +551,37 @@ pub enum OverlayCommand {
|
|||
Leave {
|
||||
name: String,
|
||||
},
|
||||
InterfacePlan {
|
||||
name: String,
|
||||
#[arg(long)]
|
||||
platform: Option<String>,
|
||||
},
|
||||
Up {
|
||||
name: String,
|
||||
#[arg(long)]
|
||||
bearer_secret: Option<String>,
|
||||
#[arg(long)]
|
||||
mtu: Option<u16>,
|
||||
},
|
||||
Down {
|
||||
name: String,
|
||||
},
|
||||
Peers {
|
||||
name: String,
|
||||
},
|
||||
Send {
|
||||
name: String,
|
||||
node: String,
|
||||
#[arg(long)]
|
||||
packet_base64: String,
|
||||
#[arg(long)]
|
||||
bearer_secret: Option<String>,
|
||||
},
|
||||
Recv {
|
||||
name: String,
|
||||
#[arg(long)]
|
||||
peek: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
|
|
@ -1297,6 +1339,32 @@ fn request_for_command(command: Command) -> Result<ControlRequest> {
|
|||
ControlRequest::OverlayJoin { name, secret, cidr }
|
||||
}
|
||||
OverlayCommand::Leave { name } => ControlRequest::OverlayLeave { name },
|
||||
OverlayCommand::InterfacePlan { name, platform } => {
|
||||
ControlRequest::OverlayInterfacePlan { name, platform }
|
||||
}
|
||||
OverlayCommand::Up {
|
||||
name,
|
||||
bearer_secret,
|
||||
mtu,
|
||||
} => ControlRequest::OverlayUp {
|
||||
name,
|
||||
bearer_secret,
|
||||
mtu,
|
||||
},
|
||||
OverlayCommand::Down { name } => ControlRequest::OverlayDown { name },
|
||||
OverlayCommand::Peers { name } => ControlRequest::OverlayPeers { name },
|
||||
OverlayCommand::Send {
|
||||
name,
|
||||
node,
|
||||
packet_base64,
|
||||
bearer_secret,
|
||||
} => ControlRequest::OverlaySend {
|
||||
name,
|
||||
node,
|
||||
packet_base64,
|
||||
bearer_secret,
|
||||
},
|
||||
OverlayCommand::Recv { name, peek } => ControlRequest::OverlayRecv { name, peek },
|
||||
},
|
||||
Command::Resource {
|
||||
command: ResourceCommand::List,
|
||||
|
|
@ -1989,6 +2057,12 @@ fn print_response(response: ControlResponse, json: bool) -> Result<()> {
|
|||
ControlResponse::OverlayJoined { join } => {
|
||||
println!("overlay: {}", join.plan.name);
|
||||
println!("resource: {}", join.plan.resource);
|
||||
println!("cidr: {}", join.network.cidr);
|
||||
println!(
|
||||
"virtual_ip: {}",
|
||||
join.network.virtual_ip.as_deref().unwrap_or("unassigned")
|
||||
);
|
||||
println!("state: {:?}", join.network.state);
|
||||
println!("enabled: {}", join.enabled);
|
||||
println!("note: {}", join.note);
|
||||
}
|
||||
|
|
@ -2001,6 +2075,99 @@ fn print_response(response: ControlResponse, json: bool) -> Result<()> {
|
|||
println!("stopped: {stopped}");
|
||||
println!("note: {note}");
|
||||
}
|
||||
ControlResponse::OverlayInterfacePlanned { plan } => {
|
||||
println!("overlay: {}", plan.name);
|
||||
println!("platform: {}", plan.platform);
|
||||
println!("interface: {}", plan.interface_name);
|
||||
println!("cidr: {}", plan.cidr);
|
||||
println!(
|
||||
"virtual_ip: {}",
|
||||
plan.virtual_ip.as_deref().unwrap_or("unassigned")
|
||||
);
|
||||
println!("requires_privileges: {}", plan.requires_privileges);
|
||||
for command in plan.commands {
|
||||
println!("command: {command}");
|
||||
}
|
||||
for note in plan.notes {
|
||||
println!("note: {note}");
|
||||
}
|
||||
}
|
||||
ControlResponse::OverlayRuntimeStarted { status } => {
|
||||
println!("overlay: {}", status.name);
|
||||
println!("interface: {}", status.interface_name);
|
||||
println!("virtual_ip: {}", status.virtual_ip);
|
||||
println!("cidr: {}", status.cidr);
|
||||
println!("mtu: {}", status.mtu);
|
||||
println!("packets_from_tun: {}", status.packets_from_tun);
|
||||
println!("packets_to_tun: {}", status.packets_to_tun);
|
||||
println!("packets_to_peers: {}", status.packets_to_peers);
|
||||
if let Some(error) = status.last_error {
|
||||
println!("last_error: {error}");
|
||||
}
|
||||
println!("note: {}", status.note);
|
||||
}
|
||||
ControlResponse::OverlayRuntimeStopped {
|
||||
name,
|
||||
stopped,
|
||||
note,
|
||||
} => {
|
||||
println!("overlay: {name}");
|
||||
println!("stopped: {stopped}");
|
||||
println!("note: {note}");
|
||||
}
|
||||
ControlResponse::OverlayPeers { name, peers, note } => {
|
||||
println!("overlay: {name}");
|
||||
if peers.is_empty() {
|
||||
println!("no overlay peer candidates");
|
||||
} else {
|
||||
for peer in peers {
|
||||
println!(
|
||||
"{}\t{}\t{}\t{}",
|
||||
peer.node_id,
|
||||
peer.endpoint_id.as_deref().unwrap_or("no-endpoint"),
|
||||
peer.virtual_ip.as_deref().unwrap_or("no-virtual-ip"),
|
||||
peer.state
|
||||
);
|
||||
}
|
||||
}
|
||||
println!("note: {note}");
|
||||
}
|
||||
ControlResponse::OverlayPacketSent {
|
||||
peer_node_id,
|
||||
peer_agent_id,
|
||||
endpoint_id,
|
||||
packet,
|
||||
allowed,
|
||||
reason,
|
||||
note,
|
||||
} => {
|
||||
println!("peer: {peer_node_id}");
|
||||
println!("agent: {peer_agent_id}");
|
||||
println!("endpoint: {endpoint_id}");
|
||||
println!("allowed: {allowed}");
|
||||
println!("reason: {reason}");
|
||||
if let Some(packet) = packet {
|
||||
println!("packet: {}", packet.id);
|
||||
println!("size_bytes: {}", packet.size_bytes);
|
||||
}
|
||||
println!("note: {note}");
|
||||
}
|
||||
ControlResponse::OverlayPackets {
|
||||
name,
|
||||
packets,
|
||||
drained,
|
||||
note,
|
||||
} => {
|
||||
println!("overlay: {name}");
|
||||
println!("drained: {drained}");
|
||||
for packet in packets {
|
||||
println!(
|
||||
"{}\t{}\t{}\t{} bytes",
|
||||
packet.id, packet.source_node, packet.destination_node, packet.size_bytes
|
||||
);
|
||||
}
|
||||
println!("note: {note}");
|
||||
}
|
||||
ControlResponse::CasAdded { hash, size_bytes } => {
|
||||
println!("{hash} {size_bytes} bytes");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue