feat(core): allow to custom DNS servers

close: #66
This commit is contained in:
Micooz 2017-06-11 18:44:19 +08:00
parent 1298982c53
commit 77a085d44a
7 changed files with 66 additions and 1 deletions

@ -51,6 +51,7 @@ module.exports = {
{name: "ss-aead-cipher", params: {method: "aes-256-gcm", info: "ss-subkey"}}
]
}],
dns: ['8.8.8.8'],
timeout: 600,
profile: false,
watch: true,

@ -68,6 +68,9 @@ const clientJs = `module.exports = {
}
],
// an ip list of DNS server
dns: [],
// close inactive connection after timeout seconds
timeout: 600,
@ -119,6 +122,9 @@ const serverJs = `module.exports = {
}
],
// an ip list of DNS server
dns: [],
// redirect data to here once preset fail to process(server side only)
// Should be formed with "host:port".
redirect: "",

@ -61,6 +61,9 @@ module.exports = {
}
],
// an ip list of DNS server
dns: [],
// close inactive connection after timeout seconds
timeout: 600,
@ -115,6 +118,9 @@ module.exports = {
}
],
// an ip list of DNS server
dns: [],
// redirect data to here once preset fail to process(server side only)
// Should be formed with "host:port".
redirect: "",
@ -203,3 +209,19 @@ from client.
```
If `redirect` is not provided, connection will be closed after random seconds when server fail to process.
## Custom DNS servers
If you encounter **ENOTFOUND** every now and then, you would better custom dns servers via `dns` options:
```
{
...
"dns": ["8.8.8.8"]
...
}
```
If no `dns` option or no ip provided in `dns`, blinksocks use system dns settings as usual.
See: https://github.com/blinksocks/blinksocks/issues/66

@ -267,6 +267,7 @@ export default class CustomPreset extends IPreset {
| \_\_SERVERS\_\_ |
| \_\_KEY\_\_ |
| \_\_PRESETS\_\_ |
| \_\_DNS\_\_ |
| \_\_REDIRECT\_\_ |
| \_\_TIMEOUT\_\_ |
| \_\_LOG_LEVEL\_\_ |

@ -1 +1 @@
'use strict';Object.defineProperty(exports,'__esModule',{value:true});exports.Config=undefined;var _fs=require('fs');var _fs2=_interopRequireDefault(_fs);var _blinksocksUtils=require('blinksocks-utils');var _constants=require('./constants');function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function mkdir(dir){try{_fs2.default.lstatSync(dir)}catch(err){if(err.code==='ENOENT'){_fs2.default.mkdirSync(dir)}}}mkdir(_constants.BLINKSOCKS_DIR);mkdir(_constants.LOG_DIR);class Config{static validate(json){if(typeof json!=='object'||Array.isArray(json)){throw Error('Invalid configuration file')}if(typeof json.host!=='string'||json.host===''){throw Error('\'host\' must be provided and is not empty')}if(!(0,_blinksocksUtils.isValidPort)(json.port)){throw Error('\'port\' is invalid')}if(typeof json.servers!=='undefined'){if(!Array.isArray(json.servers)){throw Error('\'servers\' must be provided as an array')}const servers=json.servers.filter(server=>server.enabled===true);if(servers.length<1){throw Error('\'servers\' must have at least one enabled item')}servers.forEach(this.validateServer)}else{this.validateServer(json)}if(typeof json.redirect==='string'&&json.redirect!==''){const address=json.redirect.split(':');if(address.length!==2||!(0,_blinksocksUtils.isValidPort)(+address[1])){throw Error('\'redirect\' is an invalid address')}}if(typeof json.timeout!=='number'){throw Error('\'timeout\' must be a number')}if(json.timeout<1){throw Error('\'timeout\' must be greater than 0')}if(json.timeout<60){console.warn(`==> [config] 'timeout' is too short, is ${json.timeout}s expected?`)}}static validateServer(server){if(typeof server.transport!=='string'){throw Error('\'server.transport\' must be a string')}if(!['tcp','udp'].includes(server.transport.toLowerCase())){throw Error('\'server.transport\' must be one of "tcp" or "udp"')}if(typeof server.host!=='string'||server.host===''){throw Error('\'server.host\' must be provided and is not empty')}if(!(0,_blinksocksUtils.isValidPort)(server.port)){throw Error('\'server.port\' is invalid')}if(typeof server.key!=='string'){throw Error('\'server.key\' must be a string')}if(server.key===''){throw Error('\'server.key\' cannot be empty')}if(!Array.isArray(server.presets)){throw Error('\'server.presets\' must be an array')}if(server.presets.length<1){throw Error('\'server.presets\' must contain at least one preset')}var _iteratorNormalCompletion=true;var _didIteratorError=false;var _iteratorError=undefined;try{for(var _iterator=server.presets[Symbol.iterator](),_step;!(_iteratorNormalCompletion=(_step=_iterator.next()).done);_iteratorNormalCompletion=true){const preset=_step.value;const name=preset.name,params=preset.params;if(typeof name==='undefined'){throw Error('\'server.presets[].name\' must be a string')}if(name===''){throw Error('\'server.presets[].name\' cannot be empty')}if(typeof params!=='object'||params===null){throw Error('\'server.presets[].params\' must be an object and not null')}const ps=require(`../presets/${preset.name}`).default;if(name!==server.presets[0].name){delete new ps(params||{})}}}catch(err){_didIteratorError=true;_iteratorError=err}finally{try{if(!_iteratorNormalCompletion&&_iterator.return){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}}}static init(json){this.validate(json);global.__LOCAL_HOST__=json.host;global.__LOCAL_PORT__=json.port;if(typeof json.servers!=='undefined'){global.__SERVERS__=json.servers.filter(server=>server.enabled);global.__IS_CLIENT__=true}else{global.__IS_CLIENT__=false;this.initServer(json)}global.__IS_SERVER__=!global.__IS_CLIENT__;global.__REDIRECT__=json.redirect;global.__TIMEOUT__=json.timeout;global.__PROFILE__=!!json.profile;global.__IS_WATCH__=!!json.watch;global.__LOG_LEVEL__=json.log_level||_constants.DEFAULT_LOG_LEVEL;global.__ALL_CONFIG__=json}static initServer(server){this.validateServer(server);global.__TRANSPORT__=server.transport;global.__SERVER_HOST__=server.host;global.__SERVER_PORT__=server.port;global.__KEY__=server.key;global.__PRESETS__=server.presets}}exports.Config=Config;
'use strict';Object.defineProperty(exports,'__esModule',{value:true});exports.Config=undefined;var _dns=require('dns');var _dns2=_interopRequireDefault(_dns);var _fs=require('fs');var _fs2=_interopRequireDefault(_fs);var _net=require('net');var _net2=_interopRequireDefault(_net);var _blinksocksUtils=require('blinksocks-utils');var _constants=require('./constants');function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function mkdir(dir){try{_fs2.default.lstatSync(dir)}catch(err){if(err.code==='ENOENT'){_fs2.default.mkdirSync(dir)}}}mkdir(_constants.BLINKSOCKS_DIR);mkdir(_constants.LOG_DIR);class Config{static validate(json){if(typeof json!=='object'||Array.isArray(json)){throw Error('Invalid configuration file')}if(typeof json.host!=='string'||json.host===''){throw Error('\'host\' must be provided and is not empty')}if(!(0,_blinksocksUtils.isValidPort)(json.port)){throw Error('\'port\' is invalid')}if(typeof json.servers!=='undefined'){if(!Array.isArray(json.servers)){throw Error('\'servers\' must be provided as an array')}const servers=json.servers.filter(server=>server.enabled===true);if(servers.length<1){throw Error('\'servers\' must have at least one enabled item')}servers.forEach(this.validateServer)}else{this.validateServer(json)}if(typeof json.dns!=='undefined'){if(!Array.isArray(json.dns)){throw Error('\'dns\' must be an array')}var _iteratorNormalCompletion=true;var _didIteratorError=false;var _iteratorError=undefined;try{for(var _iterator=json.dns[Symbol.iterator](),_step;!(_iteratorNormalCompletion=(_step=_iterator.next()).done);_iteratorNormalCompletion=true){const ip=_step.value;if(!_net2.default.isIP(ip)){throw Error(`"${ip}" is not an ip address`)}}}catch(err){_didIteratorError=true;_iteratorError=err}finally{try{if(!_iteratorNormalCompletion&&_iterator.return){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}}}if(typeof json.redirect==='string'&&json.redirect!==''){const address=json.redirect.split(':');if(address.length!==2||!(0,_blinksocksUtils.isValidPort)(+address[1])){throw Error('\'redirect\' is an invalid address')}}if(typeof json.timeout!=='number'){throw Error('\'timeout\' must be a number')}if(json.timeout<1){throw Error('\'timeout\' must be greater than 0')}if(json.timeout<60){console.warn(`==> [config] 'timeout' is too short, is ${json.timeout}s expected?`)}}static validateServer(server){if(typeof server.transport!=='string'){throw Error('\'server.transport\' must be a string')}if(!['tcp','udp'].includes(server.transport.toLowerCase())){throw Error('\'server.transport\' must be one of "tcp" or "udp"')}if(typeof server.host!=='string'||server.host===''){throw Error('\'server.host\' must be provided and is not empty')}if(!(0,_blinksocksUtils.isValidPort)(server.port)){throw Error('\'server.port\' is invalid')}if(typeof server.key!=='string'){throw Error('\'server.key\' must be a string')}if(server.key===''){throw Error('\'server.key\' cannot be empty')}if(!Array.isArray(server.presets)){throw Error('\'server.presets\' must be an array')}if(server.presets.length<1){throw Error('\'server.presets\' must contain at least one preset')}var _iteratorNormalCompletion2=true;var _didIteratorError2=false;var _iteratorError2=undefined;try{for(var _iterator2=server.presets[Symbol.iterator](),_step2;!(_iteratorNormalCompletion2=(_step2=_iterator2.next()).done);_iteratorNormalCompletion2=true){const preset=_step2.value;const name=preset.name,params=preset.params;if(typeof name==='undefined'){throw Error('\'server.presets[].name\' must be a string')}if(name===''){throw Error('\'server.presets[].name\' cannot be empty')}if(typeof params!=='object'||params===null){throw Error('\'server.presets[].params\' must be an object and not null')}const ps=require(`../presets/${preset.name}`).default;if(name!==server.presets[0].name){delete new ps(params||{})}}}catch(err){_didIteratorError2=true;_iteratorError2=err}finally{try{if(!_iteratorNormalCompletion2&&_iterator2.return){_iterator2.return()}}finally{if(_didIteratorError2){throw _iteratorError2}}}}static init(json){this.validate(json);global.__LOCAL_HOST__=json.host;global.__LOCAL_PORT__=json.port;if(typeof json.servers!=='undefined'){global.__SERVERS__=json.servers.filter(server=>server.enabled);global.__IS_CLIENT__=true}else{global.__IS_CLIENT__=false;this.initServer(json)}global.__IS_SERVER__=!global.__IS_CLIENT__;global.__REDIRECT__=json.redirect;global.__TIMEOUT__=json.timeout;global.__PROFILE__=!!json.profile;global.__IS_WATCH__=!!json.watch;global.__LOG_LEVEL__=json.log_level||_constants.DEFAULT_LOG_LEVEL;global.__ALL_CONFIG__=json;if(typeof json.dns!=='undefined'&&json.dns.length>0){global.__DNS__=json.dns;_dns2.default.setServers(json.dns)}}static initServer(server){this.validateServer(server);global.__TRANSPORT__=server.transport;global.__SERVER_HOST__=server.host;global.__SERVER_PORT__=server.port;global.__KEY__=server.key;global.__PRESETS__=server.presets}}exports.Config=Config;

@ -85,6 +85,23 @@ describe('Config#init', function () {
}).not.toThrow();
});
it('should throw when dns is provided but invalid', function () {
const conf = {
transport: 'tcp',
host: 'localhost',
port: 1080,
key: 'abc',
presets: [{name: 'ss-base', params: {}}],
timeout: 600
};
expect(() => Config.init({...conf, dns: null})).toThrow();
expect(() => Config.init({...conf, dns: ['']})).toThrow();
expect(() => Config.init({...conf, dns: ['localhost']})).toThrow();
expect(() => Config.init({...conf, dns: []})).not.toThrow();
expect(() => Config.init({...conf, dns: ['8.8.8.8']})).not.toThrow();
});
// others
it('should __IS_SERVER__ set to true, if no servers provided', function () {

@ -1,4 +1,6 @@
import dns from 'dns';
import fs from 'fs';
import net from 'net';
import {isValidPort} from 'blinksocks-utils';
import {BLINKSOCKS_DIR, LOG_DIR, DEFAULT_LOG_LEVEL} from './constants';
@ -58,6 +60,17 @@ export class Config {
this.validateServer(json);
}
if (typeof json.dns !== 'undefined') {
if (!Array.isArray(json.dns)) {
throw Error('\'dns\' must be an array');
}
for (const ip of json.dns) {
if (!net.isIP(ip)) {
throw Error(`"${ip}" is not an ip address`);
}
}
}
// redirect
if (typeof json.redirect === 'string' && json.redirect !== '') {
const address = json.redirect.split(':');
@ -165,6 +178,11 @@ export class Config {
global.__IS_WATCH__ = !!json.watch;
global.__LOG_LEVEL__ = json.log_level || DEFAULT_LOG_LEVEL;
global.__ALL_CONFIG__ = json;
if (typeof json.dns !== 'undefined' && json.dns.length > 0) {
global.__DNS__ = json.dns;
dns.setServers(json.dns);
}
}
static initServer(server) {