-
Notifications
You must be signed in to change notification settings - Fork 0
/
algeneva_impl.go
91 lines (75 loc) · 2.25 KB
/
algeneva_impl.go
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
package chained
import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"fmt"
"net"
"github.com/getlantern/common/config"
"github.com/getlantern/errors"
algeneva "github.com/getlantern/lantern-algeneva"
"github.com/getlantern/netx"
"github.com/getlantern/flashlight/v7/ops"
)
type algenevaImpl struct {
nopCloser
dialerOps algeneva.DialerOpts
addr string
reportDialCore reportDialCoreFn
}
func newAlgenevaImpl(addr string, pc *config.ProxyConfig, reportDialCore reportDialCoreFn) (*algenevaImpl, error) {
opts := algeneva.DialerOpts{
AlgenevaStrategy: ptSetting(pc, "algeneva_strategy"),
}
if cert := pc.Cert; cert != "" {
block, rest := pem.Decode([]byte(pc.Cert))
if block == nil {
return nil, errors.New("failed to decode proxy certificate as PEM block")
}
if len(rest) > 0 {
return nil, errors.New("unexpected extra data in proxy certificate PEM")
}
if block.Type != "CERTIFICATE" {
return nil, errors.New("expected certificate in PEM block")
}
certPool := x509.NewCertPool()
certPool.AppendCertsFromPEM([]byte(cert))
ip, _, _ := net.SplitHostPort(addr)
opts.TLSConfig = &tls.Config{
RootCAs: certPool,
ServerName: ip,
}
}
return &algenevaImpl{
dialerOps: opts,
addr: addr,
reportDialCore: reportDialCore,
}, nil
}
func (a *algenevaImpl) dialServer(op *ops.Op, ctx context.Context) (net.Conn, error) {
dialerOps := a.dialerOps
dialerOps.Dialer = &algenevaDialer{
a.reportDialCore,
op,
}
conn, err := algeneva.DialContext(ctx, "tcp", a.addr, dialerOps)
if err != nil {
return nil, fmt.Errorf("algeneva: %v", err)
}
return conn, nil
}
// algenevaDialer is a algeneva.Dialer wrapper around a reportDialCore. algeneva accepts an optional
// Dialer interface which it will use to dial the server and then wrap the resulting connection.
type algenevaDialer struct {
reportDialCore reportDialCoreFn
op *ops.Op
}
func (d *algenevaDialer) Dial(network, addr string) (net.Conn, error) {
return d.DialContext(context.Background(), network, addr)
}
func (d *algenevaDialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
return d.reportDialCore(d.op, func() (net.Conn, error) {
return netx.DialContext(ctx, network, addr)
})
}