Skip to content

Commit

Permalink
Add rudimentary PCAP and binary TPM taps
Browse files Browse the repository at this point in the history
  • Loading branch information
hslatman committed Jun 4, 2024
1 parent 502a8aa commit f6f961f
Show file tree
Hide file tree
Showing 8 changed files with 262 additions and 23 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ require (
github.com/google/go-tpm v0.9.0
github.com/google/go-tpm-tools v0.4.4
github.com/googleapis/gax-go/v2 v2.12.4
github.com/gopacket/gopacket v1.2.0
github.com/peterbourgon/diskv/v3 v3.0.1
github.com/pkg/errors v0.9.1
github.com/schollz/jsonstore v1.1.0
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,8 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.12.4 h1:9gWcmF85Wvq4ryPFvGFaOgPIs1AQX0d0bcbGw4Z96qg=
github.com/googleapis/gax-go/v2 v2.12.4/go.mod h1:KYEYLorsnIGDi/rPC8b5TdlB9kbKoFubselGIoBMCwI=
github.com/gopacket/gopacket v1.2.0 h1:eXbzFad7f73P1n2EJHQlsKuvIMJjVXK5tXoSca78I3A=
github.com/gopacket/gopacket v1.2.0/go.mod h1:BrAKEy5EOGQ76LSqh7DMAr7z0NNPdczWm2GxCG7+I8M=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
github.com/goreleaser/goreleaser v0.134.0/go.mod h1:ZT6Y2rSYa6NxQzIsdfWWNWAlYGXGbreo66NmE+3X3WQ=
Expand Down Expand Up @@ -798,6 +800,8 @@ github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oW
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug=
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
Expand Down
30 changes: 30 additions & 0 deletions tpm/debug/bin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package debug

import (
"io"
"sync"
)

type binTap struct {
sync.Mutex
w io.Writer
}

func (t *binTap) Rx() io.Writer {

Check failure on line 13 in tpm/debug/bin.go

View workflow job for this annotation

GitHub Actions / ci / lint / lint

ST1016: methods on the same type should have the same receiver name (seen 1x "w", 2x "t") (stylecheck)
return t.w
}

func (t *binTap) Tx() io.Writer {
return t.w
}

func NewBinTap(w io.Writer) Tap {
return &binTap{w: w}
}

func (w *binTap) Write(data []byte) (int, error) {

Check failure on line 25 in tpm/debug/bin.go

View workflow job for this annotation

GitHub Actions / ci / lint / lint

receiver-naming: receiver name w should be consistent with previous receiver name t for binTap (revive)
w.Lock()
defer w.Unlock()

return w.w.Write(data)
}
146 changes: 146 additions & 0 deletions tpm/debug/pcap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package debug

import (
"fmt"
"io"
"net"
"sync"
"time"

"github.com/gopacket/gopacket"
"github.com/gopacket/gopacket/layers"
"github.com/gopacket/gopacket/pcapgo"
)

type pcapTap struct {
in *pcapWriter
out *pcapWriter
}

func (t *pcapTap) Rx() io.Writer {
return t.in
}

func (t *pcapTap) Tx() io.Writer {
return t.out
}

func NewPcapTap(w io.Writer) (Tap, error) {
pw := pcapgo.NewWriter(w)
return &pcapTap{
in: &pcapWriter{
in: true,
writer: pw,
},
out: &pcapWriter{
writer: pw,
},
}, nil
}

type pcapWriter struct {
in bool
writer *pcapgo.Writer
}

var (
outSeq uint32
inSeq uint32
mu sync.Mutex
)

func (w *pcapWriter) Write(data []byte) (int, error) {
mu.Lock()
defer mu.Unlock()

err := write(w.writer, data, w.in, inSeq, outSeq)

if w.in {
inSeq += uint32(len(data))
} else {
outSeq += uint32(len(data))
}

return len(data), err
}

var ethernetLayer = &layers.Ethernet{
SrcMAC: net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
DstMAC: net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
EthernetType: layers.EthernetTypeIPv4,
}

var ipLayer = &layers.IPv4{
Version: 4,
TTL: 64,
Flags: layers.IPv4DontFragment,
Protocol: layers.IPProtocolTCP,
SrcIP: net.IP{127, 0, 0, 1},
DstIP: net.IP{127, 0, 0, 1},
}

var serializeOptions = gopacket.SerializeOptions{
FixLengths: true,
ComputeChecksums: true,
}

var decodeOptions = gopacket.DecodeOptions{
Lazy: true,
NoCopy: true,
}

const snapLen = uint32(65536)

var once sync.Once
var headerWriteError error

Check failure on line 95 in tpm/debug/pcap.go

View workflow job for this annotation

GitHub Actions / ci / lint / lint

the variable name `headerWriteError` should conform to the `errXxx` format (errname)

func write(w *pcapgo.Writer, data []byte, in bool, inSeq uint32, outSeq uint32) error {

Check failure on line 97 in tpm/debug/pcap.go

View workflow job for this annotation

GitHub Actions / ci / lint / lint

paramTypeCombine: func(w *pcapgo.Writer, data []byte, in bool, inSeq uint32, outSeq uint32) error could be replaced with func(w *pcapgo.Writer, data []byte, in bool, inSeq, outSeq uint32) error (gocritic)
var tcpLayer = &layers.TCP{Window: 16}
if in {
tcpLayer.SrcPort = layers.TCPPort(2321)
tcpLayer.DstPort = layers.TCPPort(50001)
tcpLayer.ACK = true
tcpLayer.Seq = inSeq
tcpLayer.Ack = outSeq
tcpLayer.PSH = true
} else {
tcpLayer.SrcPort = layers.TCPPort(50001)
tcpLayer.DstPort = layers.TCPPort(2321)
tcpLayer.ACK = false
tcpLayer.Seq = outSeq
}

tcpLayer.SetNetworkLayerForChecksum(ipLayer)
buffer := gopacket.NewSerializeBuffer()
if err := gopacket.SerializeLayers(buffer, serializeOptions,
ethernetLayer,
ipLayer,
tcpLayer,
gopacket.Payload(data),
); err != nil {
return fmt.Errorf("failed serializing layers: %w", err)
}

p := gopacket.NewPacket(buffer.Bytes(), layers.LayerTypeEthernet, decodeOptions)

once.Do(func() {
// TODO: do once on the very first write to the output; if it's a file, check there's no pcap header yet
if err := w.WriteFileHeader(snapLen, layers.LinkTypeEthernet); err != nil {
headerWriteError = err
}
})
if headerWriteError != nil {
return fmt.Errorf("failed writing pcap header: %w", headerWriteError)
}

ci := p.Metadata().CaptureInfo
ci.CaptureLength = len(p.Data())
ci.Length = ci.CaptureLength
ci.Timestamp = time.Now()

if err := w.WritePacket(ci, p.Data()); err != nil {
return fmt.Errorf("failed writing packet data: %w", err)
}

return nil
}
55 changes: 55 additions & 0 deletions tpm/debug/pcap_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package debug

import (
"bytes"
"encoding/hex"
"testing"

"github.com/gopacket/gopacket"
"github.com/gopacket/gopacket/pcapgo"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func Test_PcapTapWrites(t *testing.T) {
var buf bytes.Buffer
tr, err := NewPcapTap(&buf)
require.NoError(t, err)

b, err := hex.DecodeString("8001000000160000017a000000060000010600000001")
require.NoError(t, err)
n, err := tr.Tx().Write(b)
require.NoError(t, err)

assert.Equal(t, 22, n)

b, err = hex.DecodeString("80010000001b000000000100000006000000010000010678434720")
require.NoError(t, err)
n, err = tr.Rx().Write(b)
require.NoError(t, err)
assert.Equal(t, 27, n)

b, err = hex.DecodeString("8001000000160000017a000000060000010700000001")
require.NoError(t, err)
n, err = tr.Tx().Write(b)
require.NoError(t, err)
assert.Equal(t, 22, n)

b, err = hex.DecodeString("80010000001b00000000010000000600000001000001076654504d")
require.NoError(t, err)
n, err = tr.Rx().Write(b)
require.NoError(t, err)
assert.Equal(t, 27, n)

r, err := pcapgo.NewReader(&buf)
require.NoError(t, err)

count := 0
packetSource := gopacket.NewPacketSource(r, r.LinkType())
for packet := range packetSource.Packets() {
t.Log(packet.Dump())
count += 1
}

require.Equal(t, 4, count) // 4 packets expected
}
21 changes: 0 additions & 21 deletions tpm/debug/tap.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package debug

import (
"fmt"
"io"
)

Expand Down Expand Up @@ -29,23 +28,3 @@ func NewTap(rx io.Writer, tx io.Writer) Tap {
out: tx,
}
}

func NewTextTap(reads io.Writer, writes io.Writer) Tap {
return &tap{
in: &wrapper{reads, true},
out: &wrapper{writes, false},
}
}

type wrapper struct {
w io.Writer
in bool
}

func (w *wrapper) Write(data []byte) (int, error) {
if w.in {
return w.w.Write([]byte(fmt.Sprintf("<- %x\n", data)))
} else {
return w.w.Write([]byte(fmt.Sprintf("-> %x\n", data)))
}
}
26 changes: 26 additions & 0 deletions tpm/debug/text.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package debug

import (
"fmt"
"io"
)

func NewTextTap(reads io.Writer, writes io.Writer) Tap {

Check failure on line 8 in tpm/debug/text.go

View workflow job for this annotation

GitHub Actions / ci / lint / lint

paramTypeCombine: func(reads io.Writer, writes io.Writer) Tap could be replaced with func(reads, writes io.Writer) Tap (gocritic)
return &tap{
in: &wrapper{reads, true},
out: &wrapper{writes, false},
}
}

type wrapper struct {
w io.Writer
in bool
}

func (w *wrapper) Write(data []byte) (int, error) {
if w.in {
return w.w.Write([]byte(fmt.Sprintf("<- %x\n", data)))

Check failure on line 22 in tpm/debug/text.go

View workflow job for this annotation

GitHub Actions / ci / lint / lint

preferFprint: fmt.Fprintf(w.w, "<- %x\n", data) should be preferred to the w.w.Write([]byte(fmt.Sprintf("<- %x\n", data))) (gocritic)
} else {

Check failure on line 23 in tpm/debug/text.go

View workflow job for this annotation

GitHub Actions / ci / lint / lint

indent-error-flow: if block ends with a return statement, so drop this else and outdent its block (revive)
return w.w.Write([]byte(fmt.Sprintf("-> %x\n", data)))

Check failure on line 24 in tpm/debug/text.go

View workflow job for this annotation

GitHub Actions / ci / lint / lint

preferFprint: fmt.Fprintf(w.w, "-> %x\n", data) should be preferred to the w.w.Write([]byte(fmt.Sprintf("-> %x\n", data))) (gocritic)
}
}
2 changes: 0 additions & 2 deletions tpm/tpm.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,6 @@ func New(opts ...NewTPMOption) (*TPM, error) {
return nil, fmt.Errorf("invalid TPM options provided: %w", err)
}

tpmOptions.tap = debug.NewTextTap(os.Stderr, os.Stderr)

return &TPM{
deviceName: tpmOptions.deviceName,
attestConfig: tpmOptions.attestConfig,
Expand Down

0 comments on commit f6f961f

Please sign in to comment.