You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
fw-daemon/proc/socket.go

100 lines
2.0 KiB

package proc
import (
"errors"
"fmt"
"io/ioutil"
"net"
"strconv"
"strings"
)
type socketAddr struct {
ip net.IP
port uint16
}
func (sa socketAddr) String() string {
return fmt.Sprintf("%v:%d", sa.ip, sa.port)
}
type socketStatus struct {
local socketAddr
remote socketAddr
uid int
inode uint64
line string
}
func (ss *socketStatus) String() string {
return fmt.Sprintf("%s -> %s uid=%d inode=%d", ss.local, ss.remote, ss.uid, ss.inode)
}
func findUDPSocket(srcPort uint16) *socketStatus {
return findSocket("udp", func(ss socketStatus) bool {
return ss.local.port == srcPort
})
}
func findTCPSocket(srcPort uint16, dstAddr net.IP, dstPort uint16) *socketStatus {
return findSocket("tcp", func(ss socketStatus) bool {
return ss.remote.port == dstPort && ss.remote.ip.Equal(dstAddr) && ss.local.port == srcPort
})
}
func findSocket(proto string, matcher func(socketStatus) bool) *socketStatus {
var ss socketStatus
for _, line := range getSocketLines(proto) {
if len(line) == 0 {
continue
}
if err := ss.parseLine(line); err != nil {
log.Warning("Unable to parse line from /proc/net/%s [%s]: %v", proto, line, err)
continue
}
if matcher(ss) {
ss.line = line
return &ss
}
}
return nil
}
func (ss *socketStatus) parseLine(line string) error {
fs := strings.Fields(line)
if len(fs) < 10 {
return errors.New("insufficient fields")
}
if err := ss.local.parse(fs[1]); err != nil {
return err
}
if err := ss.remote.parse(fs[2]); err != nil {
return err
}
uid, err := strconv.ParseUint(fs[7], 10, 32)
if err != nil {
return err
}
ss.uid = int(uid)
inode, err := strconv.ParseUint(fs[9], 10, 64)
if err != nil {
return err
}
ss.inode = inode
return nil
}
func getSocketLines(proto string) []string {
path := fmt.Sprintf("/proc/net/%s", proto)
data, err := ioutil.ReadFile(path)
if err != nil {
log.Warning("Error reading %s: %v", path, err)
return nil
}
lines := strings.Split(string(data), "\n")
if len(lines) > 0 {
lines = lines[1:]
}
return lines
}