mirror of
				https://github.com/snltty/linker.git
				synced 2025-10-31 04:26:45 +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 }} | ||||
|           draft: 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 | ||||
|         id: upload-win-x86-oss | ||||
|         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="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="DecenterTypesLoader", ClassNameSpace="linker.plugins.decenter", InterfaceName="linker.plugins.decenter.IDecenter"}, | ||||
|         }; | ||||
|          | ||||
|         public void Initialize(IncrementalGeneratorInitializationContext context) | ||||
|   | ||||
| @@ -15,10 +15,15 @@ namespace linker.libs | ||||
|  | ||||
|         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); | ||||
| } | ||||
|  | ||||
| export const getAccesss = (machineid) => { | ||||
|     return sendWebsocketMsg('configclient/GetAccesss', machineid); | ||||
| } | ||||
| export const setAccess = (data) => { | ||||
|     return sendWebsocketMsg('configclient/SetAccess', data); | ||||
| } | ||||
| export const getSyncNames = () => { | ||||
|     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> | ||||
| </template> | ||||
| <script> | ||||
| import { setAccess } from '@/apis/config'; | ||||
| import { setAccess } from '@/apis/access'; | ||||
| import { ElMessage } from 'element-plus'; | ||||
| import { reactive, ref, watch } from 'vue'; | ||||
| import Access from '@/views/full/devices/Access.vue' | ||||
|   | ||||
| @@ -53,7 +53,7 @@ | ||||
| <script> | ||||
| import { reactive, watch,computed,  onMounted, onUnmounted } from 'vue'; | ||||
| 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 { injectGlobalData } from '@/provide'; | ||||
| export default { | ||||
| @@ -68,6 +68,7 @@ export default { | ||||
|         const connections = useConnections(); | ||||
|         const forwardConnections = useForwardConnections(); | ||||
|         const tuntapConnections = useTuntapConnections(); | ||||
|         const socks5Connections = useSocks5Connections(); | ||||
|         const state = reactive({ | ||||
|             show: true, | ||||
|             protocolTypes:{1:'tcp',2:'udp',4:'msquic'}, | ||||
| @@ -78,6 +79,7 @@ export default { | ||||
|                 return [ | ||||
|                     forwardConnections.value.list[connections.value.current], | ||||
|                     tuntapConnections.value.list[connections.value.current], | ||||
|                     socks5Connections.value.list[connections.value.current], | ||||
|                 ].filter(c=>!!c); | ||||
|             }), | ||||
|         }); | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
|             <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="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 label="" width="74" fixed="right"></el-table-column> | ||||
|         </el-table> | ||||
| @@ -12,7 +13,7 @@ | ||||
|             <Device  @edit="handleDeviceEdit" @refresh="handlePageRefresh"></Device> | ||||
|             <Tunnel  @edit="handleTunnelEdit" @refresh="handleTunnelRefresh" @connections="handleTunnelConnections"></Tunnel> | ||||
|             <Tuntap  @edit="handleTuntapEdit" @refresh="handleTuntapRefresh"></Tuntap> | ||||
|             <Socks5 @edit="_handleForwardEdit" @sedit="handleSForwardEdit"></Socks5>  | ||||
|             <Socks5 @edit="handleSocks5Edit" @refresh="handleSocks5Refresh"></Socks5>  | ||||
|             <Forward @edit="_handleForwardEdit" @sedit="handleSForwardEdit"></Forward>  | ||||
|             <Oper  @refresh="handlePageRefresh" @access="handleAccessEdit"></Oper> | ||||
|         </el-table> | ||||
| @@ -28,6 +29,7 @@ | ||||
|         <TunnelEdit v-if="tunnel.showEdit" v-model="tunnel.showEdit"  @change="handleTunnelRefresh"></TunnelEdit> | ||||
|         <ConnectionsEdit v-if="connections.showEdit" v-model="connections.showEdit" ></ConnectionsEdit> | ||||
|         <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> | ||||
|         <ForwardEdit v-if="forward.showEdit" v-model="forward.showEdit" ></ForwardEdit> | ||||
|         <ForwardCopy v-if="forward.showCopy" v-model="forward.showCopy" ></ForwardCopy> | ||||
| @@ -38,33 +40,54 @@ | ||||
| <script> | ||||
| import { injectGlobalData } from '@/provide.js' | ||||
| import { reactive, onMounted,  onUnmounted, computed } from 'vue' | ||||
| import { ElMessage } from 'element-plus' | ||||
|  | ||||
| import Oper from './Oper.vue' | ||||
| import Device from './Device.vue' | ||||
| import DeviceEdit from './DeviceEdit.vue' | ||||
| import { provideDevices } from './devices' | ||||
|  | ||||
| import AccessEdit from './AccessEdit.vue' | ||||
| import { provideAccess } from './access' | ||||
|  | ||||
| import Tuntap from './Tuntap.vue' | ||||
| import TuntapEdit from './TuntapEdit.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 TunnelEdit from './TunnelEdit.vue' | ||||
| import Socks5 from './Socks5.vue' | ||||
| import { provideTunnel } from './tunnel' | ||||
|  | ||||
| import Forward from './Forward.vue' | ||||
| import ForwardEdit from './ForwardEdit.vue' | ||||
| import ForwardCopy from './ForwardCopy.vue' | ||||
| import { provideForward } from './forward' | ||||
|  | ||||
| import SForwardEdit from './SForwardEdit.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 { provideDevices } from './devices' | ||||
|  | ||||
| import ConnectionsEdit from './ConnectionsEdit.vue' | ||||
| import { provideConnections } from './connections' | ||||
|  | ||||
| import { provideUpdater } from './updater' | ||||
| import { provideAccess } from './access' | ||||
|  | ||||
| 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) { | ||||
|  | ||||
|         const globalData = injectGlobalData(); | ||||
| @@ -76,12 +99,14 @@ export default { | ||||
|             handleDeviceEdit,handleAccessEdit, handlePageChange, handlePageSizeChange, handleDel,clearDevicesTimeout,setSort} = provideDevices(); | ||||
|  | ||||
|         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 {forward,_getForwardInfo,handleForwardEdit,_testTargetForwardInfo,clearForwardTimeout,getForwardMachines} = provideForward(); | ||||
|         const {sforward,_getSForwardInfo,handleSForwardEdit,_testLocalSForwardInfo,clearSForwardTimeout,getSForwardMachines} = provideSforward(); | ||||
|         const {connections, | ||||
|             forwardConnections,_getForwardConnections, | ||||
|             tuntapConnections,_getTuntapConnections, | ||||
|             socks5Connections,_getSocks5Connections, | ||||
|             handleTunnelConnections,clearConnectionsTimeout | ||||
|         } = provideConnections(); | ||||
|  | ||||
| @@ -107,6 +132,11 @@ export default { | ||||
|                 if(ids .length > 0){ | ||||
|                     fn = setSort(ids); | ||||
|                 } | ||||
|             }else if(row.prop == 'socks5'){ | ||||
|                 const ids = sortSocks5(devices.page.Request.Asc); | ||||
|                 if(ids .length > 0){ | ||||
|                     fn = setSort(ids); | ||||
|                 } | ||||
|             } | ||||
|             fn.then(()=>{ | ||||
|                 handlePageChange(); | ||||
| @@ -139,12 +169,14 @@ export default { | ||||
|             handlePageChange(); | ||||
|             handleTunnelRefresh(); | ||||
|             handleTuntapRefresh(); | ||||
|             handleSocks5Refresh(); | ||||
|             ElMessage.success({message:'刷新成功',grouping:true});   | ||||
|         } | ||||
|         const handlePageSearch = ()=>{ | ||||
|             handlePageChange(); | ||||
|             handleTunnelRefresh(); | ||||
|             handleTuntapRefresh(); | ||||
|             handleSocks5Refresh(); | ||||
|             ElMessage.success({message:'刷新成功',grouping:true});   | ||||
|         } | ||||
|  | ||||
| @@ -155,9 +187,11 @@ export default { | ||||
|             _getSignList(); | ||||
|             _getSignList1(); | ||||
|             _getTuntapInfo(); | ||||
|             _getSocks5Info(); | ||||
|             _getTunnelInfo(); | ||||
|             _getForwardConnections(); | ||||
|             _getTuntapConnections(); | ||||
|             _getSocks5Connections(); | ||||
|             _getForwardInfo(); | ||||
|             _getSForwardInfo(); | ||||
|  | ||||
| @@ -173,6 +207,7 @@ export default { | ||||
|             clearDevicesTimeout(); | ||||
|             clearConnectionsTimeout(); | ||||
|             clearTuntapTimeout(); | ||||
|             clearSocks5Timeout(); | ||||
|             clearTunnelTimeout(); | ||||
|             clearForwardTimeout(); | ||||
|             clearSForwardTimeout(); | ||||
| @@ -186,6 +221,7 @@ export default { | ||||
|             state,devices, machineId,handleSortChange, | ||||
|             handleDeviceEdit,handleAccessEdit,handlePageRefresh,handlePageSearch, handlePageChange,handlePageSizeChange, handleDel, | ||||
|             tuntap, handleTuntapEdit, handleTuntapRefresh, | ||||
|             socks5, handleSocks5Edit, handleSocks5Refresh, | ||||
|             tunnel,connections, handleTunnelEdit, handleTunnelRefresh,handleTunnelConnections, | ||||
|             forward,_handleForwardEdit, | ||||
|             sforward,handleSForwardEdit | ||||
|   | ||||
| @@ -1,39 +1,35 @@ | ||||
| <template> | ||||
|     <el-table-column prop="socks5" label="socks5代理" width="160"> | ||||
|     <el-table-column prop="socks5" label="socks5" width="160"> | ||||
|         <template #default="scope"> | ||||
|             <div> | ||||
|                 <div class="flex"> | ||||
|                     <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 v-if="socks5.list[scope.row.MachineId]"> | ||||
|                 <Socks5Show :config="true" :item="scope.row" @edit="handleSocks5" @refresh="handleSocks5Refresh"></Socks5Show> | ||||
|             </div>  | ||||
|         </template> | ||||
|     </el-table-column> | ||||
| </template> | ||||
| <script> | ||||
| import { injectGlobalData } from '@/provide'; | ||||
| import { useSocks5 } from './socks5'; | ||||
| import Socks5Show from './Socks5Show.vue'; | ||||
| export default { | ||||
|     emits: ['edit','sedit'], | ||||
|     emits: ['edit','refresh'], | ||||
|     components:{Socks5Show}, | ||||
|     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> | ||||
| <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> | ||||
							
								
								
									
										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> | ||||
| <script> | ||||
| import { useTunnel } from './tunnel'; | ||||
| import { useConnections,useForwardConnections,useTuntapConnections } from './connections'; | ||||
| import { useConnections,useForwardConnections,useSocks5Connections,useTuntapConnections } from './connections'; | ||||
| import { injectGlobalData } from '@/provide'; | ||||
| import { computed } from 'vue'; | ||||
|  | ||||
| @@ -36,11 +36,13 @@ export default { | ||||
|         const connections = useConnections(); | ||||
|         const forwardConnections = useForwardConnections(); | ||||
|         const tuntapConnections = useTuntapConnections(); | ||||
|         const socks5Connections = useSocks5Connections(); | ||||
|  | ||||
|         const connectionCount = (machineId)=>{ | ||||
|                 return [ | ||||
|                     forwardConnections.value.list[machineId], | ||||
|                     tuntapConnections.value.list[machineId], | ||||
|                     socks5Connections.value.list[machineId], | ||||
|                 ].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"; | ||||
|  | ||||
| const accessSymbol = Symbol(); | ||||
|   | ||||
| @@ -1,10 +1,12 @@ | ||||
| import { getForwardConnections, removeForwardConnection } from "@/apis/forward"; | ||||
| import { getTuntapConnections, removeTuntapConnection } from "@/apis/tuntap"; | ||||
| import { getSocks5Connections, removeSocks5Connection } from "@/apis/socks5"; | ||||
| import { inject, provide, ref } from "vue"; | ||||
|  | ||||
| const connectionsSymbol = Symbol(); | ||||
| const forwardConnectionsSymbol = Symbol(); | ||||
| const tuntapConnectionsSymbol = Symbol(); | ||||
| const socks5ConnectionsSymbol = Symbol(); | ||||
| export const provideConnections = () => { | ||||
|     const connections = ref({ | ||||
|         showEdit: false, | ||||
| @@ -28,8 +30,6 @@ export const provideConnections = () => { | ||||
|         list: {}, | ||||
|     }); | ||||
|     provide(forwardConnectionsSymbol, forwardConnections); | ||||
|  | ||||
|  | ||||
|     const _getForwardConnections = () => { | ||||
|         getForwardConnections(connections.value.hashcode.toString()).then((res) => { | ||||
|             if (connections.value._updateRealTime == false) | ||||
| @@ -44,6 +44,8 @@ export const provideConnections = () => { | ||||
|             forwardConnections.value.timer = setTimeout(_getForwardConnections, 1000); | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|  | ||||
|     const tuntapConnections = ref({ | ||||
|         timer: 0, | ||||
|         list: {}, | ||||
| @@ -63,6 +65,28 @@ export const provideConnections = () => { | ||||
|             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 caches = connections.value.speedCache; | ||||
|         for (let machineId in _connections) { | ||||
| @@ -93,14 +117,18 @@ export const provideConnections = () => { | ||||
|         connections.value.currentName = device.MachineName; | ||||
|         connections.value.showEdit = true; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     const clearConnectionsTimeout = () => { | ||||
|         clearTimeout(forwardConnections.value.timer); | ||||
|         clearTimeout(tuntapConnections.value.timer); | ||||
|         clearTimeout(socks5Connections.value.timer); | ||||
|     } | ||||
|     return { | ||||
|         connections, | ||||
|         forwardConnections, _getForwardConnections, | ||||
|         tuntapConnections, _getTuntapConnections, | ||||
|         socks5Connections, _getSocks5Connections, | ||||
|         handleTunnelConnections, clearConnectionsTimeout | ||||
|     } | ||||
| } | ||||
| @@ -113,3 +141,6 @@ export const useForwardConnections = () => { | ||||
| export const useTuntapConnections = () => { | ||||
|     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 { getTuntapInfo, refreshTuntap, subscribePing } from "@/apis/tuntap"; | ||||
|  | ||||
| const tuntapSymbol = Symbol(); | ||||
| export const provideTuntap = () => { | ||||
|     const globalData = injectGlobalData(); | ||||
|     const tuntap = ref({ | ||||
|         timer: 0, | ||||
|         showEdit: false, | ||||
|   | ||||
| @@ -122,7 +122,7 @@ namespace linker | ||||
|             TimerHelper.SetInterval(() => | ||||
|             { | ||||
|                 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 | ||||
|                     { | ||||
|   | ||||
| @@ -23,7 +23,10 @@ | ||||
| 		<Company>snltty</Company> | ||||
| 		<Description>1. 优化点对网和网对网的局域网IP,包括禁用IP,和冲突检测 | ||||
| 2. 一些UI优化 | ||||
| 3. 测试中,测试中,测试中,不要更新,用v1.4.9</Description> | ||||
| 3. 新增socks5代理 | ||||
| 4. 优化端口转发和内网穿透配置 | ||||
| 5. 优化网卡的一些东西 | ||||
| 6. 测试中,测试中,测试中,不要更新,用v1.4.9</Description> | ||||
| 		<Copyright>snltty</Copyright> | ||||
| 		<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl> | ||||
| 		<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.libs; | ||||
| using linker.plugins.client; | ||||
| using linker.plugins.config.messenger; | ||||
| using linker.plugins.decenter; | ||||
| using linker.plugins.messenger; | ||||
| 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(); | ||||
| 
 | ||||
|         private Dictionary<string, ClientApiAccess> accesss = new Dictionary<string, ClientApiAccess>(); | ||||
| 
 | ||||
|         private readonly FileConfig fileConfig; | ||||
| @@ -21,32 +25,43 @@ namespace linker.plugins.config | ||||
|             this.sender = sender; | ||||
|             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() | ||||
|         { | ||||
|             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) | ||||
|         { | ||||
|             //我的权限删掉它的权限==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.Update(); | ||||
|                 Version.Add(); | ||||
|                 Sync(); | ||||
|                 GetData(); | ||||
|                 DataVersion.Add(); | ||||
|             } | ||||
|         } | ||||
|         public ClientApiAccess AssignAccess(ClientApiAccess access) | ||||
| @@ -54,25 +69,5 @@ namespace linker.plugins.config | ||||
|             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 LiteDB; | ||||
| using MemoryPack; | ||||
| using System.Net; | ||||
| using System.Reflection; | ||||
| @@ -24,45 +22,6 @@ namespace linker.config | ||||
|             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; } | ||||
|  | ||||
|  | ||||
| @@ -138,10 +97,6 @@ namespace linker.config | ||||
|             return Encoding.UTF8.GetString(crypto.Decode(Convert.FromBase64String(text)).ToArray()).DeJson<ConfigClientInfo>(); | ||||
|         } | ||||
|  | ||||
|         public string ToGroupString() | ||||
|         { | ||||
|             return $"{name}->{Group.Id}->{Group.Password}"; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     [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.plugins.client; | ||||
| using linker.plugins.messenger; | ||||
| using linker.plugins.config.messenger; | ||||
| using MemoryPack; | ||||
|  | ||||
| using linker.plugins.access; | ||||
| namespace linker.plugins.config | ||||
| { | ||||
|     public sealed class ConfigClientApiController : IApiClientController | ||||
| @@ -19,18 +17,18 @@ namespace linker.plugins.config | ||||
|         private readonly ClientSignInTransfer clientSignInTransfer; | ||||
|         private readonly IMessengerSender sender; | ||||
|         private readonly ClientSignInState clientSignInState; | ||||
|         private readonly AccessTransfer accessTransfer; | ||||
|         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.config = config; | ||||
|             this.clientSignInTransfer = clientSignInTransfer; | ||||
|             this.sender = sender; | ||||
|             this.clientSignInState = clientSignInState; | ||||
|             this.accessTransfer = accessTransfer; | ||||
|             this.configSyncTreansfer = configSyncTreansfer; | ||||
|             this.accessTransfer = accessTransfer; | ||||
|         } | ||||
|  | ||||
|         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)] | ||||
|         public async Task<bool> Export(ApiControllerParamsInfo param) | ||||
|         { | ||||
| @@ -148,15 +112,18 @@ namespace linker.plugins.config | ||||
|                 Directory.CreateDirectory(configPath); | ||||
|  | ||||
|                 ConfigClientInfo client = config.Data.Client.ToJson().DeJson<ConfigClientInfo>(); | ||||
|                 client.Id = string.Empty; | ||||
|                 client.Name = string.Empty; | ||||
|                 if (configExportInfo.Single || client.OnlyNode) | ||||
|                 { | ||||
|                     client.Id = await clientSignInTransfer.GetNewId(); | ||||
|                     client.Name = configExportInfo.Name; | ||||
|                 } | ||||
|                 if (client.OnlyNode == false) | ||||
|                 { | ||||
|                     client.CApi.ApiPassword = configExportInfo.ApiPassword; | ||||
|                 } | ||||
|                 client.Name = configExportInfo.Name; | ||||
|                | ||||
|                 client.Access = accessTransfer.AssignAccess((ClientApiAccess)configExportInfo.Access); | ||||
|                 client.OnlyNode = true; | ||||
|                 client.Action.Args.Clear(); | ||||
|   | ||||
| @@ -26,9 +26,6 @@ namespace linker.plugins.config | ||||
|  | ||||
|             serviceCollection.AddSingleton<RunningConfig>(); | ||||
|  | ||||
|  | ||||
|             serviceCollection.AddSingleton<AccessTransfer>(); | ||||
|  | ||||
|             serviceCollection.AddSingleton<ConfigSyncTreansfer>(); | ||||
|             serviceCollection.AddSingleton<ConfigSyncTypesLoader>(); | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,4 @@ | ||||
| using linker.config; | ||||
| using linker.libs; | ||||
| using linker.plugins.client; | ||||
| using linker.plugins.messenger; | ||||
| using linker.plugins.messenger; | ||||
| using linker.plugins.signin.messenger; | ||||
| using MemoryPack; | ||||
|  | ||||
| @@ -18,69 +15,6 @@ namespace linker.plugins.config.messenger | ||||
|             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)] | ||||
|         public async Task SyncForward(IConnection connection) | ||||
| @@ -108,35 +42,13 @@ namespace linker.plugins.config.messenger | ||||
|  | ||||
|     public sealed class ConfigClientMessenger : IMessenger | ||||
|     { | ||||
|         private readonly AccessTransfer accessTransfer; | ||||
|         private readonly FileConfig fileConfig; | ||||
|         private readonly ClientSignInTransfer clientSignInTransfer; | ||||
|         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; | ||||
|         } | ||||
|  | ||||
|         [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)] | ||||
|         public void Sync(IConnection connection) | ||||
|         { | ||||
|   | ||||
| @@ -4,15 +4,6 @@ | ||||
|     { | ||||
|         Min = 2500, | ||||
|  | ||||
|         //Update = 2501, | ||||
|         //UpdateForward = 2502, | ||||
|  | ||||
|         Access = 2503, | ||||
|         AccessForward = 2504, | ||||
|  | ||||
|         AccessUpdate = 2505, | ||||
|         AccessUpdateForward = 2506, | ||||
|  | ||||
|         Sync = 2507, | ||||
|         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 System.Buffers; | ||||
| using System.Net; | ||||
| using linker.plugins.messenger; | ||||
|  | ||||
| namespace linker.plugins.resolver | ||||
| { | ||||
| @@ -31,6 +32,7 @@ namespace linker.plugins.resolver | ||||
|                 { | ||||
|                     return; | ||||
|                 } | ||||
|                 LoggerHelper.Instance.Info($"tcp connect from {socket.RemoteEndPoint}"); | ||||
|                 socket.KeepAlive(); | ||||
|  | ||||
|                 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) | ||||
|                 { | ||||
|                     return "your machine key is already online"; | ||||
|                     return $"your id 【{signInfo.MachineId}】 is already online, online machineName {cache.MachineName}"; | ||||
|                 } | ||||
|             } | ||||
|             await Task.CompletedTask; | ||||
|   | ||||
| @@ -42,6 +42,8 @@ namespace linker.plugins.signin.messenger | ||||
|         public async Task SignIn(IConnection connection) | ||||
|         { | ||||
|             SignInfo info = MemoryPackSerializer.Deserialize<SignInfo>(connection.ReceiveRequestWrap.Payload.Span); | ||||
|             LoggerHelper.Instance.Info($"sign in from {connection.Address}->{info.ToJson()}"); | ||||
|  | ||||
|             info.Connection = connection; | ||||
|  | ||||
|             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 linker.plugins.tunnel; | ||||
| using linker.plugins.client; | ||||
| using linker.plugins.socks5.config; | ||||
|  | ||||
| namespace linker.plugins.socks5 | ||||
| { | ||||
| @@ -18,7 +19,9 @@ namespace linker.plugins.socks5 | ||||
|         private IPEndPoint proxyEP; | ||||
|  | ||||
|         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) | ||||
|              : base(config, tunnelTransfer, relayTransfer, clientSignInTransfer, clientSignInState) | ||||
| @@ -26,13 +29,44 @@ namespace linker.plugins.socks5 | ||||
|             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) | ||||
|             { | ||||
|                 Stop(proxyEP.Port); | ||||
|             } | ||||
|             Start(new IPEndPoint(IPAddress.Any, 0), 3); | ||||
|             Start(new IPEndPoint(IPAddress.Any, port), 3); | ||||
|             proxyEP = new IPEndPoint(IPAddress.Any, LocalEndpoint.Port); | ||||
|         } | ||||
|  | ||||
| @@ -175,9 +209,9 @@ namespace linker.plugins.socks5 | ||||
|             for (int i = 0; i < maskValues.Length; 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; | ||||
|         public IPEndPoint LocalEndpoint { get; private set; } | ||||
|  | ||||
|         public bool Running {  get; private set; } | ||||
|         public string Error {  get; private set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 监听一个端口 | ||||
|         /// </summary> | ||||
|         /// <param name="port"></param> | ||||
|         private void StartTcp(IPEndPoint ep, byte bufferSize) | ||||
|         { | ||||
|             Error = string.Empty; | ||||
|             IPEndPoint _localEndPoint = ep; | ||||
|             socket = new Socket(_localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); | ||||
|             socket.IPv6Only(_localEndPoint.AddressFamily, false); | ||||
| @@ -41,8 +45,10 @@ namespace linker.plugins.socks5 | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 Error = ex.Message; | ||||
|                 LoggerHelper.Instance.Error(ex); | ||||
|             } | ||||
|             Running = true; | ||||
|         } | ||||
|         /// <summary> | ||||
|         /// 接收连接 | ||||
| @@ -63,6 +69,7 @@ namespace linker.plugins.socks5 | ||||
|                 LoggerHelper.Instance.Error(ex); | ||||
|                 token.Clear(); | ||||
|             } | ||||
|             Running = false; | ||||
|  | ||||
|         } | ||||
|         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.libs; | ||||
| using linker.plugins.client; | ||||
| using linker.plugins.decenter; | ||||
| using linker.plugins.messenger; | ||||
| using linker.plugins.tunnel.messenger; | ||||
| using linker.tunnel; | ||||
| using linker.tunnel.adapter; | ||||
| using linker.tunnel.wanport; | ||||
| using MemoryPack; | ||||
| using System.Collections.Concurrent; | ||||
| using System.Net; | ||||
| @@ -14,8 +14,12 @@ using System.Net.Quic; | ||||
|  | ||||
| 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 RunningConfig running; | ||||
|         private readonly ClientSignInState clientSignInState; | ||||
| @@ -26,6 +30,8 @@ namespace linker.plugins.tunnel | ||||
|         public VersionManager Version { get; } = new VersionManager(); | ||||
|         public ConcurrentDictionary<string, TunnelTransportRouteLevelInfo> Config { get; } = new ConcurrentDictionary<string, TunnelTransportRouteLevelInfo>(); | ||||
|  | ||||
|          | ||||
|  | ||||
|         public TunnelConfigTransfer(FileConfig config, RunningConfig running, ClientSignInState clientSignInState, IMessengerSender messengerSender, ITunnelAdapter tunnelAdapter, TunnelUpnpTransfer upnpTransfer) | ||||
|         { | ||||
|             this.config = config; | ||||
| @@ -38,12 +44,40 @@ namespace linker.plugins.tunnel | ||||
|             clientSignInState.NetworkEnabledHandle += (times) => | ||||
|             { | ||||
|                 RefreshRouteLevel(); | ||||
|                 GetRemoteRouteLevel(); | ||||
|                 DataVersion.Add(); | ||||
|                 RefreshPortMap(); | ||||
|             }; | ||||
|             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() | ||||
|         { | ||||
|             TimerHelper.Async(() => | ||||
| @@ -59,7 +93,7 @@ namespace linker.plugins.tunnel | ||||
|         /// </summary> | ||||
|         public void RefreshConfig() | ||||
|         { | ||||
|             GetRemoteRouteLevel(); | ||||
|             DataVersion.Add(); | ||||
|         } | ||||
|         /// <summary> | ||||
|         /// 修改自己的网关层级信息 | ||||
| @@ -71,42 +105,8 @@ namespace linker.plugins.tunnel | ||||
|             running.Data.Tunnel.PortMapWan = tunnelTransportFileConfigInfo.PortMapWan; | ||||
|             running.Data.Tunnel.PortMapLan = tunnelTransportFileConfigInfo.PortMapLan; | ||||
|             running.Data.Update(); | ||||
|             GetRemoteRouteLevel(); | ||||
|         } | ||||
|         /// <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(); | ||||
|                 } | ||||
|             }); | ||||
|             GetData(); | ||||
|             DataVersion.Add(); | ||||
|         } | ||||
|         private TunnelTransportRouteLevelInfo GetLocalRouteLevel() | ||||
|         { | ||||
| @@ -173,5 +173,7 @@ namespace linker.plugins.tunnel | ||||
|             } | ||||
|  | ||||
|         } | ||||
|  | ||||
|         | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -95,15 +95,6 @@ namespace linker.plugins.tunnel.messenger | ||||
|             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 | ||||
| @@ -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] | ||||
|   | ||||
| @@ -16,9 +16,6 @@ | ||||
|         Success = 2007, | ||||
|         SuccessForward = 2008, | ||||
|  | ||||
|         Config = 2009, | ||||
|         ConfigForward = 2010, | ||||
|  | ||||
|         RouteLevel = 2011, | ||||
|         RouteLevelForward = 2012, | ||||
|  | ||||
|   | ||||
| @@ -10,11 +10,16 @@ using linker.plugins.messenger; | ||||
| using linker.plugins.tuntap.config; | ||||
| using linker.tun; | ||||
| using linker.plugins.tuntap.lease; | ||||
| using linker.plugins.decenter; | ||||
|  | ||||
| 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 ClientSignInState clientSignInState; | ||||
|         private readonly FileConfig config; | ||||
| @@ -29,6 +34,8 @@ namespace linker.plugins.tuntap.client | ||||
|         private readonly ConcurrentDictionary<string, TuntapInfo> tuntapInfos = new ConcurrentDictionary<string, TuntapInfo>(); | ||||
|         public ConcurrentDictionary<string, TuntapInfo> Infos => tuntapInfos; | ||||
|  | ||||
|  | ||||
|  | ||||
|         private readonly SemaphoreSlim slim = new SemaphoreSlim(1); | ||||
|         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(); | ||||
|  | ||||
|             tuntapTransfer.OnSetupBefore += () => { NotifyConfig(); }; | ||||
|             tuntapTransfer.OnSetupAfter += () => { NotifyConfig(); }; | ||||
|             tuntapTransfer.OnSetupSuccess += () => { NotifyConfig(); runningConfig.Data.Tuntap.Running = true; runningConfig.Data.Update(); }; | ||||
|             tuntapTransfer.OnSetupBefore += () => { DataVersion.Add(); }; | ||||
|             tuntapTransfer.OnSetupAfter += () => { DataVersion.Add(); }; | ||||
|             tuntapTransfer.OnSetupSuccess += () => { DataVersion.Add(); runningConfig.Data.Tuntap.Running = true; runningConfig.Data.Update(); }; | ||||
|  | ||||
|             tuntapTransfer.OnShutdownBefore += () => { NotifyConfig(); }; | ||||
|             tuntapTransfer.OnShutdownAfter += () => { NotifyConfig(); }; | ||||
|             tuntapTransfer.OnShutdownSuccess += () => { NotifyConfig(); DeleteForward(); DelRoute(); runningConfig.Data.Tuntap.Running = false; runningConfig.Data.Update(); }; | ||||
|             tuntapTransfer.OnShutdownBefore += () => { DataVersion.Add(); }; | ||||
|             tuntapTransfer.OnShutdownAfter += () => { DataVersion.Add(); }; | ||||
|             tuntapTransfer.OnShutdownSuccess += () => { DataVersion.Add(); DeleteForward(); DelRoute(); runningConfig.Data.Tuntap.Running = false; runningConfig.Data.Update(); DataVersion.Add(); }; | ||||
|  | ||||
|  | ||||
|             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(); | ||||
|             } | ||||
|         } | ||||
|         /// <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> | ||||
|         /// 刷新IP | ||||
| @@ -86,7 +225,7 @@ namespace linker.plugins.tuntap.client | ||||
|                     tuntapTransfer.Shutdown(); | ||||
|                     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; | ||||
|                 } | ||||
|             } | ||||
|             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); | ||||
|             runningConfig.Data.Tuntap.IP = leaseInfo.IP; | ||||
|             runningConfig.Data.Tuntap.PrefixLength = leaseInfo.PrefixLength; | ||||
|             runningConfig.Data.Update(); | ||||
|             } | ||||
|  | ||||
|             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); | ||||
|         } | ||||
| @@ -137,175 +274,7 @@ namespace linker.plugins.tuntap.client | ||||
|         /// </summary> | ||||
|         public void RefreshConfig() | ||||
|         { | ||||
|             NotifyConfig(); | ||||
|         } | ||||
|         /// <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; | ||||
|             DataVersion.Add(); | ||||
|         } | ||||
|  | ||||
|         // <summary> | ||||
| @@ -377,8 +346,9 @@ namespace linker.plugins.tuntap.client | ||||
|  | ||||
|                 .Select(c => | ||||
|                 { | ||||
|                     Console.WriteLine($"{c.MachineId}->{config.Data.Client.Id}"); | ||||
|                     foreach (var lan in c.Lans) | ||||
|                     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); | ||||
| @@ -389,7 +359,7 @@ namespace linker.plugins.tuntap.client | ||||
|                     return new TuntapVeaLanIPAddressList | ||||
|                     { | ||||
|                         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(), | ||||
|                     }; | ||||
|                 }).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) | ||||
|         { | ||||
|             /* | ||||
|             foreach (var item in ip2MachineDic.Values) | ||||
|             { | ||||
|                 item.Remove(machineId); | ||||
|             } | ||||
|             */ | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|   | ||||
| @@ -101,9 +101,12 @@ namespace linker.plugins.tuntap.lease | ||||
|             cache.LastTime = DateTime.Now; | ||||
|             info.PrefixLength = NetworkHelper.PrefixValue2Length(cache.PrefixValue); | ||||
|  | ||||
|  | ||||
|             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); | ||||
|                 return info; | ||||
|             } | ||||
|   | ||||
| @@ -54,18 +54,6 @@ namespace linker.plugins.tuntap.messenger | ||||
|             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> | ||||
| @@ -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> | ||||
|   | ||||
| @@ -11,9 +11,6 @@ | ||||
|         Update = 2204, | ||||
|         UpdateForward = 2205, | ||||
|  | ||||
|         Config = 2206, | ||||
|         ConfigForward = 2207, | ||||
|  | ||||
|  | ||||
|         LeaseAddNetwork = 2208, | ||||
|         LeaseGetNetwork = 2209, | ||||
|   | ||||
| @@ -1,5 +1,8 @@ | ||||
| v1.5.1 | ||||
| 2024-10-24 17:27:23 | ||||
| 2024-10-25 17:12:39 | ||||
| 1. 优化点对网和网对网的局域网IP,包括禁用IP,和冲突检测 | ||||
| 2. 一些UI优化 | ||||
| 3. 测试中,测试中,测试中,不要更新,用v1.4.9 | ||||
| 3. 新增socks5代理 | ||||
| 4. 优化端口转发和内网穿透配置 | ||||
| 5. 优化网卡的一些东西 | ||||
| 6. 测试中,测试中,测试中,不要更新,用v1.4.9 | ||||
		Reference in New Issue
	
	Block a user
	 snltty
					snltty