node

package
v0.0.0-...-da509b5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 16, 2025 License: AGPL-3.0 Imports: 22 Imported by: 0

README

P2P 端点

服务节点搜寻(公域)

  • 外部配置:首先从本机配置的公网节点IP进行连接尝试,如果正常连接并获取数据,则无需进行后续的节点搜寻。
  • 预配置集:如果用户没有配置自己公网IP节点,则从App内置的公网节点IP进行连接。
  • 历史衍生:以历史IP记录为延伸起点,随机构造公网IP地址尝试连接。
端口
  • 标准端口号:7788 (TCP/UDP)
  • 动态端口号:目标难度工作量的初次匹配(确定性递增),见README算法说明。

请求NAT类型探测

获得Findings节点回应后,探测自身NAT类型。

连接组网

请求Findings网络节点信息集,建立更多Findings连接。连接兼顾各个NAT层次的节点,充分利用在线节点资源。

说明: 获取的节点信息进入自身服务器数据集。

连接策略
  1. 公共开放节点:Pub0, Pub1, FullC,端口不限。
  2. NAT穿透节点:RC 类型节点,端口不确定。
  3. NAT半穿透节点:P-RC 类型节点,端口不确定。
  4. 无穿透单向节点:Sym 类型节点,端口任意。

以上4类节点开放性逐渐降低,连接策略为:

  1. 高开放性节点连接为基础保障,一定数量必要保持。
  2. 尽量与低开放性节点建立连接,接收Sym节点的连入并适度保持,可分派NAT探测协助任务。
自身信息登记

提供自身应用类型、当前会话自身所用公钥。

  • 节点登记。
  • 节点查询。
  • 节点信息缓存(tmp)。
  • 节点效率测试。

Documentation

Overview

作为客户端使用的代码实现

Package node 节点模块 包含Findings候选池、连接池以及应用节点池的支持。

Index

Constants

View Source
const (
	NAT_LEVEL_NULL   = stun.NAT_LEVEL_NULL
	NAT_LEVEL_RC     = stun.NAT_LEVEL_RC
	NAT_LEVEL_PRC    = stun.NAT_LEVEL_PRC
	NAT_LEVEL_SYM    = stun.NAT_LEVEL_SYM
	NAT_LEVEL_PRCSYM = stun.NAT_LEVEL_PRCSYM
	NAT_LEVEL_ERROR  = stun.NAT_LEVEL_ERROR
)

局部需用常量引用。 注:主要用于 appliers4 类型取成员值。

Variables

View Source
var (
	// 禁闭查询通道
	BanQuery = make(chan *Banner)

	// 禁闭添加通道
	// 单向添加,带缓存无阻塞。
	BanAddto = make(chan string, 1)
)
View Source
var (
	// 池已为空。
	ErrEmptyPool = errors.New("the pool was empty")

	// 结束通知
	ErrServiceDone = errors.New("service exited successfully")
)
View Source
var (
	// 对端不在线
	ErrOnline = errors.New("the target node is offline")

	// 发送了错误的消息
	ErrSendIllegal = errors.New("the client sent an illegal message")

	// 消息格式错误
	ErrMsgFormat = errors.New("invalid message format")

	// 不支持目标类型应用
	ErrAppKind = errors.New("not support the kind of application")
)
View Source
var (
	// 应用端节点池组为空
	ErrAppsEmpty = errors.New("the clients pools is empty")

	// 没有匹配的打洞节点
	ErrAppNotFound = errors.New("no matching nodes on STUN service")
)
View Source
var ErrParseIP = errors.New("parse ip bytes failed")

IP 解析错误。

View Source
var NatNames = []string{
	NAT_LEVEL_NULL:   "Pub/FullC",
	NAT_LEVEL_RC:     "RC",
	NAT_LEVEL_PRC:    "P-RC",
	NAT_LEVEL_SYM:    "Sym",
	NAT_LEVEL_PRCSYM: "P-RC|Sym",
	NAT_LEVEL_ERROR:  "Unknown",
}

NatNames NAT 类型名集

Functions

func EncodePeer

func EncodePeer(node *Node) ([]byte, error)

EncodePeer 编码节点信息

