Commit 16665cdc authored by nanahira's avatar nanahira

add log and retry plain connection

parent 6a8ddefa
Pipeline #21235 passed with stages
in 2 minutes and 57 seconds
import { createProxyServer } from '@mutagen-d/node-proxy-server'; import { createProxyServer } from '@mutagen-d/node-proxy-server';
import { Server, createConnection } from 'net'; import { Server, createConnection } from 'net';
import { hashAddress } from './src/hash-address'; import { hashAddress } from './src/hash-address';
import { createLogger } from 'bunyan';
import { Socket } from 'net';
declare module 'net' { declare module 'net' {
interface Server { interface Server {
...@@ -17,15 +19,30 @@ declare module 'net' { ...@@ -17,15 +19,30 @@ declare module 'net' {
} }
const targetIpSym = Symbol('targetIp'); const targetIpSym = Symbol('targetIp');
const log = createLogger({ name: 'switcher' });
const server: Server = createProxyServer({ const server: Server = createProxyServer({
auth: true, auth: true,
createProxyConnection: async (info) => { createProxyConnection: async (info) => {
const socket = createConnection({ let socket: Socket;
host: info.dstHost, log.info(
port: info.dstPort, `Connecting to ${info.dstHost}:${info.dstPort} with ${info.socket[targetIpSym]}`,
localAddress: info.socket[targetIpSym] || undefined, );
}); try {
socket = createConnection({
host: info.dstHost,
port: info.dstPort,
localAddress: info.socket[targetIpSym] || undefined,
});
} catch (e) {
log.warn(
`Failed to connect to ${info.dstHost}:${info.dstPort}, retrying direct connection: ${e}`,
);
socket = createConnection({
host: info.dstHost,
port: info.dstPort,
});
}
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
socket.on('connect', () => resolve(socket)); socket.on('connect', () => resolve(socket));
socket.on('error', (error) => reject(error)); socket.on('error', (error) => reject(error));
...@@ -40,11 +57,11 @@ server.on('proxy-auth', (socket, username, password, callback) => { ...@@ -40,11 +57,11 @@ server.on('proxy-auth', (socket, username, password, callback) => {
} }
const token = `${username}:${password}`; const token = `${username}:${password}`;
socket[targetIpSym] = hashAddress(process.env.CIDR, token).toString(); socket[targetIpSym] = hashAddress(process.env.CIDR, token).toString();
console.log(`Mapped ${token} to ${socket[targetIpSym]}`); log.info(`Mapped ${token} to ${socket[targetIpSym]}`);
callback(true); callback(true);
}); });
const port = parseInt(process.env.PORT || '8080'); const port = parseInt(process.env.PORT || '8080');
server.listen(port, process.env.HOST || '0.0.0.0', () => server.listen(port, process.env.HOST || '0.0.0.0', () =>
console.log(`Listening on port ${port}`), log.info(`Listening on port ${port}`),
); );
...@@ -11,9 +11,11 @@ ...@@ -11,9 +11,11 @@
"dependencies": { "dependencies": {
"@mutagen-d/node-proxy-server": "^1.0.2", "@mutagen-d/node-proxy-server": "^1.0.2",
"@stdlib/random-base-mt19937": "^0.0.6", "@stdlib/random-base-mt19937": "^0.0.6",
"bunyan": "^1.8.15",
"ipaddr.js": "^2.0.1" "ipaddr.js": "^2.0.1"
}, },
"devDependencies": { "devDependencies": {
"@types/bunyan": "^1.8.8",
"@types/jest": "^29.5.0", "@types/jest": "^29.5.0",
"@types/node": "^18.15.11", "@types/node": "^18.15.11",
"@typescript-eslint/eslint-plugin": "^5.58.0", "@typescript-eslint/eslint-plugin": "^5.58.0",
...@@ -9363,6 +9365,15 @@ ...@@ -9363,6 +9365,15 @@
"@babel/types": "^7.3.0" "@babel/types": "^7.3.0"
} }
}, },
"node_modules/@types/bunyan": {
"version": "1.8.8",
"resolved": "https://registry.npmjs.org/@types/bunyan/-/bunyan-1.8.8.tgz",
"integrity": "sha512-Cblq+Yydg3u+sGiz2mjHjC5MPmdjY+No4qvHrF+BUhblsmSfMvsHLbOG62tPbonsqBj6sbWv1LHcsoe5Jw+/Ow==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/graceful-fs": { "node_modules/@types/graceful-fs": {
"version": "4.1.6", "version": "4.1.6",
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz",
...@@ -9872,13 +9883,13 @@ ...@@ -9872,13 +9883,13 @@
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true "devOptional": true
}, },
"node_modules/brace-expansion": { "node_modules/brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true, "devOptional": true,
"dependencies": { "dependencies": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
...@@ -9951,6 +9962,23 @@ ...@@ -9951,6 +9962,23 @@
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true "dev": true
}, },
"node_modules/bunyan": {
"version": "1.8.15",
"resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.15.tgz",
"integrity": "sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==",
"engines": [
"node >=0.10.0"
],
"bin": {
"bunyan": "bin/bunyan"
},
"optionalDependencies": {
"dtrace-provider": "~0.8",
"moment": "^2.19.3",
"mv": "~2",
"safe-json-stringify": "~1"
}
},
"node_modules/callsites": { "node_modules/callsites": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
...@@ -10087,7 +10115,7 @@ ...@@ -10087,7 +10115,7 @@
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true "devOptional": true
}, },
"node_modules/convert-source-map": { "node_modules/convert-source-map": {
"version": "2.0.0", "version": "2.0.0",
...@@ -10189,6 +10217,19 @@ ...@@ -10189,6 +10217,19 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/dtrace-provider": {
"version": "0.8.8",
"resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz",
"integrity": "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==",
"hasInstallScript": true,
"optional": true,
"dependencies": {
"nan": "^2.14.0"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.4.363", "version": "1.4.363",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.363.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.363.tgz",
...@@ -10892,7 +10933,7 @@ ...@@ -10892,7 +10933,7 @@
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"dev": true, "devOptional": true,
"dependencies": { "dependencies": {
"once": "^1.3.0", "once": "^1.3.0",
"wrappy": "1" "wrappy": "1"
...@@ -10902,7 +10943,7 @@ ...@@ -10902,7 +10943,7 @@
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true "devOptional": true
}, },
"node_modules/ipaddr.js": { "node_modules/ipaddr.js": {
"version": "2.0.1", "version": "2.0.1",
...@@ -11841,7 +11882,7 @@ ...@@ -11841,7 +11882,7 @@
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true, "devOptional": true,
"dependencies": { "dependencies": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
}, },
...@@ -11866,12 +11907,81 @@ ...@@ -11866,12 +11907,81 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/mkdirp": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
"optional": true,
"dependencies": {
"minimist": "^1.2.6"
},
"bin": {
"mkdirp": "bin/cmd.js"
}
},
"node_modules/moment": {
"version": "2.29.4",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
"optional": true,
"engines": {
"node": "*"
}
},
"node_modules/ms": { "node_modules/ms": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true "dev": true
}, },
"node_modules/mv": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz",
"integrity": "sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==",
"optional": true,
"dependencies": {
"mkdirp": "~0.5.1",
"ncp": "~2.0.0",
"rimraf": "~2.4.0"
},
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/mv/node_modules/glob": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz",
"integrity": "sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==",
"optional": true,
"dependencies": {
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "2 || 3",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
}
},
"node_modules/mv/node_modules/rimraf": {
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz",
"integrity": "sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==",
"optional": true,
"dependencies": {
"glob": "^6.0.1"
},
"bin": {
"rimraf": "bin.js"
}
},
"node_modules/nan": {
"version": "2.17.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz",
"integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==",
"optional": true
},
"node_modules/natural-compare": { "node_modules/natural-compare": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
...@@ -11884,6 +11994,15 @@ ...@@ -11884,6 +11994,15 @@
"integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
"dev": true "dev": true
}, },
"node_modules/ncp": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz",
"integrity": "sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==",
"optional": true,
"bin": {
"ncp": "bin/ncp"
}
},
"node_modules/node-int64": { "node_modules/node-int64": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
...@@ -11921,7 +12040,7 @@ ...@@ -11921,7 +12040,7 @@
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dev": true, "devOptional": true,
"dependencies": { "dependencies": {
"wrappy": "1" "wrappy": "1"
} }
...@@ -12040,7 +12159,7 @@ ...@@ -12040,7 +12159,7 @@
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"dev": true, "devOptional": true,
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
...@@ -12479,6 +12598,12 @@ ...@@ -12479,6 +12598,12 @@
"queue-microtask": "^1.2.2" "queue-microtask": "^1.2.2"
} }
}, },
"node_modules/safe-json-stringify": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz",
"integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==",
"optional": true
},
"node_modules/semver": { "node_modules/semver": {
"version": "7.4.0", "version": "7.4.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz",
...@@ -12964,7 +13089,7 @@ ...@@ -12964,7 +13089,7 @@
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true "devOptional": true
}, },
"node_modules/write-file-atomic": { "node_modules/write-file-atomic": {
"version": "4.0.2", "version": "4.0.2",
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
"patch": "sed -i -e \"s/server.emit('proxy-auth', user/server.emit('proxy-auth', socket, user/g\" -e \"s/server.emit('proxy-auth', ''/server.emit('proxy-auth', socket, ''/g\" -e \"s/await createProxyConnection({ srcHost, srcPort/await createProxyConnection({ socket, srcHost, srcPort/g\" -e \"s/await createProxyConnection({ dstHost, dstPort/await createProxyConnection({ socket, dstHost, dstPort/g\" -e \"s/server.emit('error', e)//g\" ./node_modules/@mutagen-d/node-proxy-server/src/index.js", "patch": "sed -i -e \"s/server.emit('proxy-auth', user/server.emit('proxy-auth', socket, user/g\" -e \"s/server.emit('proxy-auth', ''/server.emit('proxy-auth', socket, ''/g\" -e \"s/await createProxyConnection({ srcHost, srcPort/await createProxyConnection({ socket, srcHost, srcPort/g\" -e \"s/await createProxyConnection({ dstHost, dstPort/await createProxyConnection({ socket, dstHost, dstPort/g\" -e \"s/server.emit('error', e)//g\" ./node_modules/@mutagen-d/node-proxy-server/src/index.js",
"build": "rimraf dist && npm run patch && tsc", "build": "rimraf dist && npm run patch && tsc",
"test": "jest --passWithNoTests", "test": "jest --passWithNoTests",
"start": "node dist/index.js" "start": "node dist/index.js | bunyan"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
"testEnvironment": "node" "testEnvironment": "node"
}, },
"devDependencies": { "devDependencies": {
"@types/bunyan": "^1.8.8",
"@types/jest": "^29.5.0", "@types/jest": "^29.5.0",
"@types/node": "^18.15.11", "@types/node": "^18.15.11",
"@typescript-eslint/eslint-plugin": "^5.58.0", "@typescript-eslint/eslint-plugin": "^5.58.0",
...@@ -56,6 +57,7 @@ ...@@ -56,6 +57,7 @@
"dependencies": { "dependencies": {
"@mutagen-d/node-proxy-server": "^1.0.2", "@mutagen-d/node-proxy-server": "^1.0.2",
"@stdlib/random-base-mt19937": "^0.0.6", "@stdlib/random-base-mt19937": "^0.0.6",
"bunyan": "^1.8.15",
"ipaddr.js": "^2.0.1" "ipaddr.js": "^2.0.1"
} }
} }
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