v2raya: Update to 2.0.4
authorTianling Shen <cnsztl@immortalwrt.org>
Sat, 18 Mar 2023 15:13:26 +0000 (23:13 +0800)
committerTianling Shen <cnsztl@gmail.com>
Mon, 20 Mar 2023 07:57:32 +0000 (15:57 +0800)
- Added TproxyNotSkipBr flag for OpenWrt.
- Removed all upstreamed patches.
- Removed deprecated option.
- Re-enable ipv6/nftables auto-detect.

Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
net/v2raya/Makefile
net/v2raya/files/v2raya.config
net/v2raya/files/v2raya.init
net/v2raya/patches/013-fix-we-should-skip-interface-ppp-to-avoid-to-break-net.patch [deleted file]
net/v2raya/patches/014-fix-seed-cannot-be-read-from-vless-sharing-link-and-add-m.patch [deleted file]
net/v2raya/patches/015-fix-a-problem-that-supervisor-cannot-exit-normally.patch [deleted file]
net/v2raya/patches/016-fix-unexpected-exit-does-not-apply-stop-steps.patch [deleted file]
net/v2raya/patches/017-optimize-reduce-disk-writes.patch [deleted file]
net/v2raya/patches/018-fix-do-not-rollback-closed-transaction.patch [deleted file]
net/v2raya/patches/019-fix-simple-obfs.patch [deleted file]
net/v2raya/patches/020-feat-add-nftables-support.patch [deleted file]

index 3787374c457760a47ef63ac3fd60a0a03a65ee86..9bb77c92815e5c8db75eecfa44bbd63057c15289 100644 (file)
@@ -5,12 +5,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=v2rayA
-PKG_VERSION:=1.5.9.1698.1
-PKG_RELEASE:=4
+PKG_VERSION:=2.0.4
+PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/v2rayA/v2rayA/tar.gz/v$(PKG_VERSION)?
-PKG_HASH:=247a357230c616bf48309c61d119686e4ad56939c05afef584c45051e9dc6220
+PKG_HASH:=fb0c60d95cd208e3306cf9c5488f41fe7cf6697d58dc377e5e7d471e37ce9060
 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)/service
 
 PKG_LICENSE:=AGPL-3.0-only
@@ -22,7 +22,9 @@ PKG_BUILD_PARALLEL:=1
 PKG_USE_MIPS16:=0
 
 GO_PKG:=github.com/v2rayA/v2rayA
-GO_PKG_LDFLAGS_X:=$(GO_PKG)/conf.Version=$(PKG_VERSION)
+GO_PKG_LDFLAGS_X:= \
+       $(GO_PKG)/conf.Version=$(PKG_VERSION) \
+       $(GO_PKG)/core/iptables.TproxyNotSkipBr=true
 
 include $(INCLUDE_DIR)/package.mk
 include ../../lang/golang/golang-package.mk
@@ -57,7 +59,7 @@ define Download/v2raya-web
        URL:=https://codeload.github.com/v2rayA/v2raya-web/tar.gz/v$(PKG_VERSION)?
        URL_FILE:=$(WEB_FILE)
        FILE:=$(WEB_FILE)
-       HASH:=149097a42c3e5fa6f5c3cd46d1bf7ec4546e79ad37c1446b759539e700bd75e2
+       HASH:=39eacb70753b309a0f44ede282ad01b5c6a13d51bed72d0f5563574de9bea0b7
 endef
 
 define Build/Prepare
index 131131cf81a88e1e312f361ea5f747ab914ebb19..8ebf318cda5d12bafac1c0a133113b28bc481949 100644 (file)
@@ -10,11 +10,11 @@ config v2raya 'config'
 
        # Make sure your IPv6 network works fine before you turn it on.
        # Optional values: auto, on, off.
-       option ipv6_support 'on'
+       option ipv6_support 'auto'
 
        # Experimental feature. Make sure you have installed nftables.
        # Optional values: auto, on, off.
-       option nftables_support 'on'
+       option nftables_support 'auto'
 
        # Optional values: trace, debug, info, warn or error
        option log_level 'info'
@@ -48,7 +48,3 @@ config v2raya 'config'
        # v2rayA will pass in the --stage (pre-start, post-start, pre-stop, post-stop) argument.
        option plugin_manager ''
 
