diff --git a/listener/tun/ipstack/gvisor/tundns.go b/listener/tun/ipstack/gvisor/tundns.go index 7fba6bbe..51368675 100644 --- a/listener/tun/ipstack/gvisor/tundns.go +++ b/listener/tun/ipstack/gvisor/tundns.go @@ -85,7 +85,8 @@ func (e *dnsEndpoint) HandlePacket(id stack.TransportEndpointID, pkt *stack.Pack var msg D.Msg msg.Unpack(pkt.Data().AsRange().ToOwnedView()) writer := dnsResponseWriter{s: e.stack, pkt: pkt, id: id} - log.Debugln("[DNS] hijack udp:%s:%d", id.LocalAddress.String(), id.LocalPort) + log.Debugln("[DNS] hijack udp:%s:%d from %s:%d", id.LocalAddress.String(), id.LocalPort, + id.RemoteAddress.String(), id.RemotePort) go e.server.ServeDNS(&writer, &msg) } @@ -139,9 +140,17 @@ func (w *dnsResponseWriter) Write(b []byte) (int, error) { v := buffer.NewView(len(b)) copy(v, b) data := v.ToVectorisedView() + // w.id.LocalAddress is the source ip of DNS response - r, _ := w.s.FindRoute(w.pkt.NICID, w.id.LocalAddress, w.id.RemoteAddress, w.pkt.NetworkProtocolNumber, false /* multicastLoop */) - return writeUDP(r, data, w.id.LocalPort, w.id.RemotePort) + if !w.pkt.NetworkHeader().View().IsEmpty() && + (w.pkt.NetworkProtocolNumber == ipv4.ProtocolNumber || + w.pkt.NetworkProtocolNumber == ipv6.ProtocolNumber) { + r, _ := w.s.FindRoute(w.pkt.NICID, w.id.LocalAddress, w.id.RemoteAddress, w.pkt.NetworkProtocolNumber, false /* multicastLoop */) + return writeUDP(r, data, w.id.LocalPort, w.id.RemotePort) + } else { + log.Debugln("the network protocl[%d] is not available", w.pkt.NetworkProtocolNumber) + return 0, fmt.Errorf("the network protocl[%d] is not available", w.pkt.NetworkProtocolNumber) + } } func (w *dnsResponseWriter) Close() error { diff --git a/listener/tun/ipstack/gvisor/utils.go b/listener/tun/ipstack/gvisor/utils.go index 44063f0b..7b1b2588 100644 --- a/listener/tun/ipstack/gvisor/utils.go +++ b/listener/tun/ipstack/gvisor/utils.go @@ -2,6 +2,9 @@ package gvisor import ( "fmt" + "github.com/Dreamacro/clash/log" + "gvisor.dev/gvisor/pkg/tcpip/network/ipv4" + "gvisor.dev/gvisor/pkg/tcpip/network/ipv6" "net" "github.com/Dreamacro/clash/component/resolver" @@ -40,8 +43,15 @@ func (c *fakeConn) WriteBack(b []byte, addr net.Addr) (n int, err error) { localPort = uint16(udpaddr.Port) } - r, _ := c.s.FindRoute(c.pkt.NICID, localAddress, c.id.RemoteAddress, c.pkt.NetworkProtocolNumber, false /* multicastLoop */) - return writeUDP(r, data, localPort, c.id.RemotePort) + if !c.pkt.NetworkHeader().View().IsEmpty() && + (c.pkt.NetworkProtocolNumber == ipv4.ProtocolNumber || + c.pkt.NetworkProtocolNumber == ipv6.ProtocolNumber) { + r, _ := c.s.FindRoute(c.pkt.NICID, localAddress, c.id.RemoteAddress, c.pkt.NetworkProtocolNumber, false /* multicastLoop */) + return writeUDP(r, data, localPort, c.id.RemotePort) + } else { + log.Debugln("the network protocl[%d] is not available", c.pkt.NetworkProtocolNumber) + return 0, fmt.Errorf("the network protocl[%d] is not available", c.pkt.NetworkProtocolNumber) + } } func (c *fakeConn) LocalAddr() net.Addr {