mirror of
https://github.com/gravitl/netmaker.git
synced 2024-09-21 07:46:04 +08:00
add stun-server to netmaker
This commit is contained in:
parent
1bc1a97405
commit
fb60c528e3
144
stun-server/stun-server.go
Normal file
144
stun-server/stun-server.go
Normal file
|
@ -0,0 +1,144 @@
|
|||
package stunserver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"gortc.io/stun"
|
||||
)
|
||||
|
||||
// Server is RFC 5389 basic server implementation.
|
||||
//
|
||||
// Current implementation is UDP only and not utilizes FINGERPRINT mechanism,
|
||||
// nor ALTERNATE-SERVER, nor credentials mechanisms. It does not support
|
||||
// backwards compatibility with RFC 3489.
|
||||
type Server struct {
|
||||
Addr string
|
||||
LogAllErrors bool
|
||||
log Logger
|
||||
}
|
||||
|
||||
// Logger is used for logging formatted messages.
|
||||
type Logger interface {
|
||||
// Printf must have the same semantics as log.Printf.
|
||||
Printf(format string, args ...interface{})
|
||||
}
|
||||
|
||||
var (
|
||||
defaultLogger = logrus.New()
|
||||
software = stun.NewSoftware("netmaker-stun")
|
||||
errNotSTUNMessage = errors.New("not stun message")
|
||||
)
|
||||
|
||||
func basicProcess(addr net.Addr, b []byte, req, res *stun.Message) error {
|
||||
if !stun.IsMessage(b) {
|
||||
return errNotSTUNMessage
|
||||
}
|
||||
if _, err := req.Write(b); err != nil {
|
||||
return errors.Wrap(err, "failed to read message")
|
||||
}
|
||||
var (
|
||||
ip net.IP
|
||||
port int
|
||||
)
|
||||
switch a := addr.(type) {
|
||||
case *net.UDPAddr:
|
||||
ip = a.IP
|
||||
port = a.Port
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown addr: %v", addr))
|
||||
}
|
||||
return res.Build(req,
|
||||
stun.BindingSuccess,
|
||||
software,
|
||||
&stun.XORMappedAddress{
|
||||
IP: ip,
|
||||
Port: port,
|
||||
},
|
||||
stun.Fingerprint,
|
||||
)
|
||||
}
|
||||
|
||||
func (s *Server) serveConn(c net.PacketConn, res, req *stun.Message) error {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
buf := make([]byte, 1024)
|
||||
n, addr, err := c.ReadFrom(buf)
|
||||
if err != nil {
|
||||
s.log.Printf("ReadFrom: %v", err)
|
||||
return nil
|
||||
}
|
||||
log.Printf("read %d bytes from %s\n", n, addr)
|
||||
if _, err = req.Write(buf[:n]); err != nil {
|
||||
s.log.Printf("Write: %v", err)
|
||||
return err
|
||||
}
|
||||
if err = basicProcess(addr, buf[:n], req, res); err != nil {
|
||||
if err == errNotSTUNMessage {
|
||||
return nil
|
||||
}
|
||||
s.log.Printf("basicProcess: %v", err)
|
||||
return nil
|
||||
}
|
||||
_, err = c.WriteTo(res.Raw, addr)
|
||||
if err != nil {
|
||||
s.log.Printf("WriteTo: %v", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Serve reads packets from connections and responds to BINDING requests.
|
||||
func (s *Server) Serve(c net.PacketConn) error {
|
||||
var (
|
||||
res = new(stun.Message)
|
||||
req = new(stun.Message)
|
||||
)
|
||||
for {
|
||||
if err := s.serveConn(c, res, req); err != nil {
|
||||
s.log.Printf("serve: %v", err)
|
||||
return err
|
||||
}
|
||||
res.Reset()
|
||||
req.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
// ListenUDPAndServe listens on laddr and process incoming packets.
|
||||
func ListenUDPAndServe(serverNet, laddr string) error {
|
||||
c, err := net.ListenPacket(serverNet, laddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s := &Server{
|
||||
log: defaultLogger,
|
||||
}
|
||||
return s.Serve(c)
|
||||
}
|
||||
|
||||
func normalize(address string) string {
|
||||
if len(address) == 0 {
|
||||
address = "0.0.0.0"
|
||||
}
|
||||
if !strings.Contains(address, ":") {
|
||||
address = fmt.Sprintf("%s:%d", address, stun.DefaultPort)
|
||||
}
|
||||
return address
|
||||
}
|
||||
|
||||
func Start() {
|
||||
|
||||
normalized := normalize(fmt.Sprintf("0.0.0.0:%s", servercfg.GetStunPort()))
|
||||
logger.Log(0, "netmaker-stun listening on", normalized, "via udp")
|
||||
err := ListenUDPAndServe("udp", normalized)
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to start stun server: ", err.Error())
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue