repochecker: New plugin ip-inspector
This commit is contained in:
parent
7eb56999a3
commit
f1a2e6c360
5 changed files with 196 additions and 3 deletions
18
repochecker/pcap-inspector/README.md
Normal file
18
repochecker/pcap-inspector/README.md
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# IP-INSPECTOR
|
||||
|
||||
Inspects pcap and pcapng files for packets with ip src and ip dst using private IPs
|
||||
|
||||
Set VERBOSE_PCAP_CHECK environment variable to enable verbose mode
|
||||
|
||||
## Build library
|
||||
|
||||
go build -o ip-inspector -buildmode=plugin main.go files.go
|
||||
|
||||
## Requirement
|
||||
|
||||
github.com/google/gopacket
|
||||
|
||||
## TODO
|
||||
|
||||
Custom rules on packet filtering
|
||||
Handle log files
|
||||
157
repochecker/pcap-inspector/files.go
Normal file
157
repochecker/pcap-inspector/files.go
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
layers "github.com/google/gopacket/layers"
|
||||
"github.com/google/gopacket/pcapgo"
|
||||
"srs.epita.fr/fic-server/admin/sync"
|
||||
fic "srs.epita.fr/fic-server/libfic"
|
||||
)
|
||||
|
||||
// This interface abstract pcap and pcapng data acquisition
|
||||
// pcapgo.Reader and pcapgo.NgReader both use signature :
|
||||
// ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error)
|
||||
type PcapPacketDataReader interface {
|
||||
ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error)
|
||||
}
|
||||
|
||||
// Wrap pcago.Reader as we can't impl its interface outside its package
|
||||
type PcapReader struct {
|
||||
*pcapgo.Reader
|
||||
}
|
||||
|
||||
// Wrap pcago.NgReader as we can't impl its interface outside its package
|
||||
type PcapNgReader struct {
|
||||
*pcapgo.NgReader
|
||||
}
|
||||
|
||||
//
|
||||
// Impl interface for reading pcap and pcapng data
|
||||
//
|
||||
func (pcapReader *PcapReader) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
|
||||
return pcapReader.Reader.ReadPacketData()
|
||||
}
|
||||
|
||||
func (pcapNGReader *PcapNgReader) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
|
||||
return pcapNGReader.NgReader.ReadPacketData()
|
||||
}
|
||||
|
||||
//
|
||||
// Iterate thought each packet to find potentialy unwanted packets
|
||||
// TODO: Allow custom rules to specify what is a unwanted packet
|
||||
//
|
||||
func CheckPcap(pcapReader PcapPacketDataReader, pcapName string) (errs []error) {
|
||||
|
||||
warningFlows := make(map[gopacket.Flow]([]time.Time))
|
||||
|
||||
//
|
||||
// Handle packets from network layer section
|
||||
//
|
||||
data, ci, err := pcapReader.ReadPacketData()
|
||||
for ; err == nil; data, ci, err = pcapReader.ReadPacketData() {
|
||||
|
||||
packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.Default)
|
||||
packetNetworkLayer := packet.NetworkLayer()
|
||||
|
||||
// No network layer
|
||||
if packetNetworkLayer == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
flow := packetNetworkLayer.NetworkFlow()
|
||||
|
||||
ENDPOINT_SELECTION:
|
||||
switch flow.EndpointType() {
|
||||
|
||||
case layers.EndpointIPv4, layers.EndpointIPv6:
|
||||
src, dst := flow.Endpoints()
|
||||
|
||||
if net.ParseIP(src.String()).IsPrivate() &&
|
||||
net.ParseIP(dst.String()).IsPrivate() {
|
||||
|
||||
warningFlows[flow] = append(warningFlows[flow], ci.Timestamp)
|
||||
}
|
||||
|
||||
// Really ?
|
||||
default:
|
||||
break ENDPOINT_SELECTION
|
||||
}
|
||||
}
|
||||
|
||||
if os.Getenv("VERBOSE_PCAP_CHECK") != "" {
|
||||
for flow, timestamps := range warningFlows {
|
||||
log.Printf(
|
||||
"(%s) Found communication between two private IPs (%s => %s) at timestamps:",
|
||||
pcapName,
|
||||
flow.Src().String(),
|
||||
flow.Dst().String())
|
||||
|
||||
for _, timestamp := range timestamps {
|
||||
log.Printf("\t%s", timestamp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(warningFlows) > 0 {
|
||||
log.Printf("/!\\ %s: Found %d endpoints communicating with private IPs \n => Set VERBOSE_PCAP_CHECK env variable for details",
|
||||
pcapName,
|
||||
len(warningFlows))
|
||||
} else {
|
||||
log.Printf("%s: No endpoints communicating with private IPs \n",
|
||||
pcapName)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func CheckTextFile(fd *os.File) (errs []error) {
|
||||
return
|
||||
}
|
||||
|
||||
func InspectFileForIPAddr(file *fic.EFile, exceptions *sync.CheckExceptions) (errs []error) {
|
||||
i, ok := sync.GlobalImporter.(sync.LocalImporter)
|
||||
if !ok {
|
||||
log.Printf("Unable to load `ip-inspector.so` as the current Importer is not a LocalImporter (%T).", sync.GlobalImporter)
|
||||
return
|
||||
}
|
||||
|
||||
path := i.GetLocalPath(file.GetOrigin())
|
||||
|
||||
fd, err := os.Open(path)
|
||||
if err != nil {
|
||||
log.Printf("Unable to open %q: %s", path, err.Error())
|
||||
return
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
switch filepath.Ext(file.Name) {
|
||||
case ".pcap":
|
||||
pcapReader, err := pcapgo.NewReader(fd)
|
||||
if err != nil {
|
||||
log.Printf("Unable to load the pcap file, please check if it is a real pcap file")
|
||||
return
|
||||
}
|
||||
|
||||
errs = CheckPcap(&PcapReader{pcapReader}, file.Name)
|
||||
|
||||
case ".pcapng":
|
||||
pcapNgReader, err := pcapgo.NewNgReader(fd, pcapgo.DefaultNgReaderOptions)
|
||||
if err != nil {
|
||||
log.Printf("Unable to load the pcapng file, please check if it is a real pcapng file")
|
||||
return
|
||||
}
|
||||
errs = CheckPcap(&PcapNgReader{pcapNgReader}, file.Name)
|
||||
|
||||
default:
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
13
repochecker/pcap-inspector/main.go
Normal file
13
repochecker/pcap-inspector/main.go
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"srs.epita.fr/fic-server/admin/sync"
|
||||
)
|
||||
|
||||
var hooks *sync.CheckHooks
|
||||
|
||||
func RegisterChecksHooks(h *sync.CheckHooks) {
|
||||
hooks = h
|
||||
|
||||
h.RegisterFileHook(InspectFileForIPAddr)
|
||||
}
|
||||
Reference in a new issue