mirror of
https://github.com/soypat/lneto.git
synced 2026-08-12 10:53:44 +00:00
add gvisor-mwe and add binary sizes to README
This commit is contained in:
@@ -15,6 +15,7 @@ vendor/
|
||||
*.so
|
||||
*.dylib
|
||||
*.hex
|
||||
*.wasm
|
||||
|
||||
# Profiling
|
||||
*.pprof
|
||||
|
||||
@@ -27,6 +27,14 @@ Userspace networking primitives.
|
||||
## [`min-working-example`](./examples/min-working-example/) - Quick lneto showcase
|
||||
Get a quick showcase of how lneto can be configured and how to get a TCP listening server up and running.
|
||||
|
||||
### Binary size comparisons
|
||||
All examples include IPv4, ARP, ICMP, TCP and UDP functionality. Go and TinyGo default build flags used. **DNC**= Does Not Compile.
|
||||
|
||||
|
||||
| Program | Extra Protocols | amd64 Go | WASM Go | amd64 TinyGo | WASM TinyGo | Pico TinyGo |
|
||||
|---|---|---|---|---|---|---|
|
||||
| [Lneto MWE](./examples/min-working-example/) | DNS,NTP,DHCP | 3.8MB | 4.3MB | 1.3MB | 934kB | 181kB |
|
||||
| [Gvisor MWE w/ go-net](./examples/_import_examples/gvisor-mwe/)| None | 6.6MB | 7.5MB | DNC | DNC | DNC |
|
||||
## `xcurl` example
|
||||
You may try lneto out on linux with the [xcurl example](./examples/xcurl/) which gets an HTTP page by doing all the low-level networking part using absolutely no standard library.
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# import-examples
|
||||
This folder contains examples that need external imports to work.
|
||||
|
||||
This is done to avoid adding dependencies to lneto's go.mod file.
|
||||
- Trivial Auditing
|
||||
- No dependency analysis needed for vulnerability scanning
|
||||
- Eliminate a whole set of attack vectors for lneto importers
|
||||
- Ensures nothing outside Lneto gets compiled maintaining binary sizes small
|
||||
@@ -0,0 +1,11 @@
|
||||
module gvisormwe
|
||||
|
||||
go 1.25.7
|
||||
|
||||
require (
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/usbarmory/go-net v0.0.0-20260416163630-1078311e0956 // indirect
|
||||
golang.org/x/sys v0.26.0 // indirect
|
||||
golang.org/x/time v0.7.0 // indirect
|
||||
gvisor.dev/gvisor v0.0.0-20250911055229-61a46406f068 // indirect
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
||||
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/usbarmory/go-net v0.0.0-20260416163630-1078311e0956 h1:ZjhVXLMT/Ogxs1GIy1g8UJk7yi9G8kt90D0ElAPbaCc=
|
||||
github.com/usbarmory/go-net v0.0.0-20260416163630-1078311e0956/go.mod h1:+6WiKCFJtJQZdNM2VpwQsYGo/aBJ39pN7nWx6Td3Z8s=
|
||||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
gvisor.dev/gvisor v0.0.0-20250911055229-61a46406f068 h1:95kdltF/maTDk/Wulj7V81cSLgjB/Mg/6eJmOKsey4U=
|
||||
gvisor.dev/gvisor v0.0.0-20250911055229-61a46406f068/go.mod h1:K16uJjZ+hSqDVsXhU2Rg2FpMN7kBvjZp/Ibt5BYZJjw=
|
||||
@@ -0,0 +1,93 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
gnet "github.com/usbarmory/go-net"
|
||||
)
|
||||
|
||||
const pollTime = 5 * time.Millisecond
|
||||
|
||||
var networkDevice NetworkDevice
|
||||
|
||||
// NetworkDevice implements gnet.NetworkDevice for bridging with raw Ethernet I/O.
|
||||
type NetworkDevice struct {
|
||||
send func([]byte) error
|
||||
recv func([]byte) (int, error)
|
||||
}
|
||||
|
||||
func (d *NetworkDevice) Transmit(buf []byte) error { return d.send(buf) }
|
||||
func (d *NetworkDevice) Receive(buf []byte) (int, error) { return d.recv(buf) }
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
if err := run(ctx); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func run(ctx context.Context) error {
|
||||
// Create gVisor-based networking stack.
|
||||
stack := gnet.NewGVisorStack(1)
|
||||
|
||||
// Configure stack with MAC, IP prefix, and gateway.
|
||||
err := stack.Configure(
|
||||
"aa:bb:cc:dd:ee:ff",
|
||||
netip.MustParsePrefix("192.168.1.10/24"),
|
||||
netip.MustParseAddr("192.168.1.1"),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("configuring stack: %w", err)
|
||||
}
|
||||
|
||||
err = stack.EnableICMP()
|
||||
if err != nil {
|
||||
return fmt.Errorf("enabling ICMP: %w", err)
|
||||
}
|
||||
|
||||
// Bridge the stack with a network device for packet I/O.
|
||||
iface := &gnet.Interface{
|
||||
Stack: stack,
|
||||
NetworkDevice: &networkDevice,
|
||||
HandleStackErr: func(err error, tx bool) {
|
||||
dir := "rx"
|
||||
if tx {
|
||||
dir = "tx"
|
||||
}
|
||||
fmt.Printf("stack %s err: %v\n", dir, err)
|
||||
},
|
||||
}
|
||||
// Start the packet processing loop in a goroutine.
|
||||
go iface.Start()
|
||||
|
||||
// Create a TCP listener on port 80 using the gVisor stack.
|
||||
const sockStream = 0x1
|
||||
laddr := net.TCPAddrFromAddrPort(netip.AddrPortFrom(netip.MustParseAddr("192.168.1.10"), 80))
|
||||
c, err := stack.Socket(ctx, "tcp", syscall.AF_INET, sockStream, laddr, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating AF_INET stream socket: %w", err)
|
||||
}
|
||||
listener := c.(net.Listener)
|
||||
for ctx.Err() == nil {
|
||||
time.Sleep(pollTime)
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
fmt.Println("conn failed:", err)
|
||||
continue
|
||||
}
|
||||
go handleConn(conn)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleConn(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
conn.Write([]byte("Hello from gVisor stack!"))
|
||||
}
|
||||
Reference in New Issue
Block a user