-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit e242eb7
Showing
4 changed files
with
219 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
|
||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | ||
Version 2, December 2004 | ||
|
||
Copyright (C) 2004 Sam Hocevar <[email protected]> | ||
|
||
Everyone is permitted to copy and distribute verbatim or modified | ||
copies of this license document, and changing it is allowed as long | ||
as the name is changed. | ||
|
||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | ||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||
|
||
0. You just DO WHAT THE FUCK YOU WANT TO. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# Docker DNS | ||
|
||
Docker DNS is a DNS server that resolve Docker's container name into | ||
A record to retrieve IPv4 associated. | ||
|
||
## Installation configuration and execution | ||
|
||
First you need to clone this repository | ||
|
||
``` | ||
git clone https://github.com/dangoncalves/docker-dns | ||
``` | ||
|
||
Then change directory and install dependencies | ||
|
||
``` | ||
cd docker-dns | ||
pip3 install requirements.txt | ||
``` | ||
|
||
Execute the script as root (to bind on port 53) | ||
|
||
``` | ||
python3 docker-dns.py | ||
``` | ||
|
||
Finally you can edit `/etc/resolv.conf` and put that line at the file's begining | ||
(don't remove other nameserver entries) | ||
|
||
``` | ||
nameserver 127.0.0.1 | ||
``` | ||
|
||
## Options | ||
|
||
There are three options you can use to customize execution: | ||
|
||
* `--port` customize the port docker-dns will listen on (default 53) | ||
* `--listen-address` customize the address docker-dns will listen on | ||
(default 127.0.0.1) | ||
* `--forwarders` dns forwarders' list (coma separated list) | ||
|
||
## License | ||
|
||
This project is under WTFPL | ||
|
||
## TODO - Roadmap | ||
|
||
The project's goal is just to resolve docker containers' name into IP address. | ||
This first version do the job, but there are still some things to do like: | ||
* add tests | ||
* add AAAA queries support | ||
* add PTR queries support | ||
* automate installation | ||
* improve documentation | ||
* add Windows and Mac OS support (tested only on Linux for now) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
#!/usr/bin/env python3 | ||
""" | ||
Resolve docker container's name into IPv4 address | ||
python3 docker-dns.py | ||
""" | ||
|
||
import os | ||
import sys | ||
import signal | ||
import docker | ||
import argparse | ||
from threading import Thread | ||
from twisted.internet import reactor, defer | ||
from twisted.names import client, dns, server, error | ||
|
||
|
||
class DockerResolver(client.Resolver): | ||
"""Resolve container name into IP address.""" | ||
def __init__(self, dockerClient, servers=[]): | ||
super().__init__(resolv=None, servers=servers) | ||
self.dockerClient = dockerClient | ||
self.runningContainers = {} | ||
for c in dockerClient.containers.list(): | ||
containerName = c.attrs["Name"][1:] | ||
containerBridge = c.attrs["NetworkSettings"]["Networks"]["bridge"] | ||
containerIPv4 = containerBridge["IPAddress"] | ||
self.addContainer(containerName, containerIPv4) | ||
|
||
def addContainer(self, containerName, containerIPv4): | ||
self.runningContainers[containerName] = containerIPv4 | ||
|
||
def removeContainer(self, containerName): | ||
self.runningContainers.pop(containerName, None) | ||
|
||
def lookupAddress(self, query, timeout=None): | ||
domain = query.decode() | ||
if domain in self.runningContainers: | ||
p = dns.Record_A(address=self.runningContainers[domain].encode()) | ||
answer = dns.RRHeader(name=query, payload=p) | ||
answers = [answer] | ||
authority = [] | ||
additional = [] | ||
return defer.succeed((answers, authority, additional)) | ||
else: | ||
return super().lookupAddress(query, timeout) | ||
|
||
|
||
class EventsListener(Thread): | ||
"""Listen on start and die events.""" | ||
def __init__(self, resolver): | ||
super().__init__() | ||
self.resolver = resolver | ||
|
||
def run(self): | ||
eventListener = self.resolver.dockerClient.events( | ||
filters={"event": ["start", "die"]}, | ||
decode=True) | ||
for e in eventListener: | ||
callback = getattr(self, e["Action"] + "Callback") | ||
callback(e) | ||
|
||
def startCallback(self, event): | ||
containerName = event["Actor"]["Attributes"]["name"] | ||
api = self.resolver.dockerClient.api | ||
container = api.inspect_container(containerName) | ||
containerIPv4 = container["NetworkSettings"]["IPAddress"] | ||
self.resolver.addContainer(containerName, containerIPv4) | ||
|
||
def dieCallback(self, event): | ||
containerName = event["Actor"]["Attributes"]["name"] | ||
self.resolver.removeContainer(containerName) | ||
|
||
|
||
def getForwarders(forwarders="", listenAddress="127.0.0.1"): | ||
""" | ||
Reads forwarders from arguments or from resolv.conf and create a list of | ||
tuples containing the forwarders' IP and the port. | ||
""" | ||
if not forwarders: | ||
forwarders = [] | ||
resolvconf = open("/etc/resolv.conf", "r") | ||
for line in resolvconf: | ||
if line.startswith("nameserver") and line[11:-1] == listenAddress: | ||
continue | ||
if line.startswith("nameserver"): | ||
forwarders.append((line[11:-1], 53)) | ||
else: | ||
forwarders = forwarders.split(",") | ||
forwarders = [(address, 53) for address in forwarders] | ||
return forwarders | ||
|
||
|
||
def dockerDns(port=53, listenAddress="127.0.0.1", forwarders=[]): | ||
"""Configure and execute the DNS server.""" | ||
dockerClient = docker.from_env() | ||
resolver = DockerResolver(dockerClient=dockerClient, | ||
servers=forwarders) | ||
eventsListener = EventsListener(resolver) | ||
eventsListener.start() | ||
factory = server.DNSServerFactory(clients=[resolver]) | ||
protocol = dns.DNSDatagramProtocol(controller=factory) | ||
reactor.listenUDP(port=port, protocol=protocol, interface=listenAddress) | ||
reactor.listenTCP(port=port, factory=factory, interface=listenAddress) | ||
reactor.run() | ||
eventsListener.join(1) | ||
# For an unknown reason sys.exit() does not work | ||
# so we use this hack. | ||
os._exit(0) | ||
|
||
|
||
if __name__ == "__main__": | ||
description = "Resolve docker container's name into IPv4 address" | ||
parser = argparse.ArgumentParser(description=description) | ||
parser.add_argument("--port", | ||
action="store", | ||
dest="port", | ||
type=int, | ||
default=53) | ||
parser.add_argument("--listen-address", | ||
action="store", | ||
dest="listenAddress", | ||
default="127.0.0.1") | ||
parser.add_argument("--forwarders", | ||
action="store", | ||
dest="forwarders", | ||
default="") | ||
options = parser.parse_args() | ||
forwarders = getForwarders(forwarders=options.forwarders, | ||
listenAddress=options.listenAddress) | ||
dockerDns(port=options.port, | ||
listenAddress=options.listenAddress, | ||
forwarders=forwarders) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
attrs==17.3.0 | ||
Automat==0.6.0 | ||
certifi==2017.11.5 | ||
chardet==3.0.4 | ||
constantly==15.1.0 | ||
docker==2.6.1 | ||
docker-pycreds==0.2.1 | ||
hyperlink==17.3.1 | ||
idna==2.6 | ||
incremental==17.5.0 | ||
requests==2.18.4 | ||
six==1.11.0 | ||
Twisted==17.9.0 | ||
urllib3==1.22 | ||
websocket-client==0.44.0 | ||
zope.interface==4.4.3 |