Browse Source

Fix bugs and add UoT option for naiveproxy outbound

世界 1 week ago
parent
commit
b6b8c52411

+ 1 - 1
.github/CRONET_GO_VERSION

@@ -1 +1 @@
-3fb4098ed7e4ffe2e3d9593a744fc3717dbb369b
+fe7ab107d3a222ca878b9a727d76075938ee7cde

+ 1 - 0
.github/update_cronet.sh

@@ -8,5 +8,6 @@ PROJECTS=$SCRIPT_DIR/../..
 git -C $PROJECTS/cronet-go fetch origin main
 git -C $PROJECTS/cronet-go fetch origin go
 go get -x github.com/sagernet/cronet-go/all@$(git -C $PROJECTS/cronet-go rev-parse origin/go)
+go get -x github.com/sagernet/cronet-go@$(git -C $PROJECTS/cronet-go rev-parse origin/go)
 go mod tidy
 git -C $PROJECTS/cronet-go rev-parse origin/HEAD > "$SCRIPT_DIR/CRONET_GO_VERSION"

+ 17 - 11
.github/workflows/build.yml

@@ -69,19 +69,21 @@ jobs:
     strategy:
       matrix:
         include:
-          - { os: linux, arch: amd64, variant: purego, debian: amd64, rpm: x86_64, pacman: x86_64, openwrt: "x86_64" }
-          - { os: linux, arch: amd64, variant: glibc, naive: true, debian: amd64, rpm: x86_64, pacman: x86_64, openwrt: "x86_64" }
-          - { os: linux, arch: amd64, variant: musl, naive: true }
+          - { os: linux, arch: amd64, variant: purego, openwrt: "x86_64" }
+          - { os: linux, arch: amd64, variant: glibc, naive: true }
+          - { os: linux, arch: amd64, variant: musl, naive: true, debian: amd64, rpm: x86_64, pacman: x86_64, openwrt: "x86_64" }
 
-          - { os: linux, arch: arm64, variant: purego, debian: arm64, rpm: aarch64, pacman: aarch64, openwrt: "aarch64_cortex-a53 aarch64_cortex-a72 aarch64_cortex-a76 aarch64_generic" }
-          - { os: linux, arch: arm64, variant: glibc, naive: true, debian: arm64, rpm: aarch64, pacman: aarch64, openwrt: "aarch64_cortex-a53 aarch64_cortex-a72 aarch64_cortex-a76 aarch64_generic" }
-          - { os: linux, arch: arm64, variant: musl, naive: true }
+          - { os: linux, arch: arm64, variant: purego, openwrt: "aarch64_cortex-a53 aarch64_cortex-a72 aarch64_cortex-a76 aarch64_generic" }
+          - { os: linux, arch: arm64, variant: glibc, naive: true }
+          - { os: linux, arch: arm64, variant: musl, naive: true, debian: arm64, rpm: aarch64, pacman: aarch64, openwrt: "aarch64_cortex-a53 aarch64_cortex-a72 aarch64_cortex-a76 aarch64_generic" }
 
-          - { os: linux, arch: "386", variant: glibc, naive: true, go386: sse2, debian: i386, rpm: i386, openwrt: "i386_pentium4" }
-          - { os: linux, arch: "386", variant: musl, naive: true, go386: sse2 }
+          - { os: linux, arch: "386", go386: sse2, openwrt: "i386_pentium4" }
+          - { os: linux, arch: "386", variant: glibc, naive: true, go386: sse2 }
+          - { os: linux, arch: "386", variant: musl, naive: true, go386: sse2, debian: i386, rpm: i386, openwrt: "i386_pentium4" }
 
