feat: INP2P v0.1.0 — complete P2P tunneling system
Core modules (M1-M6): - pkg/protocol: message format, encoding, NAT type enums - pkg/config: server/client config structs, env vars, validation - pkg/auth: CRC64 token, TOTP gen/verify, one-time relay tokens - pkg/nat: UDP/TCP STUN client and server - pkg/signal: WSS message dispatch, sync request/response - pkg/punch: UDP/TCP hole punching + priority chain - pkg/mux: stream multiplexer (7B frame: StreamID+Flags+Len) - pkg/tunnel: mux-based port forwarding with stats - pkg/relay: relay manager with TOTP auth + session bridging - internal/server: signaling server (login/heartbeat/report/coordinator) - internal/client: client (NAT detect/login/punch/relay/reconnect) - cmd/inp2ps + cmd/inp2pc: main entrypoints with graceful shutdown All tests pass: 16 tests across 5 packages Code: 3559 lines core + 861 lines tests = 19 source files
This commit is contained in:
161
pkg/config/config.go
Normal file
161
pkg/config/config.go
Normal file
@@ -0,0 +1,161 @@
|
||||
// Package config provides shared configuration types.
|
||||
package config
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
Version = "0.1.0"
|
||||
|
||||
DefaultWSPort = 27183 // WSS signaling
|
||||
DefaultSTUNUDP1 = 27182 // UDP STUN port 1
|
||||
DefaultSTUNUDP2 = 27183 // UDP STUN port 2
|
||||
DefaultSTUNTCP1 = 27180 // TCP STUN port 1
|
||||
DefaultSTUNTCP2 = 27181 // TCP STUN port 2
|
||||
DefaultWebPort = 10088 // Web console
|
||||
DefaultAPIPort = 10008 // REST API
|
||||
|
||||
DefaultMaxRelayLoad = 20
|
||||
DefaultRelayPort = 27185
|
||||
|
||||
HeartbeatInterval = 30 // seconds
|
||||
HeartbeatTimeout = 90 // seconds — 3x missed heartbeats → offline
|
||||
)
|
||||
|
||||
// ServerConfig holds inp2ps configuration.
|
||||
type ServerConfig struct {
|
||||
WSPort int `json:"wsPort"`
|
||||
STUNUDP1 int `json:"stunUDP1"`
|
||||
STUNUDP2 int `json:"stunUDP2"`
|
||||
STUNTCP1 int `json:"stunTCP1"`
|
||||
STUNTCP2 int `json:"stunTCP2"`
|
||||
WebPort int `json:"webPort"`
|
||||
APIPort int `json:"apiPort"`
|
||||
DBPath string `json:"dbPath"`
|
||||
CertFile string `json:"certFile"`
|
||||
KeyFile string `json:"keyFile"`
|
||||
LogLevel int `json:"logLevel"` // 0=debug, 1=info, 2=warn, 3=error
|
||||
Token uint64 `json:"token"` // master token for auth
|
||||
JWTKey string `json:"jwtKey"` // auto-generated if empty
|
||||
|
||||
AdminUser string `json:"adminUser"`
|
||||
AdminPass string `json:"adminPass"`
|
||||
}
|
||||
|
||||
func DefaultServerConfig() ServerConfig {
|
||||
return ServerConfig{
|
||||
WSPort: DefaultWSPort,
|
||||
STUNUDP1: DefaultSTUNUDP1,
|
||||
STUNUDP2: DefaultSTUNUDP2,
|
||||
STUNTCP1: DefaultSTUNTCP1,
|
||||
STUNTCP2: DefaultSTUNTCP2,
|
||||
WebPort: DefaultWebPort,
|
||||
APIPort: DefaultAPIPort,
|
||||
DBPath: "inp2ps.db",
|
||||
LogLevel: 1,
|
||||
AdminUser: "admin",
|
||||
AdminPass: "admin123",
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ServerConfig) FillFromEnv() {
|
||||
if v := os.Getenv("INP2PS_WS_PORT"); v != "" {
|
||||
c.WSPort, _ = strconv.Atoi(v)
|
||||
}
|
||||
if v := os.Getenv("INP2PS_WEB_PORT"); v != "" {
|
||||
c.WebPort, _ = strconv.Atoi(v)
|
||||
}
|
||||
if v := os.Getenv("INP2PS_DB_PATH"); v != "" {
|
||||
c.DBPath = v
|
||||
}
|
||||
if v := os.Getenv("INP2PS_TOKEN"); v != "" {
|
||||
c.Token, _ = strconv.ParseUint(v, 10, 64)
|
||||
}
|
||||
if v := os.Getenv("INP2PS_CERT"); v != "" {
|
||||
c.CertFile = v
|
||||
}
|
||||
if v := os.Getenv("INP2PS_KEY"); v != "" {
|
||||
c.KeyFile = v
|
||||
}
|
||||
if c.JWTKey == "" {
|
||||
b := make([]byte, 32)
|
||||
rand.Read(b)
|
||||
c.JWTKey = hex.EncodeToString(b)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ServerConfig) Validate() error {
|
||||
if c.Token == 0 {
|
||||
return fmt.Errorf("token is required (INP2PS_TOKEN or -token)")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClientConfig holds inp2pc configuration.
|
||||
type ClientConfig struct {
|
||||
ServerHost string `json:"serverHost"`
|
||||
ServerPort int `json:"serverPort"`
|
||||
Node string `json:"node"`
|
||||
Token uint64 `json:"token"`
|
||||
User string `json:"user,omitempty"`
|
||||
Insecure bool `json:"insecure"` // skip TLS verify
|
||||
|
||||
// STUN ports (defaults match server defaults)
|
||||
STUNUDP1 int `json:"stunUDP1,omitempty"`
|
||||
STUNUDP2 int `json:"stunUDP2,omitempty"`
|
||||
STUNTCP1 int `json:"stunTCP1,omitempty"`
|
||||
STUNTCP2 int `json:"stunTCP2,omitempty"`
|
||||
|
||||
RelayEnabled bool `json:"relayEnabled"` // --relay
|
||||
SuperRelay bool `json:"superRelay"` // --super
|
||||
RelayPort int `json:"relayPort"`
|
||||
MaxRelayLoad int `json:"maxRelayLoad"`
|
||||
|
||||
ShareBandwidth int `json:"shareBandwidth"` // Mbps
|
||||
LogLevel int `json:"logLevel"`
|
||||
|
||||
Apps []AppConfig `json:"apps"`
|
||||
}
|
||||
|
||||
type AppConfig struct {
|
||||
AppName string `json:"appName"`
|
||||
Protocol string `json:"protocol"` // tcp, udp
|
||||
SrcPort int `json:"srcPort"`
|
||||
PeerNode string `json:"peerNode"`
|
||||
DstHost string `json:"dstHost"`
|
||||
DstPort int `json:"dstPort"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
func DefaultClientConfig() ClientConfig {
|
||||
return ClientConfig{
|
||||
ServerPort: DefaultWSPort,
|
||||
STUNUDP1: DefaultSTUNUDP1,
|
||||
STUNUDP2: DefaultSTUNUDP2,
|
||||
STUNTCP1: DefaultSTUNTCP1,
|
||||
STUNTCP2: DefaultSTUNTCP2,
|
||||
ShareBandwidth: 10,
|
||||
RelayPort: DefaultRelayPort,
|
||||
MaxRelayLoad: DefaultMaxRelayLoad,
|
||||
LogLevel: 1,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ClientConfig) Validate() error {
|
||||
if c.ServerHost == "" {
|
||||
return fmt.Errorf("serverHost is required")
|
||||
}
|
||||
if c.Token == 0 {
|
||||
return fmt.Errorf("token is required")
|
||||
}
|
||||
if c.Node == "" {
|
||||
hostname, _ := os.Hostname()
|
||||
c.Node = hostname
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user