diff --git a/.github/update.log b/.github/update.log index 0b2df56a08..283761f664 100644 --- a/.github/update.log +++ b/.github/update.log @@ -1190,3 +1190,4 @@ Update On Wed Nov 19 19:39:59 CET 2025 Update On Thu Nov 20 19:39:36 CET 2025 Update On Fri Nov 21 19:35:09 CET 2025 Update On Sat Nov 22 19:36:29 CET 2025 +Update On Sun Nov 23 19:36:55 CET 2025 diff --git a/clash-meta/.github/workflows/test.yml b/clash-meta/.github/workflows/test.yml index c6ac69cd46..ddddb5eee5 100644 --- a/clash-meta/.github/workflows/test.yml +++ b/clash-meta/.github/workflows/test.yml @@ -54,6 +54,11 @@ jobs: cd $(go env GOROOT) patch --verbose -p 1 < $GITHUB_WORKSPACE/.github/patch/go${{matrix.go-version}}.patch + - name: Remove inbound test for macOS + if: ${{ runner.os == 'macOS' }} + run: | + rm -rf listener/inbound/*_test.go + - name: Test run: go test ./... -v -count=1 diff --git a/clash-meta/config/config.go b/clash-meta/config/config.go index efc8903248..301126a61e 100644 --- a/clash-meta/config/config.go +++ b/clash-meta/config/config.go @@ -162,6 +162,7 @@ type DNS struct { FakeIPRange6 netip.Prefix FakeIPPool6 *fakeip.Pool FakeIPSkipper *fakeip.Skipper + FakeIPTTL int NameServerPolicy []dns.Policy ProxyServerNameserver []dns.NameServer DirectNameServer []dns.NameServer @@ -228,6 +229,7 @@ type RawDNS struct { FakeIPRange6 string `yaml:"fake-ip-range6" json:"fake-ip-range6"` FakeIPFilter []string `yaml:"fake-ip-filter" json:"fake-ip-filter"` FakeIPFilterMode C.FilterMode `yaml:"fake-ip-filter-mode" json:"fake-ip-filter-mode"` + FakeIPTTL int `yaml:"fake-ip-ttl" json:"fake-ip-ttl"` DefaultNameserver []string `yaml:"default-nameserver" json:"default-nameserver"` CacheAlgorithm string `yaml:"cache-algorithm" json:"cache-algorithm"` CacheMaxSize int `yaml:"cache-max-size" json:"cache-max-size"` @@ -490,6 +492,7 @@ func DefaultRawConfig() *RawConfig { IPv6Timeout: 100, EnhancedMode: C.DNSMapping, FakeIPRange: "198.18.0.1/16", + FakeIPTTL: 1, FallbackFilter: RawFallbackFilter{ GeoIP: true, GeoIPCode: "CN", @@ -1458,6 +1461,7 @@ func parseDNS(rawCfg *RawConfig, ruleProviders map[string]P.RuleProvider) (*DNS, Mode: cfg.FakeIPFilterMode, } dnsCfg.FakeIPSkipper = skipper + dnsCfg.FakeIPTTL = cfg.FakeIPTTL if dnsCfg.FakeIPRange.IsValid() { pool, err := fakeip.New(fakeip.Options{ diff --git a/clash-meta/dns/enhancer.go b/clash-meta/dns/enhancer.go index 7e34977258..0661362fd7 100644 --- a/clash-meta/dns/enhancer.go +++ b/clash-meta/dns/enhancer.go @@ -14,6 +14,7 @@ type ResolverEnhancer struct { fakeIPPool *fakeip.Pool fakeIPPool6 *fakeip.Pool fakeIPSkipper *fakeip.Skipper + fakeIPTTL int mapping *lru.LruCache[netip.Addr, string] useHosts bool } @@ -162,6 +163,7 @@ type EnhancerConfig struct { FakeIPPool *fakeip.Pool FakeIPPool6 *fakeip.Pool FakeIPSkipper *fakeip.Skipper + FakeIPTTL int UseHosts bool } @@ -177,6 +179,10 @@ func NewEnhancer(cfg EnhancerConfig) *ResolverEnhancer { e.fakeIPPool6 = cfg.FakeIPPool6 } e.fakeIPSkipper = cfg.FakeIPSkipper + e.fakeIPTTL = cfg.FakeIPTTL + if e.fakeIPTTL < 1 { + e.fakeIPTTL = 1 + } e.mapping = lru.New(lru.WithSize[netip.Addr, string](4096)) } diff --git a/clash-meta/dns/middleware.go b/clash-meta/dns/middleware.go index 4e026cd9ea..180cf00efb 100644 --- a/clash-meta/dns/middleware.go +++ b/clash-meta/dns/middleware.go @@ -146,7 +146,7 @@ func withMapping(mapping *lru.LruCache[netip.Addr, string]) middleware { } } -func withFakeIP(skipper *fakeip.Skipper, fakePool *fakeip.Pool, fakePool6 *fakeip.Pool) middleware { +func withFakeIP(skipper *fakeip.Skipper, fakePool *fakeip.Pool, fakePool6 *fakeip.Pool, fakeIPTTL int) middleware { return func(next handler) handler { return func(ctx *icontext.DNSContext, r *D.Msg) (*D.Msg, error) { q := r.Question[0] @@ -186,7 +186,7 @@ func withFakeIP(skipper *fakeip.Skipper, fakePool *fakeip.Pool, fakePool6 *fakei msg.Answer = []D.RR{rr} ctx.SetType(icontext.DNSTypeFakeIP) - setMsgTTL(msg, 1) + setMsgTTL(msg, uint32(fakeIPTTL)) msg.SetRcode(r, D.RcodeSuccess) msg.Authoritative = true msg.RecursionAvailable = true @@ -238,7 +238,7 @@ func newHandler(resolver *Resolver, mapper *ResolverEnhancer) handler { } if mapper.mode == C.DNSFakeIP { - middlewares = append(middlewares, withFakeIP(mapper.fakeIPSkipper, mapper.fakeIPPool, mapper.fakeIPPool6)) + middlewares = append(middlewares, withFakeIP(mapper.fakeIPSkipper, mapper.fakeIPPool, mapper.fakeIPPool6, mapper.fakeIPTTL)) } if mapper.mode != C.DNSNormal { diff --git a/clash-meta/docs/config.yaml b/clash-meta/docs/config.yaml index 8a5ec1f7d3..d6421e106a 100644 --- a/clash-meta/docs/config.yaml +++ b/clash-meta/docs/config.yaml @@ -275,6 +275,8 @@ dns: # 配置fake-ip-filter的匹配模式,默认为blacklist,即如果匹配成功不返回fake-ip # 可设置为whitelist,即只有匹配成功才返回fake-ip fake-ip-filter-mode: blacklist + # 配置fakeip查询返回的TTL,非必要情况下请勿修改 + fake-ip-ttl: 1 # use-hosts: true # 查询 hosts diff --git a/clash-meta/hub/executor/executor.go b/clash-meta/hub/executor/executor.go index 988d73e272..184e64de79 100644 --- a/clash-meta/hub/executor/executor.go +++ b/clash-meta/hub/executor/executor.go @@ -269,6 +269,7 @@ func updateDNS(c *config.DNS, generalIPv6 bool) { FakeIPPool: c.FakeIPPool, FakeIPPool6: c.FakeIPPool6, FakeIPSkipper: c.FakeIPSkipper, + FakeIPTTL: c.FakeIPTTL, UseHosts: c.UseHosts, }) diff --git a/clash-meta/listener/http/utils.go b/clash-meta/listener/http/utils.go index e0793ff3bb..eb19283da2 100644 --- a/clash-meta/listener/http/utils.go +++ b/clash-meta/listener/http/utils.go @@ -63,7 +63,11 @@ func removeExtraHTTPHostPort(req *http.Request) { // parseBasicProxyAuthorization parse header Proxy-Authorization and return base64-encoded credential func parseBasicProxyAuthorization(request *http.Request) string { value := request.Header.Get("Proxy-Authorization") - if !strings.HasPrefix(value, "Basic ") { + const prefix = "Basic " + // According to RFC7617, the scheme should be case-insensitive. + // In practice, some implementations do use different case styles, causing authentication to fail + // eg: https://github.com/algesten/ureq/blob/381fd42cfcb80a5eb709d64860aa0ae726f17b8e/src/unversioned/transport/connect.rs#L118 + if len(value) < len(prefix) || !strings.EqualFold(value[:len(prefix)], prefix) { return "" } diff --git a/clash-nyanpasu/manifest/version.json b/clash-nyanpasu/manifest/version.json index f00e0c0d78..8f05ecee9f 100644 --- a/clash-nyanpasu/manifest/version.json +++ b/clash-nyanpasu/manifest/version.json @@ -2,7 +2,7 @@ "manifest_version": 1, "latest": { "mihomo": "v1.19.16", - "mihomo_alpha": "alpha-c107c6a", + "mihomo_alpha": "alpha-140d892", "clash_rs": "v0.9.2", "clash_premium": "2023-09-05-gdcc8d87", "clash_rs_alpha": "0.9.2-alpha+sha.87c7b2c" @@ -69,5 +69,5 @@ "linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf" } }, - "updated_at": "2025-11-15T22:20:39.678Z" + "updated_at": "2025-11-22T22:21:07.536Z" } diff --git a/filebrowser/frontend/pnpm-lock.yaml b/filebrowser/frontend/pnpm-lock.yaml index 8b38a2a40f..c94699bb8b 100644 --- a/filebrowser/frontend/pnpm-lock.yaml +++ b/filebrowser/frontend/pnpm-lock.yaml @@ -161,7 +161,7 @@ importers: version: 2.3.1(rollup@4.53.3) vue-tsc: specifier: ^3.1.3 - version: 3.1.4(typescript@5.9.3) + version: 3.1.5(typescript@5.9.3) packages: @@ -1337,8 +1337,8 @@ packages: typescript: optional: true - '@vue/language-core@3.1.4': - resolution: {integrity: sha512-n/58wm8SkmoxMWkUNUH/PwoovWe4hmdyPJU2ouldr3EPi1MLoS7iDN46je8CsP95SnVBs2axInzRglPNKvqMcg==} + '@vue/language-core@3.1.5': + resolution: {integrity: sha512-FMcqyzWN+sYBeqRMWPGT2QY0mUasZMVIuHvmb5NT3eeqPrbHBYtCP8JWEUCDCgM+Zr62uuWY/qoeBrPrzfa78w==} peerDependencies: typescript: '*' peerDependenciesMeta: @@ -2518,8 +2518,8 @@ packages: peerDependencies: vue: ^3.0.2 - vue-tsc@3.1.4: - resolution: {integrity: sha512-GsRJxttj4WkmXW/zDwYPGMJAN3np/4jTzoDFQTpTsI5Vg/JKMWamBwamlmLihgSVHO66y9P7GX+uoliYxeI4Hw==} + vue-tsc@3.1.5: + resolution: {integrity: sha512-L/G9IUjOWhBU0yun89rv8fKqmKC+T0HfhrFjlIml71WpfBv9eb4E9Bev8FMbyueBIU9vxQqbd+oOsVcDa5amGw==} hasBin: true peerDependencies: typescript: '>=5.0.0' @@ -3905,7 +3905,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@vue/language-core@3.1.4(typescript@5.9.3)': + '@vue/language-core@3.1.5(typescript@5.9.3)': dependencies: '@volar/language-core': 2.4.23 '@vue/compiler-dom': 3.5.24 @@ -5043,10 +5043,10 @@ snapshots: dependencies: vue: 3.5.24(typescript@5.9.3) - vue-tsc@3.1.4(typescript@5.9.3): + vue-tsc@3.1.5(typescript@5.9.3): dependencies: '@volar/typescript': 2.4.23 - '@vue/language-core': 3.1.4(typescript@5.9.3) + '@vue/language-core': 3.1.5(typescript@5.9.3) typescript: 5.9.3 vue@3.5.24(typescript@5.9.3): diff --git a/lede/target/linux/bcm27xx/patches-6.12/950-0103-media-adv7180-Default-to-the-first-valid-input.patch b/lede/target/linux/bcm27xx/patches-6.12/950-0103-media-adv7180-Default-to-the-first-valid-input.patch index 52a113906f..c294e5286a 100644 --- a/lede/target/linux/bcm27xx/patches-6.12/950-0103-media-adv7180-Default-to-the-first-valid-input.patch +++ b/lede/target/linux/bcm27xx/patches-6.12/950-0103-media-adv7180-Default-to-the-first-valid-input.patch @@ -16,7 +16,7 @@ Signed-off-by: Dave Stevenson --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c -@@ -1362,6 +1362,7 @@ static const struct adv7180_chip_info ad +@@ -1352,6 +1352,7 @@ static const struct adv7180_chip_info ad static int init_device(struct adv7180_state *state) { int ret; @@ -24,7 +24,7 @@ Signed-off-by: Dave Stevenson mutex_lock(&state->mutex); -@@ -1409,6 +1410,18 @@ static int init_device(struct adv7180_st +@@ -1399,6 +1400,18 @@ static int init_device(struct adv7180_st goto out_unlock; } diff --git a/lede/target/linux/bcm27xx/patches-6.12/950-0104-media-adv7180-Add-YPrPb-support-for-ADV7282M.patch b/lede/target/linux/bcm27xx/patches-6.12/950-0104-media-adv7180-Add-YPrPb-support-for-ADV7282M.patch index 8669c93edb..1552f6358c 100644 --- a/lede/target/linux/bcm27xx/patches-6.12/950-0104-media-adv7180-Add-YPrPb-support-for-ADV7282M.patch +++ b/lede/target/linux/bcm27xx/patches-6.12/950-0104-media-adv7180-Add-YPrPb-support-for-ADV7282M.patch @@ -14,7 +14,7 @@ Signed-off-by: Dave Stevenson --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c -@@ -1351,6 +1351,7 @@ static const struct adv7180_chip_info ad +@@ -1341,6 +1341,7 @@ static const struct adv7180_chip_info ad BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | diff --git a/lede/target/linux/bcm27xx/patches-6.12/950-0295-media-adv7180-Nasty-hack-to-allow-input-selection.patch b/lede/target/linux/bcm27xx/patches-6.12/950-0295-media-adv7180-Nasty-hack-to-allow-input-selection.patch index c36033642b..fca52578af 100644 --- a/lede/target/linux/bcm27xx/patches-6.12/950-0295-media-adv7180-Nasty-hack-to-allow-input-selection.patch +++ b/lede/target/linux/bcm27xx/patches-6.12/950-0295-media-adv7180-Nasty-hack-to-allow-input-selection.patch @@ -30,7 +30,7 @@ Signed-off-by: Dave Stevenson struct adv7180_state; #define ADV7180_FLAG_RESET_POWERED BIT(0) -@@ -408,10 +412,24 @@ out: +@@ -403,10 +407,24 @@ out: return ret; } @@ -56,7 +56,7 @@ Signed-off-by: Dave Stevenson if (ret) return ret; -@@ -437,7 +455,11 @@ static int adv7180_program_std(struct ad +@@ -432,7 +450,11 @@ static int adv7180_program_std(struct ad static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std) { struct adv7180_state *state = to_state(sd); @@ -69,7 +69,7 @@ Signed-off-by: Dave Stevenson if (ret) return ret; -@@ -459,6 +481,8 @@ static int adv7180_g_std(struct v4l2_sub +@@ -454,6 +476,8 @@ static int adv7180_g_std(struct v4l2_sub { struct adv7180_state *state = to_state(sd); @@ -78,7 +78,7 @@ Signed-off-by: Dave Stevenson *norm = state->curr_norm; return 0; -@@ -900,6 +924,8 @@ static int adv7180_s_stream(struct v4l2_ +@@ -890,6 +914,8 @@ static int adv7180_s_stream(struct v4l2_ return 0; } diff --git a/lede/target/linux/bcm27xx/patches-6.12/950-0312-hwmon-sht3x-Add-DT-compatible-string.patch b/lede/target/linux/bcm27xx/patches-6.12/950-0312-hwmon-sht3x-Add-DT-compatible-string.patch index 6bb2725b28..2199a05860 100644 --- a/lede/target/linux/bcm27xx/patches-6.12/950-0312-hwmon-sht3x-Add-DT-compatible-string.patch +++ b/lede/target/linux/bcm27xx/patches-6.12/950-0312-hwmon-sht3x-Add-DT-compatible-string.patch @@ -10,7 +10,7 @@ Signed-off-by: Phil Elwell --- a/drivers/hwmon/sht3x.c +++ b/drivers/hwmon/sht3x.c -@@ -954,19 +954,19 @@ static int sht3x_probe(struct i2c_client +@@ -961,19 +961,19 @@ static int sht3x_probe(struct i2c_client return PTR_ERR_OR_ZERO(hwmon_dev); } diff --git a/lede/target/linux/bcm27xx/patches-6.12/950-0322-Bluetooth-hci_sync-Add-fallback-bd-address-prop.patch b/lede/target/linux/bcm27xx/patches-6.12/950-0322-Bluetooth-hci_sync-Add-fallback-bd-address-prop.patch index 81e8d31c1b..aea33e7533 100644 --- a/lede/target/linux/bcm27xx/patches-6.12/950-0322-Bluetooth-hci_sync-Add-fallback-bd-address-prop.patch +++ b/lede/target/linux/bcm27xx/patches-6.12/950-0322-Bluetooth-hci_sync-Add-fallback-bd-address-prop.patch @@ -20,7 +20,7 @@ Signed-off-by: Phil Elwell --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c -@@ -4930,6 +4930,7 @@ static const struct { +@@ -4935,6 +4935,7 @@ static const struct { */ static int hci_dev_setup_sync(struct hci_dev *hdev) { @@ -28,7 +28,7 @@ Signed-off-by: Phil Elwell int ret = 0; bool invalid_bdaddr; size_t i; -@@ -4958,7 +4959,8 @@ static int hci_dev_setup_sync(struct hci +@@ -4963,7 +4964,8 @@ static int hci_dev_setup_sync(struct hci test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks); if (!ret) { if (test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks) && diff --git a/lede/target/linux/bcm27xx/patches-6.12/950-0331-serial-sc16is7xx-Read-modem-line-state-at-startup.patch b/lede/target/linux/bcm27xx/patches-6.12/950-0331-serial-sc16is7xx-Read-modem-line-state-at-startup.patch index 686aba0ecf..5b5750aea0 100644 --- a/lede/target/linux/bcm27xx/patches-6.12/950-0331-serial-sc16is7xx-Read-modem-line-state-at-startup.patch +++ b/lede/target/linux/bcm27xx/patches-6.12/950-0331-serial-sc16is7xx-Read-modem-line-state-at-startup.patch @@ -16,7 +16,7 @@ Signed-off-by: Phil Elwell --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c -@@ -1196,6 +1196,9 @@ static int sc16is7xx_startup(struct uart +@@ -1189,6 +1189,9 @@ static int sc16is7xx_startup(struct uart SC16IS7XX_IER_MSI_BIT; sc16is7xx_port_write(port, SC16IS7XX_IER_REG, val); diff --git a/lede/target/linux/bcm27xx/patches-6.12/950-0392-fbdev-Allow-client-to-request-a-particular-dev-fbN-n.patch b/lede/target/linux/bcm27xx/patches-6.12/950-0392-fbdev-Allow-client-to-request-a-particular-dev-fbN-n.patch index 13e8d1bb3c..7b993d9987 100644 --- a/lede/target/linux/bcm27xx/patches-6.12/950-0392-fbdev-Allow-client-to-request-a-particular-dev-fbN-n.patch +++ b/lede/target/linux/bcm27xx/patches-6.12/950-0392-fbdev-Allow-client-to-request-a-particular-dev-fbN-n.patch @@ -55,7 +55,7 @@ Signed-off-by: Dave Stevenson #ifdef CONFIG_GUMSTIX_AM200EPD { -@@ -506,6 +509,12 @@ static void do_unregister_framebuffer(st +@@ -507,6 +510,12 @@ static void do_unregister_framebuffer(st put_fb_info(fb_info); } diff --git a/lede/target/linux/bcm27xx/patches-6.12/950-0402-drivers-thermal-step_wise-add-support-for-hysteresis.patch b/lede/target/linux/bcm27xx/patches-6.12/950-0402-drivers-thermal-step_wise-add-support-for-hysteresis.patch index d0c9fab6d4..b47c4322da 100644 --- a/lede/target/linux/bcm27xx/patches-6.12/950-0402-drivers-thermal-step_wise-add-support-for-hysteresis.patch +++ b/lede/target/linux/bcm27xx/patches-6.12/950-0402-drivers-thermal-step_wise-add-support-for-hysteresis.patch @@ -36,7 +36,7 @@ Signed-off-by: Jürgen Kreileder --- a/drivers/thermal/gov_step_wise.c +++ b/drivers/thermal/gov_step_wise.c -@@ -17,11 +17,11 @@ +@@ -17,13 +17,13 @@ #include "thermal_core.h" /* @@ -44,13 +44,15 @@ Signed-off-by: Jürgen Kreileder + * If the temperature is higher than a hysteresis temperature, * a. if the trend is THERMAL_TREND_RAISING, use higher cooling * state for this trip point - * b. if the trend is THERMAL_TREND_DROPPING, do nothing + * b. if the trend is THERMAL_TREND_DROPPING, use a lower cooling state + * for this trip point, but keep the cooling state above the applicable + * minimum - * If the temperature is lower than a trip point, + * If the temperature is lower than a hysteresis temperature, * a. if the trend is THERMAL_TREND_RAISING, do nothing * b. if the trend is THERMAL_TREND_DROPPING, use lower cooling * state for this trip point, if the cooling state already -@@ -74,19 +74,35 @@ static void thermal_zone_trip_update(str +@@ -87,19 +87,35 @@ static void thermal_zone_trip_update(str int trip_id = thermal_zone_trip_id(tz, trip); struct thermal_instance *instance; bool throttle = false; diff --git a/lede/target/linux/bcm27xx/patches-6.12/950-0409-media-i2c-adv7180-Use-MEDIA_BUS_FMT_UYVY8_1X16-for-C.patch b/lede/target/linux/bcm27xx/patches-6.12/950-0409-media-i2c-adv7180-Use-MEDIA_BUS_FMT_UYVY8_1X16-for-C.patch index 5790d79ade..9b86b31a5d 100644 --- a/lede/target/linux/bcm27xx/patches-6.12/950-0409-media-i2c-adv7180-Use-MEDIA_BUS_FMT_UYVY8_1X16-for-C.patch +++ b/lede/target/linux/bcm27xx/patches-6.12/950-0409-media-i2c-adv7180-Use-MEDIA_BUS_FMT_UYVY8_1X16-for-C.patch @@ -17,7 +17,7 @@ Signed-off-by: Dave Stevenson --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c -@@ -737,10 +737,15 @@ static int adv7180_enum_mbus_code(struct +@@ -732,10 +732,15 @@ static int adv7180_enum_mbus_code(struct struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { @@ -34,7 +34,7 @@ Signed-off-by: Dave Stevenson return 0; } -@@ -750,7 +755,10 @@ static int adv7180_mbus_fmt(struct v4l2_ +@@ -745,7 +750,10 @@ static int adv7180_mbus_fmt(struct v4l2_ { struct adv7180_state *state = to_state(sd); diff --git a/lede/target/linux/bcm27xx/patches-6.12/950-0410-media-i2c-adv7180-Add-support-for-V4L2_CID_LINK_FREQ.patch b/lede/target/linux/bcm27xx/patches-6.12/950-0410-media-i2c-adv7180-Add-support-for-V4L2_CID_LINK_FREQ.patch index 4bc7a684eb..d67112a069 100644 --- a/lede/target/linux/bcm27xx/patches-6.12/950-0410-media-i2c-adv7180-Add-support-for-V4L2_CID_LINK_FREQ.patch +++ b/lede/target/linux/bcm27xx/patches-6.12/950-0410-media-i2c-adv7180-Add-support-for-V4L2_CID_LINK_FREQ.patch @@ -1,18 +1,14 @@ -From 7e58b9c99676d641ef76edd9c097f1c3c4e6c464 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Thu, 21 Dec 2023 18:03:34 +0000 -Subject: [PATCH] media: i2c: adv7180: Add support for V4L2_CID_LINK_FREQ - -For CSI2 receivers that need to know the link frequency, -add it as a control to the driver. -Interlaced modes are 216Mbp/s or 108MHz, whilst going through -the I2P to deinterlace gives 432Mb/s or 216MHz. - -Signed-off-by: Dave Stevenson ---- - drivers/media/i2c/adv7180.c | 32 +++++++++++++++++++++++++++++++- - 1 file changed, 31 insertions(+), 1 deletion(-) - +From 954129f16c200e41a00ebebe2e22efc01b243538 Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Fri, 14 Nov 2025 14:08:18 +0000 +Subject: [PATCH] Revert "Revert "media: i2c: adv7180: Add support for + V4L2_CID_LINK_FREQ"" + +This reverts commit 00ecb85c58501f8f7ae75fcb069bbbad5542e853. +--- + drivers/media/i2c/adv7180.c | 39 +++++++++++++++++++++++++++++++++++-- + 1 file changed, 37 insertions(+), 2 deletions(-) + --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -189,6 +189,16 @@ @@ -40,7 +36,7 @@ Signed-off-by: Dave Stevenson }; #define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \ struct adv7180_state, \ -@@ -630,6 +641,9 @@ static int adv7180_s_ctrl(struct v4l2_ct +@@ -625,6 +636,9 @@ static int adv7180_s_ctrl(struct v4l2_ct if (ret) return ret; @@ -50,7 +46,7 @@ Signed-off-by: Dave Stevenson val = ctrl->val; switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: -@@ -671,6 +685,7 @@ static int adv7180_s_ctrl(struct v4l2_ct +@@ -666,6 +680,7 @@ static int adv7180_s_ctrl(struct v4l2_ct ret = -EINVAL; } @@ -58,7 +54,7 @@ Signed-off-by: Dave Stevenson mutex_unlock(&state->mutex); return ret; } -@@ -691,7 +706,7 @@ static const struct v4l2_ctrl_config adv +@@ -686,7 +701,7 @@ static const struct v4l2_ctrl_config adv static int adv7180_init_controls(struct adv7180_state *state) { @@ -67,7 +63,7 @@ Signed-off-by: Dave Stevenson v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, V4L2_CID_BRIGHTNESS, ADV7180_BRI_MIN, -@@ -717,6 +732,17 @@ static int adv7180_init_controls(struct +@@ -712,6 +727,17 @@ static int adv7180_init_controls(struct test_pattern_menu); } @@ -85,14 +81,21 @@ Signed-off-by: Dave Stevenson state->sd.ctrl_handler = &state->ctrl_hdl; if (state->ctrl_hdl.error) { int err = state->ctrl_hdl.error; -@@ -849,6 +875,10 @@ static int adv7180_set_pad_format(struct - adv7180_set_power(state, false); - adv7180_set_field_mode(state); - adv7180_set_power(state, true); +@@ -839,7 +865,16 @@ static int adv7180_set_pad_format(struct + ret = adv7180_mbus_fmt(sd, &format->format); + + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { +- state->field = format->format.field; ++ if (state->field != format->format.field) { ++ state->field = format->format.field; ++ adv7180_set_power(state, false); ++ adv7180_set_field_mode(state); ++ adv7180_set_power(state, true); + if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) + __v4l2_ctrl_s_ctrl(state->link_freq, + (state->field == V4L2_FIELD_NONE) ? + I2P_IDX : INTERLACED_IDX); - } ++ } } else { framefmt = v4l2_subdev_state_get_format(sd_state, 0); + *framefmt = format->format; diff --git a/lede/target/linux/bcm27xx/patches-6.12/950-0416-serial-sc16is7xx-Don-t-spin-if-no-data-received.patch b/lede/target/linux/bcm27xx/patches-6.12/950-0416-serial-sc16is7xx-Don-t-spin-if-no-data-received.patch index d668cf1857..26f662acdf 100644 --- a/lede/target/linux/bcm27xx/patches-6.12/950-0416-serial-sc16is7xx-Don-t-spin-if-no-data-received.patch +++ b/lede/target/linux/bcm27xx/patches-6.12/950-0416-serial-sc16is7xx-Don-t-spin-if-no-data-received.patch @@ -15,7 +15,7 @@ Signed-off-by: Phil Elwell --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c -@@ -821,6 +821,8 @@ static bool sc16is7xx_port_irq(struct sc +@@ -814,6 +814,8 @@ static bool sc16is7xx_port_irq(struct sc if (rxlen) sc16is7xx_handle_rx(port, rxlen, iir); diff --git a/lede/target/linux/bcm27xx/patches-6.12/950-0502-Bluetooth-hci_sync-Fix-crash-on-NULL-parent.patch b/lede/target/linux/bcm27xx/patches-6.12/950-0502-Bluetooth-hci_sync-Fix-crash-on-NULL-parent.patch index cb98eb72fb..db23f1f1ff 100644 --- a/lede/target/linux/bcm27xx/patches-6.12/950-0502-Bluetooth-hci_sync-Fix-crash-on-NULL-parent.patch +++ b/lede/target/linux/bcm27xx/patches-6.12/950-0502-Bluetooth-hci_sync-Fix-crash-on-NULL-parent.patch @@ -15,7 +15,7 @@ Signed-off-by: Phil Elwell --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c -@@ -4930,7 +4930,8 @@ static const struct { +@@ -4935,7 +4935,8 @@ static const struct { */ static int hci_dev_setup_sync(struct hci_dev *hdev) { diff --git a/lede/target/linux/bcm27xx/patches-6.12/950-0623-arm64-dts-broadcom-Add-display-pipeline-support-to-B.patch b/lede/target/linux/bcm27xx/patches-6.12/950-0623-arm64-dts-broadcom-Add-display-pipeline-support-to-B.patch index e5578b2d8e..f230101e7b 100644 --- a/lede/target/linux/bcm27xx/patches-6.12/950-0623-arm64-dts-broadcom-Add-display-pipeline-support-to-B.patch +++ b/lede/target/linux/bcm27xx/patches-6.12/950-0623-arm64-dts-broadcom-Add-display-pipeline-support-to-B.patch @@ -36,8 +36,8 @@ Signed-off-by: Dave Stevenson }; --- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi +++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi -@@ -265,6 +265,172 @@ - interrupt-controller; +@@ -268,6 +268,172 @@ + IRQ_TYPE_LEVEL_HIGH)>; #interrupt-cells = <3>; }; + @@ -209,7 +209,7 @@ Signed-off-by: Dave Stevenson }; timer { -@@ -280,4 +446,27 @@ +@@ -283,4 +449,27 @@ ; }; diff --git a/lede/target/linux/bcm27xx/patches-6.12/950-0628-arm64-dts-broadcom-Fixup-HVS-address-for-downstream-.patch b/lede/target/linux/bcm27xx/patches-6.12/950-0628-arm64-dts-broadcom-Fixup-HVS-address-for-downstream-.patch index a4a712e2b5..4dd931b964 100644 --- a/lede/target/linux/bcm27xx/patches-6.12/950-0628-arm64-dts-broadcom-Fixup-HVS-address-for-downstream-.patch +++ b/lede/target/linux/bcm27xx/patches-6.12/950-0628-arm64-dts-broadcom-Fixup-HVS-address-for-downstream-.patch @@ -14,7 +14,7 @@ Signed-off-by: Dave Stevenson --- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi +++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi -@@ -463,10 +463,10 @@ +@@ -466,10 +466,10 @@ hvs: hvs@107c580000 { compatible = "brcm,bcm2712-hvs"; diff --git a/lede/target/linux/bcm27xx/patches-6.12/950-0692-cgroup-Add-cgroup_enable-option.patch b/lede/target/linux/bcm27xx/patches-6.12/950-0692-cgroup-Add-cgroup_enable-option.patch index d44e050e02..64176cbfc7 100644 --- a/lede/target/linux/bcm27xx/patches-6.12/950-0692-cgroup-Add-cgroup_enable-option.patch +++ b/lede/target/linux/bcm27xx/patches-6.12/950-0692-cgroup-Add-cgroup_enable-option.patch @@ -17,7 +17,7 @@ Signed-off-by: Phil Elwell --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c -@@ -6916,6 +6916,39 @@ static int __init cgroup_disable(char *s +@@ -6932,6 +6932,39 @@ static int __init cgroup_disable(char *s } __setup("cgroup_disable=", cgroup_disable); diff --git a/lede/target/linux/bcm27xx/patches-6.12/950-0702-serial-sc16is7xx-announce-support-for-SER_RS485_RTS_.patch b/lede/target/linux/bcm27xx/patches-6.12/950-0702-serial-sc16is7xx-announce-support-for-SER_RS485_RTS_.patch index 7a8b37a00d..5109a9879d 100644 --- a/lede/target/linux/bcm27xx/patches-6.12/950-0702-serial-sc16is7xx-announce-support-for-SER_RS485_RTS_.patch +++ b/lede/target/linux/bcm27xx/patches-6.12/950-0702-serial-sc16is7xx-announce-support-for-SER_RS485_RTS_.patch @@ -31,7 +31,7 @@ Signed-off-by: Greg Kroah-Hartman --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c -@@ -1468,7 +1468,7 @@ static int sc16is7xx_setup_mctrl_ports(s +@@ -1461,7 +1461,7 @@ static int sc16is7xx_setup_mctrl_ports(s } static const struct serial_rs485 sc16is7xx_rs485_supported = { diff --git a/lede/target/linux/bcm27xx/patches-6.12/950-0794-arm64-dts-Prepare-for-size-cells-2.patch b/lede/target/linux/bcm27xx/patches-6.12/950-0794-arm64-dts-Prepare-for-size-cells-2.patch index e7f862d668..e9e661dbb8 100644 --- a/lede/target/linux/bcm27xx/patches-6.12/950-0794-arm64-dts-Prepare-for-size-cells-2.patch +++ b/lede/target/linux/bcm27xx/patches-6.12/950-0794-arm64-dts-Prepare-for-size-cells-2.patch @@ -72,7 +72,7 @@ Signed-off-by: Phil Elwell }; --- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi +++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi -@@ -463,7 +463,11 @@ +@@ -466,7 +466,11 @@ hvs: hvs@107c580000 { compatible = "brcm,bcm2712-hvs"; diff --git a/lede/target/linux/bcm27xx/patches-6.12/950-0900-arm64-dts-broadcom-bcm2712-Add-PCIe-DT-nodes.patch b/lede/target/linux/bcm27xx/patches-6.12/950-0900-arm64-dts-broadcom-bcm2712-Add-PCIe-DT-nodes.patch index 580088e861..5d619f8aa6 100644 --- a/lede/target/linux/bcm27xx/patches-6.12/950-0900-arm64-dts-broadcom-bcm2712-Add-PCIe-DT-nodes.patch +++ b/lede/target/linux/bcm27xx/patches-6.12/950-0900-arm64-dts-broadcom-bcm2712-Add-PCIe-DT-nodes.patch @@ -39,7 +39,7 @@ Signed-off-by: Stanimir Varbanov system_timer: timer@7c003000 { compatible = "brcm,bcm2835-system-timer"; reg = <0x7c003000 0x1000>; -@@ -431,6 +443,141 @@ +@@ -434,6 +446,141 @@ vc4: gpu { compatible = "brcm,bcm2712-vc6"; }; diff --git a/lede/target/linux/bcm27xx/patches-6.12/950-0949-PCI-quirks-work-around-VL805-firmware-ASPM-meddling.patch b/lede/target/linux/bcm27xx/patches-6.12/950-0949-PCI-quirks-work-around-VL805-firmware-ASPM-meddling.patch index e0c0cc105f..acc981dc2e 100644 --- a/lede/target/linux/bcm27xx/patches-6.12/950-0949-PCI-quirks-work-around-VL805-firmware-ASPM-meddling.patch +++ b/lede/target/linux/bcm27xx/patches-6.12/950-0949-PCI-quirks-work-around-VL805-firmware-ASPM-meddling.patch @@ -18,7 +18,7 @@ Signed-off-by: Jonathan Bell --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c -@@ -6255,6 +6255,22 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I +@@ -6256,6 +6256,22 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x56b1, aspm_l1_acceptable_latency); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x56c0, aspm_l1_acceptable_latency); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x56c1, aspm_l1_acceptable_latency); diff --git a/mieru/test/deploy/mihomo/test_client.sh b/mieru/test/deploy/mihomo/test_client.sh index 5d8a837cf0..37e2d49cb9 100755 --- a/mieru/test/deploy/mihomo/test_client.sh +++ b/mieru/test/deploy/mihomo/test_client.sh @@ -125,30 +125,30 @@ if [[ "$?" -ne 0 ]]; then fi echo "========== END OF CLIENT TCP TEST ==========" -# echo "========== BEGIN OF CLIENT UDP TEST ==========" -# ./mita apply config server_udp.json -# if [[ "$?" -ne 0 ]]; then -# echo "command 'mita apply config server_udp.json' failed" -# exit 1 -# fi -# echo "mieru server config:" -# ./mita describe config -# ./mita start -# if [[ "$?" -ne 0 ]]; then -# echo "command 'mita start' failed" -# exit 1 -# fi -# ./mihomo -f mihomo-client-udp.yaml & -# sleep 1 -# ./mihomo -f mihomo-client-udp-no-wait.yaml & -# sleep 1 -# run_udp_tests 1083 -# run_udp_tests 1084 "(handshake no wait)" -# print_mieru_server_metrics -# sleep 1 -# ./mita stop -# if [[ "$?" -ne 0 ]]; then -# echo "command 'mita stop' failed" -# exit 1 -# fi -# echo "========== END OF CLIENT UDP TEST ==========" +echo "========== BEGIN OF CLIENT UDP TEST ==========" +./mita apply config server_udp.json +if [[ "$?" -ne 0 ]]; then + echo "command 'mita apply config server_udp.json' failed" + exit 1 +fi +echo "mieru server config:" +./mita describe config +./mita start +if [[ "$?" -ne 0 ]]; then + echo "command 'mita start' failed" + exit 1 +fi +./mihomo -f mihomo-client-udp.yaml & +sleep 1 +./mihomo -f mihomo-client-udp-no-wait.yaml & +sleep 1 +run_udp_tests 1083 +run_udp_tests 1084 "(handshake no wait)" +print_mieru_server_metrics +sleep 1 +./mita stop +if [[ "$?" -ne 0 ]]; then + echo "command 'mita stop' failed" + exit 1 +fi +echo "========== END OF CLIENT UDP TEST ==========" diff --git a/mihomo/.github/workflows/test.yml b/mihomo/.github/workflows/test.yml index c6ac69cd46..ddddb5eee5 100644 --- a/mihomo/.github/workflows/test.yml +++ b/mihomo/.github/workflows/test.yml @@ -54,6 +54,11 @@ jobs: cd $(go env GOROOT) patch --verbose -p 1 < $GITHUB_WORKSPACE/.github/patch/go${{matrix.go-version}}.patch + - name: Remove inbound test for macOS + if: ${{ runner.os == 'macOS' }} + run: | + rm -rf listener/inbound/*_test.go + - name: Test run: go test ./... -v -count=1 diff --git a/mihomo/config/config.go b/mihomo/config/config.go index efc8903248..301126a61e 100644 --- a/mihomo/config/config.go +++ b/mihomo/config/config.go @@ -162,6 +162,7 @@ type DNS struct { FakeIPRange6 netip.Prefix FakeIPPool6 *fakeip.Pool FakeIPSkipper *fakeip.Skipper + FakeIPTTL int NameServerPolicy []dns.Policy ProxyServerNameserver []dns.NameServer DirectNameServer []dns.NameServer @@ -228,6 +229,7 @@ type RawDNS struct { FakeIPRange6 string `yaml:"fake-ip-range6" json:"fake-ip-range6"` FakeIPFilter []string `yaml:"fake-ip-filter" json:"fake-ip-filter"` FakeIPFilterMode C.FilterMode `yaml:"fake-ip-filter-mode" json:"fake-ip-filter-mode"` + FakeIPTTL int `yaml:"fake-ip-ttl" json:"fake-ip-ttl"` DefaultNameserver []string `yaml:"default-nameserver" json:"default-nameserver"` CacheAlgorithm string `yaml:"cache-algorithm" json:"cache-algorithm"` CacheMaxSize int `yaml:"cache-max-size" json:"cache-max-size"` @@ -490,6 +492,7 @@ func DefaultRawConfig() *RawConfig { IPv6Timeout: 100, EnhancedMode: C.DNSMapping, FakeIPRange: "198.18.0.1/16", + FakeIPTTL: 1, FallbackFilter: RawFallbackFilter{ GeoIP: true, GeoIPCode: "CN", @@ -1458,6 +1461,7 @@ func parseDNS(rawCfg *RawConfig, ruleProviders map[string]P.RuleProvider) (*DNS, Mode: cfg.FakeIPFilterMode, } dnsCfg.FakeIPSkipper = skipper + dnsCfg.FakeIPTTL = cfg.FakeIPTTL if dnsCfg.FakeIPRange.IsValid() { pool, err := fakeip.New(fakeip.Options{ diff --git a/mihomo/dns/enhancer.go b/mihomo/dns/enhancer.go index 7e34977258..0661362fd7 100644 --- a/mihomo/dns/enhancer.go +++ b/mihomo/dns/enhancer.go @@ -14,6 +14,7 @@ type ResolverEnhancer struct { fakeIPPool *fakeip.Pool fakeIPPool6 *fakeip.Pool fakeIPSkipper *fakeip.Skipper + fakeIPTTL int mapping *lru.LruCache[netip.Addr, string] useHosts bool } @@ -162,6 +163,7 @@ type EnhancerConfig struct { FakeIPPool *fakeip.Pool FakeIPPool6 *fakeip.Pool FakeIPSkipper *fakeip.Skipper + FakeIPTTL int UseHosts bool } @@ -177,6 +179,10 @@ func NewEnhancer(cfg EnhancerConfig) *ResolverEnhancer { e.fakeIPPool6 = cfg.FakeIPPool6 } e.fakeIPSkipper = cfg.FakeIPSkipper + e.fakeIPTTL = cfg.FakeIPTTL + if e.fakeIPTTL < 1 { + e.fakeIPTTL = 1 + } e.mapping = lru.New(lru.WithSize[netip.Addr, string](4096)) } diff --git a/mihomo/dns/middleware.go b/mihomo/dns/middleware.go index 4e026cd9ea..180cf00efb 100644 --- a/mihomo/dns/middleware.go +++ b/mihomo/dns/middleware.go @@ -146,7 +146,7 @@ func withMapping(mapping *lru.LruCache[netip.Addr, string]) middleware { } } -func withFakeIP(skipper *fakeip.Skipper, fakePool *fakeip.Pool, fakePool6 *fakeip.Pool) middleware { +func withFakeIP(skipper *fakeip.Skipper, fakePool *fakeip.Pool, fakePool6 *fakeip.Pool, fakeIPTTL int) middleware { return func(next handler) handler { return func(ctx *icontext.DNSContext, r *D.Msg) (*D.Msg, error) { q := r.Question[0] @@ -186,7 +186,7 @@ func withFakeIP(skipper *fakeip.Skipper, fakePool *fakeip.Pool, fakePool6 *fakei msg.Answer = []D.RR{rr} ctx.SetType(icontext.DNSTypeFakeIP) - setMsgTTL(msg, 1) + setMsgTTL(msg, uint32(fakeIPTTL)) msg.SetRcode(r, D.RcodeSuccess) msg.Authoritative = true msg.RecursionAvailable = true @@ -238,7 +238,7 @@ func newHandler(resolver *Resolver, mapper *ResolverEnhancer) handler { } if mapper.mode == C.DNSFakeIP { - middlewares = append(middlewares, withFakeIP(mapper.fakeIPSkipper, mapper.fakeIPPool, mapper.fakeIPPool6)) + middlewares = append(middlewares, withFakeIP(mapper.fakeIPSkipper, mapper.fakeIPPool, mapper.fakeIPPool6, mapper.fakeIPTTL)) } if mapper.mode != C.DNSNormal { diff --git a/mihomo/docs/config.yaml b/mihomo/docs/config.yaml index 8a5ec1f7d3..d6421e106a 100644 --- a/mihomo/docs/config.yaml +++ b/mihomo/docs/config.yaml @@ -275,6 +275,8 @@ dns: # 配置fake-ip-filter的匹配模式,默认为blacklist,即如果匹配成功不返回fake-ip # 可设置为whitelist,即只有匹配成功才返回fake-ip fake-ip-filter-mode: blacklist + # 配置fakeip查询返回的TTL,非必要情况下请勿修改 + fake-ip-ttl: 1 # use-hosts: true # 查询 hosts diff --git a/mihomo/hub/executor/executor.go b/mihomo/hub/executor/executor.go index 988d73e272..184e64de79 100644 --- a/mihomo/hub/executor/executor.go +++ b/mihomo/hub/executor/executor.go @@ -269,6 +269,7 @@ func updateDNS(c *config.DNS, generalIPv6 bool) { FakeIPPool: c.FakeIPPool, FakeIPPool6: c.FakeIPPool6, FakeIPSkipper: c.FakeIPSkipper, + FakeIPTTL: c.FakeIPTTL, UseHosts: c.UseHosts, }) diff --git a/mihomo/listener/http/utils.go b/mihomo/listener/http/utils.go index e0793ff3bb..eb19283da2 100644 --- a/mihomo/listener/http/utils.go +++ b/mihomo/listener/http/utils.go @@ -63,7 +63,11 @@ func removeExtraHTTPHostPort(req *http.Request) { // parseBasicProxyAuthorization parse header Proxy-Authorization and return base64-encoded credential func parseBasicProxyAuthorization(request *http.Request) string { value := request.Header.Get("Proxy-Authorization") - if !strings.HasPrefix(value, "Basic ") { + const prefix = "Basic " + // According to RFC7617, the scheme should be case-insensitive. + // In practice, some implementations do use different case styles, causing authentication to fail + // eg: https://github.com/algesten/ureq/blob/381fd42cfcb80a5eb709d64860aa0ae726f17b8e/src/unversioned/transport/connect.rs#L118 + if len(value) < len(prefix) || !strings.EqualFold(value[:len(prefix)], prefix) { return "" } diff --git a/openwrt-packages/filebrowser/Makefile b/openwrt-packages/filebrowser/Makefile index fe33f80220..3d59fa3ed3 100644 --- a/openwrt-packages/filebrowser/Makefile +++ b/openwrt-packages/filebrowser/Makefile @@ -5,12 +5,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=filebrowser -PKG_VERSION:=2.48.2 +PKG_VERSION:=2.49.0 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/filebrowser/filebrowser/tar.gz/v${PKG_VERSION}? -PKG_HASH:=382067b272689fac9f9edf293ff91941c20b7c45e58dc6d8d7330a7f08e81596 +PKG_HASH:=5f35beedf818feef315d84222dd957b8e10fab65a80a7d6ff10e22a31a11722f PKG_LICENSE:=Apache-2.0 PKG_LICENSE_FILES:=LICENSE diff --git a/openwrt-passwall/luci-app-passwall/luasrc/passwall/api.lua b/openwrt-passwall/luci-app-passwall/luasrc/passwall/api.lua index e320ee27a1..2e06645edf 100644 --- a/openwrt-passwall/luci-app-passwall/luasrc/passwall/api.lua +++ b/openwrt-passwall/luci-app-passwall/luasrc/passwall/api.lua @@ -292,9 +292,13 @@ function url(...) return require "luci.dispatcher".build_url(url) end -function trim(text) - if not text or text == "" then return "" end - return text:match("^%s*(.-)%s*$") +function trim(s) + local len = #s + local i, j = 1, len + while i <= len and s:byte(i) <= 32 do i = i + 1 end + while j >= i and s:byte(j) <= 32 do j = j - 1 end + if i > j then return "" end + return s:sub(i, j) end -- 分割字符串 @@ -1324,20 +1328,49 @@ end function get_std_domain(domain) domain = trim(domain) - if domain == "" or domain:find("#") then return "" end - -- 删除首尾所有的 . - domain = domain:gsub("^[%.]+", ""):gsub("[%.]+$", "") - -- 如果 domain 包含 '*',则分割并删除包含 '*' 的部分及其前面的部分 - if domain:find("%*") then - local parts = {} - for part in domain:gmatch("[^%.]+") do - table.insert(parts, part) + if domain == "" then return "" end + -- 含 # → "" + for i = 1, #domain do + if domain:byte(i) == 35 then return "" end -- '#' + end + local len = #domain + local si, ei = 1, len + -- 去前缀 '.' + while si <= len and domain:byte(si) == 46 do si = si + 1 end + -- 去后缀 '.' + while ei >= si and domain:byte(ei) == 46 do ei = ei - 1 end + if si > ei then return "" end + domain = domain:sub(si, ei) + len = #domain + -- 是否有 '*' + local star = false + for i = 1, len do + if domain:byte(i) == 42 then star = true break end + end + if not star then return domain end + -- 切割 label + local parts, pstart = {}, 1 + for i = 1, len + 1 do + local b = (i <= len) and domain:byte(i) or 46 -- '.' 作为结束 + if b == 46 then + parts[#parts + 1] = domain:sub(pstart, i - 1) + pstart = i + 1 end - for i = #parts, 1, -1 do - if parts[i]:find("%*") then - -- 删除包含 '*' 的部分及其前面的部分 - return parts[i + 1] and parts[i + 1] .. "." .. table.concat(parts, ".", i + 2) or "" + end + -- 从右向左找含 '*' ,并删除包含 '*' 的部分及其左边部分 + for i = #parts, 1, -1 do + local s = parts[i] + local has = false + for j = 1, #s do + if s:byte(j) == 42 then has = true break end + end + if has then + if i == #parts then return "" end + local out = parts[i + 1] + for k = i + 2, #parts do + out = out .. "." .. parts[k] end + return out end end return domain diff --git a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/rule_update.lua b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/rule_update.lua index 923a5dbe95..6a7a44a8ed 100755 --- a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/rule_update.lua +++ b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/rule_update.lua @@ -154,35 +154,13 @@ local function is_comment_line(s) end -- IPv4 检测,替代 string.find "^%d+%.%d+%.%d+%.%d+" -local function is_ipv4(s) - local dot = 0 - local last = 1 - local len = #s - for i = 1, len do - local b = s:byte(i) - if b == 46 then -- "." - dot = dot + 1 - if dot > 3 then return false end - if i == last then return false end - local seg = tonumber(s:sub(last, i - 1)) - if not seg or seg > 255 then return false end - last = i + 1 - elseif b < 48 or b > 57 then - return dot == 3 and i > last and tonumber(s:sub(last)) and tonumber(s:sub(last)) <= 255 - end - end - if dot ~= 3 or last > len then return false end - local seg = tonumber(s:sub(last)) - return seg and seg <= 255 -end - -- IPv4 cidr检测,替代 string.find "^%d+%.%d+%.%d+%.%d+[%/][%d]+$" -local function is_ipv4_cidr(s) +local function is_ipv4(s, check_cidr) local dot = 0 local seg_start = 1 local len = #s - local i = 1 local mask_start = nil + local i = 1 while i <= len do local b = s:byte(i) if b >= 48 and b <= 57 then @@ -194,6 +172,7 @@ local function is_ipv4_cidr(s) if not seg or seg > 255 then return false end seg_start = i + 1 elseif b == 47 then -- "/" + if not check_cidr then return false end if dot ~= 3 or i == seg_start then return false end local seg = tonumber(s:sub(seg_start, i - 1)) if not seg or seg > 255 then return false end @@ -204,26 +183,45 @@ local function is_ipv4_cidr(s) end i = i + 1 end - if not mask_start or mask_start > len then return false end - -- 检查 CIDR 掩码 + -- 如果没有 CIDR,则检查最后一段即可 + if not check_cidr or not mask_start then + if dot ~= 3 or seg_start > len then return false end + local seg = tonumber(s:sub(seg_start)) + return seg and seg <= 255 or false + end + -- CIDR 掩码检查 + if mask_start > len then return false end local mask = tonumber(s:sub(mask_start)) - if not mask or mask < 0 or mask > 32 then return false end - return true + return mask and mask >= 0 and mask <= 32 or false end --- IPv6 cidr检测,替代 string.find ":-[%x]+%:+[%x]-[%/][%d]+$" -local function is_ipv6_cidr(s) +local function is_ipv4_cidr(s) + return is_ipv4(s, true) +end + +local function is_ipv6(s, check_cidr) + local first = s:byte(1) + local last = s:byte(#s) + if first == 91 and last == 93 then -- "[" and "]" + s = s:sub(2, -2) + end local len = #s local i = 1 local seg_len = 0 local segs = 0 - local saw_dc = false + local saw_dc = false -- 是否出现 "::" local b while i <= len do b = s:byte(i) - if b == 47 then + -- CIDR 部分 + if b == 47 then -- '/' + if not check_cidr then + return false + end + -- 处理 "/" 之前的段 if seg_len > 0 then segs = segs + 1 end if (not saw_dc and segs ~= 8) or (saw_dc and segs > 8) then return false end + -- 解析掩码 i = i + 1 if i > len then return false end local mask = 0 @@ -234,29 +232,46 @@ local function is_ipv6_cidr(s) if mask > 128 then return false end i = i + 1 end + -- CIDR 解析成功 return true - elseif b == 58 then - if i + 1 <= len and s:byte(i + 1) == 58 then + end + -- 冒号处理(: 或 ::) + if b == 58 then + local nextb = (i+1 <= len) and s:byte(i+1) or 0 + -- "::" + if nextb == 58 then if saw_dc then return false end saw_dc = true - if seg_len > 0 then segs = segs + 1; seg_len = 0 end + if seg_len > 0 then segs = segs + 1 end + seg_len = 0 i = i + 2 else + -- 普通 ":" if seg_len == 0 then return false end segs = segs + 1 seg_len = 0 i = i + 1 end else - if not ((b >= 48 and b <= 57) or (b >= 65 and b <= 70) or (b >= 97 and b <= 102)) then - return false - end + -- hex 数字 + local is_hex = + (b >= 48 and b <= 57) or -- 0-9 + (b >= 65 and b <= 70) or -- A-F + (b >= 97 and b <= 102) -- a-f + if not is_hex then return false end seg_len = seg_len + 1 if seg_len > 4 then return false end i = i + 1 end end - return false + if seg_len > 0 then segs = segs + 1 end + if not saw_dc then return segs == 8 end + return segs <= 8 +end + +-- IPv6 cidr检测,替代 string.find ":-[%x]+%:+[%x]-[%/][%d]+$" +local function is_ipv6_cidr(s) + return is_ipv6(s, true) end -- 检测是否含有冒号,替代 string.find(line, ":") diff --git a/shadowsocks-rust/Cargo.toml b/shadowsocks-rust/Cargo.toml index a832e8ce4e..8514b05345 100644 --- a/shadowsocks-rust/Cargo.toml +++ b/shadowsocks-rust/Cargo.toml @@ -126,6 +126,7 @@ dns-over-h3 = ["shadowsocks-service/dns-over-h3"] # Enable logging output logging = [ "log4rs", + "syslog-tracing", "tracing", "tracing-subscriber", "time", @@ -249,7 +250,7 @@ windows-service = { version = "0.8", optional = true } [target.'cfg(unix)'.dependencies] xdg = "3.0" -syslog-tracing = "0.3" +syslog-tracing = { version = "0.3", optional = true } [target.'cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))'.dependencies] reqwest = { version = "0.12", features = [ diff --git a/shadowsocks-rust/src/logging/tracing.rs b/shadowsocks-rust/src/logging/tracing.rs index 3fc194df90..657ae92f70 100644 --- a/shadowsocks-rust/src/logging/tracing.rs +++ b/shadowsocks-rust/src/logging/tracing.rs @@ -212,10 +212,8 @@ fn make_syslog_writer(bin_name: &str, config: &LogSyslogWriterConfig) -> Syslog let options = Options::default(); let identity = CString::new(identity).expect("syslog identity contains null-byte ('\\0')"); - let syslogger = match Syslog::new(identity, options, facility) { + match Syslog::new(identity, options, facility) { Some(l) => l, None => panic!("syslog is already initialized"), - }; - - syslogger + } } diff --git a/sing-box/.github/setup_go_for_windows7.sh b/sing-box/.github/setup_go_for_windows7.sh index 2344453f8e..70db643ea6 100755 --- a/sing-box/.github/setup_go_for_windows7.sh +++ b/sing-box/.github/setup_go_for_windows7.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -VERSION="1.25.3" +VERSION="1.25.4" mkdir -p $HOME/go cd $HOME/go diff --git a/sing-box/.github/workflows/build.yml b/sing-box/.github/workflows/build.yml index b5de8edd31..b5a86c87c3 100644 --- a/sing-box/.github/workflows/build.yml +++ b/sing-box/.github/workflows/build.yml @@ -46,7 +46,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ^1.25.3 + go-version: ^1.25.4 - name: Check input version if: github.event_name == 'workflow_dispatch' run: |- @@ -103,15 +103,15 @@ jobs: with: fetch-depth: 0 - name: Setup Go - if: ${{ ! (matrix.legacy_go123 || matrix.legacy_go124) }} + if: ${{ ! (matrix.legacy_win7 || matrix.legacy_go124) }} uses: actions/setup-go@v5 with: - go-version: ^1.25.3 + go-version: ^1.25.4 - name: Setup Go 1.24 if: matrix.legacy_go124 uses: actions/setup-go@v5 with: - go-version: ~1.24.6 + go-version: ~1.24.10 - name: Cache Go for Windows 7 if: matrix.legacy_win7 id: cache-go-for-windows7 @@ -119,7 +119,7 @@ jobs: with: path: | ~/go/go_win7 - key: go_win7_1253 + key: go_win7_1254 - name: Setup Go for Windows 7 if: matrix.legacy_win7 && steps.cache-go-for-windows7.outputs.cache-hit != 'true' run: |- @@ -367,7 +367,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ^1.25.3 + go-version: ^1.25.4 - name: Setup Android NDK id: setup-ndk uses: nttld/setup-ndk@v1 @@ -447,7 +447,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ^1.25.3 + go-version: ^1.25.4 - name: Setup Android NDK id: setup-ndk uses: nttld/setup-ndk@v1 @@ -546,7 +546,7 @@ jobs: if: matrix.if uses: actions/setup-go@v5 with: - go-version: ^1.25.3 + go-version: ^1.25.4 - name: Set tag if: matrix.if run: |- diff --git a/sing-box/.github/workflows/linux.yml b/sing-box/.github/workflows/linux.yml index 46a680160c..ca29e05062 100644 --- a/sing-box/.github/workflows/linux.yml +++ b/sing-box/.github/workflows/linux.yml @@ -30,7 +30,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ^1.25.3 + go-version: ^1.25.4 - name: Check input version if: github.event_name == 'workflow_dispatch' run: |- @@ -71,7 +71,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ^1.25.3 + go-version: ^1.25.4 - name: Setup Android NDK if: matrix.os == 'android' uses: nttld/setup-ndk@v1 diff --git a/sing-box/adapter/upstream.go b/sing-box/adapter/upstream.go index 8b0d7c035b..59c8f75f6d 100644 --- a/sing-box/adapter/upstream.go +++ b/sing-box/adapter/upstream.go @@ -73,7 +73,7 @@ func NewUpstreamContextHandlerEx( } func (w *myUpstreamContextHandlerWrapperEx) NewConnectionEx(ctx context.Context, conn net.Conn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) { - myMetadata := ContextFrom(ctx) + _, myMetadata := ExtendContext(ctx) if source.IsValid() { myMetadata.Source = source } @@ -84,7 +84,7 @@ func (w *myUpstreamContextHandlerWrapperEx) NewConnectionEx(ctx context.Context, } func (w *myUpstreamContextHandlerWrapperEx) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) { - myMetadata := ContextFrom(ctx) + _, myMetadata := ExtendContext(ctx) if source.IsValid() { myMetadata.Source = source } @@ -146,7 +146,7 @@ type routeContextHandlerWrapperEx struct { } func (r *routeContextHandlerWrapperEx) NewConnectionEx(ctx context.Context, conn net.Conn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) { - metadata := ContextFrom(ctx) + _, metadata := ExtendContext(ctx) if source.IsValid() { metadata.Source = source } @@ -157,7 +157,7 @@ func (r *routeContextHandlerWrapperEx) NewConnectionEx(ctx context.Context, conn } func (r *routeContextHandlerWrapperEx) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) { - metadata := ContextFrom(ctx) + _, metadata := ExtendContext(ctx) if source.IsValid() { metadata.Source = source } diff --git a/sing-box/clients/android/app/src/main/java/io/nekohasekai/sfa/bg/TileService.kt b/sing-box/clients/android/app/src/main/java/io/nekohasekai/sfa/bg/TileService.kt index 8ea482fd40..30fa9302d7 100644 --- a/sing-box/clients/android/app/src/main/java/io/nekohasekai/sfa/bg/TileService.kt +++ b/sing-box/clients/android/app/src/main/java/io/nekohasekai/sfa/bg/TileService.kt @@ -1,5 +1,7 @@ package io.nekohasekai.sfa.bg +import android.app.KeyguardManager +import android.content.Context import android.service.quicksettings.Tile import android.service.quicksettings.TileService import androidx.annotation.RequiresApi @@ -32,15 +34,20 @@ class TileService : TileService(), ServiceConnection.Callback { } override fun onClick() { + val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager + if (keyguardManager.isKeyguardLocked) { + unlockAndRun { + toggleService() + } + } else { + toggleService() + } + } + + private fun toggleService() { when (connection.status) { - Status.Stopped -> { - BoxService.start() - } - - Status.Started -> { - BoxService.stop() - } - + Status.Stopped -> BoxService.start() + Status.Started -> BoxService.stop() else -> {} } } diff --git a/sing-box/clients/android/app/src/main/java/io/nekohasekai/sfa/ui/ShortcutActivity.kt b/sing-box/clients/android/app/src/main/java/io/nekohasekai/sfa/ui/ShortcutActivity.kt index 307af1248e..a91e0b6c35 100644 --- a/sing-box/clients/android/app/src/main/java/io/nekohasekai/sfa/ui/ShortcutActivity.kt +++ b/sing-box/clients/android/app/src/main/java/io/nekohasekai/sfa/ui/ShortcutActivity.kt @@ -1,6 +1,7 @@ package io.nekohasekai.sfa.ui import android.app.Activity +import android.app.KeyguardManager import android.content.Intent import android.content.pm.ShortcutManager import android.os.Build @@ -43,13 +44,39 @@ class ShortcutActivity : Activity(), ServiceConnection.Callback { ) finish() } else { - connection.connect() - if (Build.VERSION.SDK_INT >= 25) { - getSystemService()?.reportShortcutUsed("toggle") + val keyguardManager = getSystemService() + if (keyguardManager?.isKeyguardLocked == true) { + if (Build.VERSION.SDK_INT >= 26) { + keyguardManager.requestDismissKeyguard(this, object : KeyguardManager.KeyguardDismissCallback() { + override fun onDismissSucceeded() { + super.onDismissSucceeded() + connectAndToggle() + } + override fun onDismissCancelled() { + super.onDismissCancelled() + finish() + } + override fun onDismissError() { + super.onDismissError() + finish() + } + }) + } else { + finish() + } + } else { + connectAndToggle() } } } + private fun connectAndToggle() { + connection.connect() + if (Build.VERSION.SDK_INT >= 25) { + getSystemService()?.reportShortcutUsed("toggle") + } + } + override fun onServiceStatusChanged(status: Status) { when (status) { Status.Started -> BoxService.stop() diff --git a/sing-box/clients/android/version.properties b/sing-box/clients/android/version.properties index 78cfee0f59..eca3c70a1b 100644 --- a/sing-box/clients/android/version.properties +++ b/sing-box/clients/android/version.properties @@ -1,3 +1,3 @@ -VERSION_CODE=587 -VERSION_NAME=1.12.12 -GO_VERSION=go1.25.3 +VERSION_CODE=588 +VERSION_NAME=1.12.13 +GO_VERSION=go1.25.4 diff --git a/sing-box/docs/changelog.md b/sing-box/docs/changelog.md index 2eb606d37e..ff50b42c26 100644 --- a/sing-box/docs/changelog.md +++ b/sing-box/docs/changelog.md @@ -2,10 +2,20 @@ icon: material/alert-decagram --- -#### 1.13.0-alpha.27 +#### 1.13.0-alpha.28 * Fixes and improvements +_We are currently unable to notarize the standalone version of SFM for unknown reasons (TestFlight users are not affected). +Providing this update is not recommended for package managers that offer SFM standalone binaries._ + +#### 1.12.13 + +* Fixes and improvements + +_We are currently unable to notarize the standalone version of SFM for unknown reasons (TestFlight users are not affected). +Providing this update is not recommended for package managers that offer SFM standalone binaries._ + #### 1.12.12 * Fixes and improvements diff --git a/small/gn/Makefile b/small/gn/Makefile index 54d4b12fd7..c4c6849464 100644 --- a/small/gn/Makefile +++ b/small/gn/Makefile @@ -9,9 +9,9 @@ PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://gn.googlesource.com/gn.git -PKG_SOURCE_DATE:=2025-11-16 -PKG_SOURCE_VERSION:=748c9571f3d18820a7989a880d5ddf220e54af1b -PKG_MIRROR_HASH:=46b5fd492c3209018f8cc769135b6eb7c1654e5ff8fb2b74b8295d29813623f5 +PKG_SOURCE_DATE:=2025-11-23 +PKG_SOURCE_VERSION:=a156d0b1306b09bf676a72e345ca978ef6093d95 +PKG_MIRROR_HASH:=04ae2d1ecc0dbdc43e0793aad17d0031858ff48cdfd4c07809eac0b45becf7c2 PKG_LICENSE:=BSD 3-Clause PKG_LICENSE_FILES:=LICENSE diff --git a/small/gn/src/out/last_commit_position.h b/small/gn/src/out/last_commit_position.h index 47f61f975b..f79236f41f 100644 --- a/small/gn/src/out/last_commit_position.h +++ b/small/gn/src/out/last_commit_position.h @@ -3,7 +3,7 @@ #ifndef OUT_LAST_COMMIT_POSITION_H_ #define OUT_LAST_COMMIT_POSITION_H_ -#define LAST_COMMIT_POSITION_NUM 2295 -#define LAST_COMMIT_POSITION "2295 (748c9571f3d1)" +#define LAST_COMMIT_POSITION_NUM 2300 +#define LAST_COMMIT_POSITION "2300 (a156d0b1306b)" #endif // OUT_LAST_COMMIT_POSITION_H_ diff --git a/small/luci-app-passwall/luasrc/passwall/api.lua b/small/luci-app-passwall/luasrc/passwall/api.lua index e320ee27a1..2e06645edf 100644 --- a/small/luci-app-passwall/luasrc/passwall/api.lua +++ b/small/luci-app-passwall/luasrc/passwall/api.lua @@ -292,9 +292,13 @@ function url(...) return require "luci.dispatcher".build_url(url) end -function trim(text) - if not text or text == "" then return "" end - return text:match("^%s*(.-)%s*$") +function trim(s) + local len = #s + local i, j = 1, len + while i <= len and s:byte(i) <= 32 do i = i + 1 end + while j >= i and s:byte(j) <= 32 do j = j - 1 end + if i > j then return "" end + return s:sub(i, j) end -- 分割字符串 @@ -1324,20 +1328,49 @@ end function get_std_domain(domain) domain = trim(domain) - if domain == "" or domain:find("#") then return "" end - -- 删除首尾所有的 . - domain = domain:gsub("^[%.]+", ""):gsub("[%.]+$", "") - -- 如果 domain 包含 '*',则分割并删除包含 '*' 的部分及其前面的部分 - if domain:find("%*") then - local parts = {} - for part in domain:gmatch("[^%.]+") do - table.insert(parts, part) + if domain == "" then return "" end + -- 含 # → "" + for i = 1, #domain do + if domain:byte(i) == 35 then return "" end -- '#' + end + local len = #domain + local si, ei = 1, len + -- 去前缀 '.' + while si <= len and domain:byte(si) == 46 do si = si + 1 end + -- 去后缀 '.' + while ei >= si and domain:byte(ei) == 46 do ei = ei - 1 end + if si > ei then return "" end + domain = domain:sub(si, ei) + len = #domain + -- 是否有 '*' + local star = false + for i = 1, len do + if domain:byte(i) == 42 then star = true break end + end + if not star then return domain end + -- 切割 label + local parts, pstart = {}, 1 + for i = 1, len + 1 do + local b = (i <= len) and domain:byte(i) or 46 -- '.' 作为结束 + if b == 46 then + parts[#parts + 1] = domain:sub(pstart, i - 1) + pstart = i + 1 end - for i = #parts, 1, -1 do - if parts[i]:find("%*") then - -- 删除包含 '*' 的部分及其前面的部分 - return parts[i + 1] and parts[i + 1] .. "." .. table.concat(parts, ".", i + 2) or "" + end + -- 从右向左找含 '*' ,并删除包含 '*' 的部分及其左边部分 + for i = #parts, 1, -1 do + local s = parts[i] + local has = false + for j = 1, #s do + if s:byte(j) == 42 then has = true break end + end + if has then + if i == #parts then return "" end + local out = parts[i + 1] + for k = i + 2, #parts do + out = out .. "." .. parts[k] end + return out end end return domain diff --git a/small/luci-app-passwall/root/usr/share/passwall/rule_update.lua b/small/luci-app-passwall/root/usr/share/passwall/rule_update.lua index 923a5dbe95..6a7a44a8ed 100755 --- a/small/luci-app-passwall/root/usr/share/passwall/rule_update.lua +++ b/small/luci-app-passwall/root/usr/share/passwall/rule_update.lua @@ -154,35 +154,13 @@ local function is_comment_line(s) end -- IPv4 检测,替代 string.find "^%d+%.%d+%.%d+%.%d+" -local function is_ipv4(s) - local dot = 0 - local last = 1 - local len = #s - for i = 1, len do - local b = s:byte(i) - if b == 46 then -- "." - dot = dot + 1 - if dot > 3 then return false end - if i == last then return false end - local seg = tonumber(s:sub(last, i - 1)) - if not seg or seg > 255 then return false end - last = i + 1 - elseif b < 48 or b > 57 then - return dot == 3 and i > last and tonumber(s:sub(last)) and tonumber(s:sub(last)) <= 255 - end - end - if dot ~= 3 or last > len then return false end - local seg = tonumber(s:sub(last)) - return seg and seg <= 255 -end - -- IPv4 cidr检测,替代 string.find "^%d+%.%d+%.%d+%.%d+[%/][%d]+$" -local function is_ipv4_cidr(s) +local function is_ipv4(s, check_cidr) local dot = 0 local seg_start = 1 local len = #s - local i = 1 local mask_start = nil + local i = 1 while i <= len do local b = s:byte(i) if b >= 48 and b <= 57 then @@ -194,6 +172,7 @@ local function is_ipv4_cidr(s) if not seg or seg > 255 then return false end seg_start = i + 1 elseif b == 47 then -- "/" + if not check_cidr then return false end if dot ~= 3 or i == seg_start then return false end local seg = tonumber(s:sub(seg_start, i - 1)) if not seg or seg > 255 then return false end @@ -204,26 +183,45 @@ local function is_ipv4_cidr(s) end i = i + 1 end - if not mask_start or mask_start > len then return false end - -- 检查 CIDR 掩码 + -- 如果没有 CIDR,则检查最后一段即可 + if not check_cidr or not mask_start then + if dot ~= 3 or seg_start > len then return false end + local seg = tonumber(s:sub(seg_start)) + return seg and seg <= 255 or false + end + -- CIDR 掩码检查 + if mask_start > len then return false end local mask = tonumber(s:sub(mask_start)) - if not mask or mask < 0 or mask > 32 then return false end - return true + return mask and mask >= 0 and mask <= 32 or false end --- IPv6 cidr检测,替代 string.find ":-[%x]+%:+[%x]-[%/][%d]+$" -local function is_ipv6_cidr(s) +local function is_ipv4_cidr(s) + return is_ipv4(s, true) +end + +local function is_ipv6(s, check_cidr) + local first = s:byte(1) + local last = s:byte(#s) + if first == 91 and last == 93 then -- "[" and "]" + s = s:sub(2, -2) + end local len = #s local i = 1 local seg_len = 0 local segs = 0 - local saw_dc = false + local saw_dc = false -- 是否出现 "::" local b while i <= len do b = s:byte(i) - if b == 47 then + -- CIDR 部分 + if b == 47 then -- '/' + if not check_cidr then + return false + end + -- 处理 "/" 之前的段 if seg_len > 0 then segs = segs + 1 end if (not saw_dc and segs ~= 8) or (saw_dc and segs > 8) then return false end + -- 解析掩码 i = i + 1 if i > len then return false end local mask = 0 @@ -234,29 +232,46 @@ local function is_ipv6_cidr(s) if mask > 128 then return false end i = i + 1 end + -- CIDR 解析成功 return true - elseif b == 58 then - if i + 1 <= len and s:byte(i + 1) == 58 then + end + -- 冒号处理(: 或 ::) + if b == 58 then + local nextb = (i+1 <= len) and s:byte(i+1) or 0 + -- "::" + if nextb == 58 then if saw_dc then return false end saw_dc = true - if seg_len > 0 then segs = segs + 1; seg_len = 0 end + if seg_len > 0 then segs = segs + 1 end + seg_len = 0 i = i + 2 else + -- 普通 ":" if seg_len == 0 then return false end segs = segs + 1 seg_len = 0 i = i + 1 end else - if not ((b >= 48 and b <= 57) or (b >= 65 and b <= 70) or (b >= 97 and b <= 102)) then - return false - end + -- hex 数字 + local is_hex = + (b >= 48 and b <= 57) or -- 0-9 + (b >= 65 and b <= 70) or -- A-F + (b >= 97 and b <= 102) -- a-f + if not is_hex then return false end seg_len = seg_len + 1 if seg_len > 4 then return false end i = i + 1 end end - return false + if seg_len > 0 then segs = segs + 1 end + if not saw_dc then return segs == 8 end + return segs <= 8 +end + +-- IPv6 cidr检测,替代 string.find ":-[%x]+%:+[%x]-[%/][%d]+$" +local function is_ipv6_cidr(s) + return is_ipv6(s, true) end -- 检测是否含有冒号,替代 string.find(line, ":") diff --git a/small/v2ray-core/Makefile b/small/v2ray-core/Makefile index a6ad441c00..01256fcf1a 100644 --- a/small/v2ray-core/Makefile +++ b/small/v2ray-core/Makefile @@ -5,12 +5,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=v2ray-core -PKG_VERSION:=5.41.0 +PKG_VERSION:=5.42.0 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/v2fly/v2ray-core/tar.gz/v$(PKG_VERSION)? -PKG_HASH:=c67caa2d73f35a9562ecaeb5184733c943c9dafb47e8f1cfeacb892a9247e9b5 +PKG_HASH:=24e2182bf77342165511150db014668723ac4a0c9e72269b0590b0be72875b49 PKG_LICENSE:=MIT PKG_LICENSE_FILES:=LICENSE diff --git a/small/v2ray-geodata/Makefile b/small/v2ray-geodata/Makefile index bb1dc71ca8..da25bace1b 100644 --- a/small/v2ray-geodata/Makefile +++ b/small/v2ray-geodata/Makefile @@ -21,13 +21,13 @@ define Download/geoip HASH:=2445b44d9ae3ab9a867c9d1e0e244646c4c378622e14b9afaf3658ecf46a40b9 endef -GEOSITE_VER:=20251122135507 +GEOSITE_VER:=20251123125944 GEOSITE_FILE:=dlc.dat.$(GEOSITE_VER) define Download/geosite URL:=https://github.com/v2fly/domain-list-community/releases/download/$(GEOSITE_VER)/ URL_FILE:=dlc.dat FILE:=$(GEOSITE_FILE) - HASH:=dd3e5c4708dc6b1ea6c45c8ed0e429c233f459e3f48153a2507a95103c69d9e8 + HASH:=83b10b5e81f0c3c423d50af4873993041dbb788bc016478acbf1cdd778ace92a endef GEOSITE_IRAN_VER:=202511170041 diff --git a/v2rayn/v2rayN/Directory.Build.props b/v2rayn/v2rayN/Directory.Build.props index ee1b516c22..3bd59e4323 100644 --- a/v2rayn/v2rayN/Directory.Build.props +++ b/v2rayn/v2rayN/Directory.Build.props @@ -1,7 +1,7 @@ - 7.16.3 + 7.16.4 diff --git a/v2rayn/v2rayN/ServiceLib/Models/UpdateResult.cs b/v2rayn/v2rayN/ServiceLib/Models/UpdateResult.cs new file mode 100644 index 0000000000..d8f18dd421 --- /dev/null +++ b/v2rayn/v2rayN/ServiceLib/Models/UpdateResult.cs @@ -0,0 +1,21 @@ +namespace ServiceLib.Models; + +public class UpdateResult +{ + public bool Success { get; set; } + public string? Msg { get; set; } + public SemanticVersion? Version { get; set; } + public string? Url { get; set; } + + public UpdateResult(bool success, string? msg) + { + Success = success; + Msg = msg; + } + + public UpdateResult(bool success, SemanticVersion? version) + { + Success = success; + Version = version; + } +} diff --git a/v2rayn/v2rayN/ServiceLib/Resx/ResUI.Designer.cs b/v2rayn/v2rayN/ServiceLib/Resx/ResUI.Designer.cs index 4ac11d1c41..b64c0bbefb 100644 --- a/v2rayn/v2rayN/ServiceLib/Resx/ResUI.Designer.cs +++ b/v2rayn/v2rayN/ServiceLib/Resx/ResUI.Designer.cs @@ -19,7 +19,7 @@ namespace ServiceLib.Resx { // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen // (以 /str 作为命令选项),或重新生成 VS 项目。 - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class ResUI { @@ -529,7 +529,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Next proxy Configuration remarks 的本地化字符串。 + /// 查找类似 Next proxy remarks 的本地化字符串。 /// public static string LvNextProfile { get { @@ -547,7 +547,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Previous proxy Configuration remarks 的本地化字符串。 + /// 查找类似 Previous proxy remarks 的本地化字符串。 /// public static string LvPrevProfile { get { @@ -736,7 +736,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add [Anytls] Configuration 的本地化字符串。 + /// 查找类似 Add [Anytls] 的本地化字符串。 /// public static string menuAddAnytlsServer { get { @@ -745,7 +745,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add Child Configuration 的本地化字符串。 + /// 查找类似 Add Child 的本地化字符串。 /// public static string menuAddChildServer { get { @@ -754,7 +754,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add a custom configuration Configuration 的本地化字符串。 + /// 查找类似 Add a custom configuration 的本地化字符串。 /// public static string menuAddCustomServer { get { @@ -763,7 +763,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add [HTTP] Configuration 的本地化字符串。 + /// 查找类似 Add [HTTP] 的本地化字符串。 /// public static string menuAddHttpServer { get { @@ -772,7 +772,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add [Hysteria2] Configuration 的本地化字符串。 + /// 查找类似 Add [Hysteria2] 的本地化字符串。 /// public static string menuAddHysteria2Server { get { @@ -781,7 +781,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add Policy Group Configuration 的本地化字符串。 + /// 查找类似 Add Policy Group 的本地化字符串。 /// public static string menuAddPolicyGroupServer { get { @@ -790,7 +790,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add Proxy Chain Configuration 的本地化字符串。 + /// 查找类似 Add Proxy Chain 的本地化字符串。 /// public static string menuAddProxyChainServer { get { @@ -826,7 +826,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add [Shadowsocks] Configuration 的本地化字符串。 + /// 查找类似 Add [Shadowsocks] 的本地化字符串。 /// public static string menuAddShadowsocksServer { get { @@ -835,7 +835,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add [SOCKS] Configuration 的本地化字符串。 + /// 查找类似 Add [SOCKS] 的本地化字符串。 /// public static string menuAddSocksServer { get { @@ -844,7 +844,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add [Trojan] Configuration 的本地化字符串。 + /// 查找类似 Add [Trojan] 的本地化字符串。 /// public static string menuAddTrojanServer { get { @@ -853,7 +853,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add [TUIC] Configuration 的本地化字符串。 + /// 查找类似 Add [TUIC] 的本地化字符串。 /// public static string menuAddTuicServer { get { @@ -862,7 +862,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add [VLESS] Configuration 的本地化字符串。 + /// 查找类似 Add [VLESS] 的本地化字符串。 /// public static string menuAddVlessServer { get { @@ -871,7 +871,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add [VMess] Configuration 的本地化字符串。 + /// 查找类似 Add [VMess] 的本地化字符串。 /// public static string menuAddVmessServer { get { @@ -880,7 +880,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add [WireGuard] Configuration 的本地化字符串。 + /// 查找类似 Add [WireGuard] 的本地化字符串。 /// public static string menuAddWireguardServer { get { @@ -952,7 +952,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Clone selected Configuration 的本地化字符串。 + /// 查找类似 Clone selected 的本地化字符串。 /// public static string menuCopyServer { get { @@ -970,7 +970,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Edit Configuration 的本地化字符串。 + /// 查找类似 Edit 的本地化字符串。 /// public static string menuEditServer { get { @@ -997,7 +997,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Export selected Configuration for complete configuration 的本地化字符串。 + /// 查找类似 Export selected for complete configuration 的本地化字符串。 /// public static string menuExport2ClientConfig { get { @@ -1006,7 +1006,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Export selected Configuration for complete configuration to clipboard 的本地化字符串。 + /// 查找类似 Export selected for complete configuration to clipboard 的本地化字符串。 /// public static string menuExport2ClientConfigClipboard { get { @@ -1033,7 +1033,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Export Configuration 的本地化字符串。 + /// 查找类似 Export 的本地化字符串。 /// public static string menuExportConfig { get { @@ -1069,7 +1069,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Multi-Configuration Fallback by sing-box 的本地化字符串。 + /// 查找类似 Fallback by sing-box 的本地化字符串。 /// public static string menuGenGroupMultipleServerSingBoxFallback { get { @@ -1078,7 +1078,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Multi-Configuration LeastPing by sing-box 的本地化字符串。 + /// 查找类似 LeastPing by sing-box 的本地化字符串。 /// public static string menuGenGroupMultipleServerSingBoxLeastPing { get { @@ -1087,7 +1087,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Multi-Configuration Fallback by Xray 的本地化字符串。 + /// 查找类似 Fallback by Xray 的本地化字符串。 /// public static string menuGenGroupMultipleServerXrayFallback { get { @@ -1096,7 +1096,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Multi-Configuration LeastLoad by Xray 的本地化字符串。 + /// 查找类似 LeastLoad by Xray 的本地化字符串。 /// public static string menuGenGroupMultipleServerXrayLeastLoad { get { @@ -1105,7 +1105,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Multi-Configuration LeastPing by Xray 的本地化字符串。 + /// 查找类似 LeastPing by Xray 的本地化字符串。 /// public static string menuGenGroupMultipleServerXrayLeastPing { get { @@ -1114,7 +1114,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Multi-Configuration Random by Xray 的本地化字符串。 + /// 查找类似 Random by Xray 的本地化字符串。 /// public static string menuGenGroupMultipleServerXrayRandom { get { @@ -1123,7 +1123,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Multi-Configuration RoundRobin by Xray 的本地化字符串。 + /// 查找类似 RoundRobin by Xray 的本地化字符串。 /// public static string menuGenGroupMultipleServerXrayRoundRobin { get { @@ -1411,7 +1411,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Test Configurations real delay 的本地化字符串。 + /// 查找类似 Test real delay 的本地化字符串。 /// public static string menuRealPingServer { get { @@ -1501,7 +1501,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Remove Child Configuration 的本地化字符串。 + /// 查找类似 Remove Child 的本地化字符串。 /// public static string menuRemoveChildServer { get { @@ -1510,7 +1510,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Remove duplicate Configurations 的本地化字符串。 + /// 查找类似 Remove duplicate 的本地化字符串。 /// public static string menuRemoveDuplicateServer { get { @@ -1528,7 +1528,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Remove selected Configurations 的本地化字符串。 + /// 查找类似 Remove selected 的本地化字符串。 /// public static string menuRemoveServer { get { @@ -1672,7 +1672,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Configurations 的本地化字符串。 + /// 查找类似 Configuration 的本地化字符串。 /// public static string menuServers { get { @@ -1681,7 +1681,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Set as active Configuration 的本地化字符串。 + /// 查找类似 Set as active 的本地化字符串。 /// public static string menuSetDefaultServer { get { @@ -1699,7 +1699,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Share Configuration 的本地化字符串。 + /// 查找类似 Share 的本地化字符串。 /// public static string menuShareServer { get { @@ -1726,7 +1726,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Test Configurations download speed 的本地化字符串。 + /// 查找类似 Test download speed 的本地化字符串。 /// public static string menuSpeedServer { get { @@ -1870,7 +1870,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Test Configurations with tcping 的本地化字符串。 + /// 查找类似 Test tcping 的本地化字符串。 /// public static string menuTcpingServer { get { @@ -1978,7 +1978,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Configuration filter, press Enter to execute 的本地化字符串。 + /// 查找类似 Filter, press Enter to execute 的本地化字符串。 /// public static string MsgServerTitle { get { @@ -2275,7 +2275,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Are you sure you want to remove the Configuration? 的本地化字符串。 + /// 查找类似 Are you sure you want to remove? 的本地化字符串。 /// public static string RemoveServer { get { @@ -4105,7 +4105,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Tray right-click menu Configurations display limit 的本地化字符串。 + /// 查找类似 Tray right-click menu display limit 的本地化字符串。 /// public static string TbSettingsTrayMenuServersLimit { get { diff --git a/v2rayn/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayn/v2rayN/ServiceLib/Resx/ResUI.resx index 9b1a0eb883..1f38c38556 100644 --- a/v2rayn/v2rayN/ServiceLib/Resx/ResUI.resx +++ b/v2rayn/v2rayN/ServiceLib/Resx/ResUI.resx @@ -271,7 +271,7 @@ Configurations deduplication completed. Old: {0}, New: {1}. - Are you sure you want to remove the Configuration? + Are you sure you want to remove? The client configuration file is saved at: {0} @@ -397,7 +397,7 @@ Local - Configuration filter, press Enter to execute + Filter, press Enter to execute Check Update @@ -427,7 +427,7 @@ Routing Setting - Configurations + Configuration Settings @@ -478,55 +478,55 @@ Scan QR code on the screen - Clone selected Configuration + Clone selected - Remove duplicate Configurations + Remove duplicate - Remove selected Configurations + Remove selected - Set as active Configuration + Set as active Clear all service statistics - Test Configurations real delay + Test real delay Sort by test result - Test Configurations download speed + Test download speed - Test Configurations with tcping + Test tcping - Export selected Configuration for complete configuration + Export selected for complete configuration Export Share Link to Clipboard - Add a custom configuration Configuration + Add a custom configuration - Add [Shadowsocks] Configuration + Add [Shadowsocks] - Add [SOCKS] Configuration + Add [SOCKS] - Add [Trojan] Configuration + Add [Trojan] - Add [VLESS] Configuration + Add [VLESS] - Add [VMess] Configuration + Add [VMess] Select all @@ -748,7 +748,7 @@ System proxy settings - Tray right-click menu Configurations display limit + Tray right-click menu display limit Enable UDP @@ -781,7 +781,7 @@ PAC mode - Share Configuration + Share Routing @@ -922,7 +922,7 @@ Skip test - Edit Configuration + Edit Double-clicking Configuration makes it active @@ -1036,7 +1036,7 @@ Domain - Add [Hysteria2] Configuration + Add [Hysteria2] Hysteria Max bandwidth (Up/Down) @@ -1045,16 +1045,16 @@ Use System Hosts - Add [TUIC] Configuration + Add [TUIC] Congestion control - Previous proxy Configuration remarks + Previous proxy remarks - Next proxy Configuration remarks + Next proxy remarks Please make sure the Configuration remarks exist and are unique @@ -1078,7 +1078,7 @@ Enable IPv6 Address - Add [WireGuard] Configuration + Add [WireGuard] Private Key @@ -1111,7 +1111,7 @@ *grpc Authority - Add [HTTP] Configuration + Add [HTTP] which conflicts with the group previous proxy @@ -1225,7 +1225,7 @@ Export Base64-encoded Share Links to Clipboard - Export selected Configuration for complete configuration to clipboard + Export selected for complete configuration to clipboard Show or hide the main window @@ -1381,22 +1381,22 @@ Generate Policy Group from Multiple Profiles - Multi-Configuration Random by Xray + Random by Xray - Multi-Configuration RoundRobin by Xray + RoundRobin by Xray - Multi-Configuration LeastPing by Xray + LeastPing by Xray - Multi-Configuration LeastLoad by Xray + LeastLoad by Xray - Multi-Configuration LeastPing by sing-box + LeastPing by sing-box - Export Configuration + Export Current connection info test URL @@ -1411,7 +1411,7 @@ Mldsa65Verify - Add [Anytls] Configuration + Add [Anytls] Remote DNS @@ -1528,16 +1528,16 @@ Policy Group Type - Add Policy Group Configuration + Add Policy Group - Add Proxy Chain Configuration + Add Proxy Chain - Add Child Configuration + Add Child - Remove Child Configuration + Remove Child Configuration List @@ -1546,10 +1546,10 @@ Fallback - Multi-Configuration Fallback by sing-box + Fallback by sing-box - Multi-Configuration Fallback by Xray + Fallback by Xray Core '{0}' does not support network type '{1}'. diff --git a/v2rayn/v2rayN/ServiceLib/Services/DownloadService.cs b/v2rayn/v2rayN/ServiceLib/Services/DownloadService.cs index fe0da3d6e6..77d3a7c162 100644 --- a/v2rayn/v2rayN/ServiceLib/Services/DownloadService.cs +++ b/v2rayn/v2rayN/ServiceLib/Services/DownloadService.cs @@ -7,7 +7,7 @@ namespace ServiceLib.Services; /// public class DownloadService { - public event EventHandler? UpdateCompleted; + public event EventHandler? UpdateCompleted; public event ErrorEventHandler? Error; @@ -40,10 +40,10 @@ public class DownloadService { try { - UpdateCompleted?.Invoke(this, new RetResult(false, $"{ResUI.Downloading} {url}")); + UpdateCompleted?.Invoke(this, new UpdateResult(false, $"{ResUI.Downloading} {url}")); var progress = new Progress(); - progress.ProgressChanged += (sender, value) => UpdateCompleted?.Invoke(this, new RetResult(value > 100, $"...{value}%")); + progress.ProgressChanged += (sender, value) => UpdateCompleted?.Invoke(this, new UpdateResult(value > 100, $"...{value}%")); var webProxy = await GetWebProxy(blProxy); await DownloaderHelper.Instance.DownloadFileAsync(webProxy, diff --git a/v2rayn/v2rayN/ServiceLib/Services/UpdateService.cs b/v2rayn/v2rayN/ServiceLib/Services/UpdateService.cs index a1d72655ca..88272bf12b 100644 --- a/v2rayn/v2rayN/ServiceLib/Services/UpdateService.cs +++ b/v2rayn/v2rayN/ServiceLib/Services/UpdateService.cs @@ -37,7 +37,7 @@ public class UpdateService(Config config, Func updateFunc) await UpdateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, ECoreType.v2rayN)); await UpdateFunc(false, result.Msg); - url = result.Data?.ToString(); + url = result.Url.ToString(); fileName = Utils.GetTempPath(Utils.GetGuid()); await downloadHandle.DownloadFileAsync(url, fileName, true, _timeout); } @@ -86,7 +86,7 @@ public class UpdateService(Config config, Func updateFunc) await UpdateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, type)); await UpdateFunc(false, result.Msg); - url = result.Data?.ToString(); + url = result.Url.ToString(); var ext = url.Contains(".tar.gz") ? ".tar.gz" : Path.GetExtension(url); fileName = Utils.GetTempPath(Utils.GetGuid() + ext); await downloadHandle.DownloadFileAsync(url, fileName, true, _timeout); @@ -110,26 +110,26 @@ public class UpdateService(Config config, Func updateFunc) #region CheckUpdate private - private async Task CheckUpdateAsync(DownloadService downloadHandle, ECoreType type, bool preRelease) + private async Task CheckUpdateAsync(DownloadService downloadHandle, ECoreType type, bool preRelease) { try { var result = await GetRemoteVersion(downloadHandle, type, preRelease); - if (!result.Success || result.Data is null) + if (!result.Success || result.Version is null) { return result; } - return await ParseDownloadUrl(type, (SemanticVersion)result.Data); + return await ParseDownloadUrl(type, result); } catch (Exception ex) { Logging.SaveLog(_tag, ex); await UpdateFunc(false, ex.Message); - return new RetResult(false, ex.Message); + return new UpdateResult(false, ex.Message); } } - private async Task GetRemoteVersion(DownloadService downloadHandle, ECoreType type, bool preRelease) + private async Task GetRemoteVersion(DownloadService downloadHandle, ECoreType type, bool preRelease) { var coreInfo = CoreInfoManager.Instance.GetCoreInfo(type); var tagName = string.Empty; @@ -139,7 +139,7 @@ public class UpdateService(Config config, Func updateFunc) var result = await downloadHandle.TryDownloadString(url, true, Global.AppName); if (result.IsNullOrEmpty()) { - return new RetResult(false, ""); + return new UpdateResult(false, ""); } var gitHubReleases = JsonUtils.Deserialize>(result); @@ -153,12 +153,12 @@ public class UpdateService(Config config, Func updateFunc) var lastUrl = await downloadHandle.UrlRedirectAsync(url, true); if (lastUrl == null) { - return new RetResult(false, ""); + return new UpdateResult(false, ""); } tagName = lastUrl?.Split("/tag/").LastOrDefault(); } - return new RetResult(true, "", new SemanticVersion(tagName)); + return new UpdateResult(true, new SemanticVersion(tagName)); } private async Task GetCoreVersion(ECoreType type) @@ -213,10 +213,11 @@ public class UpdateService(Config config, Func updateFunc) } } - private async Task ParseDownloadUrl(ECoreType type, SemanticVersion version) + private async Task ParseDownloadUrl(ECoreType type, UpdateResult result) { try { + var version = result.Version ?? new SemanticVersion(0, 0, 0); var coreInfo = CoreInfoManager.Instance.GetCoreInfo(type); var coreUrl = await GetUrlFromCore(coreInfo) ?? string.Empty; SemanticVersion curVersion; @@ -260,16 +261,17 @@ public class UpdateService(Config config, Func updateFunc) if (curVersion >= version && version != new SemanticVersion(0, 0, 0)) { - return new RetResult(false, message); + return new UpdateResult(false, message); } - return new RetResult(true, "", url); + result.Url = url; + return result; } catch (Exception ex) { Logging.SaveLog(_tag, ex); await UpdateFunc(false, ex.Message); - return new RetResult(false, ex.Message); + return new UpdateResult(false, ex.Message); } } diff --git a/xray-core/infra/conf/transport_internet.go b/xray-core/infra/conf/transport_internet.go index 51f974b96c..5a860b1c70 100644 --- a/xray-core/infra/conf/transport_internet.go +++ b/xray-core/infra/conf/transport_internet.go @@ -810,7 +810,7 @@ type SocketConfig struct { CustomSockopt []*CustomSockoptConfig `json:"customSockopt"` AddressPortStrategy string `json:"addressPortStrategy"` HappyEyeballsSettings *HappyEyeballsConfig `json:"happyEyeballs"` - DiscardXForwardedFor bool `json:"discardXForwardedFor"` + TrustedXForwardedFor []string `json:"trustedXForwardedFor"` } // Build implements Buildable. @@ -930,7 +930,7 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) { CustomSockopt: customSockopts, AddressPortStrategy: addressPortStrategy, HappyEyeballs: happyEyeballs, - DiscardXForwardedFor: c.DiscardXForwardedFor, + TrustedXForwardedFor: c.TrustedXForwardedFor, }, nil } diff --git a/xray-core/proxy/vless/inbound/inbound.go b/xray-core/proxy/vless/inbound/inbound.go index 277ab06819..89ed0e724f 100644 --- a/xray-core/proxy/vless/inbound/inbound.go +++ b/xray-core/proxy/vless/inbound/inbound.go @@ -538,6 +538,10 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s account := request.User.Account.(*vless.MemoryAccount) + if account.Reverse != nil && request.Command != protocol.RequestCommandRvs { + return errors.New("for safety reasons, user " + account.ID.String() + " is not allowed to use forward proxy") + } + responseAddons := &encoding.Addons{ // Flow: requestAddons.Flow, } diff --git a/xray-core/transport/internet/config.pb.go b/xray-core/transport/internet/config.pb.go index 1919383606..41ce3294c2 100644 --- a/xray-core/transport/internet/config.pb.go +++ b/xray-core/transport/internet/config.pb.go @@ -530,7 +530,7 @@ type SocketConfig struct { CustomSockopt []*CustomSockopt `protobuf:"bytes,20,rep,name=customSockopt,proto3" json:"customSockopt,omitempty"` AddressPortStrategy AddressPortStrategy `protobuf:"varint,21,opt,name=address_port_strategy,json=addressPortStrategy,proto3,enum=xray.transport.internet.AddressPortStrategy" json:"address_port_strategy,omitempty"` HappyEyeballs *HappyEyeballsConfig `protobuf:"bytes,22,opt,name=happy_eyeballs,json=happyEyeballs,proto3" json:"happy_eyeballs,omitempty"` - DiscardXForwardedFor bool `protobuf:"varint,23,opt,name=discard_x_forwarded_for,json=discardXForwardedFor,proto3" json:"discard_x_forwarded_for,omitempty"` + TrustedXForwardedFor []string `protobuf:"bytes,23,rep,name=trusted_x_forwarded_for,json=trustedXForwardedFor,proto3" json:"trusted_x_forwarded_for,omitempty"` } func (x *SocketConfig) Reset() { @@ -717,11 +717,11 @@ func (x *SocketConfig) GetHappyEyeballs() *HappyEyeballsConfig { return nil } -func (x *SocketConfig) GetDiscardXForwardedFor() bool { +func (x *SocketConfig) GetTrustedXForwardedFor() []string { if x != nil { - return x.DiscardXForwardedFor + return x.TrustedXForwardedFor } - return false + return nil } type HappyEyeballsConfig struct { @@ -917,10 +917,10 @@ var file_transport_internet_config_proto_rawDesc = []byte{ 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x48, 0x61, 0x70, 0x70, 0x79, 0x45, 0x79, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x68, 0x61, 0x70, 0x70, 0x79, - 0x45, 0x79, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x73, 0x12, 0x35, 0x0a, 0x17, 0x64, 0x69, 0x73, 0x63, - 0x61, 0x72, 0x64, 0x5f, 0x78, 0x5f, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x64, 0x5f, - 0x66, 0x6f, 0x72, 0x18, 0x17, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x64, 0x69, 0x73, 0x63, 0x61, - 0x72, 0x64, 0x58, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x22, + 0x45, 0x79, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x73, 0x12, 0x35, 0x0a, 0x17, 0x74, 0x72, 0x75, 0x73, + 0x74, 0x65, 0x64, 0x5f, 0x78, 0x5f, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x64, 0x5f, + 0x66, 0x6f, 0x72, 0x18, 0x17, 0x20, 0x03, 0x28, 0x09, 0x52, 0x14, 0x74, 0x72, 0x75, 0x73, 0x74, + 0x65, 0x64, 0x58, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x22, 0x2f, 0x0a, 0x0a, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x66, 0x66, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x10, 0x02, diff --git a/xray-core/transport/internet/config.proto b/xray-core/transport/internet/config.proto index ed355eabca..e1655fdd6f 100644 --- a/xray-core/transport/internet/config.proto +++ b/xray-core/transport/internet/config.proto @@ -133,7 +133,7 @@ message SocketConfig { HappyEyeballsConfig happy_eyeballs = 22; - bool discard_x_forwarded_for = 23; + repeated string trusted_x_forwarded_for = 23; } message HappyEyeballsConfig { diff --git a/xray-core/transport/internet/httpupgrade/hub.go b/xray-core/transport/internet/httpupgrade/hub.go index 6b8f0343f8..c3a51607ae 100644 --- a/xray-core/transport/internet/httpupgrade/hub.go +++ b/xray-core/transport/internet/httpupgrade/hub.go @@ -71,11 +71,18 @@ func (s *server) Handle(conn net.Conn) (stat.Connection, error) { return nil, err } - forwardedAddrs := http_proto.ParseXForwardedFor(req.Header) - remoteAddr := conn.RemoteAddr() - if s.socketSettings != nil && s.socketSettings.DiscardXForwardedFor { - forwardedAddrs = nil + var forwardedAddrs []net.Address + if s.socketSettings != nil && len(s.socketSettings.TrustedXForwardedFor) > 0 { + for _, key := range s.socketSettings.TrustedXForwardedFor { + if len(req.Header.Values(key)) > 0 { + forwardedAddrs = http_proto.ParseXForwardedFor(req.Header) + break + } + } + } else { + forwardedAddrs = http_proto.ParseXForwardedFor(req.Header) } + remoteAddr := conn.RemoteAddr() if len(forwardedAddrs) > 0 && forwardedAddrs[0].Family().IsIP() { remoteAddr = &net.TCPAddr{ IP: forwardedAddrs[0].IP(), diff --git a/xray-core/transport/internet/splithttp/hub.go b/xray-core/transport/internet/splithttp/hub.go index 41098e8dac..5e9b9408f2 100644 --- a/xray-core/transport/internet/splithttp/hub.go +++ b/xray-core/transport/internet/splithttp/hub.go @@ -140,7 +140,17 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req return } - forwardedAddrs := http_proto.ParseXForwardedFor(request.Header) + var forwardedAddrs []net.Address + if h.socketSettings != nil && len(h.socketSettings.TrustedXForwardedFor) > 0 { + for _, key := range h.socketSettings.TrustedXForwardedFor { + if len(request.Header.Values(key)) > 0 { + forwardedAddrs = http_proto.ParseXForwardedFor(request.Header) + break + } + } + } else { + forwardedAddrs = http_proto.ParseXForwardedFor(request.Header) + } var remoteAddr net.Addr var err error remoteAddr, err = net.ResolveTCPAddr("tcp", request.RemoteAddr) @@ -156,9 +166,6 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req Port: remoteAddr.(*net.TCPAddr).Port, } } - if h.socketSettings != nil && h.socketSettings.DiscardXForwardedFor { - forwardedAddrs = nil - } if len(forwardedAddrs) > 0 && forwardedAddrs[0].Family().IsIP() { remoteAddr = &net.TCPAddr{ IP: forwardedAddrs[0].IP(), diff --git a/xray-core/transport/internet/websocket/hub.go b/xray-core/transport/internet/websocket/hub.go index a119e2df36..b47e7d5817 100644 --- a/xray-core/transport/internet/websocket/hub.go +++ b/xray-core/transport/internet/websocket/hub.go @@ -65,11 +65,18 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req return } - forwardedAddrs := http_proto.ParseXForwardedFor(request.Header) - remoteAddr := conn.RemoteAddr() - if h.socketSettings != nil && h.socketSettings.DiscardXForwardedFor { - forwardedAddrs = nil + var forwardedAddrs []net.Address + if h.socketSettings != nil && len(h.socketSettings.TrustedXForwardedFor) > 0 { + for _, key := range h.socketSettings.TrustedXForwardedFor { + if len(request.Header.Values(key)) > 0 { + forwardedAddrs = http_proto.ParseXForwardedFor(request.Header) + break + } + } + } else { + forwardedAddrs = http_proto.ParseXForwardedFor(request.Header) } + remoteAddr := conn.RemoteAddr() if len(forwardedAddrs) > 0 && forwardedAddrs[0].Family().IsIP() { remoteAddr = &net.TCPAddr{ IP: forwardedAddrs[0].IP(), diff --git a/yt-dlp/README.md b/yt-dlp/README.md index 8189015c72..c98c69f418 100644 --- a/yt-dlp/README.md +++ b/yt-dlp/README.md @@ -1870,7 +1870,6 @@ The following extractors use this feature: * `po_token`: Proof of Origin (PO) Token(s) to use. Comma seperated list of PO Tokens in the format `CLIENT.CONTEXT+PO_TOKEN`, e.g. `youtube:po_token=web.gvs+XXX,web.player=XXX,web_safari.gvs+YYY`. Context can be any of `gvs` (Google Video Server URLs), `player` (Innertube player request) or `subs` (Subtitles) * `pot_trace`: Enable debug logging for PO Token fetching. Either `true` or `false` (default) * `fetch_pot`: Policy to use for fetching a PO Token from providers. One of `always` (always try fetch a PO Token regardless if the client requires one for the given context), `never` (never fetch a PO Token), or `auto` (default; only fetch a PO Token if the client requires one for the given context) -* `playback_wait`: Duration (in seconds) to wait inbetween the extraction and download stages in order to ensure the formats are available. The default is `6` seconds * `jsc_trace`: Enable debug logging for JS Challenge fetching. Either `true` or `false` (default) #### youtube-ejs diff --git a/yt-dlp/yt_dlp/extractor/youtube/_video.py b/yt-dlp/yt_dlp/extractor/youtube/_video.py index 57edad3c0f..600e0ccda6 100644 --- a/yt-dlp/yt_dlp/extractor/youtube/_video.py +++ b/yt-dlp/yt_dlp/extractor/youtube/_video.py @@ -76,7 +76,7 @@ STREAMING_DATA_FETCH_GVS_PO_TOKEN = '__yt_dlp_fetch_gvs_po_token' STREAMING_DATA_PLAYER_TOKEN_PROVIDED = '__yt_dlp_player_token_provided' STREAMING_DATA_INNERTUBE_CONTEXT = '__yt_dlp_innertube_context' STREAMING_DATA_IS_PREMIUM_SUBSCRIBER = '__yt_dlp_is_premium_subscriber' -STREAMING_DATA_FETCHED_TIMESTAMP = '__yt_dlp_fetched_timestamp' +STREAMING_DATA_AVAILABLE_AT_TIMESTAMP = '__yt_dlp_available_at_timestamp' PO_TOKEN_GUIDE_URL = 'https://github.com/yt-dlp/yt-dlp/wiki/PO-Token-Guide' @@ -3032,7 +3032,6 @@ class YoutubeIE(YoutubeBaseInfoExtractor): elif pr: # Save client details for introspection later innertube_context = traverse_obj(player_ytcfg or self._get_default_ytcfg(client), 'INNERTUBE_CONTEXT') - fetched_timestamp = int(time.time()) sd = pr.setdefault('streamingData', {}) sd[STREAMING_DATA_CLIENT_NAME] = client sd[STREAMING_DATA_FETCH_GVS_PO_TOKEN] = fetch_gvs_po_token_func @@ -3040,7 +3039,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor): sd[STREAMING_DATA_INNERTUBE_CONTEXT] = innertube_context sd[STREAMING_DATA_FETCH_SUBS_PO_TOKEN] = fetch_subs_po_token_func sd[STREAMING_DATA_IS_PREMIUM_SUBSCRIBER] = is_premium_subscriber - sd[STREAMING_DATA_FETCHED_TIMESTAMP] = fetched_timestamp + sd[STREAMING_DATA_AVAILABLE_AT_TIMESTAMP] = self._get_available_at_timestamp(pr, video_id, client) for f in traverse_obj(sd, (('formats', 'adaptiveFormats'), ..., {dict})): f[STREAMING_DATA_CLIENT_NAME] = client f[STREAMING_DATA_FETCH_GVS_PO_TOKEN] = fetch_gvs_po_token_func @@ -3172,9 +3171,6 @@ class YoutubeIE(YoutubeBaseInfoExtractor): # save pots per client to avoid fetching again gvs_pots = {} - # For handling potential pre-playback required waiting period - playback_wait = int_or_none(self._configuration_arg('playback_wait', [None])[0], default=6) - def get_language_code_and_preference(fmt_stream): audio_track = fmt_stream.get('audioTrack') or {} display_name = audio_track.get('displayName') or '' @@ -3199,7 +3195,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor): is_premium_subscriber = streaming_data[STREAMING_DATA_IS_PREMIUM_SUBSCRIBER] player_token_provided = streaming_data[STREAMING_DATA_PLAYER_TOKEN_PROVIDED] client_name = streaming_data.get(STREAMING_DATA_CLIENT_NAME) - available_at = streaming_data[STREAMING_DATA_FETCHED_TIMESTAMP] + playback_wait + available_at = streaming_data[STREAMING_DATA_AVAILABLE_AT_TIMESTAMP] streaming_formats = traverse_obj(streaming_data, (('formats', 'adaptiveFormats'), ...)) def get_stream_id(fmt_stream): @@ -3653,6 +3649,36 @@ class YoutubeIE(YoutubeBaseInfoExtractor): })) return webpage + def _get_available_at_timestamp(self, player_response, video_id, client): + now = time.time() + wait_seconds = 0 + + for renderer in traverse_obj(player_response, ( + 'adSlots', lambda _, v: v['adSlotRenderer']['adSlotMetadata']['triggerEvent'] == 'SLOT_TRIGGER_EVENT_BEFORE_CONTENT', + 'adSlotRenderer', 'fulfillmentContent', 'fulfilledLayout', 'playerBytesAdLayoutRenderer', 'renderingContent', ( + None, + ('playerBytesSequentialLayoutRenderer', 'sequentialLayouts', ..., 'playerBytesAdLayoutRenderer', 'renderingContent'), + ), 'instreamVideoAdRenderer', {dict}, + )): + duration = traverse_obj(renderer, ('playerVars', {urllib.parse.parse_qs}, 'length_seconds', -1, {int_or_none})) + ad = 'an ad' if duration is None else f'a {duration}s ad' + + skip_time = traverse_obj(renderer, ('skipOffsetMilliseconds', {float_or_none(scale=1000)})) + if skip_time is not None: + # YT allows skipping this ad; use the wait-until-skip time instead of full ad duration + skip_time = skip_time if skip_time % 1 else int(skip_time) + ad += f' skippable after {skip_time}s' + duration = skip_time + + if duration is not None: + self.write_debug(f'{video_id}: Detected {ad} for {client}') + wait_seconds += duration + + if wait_seconds: + return math.ceil(now) + wait_seconds + + return int(now) + def _list_formats(self, video_id, microformats, video_details, player_responses, player_url, duration=None): live_broadcast_details = traverse_obj(microformats, (..., 'liveBroadcastDetails')) is_live = get_first(video_details, 'isLive')