mirror of
https://github.com/snltty/linker.git
synced 2025-09-26 21:15:57 +08:00
180
This commit is contained in:
8
.github/workflows/docker.yml
vendored
8
.github/workflows/docker.yml
vendored
@@ -57,9 +57,9 @@ jobs:
|
||||
docker tag snltty/linker-musl-x64:latest snltty/linker-musl:amd64 && \
|
||||
docker push snltty/linker-musl:amd64 && \
|
||||
docker manifest create snltty/linker-musl:latest snltty/linker-musl:amd64 snltty/linker-musl:arm64 snltty/linker-musl:arm && \
|
||||
docker manifest create snltty/linker-musl:v1.7.9 snltty/linker-musl:amd64 snltty/linker-musl:arm64 snltty/linker-musl:arm && \
|
||||
docker manifest create snltty/linker-musl:v1.8.0 snltty/linker-musl:amd64 snltty/linker-musl:arm64 snltty/linker-musl:arm && \
|
||||
docker manifest push snltty/linker-musl:latest && \
|
||||
docker manifest push snltty/linker-musl:v1.7.9 && \
|
||||
docker manifest push snltty/linker-musl:v1.8.0 && \
|
||||
docker pull --platform linux/arm/v7 snltty/linker-debian-arm:latest && \
|
||||
docker tag snltty/linker-debian-arm:latest snltty/linker-debian:arm && \
|
||||
docker push snltty/linker-debian:arm && \
|
||||
@@ -70,6 +70,6 @@ jobs:
|
||||
docker tag snltty/linker-debian-x64:latest snltty/linker-debian:amd64 && \
|
||||
docker push snltty/linker-debian:amd64 && \
|
||||
docker manifest create snltty/linker-debian:latest snltty/linker-debian:amd64 snltty/linker-debian:arm64 snltty/linker-debian:arm && \
|
||||
docker manifest create snltty/linker-debian:v1.7.9 snltty/linker-debian:amd64 snltty/linker-debian:arm64 snltty/linker-debian:arm && \
|
||||
docker manifest create snltty/linker-debian:v1.8.0 snltty/linker-debian:amd64 snltty/linker-debian:arm64 snltty/linker-debian:arm && \
|
||||
docker manifest push snltty/linker-debian:latest && \
|
||||
docker manifest push snltty/linker-debian:v1.7.9
|
||||
docker manifest push snltty/linker-debian:v1.8.0
|
26
.github/workflows/dotnet.yml
vendored
26
.github/workflows/dotnet.yml
vendored
@@ -33,11 +33,11 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.ACTIONS_TOKEN }}
|
||||
with:
|
||||
tag_name: v1.7.9
|
||||
release_name: v1.7.9.${{ steps.date.outputs.today }}
|
||||
tag_name: v1.8.0
|
||||
release_name: v1.8.0.${{ steps.date.outputs.today }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
body: "1. 一些累计更新\r\n2. 优化安卓APP,启动网卡时申请VPN权限,有新路由时重建VPN\r\n3. 新增防火墙,用于网卡、端口转发、和socks5\r\n4. 优化重启清理数据,优化了网卡自启动问题\r\n5. 检测密钥是否正确\r\n6. 如果你设备很多,请尝试升级其中一个成功重启后再升级其它"
|
||||
body: "1. 一些累计更新\r\n2. 增加NAT类型检测\r\n3. 优化内网穿透,SNAT转换,防火墙"
|
||||
- name: publish projects
|
||||
run: ./publish.bat "C:\\Android\\android-sdk"
|
||||
- name: upload-win-x86-oss
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
key-secret: ${{ secrets.ALIYUN_OSS_SECRET }}
|
||||
bucket: ide-qbcode
|
||||
asset-path: ./public/publish-zip/linker-win-x86.zip
|
||||
target-path: /downloads/linker/v1.7.9/linker-win-x86.zip
|
||||
target-path: /downloads/linker/v1.8.0/linker-win-x86.zip
|
||||
- name: upload-win-x86
|
||||
id: upload-win-x86
|
||||
uses: actions/upload-release-asset@master
|
||||
@@ -69,7 +69,7 @@ jobs:
|
||||
key-secret: ${{ secrets.ALIYUN_OSS_SECRET }}
|
||||
bucket: ide-qbcode
|
||||
asset-path: ./public/publish-zip/linker-win-x64.zip
|
||||
target-path: /downloads/linker/v1.7.9/linker-win-x64.zip
|
||||
target-path: /downloads/linker/v1.8.0/linker-win-x64.zip
|
||||
- name: upload-win-x64
|
||||
id: upload-win-x64
|
||||
uses: actions/upload-release-asset@master
|
||||
@@ -89,7 +89,7 @@ jobs:
|
||||
key-secret: ${{ secrets.ALIYUN_OSS_SECRET }}
|
||||
bucket: ide-qbcode
|
||||
asset-path: ./public/publish-zip/linker-win-arm64.zip
|
||||
target-path: /downloads/linker/v1.7.9/linker-win-arm64.zip
|
||||
target-path: /downloads/linker/v1.8.0/linker-win-arm64.zip
|
||||
- name: upload-win-arm64
|
||||
id: upload-win-arm64
|
||||
uses: actions/upload-release-asset@master
|
||||
@@ -109,7 +109,7 @@ jobs:
|
||||
key-secret: ${{ secrets.ALIYUN_OSS_SECRET }}
|
||||
bucket: ide-qbcode
|
||||
asset-path: ./public/publish-zip/linker-linux-x64.zip
|
||||
target-path: /downloads/linker/v1.7.9/linker-linux-x64.zip
|
||||
target-path: /downloads/linker/v1.8.0/linker-linux-x64.zip
|
||||
- name: upload-linux-x64
|
||||
id: upload-linux-x64
|
||||
uses: actions/upload-release-asset@master
|
||||
@@ -129,7 +129,7 @@ jobs:
|
||||
key-secret: ${{ secrets.ALIYUN_OSS_SECRET }}
|
||||
bucket: ide-qbcode
|
||||
asset-path: ./public/publish-zip/linker-linux-arm.zip
|
||||
target-path: /downloads/linker/v1.7.9/linker-linux-arm.zip
|
||||
target-path: /downloads/linker/v1.8.0/linker-linux-arm.zip
|
||||
- name: upload-linux-arm
|
||||
id: upload-linux-arm
|
||||
uses: actions/upload-release-asset@master
|
||||
@@ -149,7 +149,7 @@ jobs:
|
||||
key-secret: ${{ secrets.ALIYUN_OSS_SECRET }}
|
||||
bucket: ide-qbcode
|
||||
asset-path: ./public/publish-zip/linker-linux-arm64.zip
|
||||
target-path: /downloads/linker/v1.7.9/linker-linux-arm64.zip
|
||||
target-path: /downloads/linker/v1.8.0/linker-linux-arm64.zip
|
||||
- name: upload-linux-arm64
|
||||
id: upload-linux-arm64
|
||||
uses: actions/upload-release-asset@master
|
||||
@@ -169,7 +169,7 @@ jobs:
|
||||
key-secret: ${{ secrets.ALIYUN_OSS_SECRET }}
|
||||
bucket: ide-qbcode
|
||||
asset-path: ./public/publish-zip/linker-linux-musl-x64.zip
|
||||
target-path: /downloads/linker/v1.7.9/linker-linux-musl-x64.zip
|
||||
target-path: /downloads/linker/v1.8.0/linker-linux-musl-x64.zip
|
||||
- name: upload-linux-musl-x64
|
||||
id: upload-linux-musl-x64
|
||||
uses: actions/upload-release-asset@master
|
||||
@@ -189,7 +189,7 @@ jobs:
|
||||
key-secret: ${{ secrets.ALIYUN_OSS_SECRET }}
|
||||
bucket: ide-qbcode
|
||||
asset-path: ./public/publish-zip/linker-linux-musl-arm.zip
|
||||
target-path: /downloads/linker/v1.7.9/linker-linux-musl-arm.zip
|
||||
target-path: /downloads/linker/v1.8.0/linker-linux-musl-arm.zip
|
||||
- name: upload-linux-musl-arm
|
||||
id: upload-linux-musl-arm
|
||||
uses: actions/upload-release-asset@master
|
||||
@@ -209,7 +209,7 @@ jobs:
|
||||
key-secret: ${{ secrets.ALIYUN_OSS_SECRET }}
|
||||
bucket: ide-qbcode
|
||||
asset-path: ./public/publish-zip/linker-linux-musl-arm64.zip
|
||||
target-path: /downloads/linker/v1.7.9/linker-linux-musl-arm64.zip
|
||||
target-path: /downloads/linker/v1.8.0/linker-linux-musl-arm64.zip
|
||||
- name: upload-linux-musl-arm64
|
||||
id: upload-linux-musl-arm64
|
||||
uses: actions/upload-release-asset@master
|
||||
@@ -259,7 +259,7 @@ jobs:
|
||||
key-secret: ${{ secrets.ALIYUN_OSS_SECRET }}
|
||||
bucket: ide-qbcode
|
||||
asset-path: ./public/publish-zip/linker.apk
|
||||
target-path: /downloads/linker/v1.7.9/linker.apk
|
||||
target-path: /downloads/linker/v1.8.0/linker.apk
|
||||
- name: upload-apk
|
||||
id: upload-apk
|
||||
uses: actions/upload-release-asset@master
|
||||
|
6
.github/workflows/ipk.yml
vendored
6
.github/workflows/ipk.yml
vendored
@@ -44,7 +44,7 @@ jobs:
|
||||
key-secret: ${{ secrets.ALIYUN_OSS_SECRET }}
|
||||
bucket: ide-qbcode
|
||||
asset-path: ./public/publish-ipk/x64/linker-x64.ipk
|
||||
target-path: /downloads/linker/v1.7.9/linker-x64.ipk
|
||||
target-path: /downloads/linker/v1.8.0/linker-x64.ipk
|
||||
- name: upload-x64
|
||||
id: upload-x64
|
||||
uses: actions/upload-release-asset@master
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
key-secret: ${{ secrets.ALIYUN_OSS_SECRET }}
|
||||
bucket: ide-qbcode
|
||||
asset-path: ./public/publish-ipk/arm/linker-arm.ipk
|
||||
target-path: /downloads/linker/v1.7.9/linker-arm.ipk
|
||||
target-path: /downloads/linker/v1.8.0/linker-arm.ipk
|
||||
- name: upload-arm
|
||||
id: upload-arm
|
||||
uses: actions/upload-release-asset@master
|
||||
@@ -84,7 +84,7 @@ jobs:
|
||||
key-secret: ${{ secrets.ALIYUN_OSS_SECRET }}
|
||||
bucket: ide-qbcode
|
||||
asset-path: ./public/publish-ipk/arm64/linker-arm64.ipk
|
||||
target-path: /downloads/linker/v1.7.9/linker-arm64.ipk
|
||||
target-path: /downloads/linker/v1.8.0/linker-arm64.ipk
|
||||
- name: upload-arm64
|
||||
id: upload-arm64
|
||||
uses: actions/upload-release-asset@master
|
||||
|
56
.github/workflows/nuget.yml
vendored
56
.github/workflows/nuget.yml
vendored
@@ -83,31 +83,31 @@ jobs:
|
||||
|
||||
- name: Push
|
||||
run: |
|
||||
dotnet nuget push ./src/linker.libs/bin/release/linker.libs.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger/bin/release/linker.messenger.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.access/bin/release/linker.messenger.access.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.action/bin/release/linker.messenger.action.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.api/bin/release/linker.messenger.api.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.channel/bin/release/linker.messenger.channel.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.decenter/bin/release/linker.messenger.decenter.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.entry/bin/release/linker.messenger.entry.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.exroute/bin/release/linker.messenger.exroute.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.flow/bin/release/linker.messenger.flow.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.forward/bin/release/linker.messenger.forward.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.listen/bin/release/linker.messenger.listen.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.logger/bin/release/linker.messenger.logger.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.pcp/bin/release/linker.messenger.pcp.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.plan/bin/release/linker.messenger.plan.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.relay/bin/release/linker.messenger.relay.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.serializer.memorypack/bin/release/linker.messenger.serializer.memorypack.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.sforward/bin/release/linker.messenger.sforward.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.signin/bin/release/linker.messenger.signin.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.socks5/bin/release/linker.messenger.socks5.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.store.file/bin/release/linker.messenger.store.file.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.sync/bin/release/linker.messenger.sync.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.tunnel/bin/release/linker.messenger.tunnel.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.tuntap/bin/release/linker.messenger.tuntap.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.updater/bin/release/linker.messenger.updater.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.tun/bin/release/linker.tun.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.snat/bin/release/linker.snat.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.tunnel/bin/release/linker.tunnel.1.7.9.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.libs/bin/release/linker.libs.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger/bin/release/linker.messenger.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.access/bin/release/linker.messenger.access.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.action/bin/release/linker.messenger.action.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.api/bin/release/linker.messenger.api.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.channel/bin/release/linker.messenger.channel.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.decenter/bin/release/linker.messenger.decenter.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.entry/bin/release/linker.messenger.entry.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.exroute/bin/release/linker.messenger.exroute.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.flow/bin/release/linker.messenger.flow.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.forward/bin/release/linker.messenger.forward.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.listen/bin/release/linker.messenger.listen.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.logger/bin/release/linker.messenger.logger.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.pcp/bin/release/linker.messenger.pcp.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.plan/bin/release/linker.messenger.plan.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.relay/bin/release/linker.messenger.relay.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.serializer.memorypack/bin/release/linker.messenger.serializer.memorypack.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.sforward/bin/release/linker.messenger.sforward.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.signin/bin/release/linker.messenger.signin.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.socks5/bin/release/linker.messenger.socks5.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.store.file/bin/release/linker.messenger.store.file.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.sync/bin/release/linker.messenger.sync.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.tunnel/bin/release/linker.messenger.tunnel.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.tuntap/bin/release/linker.messenger.tuntap.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.messenger.updater/bin/release/linker.messenger.updater.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.tun/bin/release/linker.tun.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.snat/bin/release/linker.snat.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
dotnet nuget push ./src/linker.tunnel/bin/release/linker.tunnel.1.8.0.nupkg --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{ secrets.NUGET_KEY }} --no-symbols
|
||||
|
@@ -59,7 +59,7 @@
|
||||
##### 特色功能
|
||||
- **网段映射:** 当多个设备不同的局域网使用相同的内网网段(如`192.168.1.0/24`)存在冲突时,网段映射可以让你继续顺利的使用点对网和网对网,例如配置`192.168.188.0/24->192.168.1.0/24`,就可以使用`192.168.188.2`访问`192.168.1.2`。
|
||||
- **应用层NAT:** 内置了使用`WinDivert`实现的应用层NAT,即使在`win7/8,win server2008/2012`这样的老系统无法使用系统NAT时也可以顺利使用点对网和网对网。
|
||||
- **应用层防火墙** 内置了防火墙功能,应用于虚拟网卡、端口转发、socks5,可以精细控制客户端的访问权限,例如只允许A访问B的3389,其它客户端无法访问
|
||||
- **应用层防火墙:** 内置了防火墙功能,应用于虚拟网卡、端口转发、socks5,可以精细控制客户端的访问权限,例如只允许A访问B的3389,其它客户端无法访问
|
||||
|
||||
##### 其它特性
|
||||
- **UI管理:** 简洁明了的web管理页面
|
||||
@@ -84,8 +84,9 @@
|
||||
请作者喝一杯咖啡,让作者更有动力更新代码
|
||||
<p><img src="./readme/qr.jpg" width="360"></p>
|
||||
|
||||
## 🚀特别声明
|
||||
## 🚀特别说明
|
||||
|
||||
本项目已加入 [DotNetGuide](https://github.com/YSGStudyHards/DotNetGuide) 列表。<br/>
|
||||
本项目已加入 [dotNET China](https://gitee.com/dotnetchina) 组织。<br/>
|
||||
|
||||

|
@@ -33,16 +33,16 @@ do
|
||||
fi
|
||||
done
|
||||
cd public/publish/docker/linux-${p}-x64/${f}
|
||||
docker buildx build -f ${target}/public/publish/docker/linux-${p}-x64/${f}/Dockerfile-${p} --platform="linux/x86_64" --force-rm -t "${image}-${p}-x64:latest" -t "${image}-${p}-x64:v1.7.9" . --push
|
||||
docker buildx build -f ${target}/public/publish/docker/linux-${p}-x64/${f}/Dockerfile-${p} --platform="linux/x86_64" --force-rm -t "${image}-${p}-x64:latest" -t "${image}-${p}-x64:v1.8.0" . --push
|
||||
cd ../../../../../
|
||||
|
||||
|
||||
cd public/publish/docker/linux-${p}-arm64/${f}
|
||||
docker buildx build -f ${target}/public/publish/docker/linux-${p}-arm64/${f}/Dockerfile-${p} --platform="linux/arm64" --force-rm -t "${image}-${p}-arm64:latest" -t "${image}-${p}-arm64:v1.7.9" . --push
|
||||
docker buildx build -f ${target}/public/publish/docker/linux-${p}-arm64/${f}/Dockerfile-${p} --platform="linux/arm64" --force-rm -t "${image}-${p}-arm64:latest" -t "${image}-${p}-arm64:v1.8.0" . --push
|
||||
cd ../../../../../
|
||||
|
||||
cd public/publish/docker/linux-${p}-arm/${f}
|
||||
docker buildx build -f ${target}/public/publish/docker/linux-${p}-arm/${f}/Dockerfile-${p} --platform="linux/arm/v7" --force-rm -t "${image}-${p}-arm:latest" -t "${image}-${p}-arm:v1.7.9" . --push
|
||||
docker buildx build -f ${target}/public/publish/docker/linux-${p}-arm/${f}/Dockerfile-${p} --platform="linux/arm/v7" --force-rm -t "${image}-${p}-arm:latest" -t "${image}-${p}-arm:v1.8.0" . --push
|
||||
cd ../../../../../
|
||||
done
|
||||
done
|
@@ -22,7 +22,7 @@ do
|
||||
mkdir -p public/publish-ipk/${r}/data/usr/bin/linker
|
||||
cp -rf public/publish/${r}/* public/publish-ipk/${r}/data/usr/bin/linker/
|
||||
|
||||
sed -i "s|{version}|1.7.9|g" public/publish-ipk/${r}/control/control
|
||||
sed -i "s|{version}|1.8.0|g" public/publish-ipk/${r}/control/control
|
||||
sed -i 's/\r$//' public/publish-ipk/${r}/data/etc/init.d/linker
|
||||
sed -i 's/\r$//' public/publish-ipk/${r}/control/control
|
||||
sed -i 's/\r$//' public/publish-ipk/${r}/control/postinst
|
||||
|
@@ -28,7 +28,7 @@
|
||||
<ApplicationId>com.snltty.linker.app</ApplicationId>
|
||||
|
||||
<Title>linker.app</Title>
|
||||
<Version>1.7.9</Version>
|
||||
<Version>1.8.0</Version>
|
||||
<Authors>snltty</Authors>
|
||||
<Company>snltty</Company>
|
||||
<Copyright>snltty</Copyright>
|
||||
@@ -38,7 +38,7 @@
|
||||
<PackageReleaseNotes>linker</PackageReleaseNotes>
|
||||
|
||||
<!-- Versions -->
|
||||
<ApplicationDisplayVersion>1.7.9</ApplicationDisplayVersion>
|
||||
<ApplicationDisplayVersion>1.8.0</ApplicationDisplayVersion>
|
||||
<ApplicationVersion>1</ApplicationVersion>
|
||||
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">11.0</SupportedOSPlatformVersion>
|
||||
|
8
src/linker.doc.web/static/robots.txt
Normal file
8
src/linker.doc.web/static/robots.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
# START YOAST BLOCK
|
||||
# ---------------------------
|
||||
User-agent: *
|
||||
Disallow:
|
||||
|
||||
Sitemap: https://blog.snltty.com/sitemap.xml
|
||||
# ---------------------------
|
||||
# END YOAST BLOCK
|
@@ -14,9 +14,9 @@
|
||||
<Copyright>snltty</Copyright>
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DebugType>full</DebugType>
|
||||
|
@@ -16,9 +16,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger api access</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -16,9 +16,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger api action</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -17,9 +17,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger api</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -16,9 +16,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger channel</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -16,9 +16,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger decenter</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -16,9 +16,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger entry</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -16,9 +16,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger exroute</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -17,9 +17,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger firewall</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -17,9 +17,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger flow</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -17,9 +17,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger forward</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -43,7 +43,7 @@ namespace linker.messenger.forward.proxy
|
||||
}
|
||||
private async Task ReceiveUdp(AsyncUserUdpToken token, byte buffersize)
|
||||
{
|
||||
byte[] bytes = new byte[(1 << buffersize) * 1024];
|
||||
byte[] bytes = new byte[65535];
|
||||
IPEndPoint tempRemoteEP = new IPEndPoint(IPAddress.Any, IPEndPoint.MinPort);
|
||||
while (true)
|
||||
{
|
||||
@@ -217,7 +217,7 @@ namespace linker.messenger.forward.proxy
|
||||
TargetSocket = socket,
|
||||
ConnectId = connectId,
|
||||
Connection = tunnelToken.Connection,
|
||||
Buffer = new byte[(1 << tunnelToken.Proxy.BufferSize) * 1024]
|
||||
Buffer = new byte[65535]
|
||||
};
|
||||
udpToken.Proxy.Direction = ProxyDirection.Reverse;
|
||||
udpConnections.AddOrUpdate(connectId, udpToken, (a, b) => udpToken);
|
||||
|
@@ -17,9 +17,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger listen</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -16,9 +16,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger logger</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -17,9 +17,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger pcp</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -16,9 +16,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger plan</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -18,9 +18,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger relay</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -193,7 +193,7 @@ namespace linker.messenger.relay.server
|
||||
{
|
||||
if (relayDic.TryRemove(relayCache.FlowId, out TaskCompletionSource<Socket> tcsAsk))
|
||||
{
|
||||
tcsAsk.SetResult(socket);
|
||||
tcsAsk.TrySetResult(socket);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -202,11 +202,12 @@ namespace linker.messenger.relay.server
|
||||
return;
|
||||
}
|
||||
|
||||
TaskCompletionSource<Socket> tcs = new TaskCompletionSource<Socket>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
try
|
||||
{
|
||||
await socket.SendAsync(new byte[] { 0 }).ConfigureAwait(false);
|
||||
|
||||
TaskCompletionSource<Socket> tcs = new TaskCompletionSource<Socket>();
|
||||
|
||||
relayDic.TryAdd(relayCache.FlowId, tcs);
|
||||
Socket answerSocket = await tcs.Task.WaitAsync(TimeSpan.FromMilliseconds(15000)).ConfigureAwait(false);
|
||||
|
||||
@@ -220,6 +221,7 @@ namespace linker.messenger.relay.server
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
tcs.TrySetResult(null);
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Error($"{ex},flowid:{relayMessage.FlowId}");
|
||||
relayDic.TryRemove(relayCache.FlowId, out _);
|
||||
|
@@ -509,9 +509,11 @@ namespace linker.messenger.serializer.memorypack
|
||||
double Lon => info.Lon;
|
||||
[MemoryPackInclude]
|
||||
string Isp => info.Isp;
|
||||
[MemoryPackInclude]
|
||||
string Nat => info.Nat;
|
||||
|
||||
[MemoryPackConstructor]
|
||||
SerializableTunnelNetInfo(string countryCode, string city, double lat, double lon, string isp)
|
||||
SerializableTunnelNetInfo(string countryCode, string city, double lat, double lon, string isp, string nat)
|
||||
{
|
||||
var info = new TunnelNetInfo
|
||||
{
|
||||
@@ -519,7 +521,8 @@ namespace linker.messenger.serializer.memorypack
|
||||
CountryCode = countryCode,
|
||||
Isp = isp,
|
||||
Lat = lat,
|
||||
Lon = lon
|
||||
Lon = lon,
|
||||
Nat = nat
|
||||
};
|
||||
this.info = info;
|
||||
}
|
||||
|
@@ -16,9 +16,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger serializer memorypack</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -16,9 +16,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger sforward</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -115,7 +115,7 @@ namespace linker.plugins.sforward.proxy
|
||||
ulong _id = buffer1.AsSpan(flagBytes.Length).ToUInt64();
|
||||
if (tcpConnections.TryRemove(_id, out TaskCompletionSource<Socket> _tcs))
|
||||
{
|
||||
_tcs.SetResult(token.SourceSocket);
|
||||
_tcs.TrySetResult(token.SourceSocket);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -149,7 +149,15 @@ namespace linker.plugins.sforward.proxy
|
||||
//等待回复
|
||||
TaskCompletionSource<Socket> tcs = new TaskCompletionSource<Socket>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
tcpConnections.TryAdd(id, tcs);
|
||||
token.TargetSocket = await tcs.Task.WaitAsync(TimeSpan.FromMilliseconds(5000)).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
token.TargetSocket = await tcs.Task.WaitAsync(TimeSpan.FromMilliseconds(5000)).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
CloseClientSocket(token);
|
||||
return;
|
||||
}
|
||||
|
||||
//数据
|
||||
await token.TargetSocket.SendAsync(buffer1.AsMemory(0, length)).ConfigureAwait(false);
|
||||
|
@@ -45,7 +45,7 @@ namespace linker.plugins.sforward.proxy
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] buffer = new byte[(1 << bufferSize) * 1024];
|
||||
byte[] buffer = new byte[65535];
|
||||
IPEndPoint tempRemoteEP = new IPEndPoint(IPAddress.Any, IPEndPoint.MinPort);
|
||||
|
||||
string portStr = token.ListenPort.ToString();
|
||||
@@ -78,7 +78,7 @@ namespace linker.plugins.sforward.proxy
|
||||
ulong _id = memory.Slice(flagBytes.Length).ToUInt64();
|
||||
if (udptcss.TryRemove(_id, out TaskCompletionSource<IPEndPoint> _tcs))
|
||||
{
|
||||
_tcs.SetResult(source);
|
||||
_tcs.TrySetResult(source);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -91,7 +91,7 @@ namespace linker.plugins.sforward.proxy
|
||||
|
||||
int length = memory.Length;
|
||||
byte[] buf = ArrayPool<byte>.Shared.Rent(length);
|
||||
memory.CopyTo(buffer);
|
||||
memory.CopyTo(buf);
|
||||
|
||||
TimerHelper.Async(async () =>
|
||||
{
|
||||
@@ -103,13 +103,20 @@ namespace linker.plugins.sforward.proxy
|
||||
TaskCompletionSource<IPEndPoint> tcs = new TaskCompletionSource<IPEndPoint>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
udptcss.TryAdd(id, tcs);
|
||||
|
||||
IPEndPoint remote = await tcs.Task.WaitAsync(TimeSpan.FromMilliseconds(5000)).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
IPEndPoint remote = await tcs.Task.WaitAsync(TimeSpan.FromMilliseconds(5000)).ConfigureAwait(false);
|
||||
|
||||
udpConnections.TryRemove(source, out _);
|
||||
udpConnections.TryAdd(source, new UdpTargetCache { IPEndPoint = remote });
|
||||
udpConnections.TryAdd(remote, new UdpTargetCache { IPEndPoint = source });
|
||||
udpConnections.TryRemove(source, out _);
|
||||
udpConnections.TryAdd(source, new UdpTargetCache { IPEndPoint = remote });
|
||||
udpConnections.TryAdd(remote, new UdpTargetCache { IPEndPoint = source });
|
||||
|
||||
await token.SourceSocket.SendToAsync(buf.AsMemory(0, length), remote).ConfigureAwait(false);
|
||||
await token.SourceSocket.SendToAsync(buf.AsMemory(0, length), remote).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
tcs.TrySetResult(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -180,7 +187,7 @@ namespace linker.plugins.sforward.proxy
|
||||
|
||||
//连接本地服务
|
||||
Socket serviceUdp = null;
|
||||
buffer = new byte[(1 << bufferSize) * 1024];
|
||||
buffer = new byte[65535];
|
||||
IPEndPoint tempEp = new IPEndPoint(IPAddress.Any, IPEndPoint.MinPort);
|
||||
|
||||
UdpConnectedCache cache = new UdpConnectedCache { SourceSocket = serverUdp, TargetSocket = serviceUdp };
|
||||
@@ -227,7 +234,7 @@ namespace linker.plugins.sforward.proxy
|
||||
await serviceUdp.SendToAsync(memory, service).ConfigureAwait(false);
|
||||
TimerHelper.Async(async () =>
|
||||
{
|
||||
byte[] buffer = new byte[(1 << bufferSize) * 1024];
|
||||
byte[] buffer = new byte[65535];
|
||||
IPEndPoint tempEp = new IPEndPoint(IPAddress.Any, IPEndPoint.MinPort);
|
||||
while (true)
|
||||
{
|
||||
|
@@ -17,9 +17,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger signin</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -39,7 +39,7 @@ namespace linker.messenger.socks5
|
||||
}
|
||||
private async Task ReceiveUdp(AsyncUserUdpToken token, byte buffersize)
|
||||
{
|
||||
byte[] bytes = new byte[(1 << buffersize) * 1024];
|
||||
byte[] bytes = new byte[65535];
|
||||
IPEndPoint tempRemoteEP = new IPEndPoint(IPAddress.Any, IPEndPoint.MinPort);
|
||||
while (true)
|
||||
{
|
||||
@@ -201,7 +201,7 @@ namespace linker.messenger.socks5
|
||||
TargetRealEP = target,
|
||||
ConnectId = connectId,
|
||||
Connection = tunnelToken.Connection,
|
||||
Buffer = new byte[(1 << tunnelToken.Proxy.BufferSize) * 1024]
|
||||
Buffer = new byte[65535]
|
||||
};
|
||||
udpToken.Proxy.Direction = ProxyDirection.Reverse;
|
||||
udpConnections.AddOrUpdate(connectId, udpToken, (a, b) => udpToken);
|
||||
|
@@ -16,9 +16,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger socks5</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -16,9 +16,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger store file</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -18,9 +18,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger sync</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -44,6 +44,7 @@ namespace linker.messenger.tunnel
|
||||
public double Lat { get; set; }
|
||||
public double Lon { get; set; }
|
||||
public string Isp { get; set; } = string.Empty;
|
||||
public string Nat { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public sealed partial class TunnelSetRouteLevelInfo
|
||||
|
@@ -12,18 +12,17 @@ namespace linker.messenger.tunnel
|
||||
public ConcurrentDictionary<string, TunnelRouteLevelInfo> Config { get; } = new ConcurrentDictionary<string, TunnelRouteLevelInfo>();
|
||||
|
||||
private readonly ITunnelClientStore tunnelClientStore;
|
||||
private readonly TunnelNetworkTransfer tunnelNetworkTransfer;
|
||||
private readonly ISerializer serializer;
|
||||
private readonly SignInClientState signInClientState;
|
||||
|
||||
public TunnelDecenter(ITunnelClientStore tunnelClientStore, TunnelNetworkTransfer tunnelNetworkTransfer, ISerializer serializer, SignInClientState signInClientState)
|
||||
{
|
||||
this.tunnelClientStore = tunnelClientStore;
|
||||
tunnelClientStore.OnChanged += Refresh;
|
||||
this.tunnelNetworkTransfer = tunnelNetworkTransfer;
|
||||
this.serializer = serializer;
|
||||
this.signInClientState = signInClientState;
|
||||
|
||||
tunnelClientStore.OnChanged += Refresh;
|
||||
tunnelNetworkTransfer.OnChange += Refresh;
|
||||
}
|
||||
public void Refresh()
|
||||
{
|
||||
@@ -31,12 +30,14 @@ namespace linker.messenger.tunnel
|
||||
}
|
||||
public Memory<byte> GetData()
|
||||
{
|
||||
TunnelRouteLevelInfo tunnelRouteLevelInfo = GetLocalRouteLevel();
|
||||
Config.AddOrUpdate(tunnelRouteLevelInfo.MachineId, tunnelRouteLevelInfo, (a, b) => tunnelRouteLevelInfo);
|
||||
return serializer.Serialize(GetLocalRouteLevel());
|
||||
}
|
||||
public void AddData(Memory<byte> data)
|
||||
{
|
||||
TunnelRouteLevelInfo tunnelTransportRouteLevelInfo = serializer.Deserialize<TunnelRouteLevelInfo>(data.Span);
|
||||
Config.AddOrUpdate(tunnelTransportRouteLevelInfo.MachineId, tunnelTransportRouteLevelInfo, (a, b) => tunnelTransportRouteLevelInfo);
|
||||
TunnelRouteLevelInfo tunnelRouteLevelInfo = serializer.Deserialize<TunnelRouteLevelInfo>(data.Span);
|
||||
Config.AddOrUpdate(tunnelRouteLevelInfo.MachineId, tunnelRouteLevelInfo, (a, b) => tunnelRouteLevelInfo);
|
||||
}
|
||||
public void AddData(List<ReadOnlyMemory<byte>> data)
|
||||
{
|
||||
@@ -65,7 +66,7 @@ namespace linker.messenger.tunnel
|
||||
PortMapWan = tunnelClientStore.PortMapPublic,
|
||||
RouteLevelPlus = tunnelClientStore.RouteLevelPlus,
|
||||
Net = tunnelClientStore.Network.Net
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,6 +2,8 @@
|
||||
using linker.libs.extends;
|
||||
using linker.libs.timer;
|
||||
using linker.messenger.signin;
|
||||
using linker.messenger.tunnel.stun.client;
|
||||
using linker.messenger.tunnel.stun.result;
|
||||
using linker.tunnel;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
@@ -20,6 +22,8 @@ namespace linker.messenger.tunnel
|
||||
private readonly IMessengerSender messengerSender;
|
||||
private readonly ISerializer serializer;
|
||||
|
||||
public Action OnChange { get; set; } = () => { };
|
||||
|
||||
public TunnelNetworkTransfer(ISignInClientStore signInClientStore, SignInClientState signInClientState, ITunnelClientStore tunnelClientStore, IMessengerSender messengerSender, ISerializer serializer, TunnelTransfer tunnelTransfer)
|
||||
{
|
||||
this.signInClientStore = signInClientStore;
|
||||
@@ -28,7 +32,7 @@ namespace linker.messenger.tunnel
|
||||
this.messengerSender = messengerSender;
|
||||
this.serializer = serializer;
|
||||
|
||||
|
||||
|
||||
signInClientState.OnSignInSuccessBefore += async () => { RefreshRouteLevel(); tunnelTransfer.Refresh(); await Task.CompletedTask; };
|
||||
|
||||
TestQuic();
|
||||
@@ -68,6 +72,8 @@ namespace linker.messenger.tunnel
|
||||
TunnelNetInfo net = str.DeJson<TunnelNetInfo>();
|
||||
tunnelClientStore.Network.Net.Isp = net.Isp;
|
||||
tunnelClientStore.Network.Net.CountryCode = net.CountryCode;
|
||||
|
||||
OnChange?.Invoke();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -90,6 +96,7 @@ namespace linker.messenger.tunnel
|
||||
tunnelClientStore.Network.Net.City = json["location"]["city"].ToString();
|
||||
tunnelClientStore.Network.Net.Lat = double.Parse(json["location"]["latitude"].ToString());
|
||||
tunnelClientStore.Network.Net.Lon = double.Parse(json["location"]["longitude"].ToString());
|
||||
OnChange?.Invoke();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -99,16 +106,49 @@ namespace linker.messenger.tunnel
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private async Task<bool> TestNatTypeAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
IPEndPoint serverEP = NetworkHelper.GetEndPoint("stun.miwifi.com", 3478);
|
||||
|
||||
using StunClient3489 client = new(serverEP, new IPEndPoint(IPAddress.Any, 0), null);
|
||||
await client.ConnectProxyAsync();
|
||||
try
|
||||
{
|
||||
await client.QueryAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
await client.CloseProxyAsync();
|
||||
}
|
||||
|
||||
tunnelClientStore.Network.Net.Nat = client.State.NatType.ToString();
|
||||
|
||||
OnChange?.Invoke();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
{
|
||||
LoggerHelper.Instance.Error(ex);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void GetNet()
|
||||
{
|
||||
TimerHelper.Async(async () =>
|
||||
{
|
||||
bool isp = false, city = false;
|
||||
bool isp = false, city = false,nat = false;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
if (isp == false) isp = await GetIsp();
|
||||
if (city == false) city = await GetPosition();
|
||||
if (isp && city)
|
||||
if (nat == false) nat = await TestNatTypeAsync();
|
||||
if (isp && city && nat)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -128,6 +168,30 @@ namespace linker.messenger.tunnel
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public TunnelLocalNetworkInfo GetLocalNetwork()
|
||||
{
|
||||
return new TunnelLocalNetworkInfo
|
||||
{
|
||||
MachineId = signInClientState.Connection?.Id ?? string.Empty,
|
||||
HostName = Dns.GetHostName(),
|
||||
Lans = GetInterfaces(),
|
||||
Routes = tunnelClientStore.Network.RouteIPs,
|
||||
};
|
||||
}
|
||||
private static byte[] ipv6LocalBytes = new byte[] { 254, 128, 0, 0, 0, 0, 0, 0 };
|
||||
private TunnelInterfaceInfo[] GetInterfaces()
|
||||
{
|
||||
return NetworkInterface.GetAllNetworkInterfaces().Select(c => new TunnelInterfaceInfo
|
||||
{
|
||||
Name = c.Name,
|
||||
Desc = c.Description,
|
||||
Mac = Regex.Replace(c.GetPhysicalAddress().ToString(), @"(.{2})", $"$1-").Trim('-'),
|
||||
Ips = c.GetIPProperties().UnicastAddresses.Select(c => c.Address).Where(c => c.AddressFamily == AddressFamily.InterNetwork || (c.AddressFamily == AddressFamily.InterNetworkV6 && c.GetAddressBytes().AsSpan(0, 8).SequenceEqual(ipv6LocalBytes) == false)).ToArray()
|
||||
}).Where(c => c.Ips.Length > 0 && c.Ips.Any(d => d.Equals(IPAddress.Loopback)) == false).ToArray();
|
||||
}
|
||||
|
||||
|
||||
private void TestQuic()
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
@@ -168,29 +232,5 @@ namespace linker.messenger.tunnel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public TunnelLocalNetworkInfo GetLocalNetwork()
|
||||
{
|
||||
return new TunnelLocalNetworkInfo
|
||||
{
|
||||
MachineId = signInClientState.Connection?.Id ?? string.Empty,
|
||||
HostName = Dns.GetHostName(),
|
||||
Lans = GetInterfaces(),
|
||||
Routes = tunnelClientStore.Network.RouteIPs,
|
||||
};
|
||||
}
|
||||
private static byte[] ipv6LocalBytes = new byte[] { 254, 128, 0, 0, 0, 0, 0, 0 };
|
||||
private TunnelInterfaceInfo[] GetInterfaces()
|
||||
{
|
||||
return NetworkInterface.GetAllNetworkInterfaces().Select(c => new TunnelInterfaceInfo
|
||||
{
|
||||
Name = c.Name,
|
||||
Desc = c.Description,
|
||||
Mac = Regex.Replace(c.GetPhysicalAddress().ToString(), @"(.{2})", $"$1-").Trim('-'),
|
||||
Ips = c.GetIPProperties().UnicastAddresses.Select(c => c.Address).Where(c => c.AddressFamily == AddressFamily.InterNetwork || (c.AddressFamily == AddressFamily.InterNetworkV6 && c.GetAddressBytes().AsSpan(0, 8).SequenceEqual(ipv6LocalBytes) == false)).ToArray()
|
||||
}).Where(c => c.Ips.Length > 0 && c.Ips.Any(d => d.Equals(IPAddress.Loopback)) == false).ToArray();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -16,9 +16,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger tunnel</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
75
src/linker.messenger.tunnel/stun/HostnameEndpoint.cs
Normal file
75
src/linker.messenger.tunnel/stun/HostnameEndpoint.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace linker.messenger.tunnel.stun;
|
||||
|
||||
public class HostnameEndpoint
|
||||
{
|
||||
public string Hostname { get; }
|
||||
public ushort Port { get; }
|
||||
|
||||
private HostnameEndpoint(string host, ushort port)
|
||||
{
|
||||
Hostname = host;
|
||||
Port = port;
|
||||
}
|
||||
|
||||
public static bool TryParse(string s, [NotNullWhen(true)] out HostnameEndpoint? result, ushort defaultPort = 0)
|
||||
{
|
||||
result = null;
|
||||
if (string.IsNullOrEmpty(s))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int hostLength = s.Length;
|
||||
int pos = s.LastIndexOf(':');
|
||||
|
||||
if (pos > 0)
|
||||
{
|
||||
if (s[pos - 1] is ']')
|
||||
{
|
||||
hostLength = pos;
|
||||
}
|
||||
else if (s.AsSpan(0, pos).LastIndexOf(':') is -1)
|
||||
{
|
||||
hostLength = pos;
|
||||
}
|
||||
}
|
||||
|
||||
string host = s[..hostLength];
|
||||
UriHostNameType type = Uri.CheckHostName(host);
|
||||
switch (type)
|
||||
{
|
||||
case UriHostNameType.Dns:
|
||||
case UriHostNameType.IPv4:
|
||||
case UriHostNameType.IPv6:
|
||||
{
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hostLength == s.Length || ushort.TryParse(s.AsSpan(hostLength + 1), out defaultPort))
|
||||
{
|
||||
result = new HostnameEndpoint(host, defaultPort);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (IPAddress.TryParse(Hostname, out IPAddress? ip) && ip.AddressFamily is AddressFamily.InterNetworkV6)
|
||||
{
|
||||
return $@"[{ip}]:{Port}";
|
||||
}
|
||||
|
||||
return $@"{Hostname}:{Port}";
|
||||
}
|
||||
}
|
51
src/linker.messenger.tunnel/stun/StunServer.cs
Normal file
51
src/linker.messenger.tunnel/stun/StunServer.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace linker.messenger.tunnel.stun;
|
||||
|
||||
public class StunServer
|
||||
{
|
||||
public string Hostname { get; }
|
||||
public ushort Port { get; }
|
||||
|
||||
public const ushort DefaultPort = 3478;
|
||||
public const ushort DefaultTlsPort = 5349;
|
||||
|
||||
public StunServer()
|
||||
{
|
||||
Hostname = @"stun.miwifi.com";
|
||||
Port = DefaultPort;
|
||||
}
|
||||
|
||||
private StunServer(string hostname, ushort port)
|
||||
{
|
||||
Hostname = hostname;
|
||||
Port = port;
|
||||
}
|
||||
|
||||
public static bool TryParse(string s, [NotNullWhen(true)] out StunServer? result, ushort defaultPort = DefaultPort)
|
||||
{
|
||||
if (!HostnameEndpoint.TryParse(s, out HostnameEndpoint? host, defaultPort))
|
||||
{
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
result = new StunServer(host.Hostname, host.Port);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (Port is DefaultPort)
|
||||
{
|
||||
return Hostname;
|
||||
}
|
||||
if (IPAddress.TryParse(Hostname, out IPAddress? ip) && ip.AddressFamily is AddressFamily.InterNetworkV6)
|
||||
{
|
||||
return $@"[{ip}]:{Port}";
|
||||
}
|
||||
return $@"{Hostname}:{Port}";
|
||||
}
|
||||
}
|
6
src/linker.messenger.tunnel/stun/client/IStunClient.cs
Normal file
6
src/linker.messenger.tunnel/stun/client/IStunClient.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace linker.messenger.tunnel.stun.client;
|
||||
|
||||
public interface IStunClient : IDisposable
|
||||
{
|
||||
ValueTask QueryAsync(CancellationToken cancellationToken = default);
|
||||
}
|
@@ -0,0 +1,6 @@
|
||||
namespace linker.messenger.tunnel.stun.client;
|
||||
|
||||
public interface IUdpStunClient : IStunClient
|
||||
{
|
||||
TimeSpan ReceiveTimeout { get; set; }
|
||||
}
|
230
src/linker.messenger.tunnel/stun/client/StunClient3489.cs
Normal file
230
src/linker.messenger.tunnel/stun/client/StunClient3489.cs
Normal file
@@ -0,0 +1,230 @@
|
||||
using linker.messenger.tunnel.stun.enums;
|
||||
using linker.messenger.tunnel.stun.messages;
|
||||
using linker.messenger.tunnel.stun.proxy;
|
||||
using linker.messenger.tunnel.stun.result;
|
||||
using linker.messenger.tunnel.stun.utils;
|
||||
using System.Buffers;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace linker.messenger.tunnel.stun.client;
|
||||
|
||||
/// <summary>
|
||||
/// https://tools.ietf.org/html/rfc3489#section-10.1
|
||||
/// </summary>
|
||||
public class StunClient3489 : IUdpStunClient
|
||||
{
|
||||
public virtual IPEndPoint LocalEndPoint => (IPEndPoint)_proxy.Client.LocalEndPoint!;
|
||||
|
||||
public TimeSpan ReceiveTimeout { get; set; } = TimeSpan.FromSeconds(3);
|
||||
|
||||
private readonly IPEndPoint _remoteEndPoint;
|
||||
|
||||
private readonly IUdpProxy _proxy;
|
||||
|
||||
public ClassicStunResult State { get; private set; } = new();
|
||||
|
||||
public StunClient3489(IPEndPoint server, IPEndPoint local, IUdpProxy proxy = null)
|
||||
{
|
||||
_proxy = proxy ?? new NoneUdpProxy(local);
|
||||
|
||||
_remoteEndPoint = server;
|
||||
|
||||
State.LocalEndPoint = local;
|
||||
}
|
||||
|
||||
public async ValueTask ConnectProxyAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
using CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
cts.CancelAfter(ReceiveTimeout);
|
||||
|
||||
await _proxy.ConnectAsync(cts.Token);
|
||||
}
|
||||
|
||||
public async ValueTask CloseProxyAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
await _proxy.CloseAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async ValueTask QueryAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
State = new ClassicStunResult();
|
||||
|
||||
// test I
|
||||
StunResponse response1 = await Test1Async(cancellationToken);
|
||||
if (response1 is null)
|
||||
{
|
||||
State.NatType = NatType.UdpBlocked;
|
||||
return;
|
||||
}
|
||||
|
||||
State.LocalEndPoint = response1.Local;
|
||||
|
||||
IPEndPoint mappedAddress1 = response1.Message.GetMappedAddressAttribute();
|
||||
IPEndPoint changedAddress = response1.Message.GetChangedAddressAttribute();
|
||||
|
||||
State.PublicEndPoint = mappedAddress1; // 显示 test I 得到的映射地址
|
||||
|
||||
// 某些单 IP 服务器的迷惑操作
|
||||
if (mappedAddress1 is null || changedAddress is null
|
||||
|| Equals(changedAddress.Address, response1.Remote.Address)
|
||||
|| changedAddress.Port == response1.Remote.Port)
|
||||
{
|
||||
State.NatType = NatType.UnsupportedServer;
|
||||
return;
|
||||
}
|
||||
|
||||
// test II
|
||||
StunResponse response2 = await Test2Async(changedAddress, cancellationToken);
|
||||
IPEndPoint mappedAddress2 = response2?.Message.GetMappedAddressAttribute();
|
||||
|
||||
if (response2 is not null)
|
||||
{
|
||||
// 有些单 IP 服务器并不能测 NAT 类型
|
||||
if (Equals(response1.Remote.Address, response2.Remote.Address) || response1.Remote.Port == response2.Remote.Port)
|
||||
{
|
||||
State.NatType = NatType.UnsupportedServer;
|
||||
State.PublicEndPoint = mappedAddress2;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// is Public IP == link's IP?
|
||||
if (Equals(mappedAddress1, response1.Local))
|
||||
{
|
||||
// No NAT
|
||||
if (response2 is null)
|
||||
{
|
||||
|
||||
State.NatType = NatType.SymmetricUdpFirewall;
|
||||
State.PublicEndPoint = mappedAddress1;
|
||||
}
|
||||
else
|
||||
{
|
||||
State.NatType = NatType.OpenInternet;
|
||||
State.PublicEndPoint = mappedAddress2;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// NAT
|
||||
if (response2 is not null)
|
||||
{
|
||||
State.NatType = NatType.FullCone;
|
||||
State.PublicEndPoint = mappedAddress2;
|
||||
return;
|
||||
}
|
||||
|
||||
// Test I(#2)
|
||||
StunResponse response12 = await Test1_2Async(changedAddress, cancellationToken);
|
||||
IPEndPoint mappedAddress12 = response12.Message.GetMappedAddressAttribute();
|
||||
|
||||
if (mappedAddress12 is null)
|
||||
{
|
||||
State.NatType = NatType.Unknown;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Equals(mappedAddress12, mappedAddress1))
|
||||
{
|
||||
State.NatType = NatType.Symmetric;
|
||||
State.PublicEndPoint = mappedAddress12;
|
||||
return;
|
||||
}
|
||||
|
||||
// Test III
|
||||
StunResponse response3 = await Test3Async(cancellationToken);
|
||||
if (response3 is not null)
|
||||
{
|
||||
IPEndPoint mappedAddress3 = response3.Message.GetMappedAddressAttribute();
|
||||
if (mappedAddress3 is not null
|
||||
&& Equals(response3.Remote.Address, response1.Remote.Address)
|
||||
&& response3.Remote.Port != response1.Remote.Port)
|
||||
{
|
||||
State.NatType = NatType.RestrictedCone;
|
||||
State.PublicEndPoint = mappedAddress3;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
State.NatType = NatType.PortRestrictedCone;
|
||||
State.PublicEndPoint = mappedAddress12;
|
||||
}
|
||||
|
||||
private async ValueTask<StunResponse> RequestAsync(StunMessage5389 sendMessage, IPEndPoint remote, IPEndPoint receive, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
using IMemoryOwner<byte> memoryOwner = MemoryPool<byte>.Shared.Rent(0x10000);
|
||||
Memory<byte> buffer = memoryOwner.Memory;
|
||||
int length = sendMessage.WriteTo(buffer.Span);
|
||||
|
||||
await _proxy.SendToAsync(buffer[..length], SocketFlags.None, remote, cancellationToken);
|
||||
|
||||
using CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
cts.CancelAfter(ReceiveTimeout);
|
||||
SocketReceiveMessageFromResult r = await _proxy.ReceiveMessageFromAsync(buffer, SocketFlags.None, receive, cts.Token);
|
||||
|
||||
StunMessage5389 message = new();
|
||||
if (message.TryParse(buffer[..r.ReceivedBytes]) && message.IsSameTransaction(sendMessage))
|
||||
{
|
||||
return new StunResponse(message, (IPEndPoint)r.RemoteEndPoint, new IPEndPoint(r.PacketInformation.Address, ((IPEndPoint)_proxy.Client.LocalEndPoint!).Port));
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
Debug.WriteLine(ex);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
|
||||
public virtual async ValueTask<StunResponse> Test1Async(CancellationToken cancellationToken)
|
||||
{
|
||||
StunMessage5389 message = new()
|
||||
{
|
||||
StunMessageType = StunMessageType.BindingRequest,
|
||||
MagicCookie = 0
|
||||
};
|
||||
return await RequestAsync(message, _remoteEndPoint, _remoteEndPoint, cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async ValueTask<StunResponse> Test2Async(IPEndPoint other, CancellationToken cancellationToken)
|
||||
{
|
||||
StunMessage5389 message = new()
|
||||
{
|
||||
StunMessageType = StunMessageType.BindingRequest,
|
||||
MagicCookie = 0,
|
||||
Attributes = new[] { AttributeExtensions.BuildChangeRequest(true, true) }
|
||||
};
|
||||
return await RequestAsync(message, _remoteEndPoint, other, cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async ValueTask<StunResponse> Test1_2Async(IPEndPoint other, CancellationToken cancellationToken)
|
||||
{
|
||||
StunMessage5389 message = new()
|
||||
{
|
||||
StunMessageType = StunMessageType.BindingRequest,
|
||||
MagicCookie = 0
|
||||
};
|
||||
return await RequestAsync(message, other, other, cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async ValueTask<StunResponse> Test3Async(CancellationToken cancellationToken)
|
||||
{
|
||||
StunMessage5389 message = new()
|
||||
{
|
||||
StunMessageType = StunMessageType.BindingRequest,
|
||||
MagicCookie = 0,
|
||||
Attributes = new[] { AttributeExtensions.BuildChangeRequest(false, true) }
|
||||
};
|
||||
return await RequestAsync(message, _remoteEndPoint, _remoteEndPoint, cancellationToken);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_proxy.Dispose();
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
42
src/linker.messenger.tunnel/stun/enums/AttributeType.cs
Normal file
42
src/linker.messenger.tunnel/stun/enums/AttributeType.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
namespace linker.messenger.tunnel.stun.enums;
|
||||
|
||||
/// <summary>
|
||||
/// STUN Attribute Registry
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// https://tools.ietf.org/html/rfc3489#section-11.2
|
||||
/// https://tools.ietf.org/html/rfc5389#section-18.2
|
||||
/// https://tools.ietf.org/html/rfc5780#section-9.1
|
||||
/// https://tools.ietf.org/html/rfc8489#section-18.3
|
||||
/// </remarks>
|
||||
public enum AttributeType : ushort
|
||||
{
|
||||
Useless = 0x0000,
|
||||
MappedAddress = 0x0001,
|
||||
ResponseAddress = 0x0002,
|
||||
ChangeRequest = 0x0003,
|
||||
SourceAddress = 0x0004,
|
||||
ChangedAddress = 0x0005,
|
||||
Username = 0x0006,
|
||||
Password = 0x0007,
|
||||
MessageIntegrity = 0x0008,
|
||||
ErrorCode = 0x0009,
|
||||
UnknownAttribute = 0x000A,
|
||||
ReflectedFrom = 0x000B,
|
||||
Realm = 0x0014,
|
||||
Nonce = 0x0015,
|
||||
MessageIntegritySha256 = 0x001C,
|
||||
PasswordAlgorithm = 0x001D,
|
||||
UserHash = 0x001E,
|
||||
XorMappedAddress = 0x0020,
|
||||
Padding = 0x0026,
|
||||
ResponsePort = 0x0027,
|
||||
PasswordAlgorithms = 0x8002,
|
||||
AlternateDomain = 0x8003,
|
||||
Software = 0x8022,
|
||||
AlternateServer = 0x8023,
|
||||
CacheTimeout = 0x8027,
|
||||
Fingerprint = 0x8028,
|
||||
ResponseOrigin = 0x802B,
|
||||
OtherAddress = 0x802C,
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
namespace linker.messenger.tunnel.stun.enums;
|
||||
|
||||
public enum BindingTestResult
|
||||
{
|
||||
Unknown,
|
||||
UnsupportedServer,
|
||||
Success,
|
||||
Fail
|
||||
}
|
9
src/linker.messenger.tunnel/stun/enums/Class.cs
Normal file
9
src/linker.messenger.tunnel/stun/enums/Class.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace linker.messenger.tunnel.stun.enums;
|
||||
|
||||
internal enum Class : ushort
|
||||
{
|
||||
Request = 0b00000_0_000_0_0000,
|
||||
Indication = 0b00000_0_000_1_0000,
|
||||
SuccessResponse = 0b00000_1_000_0_0000,
|
||||
ErrorResponse = 0b00000_1_000_1_0000,
|
||||
}
|
15
src/linker.messenger.tunnel/stun/enums/FilteringBehavior.cs
Normal file
15
src/linker.messenger.tunnel/stun/enums/FilteringBehavior.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace linker.messenger.tunnel.stun.enums;
|
||||
|
||||
public enum FilteringBehavior
|
||||
{
|
||||
Unknown,
|
||||
UnsupportedServer,
|
||||
EndpointIndependent,
|
||||
AddressDependent,
|
||||
AddressAndPortDependent,
|
||||
|
||||
/// <summary>
|
||||
/// Filtering test applies only to UDP.
|
||||
/// </summary>
|
||||
None
|
||||
}
|
10
src/linker.messenger.tunnel/stun/enums/IpFamily.cs
Normal file
10
src/linker.messenger.tunnel/stun/enums/IpFamily.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace linker.messenger.tunnel.stun.enums;
|
||||
|
||||
/// <summary>
|
||||
/// https://tools.ietf.org/html/rfc5389#section-15.1
|
||||
/// </summary>
|
||||
public enum IpFamily : byte
|
||||
{
|
||||
IPv4 = 0x01,
|
||||
IPv6 = 0x02
|
||||
}
|
12
src/linker.messenger.tunnel/stun/enums/MappingBehavior.cs
Normal file
12
src/linker.messenger.tunnel/stun/enums/MappingBehavior.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace linker.messenger.tunnel.stun.enums;
|
||||
|
||||
public enum MappingBehavior
|
||||
{
|
||||
Unknown,
|
||||
UnsupportedServer,
|
||||
Direct,
|
||||
EndpointIndependent,
|
||||
AddressDependent,
|
||||
AddressAndPortDependent,
|
||||
Fail
|
||||
}
|
7
src/linker.messenger.tunnel/stun/enums/Method.cs
Normal file
7
src/linker.messenger.tunnel/stun/enums/Method.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace linker.messenger.tunnel.stun.enums;
|
||||
|
||||
internal enum Method : ushort
|
||||
{
|
||||
Binding = 0b00000_0_000_0_0001,
|
||||
SharedSecret = 0b00000_0_000_0_0010,
|
||||
}
|
65
src/linker.messenger.tunnel/stun/enums/NatType.cs
Normal file
65
src/linker.messenger.tunnel/stun/enums/NatType.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
namespace linker.messenger.tunnel.stun.enums;
|
||||
|
||||
/// <summary>
|
||||
/// https://tools.ietf.org/html/rfc3489#section-5
|
||||
/// https://tools.ietf.org/html/rfc3489#section-10.1
|
||||
/// </summary>
|
||||
public enum NatType
|
||||
{
|
||||
/// <summary>
|
||||
/// Unknown
|
||||
/// </summary>
|
||||
Unknown,
|
||||
|
||||
/// <summary>
|
||||
/// Server is not unsupported for testing NAT type
|
||||
/// </summary>
|
||||
UnsupportedServer,
|
||||
|
||||
/// <summary>
|
||||
/// UDP is always blocked.
|
||||
/// </summary>
|
||||
UdpBlocked,
|
||||
|
||||
/// <summary>
|
||||
/// No NAT, public IP, no firewall.
|
||||
/// </summary>
|
||||
OpenInternet,
|
||||
|
||||
/// <summary>
|
||||
/// No NAT, public IP, but symmetric UDP firewall.
|
||||
/// </summary>
|
||||
SymmetricUdpFirewall,
|
||||
|
||||
/// <summary>
|
||||
/// A full cone NAT is one where all requests from the same internal IP address and port are
|
||||
/// mapped to the same external IP address and port. Furthermore, any external host can send
|
||||
/// a packet to the internal host, by sending a packet to the mapped external address.
|
||||
/// </summary>
|
||||
FullCone,
|
||||
|
||||
/// <summary>
|
||||
/// A restricted cone NAT is one where all requests from the same internal IP address and
|
||||
/// port are mapped to the same external IP address and port. Unlike a full cone NAT, an external
|
||||
/// host (with IP address X) can send a packet to the internal host only if the internal host
|
||||
/// had previously sent a packet to IP address X.
|
||||
/// </summary>
|
||||
RestrictedCone,
|
||||
|
||||
/// <summary>
|
||||
/// A port restricted cone NAT is like a restricted cone NAT, but the restriction
|
||||
/// includes port numbers. Specifically, an external host can send a packet, with source IP
|
||||
/// address X and source port P, to the internal host only if the internal host had previously
|
||||
/// sent a packet to IP address X and port P.
|
||||
/// </summary>
|
||||
PortRestrictedCone,
|
||||
|
||||
/// <summary>
|
||||
/// A symmetric NAT is one where all requests from the same internal IP address and port,
|
||||
/// to a specific destination IP address and port, are mapped to the same external IP address and
|
||||
/// port. If the same host sends a packet with the same source address and port, but to
|
||||
/// a different destination, a different mapping is used. Furthermore, only the external host that
|
||||
/// receives a packet can send a UDP packet back to the internal host.
|
||||
/// </summary>
|
||||
Symmetric
|
||||
}
|
7
src/linker.messenger.tunnel/stun/enums/ProxyType.cs
Normal file
7
src/linker.messenger.tunnel/stun/enums/ProxyType.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace linker.messenger.tunnel.stun.enums;
|
||||
|
||||
public enum ProxyType
|
||||
{
|
||||
Plain = 0,
|
||||
Socks5 = 1
|
||||
}
|
40
src/linker.messenger.tunnel/stun/enums/StunMessageType.cs
Normal file
40
src/linker.messenger.tunnel/stun/enums/StunMessageType.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
namespace linker.messenger.tunnel.stun.enums;
|
||||
|
||||
/// <summary>
|
||||
/// This enum specifies STUN message type.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// https://tools.ietf.org/html/rfc5389#section-6
|
||||
/// </returns>
|
||||
public enum StunMessageType : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// STUN message is binding request.
|
||||
/// </summary>
|
||||
BindingRequest = Class.Request | Method.Binding,
|
||||
|
||||
/// <summary>
|
||||
/// STUN message is binding request success response.
|
||||
/// </summary>
|
||||
BindingResponse = Class.SuccessResponse | Method.Binding,
|
||||
|
||||
/// <summary>
|
||||
/// STUN message is binding request error response.
|
||||
/// </summary>
|
||||
BindingErrorResponse = Class.ErrorResponse | Method.Binding,
|
||||
|
||||
/// <summary>
|
||||
/// STUN message is "shared secret" request.
|
||||
/// </summary>
|
||||
SharedSecretRequest = Class.Request | Method.SharedSecret,
|
||||
|
||||
/// <summary>
|
||||
/// STUN message is "shared secret" request success response.
|
||||
/// </summary>
|
||||
SharedSecretResponse = Class.SuccessResponse | Method.SharedSecret,
|
||||
|
||||
/// <summary>
|
||||
/// STUN message is "shared secret" request error response.
|
||||
/// </summary>
|
||||
SharedSecretErrorResponse = Class.ErrorResponse | Method.SharedSecret,
|
||||
}
|
9
src/linker.messenger.tunnel/stun/enums/TransportType.cs
Normal file
9
src/linker.messenger.tunnel/stun/enums/TransportType.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace linker.messenger.tunnel.stun.enums;
|
||||
|
||||
public enum TransportType
|
||||
{
|
||||
Udp,
|
||||
Tcp,
|
||||
Tls,
|
||||
Dtls,
|
||||
}
|
@@ -0,0 +1,74 @@
|
||||
using linker.messenger.tunnel.stun.enums;
|
||||
using System.Buffers.Binary;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace linker.messenger.tunnel.stun.messages;
|
||||
|
||||
/// <summary>
|
||||
/// https://tools.ietf.org/html/rfc5389#section-15.1
|
||||
/// </summary>
|
||||
public abstract class AddressStunAttributeValue : IStunAttributeValue
|
||||
{
|
||||
public IpFamily Family { get; set; }
|
||||
|
||||
public ushort Port { get; set; }
|
||||
|
||||
public IPAddress Address { get; set; }
|
||||
|
||||
public virtual int WriteTo(Span<byte> buffer)
|
||||
{
|
||||
buffer[0] = 0;
|
||||
buffer[1] = (byte)Family;
|
||||
BinaryPrimitives.WriteUInt16BigEndian(buffer[2..], Port);
|
||||
Address.TryWriteBytes(buffer[4..], out int bytesWritten);
|
||||
|
||||
|
||||
return 4 + bytesWritten;
|
||||
}
|
||||
|
||||
public virtual bool TryParse(ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
int length = 4;
|
||||
|
||||
if (buffer.Length < length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Family = (IpFamily)buffer[1];
|
||||
|
||||
switch (Family)
|
||||
{
|
||||
case IpFamily.IPv4:
|
||||
length += 4;
|
||||
break;
|
||||
case IpFamily.IPv6:
|
||||
length += 16;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buffer.Length != length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Port = BinaryPrimitives.ReadUInt16BigEndian(buffer[2..]);
|
||||
|
||||
Address = new IPAddress(buffer[4..]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override string? ToString()
|
||||
{
|
||||
return Address?.AddressFamily switch
|
||||
{
|
||||
AddressFamily.InterNetwork => $@"{Address}:{Port}",
|
||||
AddressFamily.InterNetworkV6 => $@"[{Address}]:{Port}",
|
||||
_ => base.ToString()
|
||||
};
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
using Microsoft;
|
||||
|
||||
namespace linker.messenger.tunnel.stun.messages;
|
||||
|
||||
/// <summary>
|
||||
/// https://tools.ietf.org/html/rfc5780#section-7.2
|
||||
/// </summary>
|
||||
public class ChangeRequestStunAttributeValue : IStunAttributeValue
|
||||
{
|
||||
public bool ChangeIp { get; set; }
|
||||
|
||||
public bool ChangePort { get; set; }
|
||||
|
||||
public int WriteTo(Span<byte> buffer)
|
||||
{
|
||||
buffer[0] = buffer[1] = buffer[2] = 0;
|
||||
|
||||
buffer[3] = (byte)(Convert.ToInt32(ChangeIp) << 2 | Convert.ToInt32(ChangePort) << 1);
|
||||
|
||||
return 4;
|
||||
}
|
||||
|
||||
public bool TryParse(ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
if (buffer.Length != 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ChangeIp = Convert.ToBoolean(buffer[3] >> 2 & 1);
|
||||
ChangePort = Convert.ToBoolean(buffer[3] >> 1 & 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -0,0 +1,6 @@
|
||||
namespace linker.messenger.tunnel.stun.messages;
|
||||
|
||||
/// <summary>
|
||||
/// https://tools.ietf.org/html/rfc3489#section-11.2.3
|
||||
/// </summary>
|
||||
public class ChangedAddressStunAttributeValue : AddressStunAttributeValue;
|
@@ -0,0 +1,45 @@
|
||||
using System.Text;
|
||||
|
||||
namespace linker.messenger.tunnel.stun.messages;
|
||||
|
||||
/// <summary>
|
||||
/// https://tools.ietf.org/html/rfc5389#section-15.6
|
||||
/// </summary>
|
||||
public class ErrorCodeStunAttributeValue : IStunAttributeValue
|
||||
{
|
||||
public ushort ErrorCode { get; set; }
|
||||
public string ReasonPhrase { get; set; } = string.Empty;
|
||||
|
||||
public byte Class => (byte)(ErrorCode % 1000 / 100);
|
||||
public byte Number => (byte)(ErrorCode % 100);
|
||||
|
||||
public const int MaxReasonPhraseBytesLength = 762;
|
||||
|
||||
public int WriteTo(Span<byte> buffer)
|
||||
{
|
||||
buffer[0] = buffer[1] = 0;
|
||||
buffer[2] = Class;
|
||||
buffer[3] = Number;
|
||||
|
||||
int length = Encoding.UTF8.GetBytes(ReasonPhrase, buffer[4..]);
|
||||
|
||||
return 4 + Math.Min(length, MaxReasonPhraseBytesLength);
|
||||
}
|
||||
|
||||
public bool TryParse(ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
if (buffer.Length is < 4 or > (4 + MaxReasonPhraseBytesLength))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
byte @class = (byte)(buffer[2] & 0b111);
|
||||
ushort number = Math.Min(buffer[3], (ushort)99);
|
||||
|
||||
ErrorCode = (ushort)(@class * 100 + number);
|
||||
|
||||
ReasonPhrase = Encoding.UTF8.GetString(buffer[4..]);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
namespace linker.messenger.tunnel.stun.messages;
|
||||
|
||||
public interface IStunAttributeValue
|
||||
{
|
||||
int WriteTo(Span<byte> buffer);
|
||||
|
||||
bool TryParse(ReadOnlySpan<byte> buffer);
|
||||
}
|
@@ -0,0 +1,6 @@
|
||||
namespace linker.messenger.tunnel.stun.messages;
|
||||
|
||||
/// <summary>
|
||||
/// https://tools.ietf.org/html/rfc5389#section-15.1
|
||||
/// </summary>
|
||||
public class MappedAddressStunAttributeValue : AddressStunAttributeValue;
|
@@ -0,0 +1,6 @@
|
||||
namespace linker.messenger.tunnel.stun.messages;
|
||||
|
||||
/// <summary>
|
||||
/// https://tools.ietf.org/html/rfc5780#section-7.4
|
||||
/// </summary>
|
||||
public class OtherAddressStunAttributeValue : AddressStunAttributeValue;
|
@@ -0,0 +1,6 @@
|
||||
namespace linker.messenger.tunnel.stun.messages;
|
||||
|
||||
/// <summary>
|
||||
/// https://tools.ietf.org/html/rfc3489#section-11.2.11
|
||||
/// </summary>
|
||||
public class ReflectedFromStunAttributeValue : AddressStunAttributeValue;
|
@@ -0,0 +1,6 @@
|
||||
namespace linker.messenger.tunnel.stun.messages;
|
||||
|
||||
/// <summary>
|
||||
/// https://tools.ietf.org/html/rfc3489#section-11.2.2
|
||||
/// </summary>
|
||||
public class ResponseAddressStunAttributeValue : AddressStunAttributeValue;
|
@@ -0,0 +1,6 @@
|
||||
namespace linker.messenger.tunnel.stun.messages;
|
||||
|
||||
/// <summary>
|
||||
/// https://tools.ietf.org/html/rfc3489#section-11.2.5
|
||||
/// </summary>
|
||||
public class SourceAddressStunAttributeValue : AddressStunAttributeValue;
|
89
src/linker.messenger.tunnel/stun/messages/StunAttribute.cs
Normal file
89
src/linker.messenger.tunnel/stun/messages/StunAttribute.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using linker.messenger.tunnel.stun.enums;
|
||||
using System.Buffers.Binary;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace linker.messenger.tunnel.stun.messages;
|
||||
|
||||
/// <summary>
|
||||
/// https://tools.ietf.org/html/rfc5389#section-15
|
||||
/// </summary>
|
||||
public class StunAttribute
|
||||
{
|
||||
/*
|
||||
Length 是大端
|
||||
必须4字节对齐
|
||||
对齐的字节可以是任意值
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type | Length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Value (variable) ....
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
|
||||
public AttributeType Type { get; set; } = AttributeType.Useless;
|
||||
|
||||
public ushort Length { get; set; }
|
||||
|
||||
public ushort RealLength => (ushort)(Type == AttributeType.Useless ? 0 : 4 + Length + (4 - Length % 4) % 4);
|
||||
|
||||
public IStunAttributeValue Value { get; set; } = new UselessStunAttributeValue();
|
||||
|
||||
public int WriteTo(Span<byte> buffer)
|
||||
{
|
||||
int length = 4 + Length;
|
||||
int n = (4 - length % 4) % 4; // 填充的字节数
|
||||
int totalLength = length + n;
|
||||
|
||||
BinaryPrimitives.WriteUInt16BigEndian(buffer, (ushort)Type);
|
||||
BinaryPrimitives.WriteUInt16BigEndian(buffer[2..], Length);
|
||||
int valueLength = Value.WriteTo(buffer[4..]);
|
||||
|
||||
RandomNumberGenerator.Fill(buffer.Slice(length, n));
|
||||
|
||||
return totalLength;
|
||||
}
|
||||
|
||||
/// <returns>
|
||||
/// Parse 成功字节,0 则表示 Parse 失败
|
||||
/// </returns>
|
||||
public int TryParse(ReadOnlySpan<byte> buffer, ReadOnlySpan<byte> magicCookieAndTransactionId)
|
||||
{
|
||||
if (buffer.Length < 4)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
Type = (AttributeType)BinaryPrimitives.ReadUInt16BigEndian(buffer);
|
||||
|
||||
Length = BinaryPrimitives.ReadUInt16BigEndian(buffer[2..]);
|
||||
|
||||
if (buffer.Length < 4 + Length)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
ReadOnlySpan<byte> value = buffer.Slice(4, Length);
|
||||
|
||||
IStunAttributeValue t = Type switch
|
||||
{
|
||||
AttributeType.MappedAddress => new MappedAddressStunAttributeValue(),
|
||||
AttributeType.XorMappedAddress => new XorMappedAddressStunAttributeValue(magicCookieAndTransactionId),
|
||||
AttributeType.ResponseAddress => new ResponseAddressStunAttributeValue(),
|
||||
AttributeType.ChangeRequest => new ChangeRequestStunAttributeValue(),
|
||||
AttributeType.SourceAddress => new SourceAddressStunAttributeValue(),
|
||||
AttributeType.ChangedAddress => new ChangedAddressStunAttributeValue(),
|
||||
AttributeType.OtherAddress => new OtherAddressStunAttributeValue(),
|
||||
AttributeType.ReflectedFrom => new ReflectedFromStunAttributeValue(),
|
||||
AttributeType.ErrorCode => new ErrorCodeStunAttributeValue(),
|
||||
_ => new UselessStunAttributeValue()
|
||||
};
|
||||
if (t.TryParse(value))
|
||||
{
|
||||
Value = t;
|
||||
}
|
||||
|
||||
return 4 + Length + (4 - Length % 4) % 4; // 对齐
|
||||
}
|
||||
}
|
156
src/linker.messenger.tunnel/stun/messages/StunMessage5389.cs
Normal file
156
src/linker.messenger.tunnel/stun/messages/StunMessage5389.cs
Normal file
@@ -0,0 +1,156 @@
|
||||
using linker.messenger.tunnel.stun.enums;
|
||||
using System.Buffers;
|
||||
using System.Buffers.Binary;
|
||||
using System.Diagnostics;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace linker.messenger.tunnel.stun.messages;
|
||||
|
||||
/// <summary>
|
||||
/// https://tools.ietf.org/html/rfc5389#section-6
|
||||
/// </summary>
|
||||
public class StunMessage5389
|
||||
{
|
||||
#region Header
|
||||
|
||||
private const int SizeOfMessageType = sizeof(StunMessageType);
|
||||
private const int SizeOfLength = sizeof(ushort);
|
||||
private const int SizeOfMagicCookie = sizeof(uint);
|
||||
private const int SizeOfTransactionId = 12;
|
||||
public const int HeaderLength = SizeOfMessageType + SizeOfLength + SizeOfMagicCookie + SizeOfTransactionId;
|
||||
|
||||
public StunMessageType StunMessageType { get; set; }
|
||||
|
||||
public uint MagicCookie { get; set; }
|
||||
|
||||
public byte[] TransactionId { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
public IEnumerable<StunAttribute> Attributes { get; set; }
|
||||
|
||||
public ushort MessageLength => (ushort)Attributes.Sum(x => x.RealLength);
|
||||
public int Length => HeaderLength + MessageLength;
|
||||
|
||||
public StunMessage5389()
|
||||
{
|
||||
Attributes = Array.Empty<StunAttribute>();
|
||||
StunMessageType = StunMessageType.BindingRequest;
|
||||
MagicCookie = 0x2112A442;
|
||||
TransactionId = new byte[SizeOfTransactionId];
|
||||
RandomNumberGenerator.Fill(TransactionId);
|
||||
}
|
||||
|
||||
public int WriteTo(Span<byte> buffer)
|
||||
{
|
||||
ushort messageLength = MessageLength;
|
||||
int length = Length;
|
||||
|
||||
BinaryPrimitives.WriteUInt16BigEndian(buffer, (ushort)StunMessageType);
|
||||
BinaryPrimitives.WriteUInt16BigEndian(buffer[SizeOfMessageType..], messageLength);
|
||||
BinaryPrimitives.WriteUInt32BigEndian(buffer[(SizeOfMessageType + SizeOfLength)..], MagicCookie);
|
||||
TransactionId.CopyTo(buffer[(SizeOfMessageType + SizeOfLength + SizeOfMagicCookie)..]);
|
||||
|
||||
buffer = buffer[HeaderLength..];
|
||||
foreach (StunAttribute attribute in Attributes)
|
||||
{
|
||||
int outLength = attribute.WriteTo(buffer);
|
||||
buffer = buffer[outLength..];
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
public bool TryParse(ReadOnlyMemory<byte> buffer)
|
||||
{
|
||||
ReadOnlySequence<byte> sequence = new(buffer);
|
||||
return TryParse(ref sequence);
|
||||
}
|
||||
|
||||
public bool TryParse(ref ReadOnlySequence<byte> sequence)
|
||||
{
|
||||
if (sequence.Length < HeaderLength)
|
||||
{
|
||||
return false; // Check length
|
||||
}
|
||||
|
||||
SequenceReader<byte> reader = new(sequence);
|
||||
|
||||
if (!reader.TryReadBigEndian(out short typeValue))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
StunMessageType type = (StunMessageType)(ushort)(typeValue & 0b0011_1111_1111_1111);
|
||||
|
||||
if (!Enum.IsDefined(type))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
StunMessageType = type;
|
||||
|
||||
if (!reader.TryReadBigEndian(out short lengthValue))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ushort length = (ushort)lengthValue;
|
||||
|
||||
if (sequence.Length - HeaderLength < length)
|
||||
{
|
||||
return false; // Check length
|
||||
}
|
||||
|
||||
if (!reader.TryReadBigEndian(out int magicCookie))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
MagicCookie = (uint)magicCookie;
|
||||
|
||||
reader.UnreadSequence.Slice(0, SizeOfTransactionId).CopyTo(TransactionId);
|
||||
reader.Advance(SizeOfTransactionId);
|
||||
|
||||
byte[] tempBuffer = ArrayPool<byte>.Shared.Rent(length + SizeOfMagicCookie + SizeOfTransactionId);
|
||||
try
|
||||
{
|
||||
reader.UnreadSequence.Slice(0, length).CopyTo(tempBuffer);
|
||||
reader.Advance(length);
|
||||
sequence.Slice(SizeOfMessageType + SizeOfLength, SizeOfMagicCookie + SizeOfTransactionId).CopyTo(tempBuffer.AsSpan(length));
|
||||
|
||||
List<StunAttribute> list = new();
|
||||
|
||||
Span<byte> attributeBuffer = tempBuffer.AsSpan(0, length);
|
||||
ReadOnlySpan<byte> magicCookieAndTransactionId = tempBuffer.AsSpan(length, SizeOfMagicCookie + SizeOfTransactionId);
|
||||
|
||||
while (attributeBuffer.Length > default(int))
|
||||
{
|
||||
StunAttribute attribute = new();
|
||||
int offset = attribute.TryParse(attributeBuffer, magicCookieAndTransactionId);
|
||||
if (offset <= default(int))
|
||||
{
|
||||
Debug.WriteLine($@"[Warning] Ignore wrong attribute: {Convert.ToHexString(attributeBuffer)}");
|
||||
break;
|
||||
}
|
||||
|
||||
list.Add(attribute);
|
||||
attributeBuffer = attributeBuffer[offset..];
|
||||
}
|
||||
|
||||
Attributes = list;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(tempBuffer);
|
||||
}
|
||||
|
||||
sequence = reader.UnreadSequence;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsSameTransaction(StunMessage5389 other)
|
||||
{
|
||||
return MagicCookie == other.MagicCookie && TransactionId.AsSpan().SequenceEqual(other.TransactionId);
|
||||
}
|
||||
}
|
10
src/linker.messenger.tunnel/stun/messages/StunResponse.cs
Normal file
10
src/linker.messenger.tunnel/stun/messages/StunResponse.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.Net;
|
||||
|
||||
namespace linker.messenger.tunnel.stun.messages;
|
||||
|
||||
public record StunResponse(StunMessage5389 Message, IPEndPoint Remote, IPEndPoint Local)
|
||||
{
|
||||
public StunMessage5389 Message { get; set; } = Message;
|
||||
public IPEndPoint Remote { get; set; } = Remote;
|
||||
public IPEndPoint Local { get; set; } = Local;
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
using linker.messenger.tunnel.stun.enums;
|
||||
using System.Buffers.Binary;
|
||||
|
||||
namespace linker.messenger.tunnel.stun.messages;
|
||||
|
||||
/// <summary>
|
||||
/// https://tools.ietf.org/html/rfc5389#section-15.9
|
||||
/// </summary>
|
||||
public class UnknownStunAttributeValue : IStunAttributeValue
|
||||
{
|
||||
public List<AttributeType> Types { get; } = new();
|
||||
|
||||
public int WriteTo(Span<byte> buffer)
|
||||
{
|
||||
int size = Types.Count << 1;
|
||||
|
||||
foreach (AttributeType attributeType in Types)
|
||||
{
|
||||
BinaryPrimitives.WriteUInt16BigEndian(buffer, (ushort)attributeType);
|
||||
buffer = buffer[sizeof(ushort)..];
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
public bool TryParse(ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
if (buffer.Length < 2 || (buffer.Length & 1) == 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Types.Clear();
|
||||
while (!buffer.IsEmpty)
|
||||
{
|
||||
ushort type = BinaryPrimitives.ReadUInt16BigEndian(buffer);
|
||||
Types.Add((AttributeType)type);
|
||||
buffer = buffer[sizeof(ushort)..];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
namespace linker.messenger.tunnel.stun.messages;
|
||||
|
||||
/// <summary>
|
||||
/// 无法理解的属性
|
||||
/// </summary>
|
||||
public class UselessStunAttributeValue : IStunAttributeValue
|
||||
{
|
||||
public int WriteTo(Span<byte> buffer)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public bool TryParse(ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -0,0 +1,65 @@
|
||||
using Microsoft;
|
||||
using System.Buffers.Binary;
|
||||
using System.Net;
|
||||
|
||||
namespace linker.messenger.tunnel.stun.messages;
|
||||
|
||||
/// <summary>
|
||||
/// https://tools.ietf.org/html/rfc5389#section-15.2
|
||||
/// </summary>
|
||||
public class XorMappedAddressStunAttributeValue : AddressStunAttributeValue
|
||||
{
|
||||
private readonly byte[] _magicCookieAndTransactionId;
|
||||
|
||||
public XorMappedAddressStunAttributeValue(ReadOnlySpan<byte> magicCookieAndTransactionId)
|
||||
{
|
||||
_magicCookieAndTransactionId = magicCookieAndTransactionId.ToArray();
|
||||
}
|
||||
|
||||
public override int WriteTo(Span<byte> buffer)
|
||||
{
|
||||
buffer[0] = 0;
|
||||
buffer[1] = (byte)Family;
|
||||
BinaryPrimitives.WriteUInt16BigEndian(buffer[2..], Xor(Port));
|
||||
Xor(Address).TryWriteBytes(buffer[4..], out int bytesWritten);
|
||||
|
||||
return 4 + bytesWritten;
|
||||
}
|
||||
|
||||
public override bool TryParse(ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
if (!base.TryParse(buffer))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Port = Xor(Port);
|
||||
|
||||
Address = Xor(Address);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private ushort Xor(ushort port)
|
||||
{
|
||||
Span<byte> span = stackalloc byte[2];
|
||||
BinaryPrimitives.WriteUInt16BigEndian(span, port);
|
||||
span[0] ^= _magicCookieAndTransactionId[0];
|
||||
span[1] ^= _magicCookieAndTransactionId[1];
|
||||
return BinaryPrimitives.ReadUInt16BigEndian(span);
|
||||
}
|
||||
|
||||
private IPAddress Xor(IPAddress address)
|
||||
{
|
||||
Span<byte> b = stackalloc byte[16];
|
||||
address.TryWriteBytes(b, out int bytesWritten);
|
||||
|
||||
|
||||
for (int i = 0; i < bytesWritten; ++i)
|
||||
{
|
||||
b[i] ^= _magicCookieAndTransactionId[i];
|
||||
}
|
||||
|
||||
return new IPAddress(b[..bytesWritten]);
|
||||
}
|
||||
}
|
13
src/linker.messenger.tunnel/stun/proxy/IUdpProxy.cs
Normal file
13
src/linker.messenger.tunnel/stun/proxy/IUdpProxy.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace linker.messenger.tunnel.stun.proxy;
|
||||
|
||||
public interface IUdpProxy : IDisposable
|
||||
{
|
||||
Socket Client { get; }
|
||||
ValueTask ConnectAsync(CancellationToken cancellationToken = default);
|
||||
ValueTask CloseAsync(CancellationToken cancellationToken = default);
|
||||
ValueTask<SocketReceiveMessageFromResult> ReceiveMessageFromAsync(Memory<byte> buffer, SocketFlags socketFlags, EndPoint remoteEndPoint, CancellationToken cancellationToken = default);
|
||||
ValueTask<int> SendToAsync(ReadOnlyMemory<byte> buffer, SocketFlags socketFlags, EndPoint remoteEP, CancellationToken cancellationToken = default);
|
||||
}
|
41
src/linker.messenger.tunnel/stun/proxy/NoneUdpProxy.cs
Normal file
41
src/linker.messenger.tunnel/stun/proxy/NoneUdpProxy.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace linker.messenger.tunnel.stun.proxy;
|
||||
|
||||
public class NoneUdpProxy : IUdpProxy
|
||||
{
|
||||
public Socket Client { get; }
|
||||
|
||||
public NoneUdpProxy(IPEndPoint localEndPoint)
|
||||
{
|
||||
Client = new Socket(localEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
|
||||
Client.Bind(localEndPoint);
|
||||
}
|
||||
|
||||
public ValueTask ConnectAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
public ValueTask CloseAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
public ValueTask<SocketReceiveMessageFromResult> ReceiveMessageFromAsync(Memory<byte> buffer, SocketFlags socketFlags, EndPoint remoteEndPoint, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Client.ReceiveMessageFromAsync(buffer, socketFlags, remoteEndPoint, cancellationToken);
|
||||
}
|
||||
|
||||
public ValueTask<int> SendToAsync(ReadOnlyMemory<byte> buffer, SocketFlags socketFlags, EndPoint remoteEP, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Client.SendToAsync(buffer, socketFlags, remoteEP, cancellationToken);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Client.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
using linker.messenger.tunnel.stun.enums;
|
||||
|
||||
namespace linker.messenger.tunnel.stun.result;
|
||||
|
||||
public record ClassicStunResult : StunResult
|
||||
{
|
||||
public NatType NatType { get; set; } = NatType.Unknown;
|
||||
}
|
9
src/linker.messenger.tunnel/stun/result/StunResult.cs
Normal file
9
src/linker.messenger.tunnel/stun/result/StunResult.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System.Net;
|
||||
|
||||
namespace linker.messenger.tunnel.stun.result;
|
||||
|
||||
public abstract record StunResult
|
||||
{
|
||||
public IPEndPoint PublicEndPoint { get; set; }
|
||||
public IPEndPoint LocalEndPoint { get; set; }
|
||||
}
|
15
src/linker.messenger.tunnel/stun/result/StunResult5389.cs
Normal file
15
src/linker.messenger.tunnel/stun/result/StunResult5389.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using linker.messenger.tunnel.stun.enums;
|
||||
using System.Net;
|
||||
|
||||
namespace linker.messenger.tunnel.stun.result;
|
||||
|
||||
public record StunResult5389 : StunResult
|
||||
{
|
||||
public IPEndPoint?OtherEndPoint { get; set; }
|
||||
|
||||
public BindingTestResult BindingTestResult { get; set; } = BindingTestResult.Unknown;
|
||||
|
||||
public MappingBehavior MappingBehavior { get; set; } = MappingBehavior.Unknown;
|
||||
|
||||
public FilteringBehavior FilteringBehavior { get; set; } = FilteringBehavior.Unknown;
|
||||
}
|
116
src/linker.messenger.tunnel/stun/utils/AttributeExtensions.cs
Normal file
116
src/linker.messenger.tunnel/stun/utils/AttributeExtensions.cs
Normal file
@@ -0,0 +1,116 @@
|
||||
using linker.messenger.tunnel.stun.enums;
|
||||
using linker.messenger.tunnel.stun.messages;
|
||||
using System.Net;
|
||||
|
||||
namespace linker.messenger.tunnel.stun.utils;
|
||||
|
||||
public static class AttributeExtensions
|
||||
{
|
||||
public static StunAttribute BuildChangeRequest(bool changeIp, bool changePort)
|
||||
{
|
||||
return new StunAttribute
|
||||
{
|
||||
Type = AttributeType.ChangeRequest,
|
||||
Length = 4,
|
||||
Value = new ChangeRequestStunAttributeValue { ChangeIp = changeIp, ChangePort = changePort }
|
||||
};
|
||||
}
|
||||
|
||||
public static StunAttribute BuildMapping(IpFamily family, IPAddress ip, ushort port)
|
||||
{
|
||||
int length = family switch
|
||||
{
|
||||
IpFamily.IPv4 => 4,
|
||||
IpFamily.IPv6 => 16,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(family), family, null)
|
||||
};
|
||||
return new StunAttribute
|
||||
{
|
||||
Type = AttributeType.MappedAddress,
|
||||
Length = (ushort)(4 + length),
|
||||
Value = new MappedAddressStunAttributeValue
|
||||
{
|
||||
Family = family,
|
||||
Address = ip,
|
||||
Port = port
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static StunAttribute BuildChangeAddress(IpFamily family, IPAddress ip, ushort port)
|
||||
{
|
||||
int length = family switch
|
||||
{
|
||||
IpFamily.IPv4 => 4,
|
||||
IpFamily.IPv6 => 16,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(family), family, null)
|
||||
};
|
||||
return new StunAttribute
|
||||
{
|
||||
Type = AttributeType.ChangedAddress,
|
||||
Length = (ushort)(4 + length),
|
||||
Value = new ChangedAddressStunAttributeValue
|
||||
{
|
||||
Family = family,
|
||||
Address = ip,
|
||||
Port = port
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static IPEndPoint GetMappedAddressAttribute(this StunMessage5389 response)
|
||||
{
|
||||
StunAttribute mappedAddressAttribute = response.Attributes.FirstOrDefault(t => t.Type == AttributeType.MappedAddress);
|
||||
|
||||
if (mappedAddressAttribute is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
MappedAddressStunAttributeValue mapped = (MappedAddressStunAttributeValue)mappedAddressAttribute.Value;
|
||||
return new IPEndPoint(mapped.Address!, mapped.Port);
|
||||
}
|
||||
|
||||
public static IPEndPoint GetChangedAddressAttribute(this StunMessage5389 response)
|
||||
{
|
||||
StunAttribute changedAddressAttribute = response.Attributes.FirstOrDefault(t => t.Type == AttributeType.ChangedAddress);
|
||||
|
||||
if (changedAddressAttribute is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ChangedAddressStunAttributeValue address = (ChangedAddressStunAttributeValue)changedAddressAttribute.Value;
|
||||
return new IPEndPoint(address.Address!, address.Port);
|
||||
}
|
||||
|
||||
public static IPEndPoint GetXorMappedAddressAttribute(this StunMessage5389 response)
|
||||
{
|
||||
StunAttribute mappedAddressAttribute =
|
||||
response.Attributes.FirstOrDefault(t => t.Type == AttributeType.XorMappedAddress) ??
|
||||
response.Attributes.FirstOrDefault(t => t.Type == AttributeType.MappedAddress);
|
||||
|
||||
if (mappedAddressAttribute is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
AddressStunAttributeValue mapped = (AddressStunAttributeValue)mappedAddressAttribute.Value;
|
||||
return new IPEndPoint(mapped.Address!, mapped.Port);
|
||||
}
|
||||
|
||||
public static IPEndPoint GetOtherAddressAttribute(this StunMessage5389 response)
|
||||
{
|
||||
StunAttribute? addressAttribute =
|
||||
response.Attributes.FirstOrDefault(t => t.Type == AttributeType.OtherAddress) ??
|
||||
response.Attributes.FirstOrDefault(t => t.Type == AttributeType.ChangedAddress);
|
||||
|
||||
if (addressAttribute is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
AddressStunAttributeValue address = (AddressStunAttributeValue)addressAttribute.Value;
|
||||
return new IPEndPoint(address.Address!, address.Port);
|
||||
}
|
||||
}
|
@@ -16,9 +16,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger tuntap</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -16,9 +16,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger updater</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -75,7 +75,7 @@ namespace linker.messenger
|
||||
if (res == false)
|
||||
{
|
||||
sends.TryRemove(msg.RequestId, out _);
|
||||
tcs.SetResult(new MessageResponeInfo { Code = MessageResponeCodes.NOT_CONNECT });
|
||||
tcs.TrySetResult(new MessageResponeInfo { Code = MessageResponeCodes.NOT_CONNECT });
|
||||
}
|
||||
|
||||
try
|
||||
@@ -84,6 +84,7 @@ namespace linker.messenger
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
tcs.TrySetResult(new MessageResponeInfo { Code = MessageResponeCodes.NOT_CONNECT });
|
||||
sends.TryRemove(msg.RequestId, out _);
|
||||
return new MessageResponeInfo { Code = MessageResponeCodes.TIMEOUT };
|
||||
}
|
||||
@@ -153,7 +154,7 @@ namespace linker.messenger
|
||||
wrap.Payload.CopyTo(bytes);
|
||||
|
||||
AddReceive(info.MessengerId, bytes.Length);
|
||||
info.Tcs.SetResult(new MessageResponeInfo { Code = wrap.Code, Data = bytes, Connection = wrap.Connection });
|
||||
info.Tcs.TrySetResult(new MessageResponeInfo { Code = wrap.Code, Data = bytes, Connection = wrap.Connection });
|
||||
return info.MessengerId;
|
||||
}
|
||||
return 0;
|
||||
|
@@ -16,9 +16,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker messenger</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -16,9 +16,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker snat</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<project ver="10" name="linker.tray.win" libEmbed="true" icon="..\linker\favicon.ico" ui="win" output="linker.tray.win.exe" CompanyName="snltty" FileDescription="linker.tray.win" LegalCopyright="Copyright (C) snltty 2024" ProductName="linker.tray.win" InternalName="linker.install.win" FileVersion="0.0.0.271" ProductVersion="0.0.0.271" publishDir="/dist/" dstrip="false" local="false" ignored="false">
|
||||
<project ver="10" name="linker.tray.win" libEmbed="true" icon="..\linker\favicon.ico" ui="win" output="linker.tray.win.exe" CompanyName="snltty" FileDescription="linker.tray.win" LegalCopyright="Copyright (C) snltty 2024" ProductName="linker.tray.win" InternalName="linker.install.win" FileVersion="0.0.0.272" ProductVersion="0.0.0.272" publishDir="/dist/" dstrip="false" local="false" ignored="false">
|
||||
<file name="main.aardio" path="main.aardio" comment="main.aardio"/>
|
||||
<folder name="资源文件" path="res" embed="true" local="false" ignored="false">
|
||||
<file name="favicon.ico" path="res\favicon.ico" comment="res\favicon.ico"/>
|
||||
|
BIN
src/linker.tray.win/dist/linker.tray.win.exe
vendored
BIN
src/linker.tray.win/dist/linker.tray.win.exe
vendored
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>linker.web</title><link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/><script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script><script defer="defer" src="js/chunk-vendors.59893432.js"></script><script defer="defer" src="js/app.a10400b4.js"></script><link href="css/chunk-vendors.d8267b33.css" rel="stylesheet"><link href="css/app.5b1ae1f9.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but linker.web doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
||||
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>linker.web</title><link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/><script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script><script defer="defer" src="js/chunk-vendors.59893432.js"></script><script defer="defer" src="js/app.51805d8f.js"></script><link href="css/chunk-vendors.d8267b33.css" rel="stylesheet"><link href="css/app.5b1ae1f9.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but linker.web doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
@@ -1 +1 @@
|
||||
"use strict";(self["webpackChunklinker_web"]=self["webpackChunklinker_web"]||[]).push([[373],{7332:function(e,n,a){a.r(n),a.d(n,{default:function(){return O}});var t=a(6768);const s={class:"net-wrap app-wrap"},l={class:"inner absolute flex flex-column flex-nowrap"},i={class:"head"},o={class:"body flex-1 relative"},c={class:"status"};function r(e,n,a,r,u,d){const g=(0,t.g2)("Head"),p=(0,t.g2)("List"),v=(0,t.g2)("Status");return(0,t.uX)(),(0,t.CE)("div",s,[(0,t.Lk)("div",l,[(0,t.Lk)("div",i,[(0,t.bF)(g)]),(0,t.Lk)("div",o,[(0,t.bF)(p)]),(0,t.Lk)("div",c,[(0,t.bF)(v,{config:!1})])])])}a(4114);var u=a(4232);const d=e=>((0,t.Qi)("data-v-6bfe19a3"),e=e(),(0,t.jt)(),e),g={class:"head-wrap"},p={class:"tools flex"},v={class:"label"},h=d((()=>(0,t.Lk)("span",{class:"flex-1"},null,-1))),f={style:{"margin-left":"1rem"}};function k(e,n,a,s,l,i){const o=(0,t.g2)("Refresh"),c=(0,t.g2)("el-icon"),r=(0,t.g2)("el-button"),d=(0,t.g2)("Background");return(0,t.uX)(),(0,t.CE)("div",g,[(0,t.Lk)("div",p,[(0,t.Lk)("span",v,"分组 : "+(0,u.v_)(s.state.group),1),h,(0,t.bF)(r,{size:"small",onClick:s.handleRefresh},{default:(0,t.k6)((()=>[(0,t.eW)(" 刷新(F5)"),(0,t.bF)(c,null,{default:(0,t.k6)((()=>[(0,t.bF)(o)])),_:1})])),_:1},8,["onClick"]),(0,t.Lk)("div",f,[(0,t.bF)(d,{name:"net"})])])])}var C=a(3830),m=a(144),b=a(7477),L=a(5096),_={components:{Edit:b.ffu,Refresh:b.C42,Background:L.A},setup(){const e=(0,C.B)(),n=(0,m.Kh)({server:(0,t.EW)((()=>e.value.config.Client.Server.Host)),group:(0,t.EW)((()=>e.value.config.Client.Group.Name))}),a=()=>{window.location.reload()};return{state:n,handleRefresh:a}}},w=a(1241);const S=(0,w.A)(_,[["render",k],["__scopeId","data-v-6bfe19a3"]]);var F=S;const x=e=>((0,t.Qi)("data-v-68d1c30a"),e=e(),(0,t.jt)(),e),T={class:"net-list-wrap flex flex-column absolute"},z={class:"flex-1 scrollbar"},E={class:"flex"},A=x((()=>(0,t.Lk)("div",{class:"flex-1"},null,-1))),I={class:"tuntap"},P={class:"page t-c"},B={class:"page-wrap t-c"};function R(e,n,a,s,l,i){const o=(0,t.g2)("DeviceName"),c=(0,t.g2)("UpdaterBtn"),r=(0,t.g2)("TuntapShow"),u=(0,t.g2)("el-pagination");return(0,t.uX)(),(0,t.CE)("div",T,[(0,t.Lk)("div",z,[(0,t.Lk)("ul",null,[((0,t.uX)(!0),(0,t.CE)(t.FK,null,(0,t.pI)(s.devices.page.List,((e,n)=>((0,t.uX)(),(0,t.CE)("li",{key:n},[(0,t.Lk)("dl",null,[(0,t.Lk)("dt",E,[(0,t.Lk)("div",null,[(0,t.bF)(o,{item:e},null,8,["item"])]),A,(0,t.Lk)("div",null,[(0,t.bF)(c,{config:!1,item:e},null,8,["item"])])]),(0,t.Lk)("dd",I,[s.tuntap.list[e.MachineId]?((0,t.uX)(),(0,t.Wv)(r,{key:0,item:e},null,8,["item"])):(0,t.Q3)("",!0)])])])))),128))])]),(0,t.Lk)("div",P,[(0,t.Lk)("div",B,[(0,t.bF)(u,{size:"small",background:"",layout:"prev,pager, next","pager-count":5,total:s.devices.page.Count,"page-size":s.devices.page.Request.Size,"current-page":s.devices.page.Request.Page,onCurrentChange:s.handlePageChange,onSizeChange:s.handlePageSizeChange,"page-sizes":[10,20,50,100,255]},null,8,["total","page-size","current-page","onCurrentChange","onSizeChange"])])])])}var D=a(8104),X=a(7985),y=a(9383),N=a(7115),U=a(263),Q=a(4877),W=a(9983),H={components:{StarFilled:b.BQ2,UpdaterBtn:N.A,DeviceName:U.A,TuntapShow:Q.A},setup(e){(0,C.B)();const n=(0,m.Kh)({}),{devices:a,machineId:s,_getSignList:l,_getSignList1:i,handleDeviceEdit:o,handlePageChange:c,handlePageSizeChange:r,handleDel:u,clearDevicesTimeout:d}=(0,X.r)(),{tuntap:g,_getTuntapInfo:p,handleTuntapRefresh:v,clearTuntapTimeout:h,handleTuntapEdit:f,sortTuntapIP:k}=(0,D.O)(),{_getUpdater:b,_subscribeUpdater:L,clearUpdaterTimeout:_}=(0,y.d)(),{connections:w,forwardConnections:S,_getForwardConnections:F,tuntapConnections:x,_getTuntapConnections:T,socks5Connections:z,_getSocks5Connections:E,handleTunnelConnections:A,clearConnectionsTimeout:I}=(0,W.L2)();return(0,t.sV)((()=>{c(),v(),l(),i(),p(),b(),L()})),(0,t.hi)((()=>{d(),h(),_()})),{state:n,devices:a,machineId:s,handlePageChange:c,handlePageSizeChange:r,tuntap:g}}};const K=(0,w.A)(H,[["render",R],["__scopeId","data-v-68d1c30a"]]);var j=K,q=a(5317),M=a(1387),V={components:{Head:F,List:j,Status:q.A},setup(){document.addEventListener("contextmenu",(function(e){e.preventDefault()}));const e=(0,C.B)(),n=(0,M.rd)();return(0,t.sV)((()=>{0==e.value.hasAccess("NetManager")&&n.push({name:"NoPermission"})})),{}}};const G=(0,w.A)(V,[["render",r],["__scopeId","data-v-6a3f3b43"]]);var O=G}}]);
|
||||
"use strict";(self["webpackChunklinker_web"]=self["webpackChunklinker_web"]||[]).push([[127],{7332:function(e,n,a){a.r(n),a.d(n,{default:function(){return O}});var t=a(6768);const s={class:"net-wrap app-wrap"},l={class:"inner absolute flex flex-column flex-nowrap"},i={class:"head"},o={class:"body flex-1 relative"},c={class:"status"};function r(e,n,a,r,u,d){const g=(0,t.g2)("Head"),p=(0,t.g2)("List"),v=(0,t.g2)("Status");return(0,t.uX)(),(0,t.CE)("div",s,[(0,t.Lk)("div",l,[(0,t.Lk)("div",i,[(0,t.bF)(g)]),(0,t.Lk)("div",o,[(0,t.bF)(p)]),(0,t.Lk)("div",c,[(0,t.bF)(v,{config:!1})])])])}a(4114);var u=a(4232);const d=e=>((0,t.Qi)("data-v-6bfe19a3"),e=e(),(0,t.jt)(),e),g={class:"head-wrap"},p={class:"tools flex"},v={class:"label"},h=d((()=>(0,t.Lk)("span",{class:"flex-1"},null,-1))),f={style:{"margin-left":"1rem"}};function k(e,n,a,s,l,i){const o=(0,t.g2)("Refresh"),c=(0,t.g2)("el-icon"),r=(0,t.g2)("el-button"),d=(0,t.g2)("Background");return(0,t.uX)(),(0,t.CE)("div",g,[(0,t.Lk)("div",p,[(0,t.Lk)("span",v,"分组 : "+(0,u.v_)(s.state.group),1),h,(0,t.bF)(r,{size:"small",onClick:s.handleRefresh},{default:(0,t.k6)((()=>[(0,t.eW)(" 刷新(F5)"),(0,t.bF)(c,null,{default:(0,t.k6)((()=>[(0,t.bF)(o)])),_:1})])),_:1},8,["onClick"]),(0,t.Lk)("div",f,[(0,t.bF)(d,{name:"net"})])])])}var C=a(3830),m=a(144),b=a(7477),L=a(5096),_={components:{Edit:b.ffu,Refresh:b.C42,Background:L.A},setup(){const e=(0,C.B)(),n=(0,m.Kh)({server:(0,t.EW)((()=>e.value.config.Client.Server.Host)),group:(0,t.EW)((()=>e.value.config.Client.Group.Name))}),a=()=>{window.location.reload()};return{state:n,handleRefresh:a}}},w=a(1241);const S=(0,w.A)(_,[["render",k],["__scopeId","data-v-6bfe19a3"]]);var F=S;const x=e=>((0,t.Qi)("data-v-68d1c30a"),e=e(),(0,t.jt)(),e),T={class:"net-list-wrap flex flex-column absolute"},z={class:"flex-1 scrollbar"},E={class:"flex"},A=x((()=>(0,t.Lk)("div",{class:"flex-1"},null,-1))),I={class:"tuntap"},P={class:"page t-c"},B={class:"page-wrap t-c"};function R(e,n,a,s,l,i){const o=(0,t.g2)("DeviceName"),c=(0,t.g2)("UpdaterBtn"),r=(0,t.g2)("TuntapShow"),u=(0,t.g2)("el-pagination");return(0,t.uX)(),(0,t.CE)("div",T,[(0,t.Lk)("div",z,[(0,t.Lk)("ul",null,[((0,t.uX)(!0),(0,t.CE)(t.FK,null,(0,t.pI)(s.devices.page.List,((e,n)=>((0,t.uX)(),(0,t.CE)("li",{key:n},[(0,t.Lk)("dl",null,[(0,t.Lk)("dt",E,[(0,t.Lk)("div",null,[(0,t.bF)(o,{item:e},null,8,["item"])]),A,(0,t.Lk)("div",null,[(0,t.bF)(c,{config:!1,item:e},null,8,["item"])])]),(0,t.Lk)("dd",I,[s.tuntap.list[e.MachineId]?((0,t.uX)(),(0,t.Wv)(r,{key:0,item:e},null,8,["item"])):(0,t.Q3)("",!0)])])])))),128))])]),(0,t.Lk)("div",P,[(0,t.Lk)("div",B,[(0,t.bF)(u,{size:"small",background:"",layout:"prev,pager, next","pager-count":5,total:s.devices.page.Count,"page-size":s.devices.page.Request.Size,"current-page":s.devices.page.Request.Page,onCurrentChange:s.handlePageChange,onSizeChange:s.handlePageSizeChange,"page-sizes":[10,20,50,100,255]},null,8,["total","page-size","current-page","onCurrentChange","onSizeChange"])])])])}var D=a(8104),X=a(7985),y=a(9383),N=a(7115),U=a(263),Q=a(4877),W=a(9983),H={components:{StarFilled:b.BQ2,UpdaterBtn:N.A,DeviceName:U.A,TuntapShow:Q.A},setup(e){(0,C.B)();const n=(0,m.Kh)({}),{devices:a,machineId:s,_getSignList:l,_getSignList1:i,handleDeviceEdit:o,handlePageChange:c,handlePageSizeChange:r,handleDel:u,clearDevicesTimeout:d}=(0,X.r)(),{tuntap:g,_getTuntapInfo:p,handleTuntapRefresh:v,clearTuntapTimeout:h,handleTuntapEdit:f,sortTuntapIP:k}=(0,D.O)(),{_getUpdater:b,_subscribeUpdater:L,clearUpdaterTimeout:_}=(0,y.d)(),{connections:w,forwardConnections:S,_getForwardConnections:F,tuntapConnections:x,_getTuntapConnections:T,socks5Connections:z,_getSocks5Connections:E,handleTunnelConnections:A,clearConnectionsTimeout:I}=(0,W.L2)();return(0,t.sV)((()=>{c(),v(),l(),i(),p(),b(),L()})),(0,t.hi)((()=>{d(),h(),_()})),{state:n,devices:a,machineId:s,handlePageChange:c,handlePageSizeChange:r,tuntap:g}}};const K=(0,w.A)(H,[["render",R],["__scopeId","data-v-68d1c30a"]]);var j=K,q=a(1337),M=a(1387),V={components:{Head:F,List:j,Status:q.A},setup(){document.addEventListener("contextmenu",(function(e){e.preventDefault()}));const e=(0,C.B)(),n=(0,M.rd)();return(0,t.sV)((()=>{0==e.value.hasAccess("NetManager")&&n.push({name:"NoPermission"})})),{}}};const G=(0,w.A)(V,[["render",r],["__scopeId","data-v-6a3f3b43"]]);var O=G}}]);
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
src/linker.tray.win/web/js/620.066ac82f.js
Normal file
1
src/linker.tray.win/web/js/620.066ac82f.js
Normal file
File diff suppressed because one or more lines are too long
1
src/linker.tray.win/web/js/842.190b03a1.js
Normal file
1
src/linker.tray.win/web/js/842.190b03a1.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -16,9 +16,9 @@
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
<PackageReleaseNotes>linker tun</PackageReleaseNotes>
|
||||
<Version>1.7.9</Version>
|
||||
<AssemblyVersion>1.7.9</AssemblyVersion>
|
||||
<FileVersion>1.7.9</FileVersion>
|
||||
<Version>1.8.0</Version>
|
||||
<AssemblyVersion>1.8.0</AssemblyVersion>
|
||||
<FileVersion>1.8.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user