Improve: simplify macOS process searching

This commit is contained in:
gVisor bot 2020-07-29 11:27:18 +08:00
parent 0078ac2fc8
commit ba07a6d0d7

View file

@ -33,7 +33,7 @@ func (ps *Process) Match(metadata *C.Metadata) bool {
key := fmt.Sprintf("%s:%s:%s", metadata.NetWork.String(), metadata.SrcIP.String(), metadata.SrcPort) key := fmt.Sprintf("%s:%s:%s", metadata.NetWork.String(), metadata.SrcIP.String(), metadata.SrcPort)
cached, hit := processCache.Get(key) cached, hit := processCache.Get(key)
if !hit { if !hit {
name, err := getExecPathFromAddress(metadata.SrcIP, metadata.SrcPort, metadata.NetWork == C.TCP) name, err := getExecPathFromAddress(metadata)
if err != nil { if err != nil {
log.Debugln("[%s] getExecPathFromAddress error: %s", C.Process.String(), err.Error()) log.Debugln("[%s] getExecPathFromAddress error: %s", C.Process.String(), err.Error())
return false return false
@ -91,17 +91,25 @@ func getExecPathFromPID(pid uint32) (string, error) {
return filepath.Base(string(buf[:firstZero])), nil return filepath.Base(string(buf[:firstZero])), nil
} }
func getExecPathFromAddress(ip net.IP, portStr string, isTCP bool) (string, error) { func getExecPathFromAddress(metadata *C.Metadata) (string, error) {
port, err := strconv.Atoi(portStr) ip := metadata.SrcIP
port, err := strconv.Atoi(metadata.SrcPort)
if err != nil { if err != nil {
return "", err return "", err
} }
spath := "net.inet.tcp.pcblist_n" var spath string
if !isTCP { switch metadata.NetWork {
case C.TCP:
spath = "net.inet.tcp.pcblist_n"
case C.UDP:
spath = "net.inet.udp.pcblist_n" spath = "net.inet.udp.pcblist_n"
default:
return "", ErrInvalidNetwork
} }
isIPv4 := ip.To4() != nil
value, err := syscall.Sysctl(spath) value, err := syscall.Sysctl(spath)
if err != nil { if err != nil {
return "", err return "", err
@ -109,35 +117,19 @@ func getExecPathFromAddress(ip net.IP, portStr string, isTCP bool) (string, erro
buf := []byte(value) buf := []byte(value)
var kinds uint32 = 0 // from darwin-xnu/bsd/netinet/in_pcblist.c:get_pcblist_n
so, inp := 0, 0 // size/offset are round up (aligned) to 8 bytes in darwin
for i := roundUp8(xinpgenSize(buf)); i < uint32(len(buf)) && xinpgenSize(buf[i:]) > 24; i += roundUp8(xinpgenSize(buf[i:])) { // rup8(sizeof(xinpcb_n)) + rup8(sizeof(xsocket_n)) +
thisKind := binary.LittleEndian.Uint32(buf[i+4 : i+8]) // 2 * rup8(sizeof(xsockbuf_n)) + rup8(sizeof(xsockstat_n))
if kinds&thisKind == 0 { itemSize := 384
kinds |= thisKind if metadata.NetWork == C.TCP {
switch thisKind { // rup8(sizeof(xtcpcb_n))
case 0x1: itemSize += 208
// XSO_SOCKET }
so = int(i) // skip the first and last xinpgen(24 bytes) block
case 0x10: for i := 24; i < len(buf)-24; i += itemSize {
// XSO_INPCB // offset of xinpcb_n and xsocket_n
inp = int(i) inp, so := i, i+104
default:
break
}
}
// all blocks needed by tcp/udp
if (isTCP && kinds != 0x3f) || (!isTCP && kinds != 0x1f) {
continue
}
kinds = 0
// xsocket_n.xso_protocol
proto := binary.LittleEndian.Uint32(buf[so+36 : so+40])
if proto != syscall.IPPROTO_TCP && proto != syscall.IPPROTO_UDP {
continue
}
srcPort := binary.BigEndian.Uint16(buf[inp+18 : inp+20]) srcPort := binary.BigEndian.Uint16(buf[inp+18 : inp+20])
if uint16(port) != srcPort { if uint16(port) != srcPort {
@ -148,13 +140,14 @@ func getExecPathFromAddress(ip net.IP, portStr string, isTCP bool) (string, erro
flag := buf[inp+44] flag := buf[inp+44]
var srcIP net.IP var srcIP net.IP
if flag&0x1 > 0 { switch {
case flag&0x1 > 0 && isIPv4:
// ipv4 // ipv4
srcIP = net.IP(buf[inp+76 : inp+80]) srcIP = net.IP(buf[inp+76 : inp+80])
} else if flag&0x2 > 0 { case flag&0x2 > 0 && !isIPv4:
// ipv6 // ipv6
srcIP = net.IP(buf[inp+64 : inp+80]) srcIP = net.IP(buf[inp+64 : inp+80])
} else { default:
continue continue
} }
@ -163,20 +156,13 @@ func getExecPathFromAddress(ip net.IP, portStr string, isTCP bool) (string, erro
} }
// xsocket_n.so_last_pid // xsocket_n.so_last_pid
pid := binary.LittleEndian.Uint32(buf[so+68 : so+72]) pid := readNativeUint32(buf[so+68 : so+72])
return getExecPathFromPID(pid) return getExecPathFromPID(pid)
} }
return "", errors.New("process not found") return "", errors.New("process not found")
} }
func xinpgenSize(b []byte) uint32 { func readNativeUint32(b []byte) uint32 {
return binary.LittleEndian.Uint32(b[:4]) return *(*uint32)(unsafe.Pointer(&b[0]))
}
func roundUp8(n uint32) uint32 {
if n == 0 {
return uint32(8)
}
return (n + 7) & ((^uint32(8)) + 1)
} }