TURN сервер для выхода за сложные NAT

This commit is contained in:
set
2026-03-14 23:08:18 +02:00
parent ef591072f3
commit b6d5780584
3 changed files with 125 additions and 0 deletions

95
turn/turn.go Normal file
View File

@@ -0,0 +1,95 @@
package turn
import (
"fmt"
"net"
pionturn "github.com/pion/turn/v4"
)
type Server struct {
udpConn net.PacketConn
tcpListener net.Listener
srv *pionturn.Server
}
type Config struct {
ListenAddr string // "0.0.0.0:3478"
PublicIP string
Realm string
Username string
Password string
}
func Start(cfg Config) (*Server, error) {
ip := net.ParseIP(cfg.PublicIP)
if ip == nil {
return nil, fmt.Errorf("turn: invalid PublicIP: %s", cfg.PublicIP)
}
udpConn, err := net.ListenPacket("udp4", cfg.ListenAddr)
if err != nil {
return nil, err
}
tcpListener, err := net.Listen("tcp4", cfg.ListenAddr)
if err != nil {
_ = udpConn.Close()
return nil, err
}
srv, err := pionturn.NewServer(pionturn.ServerConfig{
Realm: cfg.Realm,
AuthHandler: func(username, realm string, srcAddr net.Addr) ([]byte, bool) {
if username != cfg.Username {
return nil, false
}
return pionturn.GenerateAuthKey(username, realm, cfg.Password), true
},
PacketConnConfigs: []pionturn.PacketConnConfig{
{
PacketConn: udpConn,
RelayAddressGenerator: &pionturn.RelayAddressGeneratorStatic{
RelayAddress: ip,
Address: "0.0.0.0",
},
},
},
ListenerConfigs: []pionturn.ListenerConfig{
{
Listener: tcpListener,
RelayAddressGenerator: &pionturn.RelayAddressGeneratorStatic{
RelayAddress: ip,
Address: "0.0.0.0",
},
},
},
})
if err != nil {
_ = tcpListener.Close()
_ = udpConn.Close()
return nil, err
}
return &Server{
udpConn: udpConn,
tcpListener: tcpListener,
srv: srv,
}, nil
}
func (s *Server) Close() error {
if s == nil {
return nil
}
if s.srv != nil {
_ = s.srv.Close()
}
if s.tcpListener != nil {
_ = s.tcpListener.Close()
}
if s.udpConn != nil {
_ = s.udpConn.Close()
}
return nil
}