Added new MessageType for ConnectReverse.

Added PublicAddress configuration to entry node.
This commit is contained in:
dd dd 2024-07-26 12:37:11 +02:00
parent e261e422c1
commit 9cfbd2329d
7 changed files with 64 additions and 29 deletions

View File

@ -9,7 +9,7 @@ import (
func main() { func main() {
// load the configuration // load the configuration
// from the environment // from the environment
cfg, err := config.LoadConfig[config.ProxyConfig]() cfg, err := config.LoadConfig[config.EntryConfig]()
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@ -9,8 +9,9 @@ import (
"github.com/joho/godotenv" "github.com/joho/godotenv"
) )
type ProxyConfig struct { type EntryConfig struct {
NostrRelays []string `env:"NOSTR_RELAYS" envSeparator:";"` NostrRelays []string `env:"NOSTR_RELAYS" envSeparator:";"`
PublicAddress string `env:"PUBLIC_ADDRESS"`
} }
type ExitConfig struct { type ExitConfig struct {

View File

@ -231,7 +231,7 @@ func (e *Exit) handleConnect(ctx context.Context, msg nostr.IncomingEvent, proto
func (e *Exit) handleConnectReverse(ctx context.Context, protocolMessage *protocol.Message, isTLS bool) { func (e *Exit) handleConnectReverse(ctx context.Context, protocolMessage *protocol.Message, isTLS bool) {
e.mutexMap.Lock(protocolMessage.Key.String()) e.mutexMap.Lock(protocolMessage.Key.String())
defer e.mutexMap.Unlock(protocolMessage.Key.String()) defer e.mutexMap.Unlock(protocolMessage.Key.String())
connection, err := net.Dial("tcp", ":1234") connection, err := net.Dial("tcp", protocolMessage.Destination)
if err != nil { if err != nil {
return return
} }

View File

@ -11,13 +11,20 @@ import (
"strings" "strings"
) )
type DialOptions struct {
Pool *nostr.SimplePool
PublicAddress string
ConnectionID uuid.UUID
MessageType protocol.MessageType
}
// DialSocks connects to a destination using the provided SimplePool and returns a Dialer function. // DialSocks connects to a destination using the provided SimplePool and returns a Dialer function.
// It creates a new Connection using the specified context, private key, destination address, subscription flag, and connectionID. // It creates a new Connection using the specified context, private key, destination address, subscription flag, and connectionID.
// It parses the destination address to get the public key and relays. // It parses the destination address to get the public key and relays.
// It creates a signed event using the private key, public key, and destination address. // It creates a signed event using the private key, public key, and destination address.
// It ensures that the relays are available in the pool and publishes the signed event to each relay. // It ensures that the relays are available in the pool and publishes the signed event to each relay.
// Finally, it returns the Connection and nil error. If there are any errors, nil connection and the error are returned. // Finally, it returns the Connection and nil error. If there are any errors, nil connection and the error are returned.
func DialSocks(pool *nostr.SimplePool, connectionID uuid.UUID) func(ctx context.Context, net_, addr string) (net.Conn, error) { func DialSocks(options DialOptions) func(ctx context.Context, net_, addr string) (net.Conn, error) {
return func(ctx context.Context, net_, addr string) (net.Conn, error) { return func(ctx context.Context, net_, addr string) (net.Conn, error) {
addr = strings.ReplaceAll(addr, ".", "") addr = strings.ReplaceAll(addr, ".", "")
key := nostr.GeneratePrivateKey() key := nostr.GeneratePrivateKey()
@ -25,7 +32,7 @@ func DialSocks(pool *nostr.SimplePool, connectionID uuid.UUID) func(ctx context.
WithPrivateKey(key), WithPrivateKey(key),
WithDst(addr), WithDst(addr),
WithSub(), WithSub(),
WithUUID(connectionID)) WithUUID(options.ConnectionID))
publicKey, relays, err := ParseDestination(addr) publicKey, relays, err := ParseDestination(addr)
if err != nil { if err != nil {
@ -38,16 +45,20 @@ func DialSocks(pool *nostr.SimplePool, connectionID uuid.UUID) func(ctx context.
return nil, err return nil, err
} }
opts := []protocol.MessageOption{ opts := []protocol.MessageOption{
protocol.WithType(protocol.MessageConnectReverse), protocol.WithType(options.MessageType),
protocol.WithUUID(connectionID), protocol.WithUUID(options.ConnectionID),
protocol.WithDestination(addr), }
if options.PublicAddress != "" {
opts = append(opts, protocol.WithDestination(options.PublicAddress))
} else {
opts = append(opts, protocol.WithDestination(addr)) // todo -- use public key instead
} }
ev, err := signer.CreateSignedEvent(publicKey, protocol.KindEphemeralEvent, ev, err := signer.CreateSignedEvent(publicKey, protocol.KindEphemeralEvent,
nostr.Tags{nostr.Tag{"p", publicKey}}, nostr.Tags{nostr.Tag{"p", publicKey}},
opts...) opts...)
for _, relayUrl := range relays { for _, relayUrl := range relays {
relay, err := pool.EnsureRelay(relayUrl) relay, err := options.Pool.EnsureRelay(relayUrl)
if err != nil { if err != nil {
slog.Error("error creating relay", err) slog.Error("error creating relay", err)
continue continue

View File

@ -11,14 +11,14 @@ import (
) )
type Proxy struct { type Proxy struct {
config *config.ProxyConfig // the configuration for the gateway config *config.EntryConfig // the configuration for the gateway
// a list of nostr relays to publish events to // a list of nostr relays to publish events to
relays []*nostr.Relay // deprecated -- should be used for default relay configuration relays []*nostr.Relay // deprecated -- should be used for default relay configuration
pool *nostr.SimplePool pool *nostr.SimplePool
socksServer *socks5.Server socksServer *socks5.Server
} }
func New(ctx context.Context, config *config.ProxyConfig) *Proxy { func New(ctx context.Context, config *config.EntryConfig) *Proxy {
s := &Proxy{ s := &Proxy{
config: config, config: config,
pool: nostr.NewSimplePool(ctx), pool: nostr.NewSimplePool(ctx),
@ -32,7 +32,7 @@ func New(ctx context.Context, config *config.ProxyConfig) *Proxy {
BindIP: net.IP{0, 0, 0, 0}, BindIP: net.IP{0, 0, 0, 0},
Logger: nil, Logger: nil,
Dial: nil, Dial: nil,
}, s.pool) }, s.pool, config)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/asmogo/nws/netstr" "github.com/asmogo/nws/netstr"
"github.com/asmogo/nws/protocol"
"github.com/google/uuid" "github.com/google/uuid"
"io" "io"
"net" "net"
@ -169,10 +170,20 @@ func (s *Server) handleConnect(ctx context.Context, conn net.Conn, req *Request)
// Attempt to connect // Attempt to connect
dial := s.config.Dial dial := s.config.Dial
ch := make(chan net.Conn) ch := make(chan net.Conn)
connectionID := uuid.New()
options := netstr.DialOptions{
Pool: s.pool,
PublicAddress: s.config.entryConfig.PublicAddress,
ConnectionID: connectionID,
}
if dial == nil { if dial == nil {
connectionID := uuid.New() if s.tcpListener != nil {
s.tcpListener.AddConnectChannel(connectionID, ch) s.tcpListener.AddConnectChannel(connectionID, ch)
dial = netstr.DialSocks(s.pool, connectionID) options.MessageType = protocol.MessageConnectReverse
} else {
options.MessageType = protocol.MessageConnect
}
dial = netstr.DialSocks(options)
} }
target, err := dial(ctx, "tcp", req.realDestAddr.FQDN) target, err := dial(ctx, "tcp", req.realDestAddr.FQDN)
if err != nil { if err != nil {
@ -197,11 +208,14 @@ func (s *Server) handleConnect(ctx context.Context, conn net.Conn, req *Request)
return fmt.Errorf("failed to send reply: %v", err) return fmt.Errorf("failed to send reply: %v", err)
} }
// read // read
var connR net.Conn
// wait for the connection if options.MessageType == protocol.MessageConnectReverse {
connR := <-ch // wait for the connection
defer connR.Close() connR = <-ch
defer connR.Close()
} else {
connR = target
}
// Start proxying // Start proxying
errCh := make(chan error, 2) errCh := make(chan error, 2)
go Proxy(connR, conn, errCh) go Proxy(connR, conn, errCh)

View File

@ -3,6 +3,7 @@ package socks5
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"github.com/asmogo/nws/config"
"github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr"
"log" "log"
"net" "net"
@ -49,6 +50,8 @@ type Config struct {
// Optional function for dialing out // Optional function for dialing out
Dial func(ctx context.Context, network, addr string) (net.Conn, error) Dial func(ctx context.Context, network, addr string) (net.Conn, error)
entryConfig *config.EntryConfig
} }
var ErrorNoServerAvailable = fmt.Errorf("no socks server available") var ErrorNoServerAvailable = fmt.Errorf("no socks server available")
@ -63,7 +66,7 @@ type Server struct {
} }
// New creates a new Server and potentially returns an error // New creates a new Server and potentially returns an error
func New(conf *Config, pool *nostr.SimplePool) (*Server, error) { func New(conf *Config, pool *nostr.SimplePool, config *config.EntryConfig) (*Server, error) {
// Ensure we have at least one authentication method enabled // Ensure we have at least one authentication method enabled
if len(conf.AuthMethods) == 0 { if len(conf.AuthMethods) == 0 {
if conf.Credentials != nil { if conf.Credentials != nil {
@ -87,15 +90,21 @@ func New(conf *Config, pool *nostr.SimplePool) (*Server, error) {
if conf.Logger == nil { if conf.Logger == nil {
conf.Logger = log.New(os.Stdout, "", log.LstdFlags) conf.Logger = log.New(os.Stdout, "", log.LstdFlags)
} }
listener, err := NewTCPListener() if conf.entryConfig == nil {
if err != nil { conf.entryConfig = config
return nil, err
} }
go listener.Start()
server := &Server{ server := &Server{
config: conf, config: conf,
pool: pool, pool: pool,
tcpListener: listener, }
if conf.entryConfig.PublicAddress != "" {
listener, err := NewTCPListener()
if err != nil {
return nil, err
}
go listener.Start()
server.tcpListener = listener
} }
server.authMethods = make(map[uint8]Authenticator) server.authMethods = make(map[uint8]Authenticator)