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