Commit 2d543899 authored by nanahira's avatar nanahira

ts part

parent 4826c896
...@@ -114,5 +114,6 @@ dist ...@@ -114,5 +114,6 @@ dist
*.retry *.retry
wgfrp-setconf.conf.j2 wgfrp-setconf.conf.j2
certs
__pycache__ __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'; ...@@ -8,6 +8,16 @@ import child_process from 'child_process';
import assert from 'assert'; import assert from 'assert';
import ip from 'ip'; import ip from 'ip';
import { promises as dns } from 'dns'; 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 { class InventoryBuilder {
hosts: { [key: string]: any }; hosts: { [key: string]: any };
...@@ -16,6 +26,7 @@ class InventoryBuilder { ...@@ -16,6 +26,7 @@ class InventoryBuilder {
routeLists: any; routeLists: any;
resolveCache: Map<string, string>; resolveCache: Map<string, string>;
resolver: dns.Resolver; resolver: dns.Resolver;
vars: any;
async resolveDomain(domain: string, ipv6: boolean) { async resolveDomain(domain: string, ipv6: boolean) {
if (!domain || domain.match(/(\d{1,3}\.){3}\d{1,3}/)) { if (!domain || domain.match(/(\d{1,3}\.){3}\d{1,3}/)) {
...@@ -90,7 +101,7 @@ class InventoryBuilder { ...@@ -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 rawHosts = await Promise.all(Object.values(this.hosts).map(async (h) => [h.name, await this.host_vars(h)]));
const hosts = Object.fromEntries(rawHosts); const hosts = Object.fromEntries(rawHosts);
// console.log(hosts); // console.log(hosts);
const vars = await this.loadUtilities(); this.vars = await this.loadUtilities();
const rawHostsForSwitch = rawHosts.map(rh => { const rawHostsForSwitch = rawHosts.map(rh => {
const hostVars = JSON.parse(JSON.stringify(rh[1])); const hostVars = JSON.parse(JSON.stringify(rh[1]));
hostVars.ansible_ssh_host = hostVars.address; hostVars.ansible_ssh_host = hostVars.address;
...@@ -99,8 +110,8 @@ class InventoryBuilder { ...@@ -99,8 +110,8 @@ class InventoryBuilder {
}); });
const switchHosts = Object.fromEntries(rawHostsForSwitch); const switchHosts = Object.fromEntries(rawHostsForSwitch);
const result = YAML.stringify({ const result = YAML.stringify({
wg: { hosts, vars }, wg: { hosts, vars: this.vars },
switch: { hosts: switchHosts, vars: JSON.parse(JSON.stringify(vars)) } switch: { hosts: switchHosts, vars: JSON.parse(JSON.stringify(this.vars)) }
}); });
return fs.promises.writeFile('result/inventory.yaml', result); return fs.promises.writeFile('result/inventory.yaml', result);
} }
...@@ -155,6 +166,7 @@ class InventoryBuilder { ...@@ -155,6 +166,7 @@ class InventoryBuilder {
const lanInterfaces = host.lanInterfaces; const lanInterfaces = host.lanInterfaces;
const masqInterfaces = host.masqInterfaces.length > 0 ? host.masqInterfaces.split(',') : []; const masqInterfaces = host.masqInterfaces.length > 0 ? host.masqInterfaces.split(',') : [];
const routePlans = []; const routePlans = [];
for (const h of this.connections) { for (const h of this.connections) {
if (h != host.name) { if (h != host.name) {
const to = host[h]; // 当前主机的条目 const to = host[h]; // 当前主机的条目
...@@ -191,6 +203,8 @@ class InventoryBuilder { ...@@ -191,6 +203,8 @@ class InventoryBuilder {
key: host.wgPrivateKey, key: host.wgPrivateKey,
frpsNeeded: host.frpsNeeded, frpsNeeded: host.frpsNeeded,
frpsPort: host.frpsPort, frpsPort: host.frpsPort,
ocservPort: host.ocservPort,
ocservCert: host.ocservCert || null,
gateways: _.values(this.gateways[host.name]), gateways: _.values(this.gateways[host.name]),
connections, connections,
lanInterfaces, lanInterfaces,
...@@ -198,7 +212,7 @@ class InventoryBuilder { ...@@ -198,7 +212,7 @@ class InventoryBuilder {
dockerServices: host.dockerServices, dockerServices: host.dockerServices,
routePlans, routePlans,
noBird: !!(host.noBird || host.sysBird), noBird: !!(host.noBird || host.sysBird),
systemBird: !!host.sysBird systemBird: !!host.sysBird,
}; };
} }
...@@ -231,12 +245,14 @@ class InventoryBuilder { ...@@ -231,12 +245,14 @@ class InventoryBuilder {
const localPort = (primary ? remote.port : remote.port2) + local.offset; const localPort = (primary ? remote.port : remote.port2) + local.offset;
const remotePort = (primary ? local.port : local.port2) + remote.offset; const remotePort = (primary ? local.port : local.port2) + remote.offset;
const remoteFrpsPort = remote.frpsPort; const remoteFrpsPort = remote.frpsPort;
const remoteOcservPort = remote.ocservPort;
const wgPublicKey = remote.wgPublickey; const wgPublicKey = remote.wgPublickey;
const localPeerAddress = primary ? `10.200.${local.id}.${remote.id}` : `10.201.${local.id}.${remote.id}`; 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 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 link6Address = `fe80::${primary ? 1 : 2}:${local.id}:${remote.id}/64`;
const frpType = protocol === 'wgfrp' ? (this.gatewayCompare(localGateway, remoteGateway) ? 'frps' : 'frpc') : undefined; 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) { if (frpType === 'frps' && !local.dockerServices.services.frps) {
local.frpsNeeded = true; local.frpsNeeded = true;
...@@ -259,6 +275,45 @@ class InventoryBuilder { ...@@ -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); const mtu = Math.min(localGateway ? localGateway.mtu : 1500, remoteGateway ? remoteGateway.mtu : 1500);
//console.log(local.name, name, mtu); //console.log(local.name, name, mtu);
...@@ -284,7 +339,9 @@ class InventoryBuilder { ...@@ -284,7 +339,9 @@ class InventoryBuilder {
remotePeerAddress, remotePeerAddress,
link6Address, link6Address,
remoteFrpsPort, remoteFrpsPort,
//remoteOcservPort,
frpType, frpType,
ocType,
inbound, inbound,
outbound, outbound,
mtu mtu
...@@ -293,23 +350,30 @@ class InventoryBuilder { ...@@ -293,23 +350,30 @@ class InventoryBuilder {
// frps还是frpc的积分,NAT越有利分越高 // frps还是frpc的积分,NAT越有利分越高
gatewayCompareScore(gateway: any): number { 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 const isCNScore = gateway.isCN ? 0 : 1; // 1 bit
score |= isCNScore << 8; score |= isCNScore << offset;
offset += 1;
const ipv4NatScore = ({ // 2 bits const ipv4NatScore = ({ // 2 bits
'ports': 0, 'ports': 0,
'dmz': 1 'dmz': 1
})[gateway.ipv4Nat] || 2; })[gateway.ipv4Nat] || 2;
score |= ipv4NatScore << 9; score |= ipv4NatScore << offset;
offset += 2;
const ipv4Score = ({ // 2 bits const ipv4Score = ({ // 2 bits
'static': 2, 'static': 2,
'dynamic': 1 'dynamic': 1
})[gateway.ipv4] || 0; })[gateway.ipv4] || 0;
score |= ipv4Score << 11; score |= ipv4Score << offset;
offset += 2;
const globalSSHScore = ({ // 1 bit const globalSSHScore = ({ // 1 bit
'globalssh': 1 'globalssh': 1
})[gateway.ssh] || 0; })[gateway.ssh] || 0;
score |= globalSSHScore << 12; score |= globalSSHScore << offset;
offset += 1;
return score; return score;
} }
...@@ -328,6 +392,17 @@ class InventoryBuilder { ...@@ -328,6 +392,17 @@ class InventoryBuilder {
return this.gatewayCompareScore(localGateway) > this.gatewayCompareScore(remoteGateway); 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) { async wgPublickey(privateKey) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const child = child_process.execFile('wg', ['pubkey'], { encoding: 'utf8' }, (error, stdout, stderr) => { 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