github.com/sagernet/netlink@v0.0.0-20240612041022-b9a21c07ac6a/proc_event_linux.go (about)

     1  package netlink
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"os"
     8  	"syscall"
     9  
    10  	"github.com/sagernet/netlink/nl"
    11  	"github.com/vishvananda/netns"
    12  	"golang.org/x/sys/unix"
    13  )
    14  
    15  const CN_IDX_PROC = 0x1
    16  
    17  const (
    18  	PROC_EVENT_NONE     = 0x00000000
    19  	PROC_EVENT_FORK     = 0x00000001
    20  	PROC_EVENT_EXEC     = 0x00000002
    21  	PROC_EVENT_UID      = 0x00000004
    22  	PROC_EVENT_GID      = 0x00000040
    23  	PROC_EVENT_SID      = 0x00000080
    24  	PROC_EVENT_PTRACE   = 0x00000100
    25  	PROC_EVENT_COMM     = 0x00000200
    26  	PROC_EVENT_COREDUMP = 0x40000000
    27  	PROC_EVENT_EXIT     = 0x80000000
    28  )
    29  
    30  const (
    31  	CN_VAL_PROC          = 0x1
    32  	PROC_CN_MCAST_LISTEN = 0x1
    33  )
    34  
    35  type ProcEventMsg interface {
    36  	Pid() uint32
    37  	Tgid() uint32
    38  }
    39  
    40  type ProcEventHeader struct {
    41  	What      uint32
    42  	CPU       uint32
    43  	Timestamp uint64
    44  }
    45  
    46  type ProcEvent struct {
    47  	ProcEventHeader
    48  	Msg ProcEventMsg
    49  }
    50  
    51  func (pe *ProcEvent) setHeader(h ProcEventHeader) {
    52  	pe.What = h.What
    53  	pe.CPU = h.CPU
    54  	pe.Timestamp = h.Timestamp
    55  }
    56  
    57  type ExitProcEvent struct {
    58  	ProcessPid  uint32
    59  	ProcessTgid uint32
    60  	ExitCode    uint32
    61  	ExitSignal  uint32
    62  	ParentPid   uint32
    63  	ParentTgid  uint32
    64  }
    65  
    66  type ExitProcEvent2 struct {
    67  	ProcessPid  uint32
    68  	ProcessTgid uint32
    69  	ExitCode    uint32
    70  	ExitSignal  uint32
    71  	ParentPid   uint32
    72  	ParentTgid  uint32
    73  }
    74  
    75  func (e *ExitProcEvent) Pid() uint32 {
    76  	return e.ProcessPid
    77  }
    78  
    79  func (e *ExitProcEvent) Tgid() uint32 {
    80  	return e.ProcessTgid
    81  }
    82  
    83  type ExecProcEvent struct {
    84  	ProcessPid  uint32
    85  	ProcessTgid uint32
    86  }
    87  
    88  func (e *ExecProcEvent) Pid() uint32 {
    89  	return e.ProcessPid
    90  }
    91  
    92  func (e *ExecProcEvent) Tgid() uint32 {
    93  	return e.ProcessTgid
    94  }
    95  
    96  type ForkProcEvent struct {
    97  	ParentPid  uint32
    98  	ParentTgid uint32
    99  	ChildPid   uint32
   100  	ChildTgid  uint32
   101  }
   102  
   103  func (e *ForkProcEvent) Pid() uint32 {
   104  	return e.ParentPid
   105  }
   106  
   107  func (e *ForkProcEvent) Tgid() uint32 {
   108  	return e.ParentTgid
   109  }
   110  
   111  type CommProcEvent struct {
   112  	ProcessPid  uint32
   113  	ProcessTgid uint32
   114  	Comm        [16]byte
   115  }
   116  
   117  func (e *CommProcEvent) Pid() uint32 {
   118  	return e.ProcessPid
   119  }
   120  
   121  func (e *CommProcEvent) Tgid() uint32 {
   122  	return e.ProcessTgid
   123  }
   124  
   125  func ProcEventMonitor(ch chan<- ProcEvent, done <-chan struct{}, errorChan chan<- error) error {
   126  	h, err := NewHandle()
   127  	if err != nil {
   128  		return err
   129  	}
   130  	defer h.Delete()
   131  
   132  	s, err := nl.SubscribeAt(netns.None(), netns.None(), unix.NETLINK_CONNECTOR, CN_IDX_PROC)
   133  	if err != nil {
   134  		return err
   135  	}
   136  
   137  	var nlmsg nl.NetlinkRequest
   138  
   139  	nlmsg.Pid = uint32(os.Getpid())
   140  	nlmsg.Type = unix.NLMSG_DONE
   141  	nlmsg.Len = uint32(unix.SizeofNlMsghdr)
   142  
   143  	cm := nl.NewCnMsg(CN_IDX_PROC, CN_VAL_PROC, PROC_CN_MCAST_LISTEN)
   144  	nlmsg.AddData(cm)
   145  
   146  	s.Send(&nlmsg)
   147  
   148  	if done != nil {
   149  		go func() {
   150  			<-done
   151  			s.Close()
   152  		}()
   153  	}
   154  
   155  	go func() {
   156  		defer close(ch)
   157  		for {
   158  			msgs, from, err := s.Receive()
   159  			if err != nil {
   160  				errorChan <- err
   161  				return
   162  			}
   163  			if from.Pid != nl.PidKernel {
   164  				errorChan <- fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel)
   165  				return
   166  			}
   167  
   168  			for _, m := range msgs {
   169  				e := parseNetlinkMessage(m)
   170  				if e != nil {
   171  					ch <- *e
   172  				}
   173  			}
   174  
   175  		}
   176  	}()
   177  
   178  	return nil
   179  }
   180  
   181  func parseNetlinkMessage(m syscall.NetlinkMessage) *ProcEvent {
   182  	if m.Header.Type == unix.NLMSG_DONE {
   183  		buf := bytes.NewBuffer(m.Data)
   184  		msg := &nl.CnMsg{}
   185  		hdr := &ProcEventHeader{}
   186  		binary.Read(buf, nl.NativeEndian(), msg)
   187  		binary.Read(buf, nl.NativeEndian(), hdr)
   188  
   189  		pe := &ProcEvent{}
   190  		pe.setHeader(*hdr)
   191  		switch hdr.What {
   192  		case PROC_EVENT_EXIT:
   193  			event := &ExitProcEvent{}
   194  			binary.Read(buf, nl.NativeEndian(), event)
   195  			pe.Msg = event
   196  			return pe
   197  		case PROC_EVENT_FORK:
   198  			event := &ForkProcEvent{}
   199  			binary.Read(buf, nl.NativeEndian(), event)
   200  			pe.Msg = event
   201  			return pe
   202  		case PROC_EVENT_EXEC:
   203  			event := &ExecProcEvent{}
   204  			binary.Read(buf, nl.NativeEndian(), event)
   205  			pe.Msg = event
   206  			return pe
   207  		case PROC_EVENT_COMM:
   208  			event := &CommProcEvent{}
   209  			binary.Read(buf, nl.NativeEndian(), event)
   210  			pe.Msg = event
   211  			return pe
   212  		}
   213  		return nil
   214  	}
   215  
   216  	return nil
   217  }