mirror of
https://github.com/snltty/linker.git
synced 2025-11-03 10:01:05 +08:00
sync
This commit is contained in:
2
.github/workflows/dotnet.yml
vendored
2
.github/workflows/dotnet.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
|||||||
release_name: v1.5.1.${{ steps.date.outputs.today }}
|
release_name: v1.5.1.${{ steps.date.outputs.today }}
|
||||||
draft: false
|
draft: false
|
||||||
prerelease: false
|
prerelease: false
|
||||||
body: "1. 优化点对网和网对网的局域网IP,包括禁用IP,和冲突检测\r\n2. 一些UI优化\r\n3. 测试中,测试中,测试中,不要更新,用v1.4.9"
|
body: "1. 优化点对网和网对网的局域网IP,包括禁用IP,和冲突检测\r\n2. 一些UI优化\r\n3. 新增socks5代理\r\n4. 优化端口转发和内网穿透配置\r\n5. 优化网卡的一些东西\r\n6. 测试中,测试中,测试中,不要更新,用v1.4.9"
|
||||||
- name: upload-win-x86-oss
|
- name: upload-win-x86-oss
|
||||||
id: upload-win-x86-oss
|
id: upload-win-x86-oss
|
||||||
uses: tvrcgo/oss-action@v0.1.1
|
uses: tvrcgo/oss-action@v0.1.1
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ namespace linker.gen
|
|||||||
new GeneratorInfo{ ClassName="MessengerResolverTypesLoader", ClassNameSpace="linker.plugins.messenger", InterfaceName="linker.plugins.messenger.IMessenger"},
|
new GeneratorInfo{ ClassName="MessengerResolverTypesLoader", ClassNameSpace="linker.plugins.messenger", InterfaceName="linker.plugins.messenger.IMessenger"},
|
||||||
new GeneratorInfo{ ClassName="ApiClientTypesLoader", ClassNameSpace="linker.plugins.capi", InterfaceName="linker.plugins.capi.IApiClientController"},
|
new GeneratorInfo{ ClassName="ApiClientTypesLoader", ClassNameSpace="linker.plugins.capi", InterfaceName="linker.plugins.capi.IApiClientController"},
|
||||||
new GeneratorInfo{ ClassName="ConfigSyncTypesLoader", ClassNameSpace="linker.plugins.config", InterfaceName="linker.plugins.config.IConfigSync"},
|
new GeneratorInfo{ ClassName="ConfigSyncTypesLoader", ClassNameSpace="linker.plugins.config", InterfaceName="linker.plugins.config.IConfigSync"},
|
||||||
|
new GeneratorInfo{ ClassName="DecenterTypesLoader", ClassNameSpace="linker.plugins.decenter", InterfaceName="linker.plugins.decenter.IDecenter"},
|
||||||
};
|
};
|
||||||
|
|
||||||
public void Initialize(IncrementalGeneratorInitializationContext context)
|
public void Initialize(IncrementalGeneratorInitializationContext context)
|
||||||
|
|||||||
@@ -15,10 +15,15 @@ namespace linker.libs
|
|||||||
|
|
||||||
public void Add()
|
public void Add()
|
||||||
{
|
{
|
||||||
if(Interlocked.Increment(ref version) > ulong.MaxValue - ushort.MaxValue)
|
if (Interlocked.Increment(ref version) > ulong.MaxValue - ushort.MaxValue)
|
||||||
{
|
{
|
||||||
Interlocked.Exchange(ref version, 0);
|
Interlocked.Exchange(ref version, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool Reset()
|
||||||
|
{
|
||||||
|
return Interlocked.Exchange(ref version, 0) > 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
linker.web/src/apis/access.js
Normal file
8
linker.web/src/apis/access.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { sendWebsocketMsg } from './request'
|
||||||
|
|
||||||
|
export const getAccesss = (machineid) => {
|
||||||
|
return sendWebsocketMsg('access/GetAccesss', machineid);
|
||||||
|
}
|
||||||
|
export const setAccess = (data) => {
|
||||||
|
return sendWebsocketMsg('access/SetAccess', data);
|
||||||
|
}
|
||||||
@@ -11,12 +11,6 @@ export const exportConfig = (data) => {
|
|||||||
return sendWebsocketMsg('configclient/export', data);
|
return sendWebsocketMsg('configclient/export', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getAccesss = (machineid) => {
|
|
||||||
return sendWebsocketMsg('configclient/GetAccesss', machineid);
|
|
||||||
}
|
|
||||||
export const setAccess = (data) => {
|
|
||||||
return sendWebsocketMsg('configclient/SetAccess', data);
|
|
||||||
}
|
|
||||||
export const getSyncNames = () => {
|
export const getSyncNames = () => {
|
||||||
return sendWebsocketMsg('configclient/SyncNames');
|
return sendWebsocketMsg('configclient/SyncNames');
|
||||||
}
|
}
|
||||||
|
|||||||
25
linker.web/src/apis/socks5.js
Normal file
25
linker.web/src/apis/socks5.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { sendWebsocketMsg } from './request'
|
||||||
|
|
||||||
|
|
||||||
|
export const getSocks5Connections = (hashcode = '0') => {
|
||||||
|
return sendWebsocketMsg('socks5client/connections', hashcode);
|
||||||
|
}
|
||||||
|
export const removeSocks5Connection = (id) => {
|
||||||
|
return sendWebsocketMsg('socks5client/removeconnection', id);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getSocks5Info = (hashcode = '0') => {
|
||||||
|
return sendWebsocketMsg('socks5client/get', hashcode);
|
||||||
|
}
|
||||||
|
export const runSocks5 = (name) => {
|
||||||
|
return sendWebsocketMsg('socks5client/run', name);
|
||||||
|
}
|
||||||
|
export const stopSocks5 = (name) => {
|
||||||
|
return sendWebsocketMsg('socks5client/stop', name);
|
||||||
|
}
|
||||||
|
export const updateSocks5 = (name) => {
|
||||||
|
return sendWebsocketMsg('socks5client/update', name);
|
||||||
|
}
|
||||||
|
export const refreshSocks5 = () => {
|
||||||
|
return sendWebsocketMsg('socks5client/refresh');
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { setAccess } from '@/apis/config';
|
import { setAccess } from '@/apis/access';
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import { reactive, ref, watch } from 'vue';
|
import { reactive, ref, watch } from 'vue';
|
||||||
import Access from '@/views/full/devices/Access.vue'
|
import Access from '@/views/full/devices/Access.vue'
|
||||||
|
|||||||
@@ -53,7 +53,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { reactive, watch,computed, onMounted, onUnmounted } from 'vue';
|
import { reactive, watch,computed, onMounted, onUnmounted } from 'vue';
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import { useConnections, useForwardConnections, useTuntapConnections } from './connections';
|
import { useConnections, useForwardConnections, useSocks5Connections, useTuntapConnections } from './connections';
|
||||||
import { Delete } from '@element-plus/icons-vue';
|
import { Delete } from '@element-plus/icons-vue';
|
||||||
import { injectGlobalData } from '@/provide';
|
import { injectGlobalData } from '@/provide';
|
||||||
export default {
|
export default {
|
||||||
@@ -68,6 +68,7 @@ export default {
|
|||||||
const connections = useConnections();
|
const connections = useConnections();
|
||||||
const forwardConnections = useForwardConnections();
|
const forwardConnections = useForwardConnections();
|
||||||
const tuntapConnections = useTuntapConnections();
|
const tuntapConnections = useTuntapConnections();
|
||||||
|
const socks5Connections = useSocks5Connections();
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
show: true,
|
show: true,
|
||||||
protocolTypes:{1:'tcp',2:'udp',4:'msquic'},
|
protocolTypes:{1:'tcp',2:'udp',4:'msquic'},
|
||||||
@@ -78,6 +79,7 @@ export default {
|
|||||||
return [
|
return [
|
||||||
forwardConnections.value.list[connections.value.current],
|
forwardConnections.value.list[connections.value.current],
|
||||||
tuntapConnections.value.list[connections.value.current],
|
tuntapConnections.value.list[connections.value.current],
|
||||||
|
socks5Connections.value.list[connections.value.current],
|
||||||
].filter(c=>!!c);
|
].filter(c=>!!c);
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
<el-table-column prop="Version" label="版本" width="110" sortable="custom"></el-table-column>
|
<el-table-column prop="Version" label="版本" width="110" sortable="custom"></el-table-column>
|
||||||
<el-table-column prop="tunnel" label="网关" width="90" sortable="custom"></el-table-column>
|
<el-table-column prop="tunnel" label="网关" width="90" sortable="custom"></el-table-column>
|
||||||
<el-table-column prop="tuntap" label="网卡IP" width="160" sortable="custom"></el-table-column>
|
<el-table-column prop="tuntap" label="网卡IP" width="160" sortable="custom"></el-table-column>
|
||||||
|
<el-table-column prop="socks5" label="socks5" width="160" sortable="custom"></el-table-column>
|
||||||
<el-table-column prop="forward" label=""></el-table-column>
|
<el-table-column prop="forward" label=""></el-table-column>
|
||||||
<el-table-column label="" width="74" fixed="right"></el-table-column>
|
<el-table-column label="" width="74" fixed="right"></el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -12,7 +13,7 @@
|
|||||||
<Device @edit="handleDeviceEdit" @refresh="handlePageRefresh"></Device>
|
<Device @edit="handleDeviceEdit" @refresh="handlePageRefresh"></Device>
|
||||||
<Tunnel @edit="handleTunnelEdit" @refresh="handleTunnelRefresh" @connections="handleTunnelConnections"></Tunnel>
|
<Tunnel @edit="handleTunnelEdit" @refresh="handleTunnelRefresh" @connections="handleTunnelConnections"></Tunnel>
|
||||||
<Tuntap @edit="handleTuntapEdit" @refresh="handleTuntapRefresh"></Tuntap>
|
<Tuntap @edit="handleTuntapEdit" @refresh="handleTuntapRefresh"></Tuntap>
|
||||||
<Socks5 @edit="_handleForwardEdit" @sedit="handleSForwardEdit"></Socks5>
|
<Socks5 @edit="handleSocks5Edit" @refresh="handleSocks5Refresh"></Socks5>
|
||||||
<Forward @edit="_handleForwardEdit" @sedit="handleSForwardEdit"></Forward>
|
<Forward @edit="_handleForwardEdit" @sedit="handleSForwardEdit"></Forward>
|
||||||
<Oper @refresh="handlePageRefresh" @access="handleAccessEdit"></Oper>
|
<Oper @refresh="handlePageRefresh" @access="handleAccessEdit"></Oper>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -28,6 +29,7 @@
|
|||||||
<TunnelEdit v-if="tunnel.showEdit" v-model="tunnel.showEdit" @change="handleTunnelRefresh"></TunnelEdit>
|
<TunnelEdit v-if="tunnel.showEdit" v-model="tunnel.showEdit" @change="handleTunnelRefresh"></TunnelEdit>
|
||||||
<ConnectionsEdit v-if="connections.showEdit" v-model="connections.showEdit" ></ConnectionsEdit>
|
<ConnectionsEdit v-if="connections.showEdit" v-model="connections.showEdit" ></ConnectionsEdit>
|
||||||
<TuntapEdit v-if="tuntap.showEdit" v-model="tuntap.showEdit" @change="handleTuntapRefresh"></TuntapEdit>
|
<TuntapEdit v-if="tuntap.showEdit" v-model="tuntap.showEdit" @change="handleTuntapRefresh"></TuntapEdit>
|
||||||
|
<Socks5Edit v-if="socks5.showEdit" v-model="socks5.showEdit" @change="handleSocks5Refresh"></Socks5Edit>
|
||||||
<TuntapLease v-if="tuntap.showLease" v-model="tuntap.showLease" @change="handleTuntapRefresh"></TuntapLease>
|
<TuntapLease v-if="tuntap.showLease" v-model="tuntap.showLease" @change="handleTuntapRefresh"></TuntapLease>
|
||||||
<ForwardEdit v-if="forward.showEdit" v-model="forward.showEdit" ></ForwardEdit>
|
<ForwardEdit v-if="forward.showEdit" v-model="forward.showEdit" ></ForwardEdit>
|
||||||
<ForwardCopy v-if="forward.showCopy" v-model="forward.showCopy" ></ForwardCopy>
|
<ForwardCopy v-if="forward.showCopy" v-model="forward.showCopy" ></ForwardCopy>
|
||||||
@@ -38,33 +40,54 @@
|
|||||||
<script>
|
<script>
|
||||||
import { injectGlobalData } from '@/provide.js'
|
import { injectGlobalData } from '@/provide.js'
|
||||||
import { reactive, onMounted, onUnmounted, computed } from 'vue'
|
import { reactive, onMounted, onUnmounted, computed } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
import Oper from './Oper.vue'
|
import Oper from './Oper.vue'
|
||||||
import Device from './Device.vue'
|
import Device from './Device.vue'
|
||||||
import DeviceEdit from './DeviceEdit.vue'
|
import DeviceEdit from './DeviceEdit.vue'
|
||||||
|
import { provideDevices } from './devices'
|
||||||
|
|
||||||
import AccessEdit from './AccessEdit.vue'
|
import AccessEdit from './AccessEdit.vue'
|
||||||
|
import { provideAccess } from './access'
|
||||||
|
|
||||||
import Tuntap from './Tuntap.vue'
|
import Tuntap from './Tuntap.vue'
|
||||||
import TuntapEdit from './TuntapEdit.vue'
|
import TuntapEdit from './TuntapEdit.vue'
|
||||||
import TuntapLease from './TuntapLease.vue'
|
import TuntapLease from './TuntapLease.vue'
|
||||||
|
import { provideTuntap } from './tuntap'
|
||||||
|
|
||||||
|
import Socks5 from './Socks5.vue'
|
||||||
|
import Socks5Edit from './Socks5Edit.vue'
|
||||||
|
import { provideSocks5 } from './socks5'
|
||||||
|
|
||||||
import Tunnel from './Tunnel.vue'
|
import Tunnel from './Tunnel.vue'
|
||||||
import TunnelEdit from './TunnelEdit.vue'
|
import TunnelEdit from './TunnelEdit.vue'
|
||||||
import Socks5 from './Socks5.vue'
|
import { provideTunnel } from './tunnel'
|
||||||
|
|
||||||
import Forward from './Forward.vue'
|
import Forward from './Forward.vue'
|
||||||
import ForwardEdit from './ForwardEdit.vue'
|
import ForwardEdit from './ForwardEdit.vue'
|
||||||
import ForwardCopy from './ForwardCopy.vue'
|
import ForwardCopy from './ForwardCopy.vue'
|
||||||
|
import { provideForward } from './forward'
|
||||||
|
|
||||||
import SForwardEdit from './SForwardEdit.vue'
|
import SForwardEdit from './SForwardEdit.vue'
|
||||||
import SForwardCopy from './SForwardCopy.vue'
|
import SForwardCopy from './SForwardCopy.vue'
|
||||||
import ConnectionsEdit from './ConnectionsEdit.vue'
|
|
||||||
import { ElMessage } from 'element-plus'
|
|
||||||
import { provideTuntap } from './tuntap'
|
|
||||||
import { provideTunnel } from './tunnel'
|
|
||||||
import { provideForward } from './forward'
|
|
||||||
import { provideConnections } from './connections'
|
|
||||||
import { provideSforward } from './sforward'
|
import { provideSforward } from './sforward'
|
||||||
import { provideDevices } from './devices'
|
|
||||||
|
import ConnectionsEdit from './ConnectionsEdit.vue'
|
||||||
|
import { provideConnections } from './connections'
|
||||||
|
|
||||||
import { provideUpdater } from './updater'
|
import { provideUpdater } from './updater'
|
||||||
import { provideAccess } from './access'
|
|
||||||
export default {
|
export default {
|
||||||
components: {Oper,Device,DeviceEdit,AccessEdit,Tunnel,TunnelEdit,ConnectionsEdit, Tuntap,TuntapEdit,TuntapLease, Socks5, Forward,ForwardEdit,ForwardCopy,SForwardEdit,SForwardCopy },
|
components: {Oper,
|
||||||
|
Device,DeviceEdit,
|
||||||
|
AccessEdit,
|
||||||
|
Tunnel,TunnelEdit,
|
||||||
|
ConnectionsEdit,
|
||||||
|
Tuntap,TuntapEdit,TuntapLease,
|
||||||
|
Socks5, Socks5Edit,
|
||||||
|
Forward,ForwardEdit,ForwardCopy,
|
||||||
|
SForwardEdit,SForwardCopy
|
||||||
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
|
|
||||||
const globalData = injectGlobalData();
|
const globalData = injectGlobalData();
|
||||||
@@ -76,12 +99,14 @@ export default {
|
|||||||
handleDeviceEdit,handleAccessEdit, handlePageChange, handlePageSizeChange, handleDel,clearDevicesTimeout,setSort} = provideDevices();
|
handleDeviceEdit,handleAccessEdit, handlePageChange, handlePageSizeChange, handleDel,clearDevicesTimeout,setSort} = provideDevices();
|
||||||
|
|
||||||
const {tuntap,_getTuntapInfo,handleTuntapEdit,handleTuntapRefresh,clearTuntapTimeout,getTuntapMachines,sortTuntapIP} = provideTuntap();
|
const {tuntap,_getTuntapInfo,handleTuntapEdit,handleTuntapRefresh,clearTuntapTimeout,getTuntapMachines,sortTuntapIP} = provideTuntap();
|
||||||
|
const {socks5,_getSocks5Info,handleSocks5Edit,handleSocks5Refresh,clearSocks5Timeout,getSocks5Machines,sortSocks5} = provideSocks5();
|
||||||
const {tunnel,_getTunnelInfo,handleTunnelEdit,handleTunnelRefresh,clearTunnelTimeout,sortTunnel} = provideTunnel();
|
const {tunnel,_getTunnelInfo,handleTunnelEdit,handleTunnelRefresh,clearTunnelTimeout,sortTunnel} = provideTunnel();
|
||||||
const {forward,_getForwardInfo,handleForwardEdit,_testTargetForwardInfo,clearForwardTimeout,getForwardMachines} = provideForward();
|
const {forward,_getForwardInfo,handleForwardEdit,_testTargetForwardInfo,clearForwardTimeout,getForwardMachines} = provideForward();
|
||||||
const {sforward,_getSForwardInfo,handleSForwardEdit,_testLocalSForwardInfo,clearSForwardTimeout,getSForwardMachines} = provideSforward();
|
const {sforward,_getSForwardInfo,handleSForwardEdit,_testLocalSForwardInfo,clearSForwardTimeout,getSForwardMachines} = provideSforward();
|
||||||
const {connections,
|
const {connections,
|
||||||
forwardConnections,_getForwardConnections,
|
forwardConnections,_getForwardConnections,
|
||||||
tuntapConnections,_getTuntapConnections,
|
tuntapConnections,_getTuntapConnections,
|
||||||
|
socks5Connections,_getSocks5Connections,
|
||||||
handleTunnelConnections,clearConnectionsTimeout
|
handleTunnelConnections,clearConnectionsTimeout
|
||||||
} = provideConnections();
|
} = provideConnections();
|
||||||
|
|
||||||
@@ -107,6 +132,11 @@ export default {
|
|||||||
if(ids .length > 0){
|
if(ids .length > 0){
|
||||||
fn = setSort(ids);
|
fn = setSort(ids);
|
||||||
}
|
}
|
||||||
|
}else if(row.prop == 'socks5'){
|
||||||
|
const ids = sortSocks5(devices.page.Request.Asc);
|
||||||
|
if(ids .length > 0){
|
||||||
|
fn = setSort(ids);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn.then(()=>{
|
fn.then(()=>{
|
||||||
handlePageChange();
|
handlePageChange();
|
||||||
@@ -139,12 +169,14 @@ export default {
|
|||||||
handlePageChange();
|
handlePageChange();
|
||||||
handleTunnelRefresh();
|
handleTunnelRefresh();
|
||||||
handleTuntapRefresh();
|
handleTuntapRefresh();
|
||||||
|
handleSocks5Refresh();
|
||||||
ElMessage.success({message:'刷新成功',grouping:true});
|
ElMessage.success({message:'刷新成功',grouping:true});
|
||||||
}
|
}
|
||||||
const handlePageSearch = ()=>{
|
const handlePageSearch = ()=>{
|
||||||
handlePageChange();
|
handlePageChange();
|
||||||
handleTunnelRefresh();
|
handleTunnelRefresh();
|
||||||
handleTuntapRefresh();
|
handleTuntapRefresh();
|
||||||
|
handleSocks5Refresh();
|
||||||
ElMessage.success({message:'刷新成功',grouping:true});
|
ElMessage.success({message:'刷新成功',grouping:true});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,9 +187,11 @@ export default {
|
|||||||
_getSignList();
|
_getSignList();
|
||||||
_getSignList1();
|
_getSignList1();
|
||||||
_getTuntapInfo();
|
_getTuntapInfo();
|
||||||
|
_getSocks5Info();
|
||||||
_getTunnelInfo();
|
_getTunnelInfo();
|
||||||
_getForwardConnections();
|
_getForwardConnections();
|
||||||
_getTuntapConnections();
|
_getTuntapConnections();
|
||||||
|
_getSocks5Connections();
|
||||||
_getForwardInfo();
|
_getForwardInfo();
|
||||||
_getSForwardInfo();
|
_getSForwardInfo();
|
||||||
|
|
||||||
@@ -173,6 +207,7 @@ export default {
|
|||||||
clearDevicesTimeout();
|
clearDevicesTimeout();
|
||||||
clearConnectionsTimeout();
|
clearConnectionsTimeout();
|
||||||
clearTuntapTimeout();
|
clearTuntapTimeout();
|
||||||
|
clearSocks5Timeout();
|
||||||
clearTunnelTimeout();
|
clearTunnelTimeout();
|
||||||
clearForwardTimeout();
|
clearForwardTimeout();
|
||||||
clearSForwardTimeout();
|
clearSForwardTimeout();
|
||||||
@@ -186,6 +221,7 @@ export default {
|
|||||||
state,devices, machineId,handleSortChange,
|
state,devices, machineId,handleSortChange,
|
||||||
handleDeviceEdit,handleAccessEdit,handlePageRefresh,handlePageSearch, handlePageChange,handlePageSizeChange, handleDel,
|
handleDeviceEdit,handleAccessEdit,handlePageRefresh,handlePageSearch, handlePageChange,handlePageSizeChange, handleDel,
|
||||||
tuntap, handleTuntapEdit, handleTuntapRefresh,
|
tuntap, handleTuntapEdit, handleTuntapRefresh,
|
||||||
|
socks5, handleSocks5Edit, handleSocks5Refresh,
|
||||||
tunnel,connections, handleTunnelEdit, handleTunnelRefresh,handleTunnelConnections,
|
tunnel,connections, handleTunnelEdit, handleTunnelRefresh,handleTunnelConnections,
|
||||||
forward,_handleForwardEdit,
|
forward,_handleForwardEdit,
|
||||||
sforward,handleSForwardEdit
|
sforward,handleSForwardEdit
|
||||||
|
|||||||
@@ -1,39 +1,35 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-table-column prop="socks5" label="socks5代理" width="160">
|
<el-table-column prop="socks5" label="socks5" width="160">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<div>
|
<div v-if="socks5.list[scope.row.MachineId]">
|
||||||
<div class="flex">
|
<Socks5Show :config="true" :item="scope.row" @edit="handleSocks5" @refresh="handleSocks5Refresh"></Socks5Show>
|
||||||
<div class="flex-1">
|
|
||||||
<a href="javascript:;" class="a-line" title="socks5代理">
|
|
||||||
<strong class="gateway">socks5://*:1805</strong>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<el-switch size="small" inline-prompt active-text="😀" inactive-text="😣"/>
|
|
||||||
</div>
|
|
||||||
<div>1111</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { injectGlobalData } from '@/provide';
|
import { useSocks5 } from './socks5';
|
||||||
|
import Socks5Show from './Socks5Show.vue';
|
||||||
export default {
|
export default {
|
||||||
emits: ['edit','sedit'],
|
emits: ['edit','refresh'],
|
||||||
|
components:{Socks5Show},
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const globalData = injectGlobalData();
|
|
||||||
return {}
|
const socks5 = useSocks5();
|
||||||
|
|
||||||
|
const handleSocks5 = (_socks5) => {
|
||||||
|
emit('edit',_socks5);
|
||||||
|
}
|
||||||
|
const handleSocks5Refresh = ()=>{
|
||||||
|
emit('refresh');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
socks5, handleSocks5,handleSocks5Refresh
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
.gateway{
|
|
||||||
background:linear-gradient(90deg, #c5b260, #858585, #c5b260, #858585);
|
|
||||||
-webkit-background-clip:text;
|
|
||||||
-webkit-text-fill-color:hsla(0,0%,100%,0);
|
|
||||||
&.green{
|
|
||||||
background:linear-gradient(90deg, #e4bb10, #008000, #e4bb10, #008000);
|
|
||||||
-webkit-background-clip:text;
|
|
||||||
-webkit-text-fill-color:hsla(0,0%,100%,0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
123
linker.web/src/views/full/devices/Socks5Edit.vue
Normal file
123
linker.web/src/views/full/devices/Socks5Edit.vue
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog v-model="state.show" :close-on-click-modal="false" append-to=".app-wrap" :title="`设置[${state.machineName}]代理`" top="1vh" width="600">
|
||||||
|
<div>
|
||||||
|
<el-form ref="ruleFormRef" :model="state.ruleForm" :rules="state.rules" label-width="140">
|
||||||
|
<el-form-item prop="gateway" style="margin-bottom:0">
|
||||||
|
配置代理,通过代理访问其它设备
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="代理端口" prop="Port">
|
||||||
|
<el-input v-model="state.ruleForm.Port" style="width:14rem" />
|
||||||
|
</el-form-item>
|
||||||
|
<div class="upgrade-wrap">
|
||||||
|
<el-form-item label="此设备局域网IP" prop="LanIP" class="lan-item">
|
||||||
|
<template v-for="(item, index) in state.ruleForm.Lans" :key="index">
|
||||||
|
<div class="flex" style="margin-bottom:.6rem">
|
||||||
|
<div class="flex-1">
|
||||||
|
<el-input v-model="item.IP" style="width:14rem" />
|
||||||
|
<span>/</span>
|
||||||
|
<el-input @change="handleMaskChange(index)" v-model="item.PrefixLength" style="width:4rem" />
|
||||||
|
</div>
|
||||||
|
<div class="pdl-10">
|
||||||
|
<el-checkbox v-model="item.Disabled" label="禁用记录" size="large" />
|
||||||
|
</div>
|
||||||
|
<div class="pdl-10">
|
||||||
|
<el-button type="danger" @click="handleDel(index)"><el-icon><Delete /></el-icon></el-button>
|
||||||
|
<el-button type="primary" @click="handleAdd(index)"><el-icon><Plus /></el-icon></el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
<el-form-item label="" prop="Btns">
|
||||||
|
<div>
|
||||||
|
<el-button @click="state.show = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleSave">确认</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import {updateSocks5 } from '@/apis/socks5';
|
||||||
|
import { injectGlobalData } from '@/provide';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
import { reactive, ref, watch } from 'vue';
|
||||||
|
import { useSocks5 } from './socks5';
|
||||||
|
import { Delete, Plus } from '@element-plus/icons-vue'
|
||||||
|
export default {
|
||||||
|
props: ['modelValue'],
|
||||||
|
emits: ['change','update:modelValue'],
|
||||||
|
components: {Delete,Plus},
|
||||||
|
setup(props, { emit }) {
|
||||||
|
|
||||||
|
const globalData = injectGlobalData();
|
||||||
|
const socks5 = useSocks5();
|
||||||
|
const ruleFormRef = ref(null);
|
||||||
|
const state = reactive({
|
||||||
|
show: true,
|
||||||
|
machineName:socks5.value.current.device.MachineName,
|
||||||
|
bufferSize:globalData.value.bufferSize,
|
||||||
|
ruleForm: {
|
||||||
|
Port: socks5.value.current.Port,
|
||||||
|
Lans: socks5.value.current.Lans.slice(0)
|
||||||
|
},
|
||||||
|
rules: {}
|
||||||
|
});
|
||||||
|
if (state.ruleForm.Lans.length == 0) {
|
||||||
|
state.ruleForm.Lans.push({IP:'0.0.0.0',PrefixLength:24});
|
||||||
|
}
|
||||||
|
watch(() => state.show, (val) => {
|
||||||
|
if (!val) {
|
||||||
|
setTimeout(() => {
|
||||||
|
emit('update:modelValue', val);
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleMaskChange = (index)=>{
|
||||||
|
var value = +state.ruleForm.Lans[index].PrefixLength;
|
||||||
|
if(value>32 || value<16 || isNaN(value)){
|
||||||
|
value = 24;
|
||||||
|
}
|
||||||
|
state.ruleForm.Lans[index].PrefixLength = value;
|
||||||
|
}
|
||||||
|
const handleDel = (index) => {
|
||||||
|
state.ruleForm.Lans.splice(index, 1);
|
||||||
|
if (state.ruleForm.Lans.length == 0){
|
||||||
|
handleAdd(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handleAdd = (index) => {
|
||||||
|
state.ruleForm.Lans.splice(index + 1, 0, {IP:'0.0.0.0',PrefixLength:24});
|
||||||
|
}
|
||||||
|
const handleSave = () => {
|
||||||
|
const json = JSON.parse(JSON.stringify(socks5.value.current));
|
||||||
|
json.Port = +(state.ruleForm.Port || '1805');
|
||||||
|
json.Lans = state.ruleForm.Lans.map(c=>{ c.PrefixLength=+c.PrefixLength;return c; });
|
||||||
|
updateSocks5(json).then(() => {
|
||||||
|
state.show = false;
|
||||||
|
ElMessage.success('已操作!');
|
||||||
|
emit('change')
|
||||||
|
}).catch(() => {
|
||||||
|
ElMessage.error('操作失败!');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
state, ruleFormRef,handleMaskChange, handleDel, handleAdd, handleSave
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.el-switch.is-disabled{opacity :1;}
|
||||||
|
.upgrade-wrap{
|
||||||
|
border:1px solid #ddd;
|
||||||
|
margin-bottom:2rem
|
||||||
|
padding:1rem 0 1rem 0;
|
||||||
|
}
|
||||||
|
.lan-item{
|
||||||
|
margin-bottom:0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
149
linker.web/src/views/full/devices/Socks5Show.vue
Normal file
149
linker.web/src/views/full/devices/Socks5Show.vue
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="flex">
|
||||||
|
<div class="flex-1">
|
||||||
|
<a href="javascript:;" class="a-line" @click="handleSocks5Port(socks5.list[item.MachineId])" title="此设备的socks5代理">
|
||||||
|
<template v-if="socks5.list[item.MachineId].SetupError">
|
||||||
|
<strong class="red" :title="socks5.list[item.MachineId].SetupError">
|
||||||
|
socks5://*:{{ socks5.list[item.MachineId].Port }}
|
||||||
|
</strong>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<template v-if="socks5.list[item.MachineId].running">
|
||||||
|
<strong class="green gateway">socks5://*:{{ socks5.list[item.MachineId].Port }}</strong>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<strong>socks5://*:{{ socks5.list[item.MachineId].Port }}</strong>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<template v-if="socks5.list[item.MachineId].loading">
|
||||||
|
<div>
|
||||||
|
<el-icon size="14" class="loading"><Loading /></el-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<el-switch v-model="socks5.list[item.MachineId].running" :loading="socks5.list[item.MachineId].loading" disabled @click="handleSocks5(socks5.list[item.MachineId])" size="small" inline-prompt active-text="😀" inactive-text="😣" >
|
||||||
|
</el-switch>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<template v-for="(item1,index) in socks5.list[item.MachineId].Lans" :key="index">
|
||||||
|
<template v-if="item1.Disabled">
|
||||||
|
<div class="flex yellow" title="已禁用">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="item1.Exists">
|
||||||
|
<div class="flex red" title="与其它设备填写IP、或本机局域网IP有冲突">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<div class="flex" title="正常使用" :class="{green:socks5.list[item.MachineId].running}">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { stopSocks5, runSocks5 } from '@/apis/socks5';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
import { useSocks5 } from './socks5';
|
||||||
|
import {Loading} from '@element-plus/icons-vue'
|
||||||
|
import { injectGlobalData } from '@/provide';
|
||||||
|
import { computed } from 'vue';
|
||||||
|
export default {
|
||||||
|
props:['item','config'],
|
||||||
|
emits: ['edit','refresh'],
|
||||||
|
components:{Loading},
|
||||||
|
setup (props,{emit}) {
|
||||||
|
|
||||||
|
const socks5 = useSocks5();
|
||||||
|
const globalData = injectGlobalData();
|
||||||
|
const machineId = computed(() => globalData.value.config.Client.Id);
|
||||||
|
const hasSocks5ChangeSelf = computed(()=>globalData.value.hasAccess('Socks5ChangeSelf'));
|
||||||
|
const hasSocks5ChangeOther = computed(()=>globalData.value.hasAccess('Socks5ChangeOther'));
|
||||||
|
const hasSocks5StatusSelf = computed(()=>globalData.value.hasAccess('Socks5StatusSelf'));
|
||||||
|
const hasSocks5StatusOther = computed(()=>globalData.value.hasAccess('Socks5StatusOther'));
|
||||||
|
const handleSocks5 = (socks5) => {
|
||||||
|
if(!props.config){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(machineId.value === socks5.MachineId){
|
||||||
|
if(!hasSocks5StatusSelf.value){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(!hasSocks5StatusOther.value){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn = socks5.running ? stopSocks5 (socks5.MachineId) : runSocks5(socks5.MachineId);
|
||||||
|
socks5.loading = true;
|
||||||
|
fn.then(() => {
|
||||||
|
ElMessage.success('操作成功!');
|
||||||
|
}).catch(() => {
|
||||||
|
ElMessage.error('操作失败!');
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleSocks5Port = (socks5) => {
|
||||||
|
if(!props.config && machineId.value != socks5.MachineId){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(machineId.value === socks5.MachineId){
|
||||||
|
if(!hasSocks5ChangeSelf.value){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(!hasSocks5ChangeOther.value){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
socks5.device = props.item;
|
||||||
|
emit('edit',socks5);
|
||||||
|
}
|
||||||
|
const handleSocks5Refresh = ()=>{
|
||||||
|
emit('refresh');
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
item:computed(()=>props.item),socks5, handleSocks5, handleSocks5Port,handleSocks5Refresh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
|
||||||
|
@keyframes loading {
|
||||||
|
from{transform:rotate(0deg)}
|
||||||
|
to{transform:rotate(360deg)}
|
||||||
|
}
|
||||||
|
.el-icon.loading,a.loading{
|
||||||
|
vertical-align:middle;font-weight:bold;
|
||||||
|
animation:loading 1s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-switch.is-disabled{opacity :1;}
|
||||||
|
.el-input{
|
||||||
|
width:8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gateway{
|
||||||
|
background:linear-gradient(90deg, #c5b260, #858585, #c5b260, #858585);
|
||||||
|
-webkit-background-clip:text;
|
||||||
|
-webkit-text-fill-color:hsla(0,0%,100%,0);
|
||||||
|
&.green{
|
||||||
|
background:linear-gradient(90deg, #e4bb10, #008000, #e4bb10, #008000);
|
||||||
|
-webkit-background-clip:text;
|
||||||
|
-webkit-text-fill-color:hsla(0,0%,100%,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch-btn{
|
||||||
|
font-size:1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { useTunnel } from './tunnel';
|
import { useTunnel } from './tunnel';
|
||||||
import { useConnections,useForwardConnections,useTuntapConnections } from './connections';
|
import { useConnections,useForwardConnections,useSocks5Connections,useTuntapConnections } from './connections';
|
||||||
import { injectGlobalData } from '@/provide';
|
import { injectGlobalData } from '@/provide';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
@@ -36,11 +36,13 @@ export default {
|
|||||||
const connections = useConnections();
|
const connections = useConnections();
|
||||||
const forwardConnections = useForwardConnections();
|
const forwardConnections = useForwardConnections();
|
||||||
const tuntapConnections = useTuntapConnections();
|
const tuntapConnections = useTuntapConnections();
|
||||||
|
const socks5Connections = useSocks5Connections();
|
||||||
|
|
||||||
const connectionCount = (machineId)=>{
|
const connectionCount = (machineId)=>{
|
||||||
return [
|
return [
|
||||||
forwardConnections.value.list[machineId],
|
forwardConnections.value.list[machineId],
|
||||||
tuntapConnections.value.list[machineId],
|
tuntapConnections.value.list[machineId],
|
||||||
|
socks5Connections.value.list[machineId],
|
||||||
].filter(c=>!!c && c.Connected).length;
|
].filter(c=>!!c && c.Connected).length;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { getAccesss } from "@/apis/config";
|
import { getAccesss } from "@/apis/access";
|
||||||
import { inject, provide, ref } from "vue";
|
import { inject, provide, ref } from "vue";
|
||||||
|
|
||||||
const accessSymbol = Symbol();
|
const accessSymbol = Symbol();
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { getForwardConnections, removeForwardConnection } from "@/apis/forward";
|
import { getForwardConnections, removeForwardConnection } from "@/apis/forward";
|
||||||
import { getTuntapConnections, removeTuntapConnection } from "@/apis/tuntap";
|
import { getTuntapConnections, removeTuntapConnection } from "@/apis/tuntap";
|
||||||
|
import { getSocks5Connections, removeSocks5Connection } from "@/apis/socks5";
|
||||||
import { inject, provide, ref } from "vue";
|
import { inject, provide, ref } from "vue";
|
||||||
|
|
||||||
const connectionsSymbol = Symbol();
|
const connectionsSymbol = Symbol();
|
||||||
const forwardConnectionsSymbol = Symbol();
|
const forwardConnectionsSymbol = Symbol();
|
||||||
const tuntapConnectionsSymbol = Symbol();
|
const tuntapConnectionsSymbol = Symbol();
|
||||||
|
const socks5ConnectionsSymbol = Symbol();
|
||||||
export const provideConnections = () => {
|
export const provideConnections = () => {
|
||||||
const connections = ref({
|
const connections = ref({
|
||||||
showEdit: false,
|
showEdit: false,
|
||||||
@@ -28,8 +30,6 @@ export const provideConnections = () => {
|
|||||||
list: {},
|
list: {},
|
||||||
});
|
});
|
||||||
provide(forwardConnectionsSymbol, forwardConnections);
|
provide(forwardConnectionsSymbol, forwardConnections);
|
||||||
|
|
||||||
|
|
||||||
const _getForwardConnections = () => {
|
const _getForwardConnections = () => {
|
||||||
getForwardConnections(connections.value.hashcode.toString()).then((res) => {
|
getForwardConnections(connections.value.hashcode.toString()).then((res) => {
|
||||||
if (connections.value._updateRealTime == false)
|
if (connections.value._updateRealTime == false)
|
||||||
@@ -44,6 +44,8 @@ export const provideConnections = () => {
|
|||||||
forwardConnections.value.timer = setTimeout(_getForwardConnections, 1000);
|
forwardConnections.value.timer = setTimeout(_getForwardConnections, 1000);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const tuntapConnections = ref({
|
const tuntapConnections = ref({
|
||||||
timer: 0,
|
timer: 0,
|
||||||
list: {},
|
list: {},
|
||||||
@@ -63,6 +65,28 @@ export const provideConnections = () => {
|
|||||||
tuntapConnections.value.timer = setTimeout(_getTuntapConnections, 1000);
|
tuntapConnections.value.timer = setTimeout(_getTuntapConnections, 1000);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const socks5Connections = ref({
|
||||||
|
timer: 0,
|
||||||
|
list: {},
|
||||||
|
});
|
||||||
|
provide(socks5ConnectionsSymbol, socks5Connections);
|
||||||
|
const _getSocks5Connections = () => {
|
||||||
|
getSocks5Connections(connections.value.hashcode1.toString()).then((res) => {
|
||||||
|
if (connections.value._updateRealTime == false)
|
||||||
|
connections.value.hashcode1 = res.HashCode;
|
||||||
|
if (res.List) {
|
||||||
|
parseConnections(res.List, removeSocks5Connection);
|
||||||
|
socks5Connections.value.list = res.List;
|
||||||
|
}
|
||||||
|
|
||||||
|
socks5Connections.value.timer = setTimeout(_getSocks5Connections, 1000);
|
||||||
|
}).catch((e) => {
|
||||||
|
socks5Connections.value.timer = setTimeout(_getSocks5Connections, 1000);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const parseConnections = (_connections, removeFunc) => {
|
const parseConnections = (_connections, removeFunc) => {
|
||||||
const caches = connections.value.speedCache;
|
const caches = connections.value.speedCache;
|
||||||
for (let machineId in _connections) {
|
for (let machineId in _connections) {
|
||||||
@@ -93,14 +117,18 @@ export const provideConnections = () => {
|
|||||||
connections.value.currentName = device.MachineName;
|
connections.value.currentName = device.MachineName;
|
||||||
connections.value.showEdit = true;
|
connections.value.showEdit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const clearConnectionsTimeout = () => {
|
const clearConnectionsTimeout = () => {
|
||||||
clearTimeout(forwardConnections.value.timer);
|
clearTimeout(forwardConnections.value.timer);
|
||||||
clearTimeout(tuntapConnections.value.timer);
|
clearTimeout(tuntapConnections.value.timer);
|
||||||
|
clearTimeout(socks5Connections.value.timer);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
connections,
|
connections,
|
||||||
forwardConnections, _getForwardConnections,
|
forwardConnections, _getForwardConnections,
|
||||||
tuntapConnections, _getTuntapConnections,
|
tuntapConnections, _getTuntapConnections,
|
||||||
|
socks5Connections, _getSocks5Connections,
|
||||||
handleTunnelConnections, clearConnectionsTimeout
|
handleTunnelConnections, clearConnectionsTimeout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,3 +141,6 @@ export const useForwardConnections = () => {
|
|||||||
export const useTuntapConnections = () => {
|
export const useTuntapConnections = () => {
|
||||||
return inject(tuntapConnectionsSymbol);
|
return inject(tuntapConnectionsSymbol);
|
||||||
}
|
}
|
||||||
|
export const useSocks5Connections = () => {
|
||||||
|
return inject(socks5ConnectionsSymbol);
|
||||||
|
}
|
||||||
63
linker.web/src/views/full/devices/socks5.js
Normal file
63
linker.web/src/views/full/devices/socks5.js
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import { inject, provide, ref } from "vue"
|
||||||
|
import { getSocks5Info, refreshSocks5 } from "@/apis/socks5";
|
||||||
|
|
||||||
|
const socks5Symbol = Symbol();
|
||||||
|
export const provideSocks5 = () => {
|
||||||
|
const socks5 = ref({
|
||||||
|
timer: 0,
|
||||||
|
showEdit: false,
|
||||||
|
current: null,
|
||||||
|
list: {},
|
||||||
|
hashcode: 0,
|
||||||
|
});
|
||||||
|
provide(socks5Symbol, socks5);
|
||||||
|
|
||||||
|
const _getSocks5Info = () => {
|
||||||
|
clearTimeout(socks5.value.timer);
|
||||||
|
getSocks5Info(socks5.value.hashcode.toString()).then((res) => {
|
||||||
|
socks5.value.hashcode = res.HashCode;
|
||||||
|
if (res.List) {
|
||||||
|
for (let j in res.List) {
|
||||||
|
Object.assign(res.List[j], {
|
||||||
|
running: res.List[j].Status == 2,
|
||||||
|
loading: res.List[j].Status == 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
socks5.value.list = res.List;
|
||||||
|
}
|
||||||
|
socks5.value.timer = setTimeout(_getSocks5Info, 1100);
|
||||||
|
}).catch((e) => {
|
||||||
|
socks5.value.timer = setTimeout(_getSocks5Info, 1100);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const handleSocks5Edit = (_socks5) => {
|
||||||
|
socks5.value.current = _socks5;
|
||||||
|
socks5.value.showEdit = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
const handleSocks5Refresh = () => {
|
||||||
|
refreshSocks5();
|
||||||
|
}
|
||||||
|
const clearSocks5Timeout = () => {
|
||||||
|
clearTimeout(socks5.value.timer);
|
||||||
|
socks5.value.timer = 0;
|
||||||
|
}
|
||||||
|
const getSocks5Machines = (name) => {
|
||||||
|
return Object.values(socks5.value.list)
|
||||||
|
.filter(c => c.IP.indexOf(name) >= 0 || (c.Lans.filter(d => d.IP.indexOf(name) >= 0).length > 0))
|
||||||
|
.map(c => c.MachineId);
|
||||||
|
}
|
||||||
|
const sortSocks5 = (asc) => {
|
||||||
|
const sort = Object.values(socks5.value.list).sort((a, b) => a.Port - b.Port);
|
||||||
|
return sort.map(c => c.MachineId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
socks5, _getSocks5Info, handleSocks5Edit, handleSocks5Refresh, clearSocks5Timeout, getSocks5Machines, sortSocks5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useSocks5 = () => {
|
||||||
|
return inject(socks5Symbol);
|
||||||
|
}
|
||||||
@@ -1,11 +1,8 @@
|
|||||||
import { injectGlobalData } from "@/provide";
|
|
||||||
import { ElMessage } from "element-plus";
|
|
||||||
import { inject, provide, ref } from "vue"
|
import { inject, provide, ref } from "vue"
|
||||||
import { getTuntapInfo, refreshTuntap, subscribePing } from "@/apis/tuntap";
|
import { getTuntapInfo, refreshTuntap, subscribePing } from "@/apis/tuntap";
|
||||||
|
|
||||||
const tuntapSymbol = Symbol();
|
const tuntapSymbol = Symbol();
|
||||||
export const provideTuntap = () => {
|
export const provideTuntap = () => {
|
||||||
const globalData = injectGlobalData();
|
|
||||||
const tuntap = ref({
|
const tuntap = ref({
|
||||||
timer: 0,
|
timer: 0,
|
||||||
showEdit: false,
|
showEdit: false,
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ namespace linker
|
|||||||
TimerHelper.SetInterval(() =>
|
TimerHelper.SetInterval(() =>
|
||||||
{
|
{
|
||||||
string[] files = Directory.GetFiles("logs").OrderBy(c => c).ToArray();
|
string[] files = Directory.GetFiles("logs").OrderBy(c => c).ToArray();
|
||||||
for (int i = 0; i < files.Length - 7; i++)
|
for (int i = 0; i < files.Length - 180; i++)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -23,7 +23,10 @@
|
|||||||
<Company>snltty</Company>
|
<Company>snltty</Company>
|
||||||
<Description>1. 优化点对网和网对网的局域网IP,包括禁用IP,和冲突检测
|
<Description>1. 优化点对网和网对网的局域网IP,包括禁用IP,和冲突检测
|
||||||
2. 一些UI优化
|
2. 一些UI优化
|
||||||
3. 测试中,测试中,测试中,不要更新,用v1.4.9</Description>
|
3. 新增socks5代理
|
||||||
|
4. 优化端口转发和内网穿透配置
|
||||||
|
5. 优化网卡的一些东西
|
||||||
|
6. 测试中,测试中,测试中,不要更新,用v1.4.9</Description>
|
||||||
<Copyright>snltty</Copyright>
|
<Copyright>snltty</Copyright>
|
||||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||||
|
|||||||
69
linker/plugins/access/AccessApiController.cs
Normal file
69
linker/plugins/access/AccessApiController.cs
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
using linker.config;
|
||||||
|
using linker.libs.api;
|
||||||
|
using linker.libs.extends;
|
||||||
|
using linker.plugins.capi;
|
||||||
|
using linker.libs;
|
||||||
|
using linker.plugins.client;
|
||||||
|
using linker.plugins.messenger;
|
||||||
|
using MemoryPack;
|
||||||
|
using linker.plugins.access.messenger;
|
||||||
|
|
||||||
|
namespace linker.plugins.access
|
||||||
|
{
|
||||||
|
public sealed class AccessApiController : IApiClientController
|
||||||
|
{
|
||||||
|
private readonly FileConfig config;
|
||||||
|
private readonly IMessengerSender sender;
|
||||||
|
private readonly ClientSignInState clientSignInState;
|
||||||
|
private readonly AccessTransfer accessTransfer;
|
||||||
|
|
||||||
|
public AccessApiController(FileConfig config, IMessengerSender sender, ClientSignInState clientSignInState, AccessTransfer accessTransfer)
|
||||||
|
{
|
||||||
|
this.config = config;
|
||||||
|
this.sender = sender;
|
||||||
|
this.clientSignInState = clientSignInState;
|
||||||
|
this.accessTransfer = accessTransfer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessListInfo GetAccesss(ApiControllerParamsInfo param)
|
||||||
|
{
|
||||||
|
ulong hashCode = ulong.Parse(param.Content);
|
||||||
|
if (accessTransfer.Version.Eq(hashCode, out ulong version) == false)
|
||||||
|
{
|
||||||
|
return new AccessListInfo
|
||||||
|
{
|
||||||
|
|
||||||
|
HashCode = version,
|
||||||
|
List = accessTransfer.GetAccesss()
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return new AccessListInfo { HashCode = version };
|
||||||
|
}
|
||||||
|
[ClientApiAccessAttribute(ClientApiAccess.Access)]
|
||||||
|
public async Task<bool> SetAccess(ApiControllerParamsInfo param)
|
||||||
|
{
|
||||||
|
ConfigUpdateAccessInfo configUpdateAccessInfo = param.Content.DeJson<ConfigUpdateAccessInfo>();
|
||||||
|
if (configUpdateAccessInfo.ToMachineId == config.Data.Client.Id)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
configUpdateAccessInfo.FromMachineId = config.Data.Client.Id;
|
||||||
|
MessageResponeInfo resp = await sender.SendReply(new MessageRequestWrap
|
||||||
|
{
|
||||||
|
Connection = clientSignInState.Connection,
|
||||||
|
MessengerId = (ushort)AccessMessengerIds.AccessUpdateForward,
|
||||||
|
Payload = MemoryPackSerializer.Serialize(configUpdateAccessInfo)
|
||||||
|
});
|
||||||
|
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class AccessListInfo
|
||||||
|
{
|
||||||
|
public Dictionary<string, ClientApiAccess> List { get; set; }
|
||||||
|
public ulong HashCode { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
41
linker/plugins/access/AccessStartup.cs
Normal file
41
linker/plugins/access/AccessStartup.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
using linker.config;
|
||||||
|
using linker.plugins.access.messenger;
|
||||||
|
using linker.startup;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace linker.plugins.access
|
||||||
|
{
|
||||||
|
public sealed class AccessStartup : IStartup
|
||||||
|
{
|
||||||
|
public string Name => "access";
|
||||||
|
|
||||||
|
public bool Required => true;
|
||||||
|
|
||||||
|
public StartupLevel Level => StartupLevel.Top;
|
||||||
|
|
||||||
|
public string[] Dependent => new string[] { "messenger", "signin", "serialize" };
|
||||||
|
|
||||||
|
public StartupLoadType LoadType => StartupLoadType.Normal;
|
||||||
|
|
||||||
|
public void AddClient(ServiceCollection serviceCollection, FileConfig config)
|
||||||
|
{
|
||||||
|
serviceCollection.AddSingleton<AccessApiController>();
|
||||||
|
|
||||||
|
serviceCollection.AddSingleton<AccessClientMessenger>();
|
||||||
|
serviceCollection.AddSingleton<AccessTransfer>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddServer(ServiceCollection serviceCollection, FileConfig config)
|
||||||
|
{
|
||||||
|
serviceCollection.AddSingleton<AccessServerMessenger>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UseClient(ServiceProvider serviceProvider, FileConfig config)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UseServer(ServiceProvider serviceProvider, FileConfig config)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,19 @@
|
|||||||
using linker.config;
|
using linker.config;
|
||||||
using linker.libs;
|
using linker.libs;
|
||||||
using linker.plugins.client;
|
using linker.plugins.client;
|
||||||
using linker.plugins.config.messenger;
|
using linker.plugins.decenter;
|
||||||
using linker.plugins.messenger;
|
using linker.plugins.messenger;
|
||||||
using MemoryPack;
|
using MemoryPack;
|
||||||
|
|
||||||
namespace linker.plugins.config
|
namespace linker.plugins.access
|
||||||
{
|
{
|
||||||
public sealed class AccessTransfer
|
public sealed class AccessTransfer : IDecenter
|
||||||
{
|
{
|
||||||
|
public string Name => "access";
|
||||||
|
public VersionManager DataVersion { get; } = new VersionManager();
|
||||||
|
|
||||||
public VersionManager Version { get; } = new VersionManager();
|
public VersionManager Version { get; } = new VersionManager();
|
||||||
|
|
||||||
private Dictionary<string, ClientApiAccess> accesss = new Dictionary<string, ClientApiAccess>();
|
private Dictionary<string, ClientApiAccess> accesss = new Dictionary<string, ClientApiAccess>();
|
||||||
|
|
||||||
private readonly FileConfig fileConfig;
|
private readonly FileConfig fileConfig;
|
||||||
@@ -21,32 +25,43 @@ namespace linker.plugins.config
|
|||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
this.clientSignInState = clientSignInState;
|
this.clientSignInState = clientSignInState;
|
||||||
|
|
||||||
clientSignInState.NetworkEnabledHandle += (times) => Sync();
|
clientSignInState.NetworkEnabledHandle += (times) => DataVersion.Add();
|
||||||
|
}
|
||||||
|
public Memory<byte> GetData()
|
||||||
|
{
|
||||||
|
ConfigAccessInfo info = new ConfigAccessInfo { MachineId = fileConfig.Data.Client.Id, Access = fileConfig.Data.Client.Access };
|
||||||
|
accesss[info.MachineId] = info.Access;
|
||||||
|
Version.Add();
|
||||||
|
return MemoryPackSerializer.Serialize(info);
|
||||||
|
}
|
||||||
|
public void SetData(Memory<byte> data)
|
||||||
|
{
|
||||||
|
ConfigAccessInfo access = MemoryPackSerializer.Deserialize<ConfigAccessInfo>(data.Span);
|
||||||
|
accesss[access.MachineId] = access.Access;
|
||||||
|
Version.Add();
|
||||||
|
}
|
||||||
|
public void SetData(List<ReadOnlyMemory<byte>> data)
|
||||||
|
{
|
||||||
|
List<ConfigAccessInfo> list = data.Select(c => MemoryPackSerializer.Deserialize<ConfigAccessInfo>(c.Span)).ToList();
|
||||||
|
accesss = list.ToDictionary(c => c.MachineId, d => d.Access);
|
||||||
|
accesss[fileConfig.Data.Client.Id] = fileConfig.Data.Client.Access;
|
||||||
|
Version.Add();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<string, ClientApiAccess> GetAccesss()
|
public Dictionary<string, ClientApiAccess> GetAccesss()
|
||||||
{
|
{
|
||||||
return accesss;
|
return accesss;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConfigAccessInfo GetAccess()
|
|
||||||
{
|
|
||||||
return new ConfigAccessInfo { MachineId = fileConfig.Data.Client.Id, Access = fileConfig.Data.Client.Access }; ;
|
|
||||||
}
|
|
||||||
public void SetAccess(ConfigAccessInfo access)
|
|
||||||
{
|
|
||||||
accesss[access.MachineId] = access.Access;
|
|
||||||
Version.Add();
|
|
||||||
}
|
|
||||||
public void SetAccess(ConfigUpdateAccessInfo info)
|
public void SetAccess(ConfigUpdateAccessInfo info)
|
||||||
{
|
{
|
||||||
//我的权限删掉它的权限==0,说明它至少拥有我的全部权限,我是它的子集,它有权管我
|
//我的权限删掉它的权限==0,说明它至少拥有我的全部权限,我是它的子集,它有权管我
|
||||||
if (accesss.TryGetValue(info.FromMachineId, out ClientApiAccess access) && ((~access) & fileConfig.Data.Client.Access) == 0)
|
if (accesss.TryGetValue(info.FromMachineId, out ClientApiAccess access) && (~access & fileConfig.Data.Client.Access) == 0)
|
||||||
{
|
{
|
||||||
fileConfig.Data.Client.Access = (ClientApiAccess)info.Access;
|
fileConfig.Data.Client.Access = (ClientApiAccess)info.Access;
|
||||||
fileConfig.Data.Update();
|
fileConfig.Data.Update();
|
||||||
Version.Add();
|
Version.Add();
|
||||||
Sync();
|
GetData();
|
||||||
|
DataVersion.Add();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public ClientApiAccess AssignAccess(ClientApiAccess access)
|
public ClientApiAccess AssignAccess(ClientApiAccess access)
|
||||||
@@ -54,25 +69,5 @@ namespace linker.plugins.config
|
|||||||
return fileConfig.Data.Client.Access & access;
|
return fileConfig.Data.Client.Access & access;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Sync()
|
|
||||||
{
|
|
||||||
ConfigAccessInfo access = GetAccess();
|
|
||||||
sender.SendReply(new MessageRequestWrap
|
|
||||||
{
|
|
||||||
Connection = clientSignInState.Connection,
|
|
||||||
MessengerId = (ushort)ConfigMessengerIds.AccessForward,
|
|
||||||
Timeout = 10000,
|
|
||||||
Payload = MemoryPackSerializer.Serialize(access)
|
|
||||||
}).ContinueWith((result) =>
|
|
||||||
{
|
|
||||||
if (result.Result.Code == MessageResponeCodes.OK)
|
|
||||||
{
|
|
||||||
List<ConfigAccessInfo> list = MemoryPackSerializer.Deserialize<List<ConfigAccessInfo>>(result.Result.Data.Span);
|
|
||||||
accesss = list.ToDictionary(c => c.MachineId, d => d.Access);
|
|
||||||
accesss[access.MachineId] = access.Access;
|
|
||||||
Version.Add();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
215
linker/plugins/access/config/Config.cs
Normal file
215
linker/plugins/access/config/Config.cs
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
using MemoryPack;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace linker.config
|
||||||
|
{
|
||||||
|
public sealed partial class ConfigClientInfo
|
||||||
|
{
|
||||||
|
private Dictionary<string, ClientApiAccessInfo> accesss;
|
||||||
|
public Dictionary<string, ClientApiAccessInfo> Accesss
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (accesss == null)
|
||||||
|
{
|
||||||
|
accesss = new Dictionary<string, ClientApiAccessInfo>();
|
||||||
|
Type enumType = typeof(ClientApiAccess);
|
||||||
|
// 获取所有字段值
|
||||||
|
foreach (var value in Enum.GetValues(enumType))
|
||||||
|
{
|
||||||
|
// 获取字段信息
|
||||||
|
FieldInfo fieldInfo = enumType.GetField(value.ToString());
|
||||||
|
var attribute = fieldInfo.GetCustomAttribute<ClientAccessDisplayAttribute>(false);
|
||||||
|
if (attribute != null)
|
||||||
|
{
|
||||||
|
accesss.TryAdd(fieldInfo.Name, new ClientApiAccessInfo { Text = attribute.Value, Value = (ulong)value });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return accesss;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 管理权限
|
||||||
|
/// </summary>
|
||||||
|
public ClientApiAccess Access { get; set; } = ClientApiAccess.Full;
|
||||||
|
/// <summary>
|
||||||
|
/// 是否拥有某项权限
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="clientManagerAccess"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool HasAccess(ClientApiAccess clientManagerAccess)
|
||||||
|
{
|
||||||
|
return (Access & clientManagerAccess) == clientManagerAccess;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
|
||||||
|
public sealed class ClientApiAccessAttribute : Attribute
|
||||||
|
{
|
||||||
|
public ClientApiAccess Value { get; set; }
|
||||||
|
|
||||||
|
public ClientApiAccessAttribute(ClientApiAccess value)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
|
||||||
|
public sealed class ClientAccessDisplayAttribute : Attribute
|
||||||
|
{
|
||||||
|
public string Value { get; set; }
|
||||||
|
|
||||||
|
public ClientAccessDisplayAttribute(string value)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum ClientApiAccess : ulong
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
[ClientAccessDisplayAttribute("简单管理")]
|
||||||
|
NetManager = 1,
|
||||||
|
[ClientAccessDisplayAttribute("专业管理")]
|
||||||
|
FullManager = 1 << 1,
|
||||||
|
|
||||||
|
[ClientAccessDisplayAttribute("服务器配置")]
|
||||||
|
Config = 1 << 2,
|
||||||
|
|
||||||
|
[ClientAccessDisplayAttribute("日志列表")]
|
||||||
|
LoggerShow = 1 << 3,
|
||||||
|
[ClientAccessDisplayAttribute("日志配置")]
|
||||||
|
LoggerLevel = 1 << 4,
|
||||||
|
|
||||||
|
[ClientAccessDisplayAttribute("修改本机设备名")]
|
||||||
|
RenameSelf = 1 << 5,
|
||||||
|
[ClientAccessDisplayAttribute("修改所有设备名")]
|
||||||
|
RenameOther = 1 << 6,
|
||||||
|
[ClientAccessDisplayAttribute("显示公网信息")]
|
||||||
|
ExternalShow = 1 << 7,
|
||||||
|
|
||||||
|
[ClientAccessDisplayAttribute("升级本机")]
|
||||||
|
UpdateSelf = 1 << 8,
|
||||||
|
[ClientAccessDisplayAttribute("升级所有设备")]
|
||||||
|
UpdateOther = 1 << 9,
|
||||||
|
[ClientAccessDisplayAttribute("升级服务器")]
|
||||||
|
UpdateServer = 1 << 10,
|
||||||
|
|
||||||
|
[ClientAccessDisplayAttribute("开关本机网卡")]
|
||||||
|
TuntapStatusSelf = 1 << 11,
|
||||||
|
[ClientAccessDisplayAttribute("开关所有网卡")]
|
||||||
|
TuntapStatusOther = 1 << 12,
|
||||||
|
[ClientAccessDisplayAttribute("修改本机网卡")]
|
||||||
|
TuntapChangeSelf = 1 << 13,
|
||||||
|
[ClientAccessDisplayAttribute("修改所有网卡")]
|
||||||
|
TuntapChangeOther = 1 << 14,
|
||||||
|
|
||||||
|
[ClientAccessDisplayAttribute("显示本机端口转发")]
|
||||||
|
ForwardShowSelf = 1 << 15,
|
||||||
|
[ClientAccessDisplayAttribute("显示所有设备端口转发")]
|
||||||
|
ForwardShowOther = 1 << 16,
|
||||||
|
[ClientAccessDisplayAttribute("配置本机端口转发")]
|
||||||
|
ForwardSelf = 1 << 17,
|
||||||
|
[ClientAccessDisplayAttribute("配置所有设备端口转发")]
|
||||||
|
ForwardOther = 1 << 18,
|
||||||
|
|
||||||
|
[ClientAccessDisplayAttribute("重启其它设备")]
|
||||||
|
Reboot = 1 << 19,
|
||||||
|
[ClientAccessDisplayAttribute("删除其它设备")]
|
||||||
|
Remove = 1 << 20,
|
||||||
|
|
||||||
|
[ClientAccessDisplayAttribute("修改本机网关")]
|
||||||
|
TunnelChangeSelf = 1 << 21,
|
||||||
|
[ClientAccessDisplayAttribute("修改所有设备网关")]
|
||||||
|
TunnelChangeOther = 1 << 22,
|
||||||
|
[ClientAccessDisplayAttribute("删除隧道连接")]
|
||||||
|
TunnelRemove = 1 << 23,
|
||||||
|
|
||||||
|
[ClientAccessDisplayAttribute("开启管理API")]
|
||||||
|
Api = 1 << 24,
|
||||||
|
[ClientAccessDisplayAttribute("开启管理网页")]
|
||||||
|
Web = 1 << 25,
|
||||||
|
|
||||||
|
[ClientAccessDisplayAttribute("导出配置")]
|
||||||
|
Export = 1 << 26,
|
||||||
|
|
||||||
|
[ClientAccessDisplayAttribute("修改权限")]
|
||||||
|
Access = 1 << 27,
|
||||||
|
|
||||||
|
[ClientAccessDisplayAttribute("修改打洞协议")]
|
||||||
|
Transport = 1 << 28,
|
||||||
|
|
||||||
|
[ClientAccessDisplayAttribute("修改验证参数")]
|
||||||
|
Action = 1 << 29,
|
||||||
|
|
||||||
|
[ClientAccessDisplayAttribute("查看内网穿透流量")]
|
||||||
|
SForwardFlow = 1 << 30,
|
||||||
|
|
||||||
|
[ClientAccessDisplayAttribute("查看中继流量")]
|
||||||
|
RelayFlow = ((ulong)1 << 31),
|
||||||
|
|
||||||
|
[ClientAccessDisplayAttribute("查看信标流量")]
|
||||||
|
SigninFlow = ((ulong)1 << 32),
|
||||||
|
|
||||||
|
[ClientAccessDisplayAttribute("查看流量")]
|
||||||
|
Flow = ((ulong)1 << 33),
|
||||||
|
|
||||||
|
[ClientAccessDisplayAttribute("同步配置")]
|
||||||
|
Sync = ((ulong)1 << 34),
|
||||||
|
|
||||||
|
[ClientAccessDisplayAttribute("配置组网网络")]
|
||||||
|
Lease = ((ulong)1 << 35),
|
||||||
|
|
||||||
|
[ClientAccessDisplayAttribute("开关本机socks5")]
|
||||||
|
Socks5StatusSelf = 1 << 36,
|
||||||
|
[ClientAccessDisplayAttribute("开关所有socks5")]
|
||||||
|
Socks5StatusOther = 1 << 37,
|
||||||
|
[ClientAccessDisplayAttribute("修改本机socks5")]
|
||||||
|
Socks5ChangeSelf = 1 << 38,
|
||||||
|
[ClientAccessDisplayAttribute("修改所有socks5")]
|
||||||
|
Socks5ChangeOther = 1 << 39,
|
||||||
|
|
||||||
|
Full = ulong.MaxValue >> (64 - 52),
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class ClientApiAccessInfo
|
||||||
|
{
|
||||||
|
public ulong Value { get; set; }
|
||||||
|
public string Text { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[MemoryPackable]
|
||||||
|
public sealed partial class ConfigUpdateAccessInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 设备
|
||||||
|
/// </summary>
|
||||||
|
public string FromMachineId { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 设备
|
||||||
|
/// </summary>
|
||||||
|
public string ToMachineId { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 权限
|
||||||
|
/// </summary>
|
||||||
|
public ulong Access { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[MemoryPackable]
|
||||||
|
public sealed partial class ConfigAccessInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 设备
|
||||||
|
/// </summary>
|
||||||
|
public string MachineId { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 权限
|
||||||
|
/// </summary>
|
||||||
|
public ClientApiAccess Access { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
70
linker/plugins/access/messenger/AccessMessenger.cs
Normal file
70
linker/plugins/access/messenger/AccessMessenger.cs
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
using linker.config;
|
||||||
|
using linker.libs;
|
||||||
|
using linker.plugins.client;
|
||||||
|
using linker.plugins.messenger;
|
||||||
|
using linker.plugins.signin.messenger;
|
||||||
|
using MemoryPack;
|
||||||
|
|
||||||
|
namespace linker.plugins.access.messenger
|
||||||
|
{
|
||||||
|
public sealed class AccessServerMessenger : IMessenger
|
||||||
|
{
|
||||||
|
private readonly IMessengerSender sender;
|
||||||
|
private readonly SignCaching signCaching;
|
||||||
|
|
||||||
|
public AccessServerMessenger(IMessengerSender sender, SignCaching signCaching)
|
||||||
|
{
|
||||||
|
this.sender = sender;
|
||||||
|
this.signCaching = signCaching;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MessengerId((ushort)AccessMessengerIds.AccessUpdateForward)]
|
||||||
|
public void AccessUpdateForward(IConnection connection)
|
||||||
|
{
|
||||||
|
ConfigUpdateAccessInfo info = MemoryPackSerializer.Deserialize<ConfigUpdateAccessInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
|
info.FromMachineId = connection.Id;
|
||||||
|
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache) && signCaching.TryGet(info.ToMachineId, out SignCacheInfo cache1) && cache1.GroupId == cache.GroupId)
|
||||||
|
{
|
||||||
|
uint requiestid = connection.ReceiveRequestWrap.RequestId;
|
||||||
|
|
||||||
|
sender.SendReply(new MessageRequestWrap
|
||||||
|
{
|
||||||
|
Connection = cache1.Connection,
|
||||||
|
MessengerId = (ushort)AccessMessengerIds.AccessUpdate,
|
||||||
|
Payload = MemoryPackSerializer.Serialize(info),
|
||||||
|
Timeout = 3000,
|
||||||
|
}).ContinueWith(async (result) =>
|
||||||
|
{
|
||||||
|
await sender.ReplyOnly(new MessageResponseWrap
|
||||||
|
{
|
||||||
|
RequestId = requiestid,
|
||||||
|
Connection = connection,
|
||||||
|
Payload = result.Result.Data
|
||||||
|
}, (ushort)AccessMessengerIds.AccessUpdateForward).ConfigureAwait(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class AccessClientMessenger : IMessenger
|
||||||
|
{
|
||||||
|
private readonly AccessTransfer accessTransfer;
|
||||||
|
private readonly FileConfig fileConfig;
|
||||||
|
private readonly ClientSignInTransfer clientSignInTransfer;
|
||||||
|
|
||||||
|
public AccessClientMessenger(AccessTransfer accessTransfer, FileConfig fileConfig, ClientSignInTransfer clientSignInTransfer)
|
||||||
|
{
|
||||||
|
this.accessTransfer = accessTransfer;
|
||||||
|
this.fileConfig = fileConfig;
|
||||||
|
this.clientSignInTransfer = clientSignInTransfer;
|
||||||
|
}
|
||||||
|
[MessengerId((ushort)AccessMessengerIds.AccessUpdate)]
|
||||||
|
public void AccessUpdate(IConnection connection)
|
||||||
|
{
|
||||||
|
ConfigUpdateAccessInfo info = MemoryPackSerializer.Deserialize<ConfigUpdateAccessInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
|
accessTransfer.SetAccess(info);
|
||||||
|
connection.Write(Helper.TrueArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
linker/plugins/access/messenger/AccessMessengerIds.cs
Normal file
15
linker/plugins/access/messenger/AccessMessengerIds.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
namespace linker.plugins.access.messenger
|
||||||
|
{
|
||||||
|
public enum AccessMessengerIds : ushort
|
||||||
|
{
|
||||||
|
Min = 2600,
|
||||||
|
|
||||||
|
Access = 2603,
|
||||||
|
AccessForward = 2604,
|
||||||
|
|
||||||
|
AccessUpdate = 2605,
|
||||||
|
AccessUpdateForward = 2606,
|
||||||
|
|
||||||
|
Max = 2699
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
using linker.config;
|
using linker.libs;
|
||||||
using linker.libs;
|
|
||||||
using linker.libs.extends;
|
using linker.libs.extends;
|
||||||
using LiteDB;
|
|
||||||
using MemoryPack;
|
using MemoryPack;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@@ -24,45 +22,6 @@ namespace linker.config
|
|||||||
accesss?.Clear();
|
accesss?.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Dictionary<string, ClientApiAccessInfo> accesss;
|
|
||||||
public Dictionary<string, ClientApiAccessInfo> Accesss
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (accesss == null)
|
|
||||||
{
|
|
||||||
accesss = new Dictionary<string, ClientApiAccessInfo>();
|
|
||||||
Type enumType = typeof(ClientApiAccess);
|
|
||||||
// 获取所有字段值
|
|
||||||
foreach (var value in Enum.GetValues(enumType))
|
|
||||||
{
|
|
||||||
// 获取字段信息
|
|
||||||
FieldInfo fieldInfo = enumType.GetField(value.ToString());
|
|
||||||
var attribute = fieldInfo.GetCustomAttribute<ClientAccessDisplayAttribute>(false);
|
|
||||||
if (attribute != null)
|
|
||||||
{
|
|
||||||
accesss.TryAdd(fieldInfo.Name, new ClientApiAccessInfo { Text = attribute.Value, Value = (ulong)value });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return accesss;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// 管理权限
|
|
||||||
/// </summary>
|
|
||||||
public ClientApiAccess Access { get; set; } = ClientApiAccess.Full;
|
|
||||||
/// <summary>
|
|
||||||
/// 是否拥有某项权限
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="clientManagerAccess"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool HasAccess(ClientApiAccess clientManagerAccess)
|
|
||||||
{
|
|
||||||
return (Access & clientManagerAccess) == clientManagerAccess;
|
|
||||||
}
|
|
||||||
public bool OnlyNode { get; set; }
|
public bool OnlyNode { get; set; }
|
||||||
|
|
||||||
|
|
||||||
@@ -138,10 +97,6 @@ namespace linker.config
|
|||||||
return Encoding.UTF8.GetString(crypto.Decode(Convert.FromBase64String(text)).ToArray()).DeJson<ConfigClientInfo>();
|
return Encoding.UTF8.GetString(crypto.Decode(Convert.FromBase64String(text)).ToArray()).DeJson<ConfigClientInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ToGroupString()
|
|
||||||
{
|
|
||||||
return $"{name}->{Group.Id}->{Group.Password}";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MemoryPackable]
|
[MemoryPackable]
|
||||||
@@ -194,162 +149,4 @@ namespace linker.config
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
|
|
||||||
public sealed class ClientApiAccessAttribute : Attribute
|
|
||||||
{
|
|
||||||
public ClientApiAccess Value { get; set; }
|
|
||||||
|
|
||||||
public ClientApiAccessAttribute(ClientApiAccess value)
|
|
||||||
{
|
|
||||||
Value = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
|
|
||||||
public sealed class ClientAccessDisplayAttribute : Attribute
|
|
||||||
{
|
|
||||||
public string Value { get; set; }
|
|
||||||
|
|
||||||
public ClientAccessDisplayAttribute(string value)
|
|
||||||
{
|
|
||||||
Value = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum ClientApiAccess : ulong
|
|
||||||
{
|
|
||||||
None = 0,
|
|
||||||
|
|
||||||
[ClientAccessDisplayAttribute("简单管理")]
|
|
||||||
NetManager = 1,
|
|
||||||
[ClientAccessDisplayAttribute("专业管理")]
|
|
||||||
FullManager = 1 << 1,
|
|
||||||
|
|
||||||
[ClientAccessDisplayAttribute("服务器配置")]
|
|
||||||
Config = 1 << 2,
|
|
||||||
|
|
||||||
[ClientAccessDisplayAttribute("日志列表")]
|
|
||||||
LoggerShow = 1 << 3,
|
|
||||||
[ClientAccessDisplayAttribute("日志配置")]
|
|
||||||
LoggerLevel = 1 << 4,
|
|
||||||
|
|
||||||
[ClientAccessDisplayAttribute("修改本机设备名")]
|
|
||||||
RenameSelf = 1 << 5,
|
|
||||||
[ClientAccessDisplayAttribute("修改所有设备名")]
|
|
||||||
RenameOther = 1 << 6,
|
|
||||||
[ClientAccessDisplayAttribute("显示公网信息")]
|
|
||||||
ExternalShow = 1 << 7,
|
|
||||||
|
|
||||||
[ClientAccessDisplayAttribute("升级本机")]
|
|
||||||
UpdateSelf = 1 << 8,
|
|
||||||
[ClientAccessDisplayAttribute("升级所有设备")]
|
|
||||||
UpdateOther = 1 << 9,
|
|
||||||
[ClientAccessDisplayAttribute("升级服务器")]
|
|
||||||
UpdateServer = 1 << 10,
|
|
||||||
|
|
||||||
[ClientAccessDisplayAttribute("开关本机网卡")]
|
|
||||||
TuntapStatusSelf = 1 << 11,
|
|
||||||
[ClientAccessDisplayAttribute("开关所有网卡")]
|
|
||||||
TuntapStatusOther = 1 << 12,
|
|
||||||
[ClientAccessDisplayAttribute("修改本机网卡")]
|
|
||||||
TuntapChangeSelf = 1 << 13,
|
|
||||||
[ClientAccessDisplayAttribute("修改所有网卡")]
|
|
||||||
TuntapChangeOther = 1 << 14,
|
|
||||||
|
|
||||||
[ClientAccessDisplayAttribute("显示本机端口转发")]
|
|
||||||
ForwardShowSelf = 1 << 15,
|
|
||||||
[ClientAccessDisplayAttribute("显示所有设备端口转发")]
|
|
||||||
ForwardShowOther = 1 << 16,
|
|
||||||
[ClientAccessDisplayAttribute("配置本机端口转发")]
|
|
||||||
ForwardSelf = 1 << 17,
|
|
||||||
[ClientAccessDisplayAttribute("配置所有设备端口转发")]
|
|
||||||
ForwardOther = 1 << 18,
|
|
||||||
|
|
||||||
[ClientAccessDisplayAttribute("重启其它设备")]
|
|
||||||
Reboot = 1 << 19,
|
|
||||||
[ClientAccessDisplayAttribute("删除其它设备")]
|
|
||||||
Remove = 1 << 20,
|
|
||||||
|
|
||||||
[ClientAccessDisplayAttribute("修改本机网关")]
|
|
||||||
TunnelChangeSelf = 1 << 21,
|
|
||||||
[ClientAccessDisplayAttribute("修改所有设备网关")]
|
|
||||||
TunnelChangeOther = 1 << 22,
|
|
||||||
[ClientAccessDisplayAttribute("删除隧道连接")]
|
|
||||||
TunnelRemove = 1 << 23,
|
|
||||||
|
|
||||||
[ClientAccessDisplayAttribute("开启管理API")]
|
|
||||||
Api = 1 << 24,
|
|
||||||
[ClientAccessDisplayAttribute("开启管理网页")]
|
|
||||||
Web = 1 << 25,
|
|
||||||
|
|
||||||
[ClientAccessDisplayAttribute("导出配置")]
|
|
||||||
Export = 1 << 26,
|
|
||||||
|
|
||||||
[ClientAccessDisplayAttribute("修改权限")]
|
|
||||||
Access = 1 << 27,
|
|
||||||
|
|
||||||
[ClientAccessDisplayAttribute("修改打洞协议")]
|
|
||||||
Transport = 1 << 28,
|
|
||||||
|
|
||||||
[ClientAccessDisplayAttribute("修改验证参数")]
|
|
||||||
Action = 1 << 29,
|
|
||||||
|
|
||||||
[ClientAccessDisplayAttribute("查看内网穿透流量")]
|
|
||||||
SForwardFlow = 1 << 30,
|
|
||||||
|
|
||||||
[ClientAccessDisplayAttribute("查看中继流量")]
|
|
||||||
RelayFlow = ((ulong)1 << 31),
|
|
||||||
|
|
||||||
[ClientAccessDisplayAttribute("查看信标流量")]
|
|
||||||
SigninFlow = ((ulong)1 << 32),
|
|
||||||
|
|
||||||
[ClientAccessDisplayAttribute("查看流量")]
|
|
||||||
Flow = ((ulong)1 << 33),
|
|
||||||
|
|
||||||
[ClientAccessDisplayAttribute("同步配置")]
|
|
||||||
Sync = ((ulong)1 << 34),
|
|
||||||
|
|
||||||
[ClientAccessDisplayAttribute("配置组网网络")]
|
|
||||||
Lease = ((ulong)1 << 35),
|
|
||||||
|
|
||||||
Full = ulong.MaxValue >> (64 - 52),
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ClientApiAccessInfo
|
|
||||||
{
|
|
||||||
public ulong Value { get; set; }
|
|
||||||
public string Text { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[MemoryPackable]
|
|
||||||
public sealed partial class ConfigUpdateAccessInfo
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 设备
|
|
||||||
/// </summary>
|
|
||||||
public string FromMachineId { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// 设备
|
|
||||||
/// </summary>
|
|
||||||
public string ToMachineId { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// 权限
|
|
||||||
/// </summary>
|
|
||||||
public ulong Access { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[MemoryPackable]
|
|
||||||
public sealed partial class ConfigAccessInfo
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 设备
|
|
||||||
/// </summary>
|
|
||||||
public string MachineId { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// 权限
|
|
||||||
/// </summary>
|
|
||||||
public ClientApiAccess Access { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,7 @@ using System.IO.Compression;
|
|||||||
using linker.libs;
|
using linker.libs;
|
||||||
using linker.plugins.client;
|
using linker.plugins.client;
|
||||||
using linker.plugins.messenger;
|
using linker.plugins.messenger;
|
||||||
using linker.plugins.config.messenger;
|
using linker.plugins.access;
|
||||||
using MemoryPack;
|
|
||||||
|
|
||||||
namespace linker.plugins.config
|
namespace linker.plugins.config
|
||||||
{
|
{
|
||||||
public sealed class ConfigClientApiController : IApiClientController
|
public sealed class ConfigClientApiController : IApiClientController
|
||||||
@@ -19,18 +17,18 @@ namespace linker.plugins.config
|
|||||||
private readonly ClientSignInTransfer clientSignInTransfer;
|
private readonly ClientSignInTransfer clientSignInTransfer;
|
||||||
private readonly IMessengerSender sender;
|
private readonly IMessengerSender sender;
|
||||||
private readonly ClientSignInState clientSignInState;
|
private readonly ClientSignInState clientSignInState;
|
||||||
private readonly AccessTransfer accessTransfer;
|
|
||||||
private readonly ConfigSyncTreansfer configSyncTreansfer;
|
private readonly ConfigSyncTreansfer configSyncTreansfer;
|
||||||
|
private readonly AccessTransfer accessTransfer;
|
||||||
|
|
||||||
public ConfigClientApiController(RunningConfig runningConfig, FileConfig config, ClientSignInTransfer clientSignInTransfer, IMessengerSender sender, ClientSignInState clientSignInState, AccessTransfer accessTransfer, ConfigSyncTreansfer configSyncTreansfer)
|
public ConfigClientApiController(RunningConfig runningConfig, FileConfig config, ClientSignInTransfer clientSignInTransfer, IMessengerSender sender, ClientSignInState clientSignInState, ConfigSyncTreansfer configSyncTreansfer, AccessTransfer accessTransfer)
|
||||||
{
|
{
|
||||||
this.runningConfig = runningConfig;
|
this.runningConfig = runningConfig;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.clientSignInTransfer = clientSignInTransfer;
|
this.clientSignInTransfer = clientSignInTransfer;
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
this.clientSignInState = clientSignInState;
|
this.clientSignInState = clientSignInState;
|
||||||
this.accessTransfer = accessTransfer;
|
|
||||||
this.configSyncTreansfer = configSyncTreansfer;
|
this.configSyncTreansfer = configSyncTreansfer;
|
||||||
|
this.accessTransfer = accessTransfer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Get(ApiControllerParamsInfo param)
|
public object Get(ApiControllerParamsInfo param)
|
||||||
@@ -87,40 +85,6 @@ namespace linker.plugins.config
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public AccessListInfo GetAccesss(ApiControllerParamsInfo param)
|
|
||||||
{
|
|
||||||
ulong hashCode = ulong.Parse(param.Content);
|
|
||||||
if (accessTransfer.Version.Eq(hashCode, out ulong version) == false)
|
|
||||||
{
|
|
||||||
return new AccessListInfo
|
|
||||||
{
|
|
||||||
|
|
||||||
HashCode = version,
|
|
||||||
List = accessTransfer.GetAccesss()
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return new AccessListInfo { HashCode = version };
|
|
||||||
}
|
|
||||||
[ClientApiAccessAttribute(ClientApiAccess.Access)]
|
|
||||||
public async Task<bool> SetAccess(ApiControllerParamsInfo param)
|
|
||||||
{
|
|
||||||
ConfigUpdateAccessInfo configUpdateAccessInfo = param.Content.DeJson<ConfigUpdateAccessInfo>();
|
|
||||||
if (configUpdateAccessInfo.ToMachineId == config.Data.Client.Id)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
configUpdateAccessInfo.FromMachineId = config.Data.Client.Id;
|
|
||||||
MessageResponeInfo resp = await sender.SendReply(new MessageRequestWrap
|
|
||||||
{
|
|
||||||
Connection = clientSignInState.Connection,
|
|
||||||
MessengerId = (ushort)ConfigMessengerIds.AccessUpdateForward,
|
|
||||||
Payload = MemoryPackSerializer.Serialize(configUpdateAccessInfo)
|
|
||||||
});
|
|
||||||
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[ClientApiAccessAttribute(ClientApiAccess.Export)]
|
[ClientApiAccessAttribute(ClientApiAccess.Export)]
|
||||||
public async Task<bool> Export(ApiControllerParamsInfo param)
|
public async Task<bool> Export(ApiControllerParamsInfo param)
|
||||||
{
|
{
|
||||||
@@ -148,15 +112,18 @@ namespace linker.plugins.config
|
|||||||
Directory.CreateDirectory(configPath);
|
Directory.CreateDirectory(configPath);
|
||||||
|
|
||||||
ConfigClientInfo client = config.Data.Client.ToJson().DeJson<ConfigClientInfo>();
|
ConfigClientInfo client = config.Data.Client.ToJson().DeJson<ConfigClientInfo>();
|
||||||
|
client.Id = string.Empty;
|
||||||
|
client.Name = string.Empty;
|
||||||
if (configExportInfo.Single || client.OnlyNode)
|
if (configExportInfo.Single || client.OnlyNode)
|
||||||
{
|
{
|
||||||
client.Id = await clientSignInTransfer.GetNewId();
|
client.Id = await clientSignInTransfer.GetNewId();
|
||||||
|
client.Name = configExportInfo.Name;
|
||||||
}
|
}
|
||||||
if (client.OnlyNode == false)
|
if (client.OnlyNode == false)
|
||||||
{
|
{
|
||||||
client.CApi.ApiPassword = configExportInfo.ApiPassword;
|
client.CApi.ApiPassword = configExportInfo.ApiPassword;
|
||||||
}
|
}
|
||||||
client.Name = configExportInfo.Name;
|
|
||||||
client.Access = accessTransfer.AssignAccess((ClientApiAccess)configExportInfo.Access);
|
client.Access = accessTransfer.AssignAccess((ClientApiAccess)configExportInfo.Access);
|
||||||
client.OnlyNode = true;
|
client.OnlyNode = true;
|
||||||
client.Action.Args.Clear();
|
client.Action.Args.Clear();
|
||||||
|
|||||||
@@ -26,9 +26,6 @@ namespace linker.plugins.config
|
|||||||
|
|
||||||
serviceCollection.AddSingleton<RunningConfig>();
|
serviceCollection.AddSingleton<RunningConfig>();
|
||||||
|
|
||||||
|
|
||||||
serviceCollection.AddSingleton<AccessTransfer>();
|
|
||||||
|
|
||||||
serviceCollection.AddSingleton<ConfigSyncTreansfer>();
|
serviceCollection.AddSingleton<ConfigSyncTreansfer>();
|
||||||
serviceCollection.AddSingleton<ConfigSyncTypesLoader>();
|
serviceCollection.AddSingleton<ConfigSyncTypesLoader>();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
using linker.config;
|
using linker.plugins.messenger;
|
||||||
using linker.libs;
|
|
||||||
using linker.plugins.client;
|
|
||||||
using linker.plugins.messenger;
|
|
||||||
using linker.plugins.signin.messenger;
|
using linker.plugins.signin.messenger;
|
||||||
using MemoryPack;
|
using MemoryPack;
|
||||||
|
|
||||||
@@ -18,69 +15,6 @@ namespace linker.plugins.config.messenger
|
|||||||
this.signCaching = signCaching;
|
this.signCaching = signCaching;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MessengerId((ushort)ConfigMessengerIds.AccessForward)]
|
|
||||||
public void AccessForward(IConnection connection)
|
|
||||||
{
|
|
||||||
ConfigAccessInfo info = MemoryPackSerializer.Deserialize<ConfigAccessInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
|
||||||
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache))
|
|
||||||
{
|
|
||||||
uint requiestid = connection.ReceiveRequestWrap.RequestId;
|
|
||||||
|
|
||||||
List<SignCacheInfo> caches = signCaching.Get(cache.GroupId);
|
|
||||||
List<Task<MessageResponeInfo>> tasks = new List<Task<MessageResponeInfo>>();
|
|
||||||
foreach (SignCacheInfo item in caches.Where(c => c.MachineId != connection.Id && c.Connected))
|
|
||||||
{
|
|
||||||
tasks.Add(sender.SendReply(new MessageRequestWrap
|
|
||||||
{
|
|
||||||
Connection = item.Connection,
|
|
||||||
MessengerId = (ushort)ConfigMessengerIds.Access,
|
|
||||||
Payload = connection.ReceiveRequestWrap.Payload,
|
|
||||||
Timeout = 1000,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
Task.WhenAll(tasks).ContinueWith(async (result) =>
|
|
||||||
{
|
|
||||||
List<ConfigAccessInfo> results = tasks.Where(c => c.Result.Code == MessageResponeCodes.OK)
|
|
||||||
.Select(c => MemoryPackSerializer.Deserialize<ConfigAccessInfo>(c.Result.Data.Span)).ToList();
|
|
||||||
|
|
||||||
await sender.ReplyOnly(new MessageResponseWrap
|
|
||||||
{
|
|
||||||
RequestId = requiestid,
|
|
||||||
Connection = connection,
|
|
||||||
Payload = MemoryPackSerializer.Serialize(results)
|
|
||||||
},(ushort)ConfigMessengerIds.AccessForward).ConfigureAwait(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[MessengerId((ushort)ConfigMessengerIds.AccessUpdateForward)]
|
|
||||||
public void AccessUpdateForward(IConnection connection)
|
|
||||||
{
|
|
||||||
ConfigUpdateAccessInfo info = MemoryPackSerializer.Deserialize<ConfigUpdateAccessInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
|
||||||
info.FromMachineId = connection.Id;
|
|
||||||
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache) && signCaching.TryGet(info.ToMachineId, out SignCacheInfo cache1) && cache1.GroupId == cache.GroupId)
|
|
||||||
{
|
|
||||||
uint requiestid = connection.ReceiveRequestWrap.RequestId;
|
|
||||||
|
|
||||||
sender.SendReply(new MessageRequestWrap
|
|
||||||
{
|
|
||||||
Connection = cache1.Connection,
|
|
||||||
MessengerId = (ushort)ConfigMessengerIds.AccessUpdate,
|
|
||||||
Payload = MemoryPackSerializer.Serialize(info),
|
|
||||||
Timeout = 3000,
|
|
||||||
}).ContinueWith(async (result) =>
|
|
||||||
{
|
|
||||||
await sender.ReplyOnly(new MessageResponseWrap
|
|
||||||
{
|
|
||||||
RequestId = requiestid,
|
|
||||||
Connection = connection,
|
|
||||||
Payload = result.Result.Data
|
|
||||||
}, (ushort)ConfigMessengerIds.AccessUpdateForward).ConfigureAwait(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[MessengerId((ushort)ConfigMessengerIds.SyncForward)]
|
[MessengerId((ushort)ConfigMessengerIds.SyncForward)]
|
||||||
public async Task SyncForward(IConnection connection)
|
public async Task SyncForward(IConnection connection)
|
||||||
@@ -108,35 +42,13 @@ namespace linker.plugins.config.messenger
|
|||||||
|
|
||||||
public sealed class ConfigClientMessenger : IMessenger
|
public sealed class ConfigClientMessenger : IMessenger
|
||||||
{
|
{
|
||||||
private readonly AccessTransfer accessTransfer;
|
|
||||||
private readonly FileConfig fileConfig;
|
|
||||||
private readonly ClientSignInTransfer clientSignInTransfer;
|
|
||||||
private readonly ConfigSyncTreansfer syncTreansfer;
|
private readonly ConfigSyncTreansfer syncTreansfer;
|
||||||
|
|
||||||
public ConfigClientMessenger(AccessTransfer accessTransfer, FileConfig fileConfig, ClientSignInTransfer clientSignInTransfer, ConfigSyncTreansfer syncTreansfer)
|
public ConfigClientMessenger(ConfigSyncTreansfer syncTreansfer)
|
||||||
{
|
{
|
||||||
this.accessTransfer = accessTransfer;
|
|
||||||
this.fileConfig = fileConfig;
|
|
||||||
this.clientSignInTransfer = clientSignInTransfer;
|
|
||||||
this.syncTreansfer = syncTreansfer;
|
this.syncTreansfer = syncTreansfer;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MessengerId((ushort)ConfigMessengerIds.Access)]
|
|
||||||
public void Access(IConnection connection)
|
|
||||||
{
|
|
||||||
ConfigAccessInfo info = MemoryPackSerializer.Deserialize<ConfigAccessInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
|
||||||
accessTransfer.SetAccess(info);
|
|
||||||
connection.Write(MemoryPackSerializer.Serialize((accessTransfer.GetAccess())));
|
|
||||||
}
|
|
||||||
|
|
||||||
[MessengerId((ushort)ConfigMessengerIds.AccessUpdate)]
|
|
||||||
public void AccessUpdate(IConnection connection)
|
|
||||||
{
|
|
||||||
ConfigUpdateAccessInfo info = MemoryPackSerializer.Deserialize<ConfigUpdateAccessInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
|
||||||
accessTransfer.SetAccess(info);
|
|
||||||
connection.Write(Helper.TrueArray);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MessengerId((ushort)ConfigMessengerIds.Sync)]
|
[MessengerId((ushort)ConfigMessengerIds.Sync)]
|
||||||
public void Sync(IConnection connection)
|
public void Sync(IConnection connection)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,15 +4,6 @@
|
|||||||
{
|
{
|
||||||
Min = 2500,
|
Min = 2500,
|
||||||
|
|
||||||
//Update = 2501,
|
|
||||||
//UpdateForward = 2502,
|
|
||||||
|
|
||||||
Access = 2503,
|
|
||||||
AccessForward = 2504,
|
|
||||||
|
|
||||||
AccessUpdate = 2505,
|
|
||||||
AccessUpdateForward = 2506,
|
|
||||||
|
|
||||||
Sync = 2507,
|
Sync = 2507,
|
||||||
SyncForward = 2508,
|
SyncForward = 2508,
|
||||||
|
|
||||||
|
|||||||
43
linker/plugins/decenter/DecenterStartup.cs
Normal file
43
linker/plugins/decenter/DecenterStartup.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
using linker.config;
|
||||||
|
using linker.plugins.config.messenger;
|
||||||
|
using linker.startup;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace linker.plugins.decenter
|
||||||
|
{
|
||||||
|
public sealed class DecenterStartup : IStartup
|
||||||
|
{
|
||||||
|
public string Name => "decenter";
|
||||||
|
|
||||||
|
public bool Required => true;
|
||||||
|
|
||||||
|
public StartupLevel Level => StartupLevel.Top;
|
||||||
|
|
||||||
|
public string[] Dependent => new string[] { "messenger", "signin", "serialize" };
|
||||||
|
|
||||||
|
public StartupLoadType LoadType => StartupLoadType.Normal;
|
||||||
|
|
||||||
|
public void AddClient(ServiceCollection serviceCollection, FileConfig config)
|
||||||
|
{
|
||||||
|
serviceCollection.AddSingleton<DecenterTransfer>();
|
||||||
|
serviceCollection.AddSingleton<DecenterTypesLoader>();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddServer(ServiceCollection serviceCollection, FileConfig config)
|
||||||
|
{
|
||||||
|
serviceCollection.AddSingleton<ConfigServerMessenger>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UseClient(ServiceProvider serviceProvider, FileConfig config)
|
||||||
|
{
|
||||||
|
DecenterTransfer decenterTransfer = serviceProvider.GetService<DecenterTransfer>();
|
||||||
|
DecenterTypesLoader decenterTypesLoader = serviceProvider.GetService<DecenterTypesLoader>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UseServer(ServiceProvider serviceProvider, FileConfig config)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
83
linker/plugins/decenter/DecenterTransfer.cs
Normal file
83
linker/plugins/decenter/DecenterTransfer.cs
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
using linker.plugins.client;
|
||||||
|
using linker.plugins.messenger;
|
||||||
|
using MemoryPack;
|
||||||
|
using linker.libs;
|
||||||
|
using linker.plugins.decenter.messenger;
|
||||||
|
|
||||||
|
namespace linker.plugins.decenter
|
||||||
|
{
|
||||||
|
|
||||||
|
[MemoryPackable]
|
||||||
|
public sealed partial class DecenterSyncInfo
|
||||||
|
{
|
||||||
|
public DecenterSyncInfo() { }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public Memory<byte> Data { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class DecenterTransfer
|
||||||
|
{
|
||||||
|
private List<IDecenter> syncs = new List<IDecenter>();
|
||||||
|
|
||||||
|
private readonly IMessengerSender messengerSender;
|
||||||
|
private readonly ClientSignInState clientSignInState;
|
||||||
|
public DecenterTransfer(IMessengerSender messengerSender, ClientSignInState clientSignInState)
|
||||||
|
{
|
||||||
|
this.messengerSender = messengerSender;
|
||||||
|
this.clientSignInState = clientSignInState;
|
||||||
|
SyncTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadDecenters(List<IDecenter> list)
|
||||||
|
{
|
||||||
|
syncs = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Memory<byte> Sync(DecenterSyncInfo decenterSyncInfo)
|
||||||
|
{
|
||||||
|
IDecenter sync = syncs.FirstOrDefault(c => c.Name == decenterSyncInfo.Name);
|
||||||
|
if (sync != null)
|
||||||
|
{
|
||||||
|
sync.SetData(decenterSyncInfo.Data);
|
||||||
|
return sync.GetData();
|
||||||
|
}
|
||||||
|
return Helper.EmptyArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SyncTask()
|
||||||
|
{
|
||||||
|
TimerHelper.SetInterval(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (var sync in syncs)
|
||||||
|
{
|
||||||
|
if (sync.DataVersion.Reset())
|
||||||
|
{
|
||||||
|
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
|
||||||
|
{
|
||||||
|
Connection = clientSignInState.Connection,
|
||||||
|
MessengerId = (ushort)DecenterMessengerIds.SyncForward,
|
||||||
|
Payload = MemoryPackSerializer.Serialize(new DecenterSyncInfo { Name = sync.Name, Data = sync.GetData() })
|
||||||
|
});
|
||||||
|
if (resp.Code == MessageResponeCodes.OK)
|
||||||
|
{
|
||||||
|
sync.SetData(MemoryPackSerializer.Deserialize<List<ReadOnlyMemory<byte>>>(resp.Data.Span));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||||
|
{
|
||||||
|
LoggerHelper.Instance.Error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}, () => 3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
linker/plugins/decenter/DecenterTypesLoader.cs
Normal file
17
linker/plugins/decenter/DecenterTypesLoader.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using linker.libs;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace linker.plugins.decenter
|
||||||
|
{
|
||||||
|
public sealed partial class DecenterTypesLoader
|
||||||
|
{
|
||||||
|
public DecenterTypesLoader(DecenterTransfer decenterTransfer, ServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
var types = GetSourceGeneratorTypes();
|
||||||
|
var syncs = types.Select(c => (IDecenter)serviceProvider.GetService(c)).Where(c => c != null).ToList();
|
||||||
|
decenterTransfer.LoadDecenters(syncs);
|
||||||
|
|
||||||
|
LoggerHelper.Instance.Info($"load decenter transport:{string.Join(",", syncs.Select(c => c.GetType().Name))}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
linker/plugins/decenter/IDecenter.cs
Normal file
13
linker/plugins/decenter/IDecenter.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using linker.libs;
|
||||||
|
|
||||||
|
namespace linker.plugins.decenter
|
||||||
|
{
|
||||||
|
public interface IDecenter
|
||||||
|
{
|
||||||
|
public string Name { get; }
|
||||||
|
public VersionManager DataVersion { get; }
|
||||||
|
public Memory<byte> GetData();
|
||||||
|
public void SetData(Memory<byte> data);
|
||||||
|
public void SetData(List<ReadOnlyMemory<byte>> data);
|
||||||
|
}
|
||||||
|
}
|
||||||
74
linker/plugins/decenter/messenger/DecenterMessenger.cs
Normal file
74
linker/plugins/decenter/messenger/DecenterMessenger.cs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
using linker.plugins.messenger;
|
||||||
|
using linker.plugins.signin.messenger;
|
||||||
|
using MemoryPack;
|
||||||
|
|
||||||
|
namespace linker.plugins.decenter.messenger
|
||||||
|
{
|
||||||
|
public sealed class DecenterServerMessenger : IMessenger
|
||||||
|
{
|
||||||
|
private readonly IMessengerSender sender;
|
||||||
|
private readonly SignCaching signCaching;
|
||||||
|
|
||||||
|
public DecenterServerMessenger(IMessengerSender sender, SignCaching signCaching)
|
||||||
|
{
|
||||||
|
this.sender = sender;
|
||||||
|
this.signCaching = signCaching;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[MessengerId((ushort)DecenterMessengerIds.SyncForward)]
|
||||||
|
public void SyncForward(IConnection connection)
|
||||||
|
{
|
||||||
|
DecenterSyncInfo info = MemoryPackSerializer.Deserialize<DecenterSyncInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
|
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache))
|
||||||
|
{
|
||||||
|
uint requiestid = connection.ReceiveRequestWrap.RequestId;
|
||||||
|
|
||||||
|
List<SignCacheInfo> caches = signCaching.Get(cache.GroupId);
|
||||||
|
List<Task<MessageResponeInfo>> tasks = new List<Task<MessageResponeInfo>>();
|
||||||
|
foreach (SignCacheInfo item in caches.Where(c => c.MachineId != connection.Id && c.Connected))
|
||||||
|
{
|
||||||
|
tasks.Add(sender.SendReply(new MessageRequestWrap
|
||||||
|
{
|
||||||
|
Connection = item.Connection,
|
||||||
|
MessengerId = (ushort)DecenterMessengerIds.Sync,
|
||||||
|
Payload = connection.ReceiveRequestWrap.Payload,
|
||||||
|
Timeout = 1000,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
Task.WhenAll(tasks).ContinueWith(async (result) =>
|
||||||
|
{
|
||||||
|
List<ReadOnlyMemory<byte>> results = tasks.Where(c => c.Result.Code == MessageResponeCodes.OK)
|
||||||
|
.Select(c => c.Result.Data).ToList();
|
||||||
|
|
||||||
|
await sender.ReplyOnly(new MessageResponseWrap
|
||||||
|
{
|
||||||
|
RequestId = requiestid,
|
||||||
|
Connection = connection,
|
||||||
|
Payload = MemoryPackSerializer.Serialize(results)
|
||||||
|
}, (ushort)DecenterMessengerIds.SyncForward).ConfigureAwait(false);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class DecenterClientMessenger : IMessenger
|
||||||
|
{
|
||||||
|
private readonly DecenterTransfer syncTreansfer;
|
||||||
|
|
||||||
|
public DecenterClientMessenger(DecenterTransfer syncTreansfer)
|
||||||
|
{
|
||||||
|
this.syncTreansfer = syncTreansfer;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MessengerId((ushort)DecenterMessengerIds.Sync)]
|
||||||
|
public void Sync(IConnection connection)
|
||||||
|
{
|
||||||
|
DecenterSyncInfo info = MemoryPackSerializer.Deserialize<DecenterSyncInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
|
syncTreansfer.Sync(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
12
linker/plugins/decenter/messenger/DecenterMessengerIds.cs
Normal file
12
linker/plugins/decenter/messenger/DecenterMessengerIds.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
namespace linker.plugins.decenter.messenger
|
||||||
|
{
|
||||||
|
public enum DecenterMessengerIds : ushort
|
||||||
|
{
|
||||||
|
Min = 2800,
|
||||||
|
|
||||||
|
Sync = 2807,
|
||||||
|
SyncForward = 2808,
|
||||||
|
|
||||||
|
Max = 2899
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ using System.Net.Sockets;
|
|||||||
using linker.libs.extends;
|
using linker.libs.extends;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using linker.plugins.messenger;
|
||||||
|
|
||||||
namespace linker.plugins.resolver
|
namespace linker.plugins.resolver
|
||||||
{
|
{
|
||||||
@@ -31,6 +32,7 @@ namespace linker.plugins.resolver
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
LoggerHelper.Instance.Info($"tcp connect from {socket.RemoteEndPoint}");
|
||||||
socket.KeepAlive();
|
socket.KeepAlive();
|
||||||
|
|
||||||
int length = await socket.ReceiveAsync(buffer.AsMemory(0, 1), SocketFlags.None).ConfigureAwait(false);
|
int length = await socket.ReceiveAsync(buffer.AsMemory(0, 1), SocketFlags.None).ConfigureAwait(false);
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ namespace linker.plugins.signIn.args
|
|||||||
//之前的登录有唯一编号的,则验证,唯一编号不一样,不允许登录
|
//之前的登录有唯一编号的,则验证,唯一编号不一样,不允许登录
|
||||||
if (string.IsNullOrWhiteSpace(keyOld) == false && keyNew != keyOld)
|
if (string.IsNullOrWhiteSpace(keyOld) == false && keyNew != keyOld)
|
||||||
{
|
{
|
||||||
return "your machine key is already online";
|
return $"your id 【{signInfo.MachineId}】 is already online, online machineName {cache.MachineName}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ namespace linker.plugins.signin.messenger
|
|||||||
public async Task SignIn(IConnection connection)
|
public async Task SignIn(IConnection connection)
|
||||||
{
|
{
|
||||||
SignInfo info = MemoryPackSerializer.Deserialize<SignInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
SignInfo info = MemoryPackSerializer.Deserialize<SignInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
|
LoggerHelper.Instance.Info($"sign in from {connection.Address}->{info.ToJson()}");
|
||||||
|
|
||||||
info.Connection = connection;
|
info.Connection = connection;
|
||||||
|
|
||||||
SignInResponseInfo resp = new SignInResponseInfo();
|
SignInResponseInfo resp = new SignInResponseInfo();
|
||||||
|
|||||||
176
linker/plugins/socks5/Socks5ApiController.cs
Normal file
176
linker/plugins/socks5/Socks5ApiController.cs
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
using linker.libs.api;
|
||||||
|
using MemoryPack;
|
||||||
|
using linker.libs.extends;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using linker.config;
|
||||||
|
using linker.tunnel.connection;
|
||||||
|
using linker.plugins.client;
|
||||||
|
using linker.plugins.capi;
|
||||||
|
using linker.plugins.messenger;
|
||||||
|
using linker.client.config;
|
||||||
|
using linker.plugins.socks5.config;
|
||||||
|
using linker.plugins.socks5.messenger;
|
||||||
|
|
||||||
|
namespace linker.plugins.socks5
|
||||||
|
{
|
||||||
|
public sealed class Socks5ClientApiController : IApiClientController
|
||||||
|
{
|
||||||
|
private readonly IMessengerSender messengerSender;
|
||||||
|
private readonly Socks5ConfigTransfer socks5ConfigTransfer;
|
||||||
|
private readonly ClientSignInState clientSignInState;
|
||||||
|
private readonly FileConfig config;
|
||||||
|
private readonly TunnelProxy tunnelProxy;
|
||||||
|
private readonly RunningConfig runningConfig;
|
||||||
|
|
||||||
|
|
||||||
|
public Socks5ClientApiController(IMessengerSender messengerSender, Socks5ConfigTransfer socks5ConfigTransfer, ClientSignInState clientSignInState, FileConfig config, TunnelProxy tunnelProxy, RunningConfig runningConfig, Socks5ConfigTransfer Socks5ConfigTransfer)
|
||||||
|
{
|
||||||
|
this.messengerSender = messengerSender;
|
||||||
|
this.socks5ConfigTransfer = socks5ConfigTransfer;
|
||||||
|
this.clientSignInState = clientSignInState;
|
||||||
|
this.config = config;
|
||||||
|
this.tunnelProxy = tunnelProxy;
|
||||||
|
this.runningConfig = runningConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConnectionListInfo Connections(ApiControllerParamsInfo param)
|
||||||
|
{
|
||||||
|
ulong hashCode = ulong.Parse(param.Content);
|
||||||
|
if (tunnelProxy.Version.Eq(hashCode, out ulong version) == false)
|
||||||
|
{
|
||||||
|
return new ConnectionListInfo
|
||||||
|
{
|
||||||
|
List = tunnelProxy.GetConnections(),
|
||||||
|
HashCode = version
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return new ConnectionListInfo { HashCode = version };
|
||||||
|
}
|
||||||
|
|
||||||
|
[ClientApiAccess(ClientApiAccess.TunnelRemove)]
|
||||||
|
public void RemoveConnection(ApiControllerParamsInfo param)
|
||||||
|
{
|
||||||
|
tunnelProxy.RemoveConnection(param.Content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取所有客户端的信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="param"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Socks5ListInfo Get(ApiControllerParamsInfo param)
|
||||||
|
{
|
||||||
|
ulong hashCode = ulong.Parse(param.Content);
|
||||||
|
if (socks5ConfigTransfer.Version.Eq(hashCode, out ulong version) == false)
|
||||||
|
{
|
||||||
|
return new Socks5ListInfo
|
||||||
|
{
|
||||||
|
List = socks5ConfigTransfer.Infos,
|
||||||
|
HashCode = version
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return new Socks5ListInfo { HashCode = version };
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 刷新信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="param"></param>
|
||||||
|
public void Refresh(ApiControllerParamsInfo param)
|
||||||
|
{
|
||||||
|
socks5ConfigTransfer.RefreshConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 运行网卡
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="param"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<bool> Run(ApiControllerParamsInfo param)
|
||||||
|
{
|
||||||
|
//运行自己的
|
||||||
|
if (param.Content == config.Data.Client.Id)
|
||||||
|
{
|
||||||
|
if (config.Data.Client.HasAccess(ClientApiAccess.Socks5StatusSelf) == false) return false;
|
||||||
|
|
||||||
|
socks5ConfigTransfer.Retstart();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (config.Data.Client.HasAccess(ClientApiAccess.Socks5StatusOther) == false) return false;
|
||||||
|
//运行别人的
|
||||||
|
await messengerSender.SendOnly(new MessageRequestWrap
|
||||||
|
{
|
||||||
|
Connection = clientSignInState.Connection,
|
||||||
|
MessengerId = (ushort)Socks5MessengerIds.RunForward,
|
||||||
|
Payload = MemoryPackSerializer.Serialize(param.Content)
|
||||||
|
}).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 停止网卡
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="param"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<bool> Stop(ApiControllerParamsInfo param)
|
||||||
|
{
|
||||||
|
//停止自己的
|
||||||
|
if (param.Content == config.Data.Client.Id)
|
||||||
|
{
|
||||||
|
if (config.Data.Client.HasAccess(ClientApiAccess.Socks5StatusSelf) == false) return false;
|
||||||
|
socks5ConfigTransfer.Stop();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (config.Data.Client.HasAccess(ClientApiAccess.Socks5StatusOther) == false) return false;
|
||||||
|
//停止别人的
|
||||||
|
await messengerSender.SendOnly(new MessageRequestWrap
|
||||||
|
{
|
||||||
|
Connection = clientSignInState.Connection,
|
||||||
|
MessengerId = (ushort)Socks5MessengerIds.StopForward,
|
||||||
|
Payload = MemoryPackSerializer.Serialize(param.Content)
|
||||||
|
}).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新网卡信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="param"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<bool> Update(ApiControllerParamsInfo param)
|
||||||
|
{
|
||||||
|
|
||||||
|
Socks5Info info = param.Content.DeJson<Socks5Info>();
|
||||||
|
//更新自己的
|
||||||
|
if (info.MachineId == config.Data.Client.Id)
|
||||||
|
{
|
||||||
|
if (config.Data.Client.HasAccess(ClientApiAccess.Socks5ChangeSelf) == false) return false;
|
||||||
|
socks5ConfigTransfer.UpdateConfig(info);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (config.Data.Client.HasAccess(ClientApiAccess.Socks5ChangeOther) == false) return false;
|
||||||
|
//更新别人的
|
||||||
|
await messengerSender.SendOnly(new MessageRequestWrap
|
||||||
|
{
|
||||||
|
Connection = clientSignInState.Connection,
|
||||||
|
MessengerId = (ushort)Socks5MessengerIds.UpdateForward,
|
||||||
|
Payload = MemoryPackSerializer.Serialize(info)
|
||||||
|
}).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public sealed class Socks5ListInfo
|
||||||
|
{
|
||||||
|
public ConcurrentDictionary<string, Socks5Info> List { get; set; }
|
||||||
|
public ulong HashCode { get; set; }
|
||||||
|
}
|
||||||
|
public sealed class ConnectionListInfo
|
||||||
|
{
|
||||||
|
public ConcurrentDictionary<string, ITunnelConnection> List { get; set; }
|
||||||
|
public ulong HashCode { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
248
linker/plugins/socks5/Socks5ConfigTransfer.cs
Normal file
248
linker/plugins/socks5/Socks5ConfigTransfer.cs
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
using linker.client.config;
|
||||||
|
using linker.config;
|
||||||
|
using linker.libs;
|
||||||
|
using MemoryPack;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Net;
|
||||||
|
using linker.plugins.client;
|
||||||
|
using linker.plugins.messenger;
|
||||||
|
using linker.plugins.socks5.config;
|
||||||
|
using linker.plugins.decenter;
|
||||||
|
|
||||||
|
namespace linker.plugins.socks5
|
||||||
|
{
|
||||||
|
public sealed class Socks5ConfigTransfer : IDecenter
|
||||||
|
{
|
||||||
|
public string Name => "socks5";
|
||||||
|
public VersionManager DataVersion { get; } = new VersionManager();
|
||||||
|
|
||||||
|
|
||||||
|
private readonly IMessengerSender messengerSender;
|
||||||
|
private readonly ClientSignInState clientSignInState;
|
||||||
|
private readonly FileConfig config;
|
||||||
|
private readonly RunningConfig runningConfig;
|
||||||
|
private readonly TunnelProxy tunnelProxy;
|
||||||
|
|
||||||
|
public VersionManager Version { get; } = new VersionManager();
|
||||||
|
private readonly ConcurrentDictionary<string, Socks5Info> socks5Infos = new ConcurrentDictionary<string, Socks5Info>();
|
||||||
|
public ConcurrentDictionary<string, Socks5Info> Infos => socks5Infos;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private readonly SemaphoreSlim slim = new SemaphoreSlim(1);
|
||||||
|
public Socks5ConfigTransfer(IMessengerSender messengerSender, ClientSignInState clientSignInState, FileConfig config, RunningConfig runningConfig, TunnelProxy tunnelProxy)
|
||||||
|
{
|
||||||
|
this.messengerSender = messengerSender;
|
||||||
|
this.clientSignInState = clientSignInState;
|
||||||
|
this.config = config;
|
||||||
|
this.runningConfig = runningConfig;
|
||||||
|
this.tunnelProxy = tunnelProxy;
|
||||||
|
|
||||||
|
clientSignInState.NetworkEnabledHandle += (times) => DataVersion.Add();
|
||||||
|
}
|
||||||
|
public Memory<byte> GetData()
|
||||||
|
{
|
||||||
|
Socks5Info info = new Socks5Info
|
||||||
|
{
|
||||||
|
Lans = runningConfig.Data.Socks5.Lans.Select(c => { c.Exists = false; return c; }).ToList(),
|
||||||
|
MachineId = config.Data.Client.Id,
|
||||||
|
Status = tunnelProxy.Running ? Socks5Status.Running : Socks5Status.Normal,
|
||||||
|
Port = runningConfig.Data.Socks5.Port,
|
||||||
|
SetupError = tunnelProxy.Error
|
||||||
|
};
|
||||||
|
socks5Infos.AddOrUpdate(info.MachineId, info, (a, b) => info);
|
||||||
|
Version.Add();
|
||||||
|
return MemoryPackSerializer.Serialize(info);
|
||||||
|
}
|
||||||
|
public void SetData(Memory<byte> data)
|
||||||
|
{
|
||||||
|
Socks5Info info = MemoryPackSerializer.Deserialize<Socks5Info>(data.Span);
|
||||||
|
TimerHelper.Async(async () =>
|
||||||
|
{
|
||||||
|
await slim.WaitAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
socks5Infos.AddOrUpdate(info.MachineId, info, (a, b) => info);
|
||||||
|
Version.Add();
|
||||||
|
AddRoute();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||||
|
{
|
||||||
|
LoggerHelper.Instance.Error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slim.Release();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public void SetData(List<ReadOnlyMemory<byte>> data)
|
||||||
|
{
|
||||||
|
List<Socks5Info> list = data.Select(c => MemoryPackSerializer.Deserialize<Socks5Info>(c.Span)).ToList();
|
||||||
|
TimerHelper.Async(async () =>
|
||||||
|
{
|
||||||
|
await slim.WaitAsync();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (var item in list)
|
||||||
|
{
|
||||||
|
socks5Infos.AddOrUpdate(item.MachineId, item, (a, b) => item);
|
||||||
|
item.LastTicks.Update();
|
||||||
|
}
|
||||||
|
var removes = socks5Infos.Keys.Except(list.Select(c => c.MachineId)).ToList();
|
||||||
|
foreach (var item in removes)
|
||||||
|
{
|
||||||
|
if (socks5Infos.TryGetValue(item, out Socks5Info socks5Info))
|
||||||
|
{
|
||||||
|
socks5Info.Status = Socks5Status.Normal;
|
||||||
|
socks5Info.LastTicks.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Version.Add();
|
||||||
|
AddRoute();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||||
|
{
|
||||||
|
LoggerHelper.Instance.Error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
slim.Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重启
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public void Retstart()
|
||||||
|
{
|
||||||
|
tunnelProxy.Start(runningConfig.Data.Socks5.Port);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 网卡
|
||||||
|
/// </summary>
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
tunnelProxy.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 刷新信息,把自己的配置发给别人,顺便把别人的信息带回来
|
||||||
|
/// </summary>
|
||||||
|
public void RefreshConfig()
|
||||||
|
{
|
||||||
|
DataVersion.Add();
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 更新本机信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="info"></param>
|
||||||
|
public void UpdateConfig(Socks5Info info)
|
||||||
|
{
|
||||||
|
TimerHelper.Async(() =>
|
||||||
|
{
|
||||||
|
int port = runningConfig.Data.Socks5.Port;
|
||||||
|
|
||||||
|
runningConfig.Data.Socks5.Port = info.Port;
|
||||||
|
runningConfig.Data.Socks5.Lans = info.Lans;
|
||||||
|
runningConfig.Data.Update();
|
||||||
|
|
||||||
|
bool needReboot = (port != runningConfig.Data.Socks5.Port && runningConfig.Data.Socks5.Running)
|
||||||
|
|| (runningConfig.Data.Socks5.Running && tunnelProxy.Running == false);
|
||||||
|
|
||||||
|
if (needReboot)
|
||||||
|
{
|
||||||
|
Retstart();
|
||||||
|
}
|
||||||
|
GetData();
|
||||||
|
DataVersion.Add();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加路由
|
||||||
|
/// </summary>
|
||||||
|
private void AddRoute()
|
||||||
|
{
|
||||||
|
List<Socks5LanIPAddressList> ipsList = ParseIPs(socks5Infos.Values.ToList());
|
||||||
|
Socks5LanIPAddress[] ips = ipsList.SelectMany(c => c.IPS).ToArray();
|
||||||
|
|
||||||
|
tunnelProxy.SetIPs(ips);
|
||||||
|
Version.Add();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Socks5LanIPAddressList> ParseIPs(List<Socks5Info> infos)
|
||||||
|
{
|
||||||
|
//排除的IP,
|
||||||
|
uint[] excludeIps =//本机局域网IP
|
||||||
|
config.Data.Client.Tunnel.LocalIPs.Where(c => c.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
|
||||||
|
//路由上的IP
|
||||||
|
.Concat(config.Data.Client.Tunnel.RouteIPs)
|
||||||
|
//网卡IP 服务器IP
|
||||||
|
.Concat(new IPAddress[] { runningConfig.Data.Tuntap.IP, clientSignInState.Connection.Address.Address })
|
||||||
|
//网卡配置的局域网IP
|
||||||
|
.Concat(runningConfig.Data.Socks5.Lans.Select(c => c.IP))
|
||||||
|
.Select(NetworkHelper.IP2Value)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
HashSet<uint> hashSet = new HashSet<uint>();
|
||||||
|
|
||||||
|
return infos
|
||||||
|
.Where(c => c.MachineId != config.Data.Client.Id)
|
||||||
|
.OrderByDescending(c => c.Status)
|
||||||
|
.OrderByDescending(c => c.LastTicks.Value)
|
||||||
|
|
||||||
|
.Select(c =>
|
||||||
|
{
|
||||||
|
var lans = c.Lans.Where(c => c.Disabled == false && c.IP.Equals(IPAddress.Any) == false);
|
||||||
|
foreach (var lan in lans)
|
||||||
|
{
|
||||||
|
uint ipInt = NetworkHelper.IP2Value(lan.IP);
|
||||||
|
uint maskValue = NetworkHelper.PrefixLength2Value(lan.PrefixLength);
|
||||||
|
lan.Exists = excludeIps.Count(d => (d & maskValue) == (ipInt & maskValue)) > 0 || hashSet.Contains(ipInt & maskValue);
|
||||||
|
hashSet.Add(ipInt & maskValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Socks5LanIPAddressList
|
||||||
|
{
|
||||||
|
MachineId = c.MachineId,
|
||||||
|
IPS = ParseIPs(lans.Where(c => c.Disabled == false && c.Exists == false).ToList(), c.MachineId)
|
||||||
|
.Where(c => excludeIps.Select(d => d & c.MaskValue).Contains(c.NetWork) == false).ToList(),
|
||||||
|
};
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
|
private List<Socks5LanIPAddress> ParseIPs(List<Socks5LanInfo> lans, string machineid)
|
||||||
|
{
|
||||||
|
return lans.Where(c => c.IP.Equals(IPAddress.Any) == false && c != null).Select((c, index) =>
|
||||||
|
{
|
||||||
|
return ParseIPAddress(c.IP, c.PrefixLength, machineid);
|
||||||
|
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
|
private Socks5LanIPAddress ParseIPAddress(IPAddress ip, byte prefixLength, string machineid)
|
||||||
|
{
|
||||||
|
uint ipInt = NetworkHelper.IP2Value(ip);
|
||||||
|
//掩码十进制
|
||||||
|
uint maskValue = NetworkHelper.PrefixLength2Value(prefixLength);
|
||||||
|
return new Socks5LanIPAddress
|
||||||
|
{
|
||||||
|
IPAddress = ipInt,
|
||||||
|
PrefixLength = prefixLength,
|
||||||
|
MaskValue = maskValue,
|
||||||
|
NetWork = ipInt & maskValue,
|
||||||
|
Broadcast = ipInt | ~maskValue,
|
||||||
|
OriginIPAddress = ip,
|
||||||
|
MachineId = machineid
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ using System.Net;
|
|||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using linker.plugins.tunnel;
|
using linker.plugins.tunnel;
|
||||||
using linker.plugins.client;
|
using linker.plugins.client;
|
||||||
|
using linker.plugins.socks5.config;
|
||||||
|
|
||||||
namespace linker.plugins.socks5
|
namespace linker.plugins.socks5
|
||||||
{
|
{
|
||||||
@@ -18,7 +19,9 @@ namespace linker.plugins.socks5
|
|||||||
private IPEndPoint proxyEP;
|
private IPEndPoint proxyEP;
|
||||||
|
|
||||||
private uint[] maskValues = Array.Empty<uint>();
|
private uint[] maskValues = Array.Empty<uint>();
|
||||||
private readonly ConcurrentDictionary<uint, string> dic = new ConcurrentDictionary<uint, string>();
|
private readonly ConcurrentDictionary<uint, List<string>> ip2MachineDic = new ConcurrentDictionary<uint, List<string>>();
|
||||||
|
|
||||||
|
protected override string TransactionId => "socks5";
|
||||||
|
|
||||||
public TunnelProxy(FileConfig config, TunnelTransfer tunnelTransfer, RelayTransfer relayTransfer, ClientSignInTransfer clientSignInTransfer, ClientSignInState clientSignInState)
|
public TunnelProxy(FileConfig config, TunnelTransfer tunnelTransfer, RelayTransfer relayTransfer, ClientSignInTransfer clientSignInTransfer, ClientSignInState clientSignInState)
|
||||||
: base(config, tunnelTransfer, relayTransfer, clientSignInTransfer, clientSignInState)
|
: base(config, tunnelTransfer, relayTransfer, clientSignInTransfer, clientSignInState)
|
||||||
@@ -26,13 +29,44 @@ namespace linker.plugins.socks5
|
|||||||
TaskUdp();
|
TaskUdp();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置IP,等下有连接进来,用IP匹配,才能知道这个连接是要连谁
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ips"></param>
|
||||||
|
public void SetIPs(Socks5LanIPAddress[] ips)
|
||||||
|
{
|
||||||
|
var dic = ips.GroupBy(c => c.NetWork).ToDictionary(c => c.Key, d => d.Select(e => e.MachineId).ToList());
|
||||||
|
foreach (var item in dic)
|
||||||
|
{
|
||||||
|
ip2MachineDic.AddOrUpdate(item.Key, item.Value, (a, b) => item.Value);
|
||||||
|
}
|
||||||
|
maskValues = ips.Select(c => c.MaskValue).Distinct().OrderBy(c => c).ToArray();
|
||||||
|
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 设置IP,等下有连接进来,用IP匹配,才能知道这个连接是要连谁
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="machineId"></param>
|
||||||
|
/// <param name="ip"></param>
|
||||||
|
public void SetIP(string machineId, uint ip)
|
||||||
|
{
|
||||||
|
if (ip2MachineDic.TryGetValue(ip, out List<string> list) == false)
|
||||||
|
{
|
||||||
|
list = new List<string>();
|
||||||
|
ip2MachineDic.AddOrUpdate(ip, list, (a, b) => list);
|
||||||
|
}
|
||||||
|
list.Add(machineId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Start(int port)
|
||||||
{
|
{
|
||||||
if (proxyEP != null)
|
if (proxyEP != null)
|
||||||
{
|
{
|
||||||
Stop(proxyEP.Port);
|
Stop(proxyEP.Port);
|
||||||
}
|
}
|
||||||
Start(new IPEndPoint(IPAddress.Any, 0), 3);
|
Start(new IPEndPoint(IPAddress.Any, port), 3);
|
||||||
proxyEP = new IPEndPoint(IPAddress.Any, LocalEndpoint.Port);
|
proxyEP = new IPEndPoint(IPAddress.Any, LocalEndpoint.Port);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,9 +209,9 @@ namespace linker.plugins.socks5
|
|||||||
for (int i = 0; i < maskValues.Length; i++)
|
for (int i = 0; i < maskValues.Length; i++)
|
||||||
{
|
{
|
||||||
uint network = ip & maskValues[i];
|
uint network = ip & maskValues[i];
|
||||||
if (dic.TryGetValue(network, out string machineId))
|
if (ip2MachineDic.TryGetValue(network, out List<string> machineId))
|
||||||
{
|
{
|
||||||
return await ConnectTunnel(machineId, TunnelProtocolType.Udp).ConfigureAwait(false);
|
return await ConnectTunnel(machineId[0], TunnelProtocolType.Udp).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
50
linker/plugins/socks5/Socks5Startup.cs
Normal file
50
linker/plugins/socks5/Socks5Startup.cs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
using linker.config;
|
||||||
|
using linker.plugins.socks5;
|
||||||
|
using linker.plugins.socks5.messenger;
|
||||||
|
using linker.startup;
|
||||||
|
using linker.tun;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace linker.plugins.Socks5
|
||||||
|
{
|
||||||
|
public sealed class Socks5Startup : IStartup
|
||||||
|
{
|
||||||
|
public StartupLevel Level => StartupLevel.Normal;
|
||||||
|
public string Name => "socks5";
|
||||||
|
public bool Required => false;
|
||||||
|
public string[] Dependent => new string[] { "messenger", "relay", "tunnel", "signin", "serialize", "config" };
|
||||||
|
|
||||||
|
public StartupLoadType LoadType => StartupLoadType.Normal;
|
||||||
|
|
||||||
|
|
||||||
|
public void AddClient(ServiceCollection serviceCollection, FileConfig config)
|
||||||
|
{
|
||||||
|
serviceCollection.AddSingleton<Socks5ClientApiController>();
|
||||||
|
serviceCollection.AddSingleton<LinkerTunDeviceAdapter>();
|
||||||
|
serviceCollection.AddSingleton<TunnelProxy>();
|
||||||
|
|
||||||
|
serviceCollection.AddSingleton<Socks5ClientMessenger>();
|
||||||
|
|
||||||
|
serviceCollection.AddSingleton<Socks5ConfigTransfer>();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddServer(ServiceCollection serviceCollection, FileConfig config)
|
||||||
|
{
|
||||||
|
serviceCollection.AddSingleton<Socks5ServerMessenger>();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UseClient(ServiceProvider serviceProvider, FileConfig config)
|
||||||
|
{
|
||||||
|
TunnelProxy socks5Proxy = serviceProvider.GetService<TunnelProxy>();
|
||||||
|
|
||||||
|
Socks5ConfigTransfer socks5ConfigTransfer = serviceProvider.GetService<Socks5ConfigTransfer>();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UseServer(ServiceProvider serviceProvider, FileConfig config)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,12 +15,16 @@ namespace linker.plugins.socks5
|
|||||||
private Socket socket;
|
private Socket socket;
|
||||||
public IPEndPoint LocalEndpoint { get; private set; }
|
public IPEndPoint LocalEndpoint { get; private set; }
|
||||||
|
|
||||||
|
public bool Running { get; private set; }
|
||||||
|
public string Error { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 监听一个端口
|
/// 监听一个端口
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="port"></param>
|
/// <param name="port"></param>
|
||||||
private void StartTcp(IPEndPoint ep, byte bufferSize)
|
private void StartTcp(IPEndPoint ep, byte bufferSize)
|
||||||
{
|
{
|
||||||
|
Error = string.Empty;
|
||||||
IPEndPoint _localEndPoint = ep;
|
IPEndPoint _localEndPoint = ep;
|
||||||
socket = new Socket(_localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
socket = new Socket(_localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||||
socket.IPv6Only(_localEndPoint.AddressFamily, false);
|
socket.IPv6Only(_localEndPoint.AddressFamily, false);
|
||||||
@@ -41,8 +45,10 @@ namespace linker.plugins.socks5
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
Error = ex.Message;
|
||||||
LoggerHelper.Instance.Error(ex);
|
LoggerHelper.Instance.Error(ex);
|
||||||
}
|
}
|
||||||
|
Running = true;
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 接收连接
|
/// 接收连接
|
||||||
@@ -63,6 +69,7 @@ namespace linker.plugins.socks5
|
|||||||
LoggerHelper.Instance.Error(ex);
|
LoggerHelper.Instance.Error(ex);
|
||||||
token.Clear();
|
token.Clear();
|
||||||
}
|
}
|
||||||
|
Running = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
private void ProcessAccept(AsyncUserToken acceptToken, Socket socket)
|
private void ProcessAccept(AsyncUserToken acceptToken, Socket socket)
|
||||||
|
|||||||
123
linker/plugins/socks5/config/config.cs
Normal file
123
linker/plugins/socks5/config/config.cs
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
using linker.libs;
|
||||||
|
using linker.plugins.socks5.config;
|
||||||
|
using MemoryPack;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace linker.plugins.socks5.config
|
||||||
|
{
|
||||||
|
[MemoryPackable]
|
||||||
|
public sealed partial class Socks5ConfigInfo
|
||||||
|
{
|
||||||
|
public Socks5ConfigInfo() { }
|
||||||
|
public int Port { get; set; } = 1805;
|
||||||
|
/// <summary>
|
||||||
|
/// 局域网配置列表
|
||||||
|
/// </summary>
|
||||||
|
public List<Socks5LanInfo> Lans { get; set; } = new List<Socks5LanInfo>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否在运行中
|
||||||
|
/// </summary>
|
||||||
|
public bool Running { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[MemoryPackable]
|
||||||
|
public sealed partial class Socks5LanIPAddress
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ip,存小端
|
||||||
|
/// </summary>
|
||||||
|
public uint IPAddress { get; set; }
|
||||||
|
public byte PrefixLength { get; set; }
|
||||||
|
public uint MaskValue { get; set; }
|
||||||
|
public uint NetWork { get; set; }
|
||||||
|
public uint Broadcast { get; set; }
|
||||||
|
|
||||||
|
[MemoryPackIgnore]
|
||||||
|
public string MachineId { get; set; }
|
||||||
|
|
||||||
|
[MemoryPackIgnore]
|
||||||
|
public IPAddress OriginIPAddress { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
[MemoryPackable]
|
||||||
|
public sealed partial class Socks5LanIPAddressList
|
||||||
|
{
|
||||||
|
public string MachineId { get; set; }
|
||||||
|
public List<Socks5LanIPAddress> IPS { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[MemoryPackable]
|
||||||
|
public sealed partial class Socks5Info
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 设备id
|
||||||
|
/// </summary>
|
||||||
|
public string MachineId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 状态
|
||||||
|
/// </summary>
|
||||||
|
public Socks5Status Status { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 前缀长度
|
||||||
|
/// </summary>
|
||||||
|
public int Port { get; set; } = 1804;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 局域网IP列表
|
||||||
|
/// </summary>
|
||||||
|
public List<Socks5LanInfo> Lans { get; set; } = new List<Socks5LanInfo>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 安装错误
|
||||||
|
/// </summary>
|
||||||
|
public string SetupError { get; set; }
|
||||||
|
|
||||||
|
[MemoryPackIgnore]
|
||||||
|
public LastTicksManager LastTicks { get; set; } = new LastTicksManager();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[MemoryPackable]
|
||||||
|
public sealed partial class Socks5LanInfo
|
||||||
|
{
|
||||||
|
[MemoryPackAllowSerialize]
|
||||||
|
public IPAddress IP { get; set; }
|
||||||
|
public byte PrefixLength { get; set; } = 24;
|
||||||
|
public bool Disabled { get; set; }
|
||||||
|
public bool Exists { get; set; }
|
||||||
|
public string Error { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Socks5Status : byte
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 无
|
||||||
|
/// </summary>
|
||||||
|
Normal = 0,
|
||||||
|
/// <summary>
|
||||||
|
/// 操作中
|
||||||
|
/// </summary>
|
||||||
|
Operating = 1,
|
||||||
|
/// <summary>
|
||||||
|
/// 运行中
|
||||||
|
/// </summary>
|
||||||
|
Running = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace linker.client.config
|
||||||
|
{
|
||||||
|
public sealed partial class RunningConfigInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 虚拟网卡配置
|
||||||
|
/// </summary>
|
||||||
|
public Socks5ConfigInfo Socks5 { get; set; } = new Socks5ConfigInfo();
|
||||||
|
}
|
||||||
|
}
|
||||||
127
linker/plugins/socks5/messenger/Socks5Messenger.cs
Normal file
127
linker/plugins/socks5/messenger/Socks5Messenger.cs
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
using linker.config;
|
||||||
|
using linker.plugins.messenger;
|
||||||
|
using linker.plugins.signin.messenger;
|
||||||
|
using linker.plugins.socks5.config;
|
||||||
|
using MemoryPack;
|
||||||
|
|
||||||
|
namespace linker.plugins.socks5.messenger
|
||||||
|
{
|
||||||
|
public sealed class Socks5ClientMessenger : IMessenger
|
||||||
|
{
|
||||||
|
private readonly Socks5ConfigTransfer socks5ConfigTransfer;
|
||||||
|
private readonly TunnelProxy socks5Proxy;
|
||||||
|
public Socks5ClientMessenger(Socks5ConfigTransfer socks5ConfigTransfer, TunnelProxy socks5Proxy)
|
||||||
|
{
|
||||||
|
this.socks5ConfigTransfer = socks5ConfigTransfer;
|
||||||
|
this.socks5Proxy = socks5Proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 运行
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="connection"></param>
|
||||||
|
[MessengerId((ushort)Socks5MessengerIds.Run)]
|
||||||
|
public void Run(IConnection connection)
|
||||||
|
{
|
||||||
|
socks5ConfigTransfer.Retstart();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 停止
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="connection"></param>
|
||||||
|
[MessengerId((ushort)Socks5MessengerIds.Stop)]
|
||||||
|
public void Stop(IConnection connection)
|
||||||
|
{
|
||||||
|
socks5ConfigTransfer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="connection"></param>
|
||||||
|
[MessengerId((ushort)Socks5MessengerIds.Update)]
|
||||||
|
public void Update(IConnection connection)
|
||||||
|
{
|
||||||
|
Socks5Info info = MemoryPackSerializer.Deserialize<Socks5Info>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
|
socks5ConfigTransfer.UpdateConfig(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public sealed class Socks5ServerMessenger : IMessenger
|
||||||
|
{
|
||||||
|
private readonly IMessengerSender messengerSender;
|
||||||
|
private readonly SignCaching signCaching;
|
||||||
|
private readonly FileConfig config;
|
||||||
|
|
||||||
|
public Socks5ServerMessenger(IMessengerSender messengerSender, SignCaching signCaching, FileConfig config)
|
||||||
|
{
|
||||||
|
this.messengerSender = messengerSender;
|
||||||
|
this.signCaching = signCaching;
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 转发运行命令
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="connection"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[MessengerId((ushort)Socks5MessengerIds.RunForward)]
|
||||||
|
public async Task RunForward(IConnection connection)
|
||||||
|
{
|
||||||
|
string name = MemoryPackSerializer.Deserialize<string>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
|
if (signCaching.TryGet(name, out SignCacheInfo cache) && signCaching.TryGet(connection.Id, out SignCacheInfo cache1) && cache.GroupId == cache1.GroupId)
|
||||||
|
{
|
||||||
|
await messengerSender.SendOnly(new MessageRequestWrap
|
||||||
|
{
|
||||||
|
Connection = cache.Connection,
|
||||||
|
Timeout = 3000,
|
||||||
|
MessengerId = (ushort)Socks5MessengerIds.Run
|
||||||
|
}).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 转发停止命令
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="connection"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[MessengerId((ushort)Socks5MessengerIds.StopForward)]
|
||||||
|
public async Task StopForward(IConnection connection)
|
||||||
|
{
|
||||||
|
string name = MemoryPackSerializer.Deserialize<string>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
|
if (signCaching.TryGet(name, out SignCacheInfo cache) && signCaching.TryGet(connection.Id, out SignCacheInfo cache1) && cache.GroupId == cache1.GroupId)
|
||||||
|
{
|
||||||
|
await messengerSender.SendOnly(new MessageRequestWrap
|
||||||
|
{
|
||||||
|
Connection = cache.Connection,
|
||||||
|
Timeout = 3000,
|
||||||
|
MessengerId = (ushort)Socks5MessengerIds.Stop
|
||||||
|
}).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 转发更新信息命令
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="connection"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[MessengerId((ushort)Socks5MessengerIds.UpdateForward)]
|
||||||
|
public async Task UpdateForward(IConnection connection)
|
||||||
|
{
|
||||||
|
Socks5Info info = MemoryPackSerializer.Deserialize<Socks5Info>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
|
if (signCaching.TryGet(info.MachineId, out SignCacheInfo cache) && signCaching.TryGet(connection.Id, out SignCacheInfo cache1) && cache.GroupId == cache1.GroupId)
|
||||||
|
{
|
||||||
|
await messengerSender.SendOnly(new MessageRequestWrap
|
||||||
|
{
|
||||||
|
Connection = cache.Connection,
|
||||||
|
Timeout = 3000,
|
||||||
|
MessengerId = (ushort)Socks5MessengerIds.Update,
|
||||||
|
Payload = connection.ReceiveRequestWrap.Payload
|
||||||
|
}).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
linker/plugins/socks5/messenger/Socks5MessengerIds.cs
Normal file
17
linker/plugins/socks5/messenger/Socks5MessengerIds.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
namespace linker.plugins.socks5.messenger
|
||||||
|
{
|
||||||
|
public enum Socks5MessengerIds : ushort
|
||||||
|
{
|
||||||
|
Run = 2900,
|
||||||
|
RunForward = 2901,
|
||||||
|
|
||||||
|
Stop = 2902,
|
||||||
|
StopForward = 2903,
|
||||||
|
|
||||||
|
Update = 2904,
|
||||||
|
UpdateForward = 2905,
|
||||||
|
|
||||||
|
|
||||||
|
None = 2999
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,11 +2,11 @@
|
|||||||
using linker.config;
|
using linker.config;
|
||||||
using linker.libs;
|
using linker.libs;
|
||||||
using linker.plugins.client;
|
using linker.plugins.client;
|
||||||
|
using linker.plugins.decenter;
|
||||||
using linker.plugins.messenger;
|
using linker.plugins.messenger;
|
||||||
using linker.plugins.tunnel.messenger;
|
using linker.plugins.tunnel.messenger;
|
||||||
using linker.tunnel;
|
using linker.tunnel;
|
||||||
using linker.tunnel.adapter;
|
using linker.tunnel.adapter;
|
||||||
using linker.tunnel.wanport;
|
|
||||||
using MemoryPack;
|
using MemoryPack;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
@@ -14,8 +14,12 @@ using System.Net.Quic;
|
|||||||
|
|
||||||
namespace linker.plugins.tunnel
|
namespace linker.plugins.tunnel
|
||||||
{
|
{
|
||||||
public sealed class TunnelConfigTransfer
|
public sealed class TunnelConfigTransfer:IDecenter
|
||||||
{
|
{
|
||||||
|
public string Name => "tunnel";
|
||||||
|
public VersionManager DataVersion { get; } = new VersionManager();
|
||||||
|
|
||||||
|
|
||||||
private readonly FileConfig config;
|
private readonly FileConfig config;
|
||||||
private readonly RunningConfig running;
|
private readonly RunningConfig running;
|
||||||
private readonly ClientSignInState clientSignInState;
|
private readonly ClientSignInState clientSignInState;
|
||||||
@@ -26,6 +30,8 @@ namespace linker.plugins.tunnel
|
|||||||
public VersionManager Version { get; } = new VersionManager();
|
public VersionManager Version { get; } = new VersionManager();
|
||||||
public ConcurrentDictionary<string, TunnelTransportRouteLevelInfo> Config { get; } = new ConcurrentDictionary<string, TunnelTransportRouteLevelInfo>();
|
public ConcurrentDictionary<string, TunnelTransportRouteLevelInfo> Config { get; } = new ConcurrentDictionary<string, TunnelTransportRouteLevelInfo>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public TunnelConfigTransfer(FileConfig config, RunningConfig running, ClientSignInState clientSignInState, IMessengerSender messengerSender, ITunnelAdapter tunnelAdapter, TunnelUpnpTransfer upnpTransfer)
|
public TunnelConfigTransfer(FileConfig config, RunningConfig running, ClientSignInState clientSignInState, IMessengerSender messengerSender, ITunnelAdapter tunnelAdapter, TunnelUpnpTransfer upnpTransfer)
|
||||||
{
|
{
|
||||||
this.config = config;
|
this.config = config;
|
||||||
@@ -38,12 +44,40 @@ namespace linker.plugins.tunnel
|
|||||||
clientSignInState.NetworkEnabledHandle += (times) =>
|
clientSignInState.NetworkEnabledHandle += (times) =>
|
||||||
{
|
{
|
||||||
RefreshRouteLevel();
|
RefreshRouteLevel();
|
||||||
GetRemoteRouteLevel();
|
DataVersion.Add();
|
||||||
RefreshPortMap();
|
RefreshPortMap();
|
||||||
};
|
};
|
||||||
TestQuic();
|
TestQuic();
|
||||||
}
|
}
|
||||||
|
public Memory<byte> GetData()
|
||||||
|
{
|
||||||
|
TunnelTransportRouteLevelInfo tunnelTransportRouteLevelInfo = GetLocalRouteLevel();
|
||||||
|
Config.AddOrUpdate(tunnelTransportRouteLevelInfo.MachineId, tunnelTransportRouteLevelInfo, (a, b) => tunnelTransportRouteLevelInfo);
|
||||||
|
Version.Add();
|
||||||
|
return MemoryPackSerializer.Serialize(tunnelTransportRouteLevelInfo);
|
||||||
|
}
|
||||||
|
public void SetData(Memory<byte> data)
|
||||||
|
{
|
||||||
|
TunnelTransportRouteLevelInfo tunnelTransportRouteLevelInfo = MemoryPackSerializer.Deserialize<TunnelTransportRouteLevelInfo>(data.Span);
|
||||||
|
Config.AddOrUpdate(tunnelTransportRouteLevelInfo.MachineId, tunnelTransportRouteLevelInfo, (a, b) => tunnelTransportRouteLevelInfo);
|
||||||
|
Version.Add();
|
||||||
|
}
|
||||||
|
public void SetData(List<ReadOnlyMemory<byte>> data)
|
||||||
|
{
|
||||||
|
List<TunnelTransportRouteLevelInfo> list = data.Select(c => MemoryPackSerializer.Deserialize<TunnelTransportRouteLevelInfo>(c.Span)).ToList();
|
||||||
|
foreach (var item in list)
|
||||||
|
{
|
||||||
|
Config.AddOrUpdate(item.MachineId, item, (a, b) => item);
|
||||||
|
}
|
||||||
|
TunnelTransportRouteLevelInfo config = GetLocalRouteLevel();
|
||||||
|
Config.AddOrUpdate(config.MachineId, config, (a, b) => config);
|
||||||
|
Version.Add();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 刷新网关等级数据
|
||||||
|
/// </summary>
|
||||||
private void RefreshRouteLevel()
|
private void RefreshRouteLevel()
|
||||||
{
|
{
|
||||||
TimerHelper.Async(() =>
|
TimerHelper.Async(() =>
|
||||||
@@ -59,7 +93,7 @@ namespace linker.plugins.tunnel
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void RefreshConfig()
|
public void RefreshConfig()
|
||||||
{
|
{
|
||||||
GetRemoteRouteLevel();
|
DataVersion.Add();
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 修改自己的网关层级信息
|
/// 修改自己的网关层级信息
|
||||||
@@ -71,42 +105,8 @@ namespace linker.plugins.tunnel
|
|||||||
running.Data.Tunnel.PortMapWan = tunnelTransportFileConfigInfo.PortMapWan;
|
running.Data.Tunnel.PortMapWan = tunnelTransportFileConfigInfo.PortMapWan;
|
||||||
running.Data.Tunnel.PortMapLan = tunnelTransportFileConfigInfo.PortMapLan;
|
running.Data.Tunnel.PortMapLan = tunnelTransportFileConfigInfo.PortMapLan;
|
||||||
running.Data.Update();
|
running.Data.Update();
|
||||||
GetRemoteRouteLevel();
|
GetData();
|
||||||
}
|
DataVersion.Add();
|
||||||
/// <summary>
|
|
||||||
/// 收到别人的信息
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tunnelTransportFileConfigInfo"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public TunnelTransportRouteLevelInfo OnRemoteRouteLevel(TunnelTransportRouteLevelInfo tunnelTransportFileConfigInfo)
|
|
||||||
{
|
|
||||||
Config.AddOrUpdate(tunnelTransportFileConfigInfo.MachineId, tunnelTransportFileConfigInfo, (a, b) => tunnelTransportFileConfigInfo);
|
|
||||||
Version.Add();
|
|
||||||
return GetLocalRouteLevel();
|
|
||||||
}
|
|
||||||
private void GetRemoteRouteLevel()
|
|
||||||
{
|
|
||||||
TunnelTransportRouteLevelInfo config = GetLocalRouteLevel();
|
|
||||||
messengerSender.SendReply(new MessageRequestWrap
|
|
||||||
{
|
|
||||||
Connection = clientSignInState.Connection,
|
|
||||||
MessengerId = (ushort)TunnelMessengerIds.ConfigForward,
|
|
||||||
Timeout = 10000,
|
|
||||||
Payload = MemoryPackSerializer.Serialize(config)
|
|
||||||
}).ContinueWith((result) =>
|
|
||||||
{
|
|
||||||
if (result.Result.Code == MessageResponeCodes.OK)
|
|
||||||
{
|
|
||||||
List<TunnelTransportRouteLevelInfo> list = MemoryPackSerializer.Deserialize<List<TunnelTransportRouteLevelInfo>>(result.Result.Data.Span);
|
|
||||||
foreach (var item in list)
|
|
||||||
{
|
|
||||||
Config.AddOrUpdate(item.MachineId, item, (a, b) => item);
|
|
||||||
}
|
|
||||||
TunnelTransportRouteLevelInfo config = GetLocalRouteLevel();
|
|
||||||
Config.AddOrUpdate(config.MachineId, config, (a, b) => config);
|
|
||||||
Version.Add();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
private TunnelTransportRouteLevelInfo GetLocalRouteLevel()
|
private TunnelTransportRouteLevelInfo GetLocalRouteLevel()
|
||||||
{
|
{
|
||||||
@@ -173,5 +173,7 @@ namespace linker.plugins.tunnel
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,15 +95,6 @@ namespace linker.plugins.tunnel.messenger
|
|||||||
tunnelConfigTransfer.OnLocalRouteLevel(tunnelTransportFileConfigInfo);
|
tunnelConfigTransfer.OnLocalRouteLevel(tunnelTransportFileConfigInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MessengerId((ushort)TunnelMessengerIds.Config)]
|
|
||||||
public void Config(IConnection connection)
|
|
||||||
{
|
|
||||||
TunnelTransportRouteLevelInfo tunnelTransportFileConfigInfo = MemoryPackSerializer.Deserialize<TunnelTransportRouteLevelInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
|
||||||
TunnelTransportRouteLevelInfo result = tunnelConfigTransfer.OnRemoteRouteLevel(tunnelTransportFileConfigInfo);
|
|
||||||
connection.Write(MemoryPackSerializer.Serialize(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class TunnelServerMessenger : IMessenger
|
public sealed class TunnelServerMessenger : IMessenger
|
||||||
@@ -219,40 +210,6 @@ namespace linker.plugins.tunnel.messenger
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MessengerId((ushort)TunnelMessengerIds.ConfigForward)]
|
|
||||||
public void ConfigForward(IConnection connection)
|
|
||||||
{
|
|
||||||
TunnelTransportRouteLevelInfo tunnelTransportRouteLevelInfo = MemoryPackSerializer.Deserialize<TunnelTransportRouteLevelInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
|
||||||
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache))
|
|
||||||
{
|
|
||||||
uint requestid = connection.ReceiveRequestWrap.RequestId;
|
|
||||||
|
|
||||||
List<SignCacheInfo> caches = signCaching.Get(cache.GroupId);
|
|
||||||
List<Task<MessageResponeInfo>> tasks = new List<Task<MessageResponeInfo>>();
|
|
||||||
foreach (SignCacheInfo item in caches.Where(c => c.MachineId != connection.Id && c.Connected))
|
|
||||||
{
|
|
||||||
tasks.Add(messengerSender.SendReply(new MessageRequestWrap
|
|
||||||
{
|
|
||||||
Connection = item.Connection,
|
|
||||||
MessengerId = (ushort)TunnelMessengerIds.Config,
|
|
||||||
Timeout = 3000,
|
|
||||||
Payload = connection.ReceiveRequestWrap.Payload
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
Task.WhenAll(tasks).ContinueWith(async (result) =>
|
|
||||||
{
|
|
||||||
List<TunnelTransportRouteLevelInfo> results = tasks.Where(c => c.Result.Code == MessageResponeCodes.OK).Select(c => MemoryPackSerializer.Deserialize<TunnelTransportRouteLevelInfo>(c.Result.Data.Span)).ToList();
|
|
||||||
await messengerSender.ReplyOnly(new MessageResponseWrap
|
|
||||||
{
|
|
||||||
Connection = connection,
|
|
||||||
Payload = MemoryPackSerializer.Serialize(results),
|
|
||||||
RequestId = requestid,
|
|
||||||
}, (ushort)TunnelMessengerIds.ConfigForward).ConfigureAwait(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MemoryPackable]
|
[MemoryPackable]
|
||||||
|
|||||||
@@ -16,9 +16,6 @@
|
|||||||
Success = 2007,
|
Success = 2007,
|
||||||
SuccessForward = 2008,
|
SuccessForward = 2008,
|
||||||
|
|
||||||
Config = 2009,
|
|
||||||
ConfigForward = 2010,
|
|
||||||
|
|
||||||
RouteLevel = 2011,
|
RouteLevel = 2011,
|
||||||
RouteLevelForward = 2012,
|
RouteLevelForward = 2012,
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,16 @@ using linker.plugins.messenger;
|
|||||||
using linker.plugins.tuntap.config;
|
using linker.plugins.tuntap.config;
|
||||||
using linker.tun;
|
using linker.tun;
|
||||||
using linker.plugins.tuntap.lease;
|
using linker.plugins.tuntap.lease;
|
||||||
|
using linker.plugins.decenter;
|
||||||
|
|
||||||
namespace linker.plugins.tuntap.client
|
namespace linker.plugins.tuntap.client
|
||||||
{
|
{
|
||||||
public sealed class TuntapConfigTransfer
|
public sealed class TuntapConfigTransfer : IDecenter
|
||||||
{
|
{
|
||||||
|
public string Name => "tuntap";
|
||||||
|
public VersionManager DataVersion { get; } = new VersionManager();
|
||||||
|
|
||||||
|
|
||||||
private readonly IMessengerSender messengerSender;
|
private readonly IMessengerSender messengerSender;
|
||||||
private readonly ClientSignInState clientSignInState;
|
private readonly ClientSignInState clientSignInState;
|
||||||
private readonly FileConfig config;
|
private readonly FileConfig config;
|
||||||
@@ -29,6 +34,8 @@ namespace linker.plugins.tuntap.client
|
|||||||
private readonly ConcurrentDictionary<string, TuntapInfo> tuntapInfos = new ConcurrentDictionary<string, TuntapInfo>();
|
private readonly ConcurrentDictionary<string, TuntapInfo> tuntapInfos = new ConcurrentDictionary<string, TuntapInfo>();
|
||||||
public ConcurrentDictionary<string, TuntapInfo> Infos => tuntapInfos;
|
public ConcurrentDictionary<string, TuntapInfo> Infos => tuntapInfos;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private readonly SemaphoreSlim slim = new SemaphoreSlim(1);
|
private readonly SemaphoreSlim slim = new SemaphoreSlim(1);
|
||||||
public TuntapConfigTransfer(IMessengerSender messengerSender, ClientSignInState clientSignInState, FileConfig config, TuntapProxy tuntapProxy, RunningConfig runningConfig, TuntapTransfer tuntapTransfer, LeaseClientTreansfer leaseClientTreansfer)
|
public TuntapConfigTransfer(IMessengerSender messengerSender, ClientSignInState clientSignInState, FileConfig config, TuntapProxy tuntapProxy, RunningConfig runningConfig, TuntapTransfer tuntapTransfer, LeaseClientTreansfer leaseClientTreansfer)
|
||||||
{
|
{
|
||||||
@@ -43,13 +50,13 @@ namespace linker.plugins.tuntap.client
|
|||||||
|
|
||||||
clientSignInState.NetworkEnabledHandle += (times) => RefreshIP();
|
clientSignInState.NetworkEnabledHandle += (times) => RefreshIP();
|
||||||
|
|
||||||
tuntapTransfer.OnSetupBefore += () => { NotifyConfig(); };
|
tuntapTransfer.OnSetupBefore += () => { DataVersion.Add(); };
|
||||||
tuntapTransfer.OnSetupAfter += () => { NotifyConfig(); };
|
tuntapTransfer.OnSetupAfter += () => { DataVersion.Add(); };
|
||||||
tuntapTransfer.OnSetupSuccess += () => { NotifyConfig(); runningConfig.Data.Tuntap.Running = true; runningConfig.Data.Update(); };
|
tuntapTransfer.OnSetupSuccess += () => { DataVersion.Add(); runningConfig.Data.Tuntap.Running = true; runningConfig.Data.Update(); };
|
||||||
|
|
||||||
tuntapTransfer.OnShutdownBefore += () => { NotifyConfig(); };
|
tuntapTransfer.OnShutdownBefore += () => { DataVersion.Add(); };
|
||||||
tuntapTransfer.OnShutdownAfter += () => { NotifyConfig(); };
|
tuntapTransfer.OnShutdownAfter += () => { DataVersion.Add(); };
|
||||||
tuntapTransfer.OnShutdownSuccess += () => { NotifyConfig(); DeleteForward(); DelRoute(); runningConfig.Data.Tuntap.Running = false; runningConfig.Data.Update(); };
|
tuntapTransfer.OnShutdownSuccess += () => { DataVersion.Add(); DeleteForward(); DelRoute(); runningConfig.Data.Tuntap.Running = false; runningConfig.Data.Update(); DataVersion.Add(); };
|
||||||
|
|
||||||
|
|
||||||
InitConfig();
|
InitConfig();
|
||||||
@@ -61,6 +68,138 @@ namespace linker.plugins.tuntap.client
|
|||||||
runningConfig.Data.Tuntap.Lans = runningConfig.Data.Tuntap.LanIPs.Select((a, b) => new TuntapLanInfo { IP = a, PrefixLength = (byte)runningConfig.Data.Tuntap.Masks[b] }).ToList();
|
runningConfig.Data.Tuntap.Lans = runningConfig.Data.Tuntap.LanIPs.Select((a, b) => new TuntapLanInfo { IP = a, PrefixLength = (byte)runningConfig.Data.Tuntap.Masks[b] }).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 更新本机网卡信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="info"></param>
|
||||||
|
public void UpdateConfig(TuntapInfo info)
|
||||||
|
{
|
||||||
|
TimerHelper.Async(async () =>
|
||||||
|
{
|
||||||
|
DeleteForward();
|
||||||
|
|
||||||
|
IPAddress oldIP = runningConfig.Data.Tuntap.IP;
|
||||||
|
byte prefixLength = runningConfig.Data.Tuntap.PrefixLength;
|
||||||
|
|
||||||
|
runningConfig.Data.Tuntap.IP = info.IP;
|
||||||
|
runningConfig.Data.Tuntap.Lans = info.Lans;
|
||||||
|
runningConfig.Data.Tuntap.PrefixLength = info.PrefixLength;
|
||||||
|
runningConfig.Data.Tuntap.Switch = info.Switch;
|
||||||
|
runningConfig.Data.Tuntap.Forwards = info.Forwards;
|
||||||
|
runningConfig.Data.Update();
|
||||||
|
|
||||||
|
TuntapGroup2IPInfo tuntapGroup2IPInfo = new TuntapGroup2IPInfo { IP = runningConfig.Data.Tuntap.IP, PrefixLength = runningConfig.Data.Tuntap.PrefixLength };
|
||||||
|
runningConfig.Data.Tuntap.Group2IP.AddOrUpdate(config.Data.Client.Group.Id, tuntapGroup2IPInfo, (a, b) => tuntapGroup2IPInfo);
|
||||||
|
|
||||||
|
await LeaseIP();
|
||||||
|
|
||||||
|
bool needReboot = ((oldIP.Equals(runningConfig.Data.Tuntap.IP) == false || prefixLength != runningConfig.Data.Tuntap.PrefixLength) && runningConfig.Data.Tuntap.Running)
|
||||||
|
|| (runningConfig.Data.Tuntap.Running && tuntapTransfer.Status != TuntapStatus.Running);
|
||||||
|
|
||||||
|
if (needReboot)
|
||||||
|
{
|
||||||
|
await RetstartDevice();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddForward();
|
||||||
|
}
|
||||||
|
|
||||||
|
GetData();
|
||||||
|
DataVersion.Add();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Memory<byte> GetData()
|
||||||
|
{
|
||||||
|
TuntapInfo info = new TuntapInfo
|
||||||
|
{
|
||||||
|
IP = runningConfig.Data.Tuntap.IP,
|
||||||
|
Lans = runningConfig.Data.Tuntap.Lans.Select(c => { c.Exists = false; return c; }).ToList(),
|
||||||
|
PrefixLength = runningConfig.Data.Tuntap.PrefixLength,
|
||||||
|
MachineId = config.Data.Client.Id,
|
||||||
|
Status = tuntapTransfer.Status,
|
||||||
|
SetupError = tuntapTransfer.SetupError,
|
||||||
|
NatError = tuntapTransfer.NatError,
|
||||||
|
SystemInfo = $"{System.Runtime.InteropServices.RuntimeInformation.OSDescription} {(string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("SNLTTY_LINKER_IS_DOCKER")) == false ? "Docker" : "")}",
|
||||||
|
|
||||||
|
Forwards = runningConfig.Data.Tuntap.Forwards,
|
||||||
|
Switch = runningConfig.Data.Tuntap.Switch
|
||||||
|
};
|
||||||
|
tuntapInfos.AddOrUpdate(info.MachineId, info, (a, b) => info);
|
||||||
|
Version.Add();
|
||||||
|
return MemoryPackSerializer.Serialize(info);
|
||||||
|
}
|
||||||
|
public void SetData(Memory<byte> data)
|
||||||
|
{
|
||||||
|
TuntapInfo info = MemoryPackSerializer.Deserialize<TuntapInfo>(data.Span);
|
||||||
|
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||||
|
{
|
||||||
|
LoggerHelper.Instance.Debug($"tuntap got {info.IP}");
|
||||||
|
}
|
||||||
|
|
||||||
|
TimerHelper.Async(async () =>
|
||||||
|
{
|
||||||
|
await slim.WaitAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DelRoute();
|
||||||
|
tuntapInfos.AddOrUpdate(info.MachineId, info, (a, b) => info);
|
||||||
|
Version.Add();
|
||||||
|
AddRoute();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||||
|
{
|
||||||
|
LoggerHelper.Instance.Error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slim.Release();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public void SetData(List<ReadOnlyMemory<byte>> data)
|
||||||
|
{
|
||||||
|
List<TuntapInfo> list = data.Select(c => MemoryPackSerializer.Deserialize<TuntapInfo>(c.Span)).ToList();
|
||||||
|
TimerHelper.Async(async () =>
|
||||||
|
{
|
||||||
|
await slim.WaitAsync();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DelRoute();
|
||||||
|
foreach (var item in list)
|
||||||
|
{
|
||||||
|
tuntapInfos.AddOrUpdate(item.MachineId, item, (a, b) => item);
|
||||||
|
item.LastTicks.Update();
|
||||||
|
}
|
||||||
|
var removes = tuntapInfos.Keys.Except(list.Select(c => c.MachineId)).ToList();
|
||||||
|
foreach (var item in removes)
|
||||||
|
{
|
||||||
|
if (tuntapInfos.TryGetValue(item, out TuntapInfo tuntapInfo))
|
||||||
|
{
|
||||||
|
tuntapInfo.Status = TuntapStatus.Normal;
|
||||||
|
tuntapInfo.LastTicks.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Version.Add();
|
||||||
|
AddRoute();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||||
|
{
|
||||||
|
LoggerHelper.Instance.Error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
slim.Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 刷新IP
|
/// 刷新IP
|
||||||
@@ -86,7 +225,7 @@ namespace linker.plugins.tuntap.client
|
|||||||
tuntapTransfer.Shutdown();
|
tuntapTransfer.Shutdown();
|
||||||
tuntapTransfer.Setup(runningConfig.Data.Tuntap.IP, runningConfig.Data.Tuntap.PrefixLength);
|
tuntapTransfer.Setup(runningConfig.Data.Tuntap.IP, runningConfig.Data.Tuntap.PrefixLength);
|
||||||
}
|
}
|
||||||
NotifyConfig();
|
DataVersion.Add();
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -121,13 +260,11 @@ namespace linker.plugins.tuntap.client
|
|||||||
runningConfig.Data.Tuntap.PrefixLength = tuntapGroup2IPInfo.PrefixLength;
|
runningConfig.Data.Tuntap.PrefixLength = tuntapGroup2IPInfo.PrefixLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (runningConfig.Data.Tuntap.Running || runningConfig.Data.Tuntap.IP.Equals(IPAddress.Any) == false)
|
|
||||||
{
|
|
||||||
LeaseInfo leaseInfo = await leaseClientTreansfer.LeaseIp(runningConfig.Data.Tuntap.IP, runningConfig.Data.Tuntap.PrefixLength);
|
LeaseInfo leaseInfo = await leaseClientTreansfer.LeaseIp(runningConfig.Data.Tuntap.IP, runningConfig.Data.Tuntap.PrefixLength);
|
||||||
runningConfig.Data.Tuntap.IP = leaseInfo.IP;
|
runningConfig.Data.Tuntap.IP = leaseInfo.IP;
|
||||||
runningConfig.Data.Tuntap.PrefixLength = leaseInfo.PrefixLength;
|
runningConfig.Data.Tuntap.PrefixLength = leaseInfo.PrefixLength;
|
||||||
runningConfig.Data.Update();
|
runningConfig.Data.Update();
|
||||||
}
|
|
||||||
tuntapGroup2IPInfo = new TuntapGroup2IPInfo { IP = runningConfig.Data.Tuntap.IP, PrefixLength = runningConfig.Data.Tuntap.PrefixLength };
|
tuntapGroup2IPInfo = new TuntapGroup2IPInfo { IP = runningConfig.Data.Tuntap.IP, PrefixLength = runningConfig.Data.Tuntap.PrefixLength };
|
||||||
runningConfig.Data.Tuntap.Group2IP.AddOrUpdate(config.Data.Client.Group.Id, tuntapGroup2IPInfo, (a, b) => tuntapGroup2IPInfo);
|
runningConfig.Data.Tuntap.Group2IP.AddOrUpdate(config.Data.Client.Group.Id, tuntapGroup2IPInfo, (a, b) => tuntapGroup2IPInfo);
|
||||||
}
|
}
|
||||||
@@ -137,175 +274,7 @@ namespace linker.plugins.tuntap.client
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void RefreshConfig()
|
public void RefreshConfig()
|
||||||
{
|
{
|
||||||
NotifyConfig();
|
DataVersion.Add();
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// 更新本机网卡信息
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="info"></param>
|
|
||||||
public void UpdateConfig(TuntapInfo info)
|
|
||||||
{
|
|
||||||
TimerHelper.Async(() =>
|
|
||||||
{
|
|
||||||
DeleteForward();
|
|
||||||
|
|
||||||
bool needReboot = info.IP.Equals(runningConfig.Data.Tuntap.IP) == false || info.PrefixLength != runningConfig.Data.Tuntap.PrefixLength;
|
|
||||||
|
|
||||||
runningConfig.Data.Tuntap.IP = info.IP;
|
|
||||||
runningConfig.Data.Tuntap.Lans = info.Lans;
|
|
||||||
runningConfig.Data.Tuntap.PrefixLength = info.PrefixLength;
|
|
||||||
runningConfig.Data.Tuntap.Switch = info.Switch;
|
|
||||||
runningConfig.Data.Tuntap.Forwards = info.Forwards;
|
|
||||||
|
|
||||||
TuntapGroup2IPInfo tuntapGroup2IPInfo = new TuntapGroup2IPInfo { IP = info.IP, PrefixLength = info.PrefixLength };
|
|
||||||
runningConfig.Data.Tuntap.Group2IP.AddOrUpdate(config.Data.Client.Group.Id, tuntapGroup2IPInfo, (a, b) => tuntapGroup2IPInfo);
|
|
||||||
|
|
||||||
runningConfig.Data.Update();
|
|
||||||
if (tuntapTransfer.Status == TuntapStatus.Running && needReboot)
|
|
||||||
{
|
|
||||||
tuntapTransfer.Shutdown();
|
|
||||||
tuntapTransfer.Setup(runningConfig.Data.Tuntap.IP, runningConfig.Data.Tuntap.PrefixLength);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddForward();
|
|
||||||
NotifyConfig();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// 收到别的客户端的网卡信息
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="info"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public TuntapInfo OnConfig(TuntapInfo info)
|
|
||||||
{
|
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
|
||||||
{
|
|
||||||
LoggerHelper.Instance.Debug($"tuntap got {info.IP}");
|
|
||||||
}
|
|
||||||
|
|
||||||
TimerHelper.Async(async () =>
|
|
||||||
{
|
|
||||||
await slim.WaitAsync();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
DelRoute();
|
|
||||||
tuntapInfos.AddOrUpdate(info.MachineId, info, (a, b) => info);
|
|
||||||
Version.Add();
|
|
||||||
AddRoute();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
|
||||||
{
|
|
||||||
LoggerHelper.Instance.Error(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
slim.Release();
|
|
||||||
});
|
|
||||||
|
|
||||||
return GetLocalInfo();
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// 信息有变化,刷新信息,把自己的网卡配置发给别人,顺便把别人的网卡信息带回来
|
|
||||||
/// </summary>
|
|
||||||
private void NotifyConfig()
|
|
||||||
{
|
|
||||||
TimerHelper.Async(async () =>
|
|
||||||
{
|
|
||||||
await slim.WaitAsync();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 5; i++)
|
|
||||||
{
|
|
||||||
List<TuntapInfo> list = await GetRemoteInfo().ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (list != null)
|
|
||||||
{
|
|
||||||
DelRoute();
|
|
||||||
foreach (var item in list)
|
|
||||||
{
|
|
||||||
tuntapInfos.AddOrUpdate(item.MachineId, item, (a, b) => item);
|
|
||||||
item.LastTicks.Update();
|
|
||||||
}
|
|
||||||
var removes = tuntapInfos.Keys.Except(list.Select(c => c.MachineId)).ToList();
|
|
||||||
foreach (var item in removes)
|
|
||||||
{
|
|
||||||
if (tuntapInfos.TryGetValue(item, out TuntapInfo tuntapInfo))
|
|
||||||
{
|
|
||||||
tuntapInfo.Status = TuntapStatus.Normal;
|
|
||||||
tuntapInfo.LastTicks.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Version.Add();
|
|
||||||
AddRoute();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
await Task.Delay(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
|
||||||
{
|
|
||||||
LoggerHelper.Instance.Error(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
slim.Release();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// 获取自己的网卡信息
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
private TuntapInfo GetLocalInfo()
|
|
||||||
{
|
|
||||||
TuntapInfo info = new TuntapInfo
|
|
||||||
{
|
|
||||||
IP = runningConfig.Data.Tuntap.IP,
|
|
||||||
Lans = runningConfig.Data.Tuntap.Lans.Where(c => c.Disabled == false && c.IP.Equals(IPAddress.Any) == false).Select(c => { c.Exists = false;return c; }).ToList(),
|
|
||||||
PrefixLength = runningConfig.Data.Tuntap.PrefixLength,
|
|
||||||
MachineId = config.Data.Client.Id,
|
|
||||||
Status = tuntapTransfer.Status,
|
|
||||||
SetupError = tuntapTransfer.SetupError,
|
|
||||||
NatError = tuntapTransfer.NatError,
|
|
||||||
SystemInfo = $"{System.Runtime.InteropServices.RuntimeInformation.OSDescription} {(string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("SNLTTY_LINKER_IS_DOCKER")) == false ? "Docker" : "")}",
|
|
||||||
|
|
||||||
Forwards = runningConfig.Data.Tuntap.Forwards,
|
|
||||||
Switch = runningConfig.Data.Tuntap.Switch
|
|
||||||
};
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// 获取别人的网卡信息
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
private async Task<List<TuntapInfo>> GetRemoteInfo()
|
|
||||||
{
|
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
|
||||||
{
|
|
||||||
LoggerHelper.Instance.Debug($"tuntap sync");
|
|
||||||
}
|
|
||||||
|
|
||||||
TuntapInfo info = GetLocalInfo();
|
|
||||||
tuntapInfos.AddOrUpdate(info.MachineId, info, (a, b) => info);
|
|
||||||
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
|
|
||||||
{
|
|
||||||
Connection = clientSignInState.Connection,
|
|
||||||
MessengerId = (ushort)TuntapMessengerIds.ConfigForward,
|
|
||||||
Payload = MemoryPackSerializer.Serialize(info),
|
|
||||||
Timeout = 3000
|
|
||||||
}).ConfigureAwait(false);
|
|
||||||
if (resp.Code != MessageResponeCodes.OK)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<TuntapInfo> infos = MemoryPackSerializer.Deserialize<List<TuntapInfo>>(resp.Data.Span);
|
|
||||||
infos.Add(info);
|
|
||||||
return infos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// <summary>
|
// <summary>
|
||||||
@@ -377,8 +346,9 @@ namespace linker.plugins.tuntap.client
|
|||||||
|
|
||||||
.Select(c =>
|
.Select(c =>
|
||||||
{
|
{
|
||||||
Console.WriteLine($"{c.MachineId}->{config.Data.Client.Id}");
|
var lans = c.Lans.Where(c => c.Disabled == false && c.IP.Equals(IPAddress.Any) == false);
|
||||||
foreach (var lan in c.Lans)
|
|
||||||
|
foreach (var lan in lans)
|
||||||
{
|
{
|
||||||
uint ipInt = NetworkHelper.IP2Value(lan.IP);
|
uint ipInt = NetworkHelper.IP2Value(lan.IP);
|
||||||
uint maskValue = NetworkHelper.PrefixLength2Value(lan.PrefixLength);
|
uint maskValue = NetworkHelper.PrefixLength2Value(lan.PrefixLength);
|
||||||
@@ -389,7 +359,7 @@ namespace linker.plugins.tuntap.client
|
|||||||
return new TuntapVeaLanIPAddressList
|
return new TuntapVeaLanIPAddressList
|
||||||
{
|
{
|
||||||
MachineId = c.MachineId,
|
MachineId = c.MachineId,
|
||||||
IPS = ParseIPs(c.Lans.Where(c => c.Disabled == false && c.Exists == false).ToList(), c.MachineId)
|
IPS = ParseIPs(lans.Where(c => c.Disabled == false && c.Exists == false).ToList(), c.MachineId)
|
||||||
.Where(c => excludeIps.Select(d => d & c.MaskValue).Contains(c.NetWork) == false).ToList(),
|
.Where(c => excludeIps.Select(d => d & c.MaskValue).Contains(c.NetWork) == false).ToList(),
|
||||||
};
|
};
|
||||||
}).ToList();
|
}).ToList();
|
||||||
@@ -419,5 +389,6 @@ namespace linker.plugins.tuntap.client
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,10 +54,12 @@ namespace linker.plugins.tuntap.client
|
|||||||
}
|
}
|
||||||
protected override void OffLine(string machineId)
|
protected override void OffLine(string machineId)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
foreach (var item in ip2MachineDic.Values)
|
foreach (var item in ip2MachineDic.Values)
|
||||||
{
|
{
|
||||||
item.Remove(machineId);
|
item.Remove(machineId);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -101,9 +101,12 @@ namespace linker.plugins.tuntap.lease
|
|||||||
cache.LastTime = DateTime.Now;
|
cache.LastTime = DateTime.Now;
|
||||||
info.PrefixLength = NetworkHelper.PrefixValue2Length(cache.PrefixValue);
|
info.PrefixLength = NetworkHelper.PrefixValue2Length(cache.PrefixValue);
|
||||||
|
|
||||||
|
|
||||||
LeaseCacheUserInfo self = cache.Users.FirstOrDefault(c => c.Id == userId);
|
LeaseCacheUserInfo self = cache.Users.FirstOrDefault(c => c.Id == userId);
|
||||||
if (self != null)
|
//已有的
|
||||||
|
if (self != null && (info.IP.Equals(NetworkHelper.Value2IP(self.IP)) || info.IP.Equals(IPAddress.Any)))
|
||||||
{
|
{
|
||||||
|
self.LastTime = DateTime.Now;
|
||||||
info.IP = NetworkHelper.Value2IP(self.IP);
|
info.IP = NetworkHelper.Value2IP(self.IP);
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,18 +54,6 @@ namespace linker.plugins.tuntap.messenger
|
|||||||
tuntapConfigTransfer.UpdateConfig(info);
|
tuntapConfigTransfer.UpdateConfig(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 收到别人的网卡信息
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="connection"></param>
|
|
||||||
[MessengerId((ushort)TuntapMessengerIds.Config)]
|
|
||||||
public void Config(IConnection connection)
|
|
||||||
{
|
|
||||||
TuntapInfo info = MemoryPackSerializer.Deserialize<TuntapInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
|
||||||
TuntapInfo _info = tuntapConfigTransfer.OnConfig(info);
|
|
||||||
connection.Write(MemoryPackSerializer.Serialize(_info));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 重新租赁
|
/// 重新租赁
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -154,48 +142,6 @@ namespace linker.plugins.tuntap.messenger
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 广播网卡信息命令,把自己的发给所有人,然后拿回所有人的信息
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="connection"></param>
|
|
||||||
[MessengerId((ushort)TuntapMessengerIds.ConfigForward)]
|
|
||||||
public void ConfigForward(IConnection connection)
|
|
||||||
{
|
|
||||||
TuntapInfo tuntapInfo = MemoryPackSerializer.Deserialize<TuntapInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
|
||||||
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache))
|
|
||||||
{
|
|
||||||
uint requiestid = connection.ReceiveRequestWrap.RequestId;
|
|
||||||
|
|
||||||
List<SignCacheInfo> caches = signCaching.Get(cache.GroupId);
|
|
||||||
List<Task<MessageResponeInfo>> tasks = new List<Task<MessageResponeInfo>>();
|
|
||||||
foreach (SignCacheInfo item in caches.Where(c => c.MachineId != connection.Id && c.Connected))
|
|
||||||
{
|
|
||||||
tasks.Add(messengerSender.SendReply(new MessageRequestWrap
|
|
||||||
{
|
|
||||||
Connection = item.Connection,
|
|
||||||
MessengerId = (ushort)TuntapMessengerIds.Config,
|
|
||||||
Payload = connection.ReceiveRequestWrap.Payload,
|
|
||||||
Timeout = 1000,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
Task.WhenAll(tasks).ContinueWith(async (result) =>
|
|
||||||
{
|
|
||||||
List<TuntapInfo> results = tasks.Where(c => c.Result.Code == MessageResponeCodes.OK)
|
|
||||||
.Select(c => MemoryPackSerializer.Deserialize<TuntapInfo>(c.Result.Data.Span)).ToList();
|
|
||||||
|
|
||||||
await messengerSender.ReplyOnly(new MessageResponseWrap
|
|
||||||
{
|
|
||||||
RequestId = requiestid,
|
|
||||||
Connection = connection,
|
|
||||||
Payload = MemoryPackSerializer.Serialize(results)
|
|
||||||
}, (ushort)TuntapMessengerIds.ConfigForward).ConfigureAwait(false);
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 添加网络配置
|
/// 添加网络配置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -11,9 +11,6 @@
|
|||||||
Update = 2204,
|
Update = 2204,
|
||||||
UpdateForward = 2205,
|
UpdateForward = 2205,
|
||||||
|
|
||||||
Config = 2206,
|
|
||||||
ConfigForward = 2207,
|
|
||||||
|
|
||||||
|
|
||||||
LeaseAddNetwork = 2208,
|
LeaseAddNetwork = 2208,
|
||||||
LeaseGetNetwork = 2209,
|
LeaseGetNetwork = 2209,
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
v1.5.1
|
v1.5.1
|
||||||
2024-10-24 17:27:23
|
2024-10-25 17:12:39
|
||||||
1. 优化点对网和网对网的局域网IP,包括禁用IP,和冲突检测
|
1. 优化点对网和网对网的局域网IP,包括禁用IP,和冲突检测
|
||||||
2. 一些UI优化
|
2. 一些UI优化
|
||||||
3. 测试中,测试中,测试中,不要更新,用v1.4.9
|
3. 新增socks5代理
|
||||||
|
4. 优化端口转发和内网穿透配置
|
||||||
|
5. 优化网卡的一些东西
|
||||||
|
6. 测试中,测试中,测试中,不要更新,用v1.4.9
|
||||||
Reference in New Issue
Block a user