[python网络编程]DNS服务器

在上一篇中,使用scrapy修改源IP发送请求的最后我们提到由于hosts文件不支持正则,会导致我们的随机域名DNS查询失败。使用DNS代理服务器可以解决这个问题,

下面是我用gevent写的小工具,很简单。我们只拦截匹配的A记录,然后发送DNS Response,如果不匹配,那么我们服务器就是一个DNS代理,转发请求。

# -*- coding=utf-8 -*-
import struct
from cStringIO import StringIO
from collections import namedtuple
from gevent import socket
from gevent.server import DatagramServer

Hex = lambda x : ‘0x{0:04x}‘.format(x) # Hex(256) => "0x0100"

QueryResult = namedtuple("DnsQuery",
                 "transactionID,flags,questions,answerRrs                  authorityRrs,additionalRrs,qname,qtype,qclass"
)

LOCALDNS = ("114.114.114.114",53)

Hosts = {
    "*.ttt.com":"173.194.127.144", # google ip
}

def preg_match(preg,real):
    """
    only support ‘*‘
    >>>preg_match("www.*.test*.com","www.python.test.com")
    True
    >>>preg_match("www.*.test*.com","www.python.tes.com")
    False
    """
    pre = 0
    for s in preg.split(‘*‘):
        now = real.find(s)
        if now < pre:
            return False
        pre = now +len(s)
    return True

def udp_send(address,data):
    sock = socket.socket(type=socket.SOCK_DGRAM)
    sock.connect(address)
    sock.send(data)
    response, address = sock.recvfrom(8192*4)
    return response,address

class DnsParser:

    @classmethod
    def parseQuery(self,query):
        """
               6a 02 01 00 00 01                         j.....
        00 00 00 00 00 00 03 77 77 77 03 61 61 61 03 63  .......www.aaa.c
        6f 6d 00 00 01 00 01                             om.....

        dns query package like above
        03 77 77 77 : three www

        """
        transactionID,flags,questions,answerRrs,authorityRrs,additionalRrs = map(Hex,struct.unpack("!6H",query[:12]))
        quries = StringIO(query[12:])
        c = struct.unpack("!c",quries.read(1))[0]
        domain = []
        while  c != ‘\x00‘:
            n = ord(c)
            domain.append(‘‘.join(struct.unpack("!%sc" % n,quries.read(ord(c)))))
            c = struct.unpack("!c",quries.read(1))[0]
        domain = ‘.‘.join(domain)
        qtype,qclass = map(Hex,struct.unpack("!2H",quries.read()))
        return QueryResult(transactionID,flags,questions,answerRrs,
                            authorityRrs,additionalRrs,domain,qtype,qclass)

    @classmethod
    def generateReqponse(self,queryData,ip):
        """
        only support ipv4
        """
        return ‘‘.join([queryData[:2],"\x81\x80\x00\x01\x00\x02\x00\x00\x00\x00",
          queryData[12:],"\xc0\x0c","\x00\x01","\x00\x01","\x00\x00\x00\x1e","\x00\x04",
          struct.pack(‘BBBB‘,*map(int,ip.split(‘.‘)))
          ])

class DnsServer(DatagramServer):
    def handle(self,data,address):
        query = DnsParser.parseQuery(data)
        print "get dns query from %s,query:%s" %(str(address),str(query))
        find = False
        for preg,ip in Hosts.iteritems():
            if preg_match(preg,query.qname):
                find = True
                break
        if find and query.qtype == "0x0001": #only handle A record
            print ‘domain:%s in hosts‘ % query.qname
            response = DnsParser.generateReqponse(data,ip)
            self.socket.sendto(response,address)
        else:
            print ‘transfer for %s‘ % query.qname
            response,serveraddress = udp_send(LOCALDNS,data)
            self.socket.sendto(response,address)

if __name__ == "__main__":
    DnsServer("192.168.9.178:53").serve_forever()

哈哈,刚好100行,不得不说python的强大。

来个截图:

