youtubebeat/vendor/github.com/elastic/beats/packetbeat/procs/procs_windows.go

189 lines
5.7 KiB
Go

// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
// +build windows
package procs
import (
"encoding/binary"
"errors"
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
"github.com/elastic/beats/packetbeat/protos/applayer"
)
type extractor interface {
// Extract extracts useful information from the pointed-to structure
Extract(unsafe.Pointer)
// Size of the structure
Size() int
}
type callbackFn func(uint16, int)
type extractorFactory func(fn callbackFn) extractor
type tcpRowOwnerPIDExtractor callbackFn
type tcp6RowOwnerPIDExtractor callbackFn
type udpRowOwnerPIDExtractor callbackFn
type udp6RowOwnerPIDExtractor callbackFn
var tablesByTransport = map[applayer.Transport][]struct {
family uint32
function GetExtendedTableFn
class uint32
extractor extractorFactory
}{
applayer.TransportTCP: {
{windows.AF_INET, _GetExtendedTcpTable, TCP_TABLE_OWNER_PID_ALL, extractTCPRowOwnerPID},
{windows.AF_INET6, _GetExtendedTcpTable, TCP_TABLE_OWNER_PID_ALL, extractTCP6RowOwnerPID},
},
applayer.TransportUDP: {
{windows.AF_INET, _GetExtendedUdpTable, UDP_TABLE_OWNER_PID, extractUDPRowOwnerPID},
{windows.AF_INET6, _GetExtendedUdpTable, UDP_TABLE_OWNER_PID, extractUDP6RowOwnerPID},
},
}
// GetLocalPortToPIDMapping returns the list of local port numbers and the PID
// that owns them.
func (proc *ProcessesWatcher) GetLocalPortToPIDMapping(transport applayer.Transport) (ports map[uint16]int, err error) {
tables, ok := tablesByTransport[transport]
if !ok {
return nil, fmt.Errorf("unsupported transport protocol id: %d", transport)
}
storeResults := func(localPort uint16, pid int) {
ports[localPort] = pid
}
ports = make(map[uint16]int)
for _, table := range tables {
data, err := getNetTable(table.function, false, table.family, table.class)
if err != nil {
return nil, err
}
err = parseTable(data, table.extractor(storeResults))
if err != nil {
return nil, err
}
}
return ports, nil
}
func getNetTable(fn GetExtendedTableFn, order bool, family uint32, tableClass uint32) ([]byte, error) {
// Call the winapi function with an increasing buffer until the required
// size is satisfied
for size, ptr, addr := uint32(0), []byte(nil), uintptr(0); ; {
code, err := fn(addr, &size, order, family, tableClass, 0)
if code == syscall.Errno(0) {
return ptr, nil
} else if code == syscall.ERROR_INSUFFICIENT_BUFFER {
ptr = make([]byte, size)
addr = uintptr(unsafe.Pointer(&ptr[0]))
} else {
return nil, fmt.Errorf("getNetTable failed: code=%v err=%v", code, err)
}
}
}
func parseTable(data []byte, extractor extractor) error {
lim := len(data)
if lim < sizeOfDWORD {
return errors.New("data table too small for length")
}
rowSize := extractor.Size()
n := int(*(*uint32)(unsafe.Pointer(&data[0])))
if lim < n*rowSize+sizeOfDWORD {
return errors.New("data table too small for its contents")
}
for i := 0; i < n; i++ {
ptr := unsafe.Pointer(&data[sizeOfDWORD+i*rowSize])
extractor.Extract(ptr)
}
return nil
}
// The MIB_TCP_ROW_xxx structures uses a 32-bit field to store ports:
// The first 16 bits contain the port in big-endian encoding
// The last 16 bits are unused.
func uint32FieldToPort(be uint32) uint16 {
return binary.BigEndian.Uint16((*[2]byte)(unsafe.Pointer(&be))[:])
}
func extractTCPRowOwnerPID(fn callbackFn) extractor {
return tcpRowOwnerPIDExtractor(fn)
}
func extractTCP6RowOwnerPID(fn callbackFn) extractor {
return tcp6RowOwnerPIDExtractor(fn)
}
func extractUDPRowOwnerPID(fn callbackFn) extractor {
return udpRowOwnerPIDExtractor(fn)
}
func extractUDP6RowOwnerPID(fn callbackFn) extractor {
return udp6RowOwnerPIDExtractor(fn)
}
// Extract will parse a row of Size() bytes pointed to by ptr
func (e tcpRowOwnerPIDExtractor) Extract(ptr unsafe.Pointer) {
row := (*TCPRowOwnerPID)(ptr)
e(uint32FieldToPort(row.localPort), int(row.owningPID))
}
// Size returns the size of a table row
func (tcpRowOwnerPIDExtractor) Size() int {
return int(unsafe.Sizeof(TCPRowOwnerPID{}))
}
// Extract will parse a row of Size() bytes pointed to by ptr
func (e tcp6RowOwnerPIDExtractor) Extract(ptr unsafe.Pointer) {
row := (*TCP6RowOwnerPID)(ptr)
e(uint32FieldToPort(row.localPort), int(row.owningPID))
}
// Size returns the size of a table row
func (tcp6RowOwnerPIDExtractor) Size() int {
return int(unsafe.Sizeof(TCP6RowOwnerPID{}))
}
// Extract will parse a row of Size() bytes pointed to by ptr
func (e udpRowOwnerPIDExtractor) Extract(ptr unsafe.Pointer) {
row := (*UDPRowOwnerPID)(ptr)
e(uint32FieldToPort(row.localPort), int(row.owningPID))
}
// Size returns the size of a table row
func (udpRowOwnerPIDExtractor) Size() int {
return int(unsafe.Sizeof(UDPRowOwnerPID{}))
}
// Extract will parse a row of Size() bytes pointed to by ptr
func (e udp6RowOwnerPIDExtractor) Extract(ptr unsafe.Pointer) {
row := (*UDP6RowOwnerPID)(ptr)
e(uint32FieldToPort(row.localPort), int(row.owningPID))
}
// Size returns the size of a table row
func (udp6RowOwnerPIDExtractor) Size() int {
return int(unsafe.Sizeof(UDP6RowOwnerPID{}))
}