diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d9e3c16 --- /dev/null +++ b/LICENSE @@ -0,0 +1,47 @@ +Server Side Public License (SSPL) v1.0 + +Copyright © 2025 Roman Nikolskii (romb.intu@gmail.com) + +NOTICE: This license imposes commercial use restrictions for offering this software as a service. Consult legal advice before deployment. +1. Definitions + "Software": The godpn project and its derivative works. + "Service": Any offering allowing third parties to interact with the Software’s functionality via a network. + +2. Permissions + +Subject to compliance with this license, you are granted: +✅ Use: Run the Software for any purpose, private or commercial. +✅ Modification: Create derivative works. +✅ Distribution: Redistribute source or object code. +3. Restrictions + +❌ No Commercial SaaS: You may not offer the Software (or modifications) as a publicly available Service without: + Open-sourcing all modifications and infrastructure code under SSPL, or + Obtaining a commercial license from the copyright holder (Roman Nikolskii). + +❌ No Circumvention: You may not bypass technical enforcement mechanisms. +4. Service Provider Requirements + +If you operate a Service using this Software, you must: + Disclose Source: Make available to all users: + The complete source code of the Software, including all modifications. + The source code of all system components needed to run the Service (e.g., management software, APIs). + Offer License: Provide instructions for users to obtain the source under SSPL. + +5. Attribution + +All copies must retain: + This license file. + Copyright notices in source files. + +6. Disclaimer + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR DAMAGES ARISING FROM ITS USE. +7. License Compatibility + Third-party dependencies (e.g., go-shadowsocks2) remain under their original licenses (e.g., Apache 2.0). + This license applies only to original code authored by Roman Nikolskii in the godpn project. + +8. Contact + +For commercial licensing inquiries: +📧 Roman Nikolskii – romb.intu@gmail.com diff --git a/README.md b/README.md new file mode 100644 index 0000000..5142a72 --- /dev/null +++ b/README.md @@ -0,0 +1,77 @@ +# GODPN - Decentralized Private Network + +## 🏛️ Архитектура +1. Компоненты системы + +1.1 Трекер (Coordinator Server) + +Роль: Управляет пирами, собирает метрики, назначает оптимальные подключения. + +Функции: + + Регистрирует пиры (IP, порт, доступная пропускная способность, геолокация). + Собирает статистику: скорость, пинг, трафик. + Ранжирует пиры для клиентов (по скорости/стабильности). + Начисляет монеты за трафик, списывает их у клиентов. + +Технологии: + + Echo (HTTP API для клиентов и пиров). + gRPC (для быстрого обмена метриками). + Redis (кеш рейтингов пиров). + PostgreSQL/SQLite3 (хранение данных пользователей, транзакций). + +1.2. Клиент (VPN Client) + +Роль: Подключается к пирам или центральным серверам через Shadowsocks. + +Функции: + + Получает список пиров от трекера. + Тестирует подключение (ping, speedtest). + Выбирает лучший пир/сервер. + Учитывает потраченные/заработанные монеты. + +Технологии: + + go-shadowsocks2 (подключение через SOCKS5). + libp2p (для P2P-подключений). + +1.3. Пир (Peer Node) + +Роль: Раздает трафик другим клиентам за монеты. + +Функции: + + Регистрируется на трекере. + Принимает подключения через Shadowsocks. + Отправляет метрики (трафик, скорость) трекеру. + Получает вознаграждение в монетах. + +Технологии: + + go-shadowsocks2 (режим сервера). + Prometheus + Grafana (мониторинг). + +2. Как работает трафик + +2.1. Подключение клиента + + Клиент запрашивает у трекера список доступных пиров. + Трекер возвращает доступные пиры по скорости/стоимости. + Клиент тестирует их и подключается к лучшему. + Весь трафик идет через Shadowsocks-туннель (Можно настроить). + +3. Монетизация + +3.1. Внутренняя валюта + + Монеты (токены) начисляются за отданный трафик. + Клиенты покупают подписку или тратят монеты на трафик. + +## 📜 Лицензия +Этот проект распространяется под **SSPL-1.0**. +Коммерческое использование в качестве сервиса (SaaS) без разрешения автора запрещено. + +Данная лицензия (SSPL) применяется только к коду, написанному автором godpn. +Сторонние библиотеки (например, go-shadowsocks2) используются под их исходными лицензиями. diff --git a/cmd/server/main.go b/cmd/server/main.go index 4f69ba0..cb28d83 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -3,11 +3,11 @@ package main import ( "log/slog" - "github.com/rombintu/godpn/internal/tracker" + "github.com/rombintu/godpn/internal/coordinator" ) func main() { - server := tracker.NewServer() + server := coordinator.NewServer() server.Configure() if err := server.Run(); err != nil { slog.Info(err.Error()) diff --git a/internal/coordinator/coordinator.go b/internal/coordinator/coordinator.go new file mode 100644 index 0000000..97833c2 --- /dev/null +++ b/internal/coordinator/coordinator.go @@ -0,0 +1,16 @@ +package coordinator + +import "github.com/rombintu/godpn/internal/models" + +type Coordinator struct { + // TODO временное решение + // + // ip : Peer + peers map[string]models.PeerNode +} + +func NewCoordinator() *Coordinator { + return &Coordinator{ + peers: make(map[string]models.PeerNode), + } +} diff --git a/internal/tracker/handlers.go b/internal/coordinator/handlers.go similarity index 74% rename from internal/tracker/handlers.go rename to internal/coordinator/handlers.go index 3eef7ea..5697b79 100644 --- a/internal/tracker/handlers.go +++ b/internal/coordinator/handlers.go @@ -1,4 +1,4 @@ -package tracker +package coordinator import ( "net/http" @@ -9,27 +9,26 @@ import ( ) func (s *Server) registerHandler(c echo.Context) error { - var peer models.PeerManifest - if err := c.Bind(peer); err != nil { + var node models.PeerNode + if err := c.Bind(node); err != nil { return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request"}) } - if peer.PubKey == "" { - return c.JSON(http.StatusBadRequest, map[string]string{"error": "pubkey is required"}) + if node.PublicKey == "" { + return c.JSON(http.StatusBadRequest, map[string]string{"error": "public key is required"}) } ip := c.RealIP() - if peer.IP != "" { - ip = peer.IP + if node.Endpoint != "" { + ip = node.Endpoint } s.mu.Lock() - s.tracker.peers[ip] = peer.PubKey + s.coordinator.peers[ip] = node s.mu.Unlock() - return c.JSON(http.StatusOK, map[string]string{ - "status": "registered", - "ip": ip, + return c.JSON(http.StatusOK, map[string]models.PeerNode{ + "registered": node, }) } @@ -37,7 +36,7 @@ func (s *Server) registerHandler(c echo.Context) error { func (s *Server) listPeers(c echo.Context) error { s.mu.RLock() defer s.mu.RUnlock() - return c.JSON(http.StatusOK, s.tracker.peers) + return c.JSON(http.StatusOK, s.coordinator.peers) } // WebSocket handler для реального времени @@ -54,7 +53,7 @@ func (s *Server) websocketHandler(c echo.Context) error { // Отправляем текущий список peers при подключении s.mu.RLock() - if err := ws.WriteJSON(s.tracker.peers); err != nil { + if err := ws.WriteJSON(s.coordinator.peers); err != nil { s.mu.RUnlock() return err } diff --git a/internal/tracker/server.go b/internal/coordinator/server.go similarity index 77% rename from internal/tracker/server.go rename to internal/coordinator/server.go index b441156..ab0666c 100644 --- a/internal/tracker/server.go +++ b/internal/coordinator/server.go @@ -1,4 +1,4 @@ -package tracker +package coordinator import ( "sync" @@ -8,15 +8,15 @@ import ( ) type Server struct { - router *echo.Echo - mu sync.RWMutex - tracker *Tracker + router *echo.Echo + mu sync.RWMutex + coordinator *Coordinator } func NewServer() *Server { return &Server{ - router: echo.New(), - tracker: NewTracker(), + router: echo.New(), + coordinator: NewCoordinator(), } } diff --git a/internal/models/peer.go b/internal/models/peer.go index 7e2a8f9..524641a 100644 --- a/internal/models/peer.go +++ b/internal/models/peer.go @@ -1,6 +1,29 @@ package models -type PeerManifest struct { - IP string `json:"ip" form:"ip" query:"ip"` - PubKey string `json:"pubkey" form:"pubkey" query:"pubkey" validate:"required"` +import "time" + +type PeerNode struct { + // Basic identity + PublicKey string `json:"public_key" validate:"required"` // WireGuard/SS public key + + // Network information + Endpoint string `json:"endpoint"` // IP:Port or DNS + Protocol string `json:"protocol"` // "shadowsocks", "wireguard", etc + + // Performance metrics + System string `json:"system"` // "linux", "windows", etc + Latency int `json:"latency"` // in milliseconds + Bandwidth int `json:"bandwidth"` // in Mbps + + // Geo information + Region string `json:"region,omitempty"` // "eu-west", "us-east" + Country string `json:"country,omitempty"` // 2-letter ISO code + + // System stats + Uptime float64 `json:"uptime"` // 0.0-1.0 percentage + Load float64 `json:"load"` // 5-min system load avg + + // Timestamps + LastSeen time.Time `json:"last_seen"` + FirstSeen time.Time `json:"first_seen"` } diff --git a/internal/peer/handlers.go b/internal/peer/handlers.go index d949744..364c1d0 100644 --- a/internal/peer/handlers.go +++ b/internal/peer/handlers.go @@ -6,14 +6,14 @@ import ( ) func (s *Server) connectHandler(c echo.Context) error { - var peerManifest models.PeerManifest + var node models.PeerNode - if err := c.Bind(peerManifest); err != nil { + if err := c.Bind(node); err != nil { return err } - peer := NewPeer(peerManifest.PubKey) - if err := peer.Connect(peerManifest.IP, "8080"); err != nil { + peer := NewPeer(node.PublicKey) + if err := peer.Connect(node.Endpoint); err != nil { return err } defer peer.Disconnect() diff --git a/internal/peer/peer.go b/internal/peer/peer.go index 79c6398..3c607cc 100644 --- a/internal/peer/peer.go +++ b/internal/peer/peer.go @@ -11,8 +11,9 @@ import ( ) const ( - tcpNetwork = "tcp" - bufferSize = 32 * 1024 // 32KB + tcpNetwork = "tcp" + bufferSize = 32 * 1024 // 32KB + AHEAD_CHACHA20_POLY1305 = "AEAD_CHACHA20_POLY1305" // Default method cipher ) // Ошибки подключения @@ -34,7 +35,7 @@ func NewPeer(pubKey string) *Peer { } } -func (p *Peer) Connect(ip, port string) error { +func (p *Peer) Connect(endpoint string) error { p.mu.Lock() defer p.mu.Unlock() @@ -42,12 +43,12 @@ func (p *Peer) Connect(ip, port string) error { return nil // Уже подключен } - conn, err := net.Dial(tcpNetwork, net.JoinHostPort(ip, port)) + conn, err := net.Dial(tcpNetwork, endpoint) if err != nil { return err } - cipher, err := core.PickCipher("AEAD_CHACHA20_POLY1305", []byte(p.pubKey), "") + cipher, err := core.PickCipher(AHEAD_CHACHA20_POLY1305, []byte(p.pubKey), "") if err != nil { conn.Close() return err diff --git a/internal/tracker/tracker.go b/internal/tracker/tracker.go deleted file mode 100644 index 937a0ca..0000000 --- a/internal/tracker/tracker.go +++ /dev/null @@ -1,11 +0,0 @@ -package tracker - -type Tracker struct { - peers map[string]string -} - -func NewTracker() *Tracker { - return &Tracker{ - peers: make(map[string]string), - } -}