func EncodePeers

func EncodePeers(nodes []*Node) ([]byte, error)

EncodePeers 编码节点集数据

func Init

func Init(ctx context.Context, conf *cfg.Config, stakes map[string]string, chpeer <-chan *cfg.Peer, done chan<- struct{})

Init 模块初始化。 根据传入的配置,初始化一些全局变量,启动部分内置全局服务。 @ctx 全局上下文 @conf 用户配置集 @stakes 支持的“服务:权益地址”集 @chpeer 广域搜索节点递送通道 @done 广域搜索终止通知

func NewClientApps

func NewClientApps() *clientApps

NewClientApps 新建一个映射表。

func Online

func Online(conn *websocket.Conn, long time.Duration) error

Online 检查对端是否在线 向目标连接发送探测消息,检查对端是否回应。 因为是在已有的连接上测试,所以对端无论返回啥消息,都表示在线。 @conn 当前连接 @long 读取等待超时,负值或零表示采用默认值 @return 非nil表示下线

func ProcessOnKind

func ProcessOnKind(kind *base.Kind, conn *websocket.Conn, w http.ResponseWriter)

ProcessOnKind 相应类型处理器。 根据客户端发送的声明信息,提供相应的服务。 顶层有4个服务: - SEEK_ASSISTX 上线协助,提供初始上线的节点一些Findings服务器。 - SEEK_KINDAPP 支持的应用类型探查。方便应用端广域搜寻同类应用端。 - SEEK_FINDNET Finder组网。应当是一个Findings节点请求连入。 - SEEK_APPSERV 应用端寻求服务:NAT 探测或 UDP 打洞协助。 - SEEK_PEERTCP 应用登记自己传递的节点为TCP服务器(同应用类型)。 @kind 应用端声明 @conn 当前TCP连接 @w 原始http写入器

func WebsocketDial

func WebsocketDial(ip netip.Addr, port int, long time.Duration) (*websocket.Conn, error)

WebsocketDial 创建一个websocket拨号 如果传递超时时长long为0或负值,则采用默认的30秒钟。

Types

type AppMap

type AppMap struct {
	// contains filtered or unexported fields
}

AppMap 应用端集 存储应用端关联节点与应用端自身的映射。 这是一个支持并发的简单封装,用于定向打洞检索目标节点。

func NewAppMap

func NewAppMap() *AppMap

NewAppMap 新建一个空映射集。

func (*AppMap) Add

func (c *AppMap) Add(key string, app *Applier, expire time.Duration)

Add 添加一个映射。 @app 目标应用端服务员 @expire 有效期时长

func (*AppMap) Clean

func (c *AppMap) Clean()

Clean 清理过期目标。 遍历集合,可能耗时,但Get方法也会及时清理。

func (*AppMap) Get

func (c *AppMap) Get(key string) *Applier

Get 获取目标连接。 获取时会检查是否过期,若过期会自动删除目标。 作为一种友好,即便过期,目标依然会返回(可用)。 即:仅在未找到目标时返回nil。

func (*AppMap) Remove

func (c *AppMap) Remove(key string)

Remove 移除一个映射。

type AppPool

type AppPool map[string]*AppMap

AppPool 应用端映射池 key: 应用类别(Base:Name)。

func NewAppPool

func NewAppPool(kinds []string) AppPool

NewAppPool 创建一个连接映射池。 根据传入的类别集创建。

func (AppPool) Get

func (a AppPool) Get(kind string) (*AppMap, error)

Get 获取目标类别的映射集。

func (AppPool) Supported

func (a AppPool) Supported(kind string) bool

Supported 是否支持目标类别。

type Applier

type Applier struct {
	*Node                     // 对端节点
	*LinkPeer                 // 打洞关联节点
	Kind      string          // 应用类别名
	Conn      *websocket.Conn // 当前连接(TCP)
	// contains filtered or unexported fields
}

Applier 应用端服务员 与 Finder 字段完全相同,但两者所支持的方法集不同。

func NewApplier

func NewApplier(node *Node, kname string, conn *websocket.Conn) *Applier

NewApplier 创建一个应用端服务员 初始构建时不设置打洞关联节点(LinkPeer)。

