1
0
mirror of https://github.com/fumiama/WireGold.git synced 2026-06-20 02:16:17 +08:00

完善注释

This commit is contained in:
fumiama
2021-10-25 19:29:59 +08:00
parent e29d5b2f48
commit fe6abd3898
10 changed files with 132 additions and 61 deletions

View File

@@ -1,7 +1,7 @@
package head
// map[peerip]endpoint
// Notify 是 map[peerip]endpoint
type Notify map[string]string
// peerips array
// Query 是 peerips 组成的数组
type Query []string

View File

@@ -2,17 +2,31 @@ package head
import "encoding/json"
// Packet 是发送和接收的最小单位
type Packet struct {
DataSZ uint32
Proto uint8
TTL uint8
// DataSZ len(Data)
DataSZ uint32
// Proto 详见 head
Proto uint8
// TTL is time to live
TTL uint8
// SrcPort 源端口
SrcPort uint16
// DstPort 目的端口
DstPort uint16
Src string
Dst string
Data []byte
// Src 源 ip
Src string
// Dst 目的 ip
Dst string
// Hash 使用 BLAKE2 生成加密前 Packet 的摘要
// 生成时 Hash 全 0
// https://github.com/minio/blake2b-simd
Hash [32]byte
// Data 承载的数据
Data []byte
}
// NewPacket 生成一个新包
func NewPacket(proto uint8, srcPort uint16, dstPort uint16, data []byte) *Packet {
return &Packet{
Proto: proto,
@@ -23,10 +37,14 @@ func NewPacket(proto uint8, srcPort uint16, dstPort uint16, data []byte) *Packet
}
}
// UnMashal 将 data 的数据解码到自身
// 同时通过 Hash 验证数据完整性
func (p *Packet) UnMashal(data []byte) error {
return json.Unmarshal(data, p)
}
// Mashal 将自身数据编码为 []byte
// 同时生成 Hash
func (p *Packet) Mashal(src string, dst string) ([]byte, error) {
p.DataSZ = uint32(len(p.Data))
p.Src = src

View File

@@ -1,5 +1,6 @@
package head
// Proto 类型定义
const (
ProtoHello uint8 = iota
ProtoNotify

View File

@@ -3,11 +3,18 @@ package link
import "net"
var (
// 本机私钥
// 利用 Curve25519 生成
// https://pkg.go.dev/golang.org/x/crypto/curve25519
// https://www.zhihu.com/question/266758647
privKey [32]byte
me net.IP
myend *net.UDPAddr
// 本机虚拟 ip
me net.IP
// 本机 endpoint
myend *net.UDPAddr
)
// SetMyself 设置本机参数
func SetMyself(privateKey [32]byte, myIP string, myEndpoint string) {
privKey = privateKey
var err error
@@ -22,10 +29,14 @@ func SetMyself(privateKey [32]byte, myIP string, myEndpoint string) {
}
}
// Encode 使用 ChaCha20-Poly1305 AEAD 对称加密加密
// https://pkg.go.dev/golang.org/x/crypto/chacha20poly1305
func (l *Link) Encode(b []byte) (eb []byte, err error) {
return b, nil
}
// Encode 使用 ChaCha20-Poly1305 AEAD 对称加密解密
// https://pkg.go.dev/golang.org/x/crypto/chacha20poly1305
func (l *Link) Decode(b []byte) (db []byte, err error) {
return b, nil
}

View File

@@ -9,16 +9,29 @@ import (
"github.com/sirupsen/logrus"
)
// Link 是本机到 peer 的连接抽象
type Link struct {
PubicKey [32]byte
EndPoint string
KeepAlive int64
pipe chan *head.Packet
peerip net.IP
endpoint *net.UDPAddr
allowedips []*net.IPNet
hasKeepRuning bool
status int
// peer 的公钥
pubk [32]byte
// peer 的公网 ip:port
pep string
// 决定本机是否定时向 peer 发送 hello 保持 NAT。
// 以秒为单位,小于等于 0 不发送
keepalive int64
// 收到的包的队列
pipe chan *head.Packet
// peer 的虚拟 ip
peerip net.IP
// peer 的公网 endpoint
endpoint *net.UDPAddr
// 本机允许接收/发送的 ip 网段
allowedips []*net.IPNet
// 是否已经调用过 keepAlive
haskeepruning bool
// 是否允许转发
allowtrans bool
// 连接的状态,详见下方 const
status int
}
const (
@@ -28,11 +41,15 @@ const (
)
var (
// 本机活跃的所有连接
connections = make(map[string]*Link)
connmapmu sync.RWMutex
myconn *net.UDPConn
// 读写同步锁
connmapmu sync.RWMutex
// 本机监听的 endpoint
myconn *net.UDPConn
)
// Connect 初始化与 peer 的连接
func Connect(peer string) (*Link, error) {
p, ok := IsInPeer(net.ParseIP(peer).String())
if ok {
@@ -42,6 +59,7 @@ func Connect(peer string) (*Link, error) {
return nil, errors.New("peer not exist")
}
// Close 关闭到 peer 的连接
func (l *Link) Close() {
connmapmu.Lock()
delete(connections, l.peerip.String())
@@ -49,10 +67,12 @@ func (l *Link) Close() {
l.status = LINK_STATUS_DOWN
}
// Read 从 peer 收包
func (l *Link) Read() *head.Packet {
return <-l.pipe
}
// Write 向 peer 发包
func (l *Link) Write(p *head.Packet) (n int, err error) {
p.Data, err = l.Encode(p.Data)
if err == nil {
@@ -60,7 +80,7 @@ func (l *Link) Write(p *head.Packet) (n int, err error) {
d, err = p.Mashal(me.String(), l.peerip.String())
logrus.Debugln("[link] write data", string(d))
if err == nil {
n, err = myconn.WriteToUDP(d, l.endpoint)
n, err = myconn.WriteToUDP(d, l.NextHop(l.peerip).endpoint)
}
}
return

View File

@@ -7,6 +7,7 @@ import (
"github.com/sirupsen/logrus"
)
// 监听本机 endpoint
func listen() (conn *net.UDPConn, err error) {
conn, err = net.ListenUDP("udp", myend)
if err == nil {
@@ -30,41 +31,47 @@ func listen() (conn *net.UDPConn, err error) {
p, ok := IsInPeer(packet.Src)
logrus.Infoln("[link] recv from endpoint", addr, "src", packet.Src, "dst", packet.Dst)
logrus.Debugln("[link] recv:", string(lbf))
if p.EndPoint == "" || p.EndPoint != addr.String() {
if p.pep == "" || p.pep != addr.String() {
logrus.Infoln("[link] set endpoint of peer", p.peerip, "to", addr.String())
p.endpoint = addr
p.EndPoint = addr.String()
p.pep = addr.String()
}
if ok && p.Accept(net.IP(packet.Dst)) {
packet.Data, err = p.Decode(packet.Data)
if err == nil {
switch packet.Proto {
case head.ProtoHello:
switch p.status {
case LINK_STATUS_DOWN:
_, _ = p.Write(head.NewPacket(head.ProtoHello, 0, 0, nil))
logrus.Infoln("[link] send hello ack packet")
p.status = LINK_STATUS_HALFUP
case LINK_STATUS_HALFUP:
p.status = LINK_STATUS_UP
case LINK_STATUS_UP:
if ok {
if p.IsToMe(net.ParseIP(packet.Dst)) {
packet.Data, err = p.Decode(packet.Data)
if err == nil {
switch packet.Proto {
case head.ProtoHello:
switch p.status {
case LINK_STATUS_DOWN:
_, _ = p.Write(head.NewPacket(head.ProtoHello, 0, 0, nil))
logrus.Infoln("[link] send hello ack packet")
p.status = LINK_STATUS_HALFUP
case LINK_STATUS_HALFUP:
p.status = LINK_STATUS_UP
case LINK_STATUS_UP:
break
}
case head.ProtoNotify:
logrus.Infoln("[link] recv notify")
onNotify(&packet)
case head.ProtoQuery:
logrus.Infoln("[link] recv query")
onQuery(&packet)
case head.ProtoData:
logrus.Infoln("[link] deliver to", p.peerip)
p.pipe <- &packet
default:
break
}
case head.ProtoNotify:
logrus.Infoln("[link] recv notify")
onNotify(&packet)
case head.ProtoQuery:
logrus.Infoln("[link] recv query")
onQuery(&packet)
case head.ProtoData:
logrus.Infoln("[link] deliver to", p.peerip)
p.pipe <- &packet
default:
break
}
} else if p.Accept(net.ParseIP(packet.Dst)) && p.allowtrans {
// 转发
p.Write(&packet)
logrus.Infoln("[link] trans")
}
} else {
logrus.Infoln("[link] packet to", packet.Dst, "is refused")
logrus.Infoln("[link] packet to", packet.Dst, "is refused", "(me:", me, ")")
}
}
}
@@ -74,6 +81,7 @@ func listen() (conn *net.UDPConn, err error) {
return
}
// 从 conn 读取 sz 字节数据
func readAll(conn *net.UDPConn, sz int) ([]byte, error) {
i := 0
n := 0

View File

@@ -8,11 +8,12 @@ import (
"github.com/fumiama/WireGold/gold/head"
)
// 保持 NAT
func (l *Link) keepAlive() {
if l.KeepAlive > 0 && !l.hasKeepRuning {
l.hasKeepRuning = true
if l.keepalive > 0 && !l.haskeepruning {
l.haskeepruning = true
go func() {
t := time.NewTicker(time.Second * time.Duration(l.KeepAlive))
t := time.NewTicker(time.Second * time.Duration(l.keepalive))
for range t.C {
_, _ = l.Write(head.NewPacket(head.ProtoHello, 0, 0, nil))
logrus.Infoln("[link.nat] send keep alive packet")
@@ -22,10 +23,12 @@ func (l *Link) keepAlive() {
}
}
// 收到询问包的处理函数
func onQuery(packet *head.Packet) {
// TODO: 完成data解包与notify分发
}
// 收到通告包的处理函数
func onNotify(packet *head.Packet) {
// TODO: 完成data解包与endpoint注册
}

View File

@@ -6,7 +6,8 @@ import (
"github.com/fumiama/WireGold/gold/head"
)
func AddPeer(peerip string, pubicKey [32]byte, endPoint string, allowedIPs []string, keepAlive int64) (l *Link) {
// AddPeer 添加一个 peer
func AddPeer(peerip string, pubicKey [32]byte, endPoint string, allowedIPs []string, keepAlive int64, allowTrans bool) (l *Link) {
peerip = net.ParseIP(peerip).String()
var ok bool
l, ok = IsInPeer(peerip)
@@ -14,17 +15,18 @@ func AddPeer(peerip string, pubicKey [32]byte, endPoint string, allowedIPs []str
return
}
l = &Link{
PubicKey: pubicKey,
KeepAlive: keepAlive,
pipe: make(chan *head.Packet, 32),
peerip: net.ParseIP(peerip),
pubk: pubicKey,
keepalive: keepAlive,
pipe: make(chan *head.Packet, 32),
peerip: net.ParseIP(peerip),
allowtrans: allowTrans,
}
if endPoint != "" {
e, err := net.ResolveUDPAddr("udp", endPoint)
if err != nil {
panic(err)
}
l.EndPoint = endPoint
l.pep = endPoint
l.endpoint = e
}
if allowedIPs != nil {
@@ -42,6 +44,7 @@ func AddPeer(peerip string, pubicKey [32]byte, endPoint string, allowedIPs []str
return
}
// IsInPeer 查找 peer 是否已经在册
func IsInPeer(peer string) (p *Link, ok bool) {
connmapmu.RLock()
p, ok = connections[peer]

View File

@@ -2,6 +2,7 @@ package link
import "net"
// Accept 判断是否应当接受 ip 发来的包
func (l *Link) Accept(ip net.IP) bool {
for _, cidr := range l.allowedips {
if cidr.Contains(ip) {
@@ -11,6 +12,12 @@ func (l *Link) Accept(ip net.IP) bool {
return false
}
func NextHop(ip net.IP) *Link {
return nil
// IsToMe 判断是否是发给自己的包
func (l *Link) IsToMe(ip net.IP) bool {
return ip.Equal(me)
}
// NextHop 得到前往 ip 的下一跳的 link
func (l *Link) NextHop(ip net.IP) *Link {
return l
}