Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit79ec3a5

Browse files
drakkangopherbot
authored andcommitted
ssh: allow to bind to a hostname in remote forwarding
To avoid breaking backwards compatibility, we fix Listen, whichreceives the address as a string, while ListenTCP can still onlybe used with IP addresses.Fixesgolang/go#33227Fixesgolang/go#37239Change-Id: I4d45b40fdcb0d6012ed8da59a02149fa37e7db50Reviewed-on:https://go-review.googlesource.com/c/crypto/+/599995LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>Reviewed-by: Junyang Shao <shaojunyang@google.com>Reviewed-by: Bishakh Ghosh <ghoshbishakh@gmail.com>Reviewed-by: Filippo Valsorda <filippo@golang.org>Auto-Submit: Nicola Murino <nicola.murino@gmail.com>Reviewed-by: Michael Pratt <mpratt@google.com>
1 parent122a78f commit79ec3a5

File tree

3 files changed

+86
-46
lines changed

3 files changed

+86
-46
lines changed

‎ssh/streamlocal.go‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func (c *Client) ListenUnix(socketPath string) (net.Listener, error) {
4444
if!ok {
4545
returnnil,errors.New("ssh: streamlocal-forward@openssh.com request denied by peer")
4646
}
47-
ch:=c.forwards.add(&net.UnixAddr{Name:socketPath,Net:"unix"})
47+
ch:=c.forwards.add("unix",socketPath)
4848

4949
return&unixListener{socketPath,c,ch},nil
5050
}
@@ -96,7 +96,7 @@ func (l *unixListener) Accept() (net.Conn, error) {
9696
// Close closes the listener.
9797
func (l*unixListener)Close()error {
9898
// this also closes the listener.
99-
l.conn.forwards.remove(&net.UnixAddr{Name:l.socketPath,Net:"unix"})
99+
l.conn.forwards.remove("unix",l.socketPath)
100100
m:=streamLocalChannelForwardMsg{
101101
l.socketPath,
102102
}

‎ssh/tcpip.go‎

Lines changed: 80 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"io"
1212
"math/rand"
1313
"net"
14+
"net/netip"
1415
"strconv"
1516
"strings"
1617
"sync"
@@ -22,14 +23,21 @@ import (
2223
// the returned net.Listener. The listener must be serviced, or the
2324
// SSH connection may hang.
2425
// N must be "tcp", "tcp4", "tcp6", or "unix".
26+
//
27+
// If the address is a hostname, it is sent to the remote peer as-is, without
28+
// being resolved locally, and the Listener Addr method will return a zero IP.
2529
func (c*Client)Listen(n,addrstring) (net.Listener,error) {
2630
switchn {
2731
case"tcp","tcp4","tcp6":
28-
laddr,err:=net.ResolveTCPAddr(n,addr)
32+
host,portStr,err:=net.SplitHostPort(addr)
33+
iferr!=nil {
34+
returnnil,err
35+
}
36+
port,err:=strconv.ParseInt(portStr,10,32)
2937
iferr!=nil {
3038
returnnil,err
3139
}
32-
returnc.ListenTCP(laddr)
40+
returnc.listenTCPInternal(host,int(port))
3341
case"unix":
3442
returnc.ListenUnix(addr)
3543
default:
@@ -102,15 +110,24 @@ func (c *Client) handleForwards() {
102110
// ListenTCP requests the remote peer open a listening socket
103111
// on laddr. Incoming connections will be available by calling
104112
// Accept on the returned net.Listener.
113+
//
114+
// ListenTCP accepts an IP address, to provide a hostname use [Client.Listen]
115+
// with "tcp", "tcp4", or "tcp6" network instead.
105116
func (c*Client)ListenTCP(laddr*net.TCPAddr) (net.Listener,error) {
106117
c.handleForwardsOnce.Do(c.handleForwards)
107118
ifladdr.Port==0&&isBrokenOpenSSHVersion(string(c.ServerVersion())) {
108119
returnc.autoPortListenWorkaround(laddr)
109120
}
110121

122+
returnc.listenTCPInternal(laddr.IP.String(),laddr.Port)
123+
}
124+
125+
func (c*Client)listenTCPInternal(hoststring,portint) (net.Listener,error) {
126+
c.handleForwardsOnce.Do(c.handleForwards)
127+
111128
m:=channelForwardMsg{
112-
laddr.IP.String(),
113-
uint32(laddr.Port),
129+
host,
130+
uint32(port),
114131
}
115132
// send message
116133
ok,resp,err:=c.SendRequest("tcpip-forward",true,Marshal(&m))
@@ -123,20 +140,33 @@ func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) {
123140

124141
// If the original port was 0, then the remote side will
125142
// supply a real port number in the response.
126-
ifladdr.Port==0 {
143+
ifport==0 {
127144
varpstruct {
128145
Portuint32
129146
}
130147
iferr:=Unmarshal(resp,&p);err!=nil {
131148
returnnil,err
132149
}
133-
laddr.Port=int(p.Port)
150+
port=int(p.Port)
134151
}
152+
// Construct a local address placeholder for the remote listener. If the
153+
// original host is an IP address, preserve it so that Listener.Addr()
154+
// reports the same IP. If the host is a hostname or cannot be parsed as an
155+
// IP, fall back to IPv4zero. The port field is always set, even if the
156+
// original port was 0, because in that case the remote server will assign
157+
// one, allowing callers to determine which port was selected.
158+
ip:=net.IPv4zero
159+
ifparsed,err:=netip.ParseAddr(host);err==nil {
160+
ip=net.IP(parsed.AsSlice())
161+
}
162+
laddr:=&net.TCPAddr{
163+
IP:ip,
164+
Port:port,
165+
}
166+
addr:=net.JoinHostPort(host,strconv.FormatInt(int64(port),10))
167+
ch:=c.forwards.add("tcp",addr)
135168

136-
// Register this forward, using the port number we obtained.
137-
ch:=c.forwards.add(laddr)
138-
139-
return&tcpListener{laddr,c,ch},nil
169+
return&tcpListener{laddr,addr,c,ch},nil
140170
}
141171

142172
// forwardList stores a mapping between remote
@@ -149,8 +179,9 @@ type forwardList struct {
149179
// forwardEntry represents an established mapping of a laddr on a
150180
// remote ssh server to a channel connected to a tcpListener.
151181
typeforwardEntrystruct {
152-
laddr net.Addr
153-
cchanforward
182+
addrstring// host:port or socket path
183+
networkstring// tcp or unix
184+
cchanforward
154185
}
155186

156187
// forward represents an incoming forwarded tcpip connection. The
@@ -161,12 +192,13 @@ type forward struct {
161192
raddr net.Addr// the raddr of the incoming connection
162193
}
163194

164-
func (l*forwardList)add(addrnet.Addr)chanforward {
195+
func (l*forwardList)add(n,addrstring)chanforward {
165196
l.Lock()
166197
deferl.Unlock()
167198
f:=forwardEntry{
168-
laddr:addr,
169-
c:make(chanforward,1),
199+
addr:addr,
200+
network:n,
201+
c:make(chanforward,1),
170202
}
171203
l.entries=append(l.entries,f)
172204
returnf.c
@@ -185,19 +217,20 @@ func parseTCPAddr(addr string, port uint32) (*net.TCPAddr, error) {
185217
ifport==0||port>65535 {
186218
returnnil,fmt.Errorf("ssh: port number out of range: %d",port)
187219
}
188-
ip:=net.ParseIP(string(addr))
189-
ifip==nil {
220+
ip,err:=netip.ParseAddr(addr)
221+
iferr!=nil {
190222
returnnil,fmt.Errorf("ssh: cannot parse IP address %q",addr)
191223
}
192-
return&net.TCPAddr{IP:ip,Port:int(port)},nil
224+
return&net.TCPAddr{IP:net.IP(ip.AsSlice()),Port:int(port)},nil
193225
}
194226

195227
func (l*forwardList)handleChannels(in<-chanNewChannel) {
196228
forch:=rangein {
197229
var (
198-
laddr net.Addr
199-
raddr net.Addr
200-
errerror
230+
addrstring
231+
networkstring
232+
raddr net.Addr
233+
errerror
201234
)
202235
switchchannelType:=ch.ChannelType();channelType {
203236
case"forwarded-tcpip":
@@ -207,40 +240,34 @@ func (l *forwardList) handleChannels(in <-chan NewChannel) {
207240
continue
208241
}
209242

210-
// RFC 4254 section 7.2 specifies that incoming
211-
// addresses should list the address, in string
212-
// format. It is implied that this should be an IP
213-
// address, as it would be impossible to connect to it
214-
// otherwise.
215-
laddr,err=parseTCPAddr(payload.Addr,payload.Port)
216-
iferr!=nil {
217-
ch.Reject(ConnectionFailed,err.Error())
218-
continue
219-
}
243+
// RFC 4254 section 7.2 specifies that incoming addresses should
244+
// list the address that was connected, in string format. It is the
245+
// same address used in the tcpip-forward request. The originator
246+
// address is an IP address instead.
247+
addr=net.JoinHostPort(payload.Addr,strconv.FormatUint(uint64(payload.Port),10))
248+
220249
raddr,err=parseTCPAddr(payload.OriginAddr,payload.OriginPort)
221250
iferr!=nil {
222251
ch.Reject(ConnectionFailed,err.Error())
223252
continue
224253
}
225-
254+
network="tcp"
226255
case"forwarded-streamlocal@openssh.com":
227256
varpayloadforwardedStreamLocalPayload
228257
iferr=Unmarshal(ch.ExtraData(),&payload);err!=nil {
229258
ch.Reject(ConnectionFailed,"could not parse forwarded-streamlocal@openssh.com payload: "+err.Error())
230259
continue
231260
}
232-
laddr=&net.UnixAddr{
233-
Name:payload.SocketPath,
234-
Net:"unix",
235-
}
261+
addr=payload.SocketPath
236262
raddr=&net.UnixAddr{
237263
Name:"@",
238264
Net:"unix",
239265
}
266+
network="unix"
240267
default:
241268
panic(fmt.Errorf("ssh: unknown channel type %s",channelType))
242269
}
243-
ifok:=l.forward(laddr,raddr,ch);!ok {
270+
ifok:=l.forward(network,addr,raddr,ch);!ok {
244271
// Section 7.2, implementations MUST reject spurious incoming
245272
// connections.
246273
ch.Reject(Prohibited,"no forward for address")
@@ -252,11 +279,11 @@ func (l *forwardList) handleChannels(in <-chan NewChannel) {
252279

253280
// remove removes the forward entry, and the channel feeding its
254281
// listener.
255-
func (l*forwardList)remove(addrnet.Addr) {
282+
func (l*forwardList)remove(n,addrstring) {
256283
l.Lock()
257284
deferl.Unlock()
258285
fori,f:=rangel.entries {
259-
ifaddr.Network()==f.laddr.Network()&&addr.String()==f.laddr.String() {
286+
ifn==f.network&&addr==f.addr {
260287
l.entries=append(l.entries[:i],l.entries[i+1:]...)
261288
close(f.c)
262289
return
@@ -274,11 +301,11 @@ func (l *forwardList) closeAll() {
274301
l.entries=nil
275302
}
276303

277-
func (l*forwardList)forward(laddr,raddr net.Addr,chNewChannel)bool {
304+
func (l*forwardList)forward(n,addrstring,raddr net.Addr,chNewChannel)bool {
278305
l.Lock()
279306
deferl.Unlock()
280307
for_,f:=rangel.entries {
281-
ifladdr.Network()==f.laddr.Network()&&laddr.String()==f.laddr.String() {
308+
ifn==f.network&&addr==f.addr {
282309
f.c<-forward{newCh:ch,raddr:raddr}
283310
returntrue
284311
}
@@ -288,6 +315,7 @@ func (l *forwardList) forward(laddr, raddr net.Addr, ch NewChannel) bool {
288315

289316
typetcpListenerstruct {
290317
laddr*net.TCPAddr
318+
addrstring
291319

292320
conn*Client
293321
in<-chanforward
@@ -314,13 +342,21 @@ func (l *tcpListener) Accept() (net.Conn, error) {
314342

315343
// Close closes the listener.
316344
func (l*tcpListener)Close()error {
345+
host,port,err:=net.SplitHostPort(l.addr)
346+
iferr!=nil {
347+
returnerr
348+
}
349+
rport,err:=strconv.ParseUint(port,10,32)
350+
iferr!=nil {
351+
returnerr
352+
}
317353
m:=channelForwardMsg{
318-
l.laddr.IP.String(),
319-
uint32(l.laddr.Port),
354+
host,
355+
uint32(rport),
320356
}
321357

322358
// this also closes the listener.
323-
l.conn.forwards.remove(l.laddr)
359+
l.conn.forwards.remove("tcp",l.addr)
324360
ok,_,err:=l.conn.SendRequest("cancel-tcpip-forward",true,Marshal(&m))
325361
iferr==nil&&!ok {
326362
err=errors.New("ssh: cancel-tcpip-forward failed")

‎ssh/test/forward_unix_test.go‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ func testPortForward(t *testing.T, n, listenAddr string) {
5151
}
5252
}()
5353

54+
// The forwarded address match the listen address because we run the tests
55+
// on the same host.
5456
forwardedAddr:=sshListener.Addr().String()
5557
netConn,err:=net.Dial(n,forwardedAddr)
5658
iferr!=nil {
@@ -111,6 +113,8 @@ func testPortForward(t *testing.T, n, listenAddr string) {
111113
}
112114

113115
funcTestPortForwardTCP(t*testing.T) {
116+
testPortForward(t,"tcp",":0")
117+
testPortForward(t,"tcp","[::]:0")
114118
testPortForward(t,"tcp","localhost:0")
115119
}
116120

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp