2020-10-24 20:40:46 +00:00
|
|
|
/* 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 (
|
2020-12-09 00:46:55 +00:00
|
|
|
procWintunAllocateSendPacket = modwintun.NewProc("WintunAllocateSendPacket")
|
2020-10-24 20:40:46 +00:00
|
|
|
procWintunEndSession = modwintun.NewProc("WintunEndSession")
|
|
|
|
procWintunGetReadWaitEvent = modwintun.NewProc("WintunGetReadWaitEvent")
|
2020-12-09 00:46:55 +00:00
|
|
|
procWintunReceivePacket = modwintun.NewProc("WintunReceivePacket")
|
|
|
|
procWintunReleaseReceivePacket = modwintun.NewProc("WintunReleaseReceivePacket")
|
|
|
|
procWintunSendPacket = modwintun.NewProc("WintunSendPacket")
|
2020-10-24 20:40:46 +00:00
|
|
|
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
|
2020-12-09 00:46:55 +00:00
|
|
|
r0, _, e1 := syscall.Syscall(procWintunReceivePacket.Addr(), 2, session.handle, uintptr(unsafe.Pointer(&packetSize)), 0)
|
2020-10-24 20:40:46 +00:00
|
|
|
if r0 == 0 {
|
|
|
|
err = e1
|
|
|
|
return
|
|
|
|
}
|
|
|
|
unsafeSlice(unsafe.Pointer(&packet), unsafe.Pointer(r0), int(packetSize))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (session Session) ReleaseReceivePacket(packet []byte) {
|
2020-12-09 00:46:55 +00:00
|
|
|
syscall.Syscall(procWintunReleaseReceivePacket.Addr(), 2, session.handle, uintptr(unsafe.Pointer(&packet[0])), 0)
|
2020-10-24 20:40:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (session Session) AllocateSendPacket(packetSize int) (packet []byte, err error) {
|
2020-12-09 00:46:55 +00:00
|
|
|
r0, _, e1 := syscall.Syscall(procWintunAllocateSendPacket.Addr(), 2, session.handle, uintptr(packetSize), 0)
|
2020-10-24 20:40:46 +00:00
|
|
|
if r0 == 0 {
|
|
|
|
err = e1
|
|
|
|
return
|
|
|
|
}
|
|
|
|
unsafeSlice(unsafe.Pointer(&packet), unsafe.Pointer(r0), int(packetSize))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (session Session) SendPacket(packet []byte) {
|
2020-12-09 00:46:55 +00:00
|
|
|
syscall.Syscall(procWintunSendPacket.Addr(), 2, session.handle, uintptr(unsafe.Pointer(&packet[0])), 0)
|
2020-10-24 20:40:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|