func (*Applier) Quit

func (a *Applier) Quit()

Quit 节点退出。

func (*Applier) SendPeerUDP

func (a *Applier) SendPeerUDP(addr *net.UDPAddr) error

SendPeerUDP 向客户端发送其节点UDP信息。 @addr 客户端的UDP地址

func (*Applier) Server

func (a *Applier) Server(ctx context.Context, notice chan<- *stun.Notice, client <-chan *stun.Client)

Server 作为服务器启动。 对传入的各种类型应用的打洞请求进行回应。 注记: 应用服务员只有服务进程,无对外连出。

func (*Applier) SetLinkPeer

func (a *Applier) SetLinkPeer(peer *LinkPeer)

SetLinkPeer 设置关联节点

func (*Applier) String

func (a *Applier) String() string

String 服务员的字符串表示(对端信息) 格式:IP:Port(Level)

type Appliers

type Appliers struct {
	// contains filtered or unexported fields
}

Appliers 应用端服务员缓存池。

func NewAppliers

func NewAppliers(size int) *Appliers

NewAppliers 创建集合。 size 可以为零或负数,这样就不会创建实例。 比如当前服务器不提供对外应用端服务(NAT 内网 Finder)。 @size 池大小限制 @cleanlen 清理的片段长度。 @net 支持的网络类型(tcp|udp)

func (*Appliers) Add

func (a *Appliers) Add(node *Applier) error

Add 添加成员到缓存池。

func (*Appliers) Clean

func (a *Appliers) Clean(ctx context.Context, long time.Duration)

Clean 清理缓存池 移除入池时间太久或已经下线的成员。 应用池较大,因此采用并发的清理方式(pool.CleanN)。 @long 指定过期时间长度

func (*Appliers) Dispose

func (a *Appliers) Dispose(conn *websocket.Conn) *Applier

Dispose 清除目标连接节点。 @conn 目标连接 @return 被移除的目标节点

func (*Appliers) Get

func (a *Appliers) Get() *Applier

Get 引用一个随机成员。 @return1 目标成员的位置下标 @return2 目标成员

func (*Appliers) IsFulled

func (a *Appliers) IsFulled() bool

IsFulled 缓存池是否满员

func (*Appliers) List

func (a *Appliers) List(count int) []*Applier

List 获取指定数量的随机成员。 如果指定的长度为负值或超过了池内节点数,返回全部节点。 返回集成员已随机化。 @count 获取的成员数量 @return 一个随机成员序列

func (*Appliers) Size

func (a *Appliers) Size() int

Size 返回缓存池大小

type AppliersPool

type AppliersPool map[string]appliers4

AppliersPool 应用服务员池组集 包含任意应用类型,每一个类型对应一个按NAT分类的双协议池组。 key: 应用类型名(kind:name)

func NewAppliersPool

func NewAppliersPool() AppliersPool

NewClientsPool 创建一个应用服务员池组集

func (AppliersPool) Appliers

func (cp AppliersPool) Appliers(kind string, level NatLevel) (*Appliers, error)

Appliers 获取一个应用服务员集。 level: - NAT_LEVEL_NULL - NAT_LEVEL_RC - NAT_LEVEL_PRC - NAT_LEVEL_SYM

@kind 应用类型名(kind:name) @level 目标NAT层级(0 ~ 3) @return 目标类型的节点池

func (AppliersPool) Appliers4

func (cp AppliersPool) Appliers4(kind string) []*Appliers

AppliersUDP 提取目标类型的UDP打洞信息组 如果不支持目标类型,返回nil。 注: Sym 在 Pub/FullC 主动请求时有用,但单向连接无需打洞。

func (AppliersPool) Clean

func (cp AppliersPool) Clean(ctx context.Context, kinds []string, long time.Duration)

Clean 清理目标类型的应用池组 @kinds 应用名称集(kind:name) @long 有效期时长

func (AppliersPool) Init

func (cp AppliersPool) Init(kind string, size int)

Init 初始化应用池组。 每一种应用初始使用时都需要调用该初始化函数。 注意: 不支持并发安全,因此用户需要在程序最开始时初始化自己支持的所有应用。 @kind 应用类型名(kind:name) @size 池大小限制

