├── .gitignore ├── .jshintrc ├── CONTRIBUTORS.txt ├── Gruntfile.js ├── LICENSE ├── README.md ├── bin └── docker-dns.js ├── config ├── .gitignore ├── config.js.example └── etc-services ├── docker ├── .dockerignore ├── Dockerfile ├── build_docker.sh ├── config │ ├── .gitignore │ ├── config.js.example │ └── supervisord.conf ├── log │ └── .gitignore └── run_docker.sh ├── lib ├── container-inspect.js ├── dns-service.js ├── docker-inspect.js ├── etc-services-lookup.js └── logger.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | node_modules 16 | *.project 17 | .project 18 | .settings/* 19 | .settings 20 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node":true, 3 | "evil":false, 4 | "indent":4, 5 | "passfail":false, 6 | "plusplus":false, 7 | "white":false, 8 | "smarttabs":true 9 | } -------------------------------------------------------------------------------- /CONTRIBUTORS.txt: -------------------------------------------------------------------------------- 1 | Benjamin Foote http://bnf.net 2 | Olivier Toupin https://github.com/oliviertoupin 3 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | 3 | // Project configuration. 4 | grunt.initConfig({ 5 | pkg: grunt.file.readJSON('package.json'), 6 | jshint: { 7 | jshintrc: '.jshintrc', 8 | all: ['Gruntfile.js', '*.js', 'lib/*.js', 'bin/*'] 9 | }, 10 | nodemon: { 11 | dev: { 12 | script: './bin/docker-dns', 13 | options: { 14 | args: ['-d'], 15 | nodeArgs: ['--debug'] 16 | } 17 | } 18 | } 19 | }); 20 | 21 | 22 | grunt.loadNpmTasks('grunt-nodemon'); 23 | grunt.loadNpmTasks('grunt-contrib-jshint'); 24 | // Default task(s). 25 | grunt.registerTask('default', ['nodemon']); 26 | 27 | }; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Benjamin Foote 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # docker-dns 2 | http://github.com/bnfinet/docker-dns 3 | 4 | https://registry.hub.docker.com/u/bfoote/docker-dns 5 | 6 | nodejs app to offer dns services based on a running docker enironment 7 | 8 | Benjamin Foote 9 | http://bnf.net 10 | ben@bnf.net 11 | 12 | inspired by [skydock](https://github.com/crosbymichael/skydock) and [skydns](https://github.com/skynetservices/skydns) 13 | 14 | [![NPM version](https://badge.fury.io/js/docker-dns.png)](http://badge.fury.io/js/docker-dns) 15 | [![Dependency Status](https://david-dm.org/bnfinet/docker-dns.png)](https://david-dm.org/bnfinet/docker-dns) 16 | 17 | ## docker-dns creates dns records from running containters on the fly 18 | 19 | ```docker-dns``` uses the docker api to create ```A```, ```CNAME```, and ```SRV``` records. This makes it easy to find and use containers from other containers, from the docker host, or even from the internet. It solves the issue of having to restart containers in the proper order to properly align ```--name``` and ```--link``` directives. Just start your container and be confident that it can be found using dns. 20 | 21 | you@server:~$ ping hipache.dockerA.tld 22 | PING ff14ccc7acf2.local.dockerA.tld (172.17.0.7) 56(84) bytes of data. 23 | 64 bytes from 172.17.0.7: icmp_req=1 ttl=64 time=0.046 ms 24 | 64 bytes from 172.17.0.7: icmp_req=2 ttl=64 time=0.041 ms 25 | 26 | ## setup - configure your docker daemon 27 | 28 | The docker daemon should be run with an additional ```-dns``` flag pointing at the ip address where docker-dns will run (usally the ```docker0``` bridge). This will populate each running container's ```/etc/resolv.conf```. 29 | 30 | This shows the docker daemon with -dns with dns service running behind docker0: 31 | 32 | docker -d --bip=172.17.42.1/16 --dns=172.17.42.1 33 | 34 | ## installation 35 | 36 | npm install -g docker-dns 37 | docker-dns --config config.js 38 | 39 | or git clone.. 40 | 41 | git clone http://github.com/bnfinet/docker-dns 42 | cd docker-dns 43 | cp ./config/config.js.example ./config/config.js 44 | (edit some stuff) 45 | ./bin/docker-dns.js 46 | 47 | or just run a docker instance 48 | 49 | docker pull bfoote/docker-dns 50 | cd docker 51 | cp ../config/config.js.example ./config/config.js 52 | (edit some stuff) 53 | ./run_docker.sh hostname ./config/config.js; 54 | 55 | ## the SRV use case 56 | 57 | You have a Docker.io environment setup. You spin up new instances 58 | which includes mapping specific services to multiple ports. 59 | 60 | you@dockerbox:~$ sudo docker ps -a 61 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 62 | a03ac7d516c0 hipache:latest supervisord -n 10 hours ago Up 10 hours 0.0.0.0:49192->6379/tcp, 144.76.62.2:80->80/tcp hipache 63 | f4b2dd963131 62f5bca4ec7c /usr/sbin/sshd -D 14 hours ago Up 14 hours 0.0.0.0:49189->22/tcp, 172.17.42.1:53->53/udp docker-dns 64 | fbc938bbfec1 sshd-nginx-phpfpm:latest /startup.sh 3 days ago Up 3 days 0.0.0.0:49175->22/tcp, 0.0.0.0:49176->80/tcp awesomeapp 65 | a95d1f55ea4b 07e289838094 /startup.sh 3 days ago Up 3 days 0.0.0.0:49167->22/tcp, 0.0.0.0:49168->80/tcp namearg 66 | e5c777e21c60 sshd:latest /bin/sh -c /usr/sbin 3 days ago Exit -1 namearg/sshdhost,sshd 67 | 68 | You'd like to be able to connect to ports on your dockerbox in a useful way, but you don't 69 | want to have to go lookup the port mapping and wire things up. This is called 70 | service discovery and there's a [DNS record](http://en.wikipedia.org/wiki/SRV_record) for that. 71 | 72 | you@server:~$ host -t SRV _ssh._tcp.awesomeapp.dockerA.tld 73 | awesomeapp.docker.tld has SRV record 0 10 49158 fbc938bbfec1.dockerA.tld. 74 | 75 | Where port 49158 is the docker side published port for ssh 76 | 77 | Then you can do things like... 78 | 79 | PORT=$(host -t SRV awesomeapp.docker.tld | awk '{print $7}'); 80 | ssh -p $PORT awesomeapp.dockerA.tld 81 | 82 | Alternatively you can provide just the host to get all srv records for that container 83 | 84 | you@server:~$ host -t SRV awesomeapp.dockerA.tld 85 | awesomeapp.dockerA.tld has SRV record 0 10 49175 fbc938bbfec1.dockerA.tld. 86 | awesomeapp.dockerA.tld has SRV record 0 10 49176 fbc938bbfec1.dockerA.tld. 87 | 88 | That doesn't tell you which services are running but it at least shows you the ports for that container. 89 | 90 | For that you can use wild card searches... 91 | 92 | you@server:~$ host -t SRV _redis.*.dockerA.tld 93 | _redis.*.dockerA.tld has SRV record 0 10 49188 fbc938bbfec1.dockerA.tld. 94 | _redis.*.dockerA.tld has SRV record 0 10 49189 7d6d9f0468b8.dockerA.tld. 95 | 96 | And since you can configure service discovery for multiple Docker environments you can do 97 | 98 | you@server:~$ host -t SRV _redis.*.tld 99 | _redis.*.tld has SRV record 0 10 49188 fbc938bbfec1.dockerA.tld. 100 | _redis.*.tld has SRV record 0 10 49189 7d6d9f0468b8.dockerA.tld. 101 | _redis.*.tld has SRV record 0 10 49199 4087bee527c5.dockerB.tld. 102 | _redis.*.tld has SRV record 0 10 49201 95c7e60213ac.dockerB.tld. 103 | 104 | In addition there are two namespace, 'public' and 'local'. The public side always points at 105 | the assigned port from Docker. The local side points at the port atthached to the conatiner's ip 106 | 107 | you@server:~$ host -t SRV _ssh.*.tld 108 | _ssh.*.tld has SRV record 0 10 49188 fbc938bbfec1.dockerA.tld. 109 | _ssh.*.tld has SRV record 0 10 49189 7d6d9f0468b8.dockerA.tld. 110 | _ssh.*.tld has SRV record 0 10 22 fbc938bbfec1.local.dockerA.tld. 111 | _ssh.*.tld has SRV record 0 10 22 7d6d9f0468b8.local.dockerA.tld. 112 | 113 | Namespace mappings for tld, public and local are set in the conf file. 114 | 115 | 116 | ## how we do that 117 | 118 | for each configured docker environment... 119 | docker-dns scans the docker api periodically and builds DNS records 120 | for each container... 121 | - UUID is an A record 122 | - container ID (first 12 of the UUID) is an A record 123 | - a cleaned version of the image name is CNAME to the A record 124 | - hostname (run -h) is CNAME to the A record 125 | 126 | and for all exposed ports on each container several SRV records are created by looking up the container side 'port/protocol' (such as '22/tcp') in the style of /etc/services: 127 | 128 | ```` 129 | _service._protocol.hostname.dockerA.tld 130 | _service._protocol.containerID.dockerA.tld 131 | _service._protocol.imagename.dockerA.tld 132 | ```` 133 | 134 | ## features 135 | 136 | - supports a custom fake top level domain such as 'local' or 'docker.tld' 137 | - supports multiple docker instances each with their own namespace (see the config) 138 | - supports separate 'local' namespace for routing of 172.17.0.0 addresses 139 | - maps '0.0.0.0' to a configured (possibly public) ip address 140 | 141 | ## config 142 | 143 | Copy the config file and edit. See documentation in the comments there. 144 | 145 | cp ./config/config.js.example ./config/config.js 146 | 147 | 148 | ## issues and bugs 149 | 150 | on github please.... 151 | https://github.com/bnfinet/docker-dns/issues 152 | 153 | ## next steps 154 | - ipv6 AAAA records 155 | - use Docker's event stream instead of polling 156 | - use a temporary name space for record creation 157 | -------------------------------------------------------------------------------- /bin/docker-dns.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | var pkg = require('../package.json'); 6 | var parseArgs = require('minimist'); 7 | var fs = require('fs'); 8 | var path = require('path'); 9 | var util = require('util'); 10 | var async = require('async'); 11 | var Docker = require('dockerode'); 12 | 13 | var Dinspect = require(__dirname + '/../lib/docker-inspect.js'); 14 | var dnsserver = require(__dirname + '/../lib/dns-service.js'); 15 | 16 | // application level object 17 | var ddns = { 18 | argv: parseArgs(process.argv), 19 | configFile: '', 20 | config: null, 21 | dockers: [] 22 | }; 23 | 24 | ddns.log = require(__dirname + '/../lib/logger.js'); 25 | ddns.log.prepend = 'DD'; 26 | 27 | var configureApp = function() { 28 | 29 | if (ddns.argv.h || ddns.argv.help) { 30 | util.puts(help); 31 | process.exit(); 32 | } 33 | 34 | if (ddns.argv.v || ddns.argv.version) { 35 | util.puts('docker-dns version ' + pkg.version); 36 | process.exit(); 37 | } 38 | 39 | ddns.configFile = ddns.argv.c || ddns.argv.config; 40 | 41 | // if a config file was set, and it's relative to CWD, set absolute path 42 | if (ddns.configFile && fs.existsSync(ddns.configFile)) { 43 | ddns.configFile = path.resolve(ddns.configFile); 44 | } 45 | 46 | if (!ddns.configFile) { 47 | // look for ./config/config.js 48 | ddns.configFile = path.resolve(__dirname, '..', 'config', 'config.js'); 49 | if (process.env.DOCKER_DNS_CONFIG !== undefined) { 50 | ddns.configFile = ddns.configFile.replace(/\.js$/, '_' + process.env.DOCKER_DNS_CONFIG + '.js'); 51 | } 52 | } 53 | 54 | if (!ddns.configFile) { 55 | util.puts(help); 56 | process.exit(); 57 | } 58 | 59 | if (ddns.configFile && !fs.existsSync(ddns.configFile)) { 60 | util.puts("can't find " + ddns.configFile); 61 | util.puts(help); 62 | process.exit(); 63 | } 64 | 65 | ddns.log.info('Loading config from ' + ddns.configFile); 66 | ddns.config = require(ddns.configFile); 67 | 68 | if (ddns.argv.d || ddns.argv.debug) { 69 | ddns.config.debug = true; 70 | } 71 | 72 | if (ddns.config.debug) { 73 | ddns.log.level = 'debug'; 74 | ddns.log.info('debuging enabled'); 75 | } 76 | 77 | ddns.config.logger = ddns.log; 78 | }; 79 | 80 | 81 | var main = function() { 82 | configureApp(); 83 | initializeDockers(function(errI) { 84 | if (errI) { 85 | ddns.log.error("initializaion failed, exiting"); 86 | process.exit(1); 87 | } 88 | pollDockers(function(errP) { 89 | if (errP) { 90 | ddns.log.error('polling failed'); 91 | } else { 92 | ddns.log.info('docker-dns initialized'); 93 | dnsserver.startservice(ddns.config); 94 | setInterval(pollDockers, ddns.config.pollinterval); 95 | // pollForEvents(); 96 | // setInterval(pollForEvents, pollInterval); 97 | // setInterval(refreshRecs, config.pollinterval); 98 | } 99 | }); 100 | }); 101 | }; 102 | 103 | 104 | var initializeDockers = function (cb) { 105 | async.each(ddns.config.dockers, function(dconfig, done) { 106 | dconfig.debug = ddns.config.debug; 107 | dconfig.faketld = ddns.config.faketld; 108 | dconfig.logger = ddns.config.logger; 109 | var newD = new Dinspect(dconfig); 110 | if (newD) { 111 | ddns.dockers.push(newD); 112 | done(); 113 | } else { 114 | ddns.log.error("initialization of docker "+ dconfig.publicname + " failed"); 115 | done(); 116 | }; 117 | }, cb); 118 | }; 119 | 120 | var pollDockers = function(cb) { 121 | async.each(ddns.dockers, function(docker, done) { 122 | docker.inspectContainers(function(err) { 123 | if (err) { 124 | ddns.log.error("docker inspect err: " + err); 125 | done(err); 126 | } else { 127 | ddns.log.debug("back from inspection, off to build"); 128 | docker.buildRecords(function(err, recs) { 129 | ddns.log.debug("back from build, deliver recs to dns server"); 130 | // console.log(recs); 131 | dnsserver.newrecords(recs, done); 132 | }); 133 | }; 134 | }); 135 | }, function(err) { 136 | if (typeof cb === 'function') { 137 | cb(err); 138 | } 139 | }); 140 | }; 141 | 142 | /* 143 | * not implemented 144 | * 145 | * var pollInterval = config.pollinterval; var last = Date.now() - pollInterval; 146 | * var pollForEvents = function() { var time = Date.now(); docker.D.getEvents({ 147 | * since : last }, function(err, data) { if (config.debug) { 148 | * ddns.log("---EVENT---", last, data); } if (err) { ddns.log("event error: ", 149 | * err); } else { } last = time - pollInterval; }); }; 150 | */ 151 | 152 | main(); 153 | 154 | process.on('SIGINT', function() { 155 | ddns.log.info("\nGracefully shutting down from SIGINT (Ctrl-C)"); 156 | ddns.log.info('exiting'); 157 | process.exit(); 158 | }); 159 | 160 | 161 | var help = [ 162 | 'usage: docker-dns [options]', 163 | '', 164 | 'Starts a docker-dns server', 165 | '', 166 | 'options:', 167 | ' -c, --config location of the configuration file', 168 | ' -d, --debug turn on debuging', 169 | ' -h, --help display this message', 170 | ' -v, --version version information', 171 | '', 172 | 'more info:', 173 | 'https://github.com/bnfinet/docker-dns', 174 | '', 175 | ].join('\n'); 176 | 177 | 178 | -------------------------------------------------------------------------------- /config/.gitignore: -------------------------------------------------------------------------------- 1 | /config.js 2 | -------------------------------------------------------------------------------- /config/config.js.example: -------------------------------------------------------------------------------- 1 | var config = {}; 2 | 3 | config.development = true; 4 | config.debug = false; 5 | 6 | // a fake top level domain 7 | // appended to all generated hostnames 8 | config.faketld = "docker.local"; 9 | 10 | // frequency of dns entry refresh from docker containers 11 | config.pollinterval = 17 * 1000; 12 | 13 | // multiple dockers can be configured 14 | // each one should gets it's own namespace 15 | // hostname.publicname.faketld 16 | config.dockers = [ 17 | { 18 | // for 'publicly' exposed ports 19 | // when a service is offered on '0.0.0.0' 20 | // this is the IP lookups will return 21 | publicip: "10.20.0.100", 22 | 23 | // the public name is to give this docker instance it's own namespace 24 | publicname: "public.dockerA", 25 | 26 | // the local name is to provide a namespace for routing 172.17.0.0 addresses 27 | localname: "local.dockerA", 28 | 29 | // dockerode config 30 | // see: https://github.com/apocas/dockerode 31 | // and http://docs.docker.io/en/latest/use/basics/#bind-docker 32 | dockerode: { 33 | socketPath: '/var/run/docker.sock' 34 | } 35 | } 36 | ]; 37 | 38 | // node-named config 39 | // see: https://github.com/trevoro/node-named 40 | // bindip is for this container only, not docker-wide 41 | config.node_named = { 42 | port: 53, 43 | bindip: '0.0.0.0' 44 | }; 45 | 46 | module.exports = config; -------------------------------------------------------------------------------- /config/etc-services: -------------------------------------------------------------------------------- 1 | # Network services, Internet style 2 | # 3 | # Note that it is presently the policy of IANA to assign a single well-known 4 | # port number for both TCP and UDP; hence, officially ports have two entries 5 | # even if the protocol doesn't support UDP operations. 6 | # 7 | # Updated from http://www.iana.org/assignments/port-numbers and other 8 | # sources like http://www.freebsd.org/cgi/cvsweb.cgi/src/etc/services . 9 | # New ports will be added on request if they have been officially assigned 10 | # by IANA and used in the real-world or are needed by a debian package. 11 | # If you need a huge list of used numbers please install the nmap package. 12 | 13 | tcpmux 1/tcp # TCP port service multiplexer 14 | echo 7/tcp 15 | echo 7/udp 16 | discard 9/tcp sink null 17 | discard 9/udp sink null 18 | systat 11/tcp users 19 | daytime 13/tcp 20 | daytime 13/udp 21 | netstat 15/tcp 22 | qotd 17/tcp quote 23 | msp 18/tcp # message send protocol 24 | msp 18/udp 25 | chargen 19/tcp ttytst source 26 | chargen 19/udp ttytst source 27 | ftp-data 20/tcp 28 | ftp 21/tcp 29 | fsp 21/udp fspd 30 | ssh 22/tcp # SSH Remote Login Protocol 31 | ssh 22/udp 32 | telnet 23/tcp 33 | smtp 25/tcp mail 34 | time 37/tcp timserver 35 | time 37/udp timserver 36 | rlp 39/udp resource # resource location 37 | nameserver 42/tcp name # IEN 116 38 | whois 43/tcp nicname 39 | tacacs 49/tcp # Login Host Protocol (TACACS) 40 | tacacs 49/udp 41 | re-mail-ck 50/tcp # Remote Mail Checking Protocol 42 | re-mail-ck 50/udp 43 | domain 53/tcp # Domain Name Server 44 | domain 53/udp 45 | mtp 57/tcp # deprecated 46 | tacacs-ds 65/tcp # TACACS-Database Service 47 | tacacs-ds 65/udp 48 | bootps 67/tcp # BOOTP server 49 | bootps 67/udp 50 | bootpc 68/tcp # BOOTP client 51 | bootpc 68/udp 52 | tftp 69/udp 53 | gopher 70/tcp # Internet Gopher 54 | gopher 70/udp 55 | rje 77/tcp netrjs 56 | finger 79/tcp 57 | http 80/tcp www # WorldWideWeb HTTP 58 | http 80/udp # HyperText Transfer Protocol 59 | link 87/tcp ttylink 60 | kerberos 88/tcp kerberos5 krb5 kerberos-sec # Kerberos v5 61 | kerberos 88/udp kerberos5 krb5 kerberos-sec # Kerberos v5 62 | supdup 95/tcp 63 | hostnames 101/tcp hostname # usually from sri-nic 64 | iso-tsap 102/tcp tsap # part of ISODE 65 | acr-nema 104/tcp dicom # Digital Imag. & Comm. 300 66 | acr-nema 104/udp dicom 67 | csnet-ns 105/tcp cso-ns # also used by CSO name server 68 | csnet-ns 105/udp cso-ns 69 | rtelnet 107/tcp # Remote Telnet 70 | rtelnet 107/udp 71 | pop2 109/tcp postoffice pop-2 # POP version 2 72 | pop2 109/udp pop-2 73 | pop3 110/tcp pop-3 # POP version 3 74 | pop3 110/udp pop-3 75 | sunrpc 111/tcp portmapper # RPC 4.0 portmapper 76 | sunrpc 111/udp portmapper 77 | auth 113/tcp authentication tap ident 78 | sftp 115/tcp 79 | uucp-path 117/tcp 80 | nntp 119/tcp readnews untp # USENET News Transfer Protocol 81 | ntp 123/tcp 82 | ntp 123/udp # Network Time Protocol 83 | pwdgen 129/tcp # PWDGEN service 84 | pwdgen 129/udp 85 | loc-srv 135/tcp epmap # Location Service 86 | loc-srv 135/udp epmap 87 | netbios-ns 137/tcp # NETBIOS Name Service 88 | netbios-ns 137/udp 89 | netbios-dgm 138/tcp # NETBIOS Datagram Service 90 | netbios-dgm 138/udp 91 | netbios-ssn 139/tcp # NETBIOS session service 92 | netbios-ssn 139/udp 93 | imap2 143/tcp imap # Interim Mail Access P 2 and 4 94 | imap2 143/udp imap 95 | snmp 161/tcp # Simple Net Mgmt Protocol 96 | snmp 161/udp 97 | snmp-trap 162/tcp snmptrap # Traps for SNMP 98 | snmp-trap 162/udp snmptrap 99 | cmip-man 163/tcp # ISO mgmt over IP (CMOT) 100 | cmip-man 163/udp 101 | cmip-agent 164/tcp 102 | cmip-agent 164/udp 103 | mailq 174/tcp # Mailer transport queue for Zmailer 104 | mailq 174/udp 105 | xdmcp 177/tcp # X Display Mgr. Control Proto 106 | xdmcp 177/udp 107 | nextstep 178/tcp NeXTStep NextStep # NeXTStep window 108 | nextstep 178/udp NeXTStep NextStep # server 109 | bgp 179/tcp # Border Gateway Protocol 110 | bgp 179/udp 111 | prospero 191/tcp # Cliff Neuman's Prospero 112 | prospero 191/udp 113 | irc 194/tcp # Internet Relay Chat 114 | irc 194/udp 115 | smux 199/tcp # SNMP Unix Multiplexer 116 | smux 199/udp 117 | at-rtmp 201/tcp # AppleTalk routing 118 | at-rtmp 201/udp 119 | at-nbp 202/tcp # AppleTalk name binding 120 | at-nbp 202/udp 121 | at-echo 204/tcp # AppleTalk echo 122 | at-echo 204/udp 123 | at-zis 206/tcp # AppleTalk zone information 124 | at-zis 206/udp 125 | qmtp 209/tcp # Quick Mail Transfer Protocol 126 | qmtp 209/udp 127 | z3950 210/tcp wais # NISO Z39.50 database 128 | z3950 210/udp wais 129 | ipx 213/tcp # IPX 130 | ipx 213/udp 131 | imap3 220/tcp # Interactive Mail Access 132 | imap3 220/udp # Protocol v3 133 | pawserv 345/tcp # Perf Analysis Workbench 134 | pawserv 345/udp 135 | zserv 346/tcp # Zebra server 136 | zserv 346/udp 137 | fatserv 347/tcp # Fatmen Server 138 | fatserv 347/udp 139 | rpc2portmap 369/tcp 140 | rpc2portmap 369/udp # Coda portmapper 141 | codaauth2 370/tcp 142 | codaauth2 370/udp # Coda authentication server 143 | clearcase 371/tcp Clearcase 144 | clearcase 371/udp Clearcase 145 | ulistserv 372/tcp # UNIX Listserv 146 | ulistserv 372/udp 147 | ldap 389/tcp # Lightweight Directory Access Protocol 148 | ldap 389/udp 149 | imsp 406/tcp # Interactive Mail Support Protocol 150 | imsp 406/udp 151 | svrloc 427/tcp # Server Location 152 | svrloc 427/udp 153 | https 443/tcp # http protocol over TLS/SSL 154 | https 443/udp 155 | snpp 444/tcp # Simple Network Paging Protocol 156 | snpp 444/udp 157 | microsoft-ds 445/tcp # Microsoft Naked CIFS 158 | microsoft-ds 445/udp 159 | kpasswd 464/tcp 160 | kpasswd 464/udp 161 | saft 487/tcp # Simple Asynchronous File Transfer 162 | saft 487/udp 163 | isakmp 500/tcp # IPsec - Internet Security Association 164 | isakmp 500/udp # and Key Management Protocol 165 | rtsp 554/tcp # Real Time Stream Control Protocol 166 | rtsp 554/udp 167 | nqs 607/tcp # Network Queuing system 168 | nqs 607/udp 169 | npmp-local 610/tcp dqs313_qmaster # npmp-local / DQS 170 | npmp-local 610/udp dqs313_qmaster 171 | npmp-gui 611/tcp dqs313_execd # npmp-gui / DQS 172 | npmp-gui 611/udp dqs313_execd 173 | hmmp-ind 612/tcp dqs313_intercell # HMMP Indication / DQS 174 | hmmp-ind 612/udp dqs313_intercell 175 | qmqp 628/tcp 176 | qmqp 628/udp 177 | ipp 631/tcp # Internet Printing Protocol 178 | ipp 631/udp 179 | # 180 | # UNIX specific services 181 | # 182 | exec 512/tcp 183 | biff 512/udp comsat 184 | login 513/tcp 185 | who 513/udp whod 186 | shell 514/tcp cmd # no passwords used 187 | syslog 514/udp 188 | printer 515/tcp spooler # line printer spooler 189 | talk 517/udp 190 | ntalk 518/udp 191 | route 520/udp router routed # RIP 192 | timed 525/udp timeserver 193 | tempo 526/tcp newdate 194 | courier 530/tcp rpc 195 | conference 531/tcp chat 196 | netnews 532/tcp readnews 197 | netwall 533/udp # for emergency broadcasts 198 | gdomap 538/tcp # GNUstep distributed objects 199 | gdomap 538/udp 200 | uucp 540/tcp uucpd # uucp daemon 201 | klogin 543/tcp # Kerberized `rlogin' (v5) 202 | kshell 544/tcp krcmd # Kerberized `rsh' (v5) 203 | dhcpv6-client 546/tcp 204 | dhcpv6-client 546/udp 205 | dhcpv6-server 547/tcp 206 | dhcpv6-server 547/udp 207 | afpovertcp 548/tcp # AFP over TCP 208 | afpovertcp 548/udp 209 | idfp 549/tcp 210 | idfp 549/udp 211 | remotefs 556/tcp rfs_server rfs # Brunhoff remote filesystem 212 | nntps 563/tcp snntp # NNTP over SSL 213 | nntps 563/udp snntp 214 | submission 587/tcp # Submission [RFC4409] 215 | submission 587/udp 216 | ldaps 636/tcp # LDAP over SSL 217 | ldaps 636/udp 218 | tinc 655/tcp # tinc control port 219 | tinc 655/udp 220 | silc 706/tcp 221 | silc 706/udp 222 | kerberos-adm 749/tcp # Kerberos `kadmin' (v5) 223 | # 224 | webster 765/tcp # Network dictionary 225 | webster 765/udp 226 | rsync 873/tcp 227 | rsync 873/udp 228 | ftps-data 989/tcp # FTP over SSL (data) 229 | ftps 990/tcp 230 | telnets 992/tcp # Telnet over SSL 231 | telnets 992/udp 232 | imaps 993/tcp # IMAP over SSL 233 | imaps 993/udp 234 | ircs 994/tcp # IRC over SSL 235 | ircs 994/udp 236 | pop3s 995/tcp # POP-3 over SSL 237 | pop3s 995/udp 238 | # 239 | # From ``Assigned Numbers'': 240 | # 241 | #> The Registered Ports are not controlled by the IANA and on most systems 242 | #> can be used by ordinary user processes or programs executed by ordinary 243 | #> users. 244 | # 245 | #> Ports are used in the TCP [45,106] to name the ends of logical 246 | #> connections which carry long term conversations. For the purpose of 247 | #> providing services to unknown callers, a service contact port is 248 | #> defined. This list specifies the port used by the server process as its 249 | #> contact port. While the IANA can not control uses of these ports it 250 | #> does register or list uses of these ports as a convienence to the 251 | #> community. 252 | # 253 | socks 1080/tcp # socks proxy server 254 | socks 1080/udp 255 | proofd 1093/tcp 256 | proofd 1093/udp 257 | rootd 1094/tcp 258 | rootd 1094/udp 259 | openvpn 1194/tcp 260 | openvpn 1194/udp 261 | rmiregistry 1099/tcp # Java RMI Registry 262 | rmiregistry 1099/udp 263 | kazaa 1214/tcp 264 | kazaa 1214/udp 265 | nessus 1241/tcp # Nessus vulnerability 266 | nessus 1241/udp # assessment scanner 267 | lotusnote 1352/tcp lotusnotes # Lotus Note 268 | lotusnote 1352/udp lotusnotes 269 | ms-sql-s 1433/tcp # Microsoft SQL Server 270 | ms-sql-s 1433/udp 271 | ms-sql-m 1434/tcp # Microsoft SQL Monitor 272 | ms-sql-m 1434/udp 273 | ingreslock 1524/tcp 274 | ingreslock 1524/udp 275 | prospero-np 1525/tcp # Prospero non-privileged 276 | prospero-np 1525/udp 277 | datametrics 1645/tcp old-radius 278 | datametrics 1645/udp old-radius 279 | sa-msg-port 1646/tcp old-radacct 280 | sa-msg-port 1646/udp old-radacct 281 | kermit 1649/tcp 282 | kermit 1649/udp 283 | groupwise 1677/tcp 284 | groupwise 1677/udp 285 | l2f 1701/tcp l2tp 286 | l2f 1701/udp l2tp 287 | radius 1812/tcp 288 | radius 1812/udp 289 | radius-acct 1813/tcp radacct # Radius Accounting 290 | radius-acct 1813/udp radacct 291 | msnp 1863/tcp # MSN Messenger 292 | msnp 1863/udp 293 | unix-status 1957/tcp # remstats unix-status server 294 | log-server 1958/tcp # remstats log server 295 | remoteping 1959/tcp # remstats remoteping server 296 | cisco-sccp 2000/tcp # Cisco SCCP 297 | cisco-sccp 2000/udp 298 | search 2010/tcp ndtp 299 | pipe-server 2010/tcp pipe_server 300 | nfs 2049/tcp # Network File System 301 | nfs 2049/udp # Network File System 302 | gnunet 2086/tcp 303 | gnunet 2086/udp 304 | rtcm-sc104 2101/tcp # RTCM SC-104 IANA 1/29/99 305 | rtcm-sc104 2101/udp 306 | gsigatekeeper 2119/tcp 307 | gsigatekeeper 2119/udp 308 | gris 2135/tcp # Grid Resource Information Server 309 | gris 2135/udp 310 | cvspserver 2401/tcp # CVS client/server operations 311 | cvspserver 2401/udp 312 | venus 2430/tcp # codacon port 313 | venus 2430/udp # Venus callback/wbc interface 314 | venus-se 2431/tcp # tcp side effects 315 | venus-se 2431/udp # udp sftp side effect 316 | codasrv 2432/tcp # not used 317 | codasrv 2432/udp # server port 318 | codasrv-se 2433/tcp # tcp side effects 319 | codasrv-se 2433/udp # udp sftp side effect 320 | mon 2583/tcp # MON traps 321 | mon 2583/udp 322 | dict 2628/tcp # Dictionary server 323 | dict 2628/udp 324 | f5-globalsite 2792/tcp 325 | f5-globalsite 2792/udp 326 | gsiftp 2811/tcp 327 | gsiftp 2811/udp 328 | gpsd 2947/tcp 329 | gpsd 2947/udp 330 | gds-db 3050/tcp gds_db # InterBase server 331 | gds-db 3050/udp gds_db 332 | icpv2 3130/tcp icp # Internet Cache Protocol 333 | icpv2 3130/udp icp 334 | mysql 3306/tcp 335 | mysql 3306/udp 336 | nut 3493/tcp # Network UPS Tools 337 | nut 3493/udp 338 | distcc 3632/tcp # distributed compiler 339 | distcc 3632/udp 340 | daap 3689/tcp # Digital Audio Access Protocol 341 | daap 3689/udp 342 | svn 3690/tcp subversion # Subversion protocol 343 | svn 3690/udp subversion 344 | suucp 4031/tcp # UUCP over SSL 345 | suucp 4031/udp 346 | sysrqd 4094/tcp # sysrq daemon 347 | sysrqd 4094/udp 348 | sieve 4190/tcp # ManageSieve Protocol 349 | epmd 4369/tcp # Erlang Port Mapper Daemon 350 | epmd 4369/udp 351 | remctl 4373/tcp # Remote Authenticated Command Service 352 | remctl 4373/udp 353 | f5-iquery 4353/tcp # F5 iQuery 354 | f5-iquery 4353/udp 355 | iax 4569/tcp # Inter-Asterisk eXchange 356 | iax 4569/udp 357 | mtn 4691/tcp # monotone Netsync Protocol 358 | mtn 4691/udp 359 | radmin-port 4899/tcp # RAdmin Port 360 | radmin-port 4899/udp 361 | rfe 5002/udp # Radio Free Ethernet 362 | rfe 5002/tcp 363 | mmcc 5050/tcp # multimedia conference control tool (Yahoo IM) 364 | mmcc 5050/udp 365 | sip 5060/tcp # Session Initiation Protocol 366 | sip 5060/udp 367 | sip-tls 5061/tcp 368 | sip-tls 5061/udp 369 | aol 5190/tcp # AIM 370 | aol 5190/udp 371 | xmpp-client 5222/tcp jabber-client # Jabber Client Connection 372 | xmpp-client 5222/udp jabber-client 373 | xmpp-server 5269/tcp jabber-server # Jabber Server Connection 374 | xmpp-server 5269/udp jabber-server 375 | cfengine 5308/tcp 376 | cfengine 5308/udp 377 | mdns 5353/tcp # Multicast DNS 378 | mdns 5353/udp 379 | postgresql 5432/tcp postgres # PostgreSQL Database 380 | postgresql 5432/udp postgres 381 | freeciv 5556/tcp rptp # Freeciv gameplay 382 | freeciv 5556/udp 383 | amqp 5672/tcp 384 | amqp 5672/udp 385 | amqp 5672/sctp 386 | ggz 5688/tcp # GGZ Gaming Zone 387 | ggz 5688/udp 388 | x11 6000/tcp x11-0 # X Window System 389 | x11 6000/udp x11-0 390 | x11-1 6001/tcp 391 | x11-1 6001/udp 392 | x11-2 6002/tcp 393 | x11-2 6002/udp 394 | x11-3 6003/tcp 395 | x11-3 6003/udp 396 | x11-4 6004/tcp 397 | x11-4 6004/udp 398 | x11-5 6005/tcp 399 | x11-5 6005/udp 400 | x11-6 6006/tcp 401 | x11-6 6006/udp 402 | x11-7 6007/tcp 403 | x11-7 6007/udp 404 | gnutella-svc 6346/tcp # gnutella 405 | gnutella-svc 6346/udp 406 | gnutella-rtr 6347/tcp # gnutella 407 | gnutella-rtr 6347/udp 408 | sge-qmaster 6444/tcp sge_qmaster # Grid Engine Qmaster Service 409 | sge-qmaster 6444/udp sge_qmaster 410 | sge-execd 6445/tcp sge_execd # Grid Engine Execution Service 411 | sge-execd 6445/udp sge_execd 412 | mysql-proxy 6446/tcp # MySQL Proxy 413 | mysql-proxy 6446/udp 414 | afs3-fileserver 7000/tcp bbs # file server itself 415 | afs3-fileserver 7000/udp bbs 416 | afs3-callback 7001/tcp # callbacks to cache managers 417 | afs3-callback 7001/udp 418 | afs3-prserver 7002/tcp # users & groups database 419 | afs3-prserver 7002/udp 420 | afs3-vlserver 7003/tcp # volume location database 421 | afs3-vlserver 7003/udp 422 | afs3-kaserver 7004/tcp # AFS/Kerberos authentication 423 | afs3-kaserver 7004/udp 424 | afs3-volser 7005/tcp # volume managment server 425 | afs3-volser 7005/udp 426 | afs3-errors 7006/tcp # error interpretation service 427 | afs3-errors 7006/udp 428 | afs3-bos 7007/tcp # basic overseer process 429 | afs3-bos 7007/udp 430 | afs3-update 7008/tcp # server-to-server updater 431 | afs3-update 7008/udp 432 | afs3-rmtsys 7009/tcp # remote cache manager service 433 | afs3-rmtsys 7009/udp 434 | font-service 7100/tcp xfs # X Font Service 435 | font-service 7100/udp xfs 436 | http-alt 8080/tcp webcache # WWW caching service 437 | http-alt 8080/udp 438 | bacula-dir 9101/tcp # Bacula Director 439 | bacula-dir 9101/udp 440 | bacula-fd 9102/tcp # Bacula File Daemon 441 | bacula-fd 9102/udp 442 | bacula-sd 9103/tcp # Bacula Storage Daemon 443 | bacula-sd 9103/udp 444 | xmms2 9667/tcp # Cross-platform Music Multiplexing System 445 | xmms2 9667/udp 446 | nbd 10809/tcp # Linux Network Block Device 447 | zabbix-agent 10050/tcp # Zabbix Agent 448 | zabbix-agent 10050/udp 449 | zabbix-trapper 10051/tcp # Zabbix Trapper 450 | zabbix-trapper 10051/udp 451 | amanda 10080/tcp # amanda backup services 452 | amanda 10080/udp 453 | hkp 11371/tcp # OpenPGP HTTP Keyserver 454 | hkp 11371/udp 455 | bprd 13720/tcp # VERITAS NetBackup 456 | bprd 13720/udp 457 | bpdbm 13721/tcp # VERITAS NetBackup 458 | bpdbm 13721/udp 459 | bpjava-msvc 13722/tcp # BP Java MSVC Protocol 460 | bpjava-msvc 13722/udp 461 | vnetd 13724/tcp # Veritas Network Utility 462 | vnetd 13724/udp 463 | bpcd 13782/tcp # VERITAS NetBackup 464 | bpcd 13782/udp 465 | vopied 13783/tcp # VERITAS NetBackup 466 | vopied 13783/udp 467 | dcap 22125/tcp # dCache Access Protocol 468 | gsidcap 22128/tcp # GSI dCache Access Protocol 469 | wnn6 22273/tcp # wnn6 470 | wnn6 22273/udp 471 | 472 | # 473 | # Datagram Delivery Protocol services 474 | # 475 | rtmp 1/ddp # Routing Table Maintenance Protocol 476 | nbp 2/ddp # Name Binding Protocol 477 | echo 4/ddp # AppleTalk Echo Protocol 478 | zip 6/ddp # Zone Information Protocol 479 | 480 | #========================================================================= 481 | # The remaining port numbers are not as allocated by IANA. 482 | #========================================================================= 483 | 484 | # Kerberos (Project Athena/MIT) services 485 | # Note that these are for Kerberos v4, and are unofficial. Sites running 486 | # v4 should uncomment these and comment out the v5 entries above. 487 | # 488 | kerberos4 750/udp kerberos-iv kdc # Kerberos (server) 489 | kerberos4 750/tcp kerberos-iv kdc 490 | kerberos-master 751/udp kerberos_master # Kerberos authentication 491 | kerberos-master 751/tcp 492 | passwd-server 752/udp passwd_server # Kerberos passwd server 493 | krb-prop 754/tcp krb_prop krb5_prop hprop # Kerberos slave propagation 494 | krbupdate 760/tcp kreg # Kerberos registration 495 | swat 901/tcp # swat 496 | kpop 1109/tcp # Pop with Kerberos 497 | knetd 2053/tcp # Kerberos de-multiplexor 498 | zephyr-srv 2102/udp # Zephyr server 499 | zephyr-clt 2103/udp # Zephyr serv-hm connection 500 | zephyr-hm 2104/udp # Zephyr hostmanager 501 | eklogin 2105/tcp # Kerberos encrypted rlogin 502 | # Hmmm. Are we using Kv4 or Kv5 now? Worrying. 503 | # The following is probably Kerberos v5 --- ajt@debian.org (11/02/2000) 504 | kx 2111/tcp # X over Kerberos 505 | iprop 2121/tcp # incremental propagation 506 | # 507 | # Unofficial but necessary (for NetBSD) services 508 | # 509 | supfilesrv 871/tcp # SUP server 510 | supfiledbg 1127/tcp # SUP debugging 511 | 512 | # 513 | # Services added for the Debian GNU/Linux distribution 514 | # 515 | linuxconf 98/tcp # LinuxConf 516 | poppassd 106/tcp # Eudora 517 | poppassd 106/udp 518 | ssmtp 465/tcp smtps # SMTP over SSL 519 | moira-db 775/tcp moira_db # Moira database 520 | moira-update 777/tcp moira_update # Moira update protocol 521 | moira-ureg 779/udp moira_ureg # Moira user registration 522 | spamd 783/tcp # spamassassin daemon 523 | omirr 808/tcp omirrd # online mirror 524 | omirr 808/udp omirrd 525 | customs 1001/tcp # pmake customs server 526 | customs 1001/udp 527 | skkserv 1178/tcp # skk jisho server port 528 | predict 1210/udp # predict -- satellite tracking 529 | rmtcfg 1236/tcp # Gracilis Packeten remote config server 530 | wipld 1300/tcp # Wipl network monitor 531 | xtel 1313/tcp # french minitel 532 | xtelw 1314/tcp # french minitel 533 | support 1529/tcp # GNATS 534 | cfinger 2003/tcp # GNU Finger 535 | frox 2121/tcp # frox: caching ftp proxy 536 | ninstall 2150/tcp # ninstall service 537 | ninstall 2150/udp 538 | zebrasrv 2600/tcp # zebra service 539 | zebra 2601/tcp # zebra vty 540 | ripd 2602/tcp # ripd vty (zebra) 541 | ripngd 2603/tcp # ripngd vty (zebra) 542 | ospfd 2604/tcp # ospfd vty (zebra) 543 | bgpd 2605/tcp # bgpd vty (zebra) 544 | ospf6d 2606/tcp # ospf6d vty (zebra) 545 | ospfapi 2607/tcp # OSPF-API 546 | isisd 2608/tcp # ISISd vty (zebra) 547 | afbackup 2988/tcp # Afbackup system 548 | afbackup 2988/udp 549 | afmbackup 2989/tcp # Afmbackup system 550 | afmbackup 2989/udp 551 | xtell 4224/tcp # xtell server 552 | selenium 4444/tcp # http://seleniumhq.org 553 | fax 4557/tcp # FAX transmission service (old) 554 | hylafax 4559/tcp # HylaFAX client-server protocol (new) 555 | distmp3 4600/tcp # distmp3host daemon 556 | munin 4949/tcp lrrd # Munin 557 | enbd-cstatd 5051/tcp # ENBD client statd 558 | enbd-sstatd 5052/tcp # ENBD server statd 559 | pcrd 5151/tcp # PCR-1000 Daemon 560 | noclog 5354/tcp # noclogd with TCP (nocol) 561 | noclog 5354/udp # noclogd with UDP (nocol) 562 | hostmon 5355/tcp # hostmon uses TCP (nocol) 563 | hostmon 5355/udp # hostmon uses UDP (nocol) 564 | rplay 5555/udp # RPlay audio service 565 | nrpe 5666/tcp # Nagios Remote Plugin Executor 566 | nsca 5667/tcp # Nagios Agent - NSCA 567 | mrtd 5674/tcp # MRT Routing Daemon 568 | bgpsim 5675/tcp # MRT Routing Simulator 569 | canna 5680/tcp # cannaserver 570 | redis 6379/tcp # http://redis.io/topics/config 571 | sane-port 6566/tcp sane saned # SANE network scanner daemon 572 | ircd 6667/tcp # Internet Relay Chat 573 | zope-ftp 8021/tcp # zope management by ftp 574 | tproxy 8081/tcp # Transparent Proxy 575 | omniorb 8088/tcp # OmniORB 576 | omniorb 8088/udp 577 | clc-build-daemon 8990/tcp # Common lisp build daemon 578 | xinetd 9098/tcp 579 | mandelspawn 9359/udp mandelbrot # network mandelbrot 580 | git 9418/tcp # Git Version Control System 581 | zope 9673/tcp # zope server 582 | webmin 10000/tcp 583 | kamanda 10081/tcp # amanda backup services (Kerberos) 584 | kamanda 10081/udp 585 | amandaidx 10082/tcp # amanda backup services 586 | amidxtape 10083/tcp # amanda backup services 587 | smsqp 11201/tcp # Alamin SMS gateway 588 | smsqp 11201/udp 589 | xpilot 15345/tcp # XPilot Contact Port 590 | xpilot 15345/udp 591 | sgi-cmsd 17001/udp # Cluster membership services daemon 592 | sgi-crsd 17002/udp 593 | sgi-gcd 17003/udp # SGI Group membership daemon 594 | sgi-cad 17004/tcp # Cluster Admin daemon 595 | isdnlog 20011/tcp # isdn logging system 596 | isdnlog 20011/udp 597 | vboxd 20012/tcp # voice box system 598 | vboxd 20012/udp 599 | binkp 24554/tcp # binkp fidonet protocol 600 | mongodb 27017/tcp # http://docs.mongodb.org/manual/reference/default-mongodb-port/ 601 | mongodbshard 27018/tcp # http://docs.mongodb.org/manual/reference/default-mongodb-port/ 602 | mongodbconfig 27019/tcp # http://docs.mongodb.org/manual/reference/default-mongodb-port/ 603 | asp 27374/tcp # Address Search Protocol 604 | asp 27374/udp 605 | mongodbweb 28017/tcp # http://docs.mongodb.org/manual/reference/default-mongodb-port/ 606 | csync2 30865/tcp # cluster synchronization tool 607 | dircproxy 57000/tcp # Detachable IRC Proxy 608 | tfido 60177/tcp # fidonet EMSI over telnet 609 | fido 60179/tcp # fidonet EMSI over TCP 610 | 611 | # Local services 612 | -------------------------------------------------------------------------------- /docker/.dockerignore: -------------------------------------------------------------------------------- 1 | log -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # docker-dns 3 | # a dns server for docker environments 4 | # https://github.com/bnfinet/docker-dns 5 | # 6 | 7 | # This file describes how to build docker-dns into a runnable linux container with all dependencies installed 8 | # To build: 9 | # 1) Install docker (http://docker.io) 10 | # 2) Build: ./build_docker.sh 11 | # 3) put a config file in place at ./config/config.js 12 | # 4) Run: ./run_docker.sh 13 | 14 | # base image 15 | # https://index.docker.io/u/dockerfile/nodejs/ 16 | FROM dockerfile/nodejs 17 | 18 | # supervisor 19 | RUN apt-get update && apt-get upgrade -y 20 | RUN apt-get install -y supervisor git 21 | RUN mkdir -p /var/log/supervisor 22 | ADD ./config/supervisord.conf /etc/supervisor/conf.d/supervisord.conf 23 | 24 | # code 25 | WORKDIR /opt 26 | RUN git clone https://github.com/bnfinet/docker-dns.git 27 | WORKDIR /opt/docker-dns 28 | RUN npm install 29 | 30 | EXPOSE 53/udp 31 | 32 | cmd ["supervisord", "-n"] -------------------------------------------------------------------------------- /docker/build_docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # docker rmi docker-dns 4 | # docker build --no-cache --rm -t docker-dns . 5 | docker build --rm -t bfoote/docker-dns . 6 | -------------------------------------------------------------------------------- /docker/config/.gitignore: -------------------------------------------------------------------------------- 1 | config.js 2 | -------------------------------------------------------------------------------- /docker/config/config.js.example: -------------------------------------------------------------------------------- 1 | var config = {}; 2 | 3 | config.development = true; 4 | config.debug = false; 5 | 6 | // a fake top level domain 7 | // appended to all generated hostnames 8 | config.faketld = "docker.local"; 9 | 10 | // frequency of dns entry refresh from docker containers 11 | config.pollinterval = 17 * 1000; 12 | 13 | // multiple dockers can be configured 14 | // each one should gets it's own namespace 15 | // hostname.publicname.faketld 16 | config.dockers = [ 17 | { 18 | // for 'publicly' exposed ports 19 | // when a service is offered on '0.0.0.0' 20 | // this is the IP lookups will return 21 | publicip: "10.20.0.100", 22 | 23 | // the public name is to give this docker instance it's own namespace 24 | publicname: "public.dockerA", 25 | 26 | // the local name is to provide a namespace for routing 172.17.0.0 addresses 27 | localname: "local.dockerA", 28 | 29 | // dockerode config 30 | // see: https://github.com/apocas/dockerode 31 | // and http://docs.docker.io/en/latest/use/basics/#bind-docker 32 | dockerode: { 33 | socketPath: '/var/run/docker.sock' 34 | } 35 | } 36 | ]; 37 | 38 | // node-named config 39 | // see: https://github.com/trevoro/node-named 40 | // bindip is for this container only, not docker-wide 41 | config.node_named = { 42 | port: 53, 43 | bindip: '0.0.0.0' 44 | }; 45 | 46 | module.exports = config; -------------------------------------------------------------------------------- /docker/config/supervisord.conf: -------------------------------------------------------------------------------- 1 | [supervisord] 2 | nodaemon=true 3 | 4 | [program:docker-dns] 5 | command=/opt/docker-dns/bin/docker-dns.js -c /opt/docker-dns/config/config.js 6 | stdout_logfile=/var/log/supervisor/%(program_name)s.log 7 | stderr_logfile=/var/log/supervisor/%(program_name)s.log 8 | autorestart=true 9 | 10 | -------------------------------------------------------------------------------- /docker/log/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | -------------------------------------------------------------------------------- /docker/run_docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=bfoote/docker-dns 4 | DOCKERBRIDGEIP=$(ip addr show dev docker0 | awk -F'[ /]*' '/inet /{print $3}'); 5 | 6 | 7 | function usage { 8 | cat < ip 142 | self._recs.a.push({ 143 | fqdn : fqdnFn(self.uuid), 144 | ip : ip 145 | }); 146 | 147 | // A first12(UUID) -> ip 148 | self._recs.a.push({ 149 | fqdn : fqdnFn(self.uuid12), 150 | ip : ip 151 | }); 152 | 153 | // CNAME hostname -> first12(UUID) 154 | if (self.hostname) { 155 | self._recs.cname.push({ 156 | fqdn : fqdnFn(self.hostname), 157 | a : fqdnFn(self.uuid12) 158 | }); 159 | } 160 | 161 | // CNAME imgname -> first12(UUID) 162 | if (self.imgname) { 163 | self._recs.cname.push({ 164 | fqdn : fqdnFn(self.imgname), 165 | a : fqdnFn(self.uuid12) 166 | }); 167 | } 168 | 169 | cb(); 170 | }; 171 | 172 | var rxdotsorslashorcolon = /\.|\/|:/g; 173 | proto.getImgName = function() { 174 | this.imgname = this.insp.Name.replace(rxdotsorslashorcolon, ""); 175 | }; 176 | 177 | 178 | proto._buildSRVRecords = function(cb) { 179 | var self = this; 180 | if (self.services.length === 0) { 181 | self.log.debug(self.uuid12, 'no service records'); 182 | return cb(); 183 | } 184 | async.each(self.services, function(service, done) { 185 | if (service.port && service.boundip) { 186 | async.each(["", self.uuid12, self.hostname, self.imgname], function(name, next) { 187 | if (typeof name !== 'undefined') { 188 | self.putsrvrec(service, name); 189 | self.putsrvrecForServiceName(service, name); 190 | }; 191 | next(); 192 | }, done); 193 | } else { 194 | self.log.debug("service port or bound ip missing: ", service); 195 | done(); 196 | } 197 | }, function(err) { 198 | self.log.debug(self.uuid12, "calling back from _buildSRVRecords"); 199 | // self.log(self._recs); 200 | cb(err); 201 | }); 202 | }; 203 | 204 | 205 | //anatomy of a self.service object: 206 | //{ port: '49160', 207 | // boundip: '0.0.0.0', 208 | //portproto: '22/tcp', 209 | //lookup: { name: 'ssh', port: 22, proto: 'tcp', portproto: '22/tcp' } } 210 | 211 | proto.putsrvrecForServiceName = function(service, name) { 212 | var self = this; 213 | // add a traditional host specific RFC compliant SRV record 214 | // SRV name -> _srv._proto.fqdn -> (port, fqdn) 215 | if (service && service.lookup && service.lookup.name) { 216 | var srvname = '_' + service.lookup.name + '._' + service.lookup.proto 217 | + '.' + name; 218 | self.putsrvrec(service, srvname); 219 | } 220 | }; 221 | 222 | proto.putsrvrec = function(service, name) { 223 | var self = this; 224 | 225 | // do one record for the inside with inside port 226 | if (!self._recs.srv[self.docker.localfqdn(name)]) { 227 | self._recs.srv[self.docker.localfqdn(name)] = []; 228 | } 229 | self._recs.srv.push({ 230 | fqdn : self.docker.localfqdn(name), 231 | port : parseInt(service.lookup.port), 232 | name : self.docker.localfqdn(self.uuid12) 233 | }); 234 | 235 | // do one record for the outside with outside port 236 | if (!self._recs.srv[self.docker.publicfqdn(name)]) { 237 | self._recs.srv[self.docker.publicfqdn(name)] = []; 238 | } 239 | self._recs.srv.push({ 240 | fqdn : self.docker.publicfqdn(name), 241 | port : parseInt(service.port), 242 | name : self.docker.publicfqdn(self.uuid12) 243 | }); 244 | }; 245 | 246 | proto.getIps = function() { 247 | var self = this; 248 | var ips = { 249 | internal : self.insp.NetworkSettings.IPAddress, 250 | exposed : null 251 | }; 252 | 253 | try { 254 | var iHp = self.insp.NetworkSettings.Ports; 255 | self.log.debug("iHp", iHp); 256 | if (iHp 257 | && Object.keys(iHp).length > 0 258 | && iHp[Object.keys(iHp)[0]] 259 | && iHp[Object.keys(iHp)[0]] 260 | && iHp[Object.keys(iHp)[0]][0] 261 | && iHp[Object.keys(iHp)[0]][0].HostIp 262 | ) { 263 | var hostboundip = iHp[Object 264 | .keys(iHp)[0]][0].HostIp; 265 | self.log.debug('getip ip: ', hostboundip); 266 | if (hostboundip === '0.0.0.0') { 267 | ips.exposed = self.config.publicip; 268 | } else if (hostboundip !== ips.internal) { 269 | ips.exposed = hostboundip; 270 | } 271 | } 272 | } catch (err) { 273 | self.log.error('portbinding publicip lookup failed', err); 274 | } 275 | self.ips = ips; 276 | self.log.debug("ips ", self.ips); 277 | }; 278 | -------------------------------------------------------------------------------- /lib/dns-service.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var async = require('async'); 3 | var named = require('node-named'); 4 | var _ = require('lodash'); 5 | var server = named.createServer(); 6 | var logger = require('./logger.js'); 7 | 8 | var _recs = {}; 9 | var config; 10 | 11 | var allowedChars = /[A-Za-z0-9\.\*-_]*/; 12 | server.on('query', function(query) { 13 | var domain = query.name(); 14 | 15 | if (!domain.match(allowedChars)) { 16 | logger.error('bad query',domain); 17 | server.send(query); 18 | return; 19 | } 20 | 21 | var type = query.type(); 22 | logger.info('DNS Query:', type, domain); 23 | switch (type) { 24 | case 'A': 25 | if (_recs.a[domain]) { 26 | query.addAnswer(domain, _recs.a[domain]); 27 | } else if (_recs.cname[domain]) { 28 | query.addAnswer(domain, _recs.cname[domain]); 29 | logger.debug('cname a: ', _recs.cname[domain].target, 30 | _recs.a[_recs.cname[domain].target]); 31 | query.addAnswer(_recs.cname[domain].target, 32 | _recs.a[_recs.cname[domain].target]); 33 | } 34 | server.send(query); 35 | break; 36 | case 'CNAME': 37 | query.addAnswer(domain, _recs.cname[domain]); 38 | logger.debug('cname a: ', _recs.cname[domain].target, 39 | _recs.a[_recs.cname[domain].target]); 40 | query.addAnswer(_recs.cname[domain].target, 41 | _recs.a[_recs.cname[domain].target]); 42 | server.send(query); 43 | break; 44 | case 'SOA': 45 | query.addAnswer(domain, soa); 46 | server.send(query); 47 | break; 48 | case 'SRV': 49 | console.log(_recs.srv[domain]); 50 | findMatchingSRVRecords(domain, function(err, recs) { 51 | async.each(recs, function(rec, done) { 52 | logger.debug("srv match:", rec); 53 | query.addAnswer(domain, rec); 54 | done(); 55 | }, function() { 56 | server.send(query); 57 | }); 58 | }); 59 | break; 60 | // case 'TXT': 61 | // var record = new named.TXTRecord('hello world'); 62 | // query.addAnswer(domain, record, 'TXT'); 63 | // break; 64 | default: 65 | server.send(query); 66 | } 67 | }); 68 | 69 | var findMatchingSRVRecords = function(domain, cb) { 70 | var ret = []; 71 | // return the common case immediately 72 | if (_recs.srv[domain]) { 73 | logger.debug("found domain " + domain); 74 | cb(null, _recs.srv[domain]); 75 | } else { 76 | // otherwise search for it 77 | var rx = domainToRegex(domain); 78 | // console.log(rx); 79 | async.each(Object.keys(_recs.srv), function(d, done) { 80 | if (d.match(rx)) { 81 | logger.debug("match:", d); 82 | ret = _.union(ret, _recs.srv[d]); 83 | } 84 | done(); 85 | }, function(err) { 86 | // consolidate the results to one target 87 | ret = _.uniq(ret, 'target'); 88 | cb(err, ret); 89 | }); 90 | } 91 | 92 | }; 93 | 94 | var rxwildcard = /\*/g; 95 | var domainToRegex = function(domain) { 96 | domain = domain.replace(rxwildcard, ".*"); 97 | return new RegExp(domain); 98 | }; 99 | 100 | 101 | server.on('clientError', function(error) { 102 | logger.error("there was a clientError: ", error); 103 | }); 104 | 105 | server.on('uncaughtException', function(error) { 106 | logger.error("there was an excepton: ", error.message); 107 | }); 108 | 109 | module.exports.newrecords = function(recs, cb) { 110 | logger.info("loading new dns records"); 111 | _transformRecords(recs, cb); 112 | }; 113 | 114 | var _transformRecords = function(recs, cb) { 115 | async.parallel([ function(done) { 116 | _buildArecords(recs, done); 117 | // console.log("a records", _recs.a); 118 | }, 119 | function(done) { 120 | _buildCNAMErecords(recs, done); 121 | // console.log("cname records", _recs.cname); 122 | }, 123 | function(done) { 124 | _buildSRVrecords(recs, done); 125 | } ], cb); 126 | }; 127 | 128 | var _buildArecords = function(recs, cb) { 129 | _recs.a = {}; 130 | async.each(recs.a, function(a, done) { 131 | _recs.a[a.fqdn] = new named.ARecord(a.ip); 132 | done(); 133 | }, cb); 134 | 135 | }; 136 | 137 | var _buildCNAMErecords = function(recs, cb) { 138 | _recs.cname = {}; 139 | async.each(recs.cname, function(cname, done) { 140 | // console.log("buildCNAME", cname); 141 | _recs.cname[cname.fqdn] = new named.CNAMERecord(cname.a); 142 | done(); 143 | }, cb); 144 | }; 145 | 146 | var _buildSRVrecords = function(recs, cb) { 147 | _recs.srv = {}; 148 | async.each(recs.srv, function(srv, done) { 149 | logger.debug("servicename: ", srv.name); 150 | // TODO add weight and priority 151 | if (!_recs.srv[srv.fqdn]) { 152 | _recs.srv[srv.fqdn] = []; 153 | } 154 | _recs.srv[srv.fqdn].push(new named.SRVRecord(srv.name, srv.port)); 155 | done(); 156 | }, cb); 157 | }; 158 | 159 | module.exports.startservice = function(c, cb) { 160 | config = c; 161 | logger = config.logger; 162 | _recs.soa = new named.SOARecord(config.faketld, { 163 | ttl : 10 164 | }); 165 | server.listen(config.node_named.port, config.node_named.bindip, function() { 166 | logger.info('listening for dns queries on', config.node_named.bindip, config.node_named.port); 167 | }); 168 | }; 169 | -------------------------------------------------------------------------------- /lib/docker-inspect.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var DockerOde = require('dockerode'); 3 | var async = require('async'); 4 | var _ = require('lodash'); 5 | var Cinspect = require(__dirname + '/../lib/container-inspect.js'); 6 | 7 | // TODO 8 | /* 9 | * establish A record(s) for the docker itself 10 | * 11 | */ 12 | 13 | function Dinspect(config) { 14 | var self = this; 15 | if (self.configure(config)) { 16 | self.D = new DockerOde(self.config.dockerode); 17 | self.log.debug(self.name, "new Dinspect for docker " 18 | + self.config.publicname); 19 | } 20 | } 21 | 22 | module.exports = Dinspect; 23 | 24 | var proto = Dinspect.prototype; 25 | 26 | proto.configure = function(c) { 27 | var self = this; 28 | if (!c) { 29 | console.error('BAD no config found! returning'); 30 | return false; 31 | } 32 | self.config = c; 33 | self.debug = self.config.debug; 34 | self.log = self.config.logger; 35 | self.name = self.config.publicname; 36 | return true; 37 | }; 38 | 39 | proto.buildRecords = function(cb) { 40 | var self = this; 41 | self._recs = { 42 | a : [], 43 | cname : [], 44 | srv : [] 45 | }; 46 | // TODO lookup the ip address of docker0 47 | // create an A record for locafqdn 48 | 49 | if (self.config.publicip) { 50 | self._recs.a.push({ 51 | fqdn : self.publicfqdn(), 52 | ip : self.config.publicip 53 | }); 54 | } 55 | 56 | async.each(self.containers, function(container, next) { 57 | container.buildRecords(function(err, recs) { 58 | self._recs.a = _.union(self._recs.a, recs.a); 59 | self._recs.cname = _.union(self._recs.cname, recs.cname); 60 | self._recs.srv = _.union(self._recs.srv, recs.srv); 61 | self.log.debug(self.config.publicname, '_.union of records finished'); 62 | next(); 63 | }); 64 | }, function(err) { 65 | if (err) { 66 | self.log.error(err); 67 | } 68 | self.log.info(self.config.publicname,'built records'); 69 | cb(err, self._recs); 70 | }); 71 | }; 72 | 73 | proto.inspectContainers = function(cb) { 74 | var self = this; 75 | self.log.debug(self.name, "getting containers for docker " + self.config.publicname); 76 | self.containers = []; 77 | self.D.listContainers({ all : 1 }, function(err, containers) { 78 | self.log.debug(self.name, "inspecting " + containers.length +" containers"); 79 | async.each(containers, function(container, next) { 80 | var newC = new Cinspect(self, container.Id); 81 | if (newC) { 82 | newC.gatherInfo(function() { 83 | self.containers.push(newC); 84 | next(); 85 | }); 86 | } else { 87 | self.log.error(self.name, "container inspection failed for " + container.Id); 88 | next("container inspection failed for " + container.Id); 89 | } 90 | }, cb); 91 | }); 92 | }; 93 | 94 | // the public fqdn 95 | proto.publicfqdn = function(host) { 96 | return this._actualfqdn(host, this.config.publicname); 97 | }; 98 | 99 | // usually resolving to an ip associated with docker0 172.17.42.0/16 100 | proto.localfqdn = function(host) { 101 | return this._actualfqdn(host, this.config.localname); 102 | }; 103 | 104 | proto._actualfqdn = function(host, extra) { 105 | var ret = ''; 106 | if (host) { 107 | ret = ret + host + '.'; 108 | } 109 | if (extra) { 110 | ret = ret + extra + '.'; 111 | } 112 | ret = ret + this.config.faketld; 113 | return ret; 114 | }; 115 | -------------------------------------------------------------------------------- /lib/etc-services-lookup.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var lazy = require("lazy"); 4 | var fs = require("fs"); 5 | 6 | var rxspaces = /\s+/; 7 | var rxcomment = /^#/; 8 | var rxslash = /\//; 9 | 10 | var pps = []; 11 | 12 | // format of /etc/services is 13 | // ssh 22/tcp 14 | // dns 53/udp 15 | // www 80/tcp 16 | // 17 | // parse it to beome 18 | // [ '22/tcp' : { 19 | // service: 'ssh', 20 | // port: '22', 21 | // proto: 'tcp', 22 | // portproto: '22/tcp' }] 23 | // 24 | new lazy(fs.createReadStream(__dirname + '/../config/etc-services')).lines 25 | .forEach(function(line) { 26 | var fields = line.toString().split(rxspaces); 27 | // must exist, weed out comments 28 | if (fields[0] && fields[1] && !rxcomment.test(fields[0])) { 29 | var name = fields[0]; 30 | var portproto = fields[1]; 31 | var pp = portproto.split(rxslash); 32 | var port = parseInt(pp[0], 10); 33 | var proto = pp[1]; 34 | 35 | pps[portproto] = { 36 | name : name, 37 | port : port, 38 | proto : proto, 39 | portproto : portproto 40 | }; 41 | } 42 | }); 43 | 44 | module.exports = { 45 | getService : function(portproto) { 46 | return pps[portproto]; 47 | } 48 | }; -------------------------------------------------------------------------------- /lib/logger.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | // make the logging a little easier on the eyes 7 | var log = function (logFn, args, type) { 8 | if (logger.prepend) { 9 | Array.prototype.unshift.call(args, '[' + logger.prepend + ']',type); 10 | } 11 | logFn.apply(console, args); 12 | }; 13 | 14 | var debug = function() { 15 | if (logger.level === 'debug') { 16 | log(console.log, arguments, 'debug'); 17 | } 18 | }; 19 | 20 | var info = function() { 21 | if (logger.level === 'info' || logger.level === 'debug') { 22 | log(console.log, arguments, 'info'); 23 | } 24 | }; 25 | 26 | var warn = function() { 27 | if (logger.level === 'info' || logger.level === 'debug' || logger.level === 'warn') { 28 | log(console.error, arguments, 'warn'); 29 | } 30 | }; 31 | 32 | var error = function() { 33 | log(console.error, arguments, 'error'); 34 | }; 35 | 36 | var logger; 37 | module.exports = logger = { 38 | debug: debug, 39 | info: info, 40 | warn: warn, 41 | error: error, 42 | prepend: '', 43 | level: 'info' 44 | }; 45 | 46 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docker-dns", 3 | "version": "0.2.6", 4 | "description": "dns server backed by the docker api", 5 | "scripts": { 6 | "start": "node ./bin/docker-dns.js", 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "docker", 11 | "dns", 12 | "api" 13 | ], 14 | "author": { 15 | "name": "Benjamin Foote", 16 | "email": "docker-dns@bnf.net", 17 | "url": "http://www.bnf.net/" 18 | }, 19 | "maintainer": [ 20 | "Benjamin Foote " 21 | ], 22 | "repository": { 23 | "type": "git", 24 | "url": "git@github.com:bnfinet/docker-dns.git" 25 | }, 26 | "main": "./bin/docker-dns.js", 27 | "bin": { 28 | "docker-dns": "./bin/docker-dns.js" 29 | }, 30 | "directories": { 31 | "lib": "./lib" 32 | }, 33 | "bugs": { 34 | "url": "https://github.com:bnfinet/docker-dns/issues" 35 | }, 36 | "license": "MIT", 37 | "engines": { 38 | "node": ">=0.10.0", 39 | "npm": ">=1.0.0" 40 | }, 41 | "engineStrict": true, 42 | "dependencies": { 43 | "async": "~0.9.0", 44 | "dockerode": "~2.0.6", 45 | "lazy": "~1.0.11", 46 | "lodash": "~2.4.1", 47 | "minimist": "~0.2.0", 48 | "node-named": "~0.0.1" 49 | }, 50 | "devDependencies": { 51 | "grunt": "~0.4.2", 52 | "grunt-cli": "~0.1.13", 53 | "grunt-contrib-jshint": "~0.10.0", 54 | "grunt-nodemon": "~0.3.0" 55 | } 56 | } 57 | --------------------------------------------------------------------------------