summaryrefslogtreecommitdiff
path: root/listener.go
blob: 52c08fdf5de9745b1836c24fcbd0e7c8a3dea5aa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package obfsvpn

import (
	"bytes"
	"context"
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"log"
	"net"

	pt "git.torproject.org/pluggable-transports/goptlib.git"
	"github.com/xtaci/kcp-go"
	"gitlab.com/yawning/obfs4.git/common/ntor"
	"gitlab.com/yawning/obfs4.git/transports/base"
	"gitlab.com/yawning/obfs4.git/transports/obfs4"
)

const (
	netKCP = "kcp"
)

// 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
	PublicKey  string
	Seed       [ntor.KeySeedLength]byte
	StateDir   string
}

// NewListenConfig
// perhaps this is redundant, but using the same json format than ss for debug.

func NewListenConfig(nodeIDStr, privKeyStr, pubKeyStr, seedStr, stateDir string) (*ListenConfig, error) {
	var err error
	var seed [ntor.KeySeedLength]byte
	var nodeID *ntor.NodeID
	private := new(ntor.PrivateKey)

	if nodeID, err = ntor.NodeIDFromHex(nodeIDStr); err != nil {
		return nil, err
	}

	raw, err := hex.DecodeString(privKeyStr)
	if err != nil {
		return nil, err
	}
	log.Println("DEBUG len private ley:", len(raw))
	// TODO raise invalid error if len not right
	copy(private[:], raw)

	s, err := hex.DecodeString(seedStr)
	if err != nil {
		return nil, err
	}
	copy(seed[:], s)

	lc := &ListenConfig{
		NodeID:     nodeID,
		PrivateKey: private,
		PublicKey:  pubKeyStr,
		Seed:       seed,
		StateDir:   stateDir,
	}
	return lc, nil
}

// 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 and copy data through the obfuscated conn.
// 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[:]))
	args.Add("public-key", lc.PublicKey)
	fmt.Println("pubkey:", lc.PublicKey)
	sf, err := (&obfs4.Transport{}).ServerFactory(lc.StateDir, &args)
	if err != nil {
		return nil, err
	}
	return &Listener{sf: sf, ln: ln}, nil
}

// Listen listens 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) {
	var ln net.Listener
	var err error
	switch network {
	case netKCP:
		log.Println("kcp listen on", address)
		ln, err = kcp.Listen(address)
		if err != nil {
			return nil, err
		}
	default:
		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()
}