wintun: Switch to dynamic packet sizes
Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
parent
42c6d0e261
commit
4863089120
|
@ -7,17 +7,18 @@ package tun
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"golang.zx2c4.com/wireguard/tun/wintun"
|
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
|
"golang.zx2c4.com/wireguard/tun/wintun"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
packetSizeMax = 1600
|
packetSizeMax uint32 = 0xeffc // Maximum packet size: 4 + packetSizeMax == 0xf000
|
||||||
packetExchangeMax = 256 // Number of packets that can be exchanged at a time
|
packetExchangeMax uint32 = 256 // Number of packets that may be written at a time
|
||||||
|
packetExchangeAlignment uint32 = 16 // Number of bytes packets are aligned to in exchange buffers
|
||||||
|
packetExchangeSize uint32 = 0x100000 // Exchange buffer size (defaults to 1MiB)
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -27,30 +28,26 @@ const (
|
||||||
signalMax
|
signalMax
|
||||||
)
|
)
|
||||||
|
|
||||||
type tunPacket struct {
|
|
||||||
size uint32
|
|
||||||
data [packetSizeMax]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type tunRWQueue struct {
|
|
||||||
numPackets uint32
|
|
||||||
packets [packetExchangeMax]tunPacket
|
|
||||||
left bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type nativeTun struct {
|
type nativeTun struct {
|
||||||
wt *wintun.Wintun
|
wt *wintun.Wintun
|
||||||
tunName string
|
tunName string
|
||||||
signalName *uint16
|
signalName *uint16
|
||||||
tunFile *os.File
|
tunFile *os.File
|
||||||
wrBuff tunRWQueue
|
wrBuff [packetExchangeSize]byte
|
||||||
rdBuff tunRWQueue
|
rdBuff [packetExchangeSize]byte
|
||||||
signals [signalMax]windows.Handle
|
signals [signalMax]windows.Handle
|
||||||
rdNextPacket uint32
|
wrOffset uint32
|
||||||
|
wrPacketNum uint32
|
||||||
|
rdOffset uint32
|
||||||
|
rdAvailabe uint32
|
||||||
events chan TUNEvent
|
events chan TUNEvent
|
||||||
errors chan error
|
errors chan error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func packetAlign(size uint32) uint32 {
|
||||||
|
return (size + (packetExchangeAlignment - 1)) &^ (packetExchangeAlignment - 1)
|
||||||
|
}
|
||||||
|
|
||||||
func CreateTUN(ifname string) (TUNDevice, error) {
|
func CreateTUN(ifname string) (TUNDevice, error) {
|
||||||
// Does an interface with this name already exist?
|
// Does an interface with this name already exist?
|
||||||
wt, err := wintun.GetInterface(ifname, 0)
|
wt, err := wintun.GetInterface(ifname, 0)
|
||||||
|
@ -206,19 +203,20 @@ func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if tun.rdNextPacket < tun.rdBuff.numPackets {
|
if tun.rdOffset+4 <= tun.rdAvailabe {
|
||||||
// Get packet from the queue.
|
// Get packet from the queue.
|
||||||
tunPacket := &tun.rdBuff.packets[tun.rdNextPacket]
|
size := *(*uint32)(unsafe.Pointer(&tun.rdBuff[tun.rdOffset]))
|
||||||
tun.rdNextPacket++
|
pSize := packetAlign(4 + size)
|
||||||
|
if packetSizeMax < size || tun.rdAvailabe < tun.rdOffset+pSize {
|
||||||
if packetSizeMax < tunPacket.size {
|
|
||||||
// Invalid packet size.
|
// Invalid packet size.
|
||||||
|
tun.rdAvailabe = 0
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy data.
|
// Copy data.
|
||||||
copy(buff[offset:], tunPacket.data[:tunPacket.size])
|
copy(buff[offset:], (*(*[packetSizeMax]byte)(unsafe.Pointer(&tun.rdBuff[tun.rdOffset+4])))[:size])
|
||||||
return int(tunPacket.size), nil
|
tun.rdOffset += pSize
|
||||||
|
return int(size), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if tun.signals[signalDataAvail] == 0 {
|
if tun.signals[signalDataAvail] == 0 {
|
||||||
|
@ -251,16 +249,16 @@ func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill queue.
|
// Fill queue.
|
||||||
const bufSize = int(unsafe.Sizeof(tun.rdBuff))
|
n, err := tun.tunFile.Read(tun.rdBuff[:])
|
||||||
n, err := tun.tunFile.Read((*[bufSize]byte)(unsafe.Pointer(&tun.rdBuff))[:])
|
if err != nil {
|
||||||
tun.rdNextPacket = 0
|
|
||||||
if n != bufSize || err != nil {
|
|
||||||
// TUN interface stopped, returned incomplete data, etc.
|
// TUN interface stopped, returned incomplete data, etc.
|
||||||
// Retry.
|
// Retry.
|
||||||
tun.rdBuff.numPackets = 0
|
tun.rdAvailabe = 0
|
||||||
tun.closeTUN()
|
tun.closeTUN()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
tun.rdOffset = 0
|
||||||
|
tun.rdAvailabe = uint32(n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,42 +266,40 @@ func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
|
||||||
|
|
||||||
func (tun *nativeTun) flush() error {
|
func (tun *nativeTun) flush() error {
|
||||||
// Flush write buffer.
|
// Flush write buffer.
|
||||||
const bufSize = int(unsafe.Sizeof(tun.wrBuff))
|
_, err := tun.tunFile.Write(tun.wrBuff[:tun.wrOffset])
|
||||||
n, err := tun.tunFile.Write((*[bufSize]byte)(unsafe.Pointer(&tun.wrBuff))[:])
|
tun.wrPacketNum = 0
|
||||||
tun.wrBuff.numPackets = 0
|
tun.wrOffset = 0
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if n != bufSize {
|
|
||||||
return fmt.Errorf("%d byte(s) written, %d byte(s) expected", n, bufSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tun *nativeTun) putTunPacket(buff []byte) error {
|
func (tun *nativeTun) putTunPacket(buff []byte) error {
|
||||||
size := len(buff)
|
size := uint32(len(buff))
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
return errors.New("Empty packet")
|
return errors.New("Empty packet")
|
||||||
}
|
}
|
||||||
if size > packetSizeMax {
|
if size > packetSizeMax {
|
||||||
return errors.New("Packet too big")
|
return errors.New("Packet too big")
|
||||||
}
|
}
|
||||||
|
pSize := packetAlign(4 + size)
|
||||||
|
|
||||||
if tun.wrBuff.numPackets >= packetExchangeMax {
|
if tun.wrPacketNum >= packetExchangeMax || tun.wrOffset+pSize >= packetExchangeSize {
|
||||||
// Queue is full -> flush first.
|
// Exchange buffer is full -> flush first.
|
||||||
err := tun.flush()
|
err := tun.flush()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push packet to the buffer.
|
// Write packet to the exchange buffer.
|
||||||
tunPacket := &tun.wrBuff.packets[tun.wrBuff.numPackets]
|
*(*uint32)(unsafe.Pointer(&tun.wrBuff[tun.wrOffset])) = size
|
||||||
tunPacket.size = uint32(size)
|
copy((*(*[packetSizeMax]byte)(unsafe.Pointer(&tun.wrBuff[tun.wrOffset+4])))[:size], buff)
|
||||||
copy(tunPacket.data[:size], buff)
|
|
||||||
|
|
||||||
tun.wrBuff.numPackets++
|
tun.wrPacketNum++
|
||||||
|
tun.wrOffset += pSize
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue