pcap-cli/internal/transformer/proto_translator.go (247 lines of code) (raw):

// Copyright 2024 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build proto package transformer import ( "context" "encoding/binary" "fmt" "io" "github.com/GoogleCloudPlatform/pcap-sidecar/pcap-cli/internal/pb" "github.com/google/gopacket" "github.com/google/gopacket/layers" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" ) type ( ProtoPcapTranslator struct { *pcapTranslator } ) func init() { registerTranslatorFactory(PROTO, newPROTOPcapTranslator) } func (t *ProtoPcapTranslator) done(_ context.Context) { // not implemented } func (t *ProtoPcapTranslator) next( ctx context.Context, nic *PcapIface, serial *uint64, packet *gopacket.Packet, ) fmt.Stringer { // `next` returns the container to be used for merging all layers p := &pb.Packet{} metadata := (*packet).Metadata() info := metadata.CaptureInfo p.Timestamp = timestamppb.New(info.Timestamp) pcap := p.GetPcap() pcap.Context = ctx.Value(ContextID).(string) pcap.Serial = *serial meta := p.GetMeta() meta.Truncated = metadata.Truncated meta.Length = uint64(info.Length) meta.CaptureLength = uint64(info.CaptureLength) iface := p.GetIface() iface.Index = uint32(t.iface.Index) iface.Name = t.iface.Name return p } func (t *ProtoPcapTranslator) asTranslation( buffer fmt.Stringer, ) *pb.Packet { return buffer.(*pb.Packet) } func (t *ProtoPcapTranslator) translateErrorLayer( ctx context.Context, err *gopacket.DecodeFailure, ) fmt.Stringer { // [TODO]: implement ERROR layer translation p := &pb.Packet{} return p } func (t *ProtoPcapTranslator) translateLayerError( ctx context.Context, lType gopacket.LayerType, err error, ) fmt.Stringer { // [TODO]: implement layer ERROR translation p := &pb.Packet{} return p } func (t *ProtoPcapTranslator) translateError( ctx context.Context, err error, ) fmt.Stringer { // [TODO]: implement ERROR translation p := &pb.Packet{} return p } func (t *ProtoPcapTranslator) translateEthernetLayer( ctx context.Context, eth *layers.Ethernet, ) fmt.Stringer { p := &pb.Packet{} L2 := p.GetL2() L2.Source = eth.SrcMAC.String() L2.Target = eth.DstMAC.String() return p } func (t *ProtoPcapTranslator) translateARPLayer( ctx context.Context, arp *layers.ARP, ) fmt.Stringer { // [TODO]: implement ARP layer translation p := &pb.Packet{} return p } func (t *ProtoPcapTranslator) translateICMPv4Layer( ctx context.Context, icmp4 *layers.ICMPv4, ) fmt.Stringer { // [TODO]: implement ICMPv4 layer translation p := &pb.Packet{} return p } func (t *ProtoPcapTranslator) translateICMPv6Layer( ctx context.Context, icmp6 *layers.ICMPv6, ) fmt.Stringer { // [TODO]: implement ICMPv6 layer translation p := &pb.Packet{} return p } func (t *ProtoPcapTranslator) translateICMPv6EchoLayer( ctx context.Context, prto fmt.Stringer, icmp6 *layers.ICMPv6Echo, ) fmt.Stringer { // see: https://github.com/google/gopacket/blob/master/layers/icmp6msg.go#L57-L62 // [TODO]: implement ICMPv6 ECHO layer translation p := &pb.Packet{} return p } func (t *ProtoPcapTranslator) translateICMPv6RedirectLayer( ctx context.Context, json fmt.Stringer, icmp6 *layers.ICMPv6Redirect, ) fmt.Stringer { // see: https://github.com/google/gopacket/blob/master/layers/icmp6msg.go#L97-L104 // [TODO]: implement ICMPv6 REDIRECT layer translation p := &pb.Packet{} return p } func (t *ProtoPcapTranslator) translateICMPv6L3HeaderLayer( ctx context.Context, json fmt.Stringer, icmp6 *layers.ICMPv6, ) fmt.Stringer { // [TODO]: implement ICMPv6 HEADER layer translation p := &pb.Packet{} return p } func (t *ProtoPcapTranslator) translateIPv4Layer( ctx context.Context, ip4 *layers.IPv4, ) fmt.Stringer { // [TODO]: implement IPv4 layer translation p := &pb.Packet{} L3 := p.GetIp4() L3.Source = ip4.SrcIP L3.Target = ip4.DstIP return p } func (t *ProtoPcapTranslator) translateIPv6Layer( ctx context.Context, ip6 *layers.IPv6, ) fmt.Stringer { // [TODO]: implement IPv6 layer translation p := &pb.Packet{} L3 := p.GetIp6() L3.Source = ip6.SrcIP L3.Target = ip6.DstIP return p } func (t *ProtoPcapTranslator) translateUDPLayer( ctx context.Context, udp *layers.UDP, ) fmt.Stringer { // [TODO]: implement UDP layer translation p := &pb.Packet{} L4 := p.GetUdp() L4.Source = uint32(udp.SrcPort) L4.Target = uint32(udp.DstPort) return p } func (t *ProtoPcapTranslator) translateTCPLayer( ctx context.Context, tcp *layers.TCP, ) fmt.Stringer { // [TODO]: implement TCP layer translation p := &pb.Packet{} L4 := p.GetTcp() L4.Source = uint32(tcp.SrcPort) L4.Target = uint32(tcp.DstPort) L4.Seq = tcp.Seq L4.Ack = tcp.Ack flags := L4.GetFlags() flags.Flags = uint32(parseTCPflags(tcp)) flags.Syn = tcp.SYN flags.Ack = tcp.ACK flags.Psh = tcp.PSH flags.Fin = tcp.FIN flags.Rst = tcp.RST flags.Urg = tcp.RST flags.Ece = tcp.ECE flags.Cwr = tcp.CWR return p } func (t *ProtoPcapTranslator) translateTLSLayer( ctx context.Context, tls *layers.TLS, ) fmt.Stringer { // [TODO]: implement TLS layer translation p := &pb.Packet{} return p } func (t *ProtoPcapTranslator) translateDNSLayer( ctx context.Context, dns *layers.DNS, ) fmt.Stringer { // [TODO]: implement DNS layer translation p := &pb.Packet{} return p } func (t *ProtoPcapTranslator) merge( ctx context.Context, tgt fmt.Stringer, src fmt.Stringer, ) (fmt.Stringer, error) { proto.Merge( t.asTranslation(tgt), t.asTranslation(src), ) return tgt, nil } func (t *ProtoPcapTranslator) finalize( ctx context.Context, ifaces netIfaceIndex, iface *PcapIface, serial *uint64, p *gopacket.Packet, conntrack bool, packet fmt.Stringer, ) (fmt.Stringer, error) { return packet, nil } func (t *ProtoPcapTranslator) write( ctx context.Context, writer io.Writer, packet *fmt.Stringer, ) (int, error) { translation := t.asTranslation(*packet) protoBytes, err := proto.Marshal(translation) if err != nil { return 0, err } protoBytesLen := len(protoBytes) // https://protobuf.dev/programming-guides/techniques/#streaming buf := make([]byte, 4) binary.LittleEndian.PutUint32(buf, uint32(protoBytesLen)) if _, err := writer.Write(buf); err != nil { return protoBytesLen + 4, err } if _, err := writer.Write(protoBytes); err != nil { return protoBytesLen, err } return protoBytesLen, nil } func newPROTOPcapTranslator( ctx context.Context, debug bool, verbosity PcapVerbosity, iface *PcapIface, ephemerals *PcapEphemeralPorts, ) PcapTranslator { translator := newPcapTranslator(ctx, debug, verbosity, iface, ephemerals) return &ProtoPcapTranslator{ pcapTranslator: translator, } }