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 }