mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 03:05:07 +03:00 
			
		
		
		
	Mostly working PMTU discovery when going over UDP links
This commit is contained in:
		
							parent
							
								
									0fae932512
								
							
						
					
					
						commit
						63b55cda62
					
				
					 3 changed files with 40 additions and 10 deletions
				
			
		| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,6 +29,7 @@ type sessionInfo struct {
 | 
				
			||||||
	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…
	
	Add table
		Add a link
		
	
		Reference in a new issue