Files
Xray-core/transport/internet/masque/conn.go
T

130 lines
2.7 KiB
Go

package masque
import (
"context"
go_errors "errors"
"net/netip"
"slices"
"sync"
"time"
"github.com/apernet/quic-go"
"github.com/apernet/quic-go/http3"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet/masque/connectip"
)
type PacketTooBigError struct {
ICMP []byte
}
func (e *PacketTooBigError) Error() string {
return "packet too big for the tunnel"
}
type httpConn interface {
LocalAddr() net.Addr
RemoteAddr() net.Addr
Close() error
}
type quicConn struct {
*quic.Conn
}
func (c quicConn) Close() error {
return c.CloseWithError(quic.ApplicationErrorCode(http3.ErrCodeNoError), "")
}
type Conn struct {
ipConn *connectip.Conn
httpConn httpConn
local []netip.Addr
closeOnce sync.Once
}
func (c *Conn) LocalAddrs() []netip.Addr {
return c.local
}
func (c *Conn) Read(b []byte) (int, error) {
return c.ipConn.ReadPacket(b)
}
func (c *Conn) Write(b []byte) (int, error) {
icmp, err := c.ipConn.WritePacket(b)
if err != nil {
if go_errors.Is(err, connectip.ErrMTUTooSmall) {
errors.LogWarning(context.Background(), "MASQUE: closing the tunnel as it cannot carry ", MinPacketSize, "-byte packets")
} else {
errors.LogInfoInner(context.Background(), err, "MASQUE: closing the tunnel as sending failed")
}
c.Close()
return 0, err
}
if len(icmp) > 0 {
return 0, &PacketTooBigError{ICMP: icmp}
}
return len(b), nil
}
func (c *Conn) Close() error {
c.closeOnce.Do(func() {
c.ipConn.Close()
c.httpConn.Close()
})
return nil
}
func (c *Conn) LocalAddr() net.Addr {
return c.httpConn.LocalAddr()
}
func (c *Conn) RemoteAddr() net.Addr {
return c.httpConn.RemoteAddr()
}
func (c *Conn) SetDeadline(time.Time) error {
return nil
}
func (c *Conn) SetReadDeadline(time.Time) error {
return nil
}
func (c *Conn) SetWriteDeadline(time.Time) error {
return nil
}
func (c *Conn) serveAddressAssignments() {
for {
assigned, err := c.ipConn.ReceiveAddressAssignment(context.Background())
if err != nil {
return
}
for _, addr := range c.local {
if !slices.ContainsFunc(assigned, func(a connectip.AssignedAddress) bool { return !a.Rejected() && a.IPPrefix.Contains(addr) }) {
errors.LogInfo(context.Background(), "MASQUE: closing the tunnel as the proxy withdrew ", addr)
c.Close()
return
}
}
if len(localAddrs(assigned)) > len(c.local) {
errors.LogInfo(context.Background(), "MASQUE: the proxy assigned another IP family, which is used once the tunnel is set up again")
}
}
}
func (c *Conn) serveAddressRequests() {
for {
req, err := c.ipConn.ReceiveAddressRequest(context.Background())
if err != nil {
return
}
if err := req.Respond(make([]netip.Prefix, len(req.Prefixes)), nil); err != nil {
return
}
}
}