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 }