func (AppliersPool) Size

func (cp AppliersPool) Size() int

Size 获取应用池集大小。 即池集支持的应用类型多少。

func (AppliersPool) Supported

func (cp AppliersPool) Supported(kind string) bool

Supported 是否支持目标类型服务。

type Banner struct {
	Addr  string    // IP:Port 字符串
	Reply chan bool // 回复通道(禁闭中:true,未禁闭:false)
}

Banner 禁闭查询器。

func (*Banner) Close

func (b *Banner) Close()

Close 关闭查询器。

type ClientSN

type ClientSN = stun.ClientSN

序列号引用

type Finder

type Finder struct {
	*Node                 // TCP 对端节点
	Conn  *websocket.Conn // 当前 Websocket 连接
	// contains filtered or unexported fields
}

Finder Findings组网节点 xhost 用于NewHost通知,让本地服务器向对端请求NewHost协作。

func NewFinder

func NewFinder(node *Node, conn *websocket.Conn, udpc *natx.Client) *Finder

NewFinder 新建一个Finder

func (*Finder) Client

func (f *Finder) Client(ctx context.Context, notice chan<- *stun.Notice)

Client 作为客户端启动(连出)。 注:需主动关闭 f.Conn @ctx 当前服务进程上下文 @notice 本地UDP服务器协助通知通道(NewHost)

func (*Finder) NatLevel

func (f *Finder) NatLevel() (NatLevel, error)

NatLevel 请求NAT层级探测服务。 作为客户端,向当前TCP连接的对端请求NAT探测服务。

  • 首先请求 STUN:Cone 主服务,
  • 视情况决定是否向其它对端请求 STUN:Sym 服务。 注:依然是以应用端连出的对端。

这是一个阻塞的调用,如果未出错,会等到分析出结果才返回。

使用: 初始向对端请求本服务时,需先向服务器声明自己的目的。 即 base.Kind.seek 字段设置为 SEEK_APPSERV。

kind := base.EncodeKind(...)
base.EncodeProto(base.COMMAND_KIND, kind)

@return 自身所属的NAT层级

func (*Finder) NatLive

func (f *Finder) NatLive() (time.Duration, error)

NatLive 请求NAT生存期探测服务。 作为客户端,向当前连接的对端请求NAT生存期探测。 用户通常应当多调用几次本方法,来推算出一个恰当的值。 注意:同上 NatLevel 说明。 @return NAT生命周期(-1表示出错)

func (*Finder) NewHost

func (f *Finder) NewHost(peer *stun.Client)

NewHost 请求对端发送一个UDP探测包。 @peer UDP探测包的接收端

func (*Finder) Punching

func (f *Finder) Punching(peer *LinkPeer) error

Punching 请求打洞协助。 作为客户端,向当前TCP连接的对端请求打洞协助。 @peer 自身关联的UDP节点信息

func (*Finder) Quit

func (f *Finder) Quit()

Quit 节点退出。 关闭通道,服务进程会退出后自动关闭 f.Conn。

func (*Finder) Server

func (f *Finder) Server(ctx context.Context, notice chan<- *stun.Notice)

Server 作为服务器启动(连入)。 注:上层退出会自动关闭 f.Conn @ctx 当前服务进程上下文 @notice 本地UDP服务器协助通知通道(NewHost)

type Finders

type Finders struct {
	// contains filtered or unexported fields
}

Finders 组网池。 结构和 Shortlist 相同,但方法集稍有差别。

func NewFinders

func NewFinders(size int) *Finders

NewFinders 创建一个连接池

func (*Finders) Add

func (f *Finders) Add(node *Finder) error

Add 添加一个节点。

func (*Finders) Dispose

func (f *Finders) Dispose(conn *websocket.Conn) *Finder

Dispose 清除目标连接节点。 @conn 目标连接 @return 被移除的目标节点

func (*Finders) Get

func (f *Finders) Get() *Finder

Get 引用一个随机成员。

func (*Finders) IsFulled

func (f *Finders) IsFulled() bool

IsFulled 节点池是否满员。

func (*Finders) List

func (f *Finders) List(count int) []*Finder

