From c62173ac9558581fee03e63955a7eb8941178d05 Mon Sep 17 00:00:00 2001 From: "Mohamed S. Mahmoud" <mmahmoud@redhat.com> Date: Mon, 20 Mar 2023 11:01:31 -0400 Subject: [PATCH] NETOBSERV-934: Add support for SCTP, ICMPv4/v6 protocols to ebpf agent (#103) * Add support for SCTP, ICMP amd ICMPv6 protocols to ebpf code Signed-off-by: Mohamed Mahmoud <mmahmoud@redhat.com> * update GRPC protobuf definition to include icmp fields Signed-off-by: msherif1234 <mmahmoud@redhat.com> * Add ICMP and ICMPv6 ipfix support Signed-off-by: msherif1234 <mmahmoud@redhat.com> * Add ICMPv4/6 ebpf agent support Signed-off-by: msherif1234 <mmahmoud@redhat.com> * Update unit-test cases Signed-off-by: msherif1234 <mmahmoud@redhat.com> * Add verifier error check to catch JIT errors Signed-off-by: msherif1234 <mmahmoud@redhat.com> * update flowlogs dump collector tool to include ICMP Signed-off-by: msherif1234 <mmahmoud@redhat.com> --------- Signed-off-by: Mohamed Mahmoud <mmahmoud@redhat.com> Signed-off-by: msherif1234 <mmahmoud@redhat.com> --- bpf/flow.h | 3 + bpf/flows.c | 137 +++++++++----- .../server/flowlogs-dump-collector.go | 8 +- pkg/ebpf/bpf_bpfeb.go | 2 + pkg/ebpf/bpf_bpfeb.o | Bin 21176 -> 22872 bytes pkg/ebpf/bpf_bpfel.go | 2 + pkg/ebpf/bpf_bpfel.o | Bin 21704 -> 22040 bytes pkg/ebpf/tracer.go | 7 + pkg/exporter/ipfix.go | 20 +++ pkg/exporter/kafka_proto_test.go | 2 + pkg/exporter/proto.go | 8 + pkg/flow/record_test.go | 4 + pkg/grpc/grpc_test.go | 8 + pkg/pbflow/flow.pb.go | 169 +++++++++++++----- proto/flow.proto | 6 + 15 files changed, 287 insertions(+), 89 deletions(-) diff --git a/bpf/flow.h b/bpf/flow.h index fa06e1d8..f36ce12d 100644 --- a/bpf/flow.h +++ b/bpf/flow.h @@ -45,6 +45,9 @@ typedef struct flow_id_t { u16 src_port; u16 dst_port; u8 transport_protocol; + // ICMP protocol + u8 icmp_type; + u8 icmp_code; // OS interface index u32 if_index; } __attribute__((packed)) flow_id; diff --git a/bpf/flows.c b/bpf/flows.c index bee299da..40ea1a1c 100644 --- a/bpf/flows.c +++ b/bpf/flows.c @@ -13,7 +13,6 @@ until an entry is available. 4) When hash collision is detected, we send the new entry to userpace via ringbuffer. */ - #include <linux/bpf.h> #include <linux/in.h> #include <linux/if_packet.h> @@ -55,6 +54,15 @@ #define FIN_ACK_FLAG 0x200 #define RST_ACK_FLAG 0x400 +// SCTP protocol header structure, its defined here because its not +// exported by the kernel headers like other protocols. +struct sctphdr { + __be16 source; + __be16 dest; + __be32 vtag; + __le32 checksum; +}; + // Common Ringbuffer as a conduit for ingress/egress flows to userspace struct { __uint(type, BPF_MAP_TYPE_RINGBUF); @@ -104,71 +112,111 @@ static inline void set_flags(struct tcphdr *th, u16 *flags) { *flags |= CWR_FLAG; } } -// sets flow fields from IPv4 header information -static inline int fill_iphdr(struct iphdr *ip, void *data_end, flow_id *id, u16 *flags) { - if ((void *)ip + sizeof(*ip) > data_end) { - return DISCARD; - } - __builtin_memcpy(id->src_ip, ip4in6, sizeof(ip4in6)); - __builtin_memcpy(id->dst_ip, ip4in6, sizeof(ip4in6)); - __builtin_memcpy(id->src_ip + sizeof(ip4in6), &ip->saddr, sizeof(ip->saddr)); - __builtin_memcpy(id->dst_ip + sizeof(ip4in6), &ip->daddr, sizeof(ip->daddr)); - id->transport_protocol = ip->protocol; - id->src_port = 0; - id->dst_port = 0; - switch (ip->protocol) { +// L4_info structure contains L4 headers parsed information. +struct l4_info_t { + // TCP/UDP/SCTP source port in host byte order + u16 src_port; + // TCP/UDP/SCTP destination port in host byte order + u16 dst_port; + // ICMPv4/ICMPv6 type value + u8 icmp_type; + // ICMPv4/ICMPv6 code value + u8 icmp_code; + // TCP flags + u16 flags; +}; + +// Extract L4 info for the supported protocols +static inline void fill_l4info(void *l4_hdr_start, void *data_end, u8 protocol, + struct l4_info_t *l4_info) { + switch (protocol) { case IPPROTO_TCP: { - struct tcphdr *tcp = (void *)ip + sizeof(*ip); + struct tcphdr *tcp = l4_hdr_start; if ((void *)tcp + sizeof(*tcp) <= data_end) { - id->src_port = __bpf_ntohs(tcp->source); - id->dst_port = __bpf_ntohs(tcp->dest); - set_flags(tcp, flags); + l4_info->src_port = __bpf_ntohs(tcp->source); + l4_info->dst_port = __bpf_ntohs(tcp->dest); + set_flags(tcp, &l4_info->flags); } } break; case IPPROTO_UDP: { - struct udphdr *udp = (void *)ip + sizeof(*ip); + struct udphdr *udp = l4_hdr_start; if ((void *)udp + sizeof(*udp) <= data_end) { - id->src_port = __bpf_ntohs(udp->source); - id->dst_port = __bpf_ntohs(udp->dest); + l4_info->src_port = __bpf_ntohs(udp->source); + l4_info->dst_port = __bpf_ntohs(udp->dest); + } + } break; + case IPPROTO_SCTP: { + struct sctphdr *sctph = l4_hdr_start; + if ((void *)sctph + sizeof(*sctph) <= data_end) { + l4_info->src_port = __bpf_ntohs(sctph->source); + l4_info->dst_port = __bpf_ntohs(sctph->dest); + } + } break; + case IPPROTO_ICMP: { + struct icmphdr *icmph = l4_hdr_start; + if ((void *)icmph + sizeof(*icmph) <= data_end) { + l4_info->icmp_type = icmph->type; + l4_info->icmp_code = icmph->code; + } + } break; + case IPPROTO_ICMPV6: { + struct icmp6hdr *icmp6h = l4_hdr_start; + if ((void *)icmp6h + sizeof(*icmp6h) <= data_end) { + l4_info->icmp_type = icmp6h->icmp6_type; + l4_info->icmp_code = icmp6h->icmp6_code; } } break; default: break; } +} + +// sets flow fields from IPv4 header information +static inline int fill_iphdr(struct iphdr *ip, void *data_end, flow_id *id, u16 *flags) { + struct l4_info_t l4_info; + void *l4_hdr_start; + + l4_hdr_start = (void *)ip + sizeof(*ip); + if (l4_hdr_start > data_end) { + return DISCARD; + } + __builtin_memset(&l4_info, 0, sizeof(l4_info)); + __builtin_memcpy(id->src_ip, ip4in6, sizeof(ip4in6)); + __builtin_memcpy(id->dst_ip, ip4in6, sizeof(ip4in6)); + __builtin_memcpy(id->src_ip + sizeof(ip4in6), &ip->saddr, sizeof(ip->saddr)); + __builtin_memcpy(id->dst_ip + sizeof(ip4in6), &ip->daddr, sizeof(ip->daddr)); + id->transport_protocol = ip->protocol; + fill_l4info(l4_hdr_start, data_end, ip->protocol, &l4_info); + id->src_port = l4_info.src_port; + id->dst_port = l4_info.dst_port; + id->icmp_type = l4_info.icmp_type; + id->icmp_code = l4_info.icmp_code; + *flags = l4_info.flags; + return SUBMIT; } // sets flow fields from IPv6 header information static inline int fill_ip6hdr(struct ipv6hdr *ip, void *data_end, flow_id *id, u16 *flags) { - if ((void *)ip + sizeof(*ip) > data_end) { + struct l4_info_t l4_info; + void *l4_hdr_start; + + l4_hdr_start = (void *)ip + sizeof(*ip); + if (l4_hdr_start > data_end) { return DISCARD; } - + __builtin_memset(&l4_info, 0, sizeof(l4_info)); __builtin_memcpy(id->src_ip, ip->saddr.in6_u.u6_addr8, 16); __builtin_memcpy(id->dst_ip, ip->daddr.in6_u.u6_addr8, 16); id->transport_protocol = ip->nexthdr; - id->src_port = 0; - id->dst_port = 0; - switch (ip->nexthdr) { - case IPPROTO_TCP: { - struct tcphdr *tcp = (void *)ip + sizeof(*ip); - if ((void *)tcp + sizeof(*tcp) <= data_end) { - id->src_port = __bpf_ntohs(tcp->source); - id->dst_port = __bpf_ntohs(tcp->dest); - set_flags(tcp, flags); - } - } break; - case IPPROTO_UDP: { - struct udphdr *udp = (void *)ip + sizeof(*ip); - if ((void *)udp + sizeof(*udp) <= data_end) { - id->src_port = __bpf_ntohs(udp->source); - id->dst_port = __bpf_ntohs(udp->dest); - } - } break; - default: - break; - } + fill_l4info(l4_hdr_start, data_end, ip->nexthdr, &l4_info); + id->src_port = l4_info.src_port; + id->dst_port = l4_info.dst_port; + id->icmp_type = l4_info.icmp_type; + id->icmp_code = l4_info.icmp_code; + *flags = l4_info.flags; + return SUBMIT; } // sets flow fields from Ethernet header information @@ -207,6 +255,7 @@ static inline int flow_monitor(struct __sk_buff *skb, u8 direction) { void *data = (void *)(long)skb->data; flow_id id; + __builtin_memset(&id, 0, sizeof(id)); u64 current_time = bpf_ktime_get_ns(); struct ethhdr *eth = data; u16 flags = 0; diff --git a/examples/flowlogs-dump/server/flowlogs-dump-collector.go b/examples/flowlogs-dump/server/flowlogs-dump-collector.go index 3d2c8ab9..2728e0b3 100644 --- a/examples/flowlogs-dump/server/flowlogs-dump-collector.go +++ b/examples/flowlogs-dump/server/flowlogs-dump-collector.go @@ -72,7 +72,7 @@ func main() { for records := range receivedRecords { for _, record := range records.Entries { if record.EthProtocol == ipv6 { - log.Printf("%s: %v %s IP %s:%d > %s:%d: protocol:%s dir:%d bytes:%d packets:%d flags:%d ends: %v\n", + log.Printf("%s: %v %s IP %s:%d > %s:%d: protocol:%s type: %d code: %d dir:%d bytes:%d packets:%d flags:%d ends: %v\n", ipProto[record.EthProtocol], record.TimeFlowStart.AsTime().Local().Format("15:04:05.000000"), record.Interface, @@ -81,6 +81,8 @@ func main() { net.IP(record.Network.GetDstAddr().GetIpv6()).To16(), record.Transport.DstPort, protocolByNumber[record.Transport.Protocol], + record.Icmp.IcmpType, + record.Icmp.IcmpCode, record.Direction, record.Bytes, record.Packets, @@ -88,7 +90,7 @@ func main() { record.TimeFlowEnd.AsTime().Local().Format("15:04:05.000000"), ) } else { - log.Printf("%s: %v %s IP %s:%d > %s:%d: protocol:%s dir:%d bytes:%d packets:%d flags:%d ends: %v\n", + log.Printf("%s: %v %s IP %s:%d > %s:%d: protocol:%s type: %d code: %d dir:%d bytes:%d packets:%d flags:%d ends: %v\n", ipProto[record.EthProtocol], record.TimeFlowStart.AsTime().Local().Format("15:04:05.000000"), record.Interface, @@ -97,6 +99,8 @@ func main() { ipIntToNetIP(record.Network.GetDstAddr().GetIpv4()).String(), record.Transport.DstPort, protocolByNumber[record.Transport.Protocol], + record.Icmp.IcmpType, + record.Icmp.IcmpCode, record.Direction, record.Bytes, record.Packets, diff --git a/pkg/ebpf/bpf_bpfeb.go b/pkg/ebpf/bpf_bpfeb.go index c228fd42..4eb412d7 100644 --- a/pkg/ebpf/bpf_bpfeb.go +++ b/pkg/ebpf/bpf_bpfeb.go @@ -25,6 +25,8 @@ type BpfFlowIdT struct { SrcPort uint16 DstPort uint16 TransportProtocol uint8 + IcmpType uint8 + IcmpCode uint8 IfIndex uint32 } diff --git a/pkg/ebpf/bpf_bpfeb.o b/pkg/ebpf/bpf_bpfeb.o index a758051fbf61c1587128bf00c17fba33dfdc0aac..047164e040edc9b3b37d4a583f3a9867b1da021b 100644 GIT binary patch literal 22872 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 delta 8764 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 E01rB2KmY&$ diff --git a/pkg/ebpf/bpf_bpfel.go b/pkg/ebpf/bpf_bpfel.go index 6ada0f67..4de7b8d2 100644 --- a/pkg/ebpf/bpf_bpfel.go +++ b/pkg/ebpf/bpf_bpfel.go @@ -25,6 +25,8 @@ type BpfFlowIdT struct { SrcPort uint16 DstPort uint16 TransportProtocol uint8 + IcmpType uint8 + IcmpCode uint8 IfIndex uint32 } diff --git a/pkg/ebpf/bpf_bpfel.o b/pkg/ebpf/bpf_bpfel.o index 13db62889bf77cb980cc4979750485a58c059877..b33fe54eccf9a06693134fa5d8915af4b92e6a24 100644 GIT binary patch literal 22040 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 literal 21704 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 HSg-;BJRxVw diff --git a/pkg/ebpf/tracer.go b/pkg/ebpf/tracer.go index e93fec38..32b2641b 100644 --- a/pkg/ebpf/tracer.go +++ b/pkg/ebpf/tracer.go @@ -6,6 +6,7 @@ import ( "io/fs" "strings" + "github.com/cilium/ebpf" "github.com/cilium/ebpf/ringbuf" "github.com/cilium/ebpf/rlimit" "github.com/netobserv/netobserv-ebpf-agent/pkg/ifaces" @@ -72,6 +73,12 @@ func NewFlowFetcher( return nil, fmt.Errorf("rewriting BPF constants definition: %w", err) } if err := spec.LoadAndAssign(&objects, nil); err != nil { + var ve *ebpf.VerifierError + if errors.As(err, &ve) { + // Using %+v will print the whole verifier error, not just the last + // few lines. + log.Infof("Verifier error: %+v", ve) + } return nil, fmt.Errorf("loading and assigning BPF objects: %w", err) } diff --git a/pkg/exporter/ipfix.go b/pkg/exporter/ipfix.go index 8b88ab20..67f18adc 100644 --- a/pkg/exporter/ipfix.go +++ b/pkg/exporter/ipfix.go @@ -122,6 +122,14 @@ func SendTemplateRecordv4(log *logrus.Entry, exporter *ipfixExporter.ExportingPr if err != nil { return 0, nil, err } + err = addElementToTemplate(log, "icmpTypeIPv4", nil, &elements) + if err != nil { + return 0, nil, err + } + err = addElementToTemplate(log, "icmpCodeIPv4", nil, &elements) + if err != nil { + return 0, nil, err + } err = AddRecordValuesToTemplate(log, &elements) if err != nil { return 0, nil, err @@ -183,6 +191,14 @@ func SendTemplateRecordv6(log *logrus.Entry, exporter *ipfixExporter.ExportingPr if err != nil { return 0, nil, err } + err = addElementToTemplate(log, "icmpTypeIPv6", nil, &elements) + if err != nil { + return 0, nil, err + } + err = addElementToTemplate(log, "icmpCodeIPv6", nil, &elements) + if err != nil { + return 0, nil, err + } err = AddRecordValuesToTemplate(log, &elements) if err != nil { return 0, nil, err @@ -299,6 +315,10 @@ func setIEValue(record *flow.Record, ieValPtr *entities.InfoElementWithValue) { ieVal.SetUnsigned16Value(record.Id.SrcPort) case "destinationTransportPort": ieVal.SetUnsigned16Value(record.Id.DstPort) + case "icmpTypeIPv4", "icmpTypeIPv6": + ieVal.SetUnsigned8Value(record.Id.IcmpType) + case "icmpCodeIPv4", "icmpCodeIPv6": + ieVal.SetUnsigned8Value(record.Id.IcmpCode) } } func setEntities(record *flow.Record, elements *[]entities.InfoElementWithValue) { diff --git a/pkg/exporter/kafka_proto_test.go b/pkg/exporter/kafka_proto_test.go index 5d7f94a6..884bd73c 100644 --- a/pkg/exporter/kafka_proto_test.go +++ b/pkg/exporter/kafka_proto_test.go @@ -34,6 +34,7 @@ func TestProtoConversion(t *testing.T) { record.Id.DstIp = IPAddrFromNetIP(net.ParseIP("127.3.2.1")) record.Id.SrcPort = 4321 record.Id.DstPort = 1234 + record.Id.IcmpType = 8 record.Id.TransportProtocol = 210 record.TimeFlowStart = time.Now().Add(-5 * time.Second) record.TimeFlowEnd = time.Now() @@ -58,6 +59,7 @@ func TestProtoConversion(t *testing.T) { assert.EqualValues(t, 4321, r.Transport.SrcPort) assert.EqualValues(t, 1234, r.Transport.DstPort) assert.EqualValues(t, 210, r.Transport.Protocol) + assert.EqualValues(t, 8, r.Icmp.IcmpType) assert.Equal(t, record.TimeFlowStart.UnixMilli(), r.TimeFlowStart.AsTime().UnixMilli()) assert.Equal(t, record.TimeFlowEnd.UnixMilli(), r.TimeFlowEnd.AsTime().UnixMilli()) assert.EqualValues(t, 789, r.Bytes) diff --git a/pkg/exporter/proto.go b/pkg/exporter/proto.go index 991863b8..94f9bcea 100644 --- a/pkg/exporter/proto.go +++ b/pkg/exporter/proto.go @@ -54,6 +54,10 @@ func v4FlowToPB(fr *flow.Record) *pbflow.Record { SrcPort: uint32(fr.Id.SrcPort), DstPort: uint32(fr.Id.DstPort), }, + Icmp: &pbflow.Icmp{ + IcmpType: uint32(fr.Id.IcmpType), + IcmpCode: uint32(fr.Id.IcmpCode), + }, Bytes: fr.Metrics.Bytes, TimeFlowStart: ×tamppb.Timestamp{ Seconds: fr.TimeFlowStart.Unix(), @@ -88,6 +92,10 @@ func v6FlowToPB(fr *flow.Record) *pbflow.Record { SrcPort: uint32(fr.Id.SrcPort), DstPort: uint32(fr.Id.DstPort), }, + Icmp: &pbflow.Icmp{ + IcmpType: uint32(fr.Id.IcmpType), + IcmpCode: uint32(fr.Id.IcmpCode), + }, Bytes: fr.Metrics.Bytes, TimeFlowStart: ×tamppb.Timestamp{ Seconds: fr.TimeFlowStart.Unix(), diff --git a/pkg/flow/record_test.go b/pkg/flow/record_test.go index dfbf8bf1..8f1fc59b 100644 --- a/pkg/flow/record_test.go +++ b/pkg/flow/record_test.go @@ -23,6 +23,8 @@ func TestRecordBinaryEncoding(t *testing.T) { 0x0e, 0x0f, // transport: u16 src_port 0x10, 0x11, // transport: u16 dst_port 0x12, // transport: u8 transport_protocol + 0x00, // icmp: u8 icmp_type + 0x00, // icmp: u8 icmp_code 0x13, 0x14, 0x15, 0x16, // interface index 0x06, 0x07, 0x08, 0x09, // u32 packets 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, // u64 bytes @@ -45,6 +47,8 @@ func TestRecordBinaryEncoding(t *testing.T) { SrcPort: 0x0f0e, DstPort: 0x1110, TransportProtocol: 0x12, + IcmpType: 0x00, + IcmpCode: 0x00, IfIndex: 0x16151413, }, Metrics: ebpf.BpfFlowMetrics{ diff --git a/pkg/grpc/grpc_test.go b/pkg/grpc/grpc_test.go index faeb740e..efdd355b 100644 --- a/pkg/grpc/grpc_test.go +++ b/pkg/grpc/grpc_test.go @@ -162,6 +162,10 @@ func BenchmarkIPv4GRPCCommunication(b *testing.B) { SrcPort: 23000, DstPort: 443, }, + Icmp: &pbflow.Icmp{ + IcmpType: 8, + IcmpCode: 10, + }, } records := &pbflow.Records{} for i := 0; i < 100; i++ { @@ -211,6 +215,10 @@ func BenchmarkIPv6GRPCCommunication(b *testing.B) { SrcPort: 23000, DstPort: 443, }, + Icmp: &pbflow.Icmp{ + IcmpType: 8, + IcmpCode: 10, + }, } records := &pbflow.Records{} for i := 0; i < 100; i++ { diff --git a/pkg/pbflow/flow.pb.go b/pkg/pbflow/flow.pb.go index 903e6f68..af4bee08 100644 --- a/pkg/pbflow/flow.pb.go +++ b/pkg/pbflow/flow.pb.go @@ -179,6 +179,7 @@ type Record struct { // Agent IP address to help identifying the source of the flow AgentIp *IP `protobuf:"bytes,12,opt,name=agent_ip,json=agentIp,proto3" json:"agent_ip,omitempty"` Flags uint32 `protobuf:"varint,13,opt,name=flags,proto3" json:"flags,omitempty"` + Icmp *Icmp `protobuf:"bytes,14,opt,name=icmp,proto3" json:"icmp,omitempty"` } func (x *Record) Reset() { @@ -304,6 +305,13 @@ func (x *Record) GetFlags() uint32 { return 0 } +func (x *Record) GetIcmp() *Icmp { + if x != nil { + return x.Icmp + } + return nil +} + type DataLink struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -559,6 +567,61 @@ func (x *Transport) GetProtocol() uint32 { return 0 } +type Icmp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + IcmpType uint32 `protobuf:"varint,1,opt,name=icmp_type,json=icmpType,proto3" json:"icmp_type,omitempty"` + IcmpCode uint32 `protobuf:"varint,2,opt,name=icmp_code,json=icmpCode,proto3" json:"icmp_code,omitempty"` +} + +func (x *Icmp) Reset() { + *x = Icmp{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_flow_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Icmp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Icmp) ProtoMessage() {} + +func (x *Icmp) ProtoReflect() protoreflect.Message { + mi := &file_proto_flow_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Icmp.ProtoReflect.Descriptor instead. +func (*Icmp) Descriptor() ([]byte, []int) { + return file_proto_flow_proto_rawDescGZIP(), []int{7} +} + +func (x *Icmp) GetIcmpType() uint32 { + if x != nil { + return x.IcmpType + } + return 0 +} + +func (x *Icmp) GetIcmpCode() uint32 { + if x != nil { + return x.IcmpCode + } + return 0 +} + var File_proto_flow_proto protoreflect.FileDescriptor var file_proto_flow_proto_rawDesc = []byte{ @@ -570,7 +633,7 @@ var file_proto_flow_proto_rawDesc = []byte{ 0x07, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x28, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, - 0x65, 0x73, 0x22, 0x94, 0x04, 0x0a, 0x06, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x21, 0x0a, + 0x65, 0x73, 0x22, 0xb6, 0x04, 0x0a, 0x06, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x65, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x2f, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, @@ -603,34 +666,40 @@ var file_proto_flow_proto_rawDesc = []byte{ 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x50, 0x52, 0x07, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x0d, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x22, 0x3c, 0x0a, 0x08, 0x44, 0x61, 0x74, - 0x61, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x72, 0x63, 0x5f, 0x6d, 0x61, 0x63, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x73, 0x72, 0x63, 0x4d, 0x61, 0x63, 0x12, 0x17, - 0x0a, 0x07, 0x64, 0x73, 0x74, 0x5f, 0x6d, 0x61, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x06, 0x64, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x22, 0x57, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x12, 0x25, 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x50, - 0x52, 0x07, 0x73, 0x72, 0x63, 0x41, 0x64, 0x64, 0x72, 0x12, 0x25, 0x0a, 0x08, 0x64, 0x73, 0x74, - 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, - 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x50, 0x52, 0x07, 0x64, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, - 0x22, 0x3d, 0x0a, 0x02, 0x49, 0x50, 0x12, 0x14, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x34, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x07, 0x48, 0x00, 0x52, 0x04, 0x69, 0x70, 0x76, 0x34, 0x12, 0x14, 0x0a, 0x04, - 0x69, 0x70, 0x76, 0x36, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x04, 0x69, 0x70, - 0x76, 0x36, 0x42, 0x0b, 0x0a, 0x09, 0x69, 0x70, 0x5f, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x22, - 0x5d, 0x0a, 0x09, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x19, 0x0a, 0x08, - 0x73, 0x72, 0x63, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, - 0x73, 0x72, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x70, - 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x64, 0x73, 0x74, 0x50, 0x6f, - 0x72, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2a, 0x24, - 0x0a, 0x09, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x0a, 0x07, 0x49, - 0x4e, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x45, 0x47, 0x52, 0x45, - 0x53, 0x53, 0x10, 0x01, 0x32, 0x3e, 0x0a, 0x09, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x12, 0x31, 0x0a, 0x04, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x0f, 0x2e, 0x70, 0x62, 0x66, 0x6c, - 0x6f, 0x77, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x1a, 0x16, 0x2e, 0x70, 0x62, 0x66, - 0x6c, 0x6f, 0x77, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x22, 0x00, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2f, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x28, 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x20, 0x0a, 0x04, 0x69, 0x63, 0x6d, + 0x70, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, + 0x2e, 0x49, 0x63, 0x6d, 0x70, 0x52, 0x04, 0x69, 0x63, 0x6d, 0x70, 0x22, 0x3c, 0x0a, 0x08, 0x44, + 0x61, 0x74, 0x61, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x72, 0x63, 0x5f, 0x6d, + 0x61, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x73, 0x72, 0x63, 0x4d, 0x61, 0x63, + 0x12, 0x17, 0x0a, 0x07, 0x64, 0x73, 0x74, 0x5f, 0x6d, 0x61, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x06, 0x64, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x22, 0x57, 0x0a, 0x07, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x25, 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, + 0x49, 0x50, 0x52, 0x07, 0x73, 0x72, 0x63, 0x41, 0x64, 0x64, 0x72, 0x12, 0x25, 0x0a, 0x08, 0x64, + 0x73, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, + 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x50, 0x52, 0x07, 0x64, 0x73, 0x74, 0x41, 0x64, + 0x64, 0x72, 0x22, 0x3d, 0x0a, 0x02, 0x49, 0x50, 0x12, 0x14, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x34, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x07, 0x48, 0x00, 0x52, 0x04, 0x69, 0x70, 0x76, 0x34, 0x12, 0x14, + 0x0a, 0x04, 0x69, 0x70, 0x76, 0x36, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x04, + 0x69, 0x70, 0x76, 0x36, 0x42, 0x0b, 0x0a, 0x09, 0x69, 0x70, 0x5f, 0x66, 0x61, 0x6d, 0x69, 0x6c, + 0x79, 0x22, 0x5d, 0x0a, 0x09, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x19, + 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x07, 0x73, 0x72, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x73, 0x74, + 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x64, 0x73, 0x74, + 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x22, 0x40, 0x0a, 0x04, 0x49, 0x63, 0x6d, 0x70, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x63, 0x6d, 0x70, + 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x69, 0x63, 0x6d, + 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x63, 0x6d, 0x70, 0x5f, 0x63, 0x6f, + 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x69, 0x63, 0x6d, 0x70, 0x43, 0x6f, + 0x64, 0x65, 0x2a, 0x24, 0x0a, 0x09, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, + 0x45, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x01, 0x32, 0x3e, 0x0a, 0x09, 0x43, 0x6f, 0x6c, 0x6c, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x31, 0x0a, 0x04, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x0f, 0x2e, + 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x1a, 0x16, + 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2f, 0x70, 0x62, + 0x66, 0x6c, 0x6f, 0x77, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -646,7 +715,7 @@ func file_proto_flow_proto_rawDescGZIP() []byte { } var file_proto_flow_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_proto_flow_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_proto_flow_proto_msgTypes = make([]protoimpl.MessageInfo, 8) var file_proto_flow_proto_goTypes = []interface{}{ (Direction)(0), // 0: pbflow.Direction (*CollectorReply)(nil), // 1: pbflow.CollectorReply @@ -656,26 +725,28 @@ var file_proto_flow_proto_goTypes = []interface{}{ (*Network)(nil), // 5: pbflow.Network (*IP)(nil), // 6: pbflow.IP (*Transport)(nil), // 7: pbflow.Transport - (*timestamppb.Timestamp)(nil), // 8: google.protobuf.Timestamp + (*Icmp)(nil), // 8: pbflow.Icmp + (*timestamppb.Timestamp)(nil), // 9: google.protobuf.Timestamp } var file_proto_flow_proto_depIdxs = []int32{ 3, // 0: pbflow.Records.entries:type_name -> pbflow.Record 0, // 1: pbflow.Record.direction:type_name -> pbflow.Direction - 8, // 2: pbflow.Record.time_flow_start:type_name -> google.protobuf.Timestamp - 8, // 3: pbflow.Record.time_flow_end:type_name -> google.protobuf.Timestamp + 9, // 2: pbflow.Record.time_flow_start:type_name -> google.protobuf.Timestamp + 9, // 3: pbflow.Record.time_flow_end:type_name -> google.protobuf.Timestamp 4, // 4: pbflow.Record.data_link:type_name -> pbflow.DataLink 5, // 5: pbflow.Record.network:type_name -> pbflow.Network 7, // 6: pbflow.Record.transport:type_name -> pbflow.Transport 6, // 7: pbflow.Record.agent_ip:type_name -> pbflow.IP - 6, // 8: pbflow.Network.src_addr:type_name -> pbflow.IP - 6, // 9: pbflow.Network.dst_addr:type_name -> pbflow.IP - 2, // 10: pbflow.Collector.Send:input_type -> pbflow.Records - 1, // 11: pbflow.Collector.Send:output_type -> pbflow.CollectorReply - 11, // [11:12] is the sub-list for method output_type - 10, // [10:11] is the sub-list for method input_type - 10, // [10:10] is the sub-list for extension type_name - 10, // [10:10] is the sub-list for extension extendee - 0, // [0:10] is the sub-list for field type_name + 8, // 8: pbflow.Record.icmp:type_name -> pbflow.Icmp + 6, // 9: pbflow.Network.src_addr:type_name -> pbflow.IP + 6, // 10: pbflow.Network.dst_addr:type_name -> pbflow.IP + 2, // 11: pbflow.Collector.Send:input_type -> pbflow.Records + 1, // 12: pbflow.Collector.Send:output_type -> pbflow.CollectorReply + 12, // [12:13] is the sub-list for method output_type + 11, // [11:12] is the sub-list for method input_type + 11, // [11:11] is the sub-list for extension type_name + 11, // [11:11] is the sub-list for extension extendee + 0, // [0:11] is the sub-list for field type_name } func init() { file_proto_flow_proto_init() } @@ -768,6 +839,18 @@ func file_proto_flow_proto_init() { return nil } } + file_proto_flow_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Icmp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_proto_flow_proto_msgTypes[5].OneofWrappers = []interface{}{ (*IP_Ipv4)(nil), @@ -779,7 +862,7 @@ func file_proto_flow_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_flow_proto_rawDesc, NumEnums: 1, - NumMessages: 7, + NumMessages: 8, NumExtensions: 0, NumServices: 1, }, diff --git a/proto/flow.proto b/proto/flow.proto index 9e291f72..c7b459a1 100644 --- a/proto/flow.proto +++ b/proto/flow.proto @@ -41,6 +41,7 @@ message Record { // Agent IP address to help identifying the source of the flow IP agent_ip = 12; uint32 flags = 13; + Icmp icmp = 14; } message DataLink { @@ -68,6 +69,11 @@ message Transport { uint32 protocol = 3; } +message Icmp { + uint32 icmp_type = 1; + uint32 icmp_code = 2; +} + // as defined by field 61 in // https://www.iana.org/assignments/ipfix/ipfix.xhtml enum Direction { -- GitLab