/*
GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2015 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2020 Sergey Matveev <stargrave@stargrave.org>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, version 3 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
import (
"io"
-
- "golang.org/x/crypto/poly1305"
-)
-
-const (
- EtherSize = 14
)
type TAP struct {
- Name string
- dev io.ReadWriter
- buf []byte
- sink chan []byte
- ready chan struct{}
- synced bool
+ Name string
+ Sink chan []byte
+ dev io.ReadWriter
}
-// Return maximal acceptable TAP interface MTU. This is daemon's MTU
-// minus nonce, MAC, packet size mark and Ethernet header sizes.
-func TAPMaxMTU() int {
- return MTU - poly1305.TagSize - NonceSize - PktSizeSize - EtherSize
-}
+var (
+ taps = make(map[string]*TAP)
+)
-func NewTAP(ifaceName string) (*TAP, error) {
- maxIfacePktSize := TAPMaxMTU() + EtherSize
+func NewTAP(ifaceName string, mtu int) (*TAP, error) {
tapRaw, err := newTAPer(ifaceName)
if err != nil {
return nil, err
}
tap := TAP{
- Name: ifaceName,
- dev: tapRaw,
- buf: make([]byte, maxIfacePktSize),
- sink: make(chan []byte),
- ready: make(chan struct{}),
- synced: false,
+ Name: ifaceName,
+ dev: tapRaw,
+ Sink: make(chan []byte),
}
go func() {
var n int
var err error
+ var buf []byte
+ buf0 := make([]byte, mtu)
+ buf1 := make([]byte, mtu)
+ bufZ := false
for {
- <-tap.ready
- n, err = tap.dev.Read(tap.buf)
+ if bufZ {
+ buf = buf0
+ } else {
+ buf = buf1
+ }
+ bufZ = !bufZ
+ n, err = tap.dev.Read(buf)
if err != nil {
- panic(err)
+ panic("Reading TUN/TAP:" + err.Error())
}
- tap.sink <- tap.buf[:n]
+ tap.Sink <- buf[:n]
}
}()
return &tap, nil
func (t *TAP) Write(data []byte) (n int, err error) {
return t.dev.Write(data)
}
+
+func TAPListen(ifaceName string, mtu int) (*TAP, error) {
+ tap, exists := taps[ifaceName]
+ if exists {
+ return tap, nil
+ }
+ tap, err := NewTAP(ifaceName, mtu)
+ if err != nil {
+ return nil, err
+ }
+ taps[ifaceName] = tap
+ return tap, nil
+}