List 应用多个随机成员。

func (*Finders) Other

func (f *Finders) Other(old *Finder) *Finder

Other 获取一个不同于old的节点。

func (*Finders) Size

func (f *Finders) Size() int

Size 返回节点池大小。

func (*Finders) Take

func (f *Finders) Take() *Finder

Take 提取一个随机成员。

type LinkPeer

type LinkPeer = stun.Peer

关联节点引用(UDP打洞)

type NatLevel

type NatLevel = stun.NatLevel

NAT 层级

type Node

type Node struct {
	IP    netip.Addr    // 对端 IP
	Port  int           // 监听/通讯端口
	Start time.Time     // 加入时间
	Ping  time.Duration // 节点距离(抵达时长)
}

Node 在线节点 记录节点的基本信息,可用于当前连接节点或待创建连接的节点。

func DecodePeer

func DecodePeer(data []byte) (*Node, error)

DecodePeer 解码节点信息

func DecodePeers

func DecodePeers(data []byte) ([]*Node, error)

DecodePeers 解码节点集数据 @data EncodePeers编码的数据。

func New

func New(ip netip.Addr, port int) *Node

New 创建一个节点 @ip 节点公网IP地址 @port 节点对外端口

func NewFromPeer

func NewFromPeer(p *Peer) *Node

NewFromPeer 从传输数据Peer构造。 解析错误返回nil(忽略、容错),避免恶意破坏。

func NewWithAddr

func NewWithAddr(addr net.Addr) *Node

NewWithAddr 从net.Addr实参创建节点

func Onlines

func Onlines(nodes []*Node, long time.Duration) []*Node

Onlines 节点集在线测试 检查目标节点集内的节点是否在线。 测试过程会阻塞进程,达到超时时间后会返回已成功的集合。 如果所有节点都在线,则可能提前返回。 注意: 会记录节点的ping时间,-1值表示不可达。 @nodes 目标节点集 @long 测试超时时间限定,零值表示采用系统默认值 @return 在线的节点集成员

func (*Node) Hello

func (n *Node) Hello(long time.Duration) bool

Hello 节点问候 探知对端是否有反应(可连接)。 仅针对TCP基础链路,采用普通TCP连接协议即可。 @long 测试超时时间

func (*Node) Online

func (n *Node) Online(long time.Duration) error

Online 测试对端是否在线。 拨号测试对端是否为本类服务节点(Findings)。 如果返回错误,表示对端无法连通或不是同类节点。 @long 拨号等待时间

func (*Node) String

func (n *Node) String() string

String 字符串表示 标准的 IP:Port 格式,也用于禁闭检查。

type Peer

type Peer struct {
	Ip   []byte `protobuf:"bytes,1,opt,name=ip,proto3" json:"ip,omitempty"`      // 公网 IP
	Port int32  `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"` // 端口(TCP)
	// contains filtered or unexported fields
}

节点信息 仅有可直连的 NAT:Pub/FullC 类型才会被传递。 因此无需携带 NAT 类型。

func (*Peer) Descriptor deprecated

func (*Peer) Descriptor() ([]byte, []int)

Deprecated: Use Peer.ProtoReflect.Descriptor instead.

func (*Peer) GetIp

func (x *Peer) GetIp() []byte

func (*Peer) GetPort

func (x *Peer) GetPort() int32

func (*Peer) ProtoMessage

func (*Peer) ProtoMessage()

func (*Peer) ProtoReflect

func (x *Peer) ProtoReflect() protoreflect.Message

func (*Peer) Reset

func (x *Peer) Reset()

func (*Peer) String

func (x *Peer) String() string

type PeerList

type PeerList struct {
	Peers []*Peer `protobuf:"bytes,1,rep,name=peers,proto3" json:"peers,omitempty"`
	// contains filtered or unexported fields
}

节点集定义

func (*PeerList) Descriptor deprecated

func (*PeerList) Descriptor() ([]byte, []int)

Deprecated: Use PeerList.ProtoReflect.Descriptor instead.

func (*PeerList) GetPeers

func (x *PeerList) GetPeers() []*Peer

func (*PeerList) ProtoMessage

