diff --git a/app/dns/nameserver_udp.go b/app/dns/nameserver_udp.go
index d68ffdd0..36747016 100644
--- a/app/dns/nameserver_udp.go
+++ b/app/dns/nameserver_udp.go
@@ -17,6 +17,7 @@ import (
 	"github.com/xtls/xray-core/common/session"
 	"github.com/xtls/xray-core/common/signal/pubsub"
 	"github.com/xtls/xray-core/common/task"
+	"github.com/xtls/xray-core/core"
 	dns_feature "github.com/xtls/xray-core/features/dns"
 	"github.com/xtls/xray-core/features/routing"
 	"github.com/xtls/xray-core/transport/internet/udp"
@@ -195,7 +196,7 @@ func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, client
 	for _, req := range reqs {
 		s.addPendingRequest(req)
 		b, _ := dns.PackMessage(req.msg)
-		udpCtx := context.Background()
+		udpCtx := core.ToBackgroundDetachedContext(ctx)
 		if inbound := session.InboundFromContext(ctx); inbound != nil {
 			udpCtx = session.ContextWithInbound(udpCtx, inbound)
 		}
diff --git a/core/context.go b/core/context.go
index 645ed277..d28ac7e3 100644
--- a/core/context.go
+++ b/core/context.go
@@ -25,3 +25,28 @@ func MustFromContext(ctx context.Context) *Instance {
 	}
 	return x
 }
+
+/* toContext returns ctx from the given context, or creates an Instance if the context doesn't find that.
+
+It is unsupported to use this function to create a context that is suitable to invoke Xray's internal component
+in third party code, you shouldn't use //go:linkname to alias of this function into your own package and
+use this function in your third party code.
+
+For third party code, usage enabled by creating a context to interact with Xray's internal component is unsupported,
+and may break at any time.
+
+*/
+func toContext(ctx context.Context, v *Instance) context.Context {
+	if FromContext(ctx) != v {
+		ctx = context.WithValue(ctx, xrayKey, v)
+	}
+	return ctx
+}
+
+/*ToBackgroundDetachedContext create a detached context from another context
+Internal API
+*/
+func ToBackgroundDetachedContext(ctx context.Context) context.Context {
+	instance := MustFromContext(ctx)
+	return toContext(context.Background(), instance)
+}
diff --git a/core/context_test.go b/core/context_test.go
index a16f6120..423585e1 100644
--- a/core/context_test.go
+++ b/core/context_test.go
@@ -5,9 +5,10 @@ import (
 	"testing"
 
 	. "github.com/xtls/xray-core/core"
+	_ "unsafe"
 )
 
-func TestContextPanic(t *testing.T) {
+func TestFromContextPanic(t *testing.T) {
 	defer func() {
 		r := recover()
 		if r == nil {
diff --git a/core/functions.go b/core/functions.go
index 11282462..7885fd14 100644
--- a/core/functions.go
+++ b/core/functions.go
@@ -15,7 +15,7 @@ import (
 func CreateObject(v *Instance, config interface{}) (interface{}, error) {
 	ctx := v.ctx
 	if v != nil {
-		ctx = context.WithValue(ctx, xrayKey, v)
+		ctx = toContext(v.ctx, v)
 	}
 	return common.CreateObject(ctx, config)
 }
@@ -46,10 +46,13 @@ func StartInstance(configFormat string, configBytes []byte) (*Instance, error) {
 //
 // xray:api:stable
 func Dial(ctx context.Context, v *Instance, dest net.Destination) (net.Conn, error) {
+	ctx = toContext(ctx, v)
+
 	dispatcher := v.GetFeature(routing.DispatcherType())
 	if dispatcher == nil {
 		return nil, newError("routing.Dispatcher is not registered in Xray core")
 	}
+
 	r, err := dispatcher.(routing.Dispatcher).Dispatch(ctx, dest)
 	if err != nil {
 		return nil, err
@@ -70,6 +73,8 @@ func Dial(ctx context.Context, v *Instance, dest net.Destination) (net.Conn, err
 //
 // xray:api:beta
 func DialUDP(ctx context.Context, v *Instance) (net.PacketConn, error) {
+	ctx = toContext(ctx, v)
+
 	dispatcher := v.GetFeature(routing.DispatcherType())
 	if dispatcher == nil {
 		return nil, newError("routing.Dispatcher is not registered in Xray core")