226 lines
6.1 KiB
Go
226 lines
6.1 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 !integration
|
|
|
|
package procs
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/elastic/beats/packetbeat/protos/applayer"
|
|
|
|
"github.com/elastic/beats/libbeat/common"
|
|
"github.com/elastic/beats/libbeat/logp"
|
|
)
|
|
|
|
type testingImpl struct {
|
|
localIPs []net.IP
|
|
portToPID map[applayer.Transport]map[uint16]int
|
|
pidToCmdline map[int]string
|
|
}
|
|
|
|
type runningProcess struct {
|
|
cmdline string
|
|
pid int
|
|
ports []uint16
|
|
proto applayer.Transport
|
|
}
|
|
|
|
func newTestingImpl(localIPs []net.IP, processes []runningProcess) *testingImpl {
|
|
impl := &testingImpl{
|
|
localIPs: localIPs,
|
|
portToPID: map[applayer.Transport]map[uint16]int{
|
|
applayer.TransportTCP: make(map[uint16]int),
|
|
applayer.TransportUDP: make(map[uint16]int),
|
|
},
|
|
pidToCmdline: make(map[int]string),
|
|
}
|
|
for _, proc := range processes {
|
|
for _, port := range proc.ports {
|
|
impl.portToPID[proc.proto][port] = proc.pid
|
|
}
|
|
impl.pidToCmdline[proc.pid] = proc.cmdline
|
|
}
|
|
return impl
|
|
}
|
|
|
|
func (impl *testingImpl) GetLocalPortToPIDMapping(transport applayer.Transport) (ports map[uint16]int, err error) {
|
|
return impl.portToPID[transport], nil
|
|
}
|
|
|
|
func (impl *testingImpl) GetProcessCommandLine(pid int) string {
|
|
if cmdline, ok := impl.pidToCmdline[pid]; ok {
|
|
return cmdline
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (impl *testingImpl) GetLocalIPs() ([]net.IP, error) {
|
|
return impl.localIPs, nil
|
|
}
|
|
|
|
func TestFindProcessTuple(t *testing.T) {
|
|
logp.TestingSetup()
|
|
config := ProcsConfig{
|
|
Enabled: true,
|
|
Monitored: []ProcConfig{
|
|
{Process: "NetCat", CmdlineGrep: "nc "},
|
|
{Process: "Curl", CmdlineGrep: "curl"},
|
|
{Process: "NMap", CmdlineGrep: "nmap"},
|
|
},
|
|
}
|
|
impl := newTestingImpl(
|
|
[]net.IP{
|
|
net.ParseIP("192.168.1.1"),
|
|
net.ParseIP("7777::33"),
|
|
},
|
|
[]runningProcess{
|
|
{
|
|
cmdline: "curl -o /dev/null http://example.net/",
|
|
pid: 101,
|
|
ports: []uint16{65535},
|
|
proto: applayer.TransportTCP,
|
|
},
|
|
{
|
|
cmdline: "/usr/X11/bin/webbrowser",
|
|
pid: 102,
|
|
ports: []uint16{3201, 3202, 3203},
|
|
proto: applayer.TransportTCP,
|
|
},
|
|
{
|
|
cmdline: "nc -v -l -p 80",
|
|
pid: 105,
|
|
ports: []uint16{80},
|
|
proto: applayer.TransportTCP,
|
|
},
|
|
{
|
|
cmdline: "bind",
|
|
pid: 333,
|
|
ports: []uint16{53},
|
|
proto: applayer.TransportUDP,
|
|
},
|
|
})
|
|
procs := ProcessesWatcher{}
|
|
err := procs.initWithImpl(config, impl)
|
|
assert.NoError(t, err)
|
|
|
|
for idx, testCase := range []struct {
|
|
name string
|
|
srcIP, dstIP, src, dst, srcCmd, dstCmd string
|
|
srcPort, dstPort int
|
|
proto applayer.Transport
|
|
preAction func()
|
|
}{
|
|
{
|
|
name: "Unrelated local HTTP client",
|
|
proto: applayer.TransportTCP,
|
|
srcIP: "127.0.0.1", srcPort: 12345,
|
|
dstIP: "1.2.3.4", dstPort: 80,
|
|
src: "", srcCmd: "",
|
|
dst: "", dstCmd: "",
|
|
},
|
|
{
|
|
name: "Web browser (IPv6)",
|
|
proto: applayer.TransportTCP,
|
|
srcIP: "7777::0:33", srcPort: 3201,
|
|
dstIP: "1234:1234::AAAA", dstPort: 443,
|
|
src: "", srcCmd: "/usr/X11/bin/webbrowser",
|
|
dst: "", dstCmd: "",
|
|
},
|
|
{
|
|
name: "Curl request",
|
|
proto: applayer.TransportTCP,
|
|
srcIP: "192.168.1.1", srcPort: 65535,
|
|
dstIP: "1.1.1.1", dstPort: 80,
|
|
src: "Curl", srcCmd: "curl -o /dev/null http://example.net/",
|
|
dst: "", dstCmd: "",
|
|
},
|
|
{
|
|
name: "Unrelated UDP using same port as TCP",
|
|
proto: applayer.TransportUDP,
|
|
srcIP: "192.168.1.1", srcPort: 65535,
|
|
dstIP: "1.1.1.1", dstPort: 80,
|
|
src: "", srcCmd: "",
|
|
dst: "", dstCmd: "",
|
|
},
|
|
{
|
|
name: "Local web browser to netcat server",
|
|
proto: applayer.TransportTCP,
|
|
srcIP: "127.0.0.1", srcPort: 3202,
|
|
dstIP: "127.0.0.1", dstPort: 80,
|
|
src: "", srcCmd: "/usr/X11/bin/webbrowser",
|
|
dst: "NetCat", dstCmd: "nc -v -l -p 80",
|
|
},
|
|
{
|
|
name: "External to netcat server",
|
|
proto: applayer.TransportTCP,
|
|
srcIP: "192.168.1.2", srcPort: 3203,
|
|
dstIP: "192.168.1.1", dstPort: 80,
|
|
src: "", srcCmd: "",
|
|
dst: "NetCat", dstCmd: "nc -v -l -p 80",
|
|
},
|
|
{
|
|
name: "New client",
|
|
preAction: func() {
|
|
// add a new running process
|
|
impl.pidToCmdline[555] = "/usr/bin/nmap -sT -P443 10.0.0.0/8"
|
|
impl.portToPID[applayer.TransportTCP][55555] = 555
|
|
},
|
|
proto: applayer.TransportTCP,
|
|
srcIP: "7777::33", srcPort: 55555,
|
|
dstIP: "10.1.2.3", dstPort: 443,
|
|
src: "NMap", srcCmd: "/usr/bin/nmap -sT -P443 10.0.0.0/8",
|
|
dst: "", dstCmd: "",
|
|
},
|
|
{
|
|
name: "DNS request (UDP)",
|
|
proto: applayer.TransportUDP,
|
|
srcIP: "1234:5678::55", srcPort: 533,
|
|
dstIP: "7777::33", dstPort: 53,
|
|
src: "", srcCmd: "",
|
|
dst: "", dstCmd: "bind",
|
|
},
|
|
} {
|
|
msg := fmt.Sprintf("test case #%d: %s", idx+1, testCase.name)
|
|
|
|
if testCase.preAction != nil {
|
|
testCase.preAction()
|
|
}
|
|
input := common.IPPortTuple{
|
|
BaseTuple: common.BaseTuple{
|
|
SrcIP: net.ParseIP(testCase.srcIP),
|
|
SrcPort: uint16(testCase.srcPort),
|
|
DstIP: net.ParseIP(testCase.dstIP),
|
|
DstPort: uint16(testCase.dstPort),
|
|
},
|
|
}
|
|
result := procs.FindProcessesTuple(&input, testCase.proto)
|
|
// nil result is not valid
|
|
assert.NotNil(t, result, msg)
|
|
|
|
assert.Equal(t, testCase.src, string(result.Src), msg)
|
|
assert.Equal(t, testCase.dst, string(result.Dst), msg)
|
|
assert.Equal(t, testCase.srcCmd, string(result.SrcCommand), msg)
|
|
assert.Equal(t, testCase.dstCmd, string(result.DstCommand), msg)
|
|
}
|
|
|
|
}
|