added exit-node list, exit-node start and exit-node stop
This commit is contained in:
parent
0c045dd828
commit
9d0a5289ea
@ -1,5 +1,5 @@
|
||||
use hmac::{Hmac, Mac as HamcMac};
|
||||
use punchnet::{TokenLogin, get_hostname};
|
||||
use punchnet::{ExitNodeConfiguration, TokenLogin, get_hostname};
|
||||
use reqwest::Client;
|
||||
use sdlan_sn_rs::utils::{Mac, Result, SDLanError};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -104,8 +104,8 @@ pub struct LoginData {
|
||||
// pub exit_node: Vec<ExitNode>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ExitNode {
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct ExitNode{
|
||||
pub node_id: u32,
|
||||
pub node_name: String,
|
||||
pub gateway: String,
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
use std::{net::SocketAddr, sync::atomic::Ordering, time::Duration};
|
||||
|
||||
use ipnet::Ipv4Net;
|
||||
use num_enum::TryFromPrimitive;
|
||||
use punchnet::get_edge;
|
||||
use sdlan_sn_rs::utils::{Mac, Result, SDLanError};
|
||||
use punchnet::{LocalConfigInfo, RouteInfo, get_edge, load_configuration, set_route_from_net, store_configuration};
|
||||
use sdlan_sn_rs::{config, utils::{Mac, Result, SDLanError}};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::{net::UdpSocket, time::sleep};
|
||||
|
||||
@ -18,14 +19,39 @@ pub enum InfoFuncCode {
|
||||
Info = 0x00,
|
||||
// query for exit node list,
|
||||
ExitNodeList = 0x01,
|
||||
// set exit node
|
||||
ExitNodeSet = 0x02,
|
||||
ExitNodeStop = 0x03,
|
||||
|
||||
InfoFeedback = 0x80,
|
||||
ExitNodeListFeedback = 0x81,
|
||||
ExitNodeSetFeedback = 0x82,
|
||||
ExitNodeStopFeedback = 0x83,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct SingleExitNodeInfo {
|
||||
pub in_use: bool,
|
||||
pub id: u32,
|
||||
pub name: String,
|
||||
pub gw: String,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct ExitNodeSetFeedback {
|
||||
pub ok: bool,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct ExitNodeSetQuery {
|
||||
pub id: u32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct ExitNodeListFeedback {
|
||||
pub nodes: Vec<String>,
|
||||
pub nodes: Vec<SingleExitNodeInfo>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@ -92,13 +118,54 @@ pub async fn do_query<T: serde::de::DeserializeOwned>(data_type: u8, data: &[u8]
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn query_for_exit_node_stop() {
|
||||
let result = do_query::<ExitNodeSetFeedback>(InfoFuncCode::ExitNodeStop as u8, &[], Duration::from_secs(3)).await;
|
||||
match result {
|
||||
Ok(data) => {
|
||||
if data.ok {
|
||||
println!("set exit-node ok");
|
||||
} else {
|
||||
println!("failed to set exit-node: {}", data.message);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("failed to set exit-node: {}", e.as_str());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub async fn query_for_exit_node_set(nodeid: u32) {
|
||||
let data = ExitNodeSetQuery {
|
||||
id: nodeid,
|
||||
};
|
||||
let data = serde_json::to_vec(&data).unwrap();
|
||||
let result = do_query::<ExitNodeSetFeedback>(InfoFuncCode::ExitNodeSet as u8, &data, Duration::from_secs(3)).await;
|
||||
match result {
|
||||
Ok(data) => {
|
||||
if data.ok {
|
||||
println!("set exit-node ok");
|
||||
} else {
|
||||
println!("failed to set exit-node: {}", data.message);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("failed to set exit-node: {}", e.as_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn query_for_exit_node_list() {
|
||||
let result = do_query::<ExitNodeListFeedback>(InfoFuncCode::ExitNodeList as u8, &[], Duration::from_secs(3)).await;
|
||||
match result {
|
||||
Ok(data) => {
|
||||
println!("exit nodes:");
|
||||
for node in &data.nodes {
|
||||
println!(" {}", node);
|
||||
if node.in_use {
|
||||
println!(" * id: {}, name: {}, gw: {}", node.id, node.name, node.gw);
|
||||
} else {
|
||||
println!(" id: {}, name: {}, gw: {}", node.id, node.name, node.gw);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
@ -154,7 +221,7 @@ pub async fn handle_query_for_info_info() {
|
||||
}
|
||||
|
||||
async fn handle_query_info(udp: &UdpSocket, buf: &[u8], from: SocketAddr) {
|
||||
if buf.len() < 1 {
|
||||
if buf.len() < 3 {
|
||||
return;
|
||||
}
|
||||
let tp = buf[0];
|
||||
@ -163,16 +230,139 @@ async fn handle_query_info(udp: &UdpSocket, buf: &[u8], from: SocketAddr) {
|
||||
eprintln!("invalid type: {}", tp);
|
||||
return;
|
||||
};
|
||||
let size_field = u16::from_be_bytes([buf[1], buf[2]]);
|
||||
if size_field as usize + 3 != buf.len() {
|
||||
// error!("got invalid size");
|
||||
eprintln!("got invalid size");
|
||||
return;
|
||||
}
|
||||
|
||||
match typecode {
|
||||
InfoFuncCode::Info => {
|
||||
send_info_back(udp, from).await;
|
||||
}
|
||||
InfoFuncCode::ExitNodeList => {
|
||||
send_exit_node_back(udp, from).await;
|
||||
}
|
||||
InfoFuncCode::ExitNodeSet => {
|
||||
if let Ok(data) = serde_json::from_slice::<ExitNodeSetQuery>(&buf[3..]) {
|
||||
handle_set_exit_node(udp, from, data).await;
|
||||
}
|
||||
}
|
||||
InfoFuncCode::ExitNodeStop => {
|
||||
println!("got exit node stop");
|
||||
handle_stop_exit_node(udp, from).await;
|
||||
}
|
||||
_other => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn send_exit_node_back(udp: &UdpSocket, from: SocketAddr) {
|
||||
let config = load_configuration();
|
||||
|
||||
let mut temp = Vec::new();
|
||||
for (id, node) in &config.exit_node {
|
||||
temp.push(SingleExitNodeInfo {
|
||||
name: node.node_name.clone(),
|
||||
gw: node.gateway.clone(),
|
||||
id: node.node_id,
|
||||
in_use: node.in_use,
|
||||
})
|
||||
}
|
||||
let res = ExitNodeListFeedback {
|
||||
nodes: temp
|
||||
};
|
||||
let value = serde_json::to_string(&res).unwrap();
|
||||
|
||||
let mut content = Vec::with_capacity(value.len() + 3);
|
||||
content.push(InfoFuncCode::ExitNodeListFeedback as u8);
|
||||
|
||||
let size = value.len() as u16;
|
||||
let size_buf = size.to_be_bytes();
|
||||
|
||||
content.extend_from_slice(&size_buf);
|
||||
content.extend_from_slice(value.as_bytes());
|
||||
udp.send_to(content.as_slice(), from).await;
|
||||
}
|
||||
|
||||
fn handle_set_exit_node_inner(data: u32) -> std::result::Result<LocalConfigInfo, String>{
|
||||
let configuration = load_configuration();
|
||||
|
||||
let Some(data) = configuration.exit_node.get(&data) else {
|
||||
return Err("no such id found".to_string());
|
||||
};
|
||||
let Ok(ip) = data.gateway.parse() else {
|
||||
return Err("no such id found".to_string());
|
||||
};
|
||||
|
||||
let net = "0.0.0.0/0".parse::<Ipv4Net>().unwrap();
|
||||
set_route_from_net(vec![RouteInfo{
|
||||
net,
|
||||
gw: ip,
|
||||
}]);
|
||||
|
||||
return Ok(configuration);
|
||||
}
|
||||
|
||||
async fn _handle_set_exit_node(udp: &UdpSocket, from: SocketAddr, data:Option<ExitNodeSetQuery>, result_code: InfoFuncCode) {
|
||||
let result = if data.is_none() {
|
||||
let mut configuration = load_configuration();
|
||||
for (node, value) in configuration.exit_node.iter_mut() {
|
||||
value.in_use = false;
|
||||
}
|
||||
store_configuration(&configuration);
|
||||
set_route_from_net(vec![]);
|
||||
|
||||
ExitNodeSetFeedback {
|
||||
ok: true,
|
||||
message: "ok".to_string(),
|
||||
}
|
||||
} else {
|
||||
let data = data.unwrap();
|
||||
let result = match handle_set_exit_node_inner(data.id) {
|
||||
Ok(mut configuration) => {
|
||||
if let Some(conf) = configuration.exit_node.get_mut(&data.id) {
|
||||
conf.in_use = true;
|
||||
}
|
||||
store_configuration(&configuration);
|
||||
ExitNodeSetFeedback {
|
||||
ok: true,
|
||||
message: "ok".to_string(),
|
||||
}
|
||||
}
|
||||
Err(estr) => {
|
||||
ExitNodeSetFeedback {
|
||||
ok: false,
|
||||
message: estr,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
result
|
||||
};
|
||||
|
||||
let value = serde_json::to_string(&result).unwrap();
|
||||
|
||||
let mut content = Vec::with_capacity(value.len() + 3);
|
||||
content.push(result_code as u8);
|
||||
|
||||
let size = value.len() as u16;
|
||||
let size_buf = size.to_be_bytes();
|
||||
|
||||
content.extend_from_slice(&size_buf);
|
||||
content.extend_from_slice(value.as_bytes());
|
||||
udp.send_to(content.as_slice(), from).await;
|
||||
}
|
||||
|
||||
async fn handle_stop_exit_node(udp: &UdpSocket, from: SocketAddr) {
|
||||
_handle_set_exit_node(udp, from, None, InfoFuncCode::ExitNodeStopFeedback).await;
|
||||
}
|
||||
|
||||
async fn handle_set_exit_node(udp: &UdpSocket, from: SocketAddr, data:ExitNodeSetQuery) {
|
||||
_handle_set_exit_node(udp, from, Some(data), InfoFuncCode::ExitNodeSetFeedback).await;
|
||||
}
|
||||
|
||||
async fn send_info_back(udp: &UdpSocket, from: SocketAddr) {
|
||||
let edge = get_edge();
|
||||
let ip = edge.device_config.get_ip();
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
mod api;
|
||||
mod local_udp_info;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::fs::OpenOptions;
|
||||
use std::process;
|
||||
|
||||
use clap::Parser;
|
||||
use punchnet::ExitNodeConfiguration;
|
||||
use punchnet::store_configuration;
|
||||
use std::env;
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
@ -50,6 +53,8 @@ use crate::api::LoginResponse;
|
||||
use crate::api::TEST_PREFIX;
|
||||
use crate::local_udp_info::handle_query_for_info_info;
|
||||
use crate::local_udp_info::query_for_exit_node_list;
|
||||
use crate::local_udp_info::query_for_exit_node_set;
|
||||
use crate::local_udp_info::query_for_exit_node_stop;
|
||||
use crate::local_udp_info::query_for_info;
|
||||
|
||||
const APP_USER_ENV_NAME: &str = "PUNCH_USER";
|
||||
@ -347,8 +352,12 @@ fn main() {
|
||||
ExitNodeCmd::List => {
|
||||
query_for_exit_node_list().await;
|
||||
}
|
||||
ExitNodeCmd::Start(info) => {}
|
||||
ExitNodeCmd::Stop => {}
|
||||
ExitNodeCmd::Start(info) => {
|
||||
query_for_exit_node_set(info.id).await;
|
||||
}
|
||||
ExitNodeCmd::Stop => {
|
||||
query_for_exit_node_stop().await;
|
||||
}
|
||||
}
|
||||
});
|
||||
process::exit(0);
|
||||
@ -425,7 +434,7 @@ fn main() {
|
||||
run_it(cmd, client_id, allow_routing, mac, system, version);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("failed to daemonize");
|
||||
eprintln!("failed to daemonize: {}", e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -436,6 +445,24 @@ fn main() {
|
||||
run_it(cmd, client_id, allow_routing, mac, system, version);
|
||||
}
|
||||
|
||||
fn record_exit_node(connect_info: &ConnectData) {
|
||||
let mut local_configuration = load_configuration();
|
||||
let mut temp = HashMap::new();
|
||||
for node in &connect_info.exit_node {
|
||||
temp.insert(node.node_id, ExitNodeConfiguration {
|
||||
in_use: false,
|
||||
node_id: node.node_id,
|
||||
node_name: node.node_name.clone(),
|
||||
gateway: node.gateway.clone(),
|
||||
target_network: node.target_network.clone(),
|
||||
});
|
||||
}
|
||||
local_configuration.exit_node = temp;
|
||||
if let Err(e) = store_configuration(&local_configuration) {
|
||||
error!("failed to store configuration");
|
||||
}
|
||||
}
|
||||
|
||||
fn run_it(
|
||||
cmd: CommandLineInput2,
|
||||
client_id: String,
|
||||
@ -456,6 +483,8 @@ fn run_it(
|
||||
let connect_info = parse_connect_result(
|
||||
connect(TEST_PREFIX, &client_id, &remembered.access_token).await,
|
||||
);
|
||||
|
||||
record_exit_node(&connect_info);
|
||||
daemonize_me(
|
||||
rtinfo.allow_routing || allow_routing,
|
||||
connect_info,
|
||||
@ -490,6 +519,8 @@ fn run_it(
|
||||
let connect_info = parse_connect_result(
|
||||
connect(TEST_PREFIX, &client_id, &remembered.access_token).await,
|
||||
);
|
||||
|
||||
record_exit_node(&connect_info);
|
||||
daemonize_me(
|
||||
tk.allow_routing || allow_routing,
|
||||
connect_info,
|
||||
|
||||
@ -874,7 +874,7 @@ pub fn get_install_channel() -> String {
|
||||
}
|
||||
|
||||
fn check_has_resolvectl() -> bool {
|
||||
return false;
|
||||
// return false;
|
||||
let res = Command::new("resolvectl").arg("status").output();
|
||||
if let Ok(_) = res {
|
||||
true
|
||||
@ -912,7 +912,8 @@ fn add_resolvectl(name: &str, network_domain: &str) -> Result<()> {
|
||||
if !Command::new("resolvectl")
|
||||
.arg("domain")
|
||||
.arg(name)
|
||||
.arg(format!("~{}", network_domain))
|
||||
// .arg(format!("~{}", network_domain))
|
||||
.arg("~.")
|
||||
.output()?.status.success() {
|
||||
error!("failed to run resolvectl domain");
|
||||
return Err(SDLanError::IOError("failed to resolvectl domain".to_owned()))
|
||||
|
||||
@ -49,8 +49,8 @@ pub enum ExitNodeCmd {
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct ExitNodeInfo {
|
||||
#[arg(short, long, default_value="")]
|
||||
pub name: String,
|
||||
#[arg(short, long)]
|
||||
pub id: u32,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
|
||||
@ -1,15 +1,24 @@
|
||||
use std::path::Path;
|
||||
use std::{collections::HashMap, path::Path, sync::atomic::AtomicBool};
|
||||
|
||||
use sdlan_sn_rs::utils::{Mac, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{generate_mac_address, get_base_dir};
|
||||
use crate::{ExitNodeInfo, generate_mac_address, get_base_dir};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct ExitNodeConfiguration {
|
||||
pub in_use: bool,
|
||||
pub node_id: u32,
|
||||
pub node_name: String,
|
||||
pub gateway: String,
|
||||
pub target_network: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct LocalConfigInfo {
|
||||
pub allow_routing: Option<bool>,
|
||||
pub mac: Option<[u8; 6]>
|
||||
pub mac: Option<[u8; 6]>,
|
||||
pub exit_node: HashMap<u32, ExitNodeConfiguration>,
|
||||
}
|
||||
|
||||
pub fn store_configuration(config: &LocalConfigInfo) -> Result<()> {
|
||||
@ -52,6 +61,7 @@ pub fn load_configuration() -> LocalConfigInfo {
|
||||
let config = LocalConfigInfo {
|
||||
allow_routing: Some(false),
|
||||
mac,
|
||||
exit_node: HashMap::new(),
|
||||
};
|
||||
let _ = store_configuration(&config);
|
||||
config
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user