"net"
"runtime"
"sync"
+ "sync/atomic"
+ "time"
)
type Device struct {
- mtu int
+ mtu int32
log *Logger // collection of loggers for levels
idCounter uint // for assigning debug ids to peers
fwMark uint32
}
go device.RoutineBusyMonitor()
+ go device.RoutineMTUUpdater(tun)
go device.RoutineWriteToTUN(tun)
go device.RoutineReadFromTUN(tun)
go device.RoutineReceiveIncomming()
return device
}
+func (device *Device) RoutineMTUUpdater(tun TUNDevice) {
+ logError := device.log.Error
+ for ; ; time.Sleep(time.Second) {
+ mtu, err := tun.MTU()
+ if err != nil {
+ logError.Println("Failed to load updated MTU of device:", err)
+ continue
+ }
+ atomic.StoreInt32(&device.mtu, int32(mtu))
+ }
+}
+
func (device *Device) LookupPeer(pk NoisePublicKey) *Peer {
device.mutex.RLock()
defer device.mutex.RUnlock()
// populate header fields
- func() {
- header := work.buffer[:MessageTransportHeaderSize]
+ header := work.buffer[:MessageTransportHeaderSize]
- fieldType := header[0:4]
- fieldReceiver := header[4:8]
- fieldNonce := header[8:16]
+ fieldType := header[0:4]
+ fieldReceiver := header[4:8]
+ fieldNonce := header[8:16]
- binary.LittleEndian.PutUint32(fieldType, MessageTransportType)
- binary.LittleEndian.PutUint32(fieldReceiver, work.keyPair.remoteIndex)
- binary.LittleEndian.PutUint64(fieldNonce, work.nonce)
- }()
+ binary.LittleEndian.PutUint32(fieldType, MessageTransportType)
+ binary.LittleEndian.PutUint32(fieldReceiver, work.keyPair.remoteIndex)
+ binary.LittleEndian.PutUint64(fieldNonce, work.nonce)
+
+ // pad content to MTU size
+
+ mtu := int(atomic.LoadInt32(&device.mtu))
+ for i := len(work.packet); i < mtu; i++ {
+ work.packet = append(work.packet, 0)
+ }
// encrypt content
package main
+/*
+ * The default MTU of the new device must be 1420
+ */
+
+const DefaultMTU = 1420
+
type TUNDevice interface {
Read([]byte) (int, error) // read a packet from the device (without any additional headers)
Write([]byte) (int, error) // writes a packet to the device (without any additional headers)
return tun.name
}
+func (tun *NativeTun) setMTU(n int) error {
+
+ // open datagram socket
+
+ fd, err := syscall.Socket(
+ syscall.AF_INET,
+ syscall.SOCK_DGRAM,
+ 0,
+ )
+
+ if err != nil {
+ return err
+ }
+
+ // do ioctl call
+
+ var ifr [64]byte
+ copy(ifr[:], tun.name)
+ binary.LittleEndian.PutUint32(ifr[16:20], uint32(n))
+ _, _, errno := syscall.Syscall(
+ syscall.SYS_IOCTL,
+ uintptr(fd),
+ uintptr(syscall.SIOCSIFMTU),
+ uintptr(unsafe.Pointer(&ifr[0])),
+ )
+
+ if errno != 0 {
+ return errors.New("Failed to set MTU of TUN device")
+ }
+
+ return nil
+}
+
func (tun *NativeTun) MTU() (int, error) {
// open datagram socket
// do ioctl call
var ifr [64]byte
- var flags uint16
copy(ifr[:], tun.name)
- binary.LittleEndian.PutUint16(ifr[16:], flags)
_, _, errno := syscall.Syscall(
syscall.SYS_IOCTL,
uintptr(fd),
return nil, err
}
- // prepare ifreq struct
+ // create new device
var ifr [64]byte
var flags uint16 = syscall.IFF_TUN | syscall.IFF_NO_PI
copy(ifr[:], nameBytes)
binary.LittleEndian.PutUint16(ifr[16:], flags)
- // create new device
-
_, _, errno := syscall.Syscall(
syscall.SYS_IOCTL,
uintptr(fd.Fd()),
newName := string(ifr[:])
newName = newName[:strings.Index(newName, "\000")]
- return &NativeTun{
+ device := &NativeTun{
fd: fd,
name: newName,
- }, nil
+ }
+
+ // set default MTU
+
+ err = device.setMTU(DefaultMTU)
+ return device, err
}