-          - { os: linux, arch: arm, variant: glibc, naive: true, goarm: "7", debian: armhf, rpm: armv7hl, pacman: armv7hl, openwrt: "arm_cortex-a5_vfpv4 arm_cortex-a7_neon-vfpv4 arm_cortex-a7_vfpv4 arm_cortex-a8_vfpv3 arm_cortex-a9_neon arm_cortex-a9_vfpv3-d16 arm_cortex-a15_neon-vfpv4" }
-          - { os: linux, arch: arm, variant: musl, naive: true, goarm: "7" }
+          - { os: linux, arch: arm, goarm: "7", openwrt: "arm_cortex-a5_vfpv4 arm_cortex-a7_neon-vfpv4 arm_cortex-a7_vfpv4 arm_cortex-a8_vfpv3 arm_cortex-a9_neon arm_cortex-a9_vfpv3-d16 arm_cortex-a15_neon-vfpv4" }
+          - { os: linux, arch: arm, variant: glibc, naive: true, goarm: "7" }
+          - { os: linux, arch: arm, variant: musl, naive: true, goarm: "7", debian: armhf, rpm: armv7hl, pacman: armv7hl, openwrt: "arm_cortex-a5_vfpv4 arm_cortex-a7_neon-vfpv4 arm_cortex-a7_vfpv4 arm_cortex-a8_vfpv3 arm_cortex-a9_neon arm_cortex-a9_vfpv3-d16 arm_cortex-a15_neon-vfpv4" }
 
           - { os: linux, arch: "386", go386: softfloat, openwrt: "i386_pentium-mmx" }
           - { os: linux, arch: arm, goarm: "5", openwrt: "arm_arm926ej-s arm_cortex-a7 arm_cortex-a9 arm_fa526 arm_xscale" }
@@ -362,8 +364,12 @@ jobs:
             -p "dist/openwrt.deb" \
             --architecture all \
             dist/sing-box=/usr/bin/sing-box
+          SUFFIX=""
+          if [[ "${{ matrix.variant }}" == "musl" ]]; then
+            SUFFIX="_musl"
+          fi
           for architecture in ${{ matrix.openwrt }}; do
-            .github/deb2ipk.sh "$architecture" "dist/openwrt.deb" "dist/sing-box_${{ needs.calculate_version.outputs.version }}_openwrt_${architecture}.ipk"
+            .github/deb2ipk.sh "$architecture" "dist/openwrt.deb" "dist/sing-box_${{ needs.calculate_version.outputs.version }}_openwrt_${architecture}${SUFFIX}.ipk"
           done
           rm "dist/openwrt.deb"
       - name: Archive

+ 11 - 2
docs/configuration/outbound/naive.md

@@ -1,6 +1,8 @@
-!!! quote "Changes in sing-box 1.13.0"
+---
+icon: material/new-box
+---
 
-    :material-plus: Initial release
+!!! question "Since sing-box 1.13.0"
 
 ### Structure
 
@@ -15,6 +17,7 @@
   "password": "password",
   "insecure_concurrency": 0,
   "extra_headers": {},
+  "udp_over_tcp": false | {},
   "tls": {},
 
   ... // Dial Fields
@@ -55,6 +58,12 @@ Number of concurrent tunnel connections. Multiple connections make the tunneling
 
 Extra headers to send in HTTP requests.
 
+#### udp_over_tcp
+
+UDP over TCP protocol settings.
+
+See [UDP Over TCP](/configuration/shared/udp-over-tcp/) for details.
+
 #### tls
 
 ==Required==

+ 11 - 2
docs/configuration/outbound/naive.zh.md

@@ -1,6 +1,8 @@
-!!! quote "sing-box 1.13.0 中的更改"
+---
+icon: material/new-box
+---
 
-    :material-plus: 初始版本
+!!! question "自 sing-box 1.13.0 起"
 
 ### 结构
 
@@ -15,6 +17,7 @@
   "password": "password",
   "insecure_concurrency": 0,
   "extra_headers": {},
+  "udp_over_tcp": false | {},
   "tls": {},
 
   ... // 拨号字段
@@ -55,6 +58,12 @@
 
 HTTP 请求中发送的额外头部。
 
+#### udp_over_tcp
+
+UDP over TCP 配置。
+
+参阅 [UDP Over TCP](/zh/configuration/shared/udp-over-tcp/)。
+
 #### tls
 
 ==必填==

+ 25 - 25
go.mod

