mirror of
https://github.com/hackdiaz-dev/free-turn-proxy.git
synced 2026-10-12 09:41:53 +02:00
214 lines
4.3 KiB
Go
214 lines
4.3 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/samosvalishe/free-turn-proxy/internal/transport/kcpmux"
|
|
"github.com/samosvalishe/free-turn-proxy/internal/tunnel"
|
|
"github.com/samosvalishe/free-turn-proxy/internal/uri"
|
|
"github.com/samosvalishe/free-turn-proxy/internal/wire/rtpopus"
|
|
)
|
|
|
|
// raw хранит неразобранные строковые опции до этапа assemble.
|
|
type raw struct {
|
|
Turn string
|
|
Port string
|
|
Listen string
|
|
Peer string
|
|
|
|
Provider string
|
|
Link string
|
|
Links string
|
|
|
|
N int
|
|
StreamsPerCred int
|
|
Transport string
|
|
Mode string
|
|
|
|
ObfProfile string
|
|
ObfKey string
|
|
ObfTiming time.Duration
|
|
GenObfKey bool
|
|
|
|
ManualCaptcha bool
|
|
Platform string
|
|
|
|
DNSMode string
|
|
DNSServers string
|
|
|
|
Debug bool
|
|
ClientID string
|
|
SubURL string
|
|
Routes bool
|
|
|
|
TunnelMode string
|
|
TunnelConfig string
|
|
TunnelMTU int
|
|
|
|
KCP kcpmux.Profile
|
|
}
|
|
|
|
// applyURI применяет параметры freeturn:// поверх raw-опций.
|
|
func (r *raw) applyURI(u *uri.Config) {
|
|
if u.Provider != "" {
|
|
r.Provider = u.Provider
|
|
}
|
|
if u.Transport != "" {
|
|
r.Transport = u.Transport
|
|
}
|
|
if u.Mode != "" {
|
|
r.Mode = u.Mode
|
|
}
|
|
if u.KCP != nil {
|
|
r.KCP = kcpmux.Profile{
|
|
NoDelay: u.KCP.NoDelay,
|
|
Interval: u.KCP.Interval,
|
|
Resend: u.KCP.Resend,
|
|
NC: u.KCP.NC,
|
|
SndWnd: u.KCP.SndWnd,
|
|
RcvWnd: u.KCP.RcvWnd,
|
|
MTU: u.KCP.MTU,
|
|
ACKNoDelay: u.KCP.ACKNoDelay,
|
|
}
|
|
}
|
|
if u.N > 0 {
|
|
r.N = u.N
|
|
}
|
|
if u.StreamsPerCred > 0 {
|
|
r.StreamsPerCred = u.StreamsPerCred
|
|
}
|
|
if u.ObfProfile != "" {
|
|
r.ObfProfile = u.ObfProfile
|
|
}
|
|
if u.ObfKey != "" {
|
|
r.ObfKey = u.ObfKey
|
|
}
|
|
if u.Peer != "" {
|
|
r.Peer = u.Peer
|
|
}
|
|
if u.ClientID != "" {
|
|
r.ClientID = u.ClientID
|
|
}
|
|
if u.Listen != "" {
|
|
r.Listen = u.Listen
|
|
}
|
|
if u.DNSMode != "" {
|
|
r.DNSMode = u.DNSMode
|
|
}
|
|
if u.DNSServers != "" {
|
|
r.DNSServers = u.DNSServers
|
|
}
|
|
if u.ManualCaptcha {
|
|
r.ManualCaptcha = true
|
|
}
|
|
}
|
|
|
|
func assemble(r raw) (*Client, error) {
|
|
switch r.Transport {
|
|
case TransportTCP, TransportUDP:
|
|
default:
|
|
return nil, fmt.Errorf("invalid -transport value %q: must be %s | %s", r.Transport, TransportTCP, TransportUDP)
|
|
}
|
|
switch r.Mode {
|
|
case ModeUDP, ModeTCP:
|
|
default:
|
|
return nil, fmt.Errorf("invalid -mode value %q: must be %s | %s", r.Mode, ModeUDP, ModeTCP)
|
|
}
|
|
n := r.N
|
|
if n <= 0 {
|
|
n = DefaultStreams
|
|
}
|
|
platform := Platform(r.Platform)
|
|
if platform == "" {
|
|
platform = DefaultPlatform
|
|
}
|
|
tunnelMTU := r.TunnelMTU
|
|
if tunnelMTU <= 0 {
|
|
tunnelMTU = tunnel.DefaultMTU
|
|
}
|
|
|
|
c := &Client{
|
|
TURN: TURNOpts{
|
|
Host: r.Turn,
|
|
Port: r.Port,
|
|
TransportUDP: r.Transport == TransportUDP,
|
|
N: n,
|
|
},
|
|
Obf: ObfOpts{
|
|
Profile: ObfProfile(r.ObfProfile),
|
|
GenKey: r.GenObfKey,
|
|
Timing: r.ObfTiming,
|
|
},
|
|
Proxy: ProxyOpts{
|
|
Mode: ProxyMode(r.Mode),
|
|
Listen: r.Listen,
|
|
Peer: r.Peer,
|
|
},
|
|
Provider: ProviderOpts{Name: r.Provider},
|
|
VK: VKOpts{
|
|
Links: normalizeVKLinks(r.Links, r.Link),
|
|
StreamsPerCred: r.StreamsPerCred,
|
|
ManualCaptcha: r.ManualCaptcha,
|
|
Platform: platform,
|
|
},
|
|
DNS: DNSOpts{Mode: r.DNSMode},
|
|
Log: LogOpts{Debug: r.Debug},
|
|
KCP: KCPOpts{Profile: r.KCP},
|
|
Tunnel: TunnelOpts{
|
|
Mode: tunnel.Mode(r.TunnelMode),
|
|
Config: r.TunnelConfig,
|
|
MTU: tunnelMTU,
|
|
},
|
|
ClientID: r.ClientID,
|
|
SubURL: r.SubURL,
|
|
Routes: r.Routes,
|
|
}
|
|
|
|
if r.DNSServers != "" {
|
|
c.DNS.Servers = strings.Split(r.DNSServers, ",")
|
|
}
|
|
|
|
if c.Obf.GenKey {
|
|
return c, nil
|
|
}
|
|
if err := validateObfProfile(c.Obf.Profile); err != nil {
|
|
return nil, err
|
|
}
|
|
key, err := rtpopus.DecodeKey(c.Obf.Enabled(), r.ObfKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
c.Obf.Key = key
|
|
|
|
return c, nil
|
|
}
|
|
|
|
// normalizeVKLinks извлекает join-код звонка из URL или строки кода.
|
|
func normalizeVKLinks(links, link string) []string {
|
|
items := strings.Split(links, ",")
|
|
if len(items) == 1 && items[0] == "" {
|
|
items = []string{link}
|
|
}
|
|
out := make([]string, 0, len(items))
|
|
for _, item := range items {
|
|
item = strings.TrimSpace(item)
|
|
if item == "" {
|
|
continue
|
|
}
|
|
parts := strings.Split(item, "join/")
|
|
code := parts[len(parts)-1]
|
|
if idx := strings.IndexAny(code, "/?#"); idx != -1 {
|
|
code = code[:idx]
|
|
}
|
|
if code != "" {
|
|
out = append(out, code)
|
|
}
|
|
}
|
|
if len(out) == 0 {
|
|
return nil
|
|
}
|
|
return out
|
|
}
|