Commit ad331e4e authored by nanahira's avatar nanahira

just wait for ssh

parent a05c64e5
...@@ -3214,6 +3214,11 @@ ...@@ -3214,6 +3214,11 @@
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
}, },
"eventemitter3": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
},
"events": { "events": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz",
...@@ -5608,8 +5613,7 @@ ...@@ -5608,8 +5613,7 @@
"p-finally": { "p-finally": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
"dev": true
}, },
"p-limit": { "p-limit": {
"version": "2.3.0", "version": "2.3.0",
...@@ -5627,6 +5631,23 @@ ...@@ -5627,6 +5631,23 @@
"p-limit": "^2.2.0" "p-limit": "^2.2.0"
} }
}, },
"p-queue": {
"version": "6.6.2",
"resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz",
"integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==",
"requires": {
"eventemitter3": "^4.0.4",
"p-timeout": "^3.2.0"
}
},
"p-timeout": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz",
"integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==",
"requires": {
"p-finally": "^1.0.0"
}
},
"p-try": { "p-try": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
......
...@@ -13,6 +13,7 @@ import * as IP from 'ip'; ...@@ -13,6 +13,7 @@ import * as IP from 'ip';
import * as _ from 'underscore'; import * as _ from 'underscore';
import { AppLogger } from './logger.service'; import { AppLogger } from './logger.service';
import { User } from './entities/User'; import { User } from './entities/User';
import PQueue from 'p-queue';
const validDestinations = ['chnroute', 'all']; const validDestinations = ['chnroute', 'all'];
...@@ -30,6 +31,7 @@ export class AppService { ...@@ -30,6 +31,7 @@ export class AppService {
routers: Router[]; routers: Router[];
gatewayGroups: GatewayGroup[]; gatewayGroups: GatewayGroup[];
railgunRules: RailgunRule[]; railgunRules: RailgunRule[];
syncQueue: PQueue;
constructor( constructor(
@InjectConnection('railgun') @InjectConnection('railgun')
private db: Connection, private db: Connection,
...@@ -41,17 +43,40 @@ export class AppService { ...@@ -41,17 +43,40 @@ export class AppService {
this.routers = this.configService.get('routers'); this.routers = this.configService.get('routers');
this.gatewayGroups = this.configService.get('gatewayGroups'); this.gatewayGroups = this.configService.get('gatewayGroups');
this.railgunRules = this.configService.get('railgunRules'); this.railgunRules = this.configService.get('railgunRules');
this.syncQueue = new PQueue({ concurrency: 1 });
this.addSyncTask();
}
private async syncRouter(router: Router, users: User[]) {
const ipsetData = this.getIpsetOfRouter(router, users);
// replace this part with real ssh things
console.log(router.name);
console.log(ipsetData);
}
private async sync() {
const users = await this.db.getRepository(User).find();
await Promise.all(
this.routers.map((router) => this.syncRouter(router, users)),
);
}
private async addSyncTask() {
return await this.syncQueue.add(async () => {
this.sync();
});
} }
private subnetsContain(subnets: string[], ip) { private subnetsContain(subnets: string[], ip) {
return subnets.some((subnet) => IP.cidrSubnet(subnet).contains(ip)); return subnets.some((subnet) => IP.cidrSubnet(subnet).contains(ip));
} }
private isGatewayAllowed(ip: string, gateway: Gateway) { private isGatewayAllowed(ip: string, gateway: Gateway, localOnly?: boolean) {
if (!gateway.hidden) { if (gateway.hidden) {
// 允许自己的网关的所有IP return false;
const router = gateway.routerInfo; }
if (router && this.subnetsContain(router.subnets, ip)) { // 允许自己的网关的所有IP
return true; const router = gateway.routerInfo;
} if (router && this.subnetsContain(router.subnets, ip)) {
return true;
}
if (localOnly) {
return false;
} }
// 在 railgun enterprise 表中有的IP // 在 railgun enterprise 表中有的IP
return this.railgunRules.some((rule) => { return this.railgunRules.some((rule) => {
...@@ -78,7 +103,7 @@ export class AppService { ...@@ -78,7 +103,7 @@ export class AppService {
} }
private getAllSuitableGateways(ip: string) { private getAllSuitableGateways(ip: string) {
return this.gateways.filter((gateway) => return this.gateways.filter((gateway) =>
this.isGatewayAllowed(ip, gateway), this.isGatewayAllowed(ip, gateway, false),
); );
} }
private getGatewayDisplayData( private getGatewayDisplayData(
...@@ -117,7 +142,7 @@ export class AppService { ...@@ -117,7 +142,7 @@ export class AppService {
async getClientData(rawAddress: string) { async getClientData(rawAddress: string) {
const ip = this.sortAddress(rawAddress); const ip = this.sortAddress(rawAddress);
const displayGateways = this.gateways const displayGateways = this.gateways
.filter((gateway) => this.isGatewayAllowed(ip, gateway)) .filter((gateway) => this.isGatewayAllowed(ip, gateway, false))
.map((gateway) => this.getGatewayDisplayData(gateway, ip)); .map((gateway) => this.getGatewayDisplayData(gateway, ip));
const displayGroups = this.gatewayGroups const displayGroups = this.gatewayGroups
.filter((group) => this.isGatewayGroupAllowed(ip, group)) .filter((group) => this.isGatewayGroupAllowed(ip, group))
...@@ -129,17 +154,91 @@ export class AppService { ...@@ -129,17 +154,91 @@ export class AppService {
}; };
} }
private checkId(id: number, ip: string) { private checkId(id: number, ip: string, localOnly: boolean) {
if (!id) { if (!id) {
return true; return true;
} }
if (id > 20000) { if (id > 20000 && !localOnly) {
const gatewayGroup = this.gatewayGroups.find((g) => g.id === id); const gatewayGroup = this.gatewayGroups.find((g) => g.id === id);
return gatewayGroup && this.isGatewayGroupAllowed(ip, gatewayGroup); return gatewayGroup && this.isGatewayGroupAllowed(ip, gatewayGroup);
} else { } else {
const gateway = this.gateways.find((gw) => gw.id === id); const gateway = this.gateways.find((gw) => gw.id === id);
return this.isGatewayAllowed(ip, gateway); return gateway && this.isGatewayAllowed(ip, gateway, localOnly);
}
}
private getGatewayOrGroupFromId(id: number) {
if (id > 20000) {
const gatewayGroup = this.gatewayGroups.find((g) => g.id === id);
return gatewayGroup;
} else {
const gateway = this.gateways.find((gw) => gw.id === id);
return gateway;
}
}
getIpsetNamesOfRouter(router: Router) {
const ipsets: string[] = [];
for (const destination of validDestinations) {
const selfGateways = this.gateways.filter(
(gateway) => router.name === gateway.router,
);
for (const gateway of selfGateways) {
ipsets.push(`u_${gateway.isp}_${destination}`);
}
const otherRouters = this.routers.filter((r) => r !== router);
for (const r of otherRouters) {
ipsets.push(`u_${r.name.replace(/-/g, '-')}_${destination}`);
}
for (const group of this.gatewayGroups) {
ipsets.push(`u_${group.name}_${destination}`);
}
}
return ipsets;
}
getIpsetOfRouter(router: Router, users: User[]) {
const lines: string[] = this.getIpsetNamesOfRouter(router).map(
(setname) => `flush ${setname}`,
);
for (const group of this.gatewayGroups) {
const matchUsers = users.filter(
(user) =>
user.remoteGatewayId === group.id &&
this.isGatewayGroupAllowed(user.ip, group),
);
for (const user of matchUsers) {
lines.push(`add u_${group.name.replace(/-/g, '_')}_${user.destination} ${user.ip}`);
}
}
for (const gateway of this.gateways) {
const matchUsers = users.filter(
(user) =>
user.remoteGatewayId === gateway.id &&
this.isGatewayAllowed(user.ip, gateway, false),
);
for (const user of matchUsers) {
if (gateway.routerInfo === router) {
lines.push(`add u_${gateway.isp}_${user.destination} ${user.ip}`);
} else {
lines.push(
`add u_${gateway.routerInfo.name.replace(/-/g, '_')}_${user.destination} ${user.ip}`,
);
}
}
}
const selfGateways = this.gateways.filter(
(gateway) => router.name === gateway.router,
);
for (const gateway of selfGateways) {
const setName = `u_${gateway.isp}_all`;
const matchUsers = users.filter(
(user) =>
user.localGatewayId === gateway.id &&
this.isGatewayAllowed(user.ip, gateway, true),
);
for (const user of matchUsers) {
lines.push(`add ${setName} ${user.ip}`);
}
} }
return lines.join('\n');
} }
async postData( async postData(
rawAddress: string, rawAddress: string,
...@@ -157,8 +256,8 @@ export class AppService { ...@@ -157,8 +256,8 @@ export class AppService {
}; };
} }
if ( if (
!this.checkId(remoteGatewayId, ip) || !this.checkId(remoteGatewayId, ip, false) ||
!this.checkId(localGatewayId, ip) !this.checkId(localGatewayId, ip, true)
) { ) {
return { success: false, statusCode: 404, message: 'invalid gateway' }; return { success: false, statusCode: 404, message: 'invalid gateway' };
} }
...@@ -166,6 +265,7 @@ export class AppService { ...@@ -166,6 +265,7 @@ export class AppService {
user.remoteGatewayId = remoteGatewayId || null; user.remoteGatewayId = remoteGatewayId || null;
user.localGatewayId = localGatewayId || null; user.localGatewayId = localGatewayId || null;
await this.db.getRepository(User).save(user); await this.db.getRepository(User).save(user);
this.addSyncTask();
return { success: true, statusCode: 200, message: 'success' }; return { success: true, statusCode: 200, message: 'success' };
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment