Skip to content

Commit 11730b8

Browse files
committed
feat: real time packet trace
1 parent 37bd6a7 commit 11730b8

8 files changed

Lines changed: 114 additions & 10 deletions

File tree

cmd/inspect.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,28 @@ var inspectCmd = &cobra.Command{
1616
fmt.Println("Usage: nylon inspect <interface>")
1717
return
1818
}
19-
itf := args[0]
20-
result, err := core.IPCGet(itf)
21-
if err != nil {
22-
fmt.Println("Error:", err.Error())
23-
return
19+
if ok, _ := cmd.Flags().GetBool("trace"); ok {
20+
itf := args[0]
21+
err := core.IPCTrace(itf)
22+
if err != nil {
23+
fmt.Println("Error:", err.Error())
24+
return
25+
}
26+
} else {
27+
itf := args[0]
28+
result, err := core.IPCGet(itf)
29+
if err != nil {
30+
fmt.Println("Error:", err.Error())
31+
return
32+
}
33+
fmt.Print(result)
2434
}
25-
fmt.Print(result)
2635
},
2736
GroupID: "ny",
2837
}
2938

3039
func init() {
3140
rootCmd.AddCommand(inspectCmd)
41+
42+
inspectCmd.Flags().BoolP("trace", "t", false, "Enables live packet routing capture")
3243
}

core/entrypoint.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ func Start(ccfg state.CentralCfg, ncfg state.LocalCfg, logLevel slog.Level, conf
234234

235235
func initModules(s *state.State) error {
236236
var modules []state.NyModule
237+
modules = append(modules, &NylonTrace{})
237238
modules = append(modules, &NylonRouter{})
238239
modules = append(modules, &Nylon{})
239240

core/ipc.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package core
22

33
import (
44
"bufio"
5+
"context"
56
"fmt"
67
"io"
78
"slices"
@@ -41,6 +42,37 @@ func IPCGet(itf string) (string, error) {
4142
return strings.TrimSuffix(res, "\x00"), nil
4243
}
4344

45+
func IPCTrace(itf string) error {
46+
conn, err := ipc.UAPIDial(itf)
47+
if err != nil {
48+
return err
49+
}
50+
defer conn.Close()
51+
rw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
52+
53+
_, err = rw.WriteString("get=nylon\n")
54+
if err != nil {
55+
return err
56+
}
57+
58+
_, err = rw.WriteString("trace\n")
59+
if err != nil {
60+
return err
61+
}
62+
err = rw.Flush()
63+
if err != nil {
64+
return err
65+
}
66+
67+
for {
68+
str, err := rw.ReadString('\n')
69+
if err != nil {
70+
return err
71+
}
72+
fmt.Print(str)
73+
}
74+
}
75+
4476
func HandleNylonIPCGet(s *state.State, rw *bufio.ReadWriter) error {
4577
cmd, err := rw.ReadString('\n')
4678
if err != nil {
@@ -139,6 +171,36 @@ func HandleNylonIPCGet(s *state.State, rw *bufio.ReadWriter) error {
139171
return err
140172
}
141173
return rw.Flush()
174+
case "trace\n":
175+
if !state.DBG_trace_tc {
176+
return fmt.Errorf("trace mode is not enabled")
177+
}
178+
ctx, cancel := context.WithCancel(context.Background())
179+
t := Get[*NylonTrace](s)
180+
go func() {
181+
_, _ = rw.ReadByte() // wait for EOF
182+
cancel()
183+
}()
184+
ch := make(chan interface{})
185+
t.Register(ch)
186+
defer t.Unregister(ch)
187+
for {
188+
select {
189+
case <-ctx.Done():
190+
return nil
191+
case msg := <-ch:
192+
if str, ok := msg.(string); ok {
193+
_, err := rw.WriteString(str)
194+
if err != nil {
195+
return err
196+
}
197+
err = rw.Flush()
198+
if err != nil {
199+
return err
200+
}
201+
}
202+
}
203+
}
142204
default:
143205
return fmt.Errorf("unknown command %s", cmd)
144206
}

core/nylon_tc.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package core
22

33
import (
4+
"fmt"
45
"net/netip"
56

67
"github.com/encodeous/nylon/polyamide/conn"
@@ -18,6 +19,7 @@ const (
1819

1920
func (n *Nylon) InstallTC(s *state.State) {
2021
r := Get[*NylonRouter](s)
22+
t := Get[*NylonTrace](s)
2123

2224
if state.DBG_trace_tc {
2325
n.Device.InstallFilter(func(dev *device.Device, packet *device.TCElement) (device.TCAction, error) {
@@ -33,7 +35,7 @@ func (n *Nylon) InstallTC(s *state.State) {
3335
peer != nil &&
3436
src != netip.IPv4Unspecified() && src != netip.IPv6Unspecified() &&
3537
dst != netip.IPv4Unspecified() && dst != netip.IPv6Unspecified() {
36-
dev.Log.Verbosef("Unhandled TC packet: %v -> %v, peer %s", packet.GetSrc(), packet.GetDst(), peer)
38+
t.Submit(fmt.Sprintf("Unhandled TC packet: %v -> %v, peer %s\n", packet.GetSrc(), packet.GetDst(), peer))
3739
}
3840
}
3941
return device.TcPass, nil
@@ -56,7 +58,7 @@ func (n *Nylon) InstallTC(s *state.State) {
5658
if ok && !packet.Incoming() {
5759
packet.ToPeer = entry.Peer
5860
if state.DBG_trace_tc {
59-
dev.Log.Verbosef("Fwd packet: %v -> %v, via %s", packet.GetSrc(), packet.GetDst(), entry.Nh)
61+
t.Submit(fmt.Sprintf("Fwd packet: %v -> %v, via %s\n", packet.GetSrc(), packet.GetDst(), entry.Nh))
6062
}
6163
return device.TcForward, nil
6264
}
@@ -69,7 +71,7 @@ func (n *Nylon) InstallTC(s *state.State) {
6971
if ok {
7072
packet.ToPeer = entry.Peer
7173
if state.DBG_trace_tc {
72-
dev.Log.Verbosef("Fwd packet: %v -> %v, via %s", packet.GetSrc(), packet.GetDst(), entry.Nh)
74+
t.Submit(fmt.Sprintf("Fwd packet: %v -> %v, via %s\n", packet.GetSrc(), packet.GetDst(), entry.Nh))
7375
}
7476
return device.TcForward, nil
7577
}
@@ -87,7 +89,7 @@ func (n *Nylon) InstallTC(s *state.State) {
8789
}
8890
if ttl == 0 {
8991
if state.DBG_trace_tc {
90-
dev.Log.Verbosef("TTL Expired: %v -> %v, via %s", packet.GetSrc(), packet.GetDst())
92+
t.Submit(fmt.Sprintf("TTL Expired: %v -> %v\n", packet.GetSrc(), packet.GetDst()))
9193
}
9294
return device.TcBounce, nil
9395
}
@@ -103,6 +105,9 @@ func (n *Nylon) InstallTC(s *state.State) {
103105
entry, ok := r.ExitTable.Lookup(packet.GetDst())
104106
// we should only accept packets destined to us, but not our passive clients
105107
if ok && entry.Nh == s.Id {
108+
if state.DBG_trace_tc {
109+
t.Submit(fmt.Sprintf("Exit: %v -> %v\n", packet.GetSrc(), packet.GetDst()))
110+
}
106111
//dev.Log.Verbosef("BounceCur packet: %v -> %v", packet.GetSrc(), packet.GetDst())
107112
return device.TcBounce, nil
108113
}

core/nylon_trace.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package core
2+
3+
import (
4+
"github.com/dustin/go-broadcast"
5+
"github.com/encodeous/nylon/state"
6+
)
7+
8+
type NylonTrace struct {
9+
broadcast.Broadcaster
10+
}
11+
12+
func (n *NylonTrace) Init(s *state.State) error {
13+
n.Broadcaster = broadcast.NewBroadcaster(1024)
14+
return nil
15+
}
16+
17+
func (n *NylonTrace) Cleanup(s *state.State) error {
18+
return n.Broadcaster.Close()
19+
}

core/router.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ func (r *NylonRouter) BroadcastRequestSeqno(src state.Source, seqno uint16, hopC
9797
}
9898

9999
func (r *NylonRouter) Log(event RouterEvent, desc string, args ...any) {
100+
if event == NoEpToNeighbour {
101+
return // ignored
102+
}
100103
r.Env.Log.Debug(fmt.Sprintf("%s %s", event.String(), desc), args...)
101104
}
102105

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ require (
4444
github.com/distribution/reference v0.6.0 // indirect
4545
github.com/docker/go-connections v0.6.0 // indirect
4646
github.com/docker/go-units v0.5.0 // indirect
47+
github.com/dustin/go-broadcast v0.0.0-20211018055107-71439988bd91 // indirect
4748
github.com/ebitengine/purego v0.8.4 // indirect
4849
github.com/felixge/httpsnoop v1.0.4 // indirect
4950
github.com/go-logr/logr v1.4.3 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pM
4343
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
4444
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
4545
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
46+
github.com/dustin/go-broadcast v0.0.0-20211018055107-71439988bd91 h1:jAUM3D1KIrJmwx60DKB+a/qqM69yHnu6otDGVa2t0vs=
47+
github.com/dustin/go-broadcast v0.0.0-20211018055107-71439988bd91/go.mod h1:8rK6Kbo1Jd6sK22b24aPVgAm3jlNy1q1ft+lBALdIqA=
4648
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
4749
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
4850
github.com/encodeous/metric v0.0.0-20251111175231-f339c2f7c4bd h1:B32Ob80QTv5MomcVt709TsiWyD0QrpUYtnwW1jQFNlE=

0 commit comments

Comments
 (0)