package obfsvpn import ( "bytes" "context" "crypto/rand" "encoding/hex" "net" pt "git.torproject.org/pluggable-transports/goptlib.git" "gitlab.com/yawning/obfs4.git/common/ntor" "gitlab.com/yawning/obfs4.git/transports/base" "gitlab.com/yawning/obfs4.git/transports/obfs4" ) // ListenConfig contains options for listening to an address. // If Seed is not set it defaults to a randomized value. // If StateDir is not set the current working directory is used. type ListenConfig struct { ListenConfig net.ListenConfig NodeID *ntor.NodeID PrivateKey *ntor.PrivateKey Seed [ntor.KeySeedLength]byte StateDir string } // NewListenConfigCert creates a listener config by unpacking the node ID from // its certificate. // The private key must still be specified. func NewListenConfigCert(cert string) (*ListenConfig, error) { nodeID, _, err := unpackCert(cert) if err != nil { return nil, err } return &ListenConfig{ NodeID: nodeID, }, nil } // Wrap takes an existing net.Listener and wraps it in a listener that is // configured to perform the ntor handshake. // Values from the inner net.ListenConfig are ignored. func (lc *ListenConfig) Wrap(ctx context.Context, ln net.Listener) (*Listener, error) { args := make(pt.Args) args.Add("node-id", lc.NodeID.Hex()) args.Add("private-key", lc.PrivateKey.Hex()) seed := ntor.KeySeed{} if bytes.Equal(lc.Seed[:], seed[:]) { _, err := rand.Read(seed[:]) if err != nil { return nil, err } } else { seed = lc.Seed } args.Add("drbg-seed", hex.EncodeToString(seed[:])) sf, err := (&obfs4.Transport{}).ServerFactory(lc.StateDir, &args) if err != nil { return nil, err } return &Listener{sf: sf, ln: ln}, nil } // Listen announces on the local network address. // // See func net.Dial for a description of the network and address parameters. func (lc *ListenConfig) Listen(ctx context.Context, network, address string) (*Listener, error) { ln, err := lc.ListenConfig.Listen(ctx, network, address) if err != nil { return nil, err } return lc.Wrap(ctx, ln) } // Listener is a network listener that accepts obfuscated connections and // performs the ntor handshake on them. type Listener struct { sf base.ServerFactory ln net.Listener } // Accept waits for and returns the next connection to the listener. func (l *Listener) Accept() (net.Conn, error) { conn, err := l.ln.Accept() if err != nil { return nil, err } conn, err = l.sf.WrapConn(conn) return conn, err } // Close closes the listener. // Any blocked Accept operations will be unblocked and return errors. func (l *Listener) Close() error { return l.ln.Close() } // Addr returns the listener's network address. func (l *Listener) Addr() net.Addr { return l.ln.Addr() }