From f1a2e6c360a3574ebc6cc15bf9f329bcc185b162 Mon Sep 17 00:00:00 2001 From: Mathieu Ghirlanda Date: Thu, 10 Nov 2022 16:06:24 +0100 Subject: [PATCH] repochecker: New plugin ip-inspector --- go.mod | 2 +- go.sum | 9 +- repochecker/pcap-inspector/README.md | 18 +++ repochecker/pcap-inspector/files.go | 157 +++++++++++++++++++++++++++ repochecker/pcap-inspector/main.go | 13 +++ 5 files changed, 196 insertions(+), 3 deletions(-) create mode 100644 repochecker/pcap-inspector/README.md create mode 100644 repochecker/pcap-inspector/files.go create mode 100644 repochecker/pcap-inspector/main.go diff --git a/go.mod b/go.mod index 13fda586..35f12520 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/gin-gonic/gin v1.8.1 github.com/go-git/go-git/v5 v5.4.2 github.com/go-sql-driver/mysql v1.6.0 - github.com/julienschmidt/httprouter v1.3.0 + github.com/google/gopacket v1.1.19 github.com/studio-b12/gowebdav v0.0.0-20221109171924-60ec5ad56012 github.com/u2takey/ffmpeg-go v0.4.1 github.com/yuin/goldmark v1.5.2 diff --git a/go.sum b/go.sum index 930f35f4..f01eab79 100644 --- a/go.sum +++ b/go.sum @@ -69,6 +69,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= +github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -89,8 +91,6 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfC github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= @@ -170,6 +170,7 @@ gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2 gocv.io/x/gocv v0.25.0/go.mod h1:Rar2PS6DV+T4FL+PM535EImD/h13hGVaHhnCu1xarBs= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= @@ -182,6 +183,8 @@ golang.org/x/crypto v0.2.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4 golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.1.0 h1:r8Oj8ZA2Xy12/b5KZYj3tuv7NG/fBz3TwQVvpJ9l8Rk= golang.org/x/image v0.1.0/go.mod h1:iyPr49SD/G/TBxYVB/9RRtGUT5eNbo2u4NamWeQcD5c= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -238,8 +241,10 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= diff --git a/repochecker/pcap-inspector/README.md b/repochecker/pcap-inspector/README.md new file mode 100644 index 00000000..02d200b8 --- /dev/null +++ b/repochecker/pcap-inspector/README.md @@ -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 \ No newline at end of file diff --git a/repochecker/pcap-inspector/files.go b/repochecker/pcap-inspector/files.go new file mode 100644 index 00000000..9378b86f --- /dev/null +++ b/repochecker/pcap-inspector/files.go @@ -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 +} diff --git a/repochecker/pcap-inspector/main.go b/repochecker/pcap-inspector/main.go new file mode 100644 index 00000000..fdd47121 --- /dev/null +++ b/repochecker/pcap-inspector/main.go @@ -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) +}