diff --git a/src/device.go b/src/device.go index a15961a..4981f51 100644 --- a/src/device.go +++ b/src/device.go @@ -4,10 +4,12 @@ import ( "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 @@ -118,6 +120,7 @@ func NewDevice(tun TUNDevice, logLevel int) *Device { } go device.RoutineBusyMonitor() + go device.RoutineMTUUpdater(tun) go device.RoutineWriteToTUN(tun) go device.RoutineReadFromTUN(tun) go device.RoutineReceiveIncomming() @@ -126,6 +129,18 @@ func NewDevice(tun TUNDevice, logLevel int) *Device { 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() diff --git a/src/send.go b/src/send.go index 7a2fe44..2db74ba 100644 --- a/src/send.go +++ b/src/send.go @@ -281,17 +281,22 @@ func (device *Device) RoutineEncryption() { // 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 diff --git a/src/tun.go b/src/tun.go index 85735a6..f529c54 100644 --- a/src/tun.go +++ b/src/tun.go @@ -1,5 +1,11 @@ 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) diff --git a/src/tun_linux.go b/src/tun_linux.go index 63c3886..d0e9761 100644 --- a/src/tun_linux.go +++ b/src/tun_linux.go @@ -23,6 +23,39 @@ func (tun *NativeTun) Name() string { 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 @@ -40,9 +73,7 @@ func (tun *NativeTun) MTU() (int, error) { // 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), @@ -79,7 +110,7 @@ func CreateTUN(name string) (TUNDevice, error) { return nil, err } - // prepare ifreq struct + // create new device var ifr [64]byte var flags uint16 = syscall.IFF_TUN | syscall.IFF_NO_PI @@ -90,8 +121,6 @@ func CreateTUN(name string) (TUNDevice, error) { copy(ifr[:], nameBytes) binary.LittleEndian.PutUint16(ifr[16:], flags) - // create new device - _, _, errno := syscall.Syscall( syscall.SYS_IOCTL, uintptr(fd.Fd()), @@ -106,8 +135,13 @@ func CreateTUN(name string) (TUNDevice, error) { 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 }