mirror of
https://github.com/fosrl/newt.git
synced 2026-09-22 13:59:06 +02:00
Bind the ssh server to the newt ip
This commit is contained in:
@@ -19,6 +19,7 @@ import (
|
||||
newtDevice "github.com/fosrl/newt/device"
|
||||
"github.com/fosrl/newt/holepunch"
|
||||
"github.com/fosrl/newt/logger"
|
||||
"github.com/fosrl/newt/nativessh"
|
||||
"github.com/fosrl/newt/netstack2"
|
||||
"github.com/fosrl/newt/network"
|
||||
"github.com/fosrl/newt/util"
|
||||
@@ -108,6 +109,8 @@ type WireGuardService struct {
|
||||
sharedBind *bind.SharedBind
|
||||
holePunchManager *holepunch.Manager
|
||||
useNativeInterface bool
|
||||
// SSH server running on the clients' netstack
|
||||
sshServer *sshServerHandle
|
||||
// Direct UDP relay from main tunnel to clients' WireGuard
|
||||
directRelayStop chan struct{}
|
||||
directRelayWg sync.WaitGroup
|
||||
@@ -211,6 +214,12 @@ func (s *WireGuardService) Close() {
|
||||
s.stopGetConfig = nil
|
||||
}
|
||||
|
||||
// Stop SSH server before tearing down the netstack
|
||||
if s.sshServer != nil {
|
||||
s.sshServer.stop()
|
||||
s.sshServer = nil
|
||||
}
|
||||
|
||||
// Flush access logs before tearing down the tunnel
|
||||
if s.tnet != nil {
|
||||
if ph := s.tnet.GetProxyHandler(); ph != nil {
|
||||
@@ -890,6 +899,13 @@ func (s *WireGuardService) ensureWireguardInterface(wgconfig WgConfig) error {
|
||||
logger.Error("Failed to start WireGuard tester server: %v", err)
|
||||
}
|
||||
|
||||
// Start the SSH server on the clients' netstack (port 22).
|
||||
if h, sshErr := startSSHOnNetstack(s.tnet); sshErr != nil {
|
||||
logger.Warn("nativessh: not starting SSH server on clients netstack: %v", sshErr)
|
||||
} else {
|
||||
s.sshServer = h
|
||||
}
|
||||
|
||||
// Note: we already unlocked above, so don't use defer unlock
|
||||
return nil
|
||||
}
|
||||
@@ -1563,3 +1579,31 @@ func (s *WireGuardService) filterReadOnlyFields(config string) string {
|
||||
|
||||
return strings.Join(filteredLines, "\n")
|
||||
}
|
||||
|
||||
// sshServerHandle holds the listener so the SSH server can be stopped by
|
||||
// closing it.
|
||||
type sshServerHandle struct {
|
||||
ln net.Listener
|
||||
}
|
||||
|
||||
func (h *sshServerHandle) stop() {
|
||||
_ = h.ln.Close()
|
||||
}
|
||||
|
||||
// startSSHOnNetstack creates a TCP listener on port 22 of the clients' netstack
|
||||
// and starts serving SSH connections on it in the background. The returned
|
||||
// handle can be used to stop the server by closing the listener.
|
||||
func startSSHOnNetstack(tnet *netstack2.Net) (*sshServerHandle, error) {
|
||||
srv := nativessh.NewServer(nativessh.ServerConfig{})
|
||||
ln, err := tnet.ListenTCP(&net.TCPAddr{Port: 22})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("listen on netstack port 22: %w", err)
|
||||
}
|
||||
h := &sshServerHandle{ln: ln}
|
||||
go func() {
|
||||
if err := srv.Serve(ln); err != nil {
|
||||
logger.Debug("nativessh: clients netstack server stopped: %v", err)
|
||||
}
|
||||
}()
|
||||
return h, nil
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import (
|
||||
"github.com/fosrl/newt/docker"
|
||||
"github.com/fosrl/newt/healthcheck"
|
||||
"github.com/fosrl/newt/logger"
|
||||
"github.com/fosrl/newt/nativessh"
|
||||
"github.com/fosrl/newt/proxy"
|
||||
"github.com/fosrl/newt/updates"
|
||||
"github.com/fosrl/newt/util"
|
||||
@@ -536,13 +535,6 @@ func runNewtMain(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// Start native SSH server for testing (listens on :2222).
|
||||
go func() {
|
||||
srv := nativessh.NewServer(nativessh.ServerConfig{})
|
||||
if err := srv.ListenAndServe(); err != nil {
|
||||
logger.Error("Native SSH server error: %v", err)
|
||||
}
|
||||
}()
|
||||
logger.GetLogger().SetLevel(loggerLevel)
|
||||
|
||||
// Initialize telemetry after flags are parsed (so flags override env)
|
||||
|
||||
+30
-16
@@ -58,42 +58,56 @@ func NewServer(cfg ServerConfig) *Server {
|
||||
return &Server{cfg: cfg}
|
||||
}
|
||||
|
||||
// ListenAndServe starts the SSH server and blocks until the listener is closed.
|
||||
func (s *Server) ListenAndServe() error {
|
||||
// buildSSHConfig loads keys/principals and builds the ssh.ServerConfig.
|
||||
func (s *Server) buildSSHConfig() (*ssh.ServerConfig, error) {
|
||||
caKey, err := loadCAPublicKey(s.cfg.CAKeyPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("load CA public key from %s: %w", s.cfg.CAKeyPath, err)
|
||||
return nil, fmt.Errorf("load CA public key from %s: %w", s.cfg.CAKeyPath, err)
|
||||
}
|
||||
|
||||
principals, err := loadPrincipals(s.cfg.PrincipalsPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("load principals from %s: %w", s.cfg.PrincipalsPath, err)
|
||||
return nil, fmt.Errorf("load principals from %s: %w", s.cfg.PrincipalsPath, err)
|
||||
}
|
||||
|
||||
hostSigner, err := generateHostKey()
|
||||
if err != nil {
|
||||
return fmt.Errorf("host key: %w", err)
|
||||
return nil, fmt.Errorf("host key: %w", err)
|
||||
}
|
||||
|
||||
sshCfg := &ssh.ServerConfig{
|
||||
cfg := &ssh.ServerConfig{
|
||||
PublicKeyCallback: makeCertAuthCallback(caKey, principals),
|
||||
}
|
||||
sshCfg.AddHostKey(hostSigner)
|
||||
cfg.AddHostKey(hostSigner)
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// Serve accepts connections on ln and handles them. It returns when ln is
|
||||
// closed or a non-temporary Accept error occurs.
|
||||
func (s *Server) Serve(ln net.Listener) error {
|
||||
sshCfg, err := s.buildSSHConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("nativessh: server listening on %s", ln.Addr())
|
||||
for {
|
||||
conn, err := ln.Accept()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go s.handleConn(conn, sshCfg)
|
||||
}
|
||||
}
|
||||
|
||||
// ListenAndServe starts the SSH server on the host network and blocks until
|
||||
// the listener is closed.
|
||||
func (s *Server) ListenAndServe() error {
|
||||
ln, err := net.Listen("tcp", s.cfg.ListenAddr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("listen %s: %w", s.cfg.ListenAddr, err)
|
||||
}
|
||||
defer ln.Close()
|
||||
log.Printf("nativessh: server listening on %s", s.cfg.ListenAddr)
|
||||
|
||||
for {
|
||||
conn, err := ln.Accept()
|
||||
if err != nil {
|
||||
return fmt.Errorf("accept: %w", err)
|
||||
}
|
||||
go s.handleConn(conn, sshCfg)
|
||||
}
|
||||
return s.Serve(ln)
|
||||
}
|
||||
|
||||
func (s *Server) handleConn(conn net.Conn, cfg *ssh.ServerConfig) {
|
||||
|
||||
Reference in New Issue
Block a user