wintun: ring management moved to wintun.dll
Signed-off-by: Simon Rozman <simon@rozman.si> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
committed by
Jason A. Donenfeld
parent
65e03a9182
commit
a3b231b31e
@@ -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
|
||||
}
|
||||
108
tun/wintun/session_windows.go
Normal file
108
tun/wintun/session_windows.go
Normal file
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user