功能有限,各位童鞋可以扩展,代码已经放到github,https://github.com/Skycrab/PyDnsProxy,有兴趣的童鞋一起完善。

[python网络编程]DNS服务器

时间: 2024-08-08 17:01:11

[python网络编程]DNS服务器的相关文章

[Python网络编程] DNS缓存解决方案

记得以前写爬虫的时候为了防止dns多次查询,是直接修改/etc/hosts文件的,最近看到一个优美的解决方案,修改后记录如下: import socket _dnscache={} def _setDNSCache(): """ Makes a cached version of socket._getaddrinfo to avoid subsequent DNS requests. """ def _getaddrinfo(*args, **

Python网络编程UDP服务器与客服端简单例子

[转载] https://blog.csdn.net/hu330459076/article/details/7868028 UDP服务器代码: #!/usr/bin/env python # -*- coding:UTF-8 -*- from socket import * from time import ctime HOST = '127.0.0.1' PORT = 21567 BUFSIZE = 1024 ADDR = (HOST,PORT) udpSerSock = socket(AF

python 网络编程(五)---DNS域名系统

1.域名系统定义 DNS计算机域名系统由域名服务器和域名解析器组成.通常输入的是网址就是一个域名. 2.域名查询 查询方式包括: 1)正向查询:由域名查找对应的IP(如:119.75.218.77">www.baidu.com->119.75.218.77 ) 2)反向查询:由IP查找域名(如:119.75.218.77 –> www.baidu.com) 查询方式包括: 1)递归查询:当DNS服务器接收到客户端的查询请求时,会做出相应的反应(本地DNS服务器查询.其他服务器查

Python网络编程02----基于UDP的Python简易服务器

UDP 服务器不是面向连接的,所以不用像 TCP 服务器那样做那么多设置工作.事实上,并不用设置什么东西,直接等待进来的连接就好了. ss = socket() # 创建一个服务器套接字 ss.bind() # 绑定服务器套接字 inf_loop: # 服务器无限循环 cs = ss.recvfrom()/ss.sendto() # 对话(接收与发送) ss.close() # 关闭服务器套接字 服务器端: from socket import * from time import ctime

Python 网络编程

Python 提供了两个级别访问的网络服务.: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的全部方法. 高级别的网络服务模块 SocketServer, 它提供了服务器中心类,可以简化网络服务器的开发. 什么是 Socket? Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯. socket()函数 Pyt

[python] 网络编程之套接字Socket、TCP和UDP通信实例

很早以前研究过C#和C++的网络通信,参考我的文章: C#网络编程之Tcp实现客户端和服务器聊天 C#网络编程之套接字编程基础知识 C#网络编程之使用Socket类Send.Receive方法的同步通讯 Python网络编程也类似.同时最近找工作笔试面试考察Socket套接字.TCP\UDP区别比较多,所以这篇文章主要精简了<Python核心编程(第二版)>第16章内容.内容包括:服务器和客户端架构.套接字Socket.TCP\UDP通信实例和常见笔试考题. 最后希望文章对你有所帮助,如果有不

Python 网络编程(一)

Python 网络编程 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者. socket和file的区别: file模块是针对某个指定文件进行[打开][读写][关闭] socket模块是针对 服务器端 和 客户端Socket 进行[打开][读写][关闭] socket服务端和客户端的网

Python 网络编程(二)

Python 网络编程 上一篇博客介绍了socket的基本概念以及实现了简单的TCP和UDP的客户端.服务器程序,本篇博客主要对socket编程进行更深入的讲解 一.简化版ssh实现 这是一个极其简单的仿ssh的socket程序,实现的功能为客户端发送命令,服务端接收到客户端的命令,然后在服务器上通过subrocess模块执行命令,如果命令执行有误,输出内容为空,则返回"command error"的语句给客户端,否则将命令执行的结果返回给客户端 服务端 1 2 3 4 5 6 7 8

《Python网络编程基础》笔记

主要是关于<Python网络编程笔记>这本书的笔记...可能有点乱... 总共包含6个部分.. 第一部分 第1章:客户/服务器网络介绍 未完待续.....