@@ -25,8 +25,8 @@ require (
 	github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1
 	github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a
 	github.com/sagernet/cors v1.2.1
-	github.com/sagernet/cronet-go v0.0.1-140.0.7339.123-1
-	github.com/sagernet/cronet-go/all v0.0.0-20251213155601-2094cc48331c
+	github.com/sagernet/cronet-go v0.0.0-20251215064722-77bfb8fdd9f7
+	github.com/sagernet/cronet-go/all v0.0.0-20251215064722-77bfb8fdd9f7
 	github.com/sagernet/fswatch v0.1.1
 	github.com/sagernet/gomobile v0.1.10
 	github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1
@@ -107,29 +107,29 @@ require (
 	github.com/prometheus-community/pro-bing v0.4.0 // indirect
 	github.com/quic-go/qpack v0.6.0 // indirect
 	github.com/safchain/ethtool v0.3.0 // indirect
-	github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251213155152-e4fff13128e6 // indirect
-	github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251213155152-e4fff13128e6 // indirect
+	github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251215064325-26e9598ca37b // indirect
+	github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251215064325-26e9598ca37b // indirect
 	github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
 	github.com/sagernet/nftables v0.3.0-beta.4 // indirect
 	github.com/spf13/pflag v1.0.6 // indirect

+ 50 - 50
go.sum

@@ -152,56 +152,56 @@ github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkk
 github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM=
 github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ=
 github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI=
-github.com/sagernet/cronet-go v0.0.1-140.0.7339.123-1 h1:ql2eCQp1sIinoSwNcJW+tBGToRoxm0rsU8uqRJA9Vao=
-github.com/sagernet/cronet-go v0.0.1-140.0.7339.123-1/go.mod h1:DzcRxPQdpy5y2bbabpFXotAzPfY2P4HKZ8rQj3dSClo=
-github.com/sagernet/cronet-go/all v0.0.0-20251213155601-2094cc48331c h1:3qNxvssYmfARhUtSFRbleSeSVoShwUEoxl42hqL75hA=
-github.com/sagernet/cronet-go/all v0.0.0-20251213155601-2094cc48331c/go.mod h1:/liG19g+SCq7pyaZtUHeGqUWckKfdMjR0DR83hNcxdw=
-github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251213155152-e4fff13128e6 h1:/4EvUgxjKFPSnlitNV90te7p4/Ywpxz1/zJuB8BT5Qs=
-github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251213155152-e4fff13128e6/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw=
-github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251213155152-e4fff13128e6 h1:HgpJekgPVMKdODAmz6MwPBzz6dq4nImGy/5/jqD1N90=
-github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251213155152-e4fff13128e6/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM=
-github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251213155152-e4fff13128e6 h1:3YsRLuWT0vEjIgsSdv8g45RuOMUDloO1rEsW/990CPQ=
-github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251213155152-e4fff13128e6/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc=
-github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251213155152-e4fff13128e6 h1:1TwUqHR7/gV1hTxuhlu4qWlIN5IpPWkVA/0E8Bdjtgo=
-github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251213155152-e4fff13128e6/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ=
-github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251213155152-e4fff13128e6 h1:FdA9JPgmoPYHxNgqKMyNztNyOFsxdrRvGOCxMIlHnjg=
-github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251213155152-e4fff13128e6/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs=
-github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251213155152-e4fff13128e6 h1:69q8UN4r6wy15I7VGILeApQLYUMfeFzO+uZBA68vqpM=
-github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251213155152-e4fff13128e6/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0=
-github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20251213155152-e4fff13128e6 h1:2QBSQdCMrsAQOugFvgsPJpDc+JQsS6JP/JBId1YxX/g=
-github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20251213155152-e4fff13128e6/go.mod h1:hkQzRE5GDbaH1/ioqYh0Taho4L6i0yLRCVEZ5xHz5M0=
-github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251213155152-e4fff13128e6 h1:4SUxagz2PuS7I3jNf55K50ALHtVyvV8PF2/1wnfssMk=
-github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251213155152-e4fff13128e6/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4=
-github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20251213155152-e4fff13128e6 h1:5tkFlEyQ9zF4AX7asWePmwF3hQSdrrf3a8EaQ7mJ0IE=
-github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20251213155152-e4fff13128e6/go.mod h1:M/pN6m3j0HFU6/y83n0HU6GLYys3tYdr/xTE8hVEGMo=
-github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251213155152-e4fff13128e6 h1:lLnVN2IC00au+Vc4V2ijAWdbzlXg9r/bLxm50gKT7i4=
-github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251213155152-e4fff13128e6/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ=
-github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251213155152-e4fff13128e6 h1:SUhkusdTwrPZdrUTlyyF6NcnCdET2f1TFdE4+d6YVDI=
-github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251213155152-e4fff13128e6/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU=
-github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251213155152-e4fff13128e6 h1:aFFVgvDDBuNJKrU6Bw5btlLsX+JLyXatXmHK7KePT+c=
-github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251213155152-e4fff13128e6/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI=
-github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251213155152-e4fff13128e6 h1:VW5xkrH8Quve1UC5Py37KYHLrJN9vgLJc+raIUO6d/Q=
-github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251213155152-e4fff13128e6/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ=
-github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251213155152-e4fff13128e6 h1:YQIccJVMwMPo9yy7VB0Un/fnSMt7nDh9NS/kwfctpPA=
-github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251213155152-e4fff13128e6/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0=
-github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251213155152-e4fff13128e6 h1:dyRIgfMHkCKaSOPyjYFbXmVJDTEoSRQlk6mgBN7RuUA=
-github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251213155152-e4fff13128e6/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s=
-github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251213155152-e4fff13128e6 h1:N/4oDOsP5lCNoy8UGo4v+LdCRXOnG+uzLLNhywuaQVU=
-github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251213155152-e4fff13128e6/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ=
-github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251213155152-e4fff13128e6 h1:AsYRIu6HEZ5+1ONzzsGEk6kGJzIKPflhIXhviRQUuHg=
-github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251213155152-e4fff13128e6/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow=
-github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20251213155152-e4fff13128e6 h1:63TxOukZ5bMPrQurR2S6RPCRFydKErBCJq4oLA+lPb4=
-github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20251213155152-e4fff13128e6/go.mod h1:aaX0YGl8nhGmfRWI8bc3BtDjY8Vzx6O0cS/e1uqxDq4=
-github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20251213155152-e4fff13128e6 h1:WO4WmUXYh0TqmGLQ5SQyk4A05l+GSKcoFyBzW8I7kd0=
-github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20251213155152-e4fff13128e6/go.mod h1:EdzMKA96xITc42QEI+ct4SwqX8Dn3ltKK8wzdkLWpSc=
-github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20251213155152-e4fff13128e6 h1:WQU1wWPwKOENmaSD68ltFdnn/FrdLpjJzNMjkeLGmyA=
-github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20251213155152-e4fff13128e6/go.mod h1:qix4kv1TTAJ5tY4lJ9vjhe9EY4mM+B7H5giOhbxDVcc=
-github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251213155152-e4fff13128e6 h1:1rweIHAKs+8yc1VZ/N4kod9RPJARgF5gDc4e1wh6rQo=
-github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251213155152-e4fff13128e6/go.mod h1:rnS7D+ULJX2PrP0Cy+05GS0mRZ2PP6+gVSroZKt8fjk=
-github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251213155152-e4fff13128e6 h1:NNcFjL2/F3Ux8mJuSAJKmMGcrLmkdas1X9DWuvY7BKU=
-github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251213155152-e4fff13128e6/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8=
-github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251213155152-e4fff13128e6 h1:TCgnN8XGroby1RkMKZgaQjCKKlVlmERtaNokKW4nyyo=
-github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251213155152-e4fff13128e6/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw=
+github.com/sagernet/cronet-go v0.0.0-20251215064722-77bfb8fdd9f7 h1:jb/nr5YECJ56gcAphQ7tBWierrBbaLT7v1MI9n3e/Gw=
+github.com/sagernet/cronet-go v0.0.0-20251215064722-77bfb8fdd9f7/go.mod h1:DzcRxPQdpy5y2bbabpFXotAzPfY2P4HKZ8rQj3dSClo=
+github.com/sagernet/cronet-go/all v0.0.0-20251215064722-77bfb8fdd9f7 h1:6PjoWjKnYrz/HmEezV1Z5K39EC8l+sek1V14aXlslyc=
+github.com/sagernet/cronet-go/all v0.0.0-20251215064722-77bfb8fdd9f7/go.mod h1:SrXj1iQMVqZcy8XINBJOhlBncfCe7DimX6mTRY+rdDw=
+github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251215064325-26e9598ca37b h1:+Dk1yBvaKl49l8j3YFoEvraAdt7VMy7n2Qzrs40/ekI=
+github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251215064325-26e9598ca37b/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw=
+github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251215064325-26e9598ca37b h1:tjkKLyRhD1ePdl48SjW38o7yjW1fCJ2x2nyvq5e/8oE=
+github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251215064325-26e9598ca37b/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM=
+github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251215064325-26e9598ca37b h1:P++HSm1JhmkKbDskFNfQuR8aCTg5uEWe2/5qFfj+6YU=
+github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251215064325-26e9598ca37b/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc=
+github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251215064325-26e9598ca37b h1:Rbo1r5Mk8yWlZTC8gcyuQFv2BXUI1/wWMC9Vc+cJNQ8=
+github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251215064325-26e9598ca37b/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ=
+github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251215064325-26e9598ca37b h1:VA1M5Yw09HiBD+Zemq6mOBVwBd4pr47LMN9WKOVf62Q=
+github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251215064325-26e9598ca37b/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs=
+github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251215064325-26e9598ca37b h1:AdWIsXfKxH3/hGjiYqcUSc0fb+R4vONjfRaO0emwdNA=
+github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251215064325-26e9598ca37b/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0=
+github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20251215064325-26e9598ca37b h1:sg8SupaVsj0Krc4DKSC1n2quig08bRtmsF0/iwwXeAI=
+github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20251215064325-26e9598ca37b/go.mod h1:hkQzRE5GDbaH1/ioqYh0Taho4L6i0yLRCVEZ5xHz5M0=
+github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251215064325-26e9598ca37b h1:0dmsm/vEAYxQjtH4sS/A8X6bf6YqS0I0Vc6oDZdnlRc=
+github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251215064325-26e9598ca37b/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4=
+github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20251215064325-26e9598ca37b h1:jnT/bYjzvdfGVgPEgZX0Mi0qkm8qcU/DluV+TqShVPg=
+github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20251215064325-26e9598ca37b/go.mod h1:M/pN6m3j0HFU6/y83n0HU6GLYys3tYdr/xTE8hVEGMo=
+github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251215064325-26e9598ca37b h1:/NqFcrdXS3e3Ad+ILfrwXFw3urwwFsQ1XxrDW9PkU4E=
+github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251215064325-26e9598ca37b/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ=
+github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251215064325-26e9598ca37b h1:vqeLRyeHq++RCcuUriJflTQne7hldEVJ19Or0xwCIrs=
+github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251215064325-26e9598ca37b/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU=
+github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251215064325-26e9598ca37b h1:Xr7dFoKy0o2YdPl2JcU7GtM4NxQyS8vGovd6Aw4pX8I=
+github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251215064325-26e9598ca37b/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI=
+github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251215064325-26e9598ca37b h1:GEt+x1qXt8xicDSD4GXOHs0WrVec5HAo+HmBAXzkidg=
+github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251215064325-26e9598ca37b/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ=
+github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251215064325-26e9598ca37b h1:MbjH6TmLoXlAkBWoUzuNF2w0FPfOMY6Rj9T226fe858=
+github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251215064325-26e9598ca37b/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0=
+github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251215064325-26e9598ca37b h1:AP85VNYiACL8QQeXqCUB8hz5hFOUtgwReLELRhve/4c=
+github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251215064325-26e9598ca37b/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s=
+github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251215064325-26e9598ca37b h1:4uNGGiOrJsa2S+PteucoO/Qyzz7FWHNJw2ezOkS7QiM=
+github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251215064325-26e9598ca37b/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ=
+github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251215064325-26e9598ca37b h1:N5yoxOlynwvTgaJnEOsL3iuI6FFmDJy1toyNSU+vlLA=
+github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251215064325-26e9598ca37b/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow=
+github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20251215064325-26e9598ca37b h1:JKyBNyt/DWAutvuDFjFTi0dMe0bh5zG7UUpZHH8Uqzo=
+github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20251215064325-26e9598ca37b/go.mod h1:aaX0YGl8nhGmfRWI8bc3BtDjY8Vzx6O0cS/e1uqxDq4=
+github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20251215064325-26e9598ca37b h1:m0sCMM6ry0+eXBuTPLGY9JYOVcIvtHcDEcstMo+oSTU=
+github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20251215064325-26e9598ca37b/go.mod h1:EdzMKA96xITc42QEI+ct4SwqX8Dn3ltKK8wzdkLWpSc=
+github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20251215064325-26e9598ca37b h1:UURnlFD48/9wn7cdi1NqYQuTvJZEFuQShxX8pvk2Fsg=
+github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20251215064325-26e9598ca37b/go.mod h1:qix4kv1TTAJ5tY4lJ9vjhe9EY4mM+B7H5giOhbxDVcc=
+github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251215064325-26e9598ca37b h1:jhwpI5IXK5RPvbk9+xUV9GAw2QeRZvcZprp4bJOP9e0=
+github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251215064325-26e9598ca37b/go.mod h1:rnS7D+ULJX2PrP0Cy+05GS0mRZ2PP6+gVSroZKt8fjk=
+github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251215064325-26e9598ca37b h1:qoleSwhzgH6jDSwqktbJCPDex4yMWtijcouGR8+BL+s=
+github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251215064325-26e9598ca37b/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8=
+github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251215064325-26e9598ca37b h1:v7eakED1u8ZTKjmqxa+Eu0S5ewK+r+mfEf9KI6ymu+I=
+github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251215064325-26e9598ca37b/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw=
 github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs=
 github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o=
 github.com/sagernet/gomobile v0.1.10 h1:ElqZ0OVDvyQlU91MU0C9cfU0FrILBbc65+NOKzZ1t0c=

+ 1 - 0
mkdocs.yml

@@ -158,6 +158,7 @@ nav:
           - Shadowsocks: configuration/outbound/shadowsocks.md
           - VMess: configuration/outbound/vmess.md
           - Trojan: configuration/outbound/trojan.md
+          - Naive: configuration/outbound/naive.md
           - WireGuard: configuration/outbound/wireguard.md
           - Hysteria: configuration/outbound/hysteria.md
           - ShadowTLS: configuration/outbound/shadowtls.md

+ 1 - 0
option/naive.go

@@ -19,5 +19,6 @@ type NaiveOutboundOptions struct {
 	Password            string               `json:"password,omitempty"`
 	InsecureConcurrency int                  `json:"insecure_concurrency,omitempty"`
 	ExtraHeaders        badoption.HTTPHeader `json:"extra_headers,omitempty"`
+	UDPOverTCP          *UDPOverTCPOptions   `json:"udp_over_tcp,omitempty"`
 	OutboundTLSOptionsContainer
 }

+ 61 - 34
protocol/naive/outbound.go

@@ -16,10 +16,12 @@ import (
 	C "github.com/sagernet/sing-box/constant"
 	"github.com/sagernet/sing-box/log"
 	"github.com/sagernet/sing-box/option"
+	"github.com/sagernet/sing/common"
 	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"
+	"github.com/sagernet/sing/common/uot"
 )
 
 func RegisterOutbound(registry *outbound.Registry) {
@@ -28,9 +30,10 @@ func RegisterOutbound(registry *outbound.Registry) {
 
 type Outbound struct {
 	outbound.Adapter
-	ctx    context.Context
-	logger logger.ContextLogger
-	client *cronet.NaiveClient
+	ctx       context.Context
+	logger    logger.ContextLogger
+	client    *cronet.NaiveClient
+	uotClient *uot.Client
 }
 
 func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.NaiveOutboundOptions) (adapter.Outbound, error) {
@@ -119,61 +122,85 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
 	}
 
 	client, err := cronet.NewNaiveClient(cronet.NaiveClientConfig{
-		Context:                    ctx,
-		ServerAddress:              serverAddress,
-		ServerName:                 serverName,
-		Username:                   options.Username,
-		Password:                   options.Password,
-		Concurrency:                options.InsecureConcurrency,
-		ExtraHeaders:               extraHeaders,
-		TrustedRootCertificates:    trustedRootCertificates,
-		CertificatePublicKeySHA256: options.TLS.CertificatePublicKeySHA256,
-		Dialer:                     outboundDialer,
+		Context:                           ctx,
+		ServerAddress:                     serverAddress,
+		ServerName:                        serverName,
+		Username:                          options.Username,
+		Password:                          options.Password,
+		InsecureConcurrency:               options.InsecureConcurrency,
+		ExtraHeaders:                      extraHeaders,
+		TrustedRootCertificates:           trustedRootCertificates,
+		TrustedCertificatePublicKeySHA256: options.TLS.CertificatePublicKeySHA256,
+		Dialer:                            outboundDialer,
 	})
 	if err != nil {
 		return nil, err
 	}
 
+	var uotClient *uot.Client
+	uotOptions := common.PtrValueOrDefault(options.UDPOverTCP)
+	if uotOptions.Enabled {
+		uotClient = &uot.Client{
+			Dialer:  &naiveDialer{client},
+			Version: uotOptions.Version,
+		}
+	}
 	return &Outbound{
-		Adapter: outbound.NewAdapterWithDialerOptions(C.TypeNaive, tag, []string{N.NetworkTCP}, options.DialerOptions),
-		ctx:     ctx,
-		logger:  logger,
-		client:  client,
+		Adapter:   outbound.NewAdapterWithDialerOptions(C.TypeNaive, tag, []string{N.NetworkTCP}, options.DialerOptions),
+		ctx:       ctx,
+		logger:    logger,
+		client:    client,
+		uotClient: uotClient,
 	}, nil
 }
 
-func (o *Outbound) Start(stage adapter.StartStage) error {
+func (h *Outbound) Start(stage adapter.StartStage) error {
 	if stage != adapter.StartStateStart {
 		return nil
 	}
-	err := o.client.Start()
+	err := h.client.Start()
 	if err != nil {
 		return err
 	}
-	o.logger.Info("NaiveProxy started, version: ", o.client.Engine().Version())
+	h.logger.Info("NaiveProxy started, version: ", h.client.Engine().Version())
 	return nil
 }
 
-func (o *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
-	ctx, metadata := adapter.ExtendContext(ctx)
-	metadata.Outbound = o.Tag()
-	metadata.Destination = destination
-	o.logger.InfoContext(ctx, "outbound connection to ", destination)
-	return o.client.DialContext(ctx, destination)
+func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
+	switch N.NetworkName(network) {
+	case N.NetworkTCP:
+		h.logger.InfoContext(ctx, "outbound connection to ", destination)
+		return h.client.DialEarly(destination)
+	case N.NetworkUDP:
+		if h.uotClient == nil {
+			return nil, E.New("UDP is not supported unless UDP over TCP is enabled")
+		}
+		h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
+		return h.uotClient.DialContext(ctx, network, destination)
+	default:
+		return nil, E.Extend(N.ErrUnknownNetwork, network)
+	}
+}
+
+func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
+	if h.uotClient == nil {
+		return nil, E.New("UDP is not supported unless UDP over TCP is enabled")
+	}
+	return h.uotClient.ListenPacket(ctx, destination)
 }
 
-func (o *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
-	return nil, os.ErrInvalid
+func (h *Outbound) Close() error {
+	return h.client.Close()
 }
 
-func (o *Outbound) Close() error {
-	return o.client.Close()
+func (h *Outbound) Client() *cronet.NaiveClient {
+	return h.client
 }
 
-func (o *Outbound) StartNetLogToFile(fileName string, logAll bool) bool {
-	return o.client.Engine().StartNetLogToFile(fileName, logAll)
+type naiveDialer struct {
+	*cronet.NaiveClient
 }
 
-func (o *Outbound) StopNetLog() {
-	o.client.Engine().StopNetLog()
+func (d *naiveDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
+	return d.NaiveClient.DialEarly(destination)
 }

+ 6 - 6
test/naive_self_test.go

@@ -310,12 +310,12 @@ func TestNaiveSelfECH(t *testing.T) {
 	naiveOutbound := naiveOut.(*naive.Outbound)
 
 	netLogPath := "/tmp/naive_ech_netlog.json"
-	require.True(t, naiveOutbound.StartNetLogToFile(netLogPath, true))
-	defer naiveOutbound.StopNetLog()
+	require.True(t, naiveOutbound.Client().Engine().StartNetLogToFile(netLogPath, true))
+	defer naiveOutbound.Client().Engine().StopNetLog()
 
 	testTCP(t, clientPort, testPort)
 
-	naiveOutbound.StopNetLog()
+	naiveOutbound.Client().Engine().StopNetLog()
 
 	logContent, err := os.ReadFile(netLogPath)
 	require.NoError(t, err)
@@ -418,8 +418,8 @@ func TestNaiveSelfInsecureConcurrency(t *testing.T) {
 	naiveOutbound := naiveOut.(*naive.Outbound)
 
 	netLogPath := "/tmp/naive_concurrency_netlog.json"
-	require.True(t, naiveOutbound.StartNetLogToFile(netLogPath, true))
-	defer naiveOutbound.StopNetLog()
+	require.True(t, naiveOutbound.Client().Engine().StartNetLogToFile(netLogPath, true))
+	defer naiveOutbound.Client().Engine().StopNetLog()
 
 	// Send multiple sequential connections to trigger round-robin
 	// With insecure_concurrency=3, connections will be distributed to 3 pools
@@ -427,7 +427,7 @@ func TestNaiveSelfInsecureConcurrency(t *testing.T) {
 		testTCP(t, clientPort, testPort)
 	}
 
-	naiveOutbound.StopNetLog()
+	naiveOutbound.Client().Engine().StopNetLog()
 
 	// Verify NetLog contains multiple independent HTTP/2 sessions
 	logContent, err := os.ReadFile(netLogPath)