func (*PeerList) ProtoMessage()

func (*PeerList) ProtoReflect

func (x *PeerList) ProtoReflect() protoreflect.Message

func (*PeerList) Reset

func (x *PeerList) Reset()

func (*PeerList) String

func (x *PeerList) String() string

type PunchApp

type PunchApp struct {
	// contains filtered or unexported fields
}

PunchApp 打洞应用端 用于登记定向打洞的查询目标节点。

func (PunchApp) Expired

func (p PunchApp) Expired() bool

Expired 是否以及过期。

type Rnd16

type Rnd16 = natx.Rnd16

Rnd16 密钥因子类型引用

type Shortlist

type Shortlist struct {
	// contains filtered or unexported fields
}

Shortlist 候选池类型。

func NewShortlist

func NewShortlist(size int) *Shortlist

NewShortlist 创建一个新的候选池。

func (*Shortlist) Add

func (s *Shortlist) Add(node *Node) error

Add 添加一个候选节点。 @node 待添加入池的节点

func (*Shortlist) Adds

func (s *Shortlist) Adds(list ...*Node) int

Adds 添加多个候选节点。 @list 待添加的节点序列 @return 实际成功添加的数量

func (*Shortlist) Clean

func (s *Shortlist) Clean(ctx context.Context)

Clean 清理无效连接(对端下线) 直接完成Finder的清理逻辑。 用户通常运行一个服务,定时调用该方法。

func (*Shortlist) Drop

func (s *Shortlist) Drop() []*Node

Drop 提取全部成员。 原池会被清空,但其它设置被保留。

func (*Shortlist) IsFulled

func (s *Shortlist) IsFulled() bool

IsFulled 池是否已满员。

func (*Shortlist) List

func (s *Shortlist) List(count int) []*Node

List 获取一个随机节点集。 返回集可能不足count的数量,如果池中成员不足的话。 @count 获取数量 @return 一个随机节点序列

func (*Shortlist) Size

func (s *Shortlist) Size() int

Size 获取池当前大小。

func (*Shortlist) Take

func (s *Shortlist) Take() *Node

Take 提取一个随机成员。

func (*Shortlist) Takes

func (s *Shortlist) Takes(count int) []*Node

Takes 提取一些随机成员。

func (*Shortlist) Unique

func (s *Shortlist) Unique() int

Unique 集合去重。 移除地址重复的节点,这在新节点汇入时可能产生。

type TCPStore

type TCPStore struct {
	// contains filtered or unexported fields
}

TCPStore 应用服务器库 Node存储的是对端提供的TCP服务器的节点信息。 采用快速更新的策略: - 池满即将末尾部分移动到清理游标处。 因此要求池容量大小是单次清理长度的整数倍。

func NewTCPStore

func NewTCPStore(size, count int) *TCPStore

NewTCPStore 新建一个分享池。 池大小应当是单次清理量的整数倍,否则会自动转为整数倍。 池大小至少应当是清理量大小的两倍。 @size 池大小限制 @count 单次清理大小

func (*TCPStore) Add

func (t *TCPStore) Add(node *Node) error

Add 添加一个节点。 如果池满,会触发自动清理操作,因此添加总会成功。 @return nil

func (*TCPStore) List

func (t *TCPStore) List(count int) []*Node

List 获取一个节点清单 如果池中成员不足count的数量,返回全部成员。 返回集成员是随机的。

type TCPStorePool

type TCPStorePool map[string]*TCPStore

TCPStorePool 各类TCP分享池集 key: (kind:name)

func NewTCPStorePool

func NewTCPStorePool() TCPStorePool

NewTCPStorePool 新建一个分享池集。

func (TCPStorePool) Init

func (tp TCPStorePool) Init(kind string, size, count int)

Init 初始化各类型分享池。 @kind 应用类型名(kind:name) @size 分享池大小 @count 单次清理长度

func (TCPStorePool) Supported

func (tp TCPStorePool) Supported(kind string) bool

Supported 是否支持目标类型

func (TCPStorePool) TCPStore

func (tp TCPStorePool) TCPStore(kind string) (*TCPStore, error)

TCPStore 获取目标类型的TCP分享池

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL