UNPKG

dnschain

Version:

A blockchain-based DNS + HTTPS server that fixes HTTPS security, and more!

210 lines (183 loc) 9.56 kB
### dnschain http://dnschain.net Copyright (c) 2014 okTurtles Foundation This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. ### module.exports = (dnschain) -> # 1. global dependencies # # IMPORTANT: *ALL* DNSChain globals *MUST* be prefixed with a 'g' # *EXCEPT* some of the commonly used global module dependencies below. dnschain.globals = rpc : 'json-rpc2' _ : 'lodash' S : 'string' dns2 : 'native-dns' gES : 'event-stream' Bottleneck : 'bottleneck' Promise : 'bluebird' # Initialize the global rate limiter pool, only an interface will be visible from the outside limiters = {} # Garbage collect the unused limiters every minute. #This is necessary or else the server will run out of RAM after a few days setInterval -> time = Date.now() for key,limiter of limiters # Unused in the last 5 minutes if (limiter._nextRequest+(60*1000*5)) < time delete limiters[key] , 60*1000 # Every minute # no renaming done for these for d in ['dns', 'fs', 'http','net', 'os', 'path', 'tls', 'url', 'util', 'winston'] dnschain.globals[d] = d # replace all the string values in dnschain.globals with the module they represent # and expose them into this function's namespace for k,v of dnschain.globals eval "var #{k} = dnschain.globals.#{k} = require('#{v}');" # 2. global constants _.assign dnschain.globals, gConsts: # for questions that the blockchain cannot answer (hopefully these will disappear with time) # >> Use the keys (as string values) in your config! << # >> Do *NOT* use the numerical values in your config! << # For now they're supported but their use is DEPRECATED and they *WILL* be removed! oldDNS: # Recommended method NATIVE_DNS: 0 # Use 'native-dns' module (current default). Hopefully merged into NodeJS in the future: https://github.com/joyent/node/issues/6864#issuecomment-32229852 # !! WARNING !! # > ! USING 'NODE_DNS' IS __STRONGLY DISCOURAGED__ ! < # > ! BECAUSE IT DOES NOT PROVIDE PROVIDE TTL VALUES ! < # > ! ITS USE MAY BE DEPRECATED IN THE FUTURE ! < NODE_DNS: 1 # Prior to node 0.11.x will ignore dnsOpts.oldDNS and use OS-specified DNS. Currently ignores 'dnsOpts.oldDNS' in favor of OS-specified DNS even in node 0.11.x (simply needs to be implemented). TODO: <- this! # Refuse to resolve domains in the canonical DNS system # unless the blockchain tells us to, in which case the # NATIVE_DNS method will be used for that purpose. NO_OLD_DNS: 2 # Never resolve domains in canonical DNS. Return REFUSED for all such requests. NO_OLD_DNS_EVER: 3 # 3. create global functions, and then return the entire globals object _.assign dnschain.globals, { gExternalIP: do -> cachedIP = null faces = os.networkInterfaces() default_iface = switch when os.type() is 'Darwin' and faces.en0? then 'en0' when os.type() is 'Linux' and faces.eth0? then 'eth0' else _(faces).keys().find (x)-> !x.match /lo/ (iface=default_iface, cached=true,fam='IPv4',internal=false) -> cachedIP = switch when cached and cachedIP then cachedIP else unless ips = (faces = os.networkInterfaces())[iface] throw new Error util.format("No such interface '%s'. Available: %j", iface, faces) if (address = _.find(ips, {family:fam, internal:internal})?.address) address else console.warn "Couldn't find 'address' in:".bold.red, ips console.warn "Couldn't figure out external IPv4 IP! Make SURE to manually set it in your configuration!".bold.red "NOT AN IP! SEE: https://github.com/okTurtles/dnschain/issues/111#issuecomment-71958236" gNewLogger: (name) -> new winston.Logger levels: winston.config.cli.levels colors: winston.config.cli.lcolors transports: [ new winston.transports.Console label:name level: gConf.get 'log:level' colorize: gConf.get 'log:colors' prettyPrint: gConf.get 'log:pretty' timestamp: gConf.get 'log:timestamp' ] gErr: (args...) -> e = new Error util.format args... gLogger.error e.stack throw e gFillWithRunningChecks: (server) -> gLineInfo = dnschain.globals.gLineInfo server.startCheck = (cb) -> if @running @log.warn gLineInfo "Already running!" Promise.reject() else @log.debug "Starting up..." new Promise (resolve, reject) => cb (err, args...) => if err @log.error gLineInfo("failed to start"), err reject err else @log.info "Server started.", args @running = true resolve args server.shutdownCheck = (cb) -> if @running @log.debug "Shutting down..." new Promise (resolve, reject) => cb (err, args...) => if err @log.error gLineInfo("failed to shutdown"), err reject err else @log.info "Server shutdown successfully.", args @running = false resolve args else @log.warn gLineInfo "Shutdown called when not running!" Promise.reject() server # as a convenience, return the server instance gThrottle: (key, makeLimiter) -> limiters[key] ? (limiters[key] = makeLimiter()) # TODO: this function should take one parameter: an IP string # and return either 'A' or 'AAAA' # A separate function called type2rec should do what the inner fn does # https://github.com/okTurtles/dnschain/issues/7 gIP2type: (d, ttl, type='A') -> (ip)-> dns2[type] {name:d, address:ip, ttl:ttl} # Currently this function is namecoin-specific. # DANE/TLSA info: https://tools.ietf.org/html/rfc6698 # TODO: implement RRSIG from http://tools.ietf.org/html/rfc4034 # as in: dig @8.8.4.4 +dnssec TLSA _443._tcp.good.dane.verisignlabs.com gTls2tlsa: (tls, ttl, queryname) -> [port, protocol] = (queryname.split '.')[0..1].map (o)-> o.replace '_','' if !tls?[protocol]?[port]? return [] tls[protocol][port].map (certinfo) -> dns2.TLSA name: queryname ttl: ttl usage: 3 # 3 = "Fuck CAs" :P selector: 1 # SubjectPublicKeyInfo: DER-encoded [RFC5280] matchingtype: certinfo[0] buff: new Buffer certinfo[1], 'hex' gLineInfo: (prefix='') -> stack = new Error().stack # console.log stack.split('\n')[2] [file, line] = stack.split('\n')[2].split ':' [func, file] = file.split ' (' [func, file] = ['??', func] unless file # sometimes the function isn't specified [func, file] = [func.split(' ').pop(), path.basename(file)] [junk, func] = func.split('.') func = junk unless func func = if func is '??' or func is '<anonymous>' then ' (' else " (<#{func}> " prefix + func + file + ':' + line + ')' } # 4. vars for use within the map above and elsewhere gConf = dnschain.globals.gConf = require('./config')(dnschain) gLogger = dnschain.globals.gLogger = dnschain.globals.gNewLogger 'Global' gConsts = dnschain.globals.gConsts # handle DEPRECATED numerical oldDNSMethod values method = gConf.get 'dns:oldDNSMethod' if typeof method isnt 'string' method = _.keys(_.pick gConsts.oldDNS, (v,k)-> v is method)[0] gLogger.warn "Specifying 'oldDNSMethod' as a number is DEPRECATED!".bold.red gLogger.warn "Please specify the string value instead:".bold.red, "#{method}".bold else if _.isNumber (method_num = gConsts.oldDNS[method]) # kinda hackish... but makes for easy and quick comparisons gConf.set 'dns:oldDNSMethod', method_num else gLogger.error "No such oldDNS method:".bold.red, method.bold process.exit 1 # 5. return the globals object dnschain.globals