Commit 2d543899 authored by nanahira's avatar nanahira

ts part

parent 4826c896
......@@ -114,5 +114,6 @@ dist
*.retry
wgfrp-setconf.conf.j2
certs
__pycache__
- name: '{{conn.name}}: stop wireguard'
become: true
ignore_errors: true
systemd:
name: 'wg-quick@{{conn.name}}'
state: stopped
enabled: no
- name:
explicit-ipv4 = {{conn.remoteLocalAddress}}
route = {{conn.localPeerAddress}}/32
auth = "plain[passwd=/etc/ocserv/ocpasswd]"
listen-host-is-dyndns = true
tcp-port = {{ocservPort}}
udp-port = {{ocservPort}}
run-as-user = nobody
run-as-group = daemon
socket-file = /run/ocserv.socket
server-cert = /etc/ssl/certs/fullchain.pem
server-key = /etc/ssl/certs/privkey.pem
dh-params = /etc/ssl/certs/dhparam.pem
isolate-workers = true
server-stats-reset-time = 604800
keepalive = 300
dpd = 60
mobile-dpd = 300
switch-to-tcp-timeout = 25
try-mtu-discovery = false
cert-user-oid = 0.9.2342.19200300.100.1.1
compression = true
no-compress-limit = 256
tls-priorities = "PERFORMANCE:%SERVER_PRECEDENCE"
match-tls-dtls-ciphers = false
auth-timeout = 240
idle-timeout = 1200
mobile-idle-timeout = 1800
max-ban-score = 80
ban-reset-time = 300
cookie-timeout = 604800
deny-roaming = false
rekey-time = 172800
rekey-method = ssl
connect-script = {{ansible_user_dir}}/nextgen-network/scripts/ocserv-postup.sh
disconnect-script = {{ansible_user_dir}}/nextgen-network/scripts/ocserv-predown.sh
use-occtl = true
pid-file = /run/ocserv.pid
predictable-ips = true
ipv4-network = {{address}}/32
ping-leases = false
# route = 10.198.0.53/32
config-per-user = /etc/ocserv/config-per-user/
cisco-client-compat = false
dtls-legacy = true
#!/bin/bash
dev="$TUNDEV" localPeerAddress={{conn.localPeerAddress}} remotePeerAddress={{conn.remotePeerAddress}} link6Address={{conn.link6Address}} remoteNextMark={{conn.remoteNextMark}} inbound={{conn.inbound}} outbound={{conn.outbound}} mtu={{conn.mtu|int - 66}} {{ansible_user_dir}}/nextgen-network/scripts/predown.sh
#!/bin/bash
dev="$TUNDEV" localPeerAddress={{conn.localPeerAddress}} remotePeerAddress={{conn.remotePeerAddress}} link6Address={{conn.link6Address}} remoteNextMark={{conn.remoteNextMark}} inbound={{conn.inbound}} outbound={{conn.outbound}} mtu={{conn.mtu|int - 66}} {{ansible_user_dir}}/nextgen-network/scripts/postup.sh
......@@ -8,6 +8,16 @@ import child_process from 'child_process';
import assert from 'assert';
import ip from 'ip';
import { promises as dns } from 'dns';
import { off } from 'process';
import os from "os";
async function generateOcpasswdLine(username: string, password: string) {
const tmpName = os.tmpdir() + "/" + Math.floor(Math.random() * 10000000);
await util.promisify(child_process.exec)(`echo "${password}\\n${password}" | ocpasswd -c ${tmpName} ${username}`);
const res = (await fs.promises.readFile(tmpName, "utf-8")).trim();
await fs.promises.unlink(tmpName);
return res;
}
class InventoryBuilder {
hosts: { [key: string]: any };
......@@ -16,6 +26,7 @@ class InventoryBuilder {
routeLists: any;
resolveCache: Map<string, string>;
resolver: dns.Resolver;
vars: any;
async resolveDomain(domain: string, ipv6: boolean) {
if (!domain || domain.match(/(\d{1,3}\.){3}\d{1,3}/)) {
......@@ -90,7 +101,7 @@ class InventoryBuilder {
const rawHosts = await Promise.all(Object.values(this.hosts).map(async (h) => [h.name, await this.host_vars(h)]));
const hosts = Object.fromEntries(rawHosts);
// console.log(hosts);
const vars = await this.loadUtilities();
this.vars = await this.loadUtilities();
const rawHostsForSwitch = rawHosts.map(rh => {
const hostVars = JSON.parse(JSON.stringify(rh[1]));
hostVars.ansible_ssh_host = hostVars.address;
......@@ -99,8 +110,8 @@ class InventoryBuilder {
});
const switchHosts = Object.fromEntries(rawHostsForSwitch);
const result = YAML.stringify({
wg: { hosts, vars },
switch: { hosts: switchHosts, vars: JSON.parse(JSON.stringify(vars)) }
wg: { hosts, vars: this.vars },
switch: { hosts: switchHosts, vars: JSON.parse(JSON.stringify(this.vars)) }
});
return fs.promises.writeFile('result/inventory.yaml', result);
}
......@@ -155,6 +166,7 @@ class InventoryBuilder {
const lanInterfaces = host.lanInterfaces;
const masqInterfaces = host.masqInterfaces.length > 0 ? host.masqInterfaces.split(',') : [];
const routePlans = [];
for (const h of this.connections) {
if (h != host.name) {
const to = host[h]; // 当前主机的条目
......@@ -191,6 +203,8 @@ class InventoryBuilder {
key: host.wgPrivateKey,
frpsNeeded: host.frpsNeeded,
frpsPort: host.frpsPort,
ocservPort: host.ocservPort,
ocservCert: host.ocservCert || null,
gateways: _.values(this.gateways[host.name]),
connections,
lanInterfaces,
......@@ -198,7 +212,7 @@ class InventoryBuilder {
dockerServices: host.dockerServices,
routePlans,
noBird: !!(host.noBird || host.sysBird),
systemBird: !!host.sysBird
systemBird: !!host.sysBird,
};
}
......@@ -231,12 +245,14 @@ class InventoryBuilder {
const localPort = (primary ? remote.port : remote.port2) + local.offset;
const remotePort = (primary ? local.port : local.port2) + remote.offset;
const remoteFrpsPort = remote.frpsPort;
const remoteOcservPort = remote.ocservPort;
const wgPublicKey = remote.wgPublickey;
const localPeerAddress = primary ? `10.200.${local.id}.${remote.id}` : `10.201.${local.id}.${remote.id}`;
const remotePeerAddress = primary ? `10.200.${remote.id}.${local.id}` : `10.201.${remote.id}.${local.id}`;
const link6Address = `fe80::${primary ? 1 : 2}:${local.id}:${remote.id}/64`;
const frpType = protocol === 'wgfrp' ? (this.gatewayCompare(localGateway, remoteGateway) ? 'frps' : 'frpc') : undefined;
const ocType = protocol === 'oc' ? (this.gatewayCompareOcserv(local, remote, localGateway, remoteGateway) ? 'server' : 'client') : undefined;
if (frpType === 'frps' && !local.dockerServices.services.frps) {
local.frpsNeeded = true;
......@@ -259,6 +275,45 @@ class InventoryBuilder {
};
}
if (ocType === 'server') {
if (!local.dockerServices.services.ocserv) {
local.ocservNeeded = true;
local.ocpasswdLines = [];
local.dockerServices.services.ocserv = {
restart: 'always',
image: 'git-registry.mycard.moe/nanahira/docker-ocserv',
network_mode: 'host',
command: 'ocserv -f -d 1',
cap_add: ['NET_ADMIN'],
devices: ['/dev/net/tun:/dev/net/tun'],
volumes: [
'./ocserv/ocserv.conf:/etc/ocserv.conf:ro',
'./ocserv/config-per-user:/etc/ocserv/config-per-user:ro',
'./ocserv/env-per-user:/etc/ocserv/env-per-user:ro',
'./ocserv/ocpasswd:/etc/ocserv/ocpasswd:ro',
'./ocserv/certs:/etc/ssl/certs:ro',
'$HOME/nextgen-network/scripts:$HOME/nextgen-network/scripts:ro'
]
};
}
local.ocpasswdLines.push(await generateOcpasswdLine(name, this.vars.ocservPassword));
}
if (ocType === 'client') {
local.dockerServices.services[`openconnect-${name}`] = {
restart: 'always',
image: 'git-registry.mycard.moe/railgun/openconnect',
network_mode: 'host',
command: ['bash', '-c', `echo '${this.vars.ocservPassword}' | openconnect --user=${name} --passwd-on-stdin --passtos --interface=${name} ${remoteOcservPort}`],
cap_add: ['NET_ADMIN'],
devices: ['/dev/net/tun:/dev/net/tun'],
volumes: [
`./client-scripts/${name}:/etc/vpnc:ro`,
'$HOME/nextgen-network/scripts:$HOME/nextgen-network/scripts:ro'
]
};
}
const mtu = Math.min(localGateway ? localGateway.mtu : 1500, remoteGateway ? remoteGateway.mtu : 1500);
//console.log(local.name, name, mtu);
......@@ -284,7 +339,9 @@ class InventoryBuilder {
remotePeerAddress,
link6Address,
remoteFrpsPort,
//remoteOcservPort,
frpType,
ocType,
inbound,
outbound,
mtu
......@@ -293,23 +350,30 @@ class InventoryBuilder {
// frps还是frpc的积分,NAT越有利分越高
gatewayCompareScore(gateway: any): number {
let score: number = 0xff - gateway.id; // 8 bits
let offset = 0;
let score = 0
score |= (0xff - gateway.id) << offset; // 8 bits
offset += 8;
const isCNScore = gateway.isCN ? 0 : 1; // 1 bit
score |= isCNScore << 8;
score |= isCNScore << offset;
offset += 1;
const ipv4NatScore = ({ // 2 bits
'ports': 0,
'dmz': 1
})[gateway.ipv4Nat] || 2;
score |= ipv4NatScore << 9;
score |= ipv4NatScore << offset;
offset += 2;
const ipv4Score = ({ // 2 bits
'static': 2,
'dynamic': 1
})[gateway.ipv4] || 0;
score |= ipv4Score << 11;
score |= ipv4Score << offset;
offset += 2;
const globalSSHScore = ({ // 1 bit
'globalssh': 1
})[gateway.ssh] || 0;
score |= globalSSHScore << 12;
score |= globalSSHScore << offset;
offset += 1;
return score;
}
......@@ -328,6 +392,17 @@ class InventoryBuilder {
return this.gatewayCompareScore(localGateway) > this.gatewayCompareScore(remoteGateway);
}
gatewayCompareOcserv(local: any, remote: any, localGateway: any, remoteGateway: any): boolean {
// 两边至少一个有证书才能连
assert(local.ocservCert || remote.ocservCert);
// 只有一边有证书用有证书的那边
if (!!local.ocservCert !== !!remote.ocservCert) {
return !!local.ocservCert;
}
return this.gatewayCompare(localGateway, remoteGateway);
}
async wgPublickey(privateKey) {
return new Promise((resolve, reject) => {
const child = child_process.execFile('wg', ['pubkey'], { encoding: 'utf8' }, (error, stdout, stderr) => {
......
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