github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/control/server/server.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  /*
    16  Package server provides a basic control server interface.
    17  
    18  Note that no objects are registered by default. Users must provide their own
    19  implementations of the control interface.
    20  */
    21  package server
    22  
    23  import (
    24  	"os"
    25  	"time"
    26  
    27  	"github.com/nicocha30/gvisor-ligolo/pkg/log"
    28  	"github.com/nicocha30/gvisor-ligolo/pkg/sync"
    29  	"github.com/nicocha30/gvisor-ligolo/pkg/unet"
    30  	"github.com/nicocha30/gvisor-ligolo/pkg/urpc"
    31  )
    32  
    33  // curUID is the unix user ID of the user that the control server is running as.
    34  var curUID = os.Getuid()
    35  
    36  // Server is a basic control server.
    37  type Server struct {
    38  	// socket is our bound socket.
    39  	socket *unet.ServerSocket
    40  
    41  	// server is our rpc server.
    42  	server *urpc.Server
    43  
    44  	// wg waits for the accept loop to terminate.
    45  	wg sync.WaitGroup
    46  }
    47  
    48  // New returns a new bound control server.
    49  func New(socket *unet.ServerSocket) *Server {
    50  	return &Server{
    51  		socket: socket,
    52  		server: urpc.NewServer(),
    53  	}
    54  }
    55  
    56  // FD returns the file descriptor that the server is running on.
    57  func (s *Server) FD() int {
    58  	return s.socket.FD()
    59  }
    60  
    61  // Wait waits for the main server goroutine to exit. This should be
    62  // called after a call to Serve.
    63  func (s *Server) Wait() {
    64  	s.wg.Wait()
    65  }
    66  
    67  // Stop stops the server. Note that this function should only be called once
    68  // and the server should not be used afterwards.
    69  func (s *Server) Stop(timeout time.Duration) {
    70  	s.socket.Close()
    71  	s.Wait()
    72  
    73  	// This will cause existing clients to be terminated safely. If the
    74  	// registered handlers have a Stop callback, it will be called.
    75  	s.server.Stop(timeout)
    76  }
    77  
    78  // StartServing starts listening for connect and spawns the main service
    79  // goroutine for handling incoming control requests. StartServing does not
    80  // block; to wait for the control server to exit, call Wait.
    81  func (s *Server) StartServing() error {
    82  	// Actually start listening.
    83  	if err := s.socket.Listen(); err != nil {
    84  		return err
    85  	}
    86  
    87  	s.wg.Add(1)
    88  	go func() { // S/R-SAFE: does not impact state directly.
    89  		s.serve()
    90  		s.wg.Done()
    91  	}()
    92  
    93  	return nil
    94  }
    95  
    96  // serve is the body of the main service goroutine. It handles incoming control
    97  // connections and dispatches requests to registered objects.
    98  func (s *Server) serve() {
    99  	for {
   100  		// Accept clients.
   101  		conn, err := s.socket.Accept()
   102  		if err != nil {
   103  			return
   104  		}
   105  
   106  		ucred, err := conn.GetPeerCred()
   107  		if err != nil {
   108  			log.Warningf("Control couldn't get credentials: %s", err.Error())
   109  			conn.Close()
   110  			continue
   111  		}
   112  
   113  		// Only allow this user and root.
   114  		if int(ucred.Uid) != curUID && ucred.Uid != 0 {
   115  			// Authentication failed.
   116  			log.Warningf("Control auth failure: other UID = %d, current UID = %d", ucred.Uid, curUID)
   117  			conn.Close()
   118  			continue
   119  		}
   120  
   121  		// Handle the connection non-blockingly.
   122  		s.server.StartHandling(conn)
   123  	}
   124  }
   125  
   126  // Register registers a specific control interface with the server.
   127  func (s *Server) Register(obj any) {
   128  	s.server.Register(obj)
   129  }
   130  
   131  // CreateFromFD creates a new control bound to the given 'fd'. It has no
   132  // registered interfaces and will not start serving until StartServing is
   133  // called.
   134  func CreateFromFD(fd int) (*Server, error) {
   135  	socket, err := unet.NewServerSocket(fd)
   136  	if err != nil {
   137  		return nil, err
   138  	}
   139  	return New(socket), nil
   140  }
   141  
   142  // Create creates a new control server with an abstract unix socket
   143  // with the given address, which must must be unique and a valid
   144  // abstract socket name.
   145  func Create(addr string) (*Server, error) {
   146  	socket, err := unet.Bind(addr, false)
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  	return New(socket), nil
   151  }
   152  
   153  // CreateSocket creates a socket that can be used with control server,
   154  // but doesn't start control server.  'addr' must be a valid and unique
   155  // abstract socket name.  Returns socket's FD, -1 in case of error.
   156  func CreateSocket(addr string) (int, error) {
   157  	socket, err := unet.Bind(addr, false)
   158  	if err != nil {
   159  		return -1, err
   160  	}
   161  	return socket.Release()
   162  }