mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-23 12:21:35 +00:00
Merge pull request #425 from neilalexander/sessionmtu
Re-add ICMPv6 packet too big handling
This commit is contained in:
commit
396c879d0f
@ -7,6 +7,8 @@ import (
|
|||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
|
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
|
||||||
|
"golang.org/x/net/icmp"
|
||||||
|
"golang.org/x/net/ipv6"
|
||||||
)
|
)
|
||||||
|
|
||||||
type tunConn struct {
|
type tunConn struct {
|
||||||
@ -97,8 +99,22 @@ func (s *tunConn) writer() error {
|
|||||||
}
|
}
|
||||||
// TODO write timeout and close
|
// TODO write timeout and close
|
||||||
if _, err := s.conn.Write(b); err != nil {
|
if _, err := s.conn.Write(b); err != nil {
|
||||||
|
e, eok := err.(yggdrasil.ConnError)
|
||||||
|
if !eok {
|
||||||
|
s.tun.log.Errorln(s.conn.String(), "TUN/TAP generic write error:", err)
|
||||||
|
} else if ispackettoobig, maxsize := e.PacketTooBig(); ispackettoobig {
|
||||||
|
// TODO: This currently isn't aware of IPv4 for CKR
|
||||||
|
ptb := &icmp.PacketTooBig{
|
||||||
|
MTU: int(maxsize),
|
||||||
|
Data: b[:900],
|
||||||
|
}
|
||||||
|
if packet, err := CreateICMPv6(b[8:24], b[24:40], ipv6.ICMPTypePacketTooBig, 0, ptb); err == nil {
|
||||||
|
s.tun.send <- packet
|
||||||
|
}
|
||||||
|
} else {
|
||||||
s.tun.log.Errorln(s.conn.String(), "TUN/TAP conn write error:", err)
|
s.tun.log.Errorln(s.conn.String(), "TUN/TAP conn write error:", err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
util.PutBytes(b)
|
util.PutBytes(b)
|
||||||
s.stillAlive()
|
s.stillAlive()
|
||||||
}
|
}
|
||||||
|
@ -11,21 +11,33 @@ import (
|
|||||||
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Error implements the net.Error interface
|
// ConnError implements the net.Error interface
|
||||||
type ConnError struct {
|
type ConnError struct {
|
||||||
error
|
error
|
||||||
timeout bool
|
timeout bool
|
||||||
temporary bool
|
temporary bool
|
||||||
|
maxsize int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Timeout returns true if the error relates to a timeout condition on the
|
||||||
|
// connection.
|
||||||
func (e *ConnError) Timeout() bool {
|
func (e *ConnError) Timeout() bool {
|
||||||
return e.timeout
|
return e.timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Temporary return true if the error is temporary or false if it is a permanent
|
||||||
|
// error condition.
|
||||||
func (e *ConnError) Temporary() bool {
|
func (e *ConnError) Temporary() bool {
|
||||||
return e.temporary
|
return e.temporary
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PacketTooBig returns in response to sending a packet that is too large, and
|
||||||
|
// if so, the maximum supported packet size that should be used for the
|
||||||
|
// connection.
|
||||||
|
func (e *ConnError) PacketTooBig() (bool, int) {
|
||||||
|
return e.maxsize > 0, e.maxsize
|
||||||
|
}
|
||||||
|
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
core *Core
|
core *Core
|
||||||
nodeID *crypto.NodeID
|
nodeID *crypto.NodeID
|
||||||
@ -166,7 +178,7 @@ func (c *Conn) Read(b []byte) (int, error) {
|
|||||||
select {
|
select {
|
||||||
case <-c.searchwait:
|
case <-c.searchwait:
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
return 0, ConnError{errors.New("Timeout"), true, false}
|
return 0, ConnError{errors.New("timeout"), true, false, 0}
|
||||||
}
|
}
|
||||||
// Retrieve our session info again
|
// Retrieve our session info again
|
||||||
c.mutex.RLock()
|
c.mutex.RLock()
|
||||||
@ -182,7 +194,7 @@ func (c *Conn) Read(b []byte) (int, error) {
|
|||||||
// Wait for some traffic to come through from the session
|
// Wait for some traffic to come through from the session
|
||||||
select {
|
select {
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
return 0, ConnError{errors.New("Timeout"), true, false}
|
return 0, ConnError{errors.New("timeout"), true, false, 0}
|
||||||
case p, ok := <-sinfo.recv:
|
case p, ok := <-sinfo.recv:
|
||||||
// If the session is closed then do nothing
|
// If the session is closed then do nothing
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -222,7 +234,7 @@ func (c *Conn) Read(b []byte) (int, error) {
|
|||||||
select { // Send to worker
|
select { // Send to worker
|
||||||
case sinfo.worker <- workerFunc:
|
case sinfo.worker <- workerFunc:
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
return 0, ConnError{errors.New("Timeout"), true, false}
|
return 0, ConnError{errors.New("timeout"), true, false, 0}
|
||||||
}
|
}
|
||||||
<-done // Wait for the worker to finish, failing this can cause memory errors (util.[Get||Put]Bytes stuff)
|
<-done // Wait for the worker to finish, failing this can cause memory errors (util.[Get||Put]Bytes stuff)
|
||||||
// Something went wrong in the session worker so abort
|
// Something went wrong in the session worker so abort
|
||||||
@ -260,8 +272,14 @@ func (c *Conn) Write(b []byte) (bytesWritten int, err error) {
|
|||||||
}
|
}
|
||||||
var packet []byte
|
var packet []byte
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
|
written := len(b)
|
||||||
workerFunc := func() {
|
workerFunc := func() {
|
||||||
defer close(done)
|
defer close(done)
|
||||||
|
// Does the packet exceed the permitted size for the session?
|
||||||
|
if uint16(len(b)) > sinfo.getMTU() {
|
||||||
|
written, err = 0, ConnError{errors.New("packet too big"), true, false, int(sinfo.getMTU())}
|
||||||
|
return
|
||||||
|
}
|
||||||
// Encrypt the packet
|
// Encrypt the packet
|
||||||
payload, nonce := crypto.BoxSeal(&sinfo.sharedSesKey, b, &sinfo.myNonce)
|
payload, nonce := crypto.BoxSeal(&sinfo.sharedSesKey, b, &sinfo.myNonce)
|
||||||
defer util.PutBytes(payload)
|
defer util.PutBytes(payload)
|
||||||
@ -282,14 +300,16 @@ func (c *Conn) Write(b []byte) (bytesWritten int, err error) {
|
|||||||
select { // Send to worker
|
select { // Send to worker
|
||||||
case sinfo.worker <- workerFunc:
|
case sinfo.worker <- workerFunc:
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
return 0, ConnError{errors.New("Timeout"), true, false}
|
return 0, ConnError{errors.New("timeout"), true, false, 0}
|
||||||
}
|
}
|
||||||
// Wait for the worker to finish, otherwise there are memory errors ([Get||Put]Bytes stuff)
|
// Wait for the worker to finish, otherwise there are memory errors ([Get||Put]Bytes stuff)
|
||||||
<-done
|
<-done
|
||||||
// Give the packet to the router
|
// Give the packet to the router
|
||||||
|
if written > 0 {
|
||||||
sinfo.core.router.out(packet)
|
sinfo.core.router.out(packet)
|
||||||
|
}
|
||||||
// Finally return the number of bytes we wrote
|
// Finally return the number of bytes we wrote
|
||||||
return len(b), nil
|
return written, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) Close() error {
|
func (c *Conn) Close() error {
|
||||||
|
Loading…
Reference in New Issue
Block a user