server/repochecker/pcap-inspector/files.go

145 lines
3.7 KiB
Go

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, _ *fic.Exercice, exceptions *sync.CheckExceptions) (errs error) {
fd, closer, err := sync.GetFile(sync.GlobalImporter, file.GetOrigin())
if err != nil {
log.Printf("Unable to open %q: %s", file.GetOrigin(), err.Error())
return
}
defer closer()
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
}