diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..dbc530e --- /dev/null +++ b/docs/api.md @@ -0,0 +1,39 @@ +# sdlan web api文档 +sdlan为前端提供了若干api。其中,所有的api都使用POST方法,将数据以json消息体的方式提交给服务端。服务端根据具体处理结果,返回json数据。 + +## 1. 返回消息体 +sdlan api的所有返回的消息体都遵循如下格式: + +```json +{ + "code": $int, + "message": $object, + "error": $string, +} +``` + +其中,code为0代表请求成功,返回的内容存放在`message`字段,`error`字段为空字符串;反之,如果请求失败,则`code`不为0,同时,`message`为空字符串,`error`字段为错误描述字符串。 + +在后面的描述中,如果请求成功,则默认返回的`code`为0,`error`为空字符串,而`message`会写明结构;如果返回失败,则`message`为空字符串,`code`和`error`会根据情况标明。 + +## 2. 消息请求参数说明 +在实际操作过程中,用户会需要先注册,注册成功之后,需要先使用用户名和密码进行登录,密码验证成功之后,后台会返回一个token,该token有效期为一个小时,在登录成功之后所有其他的接口(即除了register和login接口),在发起请求的时候,都需要在请求头的header里面带上`token`,否则会权限热症失败,返回`code`为400,`error`为`“unauthorized”` + +## 3. 实际接口 +实际接口分成几个类别列举。 + +### 4.1. 用户操作 +用户操作包括用户注册,登录,登出,创建/删除/查看register-token(用于节点登录时填写的token);修改密码等一系列关于用于的操作。 + +### 4.2. 网络操作 +网络操作主要包括网络的创建、列举、删除、路由(给网络添加、删除一系列路由信息)等操作。 + +### 4.3. 节点操作 +节点操作包括对节点的授权、取消授权、在网络之间移动等操作。 + +#### 4.3.1 授权节点 +该接口用于对未授权的节点进行授权操作。 + +``` +POST /peer/authorize +``` diff --git a/src/config.rs b/src/config.rs index cc2c3f6..727efb0 100644 --- a/src/config.rs +++ b/src/config.rs @@ -3,7 +3,7 @@ pub const FLAGS_TYPE_MASK: u16 = 0x001f; pub const FLAGS_BITS_MASK: u16 = 0xffe0; // common头的flags里面的flag,可以组合 -// 表示从SN发送过来的REGISTER_SUPER消息,主要用于SN注册 +// 表示从SN主动发送到其他SN的消息 pub const SDLNA_FLAGS_FEDERATION: u16 = 0x0010; pub const SDLAN_FLAGS_FROM_SN: u16 = 0x0020; pub const SDLAN_FLAGS_SOCKET: u16 = 0x0040; diff --git a/src/packet/command.rs b/src/packet/command.rs index ea4fef5..5398da3 100644 --- a/src/packet/command.rs +++ b/src/packet/command.rs @@ -5,8 +5,7 @@ use serde_repr::{Deserialize_repr, Serialize_repr}; #[derive(Debug, PartialEq, Serialize_repr, Deserialize_repr, Copy, Clone)] #[repr(u8)] pub enum CommandType { - AuthorizePeer, - MovePeer, + MovePeer = 1, } #[derive(Serialize, Deserialize)] @@ -15,6 +14,16 @@ pub struct Command { pub message: Value, } +#[derive(Serialize, Deserialize)] +pub struct MovePeerCommandReq { + pub from_id: String, + pub to_id: String, + pub peer_id: String, + pub new_ip: u32, + pub net_bit_len: u8, + pub user_id: u64, +} + #[derive(Serialize, Deserialize)] pub struct CommandResp { cmd_type: CommandType, diff --git a/src/packet/common.rs b/src/packet/common.rs index a91c3f0..299f6ce 100644 --- a/src/packet/common.rs +++ b/src/packet/common.rs @@ -11,7 +11,11 @@ use crate::utils::*; pub struct Common<'a> { pub packet_id: u16, pub version: u8, + // client's uuid pub id: &'a str, + + pub token: u64, + pub ttl: u8, // packet type pub pc: PacketType, @@ -25,6 +29,8 @@ impl<'a> Common<'a> { encode_u8(&mut result, self.version); encode_buf_without_size(&mut result, &self.id.as_bytes(), 32); + // result.extend_from_slice(self.id.as_bytes()); + result.extend_from_slice(&self.token.to_be_bytes()); // encode_buf_with_size_1(&mut result, self.id.as_bytes()); encode_u8(&mut result, self.ttl); @@ -37,10 +43,11 @@ impl<'a> Common<'a> { result } - pub fn from_slice(value: &'a [u8]) -> Result<(Common<'a>, &'a [u8])> { - let id_len = 32; + pub fn from_slice(value: &'a [u8]) -> Result<(Common, &'a [u8])> { + const id_len: usize = 32; + const token_len: usize = 8; - if value.len() < 7 + id_len { + if value.len() < 7 + id_len + token_len { return Err("common header length error".into()); } let packet_id = u16::from_be_bytes(value[0..2].try_into().unwrap()); @@ -51,26 +58,36 @@ impl<'a> Common<'a> { Ok(s) => s, Err(e) => return Err(SDLanError::ConvertError(e.to_string())), }; + // let id = u64::from_be_bytes(v1); id = id.trim_end_matches('\0'); - let ttl = value[3 + id_len]; - let flags = BigEndian::read_u16(&value[4 + id_len..6 + id_len]); - let pc = value[6 + id_len]; + + let token = u64::from_be_bytes( + value[3 + id_len..3 + id_len + token_len] + .try_into() + .unwrap(), + ); + + let ttl = value[3 + id_len + token_len]; + let flags = BigEndian::read_u16(&value[4 + id_len + token_len..6 + id_len + token_len]); + let pc = value[6 + id_len + token_len]; let common = Self { packet_id, version, id, ttl, + token, pc: pc.into(), flags: flags, }; - Ok((common, &value[7 + id_len..])) + Ok((common, &value[7 + id_len + token_len..])) } pub fn from_old_common(cmn: &'a Common) -> Self { return Common { packet_id: cmn.packet_id, id: cmn.id, + token: cmn.token, version: cmn.version, ttl: cmn.ttl, pc: cmn.pc, @@ -82,6 +99,7 @@ impl<'a> Common<'a> { return Common { packet_id: 0, id, + token: 0, version: 1, ttl: 2, pc: PacketType::PKTInvalid, @@ -169,11 +187,13 @@ mod test { packet_id: 0, version: 0, id, + token: 0, ttl: 2, pc: 1.into(), flags: 0, }; let value1 = common.encode(); + println!("value1.len: {}", value1.len()); let (common2, _) = Common::from_slice(&value1).unwrap(); println!("common2 = {:?}", common2); assert_eq!(common.id, common2.id); diff --git a/src/packet/register_super.rs b/src/packet/register_super.rs index 2384c51..d35b92e 100644 --- a/src/packet/register_super.rs +++ b/src/packet/register_super.rs @@ -20,9 +20,8 @@ pub struct RegisterSuper<'a> { // 自身的公钥 pub pub_key: String, - // user's token, can be used to specify a user - pub token: &'a str, + // pub token: &'a str, } #[cfg(test)] @@ -74,7 +73,7 @@ mod test { net_bit_len: 24, }, pub_key: "public key".to_string(), - token: "user's token", + // token: "user's token", }; let res = serde_json::to_string(&pkt1).unwrap(); println!("unmarshaled as {}", res); @@ -87,6 +86,7 @@ mod test { packet_id: 0, version: 1, id: "asxalex", + token: 0, ttl: 128, pc: PacketType::PKTRegisterSuper, flags: config::SDLAN_FLAGS_FROM_SN, @@ -112,7 +112,7 @@ mod test { net_bit_len: 24, }, pub_key: "public key".to_string(), - token: "user's token", + // token: "user's token", }; (cmn1, pkt1) } @@ -147,7 +147,7 @@ mod test { assert_eq!(pkt1.dev_addr.net_addr(), pkt2.dev_addr.net_addr(),); assert_eq!(pkt1.dev_addr.net_bit_len(), pkt2.dev_addr.net_bit_len()); assert_eq!(pkt1.pub_key, pkt2.pub_key); - assert_eq!(pkt1.token, pkt2.token); + // assert_eq!(pkt1.token, pkt2.token); } #[test] diff --git a/src/peer.rs b/src/peer.rs index 7ac1935..4676c89 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -1,11 +1,13 @@ #![allow(unused)] use super::utils::Result; use dashmap::DashMap; +use dashmap::DashSet; use futures::future::BoxFuture; use serde::{Deserialize, Serialize}; use sqlx::prelude::FromRow; use std::default::Default; use std::future::Future; +use std::hash::Hasher; use std::sync::atomic::{AtomicU32, AtomicU64, AtomicU8, Ordering}; use std::sync::RwLock; @@ -197,6 +199,7 @@ use crate::utils::SDLanError; use std::pin::Pin; pub struct PeerMap { pub peers: DashMap>, + // from client's uuid, to the // ip to peer's uuid, the ip is the logical ip // of tun // pub peer_ip_map: DashMap, @@ -264,6 +267,103 @@ impl PeerMap { } } +#[derive(Debug)] +pub struct EdgeInfo { + pub edges: DashSet, + ip_to_edge_id: DashMap, +} + +impl Default for EdgeInfo { + fn default() -> Self { + Self::new() + } +} + +impl EdgeInfo { + pub fn new() -> Self { + Self { + edges: DashSet::new(), + ip_to_edge_id: DashMap::new(), + } + } + + // purge peer in self and in PeerMap, together + pub fn purge_peer(&self, id: &str, pm: &PeerMap) { + if let Some((_k, v)) = pm.peers.remove(id) { + let ip = v.dev_addr.net_addr(); + self.ip_to_edge_id.remove(&ip); + } + self.edges.remove(id); + } + + pub fn unbind_peer(&self, id: &str, ip: u32) { + self.edges.remove(id); + if ip != 0 { + self.ip_to_edge_id.remove(&ip); + } + } + + pub fn get_peer_with_id<'a>(&self, id: &'a str, pm: &'a PeerMap) -> Option> { + if !self.edges.contains(id) { + return None; + } else { + if let Some(p) = pm.peers.get(id) { + Some(p.clone()) + } else { + // edge conatains, but global peermap does not + // remove it in edges + self.edges.remove(id); + None + } + } + } + + pub fn iter_peer_with_id<'a, F>(&'a self, pm: &'a PeerMap, f: F) -> Option<(String, Arc)> + where + F: Fn(&Arc) -> bool, + { + for id in self.edges.iter() { + if let Some(temp) = pm.peers.get(&*id) { + if f(&temp) { + return Some((id.to_owned(), temp.clone())); + } + } + } + None + } + + pub fn get_peer_with_ip(&self, ip: u32, pm: &PeerMap) -> Option> { + if let Some(id) = self.ip_to_edge_id.get(&ip) { + if let Some(p) = pm.peers.get(&*id) { + return Some(p.clone()); + } + } + None + } + + pub fn contains(&self, id: &str) -> bool { + self.edges.contains(id) + } + + pub fn insert_peer(&self, ip: u32, id: String) { + if ip != 0 { + self.ip_to_edge_id.insert(ip, id.clone()); + } + self.edges.insert(id); + } + + // 重新绑定一个id + pub fn rebind_peer_ip(&self, ip: u32, oldid: &str, newid: &str, pm: &PeerMap) { + if let Some((_, v)) = pm.peers.remove(oldid) { + pm.peers.insert(newid.to_owned(), v); + } + self.ip_to_edge_id.remove(&ip); + self.ip_to_edge_id.insert(ip, newid.to_owned()); + self.edges.remove(oldid); + self.edges.insert(newid.to_owned()); + } +} + #[cfg(test)] mod test { use crate::config::AF_INET; diff --git a/src/utils/error.rs b/src/utils/error.rs index 9224fb6..ce8cc51 100644 --- a/src/utils/error.rs +++ b/src/utils/error.rs @@ -1,10 +1,12 @@ use std::{convert::From, net::AddrParseError, string::ParseError}; +use aes::cipher::typenum::IsLessOrEqual; + pub type Result = std::result::Result; #[derive(Debug)] pub enum SDLanError { - IOError(std::io::Error), + IOError(String), NormalError(&'static str), ConvertError(String), SerializeError(String), @@ -12,9 +14,22 @@ pub enum SDLanError { DBError(String), } +impl SDLanError { + pub fn as_str(&self) -> &str { + match *self { + Self::IOError(ref e) => e, + Self::NormalError(ref s) => s, + Self::ConvertError(ref e) => e, + Self::SerializeError(ref e) => e, + Self::EncryptError(ref e) => e, + Self::DBError(ref e) => e, + } + } +} + impl From for SDLanError { fn from(value: std::io::Error) -> Self { - Self::IOError(value) + Self::IOError(value.to_string()) } } diff --git a/src/utils/helper.rs b/src/utils/helper.rs index b47ae06..6a585d1 100644 --- a/src/utils/helper.rs +++ b/src/utils/helper.rs @@ -31,7 +31,15 @@ impl MyDashMap { } } -use std::time::{SystemTime, UNIX_EPOCH}; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; + +pub fn get_timestamp_after_duration(d: Duration) -> u64 { + if let Some(t) = SystemTime::now().checked_add(d) { + t.duration_since(UNIX_EPOCH).unwrap().as_secs() + } else { + 0 + } +} pub fn get_current_timestamp() -> u64 { SystemTime::now() .duration_since(UNIX_EPOCH) diff --git a/src/utils/myuuid.rs b/src/utils/myuuid.rs index 7c53a95..ddc4827 100644 --- a/src/utils/myuuid.rs +++ b/src/utils/myuuid.rs @@ -3,3 +3,11 @@ use uuid::Uuid; pub fn gen_uuid() -> String { format!("{:032x}", Uuid::new_v4().as_u128()) } + +pub fn gen_uuid_u64() -> u64 { + (Uuid::new_v4().as_u128() >> 64) as u64 +} + +pub fn gen_uuid_u128() -> u128 { + Uuid::new_v4().as_u128() +}