This commit is contained in:
nic
2025-07-23 17:56:38 +03:00
parent a31b9310a2
commit 1c181d7e22
10 changed files with 196 additions and 44 deletions
+47
View File
@@ -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 Softwares 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
+77
View File
@@ -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) используются под их исходными лицензиями.
+2 -2
View File
@@ -3,11 +3,11 @@ package main
import ( import (
"log/slog" "log/slog"
"github.com/rombintu/godpn/internal/tracker" "github.com/rombintu/godpn/internal/coordinator"
) )
func main() { func main() {
server := tracker.NewServer() server := coordinator.NewServer()
server.Configure() server.Configure()
if err := server.Run(); err != nil { if err := server.Run(); err != nil {
slog.Info(err.Error()) slog.Info(err.Error())
+16
View File
@@ -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),
}
}
@@ -1,4 +1,4 @@
package tracker package coordinator
import ( import (
"net/http" "net/http"
@@ -9,27 +9,26 @@ import (
) )
func (s *Server) registerHandler(c echo.Context) error { func (s *Server) registerHandler(c echo.Context) error {
var peer models.PeerManifest var node models.PeerNode
if err := c.Bind(peer); err != nil { if err := c.Bind(node); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request"})
} }
if peer.PubKey == "" { if node.PublicKey == "" {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "pubkey is required"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "public key is required"})
} }
ip := c.RealIP() ip := c.RealIP()
if peer.IP != "" { if node.Endpoint != "" {
ip = peer.IP ip = node.Endpoint
} }
s.mu.Lock() s.mu.Lock()
s.tracker.peers[ip] = peer.PubKey s.coordinator.peers[ip] = node
s.mu.Unlock() s.mu.Unlock()
return c.JSON(http.StatusOK, map[string]string{ return c.JSON(http.StatusOK, map[string]models.PeerNode{
"status": "registered", "registered": node,
"ip": ip,
}) })
} }
@@ -37,7 +36,7 @@ func (s *Server) registerHandler(c echo.Context) error {
func (s *Server) listPeers(c echo.Context) error { func (s *Server) listPeers(c echo.Context) error {
s.mu.RLock() s.mu.RLock()
defer s.mu.RUnlock() defer s.mu.RUnlock()
return c.JSON(http.StatusOK, s.tracker.peers) return c.JSON(http.StatusOK, s.coordinator.peers)
} }
// WebSocket handler для реального времени // WebSocket handler для реального времени
@@ -54,7 +53,7 @@ func (s *Server) websocketHandler(c echo.Context) error {
// Отправляем текущий список peers при подключении // Отправляем текущий список peers при подключении
s.mu.RLock() s.mu.RLock()
if err := ws.WriteJSON(s.tracker.peers); err != nil { if err := ws.WriteJSON(s.coordinator.peers); err != nil {
s.mu.RUnlock() s.mu.RUnlock()
return err return err
} }
@@ -1,4 +1,4 @@
package tracker package coordinator
import ( import (
"sync" "sync"
@@ -8,15 +8,15 @@ import (
) )
type Server struct { type Server struct {
router *echo.Echo router *echo.Echo
mu sync.RWMutex mu sync.RWMutex
tracker *Tracker coordinator *Coordinator
} }
func NewServer() *Server { func NewServer() *Server {
return &Server{ return &Server{
router: echo.New(), router: echo.New(),
tracker: NewTracker(), coordinator: NewCoordinator(),
} }
} }
+26 -3
View File
@@ -1,6 +1,29 @@
package models package models
type PeerManifest struct { import "time"
IP string `json:"ip" form:"ip" query:"ip"`
PubKey string `json:"pubkey" form:"pubkey" query:"pubkey" validate:"required"` 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"`
} }
+4 -4
View File
@@ -6,14 +6,14 @@ import (
) )
func (s *Server) connectHandler(c echo.Context) error { 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 return err
} }
peer := NewPeer(peerManifest.PubKey) peer := NewPeer(node.PublicKey)
if err := peer.Connect(peerManifest.IP, "8080"); err != nil { if err := peer.Connect(node.Endpoint); err != nil {
return err return err
} }
defer peer.Disconnect() defer peer.Disconnect()
+6 -5
View File
@@ -11,8 +11,9 @@ import (
) )
const ( const (
tcpNetwork = "tcp" tcpNetwork = "tcp"
bufferSize = 32 * 1024 // 32KB 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() p.mu.Lock()
defer p.mu.Unlock() defer p.mu.Unlock()
@@ -42,12 +43,12 @@ func (p *Peer) Connect(ip, port string) error {
return nil // Уже подключен return nil // Уже подключен
} }
conn, err := net.Dial(tcpNetwork, net.JoinHostPort(ip, port)) conn, err := net.Dial(tcpNetwork, endpoint)
if err != nil { if err != nil {
return err 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 { if err != nil {
conn.Close() conn.Close()
return err return err
-11
View File
@@ -1,11 +0,0 @@
package tracker
type Tracker struct {
peers map[string]string
}
func NewTracker() *Tracker {
return &Tracker{
peers: make(map[string]string),
}
}