176 lines
2.7 KiB
Go
176 lines
2.7 KiB
Go
//go:build linux
|
|
|
|
package platform
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"unsafe"
|
|
)
|
|
|
|
var netIndexOfLocal = -1
|
|
var netIndexOfUid = -1
|
|
|
|
var nativeEndian binary.ByteOrder
|
|
|
|
func QuerySocketUidFromProcFs(source, _ net.Addr) int {
|
|
if netIndexOfLocal < 0 || netIndexOfUid < 0 {
|
|
return -1
|
|
}
|
|
|
|
network := source.Network()
|
|
|
|
if strings.HasSuffix(network, "4") || strings.HasSuffix(network, "6") {
|
|
network = network[:len(network)-1]
|
|
}
|
|
|
|
path := "/proc/net/" + network
|
|
|
|
var sIP net.IP
|
|
var sPort int
|
|
|
|
switch s := source.(type) {
|
|
case *net.TCPAddr:
|
|
sIP = s.IP
|
|
sPort = s.Port
|
|
case *net.UDPAddr:
|
|
sIP = s.IP
|
|
sPort = s.Port
|
|
default:
|
|
return -1
|
|
}
|
|
|
|
sIP = sIP.To16()
|
|
if sIP == nil {
|
|
return -1
|
|
}
|
|
|
|
uid := doQuery(path+"6", sIP, sPort)
|
|
if uid == -1 {
|
|
sIP = sIP.To4()
|
|
if sIP == nil {
|
|
return -1
|
|
}
|
|
uid = doQuery(path, sIP, sPort)
|
|
}
|
|
|
|
return uid
|
|
}
|
|
|
|
func doQuery(path string, sIP net.IP, sPort int) int {
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
return -1
|
|
}
|
|
|
|
defer func(file *os.File) {
|
|
_ = file.Close()
|
|
}(file)
|
|
|
|
reader := bufio.NewReader(file)
|
|
|
|
var bytes [2]byte
|
|
|
|
binary.BigEndian.PutUint16(bytes[:], uint16(sPort))
|
|
|
|
local := fmt.Sprintf("%s:%s", hex.EncodeToString(nativeEndianIP(sIP)), hex.EncodeToString(bytes[:]))
|
|
|
|
for {
|
|
row, _, err := reader.ReadLine()
|
|
if err != nil {
|
|
return -1
|
|
}
|
|
|
|
fields := strings.Fields(string(row))
|
|
|
|
if len(fields) <= netIndexOfLocal || len(fields) <= netIndexOfUid {
|
|
continue
|
|
}
|
|
|
|
if strings.EqualFold(local, fields[netIndexOfLocal]) {
|
|
uid, err := strconv.Atoi(fields[netIndexOfUid])
|
|
if err != nil {
|
|
return -1
|
|
}
|
|
|
|
return uid
|
|
}
|
|
}
|
|
}
|
|
|
|
func nativeEndianIP(ip net.IP) []byte {
|
|
result := make([]byte, len(ip))
|
|
|
|
for i := 0; i < len(ip); i += 4 {
|
|
value := binary.BigEndian.Uint32(ip[i:])
|
|
|
|
nativeEndian.PutUint32(result[i:], value)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func init() {
|
|
file, err := os.Open("/proc/net/tcp")
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
defer func(file *os.File) {
|
|
_ = file.Close()
|
|
}(file)
|
|
|
|
reader := bufio.NewReader(file)
|
|
|
|
header, _, err := reader.ReadLine()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
columns := strings.Fields(string(header))
|
|
|
|
var txQueue, rxQueue, tr, tmWhen bool
|
|
|
|
for idx, col := range columns {
|
|
offset := 0
|
|
|
|
if txQueue && rxQueue {
|
|
offset--
|
|
}
|
|
|
|
if tr && tmWhen {
|
|
offset--
|
|
}
|
|
|
|
switch col {
|
|
case "tx_queue":
|
|
txQueue = true
|
|
case "rx_queue":
|
|
rxQueue = true
|
|
case "tr":
|
|
tr = true
|
|
case "tm->when":
|
|
tmWhen = true
|
|
case "local_address":
|
|
netIndexOfLocal = idx + offset
|
|
case "uid":
|
|
netIndexOfUid = idx + offset
|
|
}
|
|
}
|
|
}
|
|
|
|
func init() {
|
|
var x uint32 = 0x01020304
|
|
if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
|
|
nativeEndian = binary.BigEndian
|
|
} else {
|
|
nativeEndian = binary.LittleEndian
|
|
}
|
|
}
|