-
Notifications
You must be signed in to change notification settings - Fork 1
/
cmd_proxy.go
160 lines (128 loc) · 3.7 KB
/
cmd_proxy.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
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 main
import (
"context"
"fmt"
"net"
"github.com/rumpelsepp/gcat/lib/helper"
"github.com/rumpelsepp/gcat/lib/proxy"
"github.com/spf13/cobra"
_ "github.com/rumpelsepp/gcat/lib/proxy/exec"
_ "github.com/rumpelsepp/gcat/lib/proxy/quic"
_ "github.com/rumpelsepp/gcat/lib/proxy/stdio"
_ "github.com/rumpelsepp/gcat/lib/proxy/tcp"
_ "github.com/rumpelsepp/gcat/lib/proxy/tun"
_ "github.com/rumpelsepp/gcat/lib/proxy/unix"
_ "github.com/rumpelsepp/gcat/lib/proxy/websocket"
_ "github.com/rumpelsepp/gcat/lib/proxy/webtransport"
)
type mainLoop struct {
proxyLeft *proxy.ProxyDescription
proxyRight *proxy.ProxyDescription
ctx context.Context
}
func CreateLoop(addrLeft, addrRight string) (*mainLoop, error) {
addrLeftParsed, err := proxy.ParseAddr(addrLeft)
if err != nil {
return nil, err
}
addrRightParsed, err := proxy.ParseAddr(addrRight)
if err != nil {
return nil, err
}
proxyLeft, err := proxy.Registry.FindAndCreateProxy(addrLeftParsed)
if err != nil {
return nil, err
}
proxyRight, err := proxy.Registry.FindAndCreateProxy(addrRightParsed)
if err != nil {
return nil, err
}
return &mainLoop{
proxyLeft: proxyLeft,
proxyRight: proxyRight,
ctx: context.Background(),
}, nil
}
func (l *mainLoop) SupportsMultiple() bool {
if !l.proxyLeft.SupportsMultiple || !l.proxyRight.SupportsMultiple {
return false
}
return true
}
func (l *mainLoop) Connect() (net.Conn, net.Conn, error) {
connLeft, err := l.proxyLeft.Connect(l.ctx)
if err != nil {
return nil, nil, err
}
connRight, err := l.proxyRight.Connect(l.ctx)
if err != nil {
return nil, nil, err
}
return connLeft, connRight, nil
}
type proxyOptions struct {
loop bool
parallel bool
}
var (
proxyOpts proxyOptions
proxyCmd = &cobra.Command{
Use: "proxy [flags] URL1 URL2",
Short: "Act as a fancy socat like proxy tool",
Long: `The proxy command needs two arguments which specify the data pipeline.
The arguments are URLs; in some rare cases it might be required to escape
certain parts of the url. For more information to URLs see the "proxies"
command.
`,
Example: ` Listen on localhost tcp port 1234 and proxy to stdio.
$ gcat proxy tcp-listen://localhost:1234 -
Forward TCP traffic from "localhost:8080" to "1.1.1.1:80":
$ gcat proxy tcp-listen://localhost:1234 tcp://1.1.1.1:80
Tunnel IP traffic through SSH (https://rumpelsepp.org/blog/vpn-over-ssh/):
# gcat proxy "tun://192.168.255.1/24" exec:'ssh root@HOST gcat proxy tun://192.168.255.2/24 -'
SSH Tunnel through Websocket (https://rumpelsepp.org/blog/ssh-through-websocket/):
$ ssh -o 'ProxyCommand=gcat proxy wss://example.org/ssh/ -' user@example.org`,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) != 2 {
return fmt.Errorf("provide two urls")
}
loop, err := CreateLoop(args[0], args[1])
if err != nil {
return err
}
if proxyOpts.parallel {
if !loop.SupportsMultiple() {
return fmt.Errorf("multiple connections not supported by chosen pipeline")
}
for {
lConn, rConn, err := loop.Connect()
if err != nil {
return err
}
go helper.BidirectCopy(lConn, rConn)
}
}
if proxyOpts.loop {
for {
lConn, rConn, err := loop.Connect()
if err != nil {
return err
}
helper.BidirectCopy(lConn, rConn)
}
}
lConn, rConn, err := loop.Connect()
if err != nil {
return err
}
helper.BidirectCopy(lConn, rConn)
return nil
},
}
)
func init() {
rootCmd.AddCommand(proxyCmd)
f := proxyCmd.Flags()
f.BoolVarP(&proxyOpts.loop, "loop", "l", false, "keep the listener running")
f.BoolVarP(&proxyOpts.parallel, "parallel", "p", false, "serve multiple connections in parallel")
}