Files
2026-08-25 15:44:16 +03:00

82 lines
2.3 KiB
Go

package bind
import (
"net"
"net/netip"
"sync/atomic"
"time"
"github.com/amnezia-vpn/amneziawg-go/v3/conn"
"github.com/samosvalishe/free-turn-proxy/internal/tunnel"
)
// SinglePeerBind подключает WireGuard к каналу net.PacketConn вместо сокета.
type SinglePeerBind struct {
pc net.PacketConn
closed atomic.Bool
}
type peerEndpoint struct{}
func (peerEndpoint) ClearSrc() {}
func (peerEndpoint) SrcToString() string { return "" }
func (peerEndpoint) DstToString() string { return tunnel.EndpointSinglePeer }
func (peerEndpoint) DstToBytes() []byte { return []byte{} }
func (peerEndpoint) DstIP() netip.Addr { return netip.Addr{} }
func (peerEndpoint) SrcIP() netip.Addr { return netip.Addr{} }
var theEndpoint conn.Endpoint = peerEndpoint{}
func NewSinglePeerBind(pc net.PacketConn) *SinglePeerBind {
return &SinglePeerBind{pc: pc}
}
// Open инициализирует функции приёма пакетов и сбрасывает дедлайны.
func (b *SinglePeerBind) Open(uint16) ([]conn.ReceiveFunc, uint16, error) {
b.closed.Store(false)
if err := b.pc.SetReadDeadline(time.Time{}); err != nil {
return nil, 0, err
}
return []conn.ReceiveFunc{b.receive}, 0, nil
}
func (b *SinglePeerBind) receive(packets [][]byte, sizes []int, eps []conn.Endpoint) (int, error) {
n, _, err := b.pc.ReadFrom(packets[0])
if err != nil {
// При закрытом Bind возвращаем net.ErrClosed для корректного выхода из цикла чтения.
if b.closed.Load() {
return 0, net.ErrClosed
}
return 0, err
}
sizes[0] = n
eps[0] = theEndpoint
return 1, nil
}
func (b *SinglePeerBind) Send(bufs [][]byte, _ conn.Endpoint) error {
for _, buf := range bufs {
if _, err := b.pc.WriteTo(buf, nil); err != nil {
return err
}
}
return nil
}
func (*SinglePeerBind) ParseEndpoint(string) (conn.Endpoint, error) {
return theEndpoint, nil
}
func (*SinglePeerBind) BatchSize() int { return 1 }
func (*SinglePeerBind) SetMark(uint32) error { return nil }
// Close прерывает текущие операции чтения без закрытия нижележащего PacketConn.
func (b *SinglePeerBind) Close() error {
if !b.closed.CompareAndSwap(false, true) {
return nil
}
return b.pc.SetReadDeadline(time.Unix(1, 0))
}