-       # Specify the certification path instead of automatically generating a self-signed certificate.
-       # Example: /etc/v2raya/grpc_certificate.crt,/etc/v2raya/grpc_private.key
-       option vless_grpc_inbound_cert_key ''
-
index 2b77fa5dcdcdba7ee55b6b1dfa29c9226f58baf3..b4a719613017f885a12d431779f8142fa74cc12a 100755 (executable)
@@ -42,8 +42,8 @@ start_service() {
 
        append_env_arg "config" "address" "0.0.0.0:2017"
        append_env_arg "config" "config" "/etc/v2raya"
-       append_env_arg "config" "ipv6_support" "on"
-       append_env_arg "config" "nftables_support" "on"
+       append_env_arg "config" "ipv6_support" "auto"
+       append_env_arg "config" "nftables_support" "auto"
        append_env_arg "config" "log_level" "info"
        append_env_arg "config" "log_file" "/var/log/v2raya/v2raya.log"
        append_env_arg "config" "log_max_days" "3"
@@ -52,7 +52,6 @@ start_service() {
        append_env_arg "config" "transparent_hook"
        append_env_arg "config" "core_hook"
        append_env_arg "config" "plugin_manager"
-       append_env_arg "config" "vless_grpc_inbound_cert_key"
        append_env_bool "config" "log_disable_color"
        append_env_bool "config" "log_disable_timestamp"
 
diff --git a/net/v2raya/patches/013-fix-we-should-skip-interface-ppp-to-avoid-to-break-net.patch b/net/v2raya/patches/013-fix-we-should-skip-interface-ppp-to-avoid-to-break-net.patch
deleted file mode 100644 (file)
index 5de1a86..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-From ca6a05273284daa04856a840e64f3936f700b7c3 Mon Sep 17 00:00:00 2001
-From: mzz2017 <mzz@tuta.io>
-Date: Fri, 16 Sep 2022 15:13:11 +0800
-Subject: [PATCH] fix: we should skip interface ppp+ to avoid to break net
-
----
- service/core/iptables/tproxy.go | 6 +++++-
- 1 file changed, 5 insertions(+), 1 deletion(-)
-
---- a/core/iptables/tproxy.go
-+++ b/core/iptables/tproxy.go
-@@ -16,7 +16,7 @@ var Tproxy tproxy
- func (t *tproxy) AddIPWhitelist(cidr string) {
-       // avoid duplication
-       t.RemoveIPWhitelist(cidr)
--      pos := 5
-+      pos := 7
-       if configure.GetSettingNotNil().AntiPollution != configure.AntipollutionClosed {
-               pos += 3
-       }
-@@ -67,6 +67,8 @@ iptables -w 2 -t mangle -A TP_RULE -j CO
- iptables -w 2 -t mangle -A TP_RULE -m mark --mark 0x40/0xc0 -j RETURN
- iptables -w 2 -t mangle -A TP_RULE -i docker+ -j RETURN
- iptables -w 2 -t mangle -A TP_RULE -i veth+ -j RETURN
-+iptables -w 2 -t mangle -A TP_RULE -i ppp+ -j RETURN
-+iptables -w 2 -t mangle -A TP_RULE -i dn42-+ -j RETURN
- `
-       if configure.GetSettingNotNil().AntiPollution != configure.AntipollutionClosed {
-               commands += `
-@@ -125,6 +127,8 @@ ip6tables -w 2 -t mangle -A TP_RULE -j C
- ip6tables -w 2 -t mangle -A TP_RULE -m mark --mark 0x40/0xc0 -j RETURN
- ip6tables -w 2 -t mangle -A TP_RULE -i docker+ -j RETURN
- ip6tables -w 2 -t mangle -A TP_RULE -i veth+ -j RETURN
-+ip6tables -w 2 -t mangle -A TP_RULE -i ppp+ -j RETURN
-+ip6tables -w 2 -t mangle -A TP_RULE -i dn42-+ -j RETURN
- `
-               if configure.GetSettingNotNil().AntiPollution != configure.AntipollutionClosed {
-                       commands += `
diff --git a/net/v2raya/patches/014-fix-seed-cannot-be-read-from-vless-sharing-link-and-add-m.patch b/net/v2raya/patches/014-fix-seed-cannot-be-read-from-vless-sharing-link-and-add-m.patch
deleted file mode 100644 (file)
index ba50306..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-From 5db722b22b39642280572a62b149d4e1efa21ce3 Mon Sep 17 00:00:00 2001
-From: mzz2017 <mzz@tuta.io>
-Date: Mon, 8 Aug 2022 22:30:36 +0800
-Subject: [PATCH] fix: seed cannot be read from vless sharing-link and add
- missing sni field. #616
-
----
- service/core/serverObj/v2ray.go | 24 +++++++++++-------------
- 1 file changed, 11 insertions(+), 13 deletions(-)
-
---- a/core/serverObj/v2ray.go
-+++ b/core/serverObj/v2ray.go
-@@ -12,7 +12,6 @@ import (
-       "time"
-       jsoniter "github.com/json-iterator/go"
--      "github.com/tidwall/gjson"
-       "github.com/v2rayA/v2rayA/common"
-       "github.com/v2rayA/v2rayA/core/coreObj"
-       "github.com/v2rayA/v2rayA/core/v2ray/service"
-@@ -39,6 +38,7 @@ type V2Ray struct {
-       Net           string `json:"net"`
-       Type          string `json:"type"`
-       Host          string `json:"host"`
-+      SNI           string `json:"sni"`
-       Path          string `json:"path"`
-       TLS           string `json:"tls"`
-       Flow          string `json:"flow,omitempty"`
-@@ -69,7 +69,8 @@ func ParseVlessURL(vless string) (data *
-               ID:            u.User.String(),
-               Net:           u.Query().Get("type"),
-               Type:          u.Query().Get("headerType"),
--              Host:          u.Query().Get("sni"),
-+              Host:          u.Query().Get("host"),
-+              SNI:           u.Query().Get("sni"),
-               Path:          u.Query().Get("path"),
-               TLS:           u.Query().Get("security"),
-               Flow:          u.Query().Get("flow"),
-@@ -86,16 +87,13 @@ func ParseVlessURL(vless string) (data *
-       if data.Type == "" {
-               data.Type = "none"
-       }
--      if data.Host == "" {
--              data.Host = u.Query().Get("host")
--      }
-       if data.TLS == "" {
-               data.TLS = "none"
-       }
-       if data.Flow == "" {
-               data.Flow = "xtls-rprx-direct"
-       }
--      if data.Type == "mkcp" || data.Type == "kcp" {
-+      if data.Net == "mkcp" || data.Net == "kcp" {
-               data.Path = u.Query().Get("seed")
-       }
-       return data, nil
-@@ -145,6 +143,7 @@ func ParseVmessURL(vmess string) (data *
-               if aid == "" {
-                       aid = q.Get("aid")
-               }
-+              sni := q.Get("sni")
-               info = V2Ray{
-                       ID:            subMatch[1],
-                       Add:           subMatch[2],
-@@ -152,6 +151,7 @@ func ParseVmessURL(vmess string) (data *
-                       Ps:            ps,
-                       Host:          obfsParam,
-                       Path:          path,
-+                      SNI:           sni,
-                       Net:           obfs,
-                       Aid:           aid,
-                       TLS:           map[string]string{"1": "tls"}[q.Get("tls")],
-@@ -165,12 +165,6 @@ func ParseVmessURL(vmess string) (data *
-               if err != nil {
-                       return
-               }
--              if info.Host == "" {
--                      sni := gjson.Get(raw, "sni")
--                      if sni.Exists() {
--                              info.Host = sni.String()
--                      }
--              }
-       }
-       // correct the wrong vmess as much as possible
-       if strings.HasPrefix(info.Host, "/") && info.Path == "" {
-@@ -328,7 +322,9 @@ func (v *V2Ray) Configuration(info Prior
-                               core.StreamSettings.TLSSettings.AllowInsecure = true
-                       }
-                       // SNI
--                      if v.Host != "" {
-+                      if v.SNI != "" {
-+                              core.StreamSettings.TLSSettings.ServerName = v.SNI
-+                      } else if v.Host != "" {
-                               core.StreamSettings.TLSSettings.ServerName = v.Host
-                       }
-                       // Alpn
-@@ -345,6 +341,8 @@ func (v *V2Ray) Configuration(info Prior
-                       // SNI
-                       if v.Host != "" {
-                               core.StreamSettings.XTLSSettings.ServerName = v.Host
-+                      } else if v.Host != "" {
-+                              core.StreamSettings.TLSSettings.ServerName = v.Host
-                       }
-                       if v.AllowInsecure {
-                               core.StreamSettings.XTLSSettings.AllowInsecure = true
diff --git a/net/v2raya/patches/015-fix-a-problem-that-supervisor-cannot-exit-normally.patch b/net/v2raya/patches/015-fix-a-problem-that-supervisor-cannot-exit-normally.patch
deleted file mode 100644 (file)
index 5447dc0..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-From 3f78422f81f3abc2668fc3938b31d213bfe4dfff Mon Sep 17 00:00:00 2001
-From: mzz2017 <mzz@tuta.io>
-Date: Sun, 28 Aug 2022 17:54:36 +0800
-Subject: [PATCH] fix: a problem that supervisor cannot exit normally
-
----
- service/core/specialMode/infra/handle.go     | 11 ++++++----
- service/core/specialMode/infra/supervisor.go | 22 ++++++++------------
- 2 files changed, 16 insertions(+), 17 deletions(-)
-
---- a/core/specialMode/infra/handle.go
-+++ b/core/specialMode/infra/handle.go
-@@ -127,10 +127,13 @@ func (interfaceHandle *handle) handleRec
-       return results, msg
- }
--func packetFilter(portCache *portCache, pPacket *gopacket.Packet, whitelistDnsServers *v2router.GeoIPMatcher) (m *dnsmessage.Message, pSAddr, pSPort, pDAddr, pDPort *gopacket.Endpoint) {
--      packet := *pPacket
--      trans := packet.TransportLayer()
-+func packetFilter(portCache *portCache, packet gopacket.Packet, whitelistDnsServers *v2router.GeoIPMatcher) (m *dnsmessage.Message, pSAddr, pSPort, pDAddr, pDPort *gopacket.Endpoint) {
-+      //跳过非网络层的包
-+      if packet.NetworkLayer() == nil {
-+              return
-+      }
-       //跳过非传输层的包
-+      trans := packet.TransportLayer()
-       if trans == nil {
-               return
-       }
-@@ -180,7 +183,7 @@ func packetFilter(portCache *portCache,
- }
- func (interfaceHandle *handle) handlePacket(packet gopacket.Packet, ifname string, whitelistDnsServers *v2router.GeoIPMatcher, whitelistDomains *strmatcher.MatcherGroup) {
--      m, sAddr, sPort, dAddr, dPort := packetFilter(interfaceHandle.portCache, &packet, whitelistDnsServers)
-+      m, sAddr, sPort, dAddr, dPort := packetFilter(interfaceHandle.portCache, packet, whitelistDnsServers)
-       if m == nil {
-               return
-       }
---- a/core/specialMode/infra/supervisor.go
-+++ b/core/specialMode/infra/supervisor.go
-@@ -9,7 +9,6 @@ import (
-       v2router "github.com/v2rayA/v2ray-lib/router"
-       "github.com/v2rayA/v2rayA/pkg/util/log"
-       "sync"
--      "time"
- )
- type DnsSupervisor struct {
-@@ -70,7 +69,7 @@ func (d *DnsSupervisor) DeleteHandles(if
-       }
-       close(d.handles[ifname].done)
-       delete(d.handles, ifname)
--      log.Trace("DnsSupervisor:%v closed", ifname)
-+      log.Trace("DnsSupervisor:%v deleted", ifname)
-       return
- }
-@@ -81,28 +80,24 @@ func (d *DnsSupervisor) Run(ifname strin
-       d.inner.Lock()
-       handle, ok := d.handles[ifname]
-       if !ok {
-+              d.inner.Unlock()
-               return fmt.Errorf("Run: %v not exsits", ifname)
-       }
-       if handle.running {
-+              d.inner.Unlock()
-               return fmt.Errorf("Run: %v is running", ifname)
-       }
-       handle.running = true
-       log.Trace("[DnsSupervisor] " + ifname + ": running")
--      pkgsrc := gopacket.NewPacketSource(handle, layers.LayerTypeEthernet)
-+      // we only decode UDP packets
-+      pkgsrc := gopacket.NewPacketSource(handle, layers.LayerTypeDNS)
-       pkgsrc.NoCopy = true
-+      //pkgsrc.Lazy = true
-       d.inner.Unlock()
-       packets := pkgsrc.Packets()
-       go func() {
--              for {
--                      //心跳包,防止内存泄漏
--                      packets <- gopacket.NewPacket(nil, layers.LinkTypeEthernet, gopacket.DecodeOptions{})
--                      select {
--                      case <-handle.done:
--                              return
--                      default:
--                              time.Sleep(2 * time.Second)
--                      }
--              }
-+              <-handle.done
-+              packets <- gopacket.NewPacket(nil, layers.LinkTypeEthernet, pkgsrc.DecodeOptions)
-       }()
- out:
-       for packet := range packets {
-@@ -113,5 +108,6 @@ out:
-               }
-               go handle.handlePacket(packet, ifname, whitelistDnsServers, whitelistDomains)
-       }
-+      log.Trace("DnsSupervisor:%v closed", ifname)
-       return
- }
diff --git a/net/v2raya/patches/016-fix-unexpected-exit-does-not-apply-stop-steps.patch b/net/v2raya/patches/016-fix-unexpected-exit-does-not-apply-stop-steps.patch
deleted file mode 100644 (file)
index a945dbd..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-From 153b72ed623876ad73b731c2ec2344e9057d3c35 Mon Sep 17 00:00:00 2001
-From: mzz2017 <mzz@tuta.io>
-Date: Wed, 21 Sep 2022 16:50:24 +0800
-Subject: [PATCH] fix: unexpected exit does not apply stop steps
-
----
- service/core/v2ray/process.go        | 4 ++--
- service/core/v2ray/processManager.go | 8 +++-----
- 2 files changed, 5 insertions(+), 7 deletions(-)
-
---- a/core/v2ray/process.go
-+++ b/core/v2ray/process.go
-@@ -35,7 +35,7 @@ type Process struct {
-       tag2WhichIndex map[string]int
- }
--func NewProcess(tmpl *Template, prestart func() error, poststart func() error) (process *Process, err error) {
-+func NewProcess(tmpl *Template, prestart func() error, poststart func() error, stopfunc func(p *Process)) (process *Process, err error) {
-       process = &Process{
-               template: tmpl,
-       }
-@@ -111,7 +111,7 @@ func NewProcess(tmpl *Template, prestart
-                       // canceled by v2rayA
-                       return
-               }
--              defer ProcessManager.Stop(false)
-+              defer stopfunc(process)
-               var t []string
-               if p != nil {
-                       if p.Success() {
---- a/core/v2ray/processManager.go
-+++ b/core/v2ray/processManager.go
-@@ -245,16 +245,14 @@ func (m *CoreProcessManager) Start(t *Te
-               return m.beforeStart(t)
-       }, func() error {
-               return m.afterStart(t)
-+      }, func(p *Process) {
-+              m.p = p
-+              ProcessManager.Stop(false)
-       })
-       if err != nil {
-               return err
-       }
-       m.p = process
--      defer func() {
--              if err != nil {
--                      m.stop(true)
--              }
--      }()
-       configure.SetRunning(true)
-       return nil
diff --git a/net/v2raya/patches/017-optimize-reduce-disk-writes.patch b/net/v2raya/patches/017-optimize-reduce-disk-writes.patch
deleted file mode 100644 (file)
index 5437570..0000000
+++ /dev/null
@@ -1,336 +0,0 @@
-From 00366b224b2e28861b80f677e8aa604c5d08dae3 Mon Sep 17 00:00:00 2001
-From: Kelo <meetkelo@outlook.com>
-Date: Sat, 29 Oct 2022 16:27:26 +0800
-Subject: [PATCH] optimize: reduce disk writes
-
----
- service/db/boltdb.go  | 43 +++++++++++++++++++++++++++++++----
- service/db/listOp.go  | 48 +++++++++++++++++++++------------------
- service/db/plainOp.go | 52 ++++++++++++++++++++++++-------------------
- service/db/setOp.go   | 20 +++++++++--------
- 4 files changed, 105 insertions(+), 58 deletions(-)
-
---- a/db/boltdb.go
-+++ b/db/boltdb.go
-@@ -1,13 +1,14 @@
- package db
- import (
--      "go.etcd.io/bbolt"
--      "github.com/v2rayA/v2rayA/conf"
--      "github.com/v2rayA/v2rayA/pkg/util/copyfile"
--      "github.com/v2rayA/v2rayA/pkg/util/log"
-       "os"
-       "path/filepath"
-       "sync"
-+
-+      "github.com/v2rayA/v2rayA/conf"
-+      "github.com/v2rayA/v2rayA/pkg/util/copyfile"
-+      "github.com/v2rayA/v2rayA/pkg/util/log"
-+      "go.etcd.io/bbolt"
- )
- var once sync.Once
-@@ -46,3 +47,37 @@ func DB() *bbolt.DB {
-       once.Do(initDB)
-       return db
- }
-+
-+// The function should return a dirty flag.
-+// If the dirty flag is true and there is no error then the transaction is commited.
-+// Otherwise, the transaction is rolled back.
-+func Transaction(db *bbolt.DB, fn func(*bbolt.Tx) (bool, error)) error {
-+      tx, err := db.Begin(true)
-+      if err != nil {
-+              return err
-+      }
-+      defer tx.Rollback()
-+      dirty, err := fn(tx)
-+      if err != nil {
-+              _ = tx.Rollback()
-+              return err
-+      }
-+      if !dirty {
-+              return nil
-+      }
-+      return tx.Commit()
-+}
-+
-+// If the bucket does not exist, the dirty flag is setted
-+func CreateBucketIfNotExists(tx *bbolt.Tx, name []byte, dirty *bool) (*bbolt.Bucket, error) {
-+      bkt := tx.Bucket(name)
-+      if bkt != nil {
-+              return bkt, nil
-+      }
-+      bkt, err := tx.CreateBucket(name)
-+      if err != nil {
-+              return nil, err
-+      }
-+      *dirty = true
-+      return bkt, nil
-+}
---- a/db/listOp.go
-+++ b/db/listOp.go
-@@ -2,13 +2,14 @@ package db
- import (
-       "fmt"
--      "go.etcd.io/bbolt"
--      jsoniter "github.com/json-iterator/go"
--      "github.com/tidwall/gjson"
--      "github.com/tidwall/sjson"
-       "reflect"
-       "sort"
-       "strconv"
-+
-+      jsoniter "github.com/json-iterator/go"
-+      "github.com/tidwall/gjson"
-+      "github.com/tidwall/sjson"
-+      "go.etcd.io/bbolt"
- )
- func ListSet(bucket string, key string, index int, val interface{}) (err error) {
-@@ -31,20 +32,21 @@ func ListSet(bucket string, key string,
- }
- func ListGet(bucket string, key string, index int) (b []byte, err error) {
--      err = DB().Update(func(tx *bbolt.Tx) error {
--              if bkt, err := tx.CreateBucketIfNotExists([]byte(bucket)); err != nil {
--                      return err
-+      err = Transaction(DB(), func(tx *bbolt.Tx) (bool, error) {
-+              dirty := false
-+              if bkt, err := CreateBucketIfNotExists(tx, []byte(bucket), &dirty); err != nil {
-+                      return dirty, err
-               } else {
-                       v := bkt.Get([]byte(key))
-                       if v == nil {
--                              return fmt.Errorf("ListGet: can't get element from an empty list")
-+                              return dirty, fmt.Errorf("ListGet: can't get element from an empty list")
-                       }
-                       r := gjson.GetBytes(v, strconv.Itoa(index))
-                       if r.Exists() {
-                               b = []byte(r.Raw)
--                              return nil
-+                              return dirty, nil
-                       } else {
--                              return fmt.Errorf("ListGet: no such element")
-+                              return dirty, fmt.Errorf("ListGet: no such element")
-                       }
-               }
-       })
-@@ -79,24 +81,25 @@ func ListAppend(bucket string, key strin
- }
- func ListGetAll(bucket string, key string) (list [][]byte, err error) {
--      err = DB().Update(func(tx *bbolt.Tx) error {
--              if bkt, err := tx.CreateBucketIfNotExists([]byte(bucket)); err != nil {
--                      return err
-+      err = Transaction(DB(), func(tx *bbolt.Tx) (bool, error) {
-+              dirty := false
-+              if bkt, err := CreateBucketIfNotExists(tx, []byte(bucket), &dirty); err != nil {
-+                      return dirty, err
-               } else {
-                       b := bkt.Get([]byte(key))
-                       if b == nil {
--                              return nil
-+                              return dirty, nil
-                       }
-                       parsed := gjson.ParseBytes(b)
-                       if !parsed.IsArray() {
--                              return fmt.Errorf("ListGetAll: is not array")
-+                              return dirty, fmt.Errorf("ListGetAll: is not array")
-                       }
-                       results := parsed.Array()
-                       for _, r := range results {
-                               list = append(list, []byte(r.Raw))
-                       }
-               }
--              return nil
-+              return dirty, nil
-       })
-       return list, err
- }
-@@ -143,21 +146,22 @@ func ListRemove(bucket, key string, inde
- }
- func ListLen(bucket string, key string) (length int, err error) {
--      err = DB().Update(func(tx *bbolt.Tx) error {
--              if bkt, err := tx.CreateBucketIfNotExists([]byte(bucket)); err != nil {
--                      return err
-+      err = Transaction(DB(), func(tx *bbolt.Tx) (bool, error) {
-+              dirty := false
-+              if bkt, err := CreateBucketIfNotExists(tx, []byte(bucket), &dirty); err != nil {
-+                      return dirty, err
-               } else {
-                       b := bkt.Get([]byte(key))
-                       if b == nil {
--                              return nil
-+                              return dirty, nil
-                       }
-                       parsed := gjson.ParseBytes(b)
-                       if !parsed.IsArray() {
--                              return fmt.Errorf("ListLen: is not array")
-+                              return dirty, fmt.Errorf("ListLen: is not array")
-                       }
-                       length = len(parsed.Array())
-               }
--              return nil
-+              return dirty, nil
-       })
-       return length, err
- }
---- a/db/plainOp.go
-+++ b/db/plainOp.go
-@@ -2,50 +2,54 @@ package db
- import (
-       "fmt"
--      "go.etcd.io/bbolt"
-+
-       jsoniter "github.com/json-iterator/go"
-       "github.com/v2rayA/v2rayA/common"
-       "github.com/v2rayA/v2rayA/pkg/util/log"
-+      "go.etcd.io/bbolt"
- )
- func Get(bucket string, key string, val interface{}) (err error) {
--      return DB().Update(func(tx *bbolt.Tx) error {
--              if bkt, err := tx.CreateBucketIfNotExists([]byte(bucket)); err != nil {
--                      return err
-+      return Transaction(DB(), func(tx *bbolt.Tx) (bool, error) {
-+              dirty := false
-+              if bkt, err := CreateBucketIfNotExists(tx, []byte(bucket), &dirty); err != nil {
-+                      return dirty, err
-               } else {
-                       if v := bkt.Get([]byte(key)); v == nil {
--                              return fmt.Errorf("Get: key is not found")
-+                              return dirty, fmt.Errorf("Get: key is not found")
-                       } else {
--                              return jsoniter.Unmarshal(v, val)
-+                              return dirty, jsoniter.Unmarshal(v, val)
-                       }
-               }
-       })
- }
- func GetRaw(bucket string, key string) (b []byte, err error) {
--      err = DB().Update(func(tx *bbolt.Tx) error {
--              if bkt, err := tx.CreateBucketIfNotExists([]byte(bucket)); err != nil {
--                      return err
-+      err = Transaction(DB(), func(tx *bbolt.Tx) (bool, error) {
-+              dirty := false
-+              if bkt, err := CreateBucketIfNotExists(tx, []byte(bucket), &dirty); err != nil {
-+                      return dirty, err
-               } else {
-                       v := bkt.Get([]byte(key))
-                       if v == nil {
--                              return fmt.Errorf("GetRaw: key is not found")
-+                              return dirty, fmt.Errorf("GetRaw: key is not found")
-                       }
-                       b = common.BytesCopy(v)
--                      return nil
-+                      return dirty, nil
-               }
-       })
-       return b, err
- }
- func Exists(bucket string, key string) (exists bool) {
--      if err := DB().Update(func(tx *bbolt.Tx) error {
--              if bkt, err := tx.CreateBucketIfNotExists([]byte(bucket)); err != nil {
--                      return err
-+      if err := Transaction(DB(), func(tx *bbolt.Tx) (bool, error) {
-+              dirty := false
-+              if bkt, err := CreateBucketIfNotExists(tx, []byte(bucket), &dirty); err != nil {
-+                      return dirty, err
-               } else {
-                       v := bkt.Get([]byte(key))
-                       exists = v != nil
--                      return nil
-+                      return dirty, nil
-               }
-       }); err != nil {
-               log.Warn("%v", err)
-@@ -55,23 +59,25 @@ func Exists(bucket string, key string) (
- }
- func GetBucketLen(bucket string) (length int, err error) {
--      err = DB().Update(func(tx *bbolt.Tx) error {
--              if bkt, err := tx.CreateBucketIfNotExists([]byte(bucket)); err != nil {
--                      return err
-+      err = Transaction(DB(), func(tx *bbolt.Tx) (bool, error) {
-+              dirty := false
-+              if bkt, err := CreateBucketIfNotExists(tx, []byte(bucket), &dirty); err != nil {
-+                      return dirty, err
-               } else {
-                       length = bkt.Stats().KeyN
-               }
--              return nil
-+              return dirty, nil
-       })
-       return length, err
- }
- func GetBucketKeys(bucket string) (keys []string, err error) {
--      err = DB().Update(func(tx *bbolt.Tx) error {
--              if bkt, err := tx.CreateBucketIfNotExists([]byte(bucket)); err != nil {
--                      return err
-+      err = Transaction(DB(), func(tx *bbolt.Tx) (bool, error) {
-+              dirty := false
-+              if bkt, err := CreateBucketIfNotExists(tx, []byte(bucket), &dirty); err != nil {
-+                      return dirty, err
-               } else {
--                      return bkt.ForEach(func(k, v []byte) error {
-+                      return dirty, bkt.ForEach(func(k, v []byte) error {
-                               keys = append(keys, string(k))
-                               return nil
-                       })
---- a/db/setOp.go
-+++ b/db/setOp.go
-@@ -4,8 +4,9 @@ import (
-       "bytes"
-       "crypto/sha256"
-       "encoding/gob"
--      "go.etcd.io/bbolt"
-+
-       "github.com/v2rayA/v2rayA/common"
-+      "go.etcd.io/bbolt"
- )
- type set map[[32]byte]interface{}
-@@ -28,26 +29,27 @@ func toSha256(val interface{}) (hash [32
- }
- func setOp(bucket string, key string, f func(m set) (readonly bool, err error)) (err error) {
--      return DB().Update(func(tx *bbolt.Tx) error {
--              if bkt, err := tx.CreateBucketIfNotExists([]byte(bucket)); err != nil {
--                      return err
-+      return Transaction(DB(), func(tx *bbolt.Tx) (bool, error) {
-+              dirty := false
-+              if bkt, err := CreateBucketIfNotExists(tx, []byte(bucket), &dirty); err != nil {
-+                      return dirty, err
-               } else {
-                       var m set
-                       v := bkt.Get([]byte(key))
-                       if v == nil {
-                               m = make(set)
-                       } else if err := gob.NewDecoder(bytes.NewReader(v)).Decode(&m); err != nil {
--                              return err
-+                              return dirty, err
-                       }
-                       if readonly, err := f(m); err != nil {
--                              return err
-+                              return dirty, err
-                       } else if readonly {
--                              return nil
-+                              return dirty, nil
-                       }
-                       if b, err := common.ToBytes(m); err != nil {
--                              return err
-+                              return dirty, err
-                       } else {
--                              return bkt.Put([]byte(key), b)
-+                              return true, bkt.Put([]byte(key), b)
-                       }
-               }
-       })
diff --git a/net/v2raya/patches/018-fix-do-not-rollback-closed-transaction.patch b/net/v2raya/patches/018-fix-do-not-rollback-closed-transaction.patch
deleted file mode 100644 (file)
index b9815f4..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-From 451912074ba1ba4000c66874876bc0a6b64cb5da Mon Sep 17 00:00:00 2001
-From: Kelo <meetkelo@outlook.com>
-Date: Sun, 30 Oct 2022 16:49:22 +0800
-Subject: [PATCH] fix: do not rollback closed transaction
-
----
- service/db/boltdb.go | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
---- a/db/boltdb.go
-+++ b/db/boltdb.go
-@@ -56,14 +56,13 @@ func Transaction(db *bbolt.DB, fn func(*
-       if err != nil {
-               return err
-       }
--      defer tx.Rollback()
-       dirty, err := fn(tx)
-       if err != nil {
-               _ = tx.Rollback()
-               return err
-       }
-       if !dirty {
--              return nil
-+              return tx.Rollback()
-       }
-       return tx.Commit()
- }
diff --git a/net/v2raya/patches/019-fix-simple-obfs.patch b/net/v2raya/patches/019-fix-simple-obfs.patch
deleted file mode 100644 (file)
index e76b49c..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-From 58a6cf270e43ec3eaeef7d1c65de76278dd6d349 Mon Sep 17 00:00:00 2001
-From: mzz2017 <2017@duck.com>
-Date: Mon, 13 Feb 2023 14:42:07 +0800
-Subject: [PATCH] fix: simple-obfs
-
----
- service/pkg/plugin/simpleobfs/http.go | 8 +++++++-
- service/pkg/plugin/simpleobfs/tls.go  | 7 +++++++
- 2 files changed, 14 insertions(+), 1 deletion(-)
-
---- a/pkg/plugin/simpleobfs/http.go
-+++ b/pkg/plugin/simpleobfs/http.go
-@@ -12,6 +12,7 @@ import (
-       "net"
-       "net/http"
-       "strings"
-+      "sync"
- )
- // HTTPObfs is shadowsocks http simple-obfs implementation
-@@ -24,9 +25,13 @@ type HTTPObfs struct {
-       offset        int
-       firstRequest  bool
-       firstResponse bool
-+      rMu           sync.Mutex
-+      wMu           sync.Mutex
- }
- func (ho *HTTPObfs) Read(b []byte) (int, error) {
-+      ho.rMu.Lock()
-+      defer ho.rMu.Unlock()
-       if ho.buf != nil {
-               n := copy(b, ho.buf[ho.offset:])
-               ho.offset += n
-@@ -64,6 +69,8 @@ func (ho *HTTPObfs) Read(b []byte) (int,
- }
- func (ho *HTTPObfs) Write(b []byte) (int, error) {
-+      ho.wMu.Lock()
-+      defer ho.wMu.Unlock()
-       if ho.firstRequest {
-               randBytes := make([]byte, 16)
-               rand.Read(randBytes)
-@@ -71,7 +78,6 @@ func (ho *HTTPObfs) Write(b []byte) (int
-               req.Header.Set("User-Agent", fmt.Sprintf("curl/7.%d.%d", rand.Int()%54, rand.Int()%2))
-               req.Header.Set("Upgrade", "websocket")
-               req.Header.Set("Connection", "Upgrade")
--              req.Host = ho.host
-               if ho.port != "80" {
-                       req.Host = fmt.Sprintf("%s:%s", ho.host, ho.port)
-               }
---- a/pkg/plugin/simpleobfs/tls.go
-+++ b/pkg/plugin/simpleobfs/tls.go
-@@ -8,6 +8,7 @@ import (
-       "io"
-       "math/rand"
-       "net"
-+      "sync"
-       "time"
- )
-@@ -26,6 +27,8 @@ type TLSObfs struct {
-       remain        int
-       firstRequest  bool
-       firstResponse bool
-+      rMu           sync.Mutex
-+      wMu           sync.Mutex
- }
- func (to *TLSObfs) read(b []byte, discardN int) (int, error) {
-@@ -54,6 +57,8 @@ func (to *TLSObfs) read(b []byte, discar
- }
- func (to *TLSObfs) Read(b []byte) (int, error) {
-+      to.rMu.Lock()
-+      defer to.rMu.Unlock()
-       if to.remain > 0 {
-               length := to.remain
-               if length > len(b) {
-@@ -77,6 +82,8 @@ func (to *TLSObfs) Read(b []byte) (int,
-       return to.read(b, 3)
- }
- func (to *TLSObfs) Write(b []byte) (int, error) {
-+      to.wMu.Lock()
-+      defer to.wMu.Unlock()
-       length := len(b)
-       for i := 0; i < length; i += chunkSize {
-               end := i + chunkSize
diff --git a/net/v2raya/patches/020-feat-add-nftables-support.patch b/net/v2raya/patches/020-feat-add-nftables-support.patch
deleted file mode 100644 (file)
index 50ef49b..0000000
+++ /dev/null
@@ -1,624 +0,0 @@
-From d10cf52839e848870df0ea852d9a818ac03e7aa3 Mon Sep 17 00:00:00 2001
-From: cubercsl <2014cais01@gmail.com>
-Date: Thu, 19 Jan 2023 16:43:30 +0800
-Subject: [PATCH 1/5] feat: add nftables support
-
-fix: use iptables-nft if nftables-support is on
-fix: save nft to V2RAYA_CONFIG
-fix: tproxy for ipv6
-chore: small change in table format
----
- service/conf/environmentConfig.go     |   1 +
- service/core/iptables/dropSpoofing.go |   4 +-
- service/core/iptables/iptables.go     |   7 +-
- service/core/iptables/redirect.go     | 142 +++++++++++++++++--
- service/core/iptables/tproxy.go       | 195 +++++++++++++++++++++++++-
- service/core/iptables/utils.go        |  23 ++-
- service/core/iptables/watcher.go      |   1 +
- service/core/v2ray/asset/asset.go     |  17 ++-
- service/core/v2ray/transparent.go     |   9 +-
- 9 files changed, 367 insertions(+), 32 deletions(-)
-
---- a/conf/environmentConfig.go
-+++ b/conf/environmentConfig.go
-@@ -24,6 +24,7 @@ type Params struct {
-       WebDir                  string   `id:"webdir" desc:"v2rayA web files directory. use embedded files if not specify."`
-       VlessGrpcInboundCertKey []string `id:"vless-grpc-inbound-cert-key" desc:"Specify the certification path instead of automatically generating a self-signed certificate. Example: /etc/v2raya/grpc_certificate.crt,/etc/v2raya/grpc_private.key"`
-       IPV6Support             string   `id:"ipv6-support" default:"auto" desc:"Optional values: auto, on, off. Make sure your IPv6 network works fine before you turn it on."`
-+      NFTablesSupport         string   `id:"nftables-support" default:"off" desc:"Optional values: auto, on, off. Experimental feature. Make sure you have installed nftables."`
-       PassCheckRoot           bool     `desc:"Skip privilege checking. Use it only when you cannot start v2raya but confirm you have root privilege"`
-       ResetPassword           bool     `id:"reset-password"`
-       LogLevel                string   `id:"log-level" default:"info" desc:"Optional values: trace, debug, info, warn or error"`
---- a/core/iptables/dropSpoofing.go
-+++ b/core/iptables/dropSpoofing.go
-@@ -34,7 +34,7 @@ ip6tables -w 2 -I FORWARD -j DROP_SPOOFI
- `
-       }
-       return Setter{
--              Cmds:      commands,
-+              Cmds: commands,
-       }
- }
-@@ -54,6 +54,6 @@ ip6tables -w 2 -X DROP_SPOOFING
- `
-       }
-       return Setter{
--              Cmds:      commands,
-+              Cmds: commands,
-       }
- }
---- a/core/iptables/iptables.go
-+++ b/core/iptables/iptables.go
-@@ -1,11 +1,12 @@
- package iptables
- import (
--      "github.com/v2rayA/v2rayA/common"
--      "github.com/v2rayA/v2rayA/common/cmds"
-       "strings"
-       "sync"
-       "time"
-+
-+      "github.com/v2rayA/v2rayA/common"
-+      "github.com/v2rayA/v2rayA/common/cmds"
- )
- // http://briteming.hatenablog.com/entry/2019/06/18/175518
-@@ -56,6 +57,10 @@ func (c Setter) Run(stopAtError bool) er
-       if common.IsDocker() {
-               commands = strings.ReplaceAll(commands, "iptables", "iptables-legacy")
-               commands = strings.ReplaceAll(commands, "ip6tables", "ip6tables-legacy")
-+      } else if (!cmds.IsCommandValid("iptables") || IsNFTablesSupported()) &&
-+              cmds.IsCommandValid("iptables-nft") {
-+              commands = strings.ReplaceAll(commands, "iptables", "iptables-nft")
-+              commands = strings.ReplaceAll(commands, "ip6tables", "ip6tables-nft")
-       }
-       var errs []error
-       if c.PreFunc != nil {
---- a/core/iptables/redirect.go
-+++ b/core/iptables/redirect.go
-@@ -2,15 +2,34 @@ package iptables
- import (
-       "fmt"
--      "github.com/v2rayA/v2rayA/common/cmds"
-+      "os"
-       "strings"
-+
-+      "github.com/v2rayA/v2rayA/common/cmds"
-+      "github.com/v2rayA/v2rayA/core/v2ray/asset"
- )
--type redirect struct{}
-+type redirect interface {
-+      AddIPWhitelist(cidr string)
-+      RemoveIPWhitelist(cidr string)
-+      GetSetupCommands() Setter
-+      GetCleanCommands() Setter
-+}
-+
-+type legacyRedirect struct{}
-+type nftRedirect struct{}
- var Redirect redirect
--func (r *redirect) AddIPWhitelist(cidr string) {
-+func init() {
-+      if IsNFTablesSupported() {
-+              Redirect = &nftRedirect{}
-+      } else {
-+              Redirect = &legacyRedirect{}
-+      }
-+}
-+
-+func (r *legacyRedirect) AddIPWhitelist(cidr string) {
-       // avoid duplication
-       r.RemoveIPWhitelist(cidr)
-       var commands string
-@@ -22,13 +41,13 @@ func (r *redirect) AddIPWhitelist(cidr s
-       cmds.ExecCommands(commands, false)
- }
--func (r *redirect) RemoveIPWhitelist(cidr string) {
-+func (r *legacyRedirect) RemoveIPWhitelist(cidr string) {
-       var commands string
-       commands = fmt.Sprintf(`iptables -w 2 -t mangle -D TP_RULE -d %s -j RETURN`, cidr)
-       cmds.ExecCommands(commands, false)
- }
--func (r *redirect) GetSetupCommands() Setter {
-+func (r *legacyRedirect) GetSetupCommands() Setter {
-       commands := `
- iptables -w 2 -t nat -N TP_OUT
- iptables -w 2 -t nat -N TP_PRE
-@@ -84,11 +103,11 @@ ip6tables -w 2 -t nat -A TP_OUT -j TP_RU
- `
-       }
-       return Setter{
--              Cmds:      commands,
-+              Cmds: commands,
-       }
- }
--func (r *redirect) GetCleanCommands() Setter {
-+func (r *legacyRedirect) GetCleanCommands() Setter {
-       commands := `
- iptables -w 2 -t nat -F TP_OUT
- iptables -w 2 -t nat -D OUTPUT -p tcp -j TP_OUT
-@@ -112,6 +131,113 @@ ip6tables -w 2 -t nat -X TP_RULE
- `
-       }
-       return Setter{
--              Cmds:      commands,
-+              Cmds: commands,
-+      }
-+}
-+
-+func (t *nftRedirect) AddIPWhitelist(cidr string) {
-+      command := fmt.Sprintf("nft add element inet v2raya interface { %s }", cidr)
-+      if !strings.Contains(cidr, ".") {
-+              command = strings.Replace(command, "interface", "interface6", 1)
-+      }
-+      cmds.ExecCommands(command, false)
-+}
-+
-+func (t *nftRedirect) RemoveIPWhitelist(cidr string) {
-+      command := fmt.Sprintf("nft delete element inet v2raya interface { %s }", cidr)
-+      if !strings.Contains(cidr, ".") {
-+              command = strings.Replace(command, "interface", "interface6", 1)
-       }
-+      cmds.ExecCommands(command, false)
-+}
-+
-+func (r *nftRedirect) GetSetupCommands() Setter {
-+      // 198.18.0.0/15 and fc00::/7 are reserved for private use but used by fakedns
-+      table := `
-+table inet v2raya {
-+    set whitelist {
-+        type ipv4_addr
-+        flags interval
-+        auto-merge
-+        elements = {
-+            0.0.0.0/32,
-+            10.0.0.0/8,
-+            100.64.0.0/10,
-+            127.0.0.0/8,
-+            169.254.0.0/16,
-+            172.16.0.0/12,
-+            192.0.0.0/24,
-+            192.0.2.0/24,
-+            192.88.99.0/24,
-+            192.168.0.0/16,
-+            198.51.100.0/24,
-+            203.0.113.0/24,
-+            224.0.0.0/4,
-+            240.0.0.0/4
-+        }
-+    }
-+
-+    set whitelist6 {
-+        type ipv6_addr
-+        flags interval
-+        auto-merge
-+        elements = {
-+            ::/128,
-+            ::1/128,
-+            64:ff9b::/96,
-+            100::/64,
-+            2001::/32,
-+            2001:20::/28,
-+            fe80::/10,
-+            ff00::/8
-+        }
-+    }
-+
-+    set interface {
-+        type ipv4_addr
-+        flags interval
-+        auto-merge
-+    }
-+
-+    set interface6 {
-+        type ipv6_addr
-+        flags interval
-+        auto-merge
-+    }
-+
-+    chain tp_rule {
-+        ip daddr @whitelist return
-+        ip daddr @interface return
-+        ip6 daddr @whitelist6 return
-+        ip6 daddr @interface6 return
-+        meta mark & 0x80 == 0x80 return
-+        meta l4proto tcp redirect to :32345
-+    }
-+
-+    chain tp_pre {
-+        type nat hook prerouting priority dstnat - 5
-+        meta nfproto { ipv4, ipv6 } meta l4proto tcp jump tp_rule
-+    }
-+
-+    chain tp_out {
-+        type nat hook output priority -105
-+        meta nfproto { ipv4, ipv6 } meta l4proto tcp jump tp_rule
-+    }
-+}
-+`
-+      if !IsIPv6Supported() {
-+              table = strings.ReplaceAll(table, "meta nfproto { ipv4, ipv6 }", "meta nfproto ipv4")
-+      }
-+
-+      nftablesConf := asset.GetNFTablesConfigPath()
-+      os.WriteFile(nftablesConf, []byte(table), 0644)
-+
-+      command := `nft -f ` + nftablesConf
-+
-+      return Setter{Cmds: command}
-+}
-+
-+func (r *nftRedirect) GetCleanCommands() Setter {
-+      command := `nft delete table inet v2raya`
-+      return Setter{Cmds: command}
- }
---- a/core/iptables/tproxy.go
-+++ b/core/iptables/tproxy.go
-@@ -2,18 +2,36 @@ package iptables
- import (
-       "fmt"
-+      "os"
-+      "strings"
-+
-       "github.com/v2rayA/v2rayA/common/cmds"
-+      "github.com/v2rayA/v2rayA/core/v2ray/asset"
-       "github.com/v2rayA/v2rayA/db/configure"
--      "strings"
- )
--type tproxy struct {
--      watcher *LocalIPWatcher
-+type tproxy interface {
-+      AddIPWhitelist(cidr string)
-+      RemoveIPWhitelist(cidr string)
-+      GetSetupCommands() Setter
-+      GetCleanCommands() Setter
- }
-+type legacyTproxy struct{}
-+
-+type nftTproxy struct{}
-+
- var Tproxy tproxy
--func (t *tproxy) AddIPWhitelist(cidr string) {
-+func init() {
-+      if IsNFTablesSupported() {
-+              Tproxy = &nftTproxy{}
-+      } else {
-+              Tproxy = &legacyTproxy{}
-+      }
-+}
-+
-+func (t *legacyTproxy) AddIPWhitelist(cidr string) {
-       // avoid duplication
-       t.RemoveIPWhitelist(cidr)
-       pos := 7
-@@ -30,7 +48,7 @@ func (t *tproxy) AddIPWhitelist(cidr str
-       cmds.ExecCommands(commands, false)
- }
--func (t *tproxy) RemoveIPWhitelist(cidr string) {
-+func (t *legacyTproxy) RemoveIPWhitelist(cidr string) {
-       var commands string
-       commands = fmt.Sprintf(`iptables -w 2 -t mangle -D TP_RULE -d %s -j RETURN`, cidr)
-       if !strings.Contains(cidr, ".") {
-@@ -40,7 +58,7 @@ func (t *tproxy) RemoveIPWhitelist(cidr
-       cmds.ExecCommands(commands, false)
- }
--func (t *tproxy) GetSetupCommands() Setter {
-+func (t *legacyTproxy) GetSetupCommands() Setter {
-       commands := `
- ip rule add fwmark 0x40/0xc0 table 100
- ip route add local 0.0.0.0/0 dev lo table 100
-@@ -158,7 +176,7 @@ ip6tables -w 2 -t mangle -A TP_MARK -j C
-       }
- }
--func (t *tproxy) GetCleanCommands() Setter {
-+func (t *legacyTproxy) GetCleanCommands() Setter {
-       commands := `
- ip rule del fwmark 0x40/0xc0 table 100 
- ip route del local 0.0.0.0/0 dev lo table 100
-@@ -195,3 +213,166 @@ ip6tables -w 2 -t mangle -X TP_MARK
-               Cmds:      commands,
-       }
- }
-+
-+func (t *nftTproxy) AddIPWhitelist(cidr string) {
-+      command := fmt.Sprintf("nft add element inet v2raya interface { %s }", cidr)
-+      if !strings.Contains(cidr, ".") {
-+              command = strings.Replace(command, "interface", "interface6", 1)
-+      }
-+      cmds.ExecCommands(command, false)
-+}
-+
-+func (t *nftTproxy) RemoveIPWhitelist(cidr string) {
-+      command := fmt.Sprintf("nft delete element inet v2raya interface { %s }", cidr)
-+      if !strings.Contains(cidr, ".") {
-+              command = strings.Replace(command, "interface", "interface6", 1)
-+      }
-+      cmds.ExecCommands(command, false)
-+}
-+
-+func (t *nftTproxy) GetSetupCommands() Setter {
-+      // 198.18.0.0/15 and fc00::/7 are reserved for private use but used by fakedns
-+      table := `
-+table inet v2raya {
-+    set whitelist {
-+        type ipv4_addr
-+        flags interval
-+        auto-merge
-+        elements = {
-+            0.0.0.0/32,
-+            10.0.0.0/8,
-+            100.64.0.0/10,
-+            127.0.0.0/8,
-+            169.254.0.0/16,
-+            172.16.0.0/12,
-+            192.0.0.0/24,
-+            192.0.2.0/24,
-+            192.88.99.0/24,
-+            192.168.0.0/16,
-+            198.51.100.0/24,
-+            203.0.113.0/24,
-+            224.0.0.0/4,
-+            240.0.0.0/4
-+        }
-+    }
-+
-+    set whitelist6 {
-+        type ipv6_addr
-+        flags interval
-+        auto-merge
-+        elements = {
-+            ::/128,
-+            ::1/128,
-+            64:ff9b::/96,
-+            100::/64,
-+            2001::/32,
-+            2001:20::/28,
-+            fe80::/10,
-+            ff00::/8
-+        }
-+    }
-+
-+    set interface {
-+        type ipv4_addr
-+        flags interval
-+        auto-merge
-+    }
-+
-+    set interface6 {
-+        type ipv6_addr
-+        flags interval
-+        auto-merge
-+    }
-+
-+    chain tp_out {
-+        meta mark & 0x80 == 0x80 return
-+        meta l4proto { tcp, udp } fib saddr type local fib daddr type != local jump tp_rule
-+    }
-+
-+    chain tp_pre {
-+        iifname "lo" mark & 0xc0 != 0x40 return
-+        meta l4proto { tcp, udp } fib saddr type != local fib daddr type != local jump tp_rule
-+        meta l4proto { tcp, udp } mark & 0xc0 == 0x40 tproxy ip to 127.0.0.1:32345
-+        meta l4proto { tcp, udp } mark & 0xc0 == 0x40 tproxy ip6 to [::1]:32345
-+    }
-+
-+    chain output {
-+        type route hook output priority mangle - 5; policy accept;
-+        meta nfproto { ipv4, ipv6 } jump tp_out
-+    }
-+
-+    chain prerouting {
-+        type filter hook prerouting priority mangle - 5; policy accept;
-+        meta nfproto { ipv4, ipv6 } jump tp_pre
-+    }
-+
-+    chain tp_rule {
-+        meta mark set ct mark
-+        meta mark & 0xc0 == 0x40 return
-+        iifname "docker*" return
-+        iifname "veth*" return
-+        iifname "wg*" return
-+        iifname "ppp*" return
-+        # anti-pollution
-+        ip daddr @interface return
-+        ip daddr @whitelist return
-+        ip6 daddr @interface6 return
-+        ip6 daddr @whitelist6 return
-+        jump tp_mark
-+    }
-+
-+    chain tp_mark {
-+        tcp flags & (fin | syn | rst | ack) == syn meta mark set mark | 0x40
-+        meta l4proto udp ct state new meta mark set mark | 0x40
-+        ct mark set mark
-+    }
-+}
-+`
-+      if configure.GetSettingNotNil().AntiPollution != configure.AntipollutionClosed {
-+              table = strings.ReplaceAll(table, "# anti-pollution", `
-+        meta l4proto { tcp, udp } th dport 53 jump tp_mark
-+        meta mark & 0xc0 == 0x40 return
-+              `)
-+      }
-+
-+      if !IsIPv6Supported() {
-+              // drop ipv6 packets hooks
-+              table = strings.ReplaceAll(table, "meta nfproto { ipv4, ipv6 }", "meta nfproto ipv4")
-+      }
-+
-+      nftablesConf := asset.GetNFTablesConfigPath()
-+      os.WriteFile(nftablesConf, []byte(table), 0644)
-+
-+      command := `
-+ip rule add fwmark 0x40/0xc0 table 100
-+ip route add local 0.0.0.0/0 dev lo table 100
-+`
-+      if IsIPv6Supported() {
-+              command += `
-+ip -6 rule add fwmark 0x40/0xc0 table 100
-+ip -6 route add local ::/0 dev lo table 100
-+`
-+      }
-+
-+      command += `nft -f ` + nftablesConf
-+      return Setter{Cmds: command}
-+}
-+
-+func (t *nftTproxy) GetCleanCommands() Setter {
-+      command := `
-+ip rule del fwmark 0x40/0xc0 table 100
-+ip route del local 0.0.0.0/0 dev lo table 100
-+`
-+      if IsIPv6Supported() {
-+              command += `
-+ip -6 rule del fwmark 0x40/0xc0 table 100
-+ip -6 route del local ::/0 dev lo table 100
-+              `
-+      }
-+
-+      command += `nft delete table inet v2raya`
-+      if !IsIPv6Supported() {
-+              command = strings.Replace(command, "inet", "ip", 1)
-+      }
-+      return Setter{Cmds: command}
-+}
---- a/core/iptables/utils.go
-+++ b/core/iptables/utils.go
-@@ -1,12 +1,13 @@
- package iptables
- import (
-+      "net"
-+      "strconv"
-+
-       "github.com/v2rayA/v2rayA/common"
-       "github.com/v2rayA/v2rayA/common/cmds"
-       "github.com/v2rayA/v2rayA/conf"
-       "golang.org/x/net/nettest"
--      "net"
--      "strconv"
- )
- func IPNet2CIDR(ipnet *net.IPNet) string {
-@@ -44,3 +45,21 @@ func IsIPv6Supported() bool {
-       }
-       return cmds.IsCommandValid("ip6tables")
- }
-+
-+func IsNFTablesSupported() bool {
-+
-+      switch conf.GetEnvironmentConfig().NFTablesSupport {
-+      // Warning:
-+      // This is an experimental feature for nftables support.
-+      // The default value is "off" for now but may be changed to "auto" in the future
-+      case "on":
-+              return true
-+      case "off":
-+              return false
-+      default:
-+      }
-+      if common.IsDocker() {
-+              return false
-+      }
-+      return cmds.IsCommandValid("nft")
-+}
---- a/core/iptables/watcher.go
-+++ b/core/iptables/watcher.go
-@@ -10,6 +10,7 @@ type LocalIPWatcher struct {
-       cidrPool    map[string]struct{}
-       AddedFunc   func(cidr string)
-       RemovedFunc func(cidr string)
-+      UpdateFunc  func(cidrs []string)
- }
- func NewLocalIPWatcher(interval time.Duration, AddedFunc func(cidr string), RemovedFunc func(cidr string)) *LocalIPWatcher {
---- a/core/v2ray/asset/asset.go
-+++ b/core/v2ray/asset/asset.go
-@@ -3,12 +3,6 @@ package asset
- import (
-       "errors"
-       "fmt"
--      "github.com/adrg/xdg"
--      "github.com/muhammadmuzzammil1998/jsonc"
--      "github.com/v2rayA/v2rayA/common/files"
--      "github.com/v2rayA/v2rayA/conf"
--      "github.com/v2rayA/v2rayA/core/v2ray/where"
--      "github.com/v2rayA/v2rayA/pkg/util/log"
-       "io"
-       "io/fs"
-       "net/http"
-@@ -17,6 +11,13 @@ import (
-       "path/filepath"
-       "runtime"
-       "time"
-+
-+      "github.com/adrg/xdg"
-+      "github.com/muhammadmuzzammil1998/jsonc"
-+      "github.com/v2rayA/v2rayA/common/files"
-+      "github.com/v2rayA/v2rayA/conf"
-+      "github.com/v2rayA/v2rayA/core/v2ray/where"
-+      "github.com/v2rayA/v2rayA/pkg/util/log"
- )
- func GetV2rayLocationAssetOverride() string {
-@@ -140,6 +141,10 @@ func GetV2rayConfigDirPath() (p string)
-       return conf.GetEnvironmentConfig().V2rayConfigDirectory
- }
-+func GetNFTablesConfigPath() (p string) {
-+      return path.Join(conf.GetEnvironmentConfig().Config, "v2raya.nft")
-+}
-+
- func Download(url string, to string) (err error) {
-       log.Info("Downloading %v to %v", url, to)
-       c := http.Client{Timeout: 90 * time.Second}
---- a/core/v2ray/transparent.go
-+++ b/core/v2ray/transparent.go
-@@ -2,13 +2,14 @@ package v2ray
- import (
-       "fmt"
-+      "strings"
-+      "time"
-+
-       "github.com/v2rayA/v2rayA/conf"
-       "github.com/v2rayA/v2rayA/core/iptables"
-       "github.com/v2rayA/v2rayA/core/specialMode"
-       "github.com/v2rayA/v2rayA/db/configure"
-       "github.com/v2rayA/v2rayA/pkg/util/log"
--      "strings"
--      "time"
- )
- func deleteTransparentProxyRules() {
-@@ -45,12 +46,12 @@ func writeTransparentProxyRules() (err e
-                       }
-                       return fmt.Errorf("not support \"tproxy\" mode of transparent proxy: %w", err)
-               }
--              iptables.SetWatcher(&iptables.Tproxy)
-+              iptables.SetWatcher(iptables.Tproxy)
-       case configure.TransparentRedirect:
-               if err = iptables.Redirect.GetSetupCommands().Run(true); err != nil {
-                       return fmt.Errorf("not support \"redirect\" mode of transparent proxy: %w", err)
-               }
--              iptables.SetWatcher(&iptables.Redirect)
-+              iptables.SetWatcher(iptables.Redirect)
-       case configure.TransparentSystemProxy:
-               if err = iptables.SystemProxy.GetSetupCommands().Run(true); err != nil {
-                       return fmt.Errorf("not support \"system proxy\" mode of transparent proxy: %w", err)