package audit import ( "net" "strconv" "strings" "time" "gitlab.com/inetmock/inetmock/pkg/audit/details" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" "google.golang.org/protobuf/types/known/timestamppb" ) type Details interface { MarshalToWireFormat() (*anypb.Any, error) } type Event struct { ID int64 Timestamp time.Time Transport TransportProtocol Application AppProtocol SourceIP net.IP DestinationIP net.IP SourcePort uint16 DestinationPort uint16 ProtocolDetails Details TLS *TLSDetails } func (e *Event) ProtoMessage() proto.Message { var sourceIP isEventEntity_SourceIP if ipv4 := e.SourceIP.To4(); ipv4 != nil { sourceIP = &EventEntity_SourceIPv4{SourceIPv4: ipv4ToUint32(ipv4)} } else { sourceIP = &EventEntity_SourceIPv6{SourceIPv6: ipv6ToBytes(e.SourceIP)} } var destinationIP isEventEntity_DestinationIP if ipv4 := e.DestinationIP.To4(); ipv4 != nil { destinationIP = &EventEntity_DestinationIPv4{DestinationIPv4: ipv4ToUint32(ipv4)} } else { destinationIP = &EventEntity_DestinationIPv6{DestinationIPv6: ipv6ToBytes(e.DestinationIP)} } var tlsDetails *TLSDetailsEntity = nil if e.TLS != nil { tlsDetails = e.TLS.ProtoMessage() } var detailsEntity *anypb.Any = nil if e.ProtocolDetails != nil { if any, err := e.ProtocolDetails.MarshalToWireFormat(); err == nil { detailsEntity = any } } return &EventEntity{ Id: e.ID, Timestamp: timestamppb.New(e.Timestamp), Transport: e.Transport, Application: e.Application, SourceIP: sourceIP, DestinationIP: destinationIP, SourcePort: uint32(e.SourcePort), DestinationPort: uint32(e.DestinationPort), Tls: tlsDetails, ProtocolDetails: detailsEntity, } } func (e *Event) ApplyDefaults(id int64) { e.ID = id emptyTime := time.Time{} if e.Timestamp == emptyTime { e.Timestamp = time.Now().UTC() } } func (e *Event) SetSourceIPFromAddr(remoteAddr net.Addr) { ip, port := parseIPPortFromAddr(remoteAddr) e.SourceIP = ip e.SourcePort = port } func (e *Event) SetDestinationIPFromAddr(localAddr net.Addr) { ip, port := parseIPPortFromAddr(localAddr) e.DestinationIP = ip e.DestinationPort = port } func NewEventFromProto(msg *EventEntity) (ev Event) { var sourceIP net.IP switch ip := msg.GetSourceIP().(type) { case *EventEntity_SourceIPv4: sourceIP = uint32ToIP(ip.SourceIPv4) case *EventEntity_SourceIPv6: sourceIP = uint64ToIP(ip.SourceIPv6) } var destinationIP net.IP switch ip := msg.GetDestinationIP().(type) { case *EventEntity_DestinationIPv4: destinationIP = uint32ToIP(ip.DestinationIPv4) case *EventEntity_DestinationIPv6: destinationIP = uint64ToIP(ip.DestinationIPv6) } ev = Event{ ID: msg.GetId(), Timestamp: msg.GetTimestamp().AsTime(), Transport: msg.GetTransport(), Application: msg.GetApplication(), SourceIP: sourceIP, DestinationIP: destinationIP, SourcePort: uint16(msg.GetSourcePort()), DestinationPort: uint16(msg.GetDestinationPort()), ProtocolDetails: guessDetailsFromApp(msg.GetProtocolDetails()), TLS: NewTLSDetailsFromProto(msg.GetTls()), } return } func parseIPPortFromAddr(addr net.Addr) (ip net.IP, port uint16) { switch a := addr.(type) { case *net.TCPAddr: return a.IP, uint16(a.Port) case *net.UDPAddr: return a.IP, uint16(a.Port) case *net.UnixAddr: return default: ipPortSplit := strings.Split(addr.String(), ":") if len(ipPortSplit) != 2 { return } ip = net.ParseIP(ipPortSplit[0]) if p, err := strconv.Atoi(ipPortSplit[1]); err == nil { port = uint16(p) } return } } func guessDetailsFromApp(any *anypb.Any) Details { var detailsProto proto.Message var err error if detailsProto, err = any.UnmarshalNew(); err != nil { return nil } switch any.TypeUrl { case "type.googleapis.com/inetmock.audit.HTTPDetailsEntity": return details.NewHTTPFromWireFormat(detailsProto.(*details.HTTPDetailsEntity)) case "type.googleapis.com/inetmock.audit.DNSDetailsEntity": return details.NewDNSFromWireFormat(detailsProto.(*details.DNSDetailsEntity)) default: return nil } }