package wireguard import ( "context" "fmt" "os" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/buffer" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/link/channel" "gvisor.dev/gvisor/pkg/tcpip/stack" wgtun "golang.zx2c4.com/wireguard/tun" ) type WgTun struct { events chan wgtun.Event ch *channel.Endpoint stack *stack.Stack ctx context.Context cancel context.CancelFunc } func (tun *WgTun) File() *os.File { fmt.Println("File") return nil } func (tun *WgTun) Read(buff []byte, offset int) (int, error) { fmt.Println("Read ", len(buff), offset) p, ok := tun.ch.ReadContext(tun.ctx) if ok == false { fmt.Println("Read error") return 0, nil // FIXME error } vv := p.Pkt.Data v := vv.ToView() h := p.Pkt.Header.View() fmt.Println("Read packet", vv.Size(), len(v), len(h), h) if len(buff) - offset < len(h) + len(v) { fmt.Println("Short buffer") return 0, nil // FIXME error } copy(buff[offset:], h) copy(buff[offset+len(h):], v) return len(h)+len(v), nil } func versionToProtocol(version int) tcpip.NetworkProtocolNumber { switch version { case header.IPv4Version: return header.IPv4ProtocolNumber case header.IPv6Version: return header.IPv6ProtocolNumber } return 0 } func (tun *WgTun) Write(buff []byte, offset int) (int, error) { size := len(buff) - offset fmt.Println("Write ", len(buff), offset, size) if size < 1 { return 0, nil // FIXME error } buffSlice := buff[offset : offset+size] pkt := tcpip.PacketBuffer{ Data: buffer.NewViewFromBytes(buffSlice).ToVectorisedView(), } //version := buff[offset] & 0x0f protocol := versionToProtocol(header.IPVersion(buffSlice)) netProto := tun.stack.NetworkProtocolInstance(protocol) if netProto == nil { fmt.Println("Write not ok") return 0, nil } src, dst := netProto.ParseAddresses(pkt.Data.First()) fmt.Println("Write ", src, dst) // TODO change destination address tun.ch.InjectInbound(protocol, pkt) // FIXME detect protocol number return size, nil } func (tun *WgTun) Flush() error { // TODO: can flushing be implemented by buffering and using sendmmsg? fmt.Println("Flush") return nil } func (tun *WgTun) MTU() (int, error) { fmt.Println("MTU") return 1280, nil } func (tun *WgTun) Name() (string, error) { fmt.Println("Name") return "foobar", nil } func (tun *WgTun) Events() chan wgtun.Event { fmt.Println("Events") return tun.events } func (tun *WgTun) Close() error { fmt.Println("Close") // TODO // tun.cancel() return nil } func CreateWgTun(s *stack.Stack, ch *channel.Endpoint) (wgtun.Device, error) { size := 16 ctx, cancel := context.WithCancel(context.Background()) tun := &WgTun{ ch: ch, events: make(chan wgtun.Event, size), stack: s, ctx: ctx, cancel: cancel, } // go func() { fmt.Println("Post event") tun.events <- wgtun.EventUp fmt.Println("Posted event") // }() return tun, nil }