initial commit
This commit is contained in:
commit
5fa84e31b9
|
|
@ -0,0 +1,7 @@
|
||||||
|
node_modules/
|
||||||
|
./node_modules/
|
||||||
|
node_modules/*
|
||||||
|
node_modules/**
|
||||||
|
./node_modules/*
|
||||||
|
./node_modules/**
|
||||||
|
package-lock.json
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
# FearlessVPN-NG
|
||||||
|
Новый FearlessVPN (старый скоро будет доступен) работает по UDP (старый работал по HTTPS, хоть через Cloudflare).
|
||||||
|
|
||||||
|
# Как настроить
|
||||||
|
Мне лень всё расписывать, вроде всё понятно.
|
||||||
|
|
||||||
|
# Как перенаправить весь трафик
|
||||||
|
На Linux надо делать что-то с `ip route`. Не шарю
|
||||||
|
|
||||||
|
# Завершение
|
||||||
|
Самый понятный README. Потом переделаю.
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
type: client
|
||||||
|
port: 5454
|
||||||
|
endpoint: 192.168.0.158
|
||||||
|
mtu: 1400
|
||||||
|
subnet: 10.3.8.0
|
||||||
|
len: 24
|
||||||
|
iv: aiD6UuDsVPJyKudkc_SZBUlH-MRzLaZROiQwD11irtI
|
||||||
|
globalKey: mcCOmjwTUF6jNFQkbTWHrwyOMA6KV7oRFrK8lIawT5U
|
||||||
|
algorithm: aes-256-cbc
|
||||||
|
privateKey: Wf7U1DzfrkkFs9OugXHauYqmgfyWVLwxXoskrOebObg
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
// 13 b4 37 XX XX XX XX > (pk) - Authenticated
|
||||||
|
// 13 37 > (pk) - I am <...>
|
||||||
|
// e7 5a 3d ed > (gk) - Authenticate yourself
|
||||||
|
// 55 44 e9 37 < (pk) - Forget me
|
||||||
|
// e7 5a 3d ea > (pk) - Forget me. OK
|
||||||
|
|
||||||
|
const dgram = require('dgram');
|
||||||
|
const net = require('net');
|
||||||
|
const { Tun } = require('tuntap2');
|
||||||
|
const { encrypt, decrypt } = require('../encryption');
|
||||||
|
const IP = require('ip-packet');
|
||||||
|
const sock = dgram.createSocket('udp4');
|
||||||
|
|
||||||
|
const tun = new Tun();
|
||||||
|
|
||||||
|
var established = false;
|
||||||
|
|
||||||
|
sock.on('message', (msg, info) => {
|
||||||
|
const pd = decrypt(msg, config.privateKey, config.iv, config.algorithm);
|
||||||
|
const gd = decrypt(msg, config.globalKey, config.iv, config.algorithm);
|
||||||
|
const dec = pd.length == 0 ? gd : pd;
|
||||||
|
if (dec.length == 4 && dec[0] == 0xe7 && dec[1] == 0x5a && dec[2] == 0x3d && dec[3] == 0xed) {
|
||||||
|
console.log(`Server asks to authenticate. Authenticating...`);
|
||||||
|
authenticateAndCheck();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (dec.length == 7 && dec[0] == 0x13 && dec[1] == 0xb4 && dec[2] == 0x37) {
|
||||||
|
const ip = dec.slice(3);
|
||||||
|
const strIp = ip.map(s => s.toString()).join('.');
|
||||||
|
console.log(`My IP: ${strIp}`);
|
||||||
|
tun.mtu = config.mtu;
|
||||||
|
tun.ipv4 = `${strIp}/${config.len}`;
|
||||||
|
tun.isUp = true;
|
||||||
|
tun.on('data', (d) => {
|
||||||
|
sock.send(
|
||||||
|
encrypt(
|
||||||
|
d,
|
||||||
|
config.privateKey,
|
||||||
|
config.iv,
|
||||||
|
config.algorithm
|
||||||
|
),
|
||||||
|
config.port,
|
||||||
|
config.endpoint
|
||||||
|
);
|
||||||
|
});
|
||||||
|
established = true;
|
||||||
|
}
|
||||||
|
if (established && (dec[0] >> 4 == 4)) {
|
||||||
|
tun.write(dec);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function authenticate() {
|
||||||
|
sock.send(
|
||||||
|
encrypt(
|
||||||
|
Buffer.from([
|
||||||
|
0x13, 0x37
|
||||||
|
]),
|
||||||
|
config.privateKey,
|
||||||
|
config.iv,
|
||||||
|
config.algorithm
|
||||||
|
),
|
||||||
|
config.port,
|
||||||
|
config.endpoint
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function authenticateAndCheck() {
|
||||||
|
authenticate();
|
||||||
|
|
||||||
|
var i = setInterval(() => {
|
||||||
|
if (!established) {
|
||||||
|
console.log(`Connection not established. Authenticating again...`);
|
||||||
|
authenticate();
|
||||||
|
} else {
|
||||||
|
clearInterval(i);
|
||||||
|
console.log(`Authenticated.`);
|
||||||
|
}
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
authenticateAndCheck();
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
const fs = require('fs');
|
||||||
|
const YAML = require('yaml');
|
||||||
|
|
||||||
|
function getConfig(file) {
|
||||||
|
return YAML.parse(fs.readFileSync(file, 'utf-8'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveConfig(file, conf) {
|
||||||
|
fs.writeFileSync(file, YAML.stringify(conf));
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getConfig,
|
||||||
|
saveConfig
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
const { getConfig, saveConfig } = require("./config");
|
||||||
|
const genkey = require("./genkey");
|
||||||
|
|
||||||
|
const configFile = process.argv[2];
|
||||||
|
|
||||||
|
const config = getConfig(configFile);
|
||||||
|
|
||||||
|
if (config.type != 'server') {
|
||||||
|
console.error('Not server');
|
||||||
|
process.exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [ username, addr ] = process.argv.slice(3);
|
||||||
|
const user = {
|
||||||
|
username,
|
||||||
|
addr,
|
||||||
|
key: genkey.genkey()
|
||||||
|
};
|
||||||
|
|
||||||
|
config.users[username] = user;
|
||||||
|
saveConfig(configFile, config);
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
function encrypt(payload, key, secret_iv, algorithm) {
|
||||||
|
try {
|
||||||
|
const iv = crypto
|
||||||
|
.createHash('sha512')
|
||||||
|
.update(secret_iv)
|
||||||
|
.digest('hex')
|
||||||
|
.substring(0, 16)
|
||||||
|
const cipher = crypto.createCipheriv(algorithm, crypto
|
||||||
|
.createHash('sha512')
|
||||||
|
.update(key)
|
||||||
|
.digest('hex')
|
||||||
|
.substring(0, 32), iv);
|
||||||
|
let encrypted = cipher.update(payload, 'binary', 'binary');
|
||||||
|
encrypted += cipher.final('binary');
|
||||||
|
return Buffer.from(encrypted, 'binary');
|
||||||
|
} catch (error) {
|
||||||
|
return Buffer.from('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function decrypt(payload, key, secret_iv, algorithm) {
|
||||||
|
try {
|
||||||
|
const iv = crypto
|
||||||
|
.createHash('sha512')
|
||||||
|
.update(secret_iv)
|
||||||
|
.digest('hex')
|
||||||
|
.substring(0, 16)
|
||||||
|
const decipher = crypto.createDecipheriv(algorithm, crypto
|
||||||
|
.createHash('sha512')
|
||||||
|
.update(key)
|
||||||
|
.digest('hex')
|
||||||
|
.substring(0, 32), iv);
|
||||||
|
let decrypted = decipher.update(payload, 'binary', 'binary');
|
||||||
|
decrypted += decipher.final('binary');
|
||||||
|
return Buffer.from(decrypted, 'binary');
|
||||||
|
} catch (error) {
|
||||||
|
return Buffer.from('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
encrypt, decrypt
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
const md5 = require('md5');
|
||||||
|
const { v4 } = require('uuid');
|
||||||
|
|
||||||
|
console.log(Buffer.from(md5(v4()) + md5(v4()), 'hex').toString('base64url'));
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
genkey: () => {
|
||||||
|
return Buffer.from(md5(v4()) + md5(v4()), 'hex').toString('base64url');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
const { getConfig } = require("./config");
|
||||||
|
|
||||||
|
const [ nodejs, indexjs, configFile ] = process.argv;
|
||||||
|
|
||||||
|
const conf = getConfig(configFile);
|
||||||
|
|
||||||
|
globalThis.configFile = configFile;
|
||||||
|
globalThis.config = conf;
|
||||||
|
|
||||||
|
if (conf.type == 'server') {
|
||||||
|
require('./server/');
|
||||||
|
} else if (conf.type == 'client') {
|
||||||
|
require('./client/');
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"name": "fearlessvpn_ng",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "OfficialDakari",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"crystals-kyber": "^5.1.0",
|
||||||
|
"ip-packet": "^1.1.0",
|
||||||
|
"md5": "^2.3.0",
|
||||||
|
"tuntap2": "^0.9.1",
|
||||||
|
"uuid": "^9.0.1",
|
||||||
|
"yaml": "^2.4.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
type: server
|
||||||
|
port: 5454
|
||||||
|
mtu: 1400
|
||||||
|
subnet: 10.3.8.0
|
||||||
|
len: 24
|
||||||
|
addr: 10.3.8.1
|
||||||
|
iv: aiD6UuDsVPJyKudkc_SZBUlH-MRzLaZROiQwD11irtI
|
||||||
|
globalKey: mcCOmjwTUF6jNFQkbTWHrwyOMA6KV7oRFrK8lIawT5U
|
||||||
|
algorithm: aes-256-cbc
|
||||||
|
users:
|
||||||
|
officialdakari:
|
||||||
|
username: officialdakari
|
||||||
|
addr: 10.3.8.2
|
||||||
|
key: Wf7U1DzfrkkFs9OugXHauYqmgfyWVLwxXoskrOebObg
|
||||||
|
|
@ -0,0 +1,130 @@
|
||||||
|
// 13 b4 37 XX XX XX XX > (pk) - Authenticated
|
||||||
|
// 13 37 > (pk) - I am <...>
|
||||||
|
// e7 5a 3d ed > (gk) - Authenticate yourself
|
||||||
|
// 55 44 e9 37 < (pk) - Forget me
|
||||||
|
// e7 5a 3d ea > (pk) - Forget me. OK
|
||||||
|
|
||||||
|
const dgram = require('dgram');
|
||||||
|
const net = require('net');
|
||||||
|
const { Tun } = require('tuntap2');
|
||||||
|
const { encrypt, decrypt } = require('../encryption');
|
||||||
|
const IP = require('ip-packet');
|
||||||
|
|
||||||
|
const conns = {};
|
||||||
|
const ips = {};
|
||||||
|
const ports = {};
|
||||||
|
|
||||||
|
const sock = dgram.createSocket('udp4');
|
||||||
|
|
||||||
|
const l = new net.BlockList();
|
||||||
|
l.addSubnet(config.subnet, config.len);
|
||||||
|
|
||||||
|
const tun = new Tun();
|
||||||
|
|
||||||
|
tun.mtu = config.mtu;
|
||||||
|
tun.ipv4 = `${config.addr}/${config.len}`;
|
||||||
|
tun.isUp = true;
|
||||||
|
|
||||||
|
tun.on('data', (buff) => {
|
||||||
|
if (buff[0] >> 4 !== 4) return;
|
||||||
|
const p = IP.decode(buff);
|
||||||
|
//(p);
|
||||||
|
const user = Object.values(config.users).find(x => x.addr == p.destinationIp);
|
||||||
|
//(user);
|
||||||
|
if (!user) return;
|
||||||
|
const targetIp = ips[user.username];
|
||||||
|
const targetPort = ports[user.username];
|
||||||
|
//(targetIp, targetPort);
|
||||||
|
if (!targetIp || !targetPort) return;
|
||||||
|
sock.send(encrypt(IP.encode(p), user.key, config.iv, config.algorithm), targetPort, targetIp);
|
||||||
|
})
|
||||||
|
|
||||||
|
sock.on('listening', () => {
|
||||||
|
const a = sock.address();
|
||||||
|
console.log(`Listening on ${a.address}:${a.port}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
sock.on('message', (msg, info) => {
|
||||||
|
if (!conns[info.address]) {
|
||||||
|
for (const uname in config.users) {
|
||||||
|
const u = config.users[uname];
|
||||||
|
const dec = decrypt(msg, u.key, config.iv, config.algorithm);
|
||||||
|
if (dec.length == 2 && dec[0] == 0x13 && dec[1] == 0x37) {
|
||||||
|
conns[info.address] = uname;
|
||||||
|
ips[uname] = info.address;
|
||||||
|
const spl = u.addr.split('.').map(s => parseInt(s));
|
||||||
|
const buff = Buffer.from([
|
||||||
|
0x13,
|
||||||
|
0xb4,
|
||||||
|
0x37,
|
||||||
|
...spl
|
||||||
|
]);
|
||||||
|
const enc = encrypt(buff, u.key, config.iv, config.algorithm);
|
||||||
|
sock.send(enc, info.port, info.address);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const buff = Buffer.from([
|
||||||
|
0xe7,
|
||||||
|
0x5a,
|
||||||
|
0x3d,
|
||||||
|
0xed
|
||||||
|
]);
|
||||||
|
const enc = encrypt(buff, config.globalKey, config.iv, config.algorithm);
|
||||||
|
sock.send(enc, info.port, info.address);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
const uname = conns[info.address];
|
||||||
|
ports[uname] = info.port;
|
||||||
|
ips[uname] = info.address;
|
||||||
|
const acc = config.users[uname];
|
||||||
|
const dec = decrypt(msg, acc.key, config.iv, config.algorithm);
|
||||||
|
//(dec);
|
||||||
|
if (dec.length == 0) {
|
||||||
|
console.error(`Empty or malformed packet from ${uname}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (dec.length == 2 && dec[0] == 0x13 && dec[1] == 0x37) {
|
||||||
|
const spl = acc.addr.split('.').map(s => parseInt(s));
|
||||||
|
const buff = Buffer.from([
|
||||||
|
0x13,
|
||||||
|
0xb4,
|
||||||
|
0x37,
|
||||||
|
...spl
|
||||||
|
]);
|
||||||
|
const enc = encrypt(buff, acc.key, config.iv, config.algorithm);
|
||||||
|
sock.send(enc, info.port, info.address);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (dec.length == 4 &&
|
||||||
|
dec[0] == 0x55 && dec[1] == 0x44 && dec[2] == 0xe9 && dec[3] == 0x37) {
|
||||||
|
const buff = Buffer.from([
|
||||||
|
0xe7,
|
||||||
|
0x5a,
|
||||||
|
0x3d,
|
||||||
|
0xea
|
||||||
|
]);
|
||||||
|
const enc = encrypt(buff, acc.key, config.iv, config.algorithm);
|
||||||
|
sock.send(enc, info.port, info.address);
|
||||||
|
delete conns[info.address];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((dec[0] >> 4) !== 4) return;
|
||||||
|
const packet = IP.decode(dec);
|
||||||
|
//(packet);
|
||||||
|
packet.sourceIp = acc.addr;
|
||||||
|
if ((config.allow_outbound && !l.check(packet.destinationIp)) || packet.destinationIp == config.addr) {
|
||||||
|
tun.write(dec);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const user = Object.values(config.users).find(x => x.addr == packet.destinationIp);
|
||||||
|
if (!user) return;
|
||||||
|
const targetIp = conns[user.username];
|
||||||
|
const targetPort = ports[user.username];
|
||||||
|
if (!targetIp || !targetPort) return;
|
||||||
|
sock.send(encrypt(dec, user.key, config.iv, config.algorithm), targetPort, targetIp);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
sock.bind(config.port);
|
||||||
Loading…
Reference in New Issue