diff options
Diffstat (limited to 'tun/wintun')
-rw-r--r-- | tun/wintun/ring_windows.go | 117 | ||||
-rw-r--r-- | tun/wintun/session_windows.go | 108 | ||||
-rw-r--r-- | tun/wintun/wintun_windows.go | 11 |
3 files changed, 108 insertions, 128 deletions
diff --git a/tun/wintun/ring_windows.go b/tun/wintun/ring_windows.go deleted file mode 100644 index ed460fb..0000000 --- a/tun/wintun/ring_windows.go +++ /dev/null @@ -1,117 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2020 WireGuard LLC. All Rights Reserved. - */ - -package wintun - -import ( - "runtime" - "unsafe" - - "golang.org/x/sys/windows" -) - -const ( - PacketAlignment = 4 // Number of bytes packets are aligned to in rings - PacketSizeMax = 0xffff // Maximum packet size - PacketCapacity = 0x800000 // Ring capacity, 8MiB - PacketTrailingSize = uint32(unsafe.Sizeof(PacketHeader{})) + ((PacketSizeMax + (PacketAlignment - 1)) &^ (PacketAlignment - 1)) - PacketAlignment - ioctlRegisterRings = (51820 << 16) | (0x970 << 2) | 0 /*METHOD_BUFFERED*/ | (0x3 /*FILE_READ_DATA | FILE_WRITE_DATA*/ << 14) -) - -type PacketHeader struct { - Size uint32 -} - -type Packet struct { - PacketHeader - Data [PacketSizeMax]byte -} - -type Ring struct { - Head uint32 - Tail uint32 - Alertable int32 - Data [PacketCapacity + PacketTrailingSize]byte -} - -type RingDescriptor struct { - Send, Receive struct { - Size uint32 - Ring *Ring - TailMoved windows.Handle - } -} - -// Wrap returns value modulo ring capacity -func (rb *Ring) Wrap(value uint32) uint32 { - return value & (PacketCapacity - 1) -} - -// Aligns a packet size to PacketAlignment -func PacketAlign(size uint32) uint32 { - return (size + (PacketAlignment - 1)) &^ (PacketAlignment - 1) -} - -func NewRingDescriptor() (descriptor *RingDescriptor, err error) { - descriptor = new(RingDescriptor) - allocatedRegion, err := windows.VirtualAlloc(0, unsafe.Sizeof(Ring{})*2, windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_READWRITE) - if err != nil { - return - } - defer func() { - if err != nil { - descriptor.free() - descriptor = nil - } - }() - descriptor.Send.Size = uint32(unsafe.Sizeof(Ring{})) - descriptor.Send.Ring = (*Ring)(unsafe.Pointer(allocatedRegion)) - descriptor.Send.TailMoved, err = windows.CreateEvent(nil, 0, 0, nil) - if err != nil { - return - } - - descriptor.Receive.Size = uint32(unsafe.Sizeof(Ring{})) - descriptor.Receive.Ring = (*Ring)(unsafe.Pointer(allocatedRegion + unsafe.Sizeof(Ring{}))) - descriptor.Receive.TailMoved, err = windows.CreateEvent(nil, 0, 0, nil) - if err != nil { - windows.CloseHandle(descriptor.Send.TailMoved) - return - } - runtime.SetFinalizer(descriptor, func(d *RingDescriptor) { d.free() }) - return -} - -func (descriptor *RingDescriptor) free() { - if descriptor.Send.Ring != nil { - windows.VirtualFree(uintptr(unsafe.Pointer(descriptor.Send.Ring)), 0, windows.MEM_RELEASE) - descriptor.Send.Ring = nil - descriptor.Receive.Ring = nil - } -} - -func (descriptor *RingDescriptor) Close() { - if descriptor.Send.TailMoved != 0 { - windows.CloseHandle(descriptor.Send.TailMoved) - descriptor.Send.TailMoved = 0 - } - if descriptor.Send.TailMoved != 0 { - windows.CloseHandle(descriptor.Receive.TailMoved) - descriptor.Receive.TailMoved = 0 - } -} - -func (wintun *Adapter) Register(descriptor *RingDescriptor) (windows.Handle, error) { - handle, err := wintun.OpenAdapterDeviceObject() - if err != nil { - return 0, err - } - var bytesReturned uint32 - err = windows.DeviceIoControl(handle, ioctlRegisterRings, (*byte)(unsafe.Pointer(descriptor)), uint32(unsafe.Sizeof(*descriptor)), nil, 0, &bytesReturned, nil) - if err != nil { - return 0, err - } - return handle, nil -} diff --git a/tun/wintun/session_windows.go b/tun/wintun/session_windows.go new file mode 100644 index 0000000..1619e5a --- /dev/null +++ b/tun/wintun/session_windows.go @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2020 WireGuard LLC. All Rights Reserved. + */ + +package wintun + +import ( + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +type Session struct { + handle uintptr +} + +const ( + PacketSizeMax = 0xffff // Maximum packet size + RingCapacityMin = 0x20000 // Minimum ring capacity (128 kiB) + RingCapacityMax = 0x4000000 // Maximum ring capacity (64 MiB) +) + +// Packet with data +type Packet struct { + Next *Packet // Pointer to next packet in queue + Size uint32 // Size of packet (max WINTUN_MAX_IP_PACKET_SIZE) + Data *[PacketSizeMax]byte // Pointer to layer 3 IPv4 or IPv6 packet +} + +var ( + procWintunAllocateSendPacket = modwintun.NewProc("WintunAllocateSendPacket").Addr() + procWintunEndSession = modwintun.NewProc("WintunEndSession") + procWintunGetReadWaitEvent = modwintun.NewProc("WintunGetReadWaitEvent") + procWintunReceivePacket = modwintun.NewProc("WintunReceivePacket").Addr() + procWintunReleaseReceivePacket = modwintun.NewProc("WintunReleaseReceivePacket").Addr() + procWintunSendPacket = modwintun.NewProc("WintunSendPacket").Addr() + procWintunStartSession = modwintun.NewProc("WintunStartSession") +) + +func (wintun *Adapter) StartSession(capacity uint32) (session Session, err error) { + r0, _, e1 := syscall.Syscall(procWintunStartSession.Addr(), 2, uintptr(wintun.handle), uintptr(capacity), 0) + if r0 == 0 { + err = e1 + } else { + session = Session{r0} + } + return +} + +func (session Session) End() { + syscall.Syscall(procWintunEndSession.Addr(), 1, session.handle, 0, 0) + session.handle = 0 +} + +func (session Session) ReadWaitEvent() (handle windows.Handle) { + r0, _, _ := syscall.Syscall(procWintunGetReadWaitEvent.Addr(), 1, session.handle, 0, 0) + handle = windows.Handle(r0) + return +} + +func (session Session) ReceivePacket() (packet []byte, err error) { + var packetSize uint32 + r0, _, e1 := syscall.Syscall(procWintunReceivePacket, 2, session.handle, uintptr(unsafe.Pointer(&packetSize)), 0) + if r0 == 0 { + err = e1 + return + } + unsafeSlice(unsafe.Pointer(&packet), unsafe.Pointer(r0), int(packetSize)) + return +} + +func (session Session) ReleaseReceivePacket(packet []byte) { + syscall.Syscall(procWintunReleaseReceivePacket, 2, session.handle, uintptr(unsafe.Pointer(&packet[0])), 0) +} + +func (session Session) AllocateSendPacket(packetSize int) (packet []byte, err error) { + r0, _, e1 := syscall.Syscall(procWintunAllocateSendPacket, 2, session.handle, uintptr(packetSize), 0) + if r0 == 0 { + err = e1 + return + } + unsafeSlice(unsafe.Pointer(&packet), unsafe.Pointer(r0), int(packetSize)) + return +} + +func (session Session) SendPacket(packet []byte) { + syscall.Syscall(procWintunSendPacket, 2, session.handle, uintptr(unsafe.Pointer(&packet[0])), 0) +} + +// unsafeSlice updates the slice slicePtr to be a slice +// referencing the provided data with its length & capacity set to +// lenCap. +// +// TODO: when Go 1.16 or Go 1.17 is the minimum supported version, +// update callers to use unsafe.Slice instead of this. +func unsafeSlice(slicePtr, data unsafe.Pointer, lenCap int) { + type sliceHeader struct { + Data unsafe.Pointer + Len int + Cap int + } + h := (*sliceHeader)(slicePtr) + h.Data = data + h.Len = lenCap + h.Cap = lenCap +} diff --git a/tun/wintun/wintun_windows.go b/tun/wintun/wintun_windows.go index ac33579..e7ba8b6 100644 --- a/tun/wintun/wintun_windows.go +++ b/tun/wintun/wintun_windows.go @@ -45,7 +45,6 @@ var ( procWintunGetAdapterLUID = modwintun.NewProc("WintunGetAdapterLUID") procWintunGetAdapterName = modwintun.NewProc("WintunGetAdapterName") procWintunGetRunningDriverVersion = modwintun.NewProc("WintunGetRunningDriverVersion") - procWintunOpenAdapterDeviceObject = modwintun.NewProc("WintunOpenAdapterDeviceObject") procWintunSetAdapterName = modwintun.NewProc("WintunSetAdapterName") procWintunSetLogger = modwintun.NewProc("WintunSetLogger") ) @@ -210,16 +209,6 @@ func RunningVersion() (version uint32, err error) { return } -// handle returns a handle to the adapter device object. Release handle with windows.CloseHandle -func (wintun *Adapter) OpenAdapterDeviceObject() (handle windows.Handle, err error) { - r0, _, e1 := syscall.Syscall(procWintunOpenAdapterDeviceObject.Addr(), 1, uintptr(wintun.handle), 0, 0) - handle = windows.Handle(r0) - if handle == windows.InvalidHandle { - err = e1 - } - return -} - // LUID returns the LUID of the adapter. func (wintun *Adapter) LUID() (luid uint64) { syscall.Syscall(procWintunGetAdapterLUID.Addr(), 2, uintptr(wintun.handle), uintptr(unsafe.Pointer(&luid)), 0) |