mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-09-30 13:05:43 +00:00
https://github.com/XTLS/Xray-core/pull/6807#issuecomment-5808933074 https://github.com/XTLS/Xray-core/pull/6810#issuecomment-5842441136
130 lines
2.7 KiB
Go
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
|
|
}
|
|
}
|
|
}
|