| 
									
										
										
										
											2017-05-03 10:09:34 +03:00
										 |  |  | package ssh | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"io" | 
					
						
							|  |  |  | 	"net" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // streamLocalChannelOpenDirectMsg is a struct used for SSH_MSG_CHANNEL_OPEN message | 
					
						
							|  |  |  | // with "direct-streamlocal@openssh.com" string. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // See openssh-portable/PROTOCOL, section 2.4. connection: Unix domain socket forwarding | 
					
						
							|  |  |  | // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL#L235 | 
					
						
							|  |  |  | type streamLocalChannelOpenDirectMsg struct { | 
					
						
							|  |  |  | 	socketPath string | 
					
						
							|  |  |  | 	reserved0  string | 
					
						
							|  |  |  | 	reserved1  uint32 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // forwardedStreamLocalPayload is a struct used for SSH_MSG_CHANNEL_OPEN message | 
					
						
							|  |  |  | // with "forwarded-streamlocal@openssh.com" string. | 
					
						
							|  |  |  | type forwardedStreamLocalPayload struct { | 
					
						
							|  |  |  | 	SocketPath string | 
					
						
							|  |  |  | 	Reserved0  string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // streamLocalChannelForwardMsg is a struct used for SSH2_MSG_GLOBAL_REQUEST message | 
					
						
							|  |  |  | // with "streamlocal-forward@openssh.com"/"cancel-streamlocal-forward@openssh.com" string. | 
					
						
							|  |  |  | type streamLocalChannelForwardMsg struct { | 
					
						
							|  |  |  | 	socketPath string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ListenUnix is similar to ListenTCP but uses a Unix domain socket. | 
					
						
							|  |  |  | func (c *Client) ListenUnix(socketPath string) (net.Listener, error) { | 
					
						
							| 
									
										
										
										
											2019-01-04 09:22:59 +02:00
										 |  |  | 	c.handleForwardsOnce.Do(c.handleForwards) | 
					
						
							| 
									
										
										
										
											2017-05-03 10:09:34 +03:00
										 |  |  | 	m := streamLocalChannelForwardMsg{ | 
					
						
							|  |  |  | 		socketPath, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// send message | 
					
						
							|  |  |  | 	ok, _, err := c.SendRequest("streamlocal-forward@openssh.com", true, Marshal(&m)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		return nil, errors.New("ssh: streamlocal-forward@openssh.com request denied by peer") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ch := c.forwards.add(&net.UnixAddr{Name: socketPath, Net: "unix"}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return &unixListener{socketPath, c, ch}, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (c *Client) dialStreamLocal(socketPath string) (Channel, error) { | 
					
						
							|  |  |  | 	msg := streamLocalChannelOpenDirectMsg{ | 
					
						
							|  |  |  | 		socketPath: socketPath, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ch, in, err := c.OpenChannel("direct-streamlocal@openssh.com", Marshal(&msg)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	go DiscardRequests(in) | 
					
						
							|  |  |  | 	return ch, err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type unixListener struct { | 
					
						
							|  |  |  | 	socketPath string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	conn *Client | 
					
						
							|  |  |  | 	in   <-chan forward | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Accept waits for and returns the next connection to the listener. | 
					
						
							|  |  |  | func (l *unixListener) Accept() (net.Conn, error) { | 
					
						
							|  |  |  | 	s, ok := <-l.in | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		return nil, io.EOF | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ch, incoming, err := s.newCh.Accept() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	go DiscardRequests(incoming) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return &chanConn{ | 
					
						
							|  |  |  | 		Channel: ch, | 
					
						
							|  |  |  | 		laddr: &net.UnixAddr{ | 
					
						
							|  |  |  | 			Name: l.socketPath, | 
					
						
							|  |  |  | 			Net:  "unix", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		raddr: &net.UnixAddr{ | 
					
						
							|  |  |  | 			Name: "@", | 
					
						
							|  |  |  | 			Net:  "unix", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Close closes the listener. | 
					
						
							|  |  |  | func (l *unixListener) Close() error { | 
					
						
							|  |  |  | 	// this also closes the listener. | 
					
						
							|  |  |  | 	l.conn.forwards.remove(&net.UnixAddr{Name: l.socketPath, Net: "unix"}) | 
					
						
							|  |  |  | 	m := streamLocalChannelForwardMsg{ | 
					
						
							|  |  |  | 		l.socketPath, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ok, _, err := l.conn.SendRequest("cancel-streamlocal-forward@openssh.com", true, Marshal(&m)) | 
					
						
							|  |  |  | 	if err == nil && !ok { | 
					
						
							|  |  |  | 		err = errors.New("ssh: cancel-streamlocal-forward@openssh.com failed") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Addr returns the listener's network address. | 
					
						
							|  |  |  | func (l *unixListener) Addr() net.Addr { | 
					
						
							|  |  |  | 	return &net.UnixAddr{ | 
					
						
							|  |  |  | 		Name: l.socketPath, | 
					
						
							|  |  |  | 		Net:  "unix", | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |