mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-22 14:10:28 +00:00
Merge pull request #22 from Arceliar/udp_mtu_fix
Mostly working PMTU discovery when going over UDP links
This commit is contained in:
commit
33c9f74f48
@ -91,6 +91,7 @@ const boxPubKeyLen = 32
|
|||||||
const boxPrivKeyLen = 32
|
const boxPrivKeyLen = 32
|
||||||
const boxSharedKeyLen = 32
|
const boxSharedKeyLen = 32
|
||||||
const boxNonceLen = 24
|
const boxNonceLen = 24
|
||||||
|
const boxOverhead = box.Overhead
|
||||||
|
|
||||||
type boxPubKey [boxPubKeyLen]byte
|
type boxPubKey [boxPubKeyLen]byte
|
||||||
type boxPrivKey [boxPrivKeyLen]byte
|
type boxPrivKey [boxPrivKeyLen]byte
|
||||||
|
@ -28,7 +28,8 @@ type sessionInfo struct {
|
|||||||
send chan []byte
|
send chan []byte
|
||||||
recv chan *wire_trafficPacket
|
recv chan *wire_trafficPacket
|
||||||
nonceMask uint64
|
nonceMask uint64
|
||||||
tstamp int64 // tstamp from their last session ping, replay attack mitigation
|
tstamp int64 // tstamp from their last session ping, replay attack mitigation
|
||||||
|
mtuTime time.Time // time myMTU was last changed
|
||||||
}
|
}
|
||||||
|
|
||||||
type sessionPing struct {
|
type sessionPing struct {
|
||||||
@ -152,15 +153,7 @@ func (ss *sessions) createSession(theirPermKey *boxPubKey) *sessionInfo {
|
|||||||
sinfo.myNonce = *newBoxNonce()
|
sinfo.myNonce = *newBoxNonce()
|
||||||
sinfo.theirMTU = 1280
|
sinfo.theirMTU = 1280
|
||||||
sinfo.myMTU = uint16(ss.core.tun.mtu)
|
sinfo.myMTU = uint16(ss.core.tun.mtu)
|
||||||
if sinfo.myMTU > 2048 {
|
sinfo.mtuTime = time.Now()
|
||||||
// FIXME this is a temporary workaround to an issue with UDP peers
|
|
||||||
// UDP links need to fragment packets (within ygg) to get them over the wire
|
|
||||||
// For some reason, TCP streams over UDP peers can get stuck in a bad state
|
|
||||||
// When this happens, TCP throttles back, and each TCP retransmission loses fragments
|
|
||||||
// On my wifi network, it seems to happen around the 22nd-23rd fragment of a large packet
|
|
||||||
// By setting the path MTU to something small, this should (hopefully) mitigate the issue
|
|
||||||
sinfo.myMTU = 2048
|
|
||||||
}
|
|
||||||
higher := false
|
higher := false
|
||||||
for idx := range ss.core.boxPub {
|
for idx := range ss.core.boxPub {
|
||||||
if ss.core.boxPub[idx] > sinfo.theirPermPub[idx] {
|
if ss.core.boxPub[idx] > sinfo.theirPermPub[idx] {
|
||||||
@ -387,14 +380,42 @@ func (sinfo *sessionInfo) doSend(bs []byte) {
|
|||||||
|
|
||||||
func (sinfo *sessionInfo) doRecv(p *wire_trafficPacket) {
|
func (sinfo *sessionInfo) doRecv(p *wire_trafficPacket) {
|
||||||
defer util_putBytes(p.payload)
|
defer util_putBytes(p.payload)
|
||||||
|
payloadSize := uint16(len(p.payload))
|
||||||
if !sinfo.nonceIsOK(&p.nonce) {
|
if !sinfo.nonceIsOK(&p.nonce) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
bs, isOK := boxOpen(&sinfo.sharedSesKey, p.payload, &p.nonce)
|
bs, isOK := boxOpen(&sinfo.sharedSesKey, p.payload, &p.nonce)
|
||||||
if !isOK {
|
if !isOK {
|
||||||
|
// We're going to guess that the session MTU is too large
|
||||||
|
// Set myMTU to the largest value we think we can receive
|
||||||
|
fixSessionMTU := func() {
|
||||||
|
// This clamps down to 1280 almost immediately over ipv4
|
||||||
|
// Over link-local ipv6, it seems to approach link MTU
|
||||||
|
// So maybe it's doing the right thing?...
|
||||||
|
//sinfo.core.log.Println("DEBUG got bad packet:", payloadSize)
|
||||||
|
newMTU := payloadSize - boxOverhead
|
||||||
|
if newMTU < 1280 {
|
||||||
|
newMTU = 1280
|
||||||
|
}
|
||||||
|
if newMTU < sinfo.myMTU {
|
||||||
|
sinfo.myMTU = newMTU
|
||||||
|
//sinfo.core.log.Println("DEBUG set MTU to:", sinfo.myMTU)
|
||||||
|
sinfo.core.sessions.sendPingPong(sinfo, false)
|
||||||
|
sinfo.mtuTime = time.Now()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
go func() { sinfo.core.router.admin <- fixSessionMTU }()
|
||||||
util_putBytes(bs)
|
util_putBytes(bs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
fixSessionMTU := func() {
|
||||||
|
if time.Since(sinfo.mtuTime) > time.Minute {
|
||||||
|
sinfo.myMTU = uint16(sinfo.core.tun.mtu)
|
||||||
|
sinfo.mtuTime = time.Now()
|
||||||
|
//sinfo.core.log.Println("DEBUG: Reset MTU to:", sinfo.myMTU)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
go func() { sinfo.core.router.admin <- fixSessionMTU }()
|
||||||
sinfo.updateNonce(&p.nonce)
|
sinfo.updateNonce(&p.nonce)
|
||||||
sinfo.time = time.Now()
|
sinfo.time = time.Now()
|
||||||
sinfo.core.router.recvPacket(bs, &sinfo.theirAddr, &sinfo.theirSubnet)
|
sinfo.core.router.recvPacket(bs, &sinfo.theirAddr, &sinfo.theirSubnet)
|
||||||
|
@ -182,6 +182,13 @@ func (iface *udpInterface) handleKeys(msg []byte, addr connAddr) {
|
|||||||
//defer util_putBytes(bs)
|
//defer util_putBytes(bs)
|
||||||
chunks, chunk, count, payload := udp_decode(bs)
|
chunks, chunk, count, payload := udp_decode(bs)
|
||||||
if count != conn.countIn {
|
if count != conn.countIn {
|
||||||
|
if len(inBuf) > 0 {
|
||||||
|
// Something went wrong
|
||||||
|
// Forward whatever we have
|
||||||
|
// Maybe the destination can do something about it
|
||||||
|
msg := append(util_getBytes(), inBuf...)
|
||||||
|
conn.peer.handlePacket(msg, conn.linkIn)
|
||||||
|
}
|
||||||
inChunks = 0
|
inChunks = 0
|
||||||
inBuf = inBuf[:0]
|
inBuf = inBuf[:0]
|
||||||
conn.countIn = count
|
conn.countIn = count
|
||||||
@ -194,6 +201,7 @@ func (iface *udpInterface) handleKeys(msg []byte, addr connAddr) {
|
|||||||
}
|
}
|
||||||
msg := append(util_getBytes(), inBuf...)
|
msg := append(util_getBytes(), inBuf...)
|
||||||
conn.peer.handlePacket(msg, conn.linkIn)
|
conn.peer.handlePacket(msg, conn.linkIn)
|
||||||
|
inBuf = inBuf[:0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conn.peer.out = func(msg []byte) {
|
conn.peer.out = func(msg []byte) {
|
||||||
|
Loading…
Reference in New Issue
Block a user