Avez-vous déjà pensé "Je veux créer mon propre serveur DNS"?
Il ne s'agit pas d'apt-get install bind9
, mais de créer un programme de serveur DNS.
«Je n'ai pas besoin de cela, j'ai besoin de créer mes propres bloquer l'accès aux ressources inutiles sur les pages Web et [la productivité au travail. [Http://engineer.typemag.jp/article/fukuyuki41) N'est-ce pas à peu près l'heure? ”N'est-ce pas?
Cependant, si vous pouviez contrôler librement la réponse DNS avec Python, vous pourriez faire quelque chose de plus intéressant.
Soudain, j'ai cherché sur Google comment créer mon propre serveur DNS avec Python.
Il existe une méthode pour créer un serveur DNS en utilisant Twisted dans l'article trouvé dans Qiita. http://qiita.com/futoase/items/174883d7fa8d2dd4240a
Après avoir examiné la dernière documentation, j'ai trouvé qu'il était plus facile que prévu de créer un serveur DNS personnalisé qui assemble dynamiquement les réponses.
http://twistedmatrix.com/documents/current/names/howto/custom-server.html
C'est fantastique! Vos rêves se répandront!
Puisque le contenu de la réponse peut être assemblé avec du code Python, il semble que diverses choses intéressantes puissent être faites.
Par exemple, Retty a créé son propre serveur DNS pour faciliter le passage à un environnement de test. En combinant avec les paramètres LAN sans fil, la même demande que la production peut être envoyée à l'environnement de test simplement en se connectant à un point d'accès spécifique.
Dans le réseau de l'entreprise, un serveur DNS pour l'environnement de test créé par Twisted est en cours d'exécution, et lorsque vous demandez le nom d'hôte de l'environnement de production, l'adresse IP du résultat de la demande du nom d'hôte de l'environnement de test est renvoyée. En utilisant un LAN sans fil qui prend en charge les VLAN et plusieurs ESSID, les clients connectés à un nom de point d'accès spécifique interrogent automatiquement le serveur DNS pour l'environnement de test. Par conséquent, même si la demande concerne la même URL que l'environnement de production, si vous contactez le serveur DNS pour l'environnement de test, vous serez dirigé vers l'environnement de test. C'est DNS Spoo ... Oh, on dirait que quelqu'un est venu.
En outre, il peut être possible de se lier à d'autres services tels qu'AWS pour créer un serveur DNS qui renvoie une réponse appropriée en fonction de la configuration et de l'état du service.
Créons donc un serveur DNS qui fonctionne avec l'API AWS.
Si vous demandez l'ID d'une instance EC2 comme ʻi-abcd1234.ec2.local`, il retournera l'adresse IP attribuée à l'instance.
Après avoir rendu Python 2 et pip disponibles, insérez Twisted. À partir de Twisted-15.5.0, cela ne semblait pas fonctionner car une partie du code lié au serveur DNS ne prenait pas en charge Python 3.
[user@localhost]$ pip2 install twisted
Dans cet exemple, nous accéderons à AWS, donc installez Boto 3 et l'AWS CLI et définissez les informations d'identification.
[user@localhost]$ pip2 install boto3 awscli
[user@localhost]$ aws configure
Les exemples suivants ont été confirmés pour fonctionner avec Python-2.7.10, Twisted-15.5.0 et boto3-1.2.3.
Selon Twisted Documents (http://twistedmatrix.com/documents/current/names/howto/custom-server.html#a-server-which-computes-responses-dynamically), résolution de nom dynamique Il semble que le moyen le plus rapide d'y parvenir soit de créer et d'enregistrer un résolveur personnalisé. Twisted gère le traitement du protocole, c'est donc très simple.
Donc, pour les demandes au domaine ʻec2.local`, nous considérerons la première étiquette comme l'ID d'instance EC2 et créerons un résolveur qui répond avec cette adresse IP.
Vous pouvez le faire en héritant de twisted.names.common.ResolverBase
et en remplaçant lookupAddress ()
.
resolver.py
# coding=utf-8
import boto3
import botocore
from twisted.internet import defer
from twisted.logger import Logger
from twisted.names import common, dns, error
log = Logger()
ec2 = boto3.resource('ec2')
def find_ec2_address(instance_id):
if instance_id:
try:
instance = ec2.Instance(instance_id)
#Instance si vous avez besoin d'une adresse IP publique.public_ip_Peut être obtenu à partir de l'adresse.
address = instance.private_ip_address
log.debug('Found {instance!r} address={address}', instance=instance, address=address)
return address
except botocore.exceptions.ClientError:
log.failure('Failed to find {instance_id}', instance_id=instance_id)
class EC2ResourceResolver(common.ResolverBase):
#Domaine à renommer dynamiquement
_suffix = '.ec2.local'
_ttl = 30
def _should_resolve(self, name):
return name.lower().endswith(self._suffix)
def lookupAddress(self, name, timeout=None):
log.debug('Looking up address {name}', name=name)
if self._should_resolve(name):
#Considérez la première étiquette comme l'ID d'instance EC2.
instance_id = name.split('.', 1)[0]
address = find_ec2_address(instance_id)
answer, authority, additional = common.EMPTY_RESULT
if address:
answer = [
dns.RRHeader(
name=name,
ttl=self._ttl,
payload=dns.Record_A(address=b'%s' % (address,), ttl=self._ttl),
auth=True)
]
return defer.succeed((answer, authority, additional))
# error.DomainError()Si vous échouez, il contactera le résolveur suivant.
return defer.fail(error.DomainError(name))
lookupAllRecords = lookupAddress
#Pour éviter les requêtes répétées à d'autres résolveurs
#D'autres types de requêtes sont également résolus en tant que résultats vides dans le domaine cible.
def _lookup(self, name, cls, type, timeout):
if self._should_resolve(name):
return defer.succeed(common.EMPTY_RESULT)
return defer.fail(error.DomainError(name))
Oups, Twisted est un framework de programmation asynchrone, mais il est bloqué en appelant boto ... Je crains qu'il ne se comporte pas bien, mais cette fois c'est un échantillon, alors passons à autre chose.
Ensuite, créez un serveur de cache DNS qui utilise ce résolveur pour la résolution de noms.
ec2-dns-server.py
#!/usr/bin/env python2
# coding=utf-8
import sys
from twisted.internet import reactor
from twisted.names import client, dns, server
from twisted.python import log
from resolver import EC2ResourceResolver
def main():
log.startLogging(sys.stderr)
factory = server.DNSServerFactory(
clients=[
EC2ResourceResolver(),
client.Resolver(servers=[('8.8.8.8', 53), ('8.8.4.4', 53)])
]
)
protocol = dns.DNSDatagramProtocol(factory)
reactor.listenUDP(10053, protocol)
reactor.listenTCP(10053, factory)
reactor.run()
if __name__ == '__main__':
raise SystemExit(main())
Dans cet exemple, la requête DNS est écoutée sur le port 10053 et la requête non résolue est relayée vers Google Public DNS ("8.8.8.8", "8.8.4.4").
Si vous voulez obtenir cette destination de relais depuis / etc / resolv.conf
client.Resolver(servers=[('8.8.8.8', 53), ('8.8.4.4', 53)])
Partie de
client.Resolver(resolv='/etc/resolv.conf')
Ce n'est pas grave si vous le réécrivez.
Déplaçons-le.
[user@localhost]$ python2 ec2-dns-server.py
2015-12-24 20:35:49+0900 [-] Log opened.
2015-12-24 20:35:49+0900 [-] DNSDatagramProtocol starting on 10053
2015-12-24 20:35:49+0900 [-] Starting protocol <twisted.names.dns.DNSDatagramProtocol object at 0x6fffe4bccd0>
2015-12-24 20:35:49+0900 [-] DNSServerFactory starting on 10053
2015-12-24 20:35:49+0900 [-] Starting factory <twisted.names.server.DNSServerFactory instance at 0x6fffe4c61b8>
Je vais le tester en utilisant dig pour voir s'il fonctionne correctement
[user@localhost]$ dig -p 10053 @localhost i-abcd1234.ec2.local +norecurse +short
10.11.25.25
Si l'adresse de l'instance EC2 est renvoyée comme ceci, cela fonctionne correctement.
Le DNS peut être un service abordable à utiliser comme fenêtre de découverte de service, car les points de terminaison AWS fournissent divers noms DNS (xxxx.amazonaws.com
).
[RFC 2782](https: // www.) Utilisé par Active Directory est un moyen de trouver l'emplacement d'un service par nom abstrait en utilisant DNS. Aliase utilisant l'enregistrement SRV (ietf.org/rfc/rfc2782.txt) ou, plus concis, CNAME comme dans RFC 2219 Il semble y avoir un moyen. La méthode d'attribution d'un alias avec CNAME a l'avantage d'être très polyvalente, et en fait, dans AWS, [RDS for Oracle Database Multi-AZ](http://aws.typepad.com/aws_japan/2012/05/multi-az- option-for-amazon-rds-for-oracle-database.html) et Détection automatique du nœud ElastiCache ) Semble être utilisé.
Cependant, même si vous essayez d'abstraire l'emplacement du service avec CNAME, il existe diverses restrictions avec CNAME. Par exemple, dans une configuration où l'environnement change dynamiquement en augmentant ou en abaissant l'instance, le problème de la façon de maintenir et de gérer la correspondance avec l'hôte réel demeure.
Par conséquent, ["Terms from settings"](https://ja.wikipedia.org/wiki/%E8%A8%AD%E5%AE%9A%E3%82%88%E3%82%8A%E8%A6% 8F% E7% B4% 84) Si vous attribuez à une ressource telle qu'une instance EC2 un nom facile à gérer à partir du programme, vous pouvez créer un service DNS qui répond dynamiquement à l'aide des métadonnées de la ressource. C'est vrai. Excluez les esclaves qui ont des retards de réplication tels que MySQL et provoquent un basculement (Je peux le faire avec HAProxy), plus Vos rêves peuvent se propager.
Recommended Posts