github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/monitor/remoteapi/server/server.go (about)

     1  package server
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"net"
     8  	"net/http"
     9  	"regexp"
    10  	"strconv"
    11  
    12  	"go.aporeto.io/enforcerd/trireme-lib/common"
    13  	"go.aporeto.io/enforcerd/trireme-lib/monitor/registerer"
    14  	"go.uber.org/zap"
    15  )
    16  
    17  // EventServer is a new event server
    18  type EventServer struct {
    19  	socketPath string
    20  	server     *http.Server
    21  	registerer registerer.Registerer
    22  }
    23  
    24  // NewEventServer creates a new event server
    25  func NewEventServer(address string, registerer registerer.Registerer) (*EventServer, error) {
    26  
    27  	err := cleanupPipe(address)
    28  	if err != nil {
    29  		return nil, err
    30  	}
    31  
    32  	return &EventServer{
    33  		socketPath: address,
    34  		registerer: registerer,
    35  	}, nil
    36  }
    37  
    38  // ServeHTTP is called for every request.
    39  func (e *EventServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    40  	e.create(w, r)
    41  }
    42  
    43  // Run runs the server. The server will run in the background. It will
    44  // gracefully die with the provided context.
    45  func (e *EventServer) Run(ctx context.Context) error {
    46  
    47  	// Create the handler
    48  	e.server = &http.Server{
    49  		Handler: e,
    50  	}
    51  
    52  	listener, err := e.makePipe()
    53  
    54  	if err != nil {
    55  		return err
    56  	}
    57  
    58  	// Start serving HTTP requests in the background
    59  	go e.server.Serve(listener) // nolint
    60  
    61  	// Listen for context cancellation to close the socket.
    62  	go func() {
    63  		<-ctx.Done()
    64  		listener.Close() // nolint
    65  	}()
    66  
    67  	return nil
    68  }
    69  
    70  // create is the main hadler that process and validates the events
    71  // before calling the actual monitor handlers to process the event.
    72  func (e *EventServer) create(w http.ResponseWriter, r *http.Request) {
    73  	event := &common.EventInfo{}
    74  	defer r.Body.Close() // nolint
    75  
    76  	if err := json.NewDecoder(r.Body).Decode(event); err != nil {
    77  		http.Error(w, "Invalid request", http.StatusBadRequest)
    78  		return
    79  	}
    80  
    81  	if err := validateTypes(event); err != nil {
    82  		zap.L().Error("Error in validating types", zap.Error(err), zap.Reflect("Event", event))
    83  		http.Error(w, fmt.Sprintf("Invalid request fields: %s", err), http.StatusBadRequest)
    84  		return
    85  	}
    86  
    87  	if err := validateUser(r, event); err != nil {
    88  		http.Error(w, fmt.Sprintf("Invalid user to pid mapping found: %s", err), http.StatusForbidden)
    89  		return
    90  	}
    91  
    92  	if err := validateEvent(event); err != nil {
    93  		http.Error(w, fmt.Sprintf("Bad request: %s", err), http.StatusBadRequest)
    94  		return
    95  	}
    96  
    97  	if err := e.processEvent(r.Context(), event); err != nil {
    98  		zap.L().Error("Error in processing event", zap.Error(err), zap.Reflect("Event", event))
    99  		http.Error(w, fmt.Sprintf("Cannot handle request: %s", err), http.StatusInternalServerError)
   100  		return
   101  	}
   102  
   103  	w.WriteHeader(http.StatusAccepted)
   104  }
   105  
   106  // processEvent processes the event by retrieving the right monitor handler.
   107  func (e *EventServer) processEvent(ctx context.Context, eventInfo *common.EventInfo) (err error) {
   108  
   109  	if e.registerer == nil {
   110  		return fmt.Errorf("No registered handlers")
   111  	}
   112  
   113  	f, err := e.registerer.GetHandler(eventInfo.PUType, eventInfo.EventType)
   114  	if err != nil {
   115  		return fmt.Errorf("Handler not found: %s", err)
   116  	}
   117  
   118  	return f(ctx, eventInfo)
   119  }
   120  
   121  // validateTypes validates the various types and prevents any bad strings.
   122  func validateTypes(event *common.EventInfo) error {
   123  
   124  	regexStrings := regexp.MustCompile("^[a-zA-Z0-9_:.$%/-]{0,256}$")
   125  	regexNS := regexp.MustCompile("^[a-zA-Z0-9/-]{0,128}$")
   126  	regexCgroup := regexp.MustCompile("^/trireme/(uid/){0,1}[a-zA-Z0-9_:.$%]{1,64}$")
   127  
   128  	if _, ok := common.EventMap[event.EventType]; !ok {
   129  		return fmt.Errorf("invalid event: %s", string(event.EventType))
   130  	}
   131  
   132  	if event.PUType > common.TransientPU {
   133  		return fmt.Errorf("invalid pu type %v", event.PUType)
   134  	}
   135  
   136  	if len(event.Cgroup) > 0 && !regexCgroup.Match([]byte(event.Cgroup)) {
   137  		return fmt.Errorf("Invalid cgroup format: %s", event.Cgroup)
   138  	}
   139  
   140  	if !regexNS.Match([]byte(event.NS)) {
   141  		return fmt.Errorf("Namespace is not of the right format")
   142  	}
   143  
   144  	for k, v := range event.IPs {
   145  		if !regexStrings.Match([]byte(k)) {
   146  			return fmt.Errorf("Invalid IP name: %s", k)
   147  		}
   148  
   149  		if ip := net.ParseIP(v); ip == nil {
   150  			return fmt.Errorf("Invalid IP address: %s", v)
   151  		}
   152  	}
   153  
   154  	return nil
   155  }
   156  
   157  // validateEvent validates that this is reasonable event and
   158  // modifies the default values.
   159  func validateEvent(event *common.EventInfo) error {
   160  
   161  	if event.EventType == common.EventCreate || event.EventType == common.EventStart {
   162  		if event.HostService {
   163  			if event.NetworkOnlyTraffic {
   164  				if event.Name == "" {
   165  					return fmt.Errorf("Service name must be provided and must not be default")
   166  				}
   167  			}
   168  		} else {
   169  			if event.PUID == "" {
   170  				event.PUID = strconv.Itoa(int(event.PID))
   171  			}
   172  		}
   173  	}
   174  
   175  	if event.EventType == common.EventStop || event.EventType == common.EventDestroy {
   176  		regStop := regexp.MustCompile("^/trireme/[a-zA-Z0-9_]{1,11}$")
   177  		if event.Cgroup != "" && !regStop.Match([]byte(event.Cgroup)) {
   178  			return fmt.Errorf("Cgroup is not of the right format")
   179  		}
   180  	}
   181  
   182  	return nil
   183  }