Skip to content

Commit

Permalink
Implement TCP and ICMP rejects
Browse files Browse the repository at this point in the history
  • Loading branch information
nekohasekai committed Oct 22, 2024
1 parent 1962bf3 commit 8ae8c91
Show file tree
Hide file tree
Showing 7 changed files with 254 additions and 105 deletions.
28 changes: 11 additions & 17 deletions stack_gvisor.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
)

const WithGVisor = true
Expand Down Expand Up @@ -79,7 +80,7 @@ func (t *GVisor) Start() error {
tcpForwarder := tcp.NewForwarder(ipStack, 0, 1024, func(r *tcp.ForwarderRequest) {
source := M.SocksaddrFrom(AddrFromAddress(r.ID().RemoteAddress), r.ID().RemotePort)
destination := M.SocksaddrFrom(AddrFromAddress(r.ID().LocalAddress), r.ID().LocalPort)
pErr := t.handler.PrepareConnection(source, destination)
pErr := t.handler.PrepareConnection(N.NetworkTCP, source, destination)
if pErr != nil {
r.Complete(gWriteUnreachable(t.stack, r.Packet(), err) == os.ErrInvalid)
return
Expand All @@ -96,28 +97,21 @@ func (t *GVisor) Start() error {
ipStack.SetTransportProtocolHandler(tcp.ProtocolNumber, tcpForwarder.HandlePacket)
if !t.endpointIndependentNat {
udpForwarder := udp.NewForwarder(ipStack, func(r *udp.ForwarderRequest) {
source := M.SocksaddrFrom(AddrFromAddress(r.ID().RemoteAddress), r.ID().RemotePort)
destination := M.SocksaddrFrom(AddrFromAddress(r.ID().LocalAddress), r.ID().LocalPort)
pErr := t.handler.PrepareConnection(N.NetworkUDP, source, destination)
if pErr != nil {
gWriteUnreachable(t.stack, r.Packet(), err)
r.Packet().DecRef()
return
}
var wq waiter.Queue
endpoint, err := r.CreateEndpoint(&wq)
if err != nil {
return
}
udpConn := gonet.NewUDPConn(&wq, endpoint)
lAddr := udpConn.RemoteAddr()
rAddr := udpConn.LocalAddr()
if lAddr == nil || rAddr == nil {
endpoint.Abort()
return
}
source := M.SocksaddrFromNet(lAddr)
destination := M.SocksaddrFromNet(rAddr)
pErr := t.handler.PrepareConnection(source, destination)
if pErr != nil {
gWriteUnreachable(t.stack, r.Packet(), pErr)
r.Packet().DecRef()
return
}
go func() {
ctx, conn := canceler.NewPacketConn(t.ctx, bufio.NewUnbindPacketConnWithAddr(udpConn, destination), time.Duration(t.udpTimeout)*time.Second)
ctx, conn := canceler.NewPacketConn(t.ctx, bufio.NewUnbindPacketConnWithAddr(gonet.NewUDPConn(&wq, endpoint), destination), t.udpTimeout)
t.handler.NewPacketConnectionEx(ctx, conn, source, destination, nil)
}()
})
Expand Down
6 changes: 3 additions & 3 deletions stack_gvisor_lazy.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,15 +199,15 @@ func gWriteUnreachable(gStack *stack.Stack, packet *stack.PacketBuffer, err erro
return nil
} else if errors.Is(err, syscall.ENETUNREACH) {
if packet.NetworkProtocolNumber == header.IPv4ProtocolNumber {
return gWriteUnreachable4(gStack, packet, stack.RejectIPv4WithICMPNetProhibited)
return gWriteUnreachable4(gStack, packet, stack.RejectIPv4WithICMPNetUnreachable)
} else {
return gWriteUnreachable6(gStack, packet, stack.RejectIPv6WithICMPNoRoute)
}
} else if errors.Is(err, syscall.EHOSTUNREACH) {
if packet.NetworkProtocolNumber == header.IPv4ProtocolNumber {
return gWriteUnreachable4(gStack, packet, stack.RejectIPv4WithICMPHostProhibited)
return gWriteUnreachable4(gStack, packet, stack.RejectIPv4WithICMPHostUnreachable)
} else {
return gWriteUnreachable6(gStack, packet, stack.RejectIPv6WithICMPNoRoute)
return gWriteUnreachable6(gStack, packet, stack.RejectIPv6WithICMPAddrUnreachable)
}
} else if errors.Is(err, syscall.ECONNREFUSED) {
if packet.NetworkProtocolNumber == header.IPv4ProtocolNumber {
Expand Down
2 changes: 1 addition & 1 deletion stack_gvisor_udp.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func (f *UDPForwarder) HandlePacket(id stack.TransportEndpointID, pkt *stack.Pac
func rangeIterate(r stack.Range, fn func(*buffer.View))

func (f *UDPForwarder) PreparePacketConnection(source M.Socksaddr, destination M.Socksaddr, userData any) (bool, context.Context, N.PacketWriter, N.CloseHandlerFunc) {
pErr := f.handler.PrepareConnection(source, destination)
pErr := f.handler.PrepareConnection(N.NetworkUDP, source, destination)
if pErr != nil {
gWriteUnreachable(f.stack, userData.(*stack.PacketBuffer), pErr)
return false, nil, nil, nil
Expand Down
28 changes: 13 additions & 15 deletions stack_mixed.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
package tun

import (
"time"

"github.com/sagernet/gvisor/pkg/buffer"
"github.com/sagernet/gvisor/pkg/tcpip"
"github.com/sagernet/gvisor/pkg/tcpip/adapters/gonet"
Expand All @@ -18,6 +16,7 @@ import (
"github.com/sagernet/sing/common/canceler"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
)

type Mixed struct {
Expand Down Expand Up @@ -51,23 +50,22 @@ func (m *Mixed) Start() error {
return err
}
if !m.endpointIndependentNat {
udpForwarder := udp.NewForwarder(ipStack, func(request *udp.ForwarderRequest) {
var wq waiter.Queue
endpoint, err := request.CreateEndpoint(&wq)
if err != nil {
udpForwarder := udp.NewForwarder(ipStack, func(r *udp.ForwarderRequest) {
source := M.SocksaddrFrom(AddrFromAddress(r.ID().RemoteAddress), r.ID().RemotePort)
destination := M.SocksaddrFrom(AddrFromAddress(r.ID().LocalAddress), r.ID().LocalPort)
pErr := m.handler.PrepareConnection(N.NetworkUDP, source, destination)
if pErr != nil {
gWriteUnreachable(m.stack, r.Packet(), err)
r.Packet().DecRef()
return
}
udpConn := gonet.NewUDPConn(&wq, endpoint)
lAddr := udpConn.RemoteAddr()
rAddr := udpConn.LocalAddr()
if lAddr == nil || rAddr == nil {
endpoint.Abort()
var wq waiter.Queue
endpoint, err := r.CreateEndpoint(&wq)
if err != nil {
return
}
go func() {
source := M.SocksaddrFromNet(lAddr)
destination := M.SocksaddrFromNet(rAddr)
ctx, conn := canceler.NewPacketConn(m.ctx, bufio.NewUnbindPacketConnWithAddr(udpConn, destination), time.Duration(m.udpTimeout)*time.Second)
ctx, conn := canceler.NewPacketConn(m.ctx, bufio.NewUnbindPacketConnWithAddr(gonet.NewUDPConn(&wq, endpoint), destination), m.udpTimeout)
m.handler.NewPacketConnectionEx(ctx, conn, source, destination, nil)
}()
})
Expand Down Expand Up @@ -229,7 +227,7 @@ func (m *Mixed) processIPv6(ipHdr header.IPv6) (writeBack bool, err error) {
}
switch ipHdr.TransportProtocol() {
case header.TCPProtocolNumber:
err = m.processIPv6TCP(ipHdr, ipHdr.Payload())
writeBack, err = m.processIPv6TCP(ipHdr, ipHdr.Payload())
case header.UDPProtocolNumber:
writeBack = false
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
Expand Down
Loading

0 comments on commit 8ae8c91

Please sign in to comment.