package util import ( "crypto/rand" "encoding/base32" "encoding/binary" "github.com/google/gopacket" "github.com/google/gopacket/layers" "github.com/google/gopacket/pcapgo" log "github.com/sirupsen/logrus" "hash/adler32" "io/ioutil" "net" "os" "strconv" "strings" "time" ) // WritePcap writes the provided data to a given pcap file func WritePcap(file string, data []byte) { f, err := os.Create(file) if err != nil { log.Errorf("Error writing pcap file %s", file) } defer f.Close() r, err := pcapgo.NewNgWriter(f, layers.LinkTypeEthernet) if err != nil { log.Errorf("Error writing pcap file %s", file) } defer r.Flush() ci := gopacket.CaptureInfo{ Timestamp: time.Now(), CaptureLength: len(data), Length: len(data), } err = r.WritePacket(ci, data) } // WriteBinary writes the provided data to a given binary file func WriteBinary(file string, data []byte) { if err := ioutil.WriteFile(file, data, 0644); err != nil { log.Errorf("Error writing binary file %s", file) } } func WritePIDFile(filename string) { if filename == "" { return } if err := ioutil.WriteFile(filename, []byte(strconv.Itoa(os.Getpid())+"\n"), 0644); err != nil { log.Errorf("Error writing PID file %s", filename) } } func GenerateMac(customMAC string) net.HardwareAddr { if customMAC != "" { ret, _ := net.ParseMAC(customMAC) return ret } buf := make([]byte, 6) var mac net.HardwareAddr if _, err := rand.Read(buf); err != nil { log.Error("Error generating random mac") ret, _ := net.ParseMAC("52:54:00:12:34:aa") return ret } // Set local bit, ensure unicast address buf[0] = (buf[0] | 2) & 0xfe mac = append(mac, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]) return mac } func GenerateXID() []byte { buf := make([]byte, 4) if _, err := rand.Read(buf); err != nil { log.Error("Error generating random xid") return []byte{36, 23, 250, 224} // chosen by fair dice roll // guaranteed to be random --> https://xkcd.com/221/ } return buf } func GenerateUId(path string) string { adl := adler32.Checksum([]byte(path)) byt := make([]byte, 4) for i := uint32(0); i < 4; i++ { byt[i] = byte((adl >> (8 * i)) & 0xff) } b32 := base32.StdEncoding.EncodeToString(byt) return strings.ReplaceAll(b32, "=", "") } // If is a helper type to form expressive ternary expressions being the // concatenation of a type conversion and a method call such as: // // i := If(cond).Int(a, b) // // For details, see https://stackoverflow.com/a/59375088/1705598 type If bool // If returns a if c is true, b otherwise. func (c If) If(a, b interface{}) interface{} { if c { return a } return b } // MAC returns a if c is true, b otherwise. func (c If) MAC(a, b net.HardwareAddr) net.HardwareAddr { if c { return a } return b } // IP returns a if c is true, b otherwise. func (c If) IP(a, b net.IP) net.IP { if c { return a } return b } // Source: https://github.com/aler9/landiscover/blob/main/utils.go // partpart func DnsQueryDecode(data []byte, start int) (string, int) { var read []byte toread := uint8(0) pos := start for ; true; pos++ { if pos >= len(data) { // decoding terminated before null character return "", -1 } if data[pos] == 0x00 { if toread > 0 { // decoding terminated before part parsing return "", -1 } break // query correctly decoded } if toread == 0 { // we need a size or pointer if len(read) > 0 { // add separator read = append(read, '.') } if (data[pos] & 0xC0) == 0xC0 { // pointer ptr := int(binary.BigEndian.Uint16(data[pos:pos+2]) & 0x3FFF) pos++ // skip next byte substr, subread := DnsQueryDecode(data, ptr) if subread <= 0 { return "", -1 } read = append(read, []byte(substr)...) break // query correctly decoded } else { // size toread = data[pos] } } else { // byte inside part read = append(read, data[pos]) toread-- } } return string(read), pos + 1 - start } func DnsQueryEncode(in string) []byte { tmp := strings.Split(in, ".") l := 0 for _, part := range tmp { bpart := []byte(part) l++ l += len(bpart) } l++ ret := make([]byte, l) i := 0 for _, part := range tmp { bpart := []byte(part) ret[i] = uint8(len(bpart)) i++ copy(ret[i:], bpart) i += len(bpart) } ret[i] = uint8(0) return ret }