2023-04-07 19:30:05 +00:00
|
|
|
package sturn
|
2023-04-07 18:42:17 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
// "encoding/json"
|
2023-04-08 00:47:04 +00:00
|
|
|
"encoding/hex"
|
2023-04-07 18:42:17 +00:00
|
|
|
"sync"
|
2023-04-08 00:47:04 +00:00
|
|
|
"github.com/theckman/go-securerandom"
|
2023-04-07 18:42:17 +00:00
|
|
|
// "time"
|
2023-04-08 00:47:04 +00:00
|
|
|
"errors"
|
2023-04-07 18:42:17 +00:00
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
)
|
|
|
|
|
|
|
|
var sturn *Sturn
|
2023-04-07 19:30:05 +00:00
|
|
|
const SturnKeepAlive = 3600
|
2023-04-07 22:02:31 +00:00
|
|
|
const SturnMaxSize = 1024
|
|
|
|
const SturnMaxBindFail = 16
|
2023-04-08 00:47:04 +00:00
|
|
|
const SturnNonceSize = 8
|
|
|
|
const SturnPassSize = 8
|
2023-04-07 18:42:17 +00:00
|
|
|
|
2023-04-10 22:14:51 +00:00
|
|
|
type SturnAllocation struct {
|
|
|
|
source string
|
|
|
|
transaction []byte
|
|
|
|
response []byte
|
|
|
|
port int
|
|
|
|
}
|
|
|
|
|
2023-04-07 18:42:17 +00:00
|
|
|
type SturnSession struct {
|
2023-04-08 00:47:04 +00:00
|
|
|
user string
|
|
|
|
auth string
|
2023-04-10 22:14:51 +00:00
|
|
|
allocations []*SturnAllocation
|
2023-04-07 18:42:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Sturn struct {
|
|
|
|
sync sync.Mutex
|
2023-04-08 00:47:04 +00:00
|
|
|
sessionId int
|
|
|
|
sessions map[string]*SturnSession
|
|
|
|
closing bool
|
2023-04-08 05:59:09 +00:00
|
|
|
port int
|
2023-04-07 18:42:17 +00:00
|
|
|
conn *net.PacketConn
|
|
|
|
closed chan bool
|
2023-04-07 22:02:31 +00:00
|
|
|
buf []byte
|
2023-04-08 00:47:04 +00:00
|
|
|
publicIp string
|
2023-04-08 05:59:09 +00:00
|
|
|
relayStart int
|
|
|
|
relayCount int
|
|
|
|
relayPorts map[int]bool
|
|
|
|
relayIndex int
|
2023-04-07 18:42:17 +00:00
|
|
|
}
|
|
|
|
|
2023-04-08 05:59:09 +00:00
|
|
|
func Listen(port int, relayStart int, relayCount int) (error) {
|
2023-04-07 18:42:17 +00:00
|
|
|
|
|
|
|
if (sturn != nil) {
|
|
|
|
(*sturn.conn).Close()
|
|
|
|
<-sturn.closed
|
|
|
|
sturn = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
address := fmt.Sprintf(":%d", port)
|
|
|
|
conn, err := net.ListenPacket("udp", address)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-04-08 05:59:09 +00:00
|
|
|
relayPorts := make(map[int]bool)
|
|
|
|
for i := 0; i < relayCount; i++ {
|
|
|
|
relayPorts[i] = true
|
|
|
|
}
|
|
|
|
|
2023-04-10 22:14:51 +00:00
|
|
|
sturn = &Sturn{
|
2023-04-08 00:47:04 +00:00
|
|
|
sessionId: 0,
|
|
|
|
closing: false,
|
2023-04-07 18:42:17 +00:00
|
|
|
port: port,
|
|
|
|
relayStart: relayStart,
|
2023-04-08 05:59:09 +00:00
|
|
|
relayCount: relayCount,
|
|
|
|
relayPorts: relayPorts,
|
2023-04-07 18:42:17 +00:00
|
|
|
conn: &conn,
|
2023-04-07 22:02:31 +00:00
|
|
|
buf: make([]byte, SturnMaxSize),
|
2023-04-10 22:14:51 +00:00
|
|
|
sessions: make(map[string]*SturnSession),
|
2023-04-07 18:42:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
go sturn.serve(conn);
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func Close() {
|
|
|
|
if (sturn != nil) {
|
|
|
|
(*sturn.conn).Close()
|
|
|
|
<-sturn.closed
|
|
|
|
sturn = nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Sturn) serve(conn net.PacketConn) {
|
|
|
|
for {
|
2023-04-07 22:02:31 +00:00
|
|
|
buf := make([]byte, SturnMaxSize)
|
2023-04-07 18:42:17 +00:00
|
|
|
n, addr, err := conn.ReadFrom(buf)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return
|
|
|
|
}
|
2023-04-07 19:30:05 +00:00
|
|
|
s.handleMessage(buf[:n], addr);
|
2023-04-07 18:42:17 +00:00
|
|
|
}
|
2023-04-07 19:30:05 +00:00
|
|
|
|
2023-04-08 00:47:04 +00:00
|
|
|
s.sync.Lock()
|
|
|
|
s.closing = true
|
|
|
|
for _, session := range s.sessions {
|
|
|
|
// TODO cleanup session
|
|
|
|
fmt.Println(session)
|
|
|
|
}
|
|
|
|
s.sync.Unlock()
|
2023-04-07 19:30:05 +00:00
|
|
|
|
2023-04-07 18:42:17 +00:00
|
|
|
s.closed <- true
|
|
|
|
}
|
|
|
|
|
2023-04-08 00:47:04 +00:00
|
|
|
func TestSession() {
|
|
|
|
if sturn != nil {
|
|
|
|
sturn.sync.Lock()
|
|
|
|
defer sturn.sync.Unlock()
|
|
|
|
if sturn.closing {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
session := &SturnSession{
|
|
|
|
user: "user",
|
|
|
|
auth: "pass",
|
|
|
|
}
|
|
|
|
sturn.sessions["user"] = session
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Sturn) addSession() (*SturnSession, error) {
|
|
|
|
s.sync.Lock()
|
|
|
|
defer s.sync.Unlock()
|
|
|
|
if !s.closing {
|
|
|
|
return nil, errors.New("closing sturn")
|
|
|
|
}
|
|
|
|
s.sessionId += 1
|
|
|
|
user := fmt.Sprintf("%08d", s.sessionId)
|
|
|
|
authBin, authErr := securerandom.Bytes(SturnPassSize)
|
|
|
|
if authErr != nil {
|
|
|
|
return nil, authErr
|
|
|
|
}
|
|
|
|
session := &SturnSession{
|
|
|
|
user: user,
|
|
|
|
auth: hex.EncodeToString(authBin),
|
|
|
|
}
|
|
|
|
s.sessions[user] = session
|
|
|
|
return session, nil
|
|
|
|
}
|
|
|
|
|
2023-04-08 05:59:09 +00:00
|
|
|
func (s *Sturn) getRelayPort() (int, error) {
|
|
|
|
s.relayIndex += 1;
|
|
|
|
for i := 0; i < s.relayCount; i++ {
|
|
|
|
key := (i + s.relayIndex) % s.relayCount;
|
|
|
|
if s.relayPorts[key] {
|
|
|
|
s.relayPorts[key] = false
|
|
|
|
return s.relayStart + key, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0, errors.New("no available relay port")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Sturn) setRelayPort(port int) {
|
|
|
|
key := port - s.relayStart
|
|
|
|
s.relayPorts[key] = true
|
|
|
|
}
|
|
|
|
|