Skip to content

Commit

Permalink
Refactor: refactor find process (#2781)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kr328 authored Jun 13, 2023
1 parent 289025c commit 13d9e96
Show file tree
Hide file tree
Showing 21 changed files with 650 additions and 468 deletions.
6 changes: 5 additions & 1 deletion adapter/inbound/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,24 @@ package inbound

import (
"net"
"net/netip"

C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/context"
"github.com/Dreamacro/clash/transport/socks5"
)

// NewHTTP receive normal http request and return HTTPContext
func NewHTTP(target socks5.Addr, source net.Addr, conn net.Conn) *context.ConnContext {
func NewHTTP(target socks5.Addr, source net.Addr, originTarget net.Addr, conn net.Conn) *context.ConnContext {
metadata := parseSocksAddr(target)
metadata.NetWork = C.TCP
metadata.Type = C.HTTP
if ip, port, err := parseAddr(source.String()); err == nil {
metadata.SrcIP = ip
metadata.SrcPort = port
}
if addrPort, err := netip.ParseAddrPort(originTarget.String()); err == nil {
metadata.OriginDst = addrPort
}
return context.NewConnContext(conn, metadata)
}
4 changes: 4 additions & 0 deletions adapter/inbound/https.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package inbound
import (
"net"
"net/http"
"net/netip"

C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/context"
Expand All @@ -16,5 +17,8 @@ func NewHTTPS(request *http.Request, conn net.Conn) *context.ConnContext {
metadata.SrcIP = ip
metadata.SrcPort = port
}
if addrPort, err := netip.ParseAddrPort(conn.LocalAddr().String()); err == nil {
metadata.OriginDst = addrPort
}
return context.NewConnContext(conn, metadata)
}
9 changes: 7 additions & 2 deletions adapter/inbound/packet.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package inbound

import (
"net"
"net/netip"

C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/transport/socks5"
)
Expand All @@ -17,15 +20,17 @@ func (s *PacketAdapter) Metadata() *C.Metadata {
}

// NewPacket is PacketAdapter generator
func NewPacket(target socks5.Addr, packet C.UDPPacket, source C.Type) *PacketAdapter {
func NewPacket(target socks5.Addr, originTarget net.Addr, packet C.UDPPacket, source C.Type) *PacketAdapter {
metadata := parseSocksAddr(target)
metadata.NetWork = C.UDP
metadata.Type = source
if ip, port, err := parseAddr(packet.LocalAddr().String()); err == nil {
metadata.SrcIP = ip
metadata.SrcPort = port
}

if addrPort, err := netip.ParseAddrPort(originTarget.String()); err == nil {
metadata.OriginDst = addrPort
}
return &PacketAdapter{
UDPPacket: packet,
metadata: metadata,
Expand Down
5 changes: 4 additions & 1 deletion adapter/inbound/socket.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package inbound

import (
"net"
"net/netip"

C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/context"
Expand All @@ -17,6 +18,8 @@ func NewSocket(target socks5.Addr, conn net.Conn, source C.Type) *context.ConnCo
metadata.SrcIP = ip
metadata.SrcPort = port
}

if addrPort, err := netip.ParseAddrPort(conn.LocalAddr().String()); err == nil {
metadata.OriginDst = addrPort
}
return context.NewConnContext(conn, metadata)
}
6 changes: 3 additions & 3 deletions component/process/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package process

import (
"errors"
"net"
"net/netip"
)

var (
Expand All @@ -16,6 +16,6 @@ const (
UDP = "udp"
)

func FindProcessName(network string, srcIP net.IP, srcPort int) (string, error) {
return findProcessName(network, srcIP, srcPort)
func FindProcessPath(network string, from netip.AddrPort, to netip.AddrPort) (string, error) {
return findProcessPath(network, from, to)
}
22 changes: 14 additions & 8 deletions component/process/process_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package process

import (
"encoding/binary"
"net"
"net/netip"
"strconv"
"strings"
"syscall"
Expand Down Expand Up @@ -33,7 +33,7 @@ var structSize = func() int {
}
}()

func findProcessName(network string, ip net.IP, port int) (string, error) {
func findProcessPath(network string, from netip.AddrPort, _ netip.AddrPort) (string, error) {
var spath string
switch network {
case TCP:
Expand All @@ -44,7 +44,7 @@ func findProcessName(network string, ip net.IP, port int) (string, error) {
return "", ErrInvalidNetwork
}

isIPv4 := ip.To4() != nil
isIPv4 := from.Addr().Is4()

value, err := syscall.Sysctl(spath)
if err != nil {
Expand All @@ -65,30 +65,36 @@ func findProcessName(network string, ip net.IP, port int) (string, error) {
inp, so := i, i+104

srcPort := binary.BigEndian.Uint16(buf[inp+18 : inp+20])
if uint16(port) != srcPort {
if from.Port() != srcPort {
continue
}

// FIXME: add dstPort check

// xinpcb_n.inp_vflag
flag := buf[inp+44]

var (
srcIP net.IP
srcIP netip.Addr
srcIPOk bool
srcIsIPv4 bool
)
switch {
case flag&0x1 > 0 && isIPv4:
// ipv4
srcIP = net.IP(buf[inp+76 : inp+80])
srcIP, srcIPOk = netip.AddrFromSlice(buf[inp+76 : inp+80])
srcIsIPv4 = true
case flag&0x2 > 0 && !isIPv4:
// ipv6
srcIP = net.IP(buf[inp+64 : inp+80])
srcIP, srcIPOk = netip.AddrFromSlice(buf[inp+64 : inp+80])
default:
continue
}
if !srcIPOk {
continue
}

if ip.Equal(srcIP) {
if from.Addr() == srcIP { // FIXME: add dstIP check
// xsocket_n.so_last_pid
pid := readNativeUint32(buf[so+68 : so+72])
return getExecPathFromPID(pid)
Expand Down
217 changes: 217 additions & 0 deletions component/process/process_freebsd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
package process

import (
"encoding/binary"
"fmt"
"net/netip"
"strconv"
"strings"
"unsafe"

"golang.org/x/sys/unix"
)

type Xinpgen12 [64]byte // size 64

type InEndpoints12 struct {
FPort [2]byte
LPort [2]byte
FAddr [16]byte
LAddr [16]byte
ZoneID uint32
} // size 40

type XTcpcb12 struct {
Len uint32 // offset 0
Padding1 [20]byte // offset 4
SocketAddr uint64 // offset 24
Padding2 [84]byte // offset 32
Family uint32 // offset 116
Padding3 [140]byte // offset 120
InEndpoints InEndpoints12 // offset 260
Padding4 [444]byte // offset 300
} // size 744

type XInpcb12 struct {
Len uint32 // offset 0
Padding1 [12]byte // offset 4
SocketAddr uint64 // offset 16
Padding2 [84]byte // offset 24
Family uint32 // offset 108
Padding3 [140]byte // offset 112
InEndpoints InEndpoints12 // offset 252
Padding4 [108]byte // offset 292
} // size 400

type XFile12 struct {
Size uint64 // offset 0
Pid uint32 // offset 8
Padding1 [44]byte // offset 12
DataAddr uint64 // offset 56
Padding2 [64]byte // offset 64
} // size 128

var majorVersion = func() int {
releaseVersion, err := unix.Sysctl("kern.osrelease")
if err != nil {
return 0
}

majorVersionText, _, _ := strings.Cut(releaseVersion, ".")

majorVersion, err := strconv.Atoi(majorVersionText)
if err != nil {
return 0
}

return majorVersion
}()

func findProcessPath(network string, from netip.AddrPort, to netip.AddrPort) (string, error) {
switch majorVersion {
case 12, 13:
return findProcessPath12(network, from, to)
}

return "", ErrPlatformNotSupport
}

func findProcessPath12(network string, from netip.AddrPort, to netip.AddrPort) (string, error) {
switch network {
case TCP:
data, err := unix.SysctlRaw("net.inet.tcp.pcblist")
if err != nil {
return "", err
}

if len(data) < int(unsafe.Sizeof(Xinpgen12{})) {
return "", fmt.Errorf("invalid sysctl data len: %d", len(data))
}

data = data[unsafe.Sizeof(Xinpgen12{}):]

for len(data) > int(unsafe.Sizeof(XTcpcb12{}.Len)) {
tcb := (*XTcpcb12)(unsafe.Pointer(&data[0]))
if tcb.Len < uint32(unsafe.Sizeof(XTcpcb12{})) || uint32(len(data)) < tcb.Len {
break
}

data = data[tcb.Len:]

var (
connFromAddr netip.Addr
connToAddr netip.Addr
)
if tcb.Family == unix.AF_INET {
connFromAddr = netip.AddrFrom4([4]byte(tcb.InEndpoints.LAddr[12:16]))
connToAddr = netip.AddrFrom4([4]byte(tcb.InEndpoints.FAddr[12:16]))
} else if tcb.Family == unix.AF_INET6 {
connFromAddr = netip.AddrFrom16(tcb.InEndpoints.LAddr)
connToAddr = netip.AddrFrom16(tcb.InEndpoints.FAddr)
} else {
continue
}

connFrom := netip.AddrPortFrom(connFromAddr, binary.BigEndian.Uint16(tcb.InEndpoints.LPort[:]))
connTo := netip.AddrPortFrom(connToAddr, binary.BigEndian.Uint16(tcb.InEndpoints.FPort[:]))

if connFrom == from && connTo == to {
pid, err := findPidBySocketAddr12(tcb.SocketAddr)
if err != nil {
return "", err
}

return findExecutableByPid(pid)
}
}
case UDP:
data, err := unix.SysctlRaw("net.inet.udp.pcblist")
if err != nil {
return "", err
}

if len(data) < int(unsafe.Sizeof(Xinpgen12{})) {
return "", fmt.Errorf("invalid sysctl data len: %d", len(data))
}

data = data[unsafe.Sizeof(Xinpgen12{}):]

for len(data) > int(unsafe.Sizeof(XInpcb12{}.Len)) {
icb := (*XInpcb12)(unsafe.Pointer(&data[0]))
if icb.Len < uint32(unsafe.Sizeof(XInpcb12{})) || uint32(len(data)) < icb.Len {
break
}
data = data[icb.Len:]

var connFromAddr netip.Addr

if icb.Family == unix.AF_INET {
connFromAddr = netip.AddrFrom4([4]byte(icb.InEndpoints.LAddr[12:16]))
} else if icb.Family == unix.AF_INET6 {
connFromAddr = netip.AddrFrom16(icb.InEndpoints.LAddr)
} else {
continue
}

connFrom := netip.AddrPortFrom(connFromAddr, binary.BigEndian.Uint16(icb.InEndpoints.LPort[:]))

if connFrom == from {
pid, err := findPidBySocketAddr12(icb.SocketAddr)
if err != nil {
return "", err
}

return findExecutableByPid(pid)
}
}
}

return "", ErrNotFound
}

func findPidBySocketAddr12(socketAddr uint64) (uint32, error) {
buf, err := unix.SysctlRaw("kern.file")
if err != nil {
return 0, err
}

filesLen := len(buf) / int(unsafe.Sizeof(XFile12{}))
files := unsafe.Slice((*XFile12)(unsafe.Pointer(&buf[0])), filesLen)

for _, file := range files {
if file.Size != uint64(unsafe.Sizeof(XFile12{})) {
return 0, fmt.Errorf("invalid xfile size: %d", file.Size)
}

if file.DataAddr == socketAddr {
return file.Pid, nil
}
}

return 0, ErrNotFound
}

func findExecutableByPid(pid uint32) (string, error) {
buf := make([]byte, unix.PathMax)
size := uint64(len(buf))
mib := [4]uint32{
unix.CTL_KERN,
14, // KERN_PROC
12, // KERN_PROC_PATHNAME
pid,
}

_, _, errno := unix.Syscall6(
unix.SYS___SYSCTL,
uintptr(unsafe.Pointer(&mib[0])),
uintptr(len(mib)),
uintptr(unsafe.Pointer(&buf[0])),
uintptr(unsafe.Pointer(&size)),
0,
0)
if errno != 0 || size == 0 {
return "", fmt.Errorf("sysctl: get proc name: %w", errno)
}

return string(buf[:size-1]), nil
}
Loading

0 comments on commit 13d9e96

Please sign in to comment.