TXT-записи в dnsPython - PullRequest
       68

TXT-записи в dnsPython

3 голосов
/ 24 июля 2010

Я реализовал простой DNS-сервер. Он просто отвечает записью TXT. Я принимаю скрипт в качестве сервера NS для example.com. Сервер NS - это x.y.z.k. Это работает нормально, когда я выдаю что-то вроде:

$ dig demo.example.com @x.y.z.k

; <<>> DiG 9.3.6-P1-RedHat-9.3.6-4.P1.el5_4.1 <<>> demo.example.com @x.y.z.k
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10028
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 2

;; QUESTION SECTION:
;demo.example.com. IN A

;; ANSWER SECTION:
demo.example.com. 1000 IN TXT "test message"

но это не работает, когда я задаю тот же вопрос от одного из общедоступные серверы имен (например, DNS Sun в 4.2.2.1):

$ dig demo.example.com @4.2.2.1 (я получаю то же самое при выдаче $ dig demo.example.com @4.2.2.1 TXT)

; <<>> DiG 9.3.6-P1-RedHat-9.3.6-4.P1.el5_4.1 <<>> demo.example.com
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 10905
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;demo.example.com. IN A

;; Query time: 5837 msec
;; SERVER: 172.16.1.1#53(172.16.1.1)
;; WHEN: Tue Jul 20 04:01:27 2010
;; MSG SIZE  rcvd: 75

Ребята, вы понимаете, что не так? Интересно, если я изменюсь тип ответа на что-то вроде CNAME, а не TXT, работает нормально.

def dns_respond(resp, q, data_type):
    rrset = dns.rrset.from_text(q.name, 1000,
           dns.rdataclass.IN, dns.rdatatype.TXT, 'test message')
    resp.answer.append(rrset)
    return resp

def dns_ok(resp, q, data = None, msg = ''):
    return dns_respond(resp = resp, q = q, data_type = 'OK')

def dns_error(resp, q):
    return dns_respond(resp = resp, q = q, data_type = 'Error')

def requestHandler(address, message):
    resp = None
    message_id = ord(message[0]) * 256 + ord(message[1])
    logging.debug('msg id = ' + str(message_id))
    if message_id in serving_ids:
        # the request is already taken, drop this message
        logging.debug('I am already serving this request.')
        return
    serving_ids.append(message_id)
    msg = dns.message.from_wire(message)
    op = msg.opcode()
    if op == 0:
        # standard and inverse query
        qs = msg.question
        if len(qs) > 0:
            q = qs[0]
            logging.debug('request is ' + str(q))
            if q.rdtype == dns.rdatatype.A:
                resp = std_qry(msg)
            else:
                # not implemented
                #resp = std_qry(msg)
                resp = make_response(qry=msg, RCODE=4)   
    else:
        # not implemented
        resp = make_response(qry=msg, RCODE=4)   

    if resp:
        s.sendto(resp.to_wire(), address)

def std_qry(msg):
    qs = msg.question
    logging.debug(str(len(qs)) + ' questions.')

    answers = []
    nxdomain = False
    for q in qs:
        resp = make_response(qry=msg)
        logging.critical('Sending...')
        return dns_ok(resp, q)

def make_response(qry=None, id=None, RCODE=0):
    if qry is None and id is None:
        raise Exception, 'bad use of make_response'
    if qry is None:
        resp = dns.message.Message(id)
        # QR = 1
        resp.flags |= dns.flags.QR
        if RCODE != 1:
            raise Exception, 'bad use of make_response'
    else:
        resp = dns.message.make_response(qry)
    #resp.flags |= dns.flags.AA
    resp.flags |= dns.flags.RA
    resp.set_rcode(RCODE)
    return resp
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', 53))
logging.debug('binded to UDP port 53.')
serving_ids = []

while True:
    logging.debug('waiting requests.')
    message, address = s.recvfrom(1024)
    logging.debug('serving a request.')
    requestHandler(address, message)

1 Ответ

3 голосов
/ 24 июля 2010

Я вижу несколько реальных ошибок, которые мешают этой работе:

  1. Вы возвращаете запись TXT в запрос записи A - это, вероятно, ограничитель показа.
  2. Вы должны вернуть флаг AA (достоверный ответ) вместо RA
  3. Ваши заголовки говорят, что есть два ответа в разделе полномочий и дополнительных разделах, но их нет
  4. Вы не удаляете обслуживаемые идентификаторы из списка после того, как они действительно были обслужены

Кроме того, существует несколько проблем, связанных с протоколом, которые необходимо устранить:

  1. Вы должны иметь возможность возвращать NS записей и SOA записей при запросе, иначе ваша делегация может работать ненадежно
  2. При сопоставлении запросов следует использовать целое (исходный IP, исходный порт, queryID) учитывается, а не только (queryID)
  3. Если имя вопроса находится в правильном домене, но не в правильном поддомене, вы должны вернуть NXDOMAIN (rcode = 3)
  4. Еслиназвание вопроса соответствует правильному поддомену буt неправильный тип записи, вы должны вернуть NOERROR (rcode = 0) вместо NOTIMPL
  5. Если имя вопроса вообще не является частью правильного домена, вы должны вернуть REFUSED (rcode= 5)
...