Скрипт для извлечения исходных доменов из файла зоны DNS не пропускает строки с пробелами в начале - PullRequest
1 голос
/ 16 апреля 2019

Я хочу санировать наш файл зоны DNS, чтобы извлечь исходные домены, содержащие только записи CNAME и A, и удалить все комментарии, записи TXT, MX и SRV. Самое главное, я бы хотел автоматизировать этот процесс.

Мне удалось создать RegEx, который можно использовать для поиска и замены в возвышенном тексте, и для достижения требуемого результата требуется несколько итераций.

Давайте возьмем следующий пример файла зоны DNS в качестве примера:

$ORIGIN example.com.
@                      3600 SOA   ns1.p30.dynect.net. (
                              zone-admin.dyndns.com.     ; address of responsible party
                              2016072701                 ; serial number
                      86400 IN  NS  ns1.p30.dynect.net.
                       3600 IN  MX  10 mail.example.com.
                         60 IN  A   204.13.248.106
abc                        TXT      "v=spf1 includespf.dynect.net ~all"
mail                        IN  A        204.13.248.106
vpn                         IN  TXT    v=spf1 includespf.dynect.net ~all"
vpn2                      IN  MX     v=spf1 includespf.dynect.net ~all"
webapp                      IN  A        216.146.46.10
#webapp1                  IN  A       216.146.46.10
xyz                         IN  CNAME     example.com.
webapp                      IN  SRV     216.146.46.11
;webapp2                  IN    A         216.146.46.11

Шаг 1

Используйте это для "Найти"

(^;.*)|(^#.*)|(^\$.*)|(^@.*)|(.*IN\h+MX.*)|(.*IN\h+TXT.*)|(.*IN\h+SRV.*)|(.*IN\h+NS.*)|(.*\h+TXT.*)|(\h.+)|(^[\n\r\h]+)

и заменить ничем.

Это очистит файл Zone и отобразит только исходные домены, которые указывают на записи CNAME и A.

Шаг 2

Используйте следующее для «Найти»

(.+$)

и замените его на

\1.example.com

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

mail.example.com
webapp.example.com
xyz.example.com


Сейчас я пытаюсь написать скрипт Python, который выполняет вышеуказанное для данного файла зоны и выводит его в файл .txt.

Wiktor Stribiżew , бог RegEx и Python здесь, в Stack Overflow, помог мне написать следующее:

import re

regex = re.compile(r'^(?:\s+|[;#$@].*)|.*IN\s+(?:MX|TXT|SRV|NS).*|.*\s+TXT.*|\s.+')
with open('1.txt', 'r',encoding='UTF8') as dns:
    with open('2.txt', 'w',encoding='UTF8') as output:
        for line in dns:
            if line.strip():
                line = regex.sub('', line.strip())
                if line:
                    output.write("{}.example.com\n".format(line))

К сожалению, вывод для скрипта такой:

zone-admin.dyndns.com..example.com
2016072701.example.com
60.example.com
mail.example.com
webapp.example.com
xyz.example.com

Скрипт не пропускает строки, начинающиеся с пробела. Что я делаю не так?

1 Ответ

2 голосов
/ 17 апреля 2019

Похоже, у вас есть две ошибки, каждая из которых приведет к неправильному использованию строк, начинающихся с пробела.


Первая ошибка в утверждении

line = regex.sub('', line.strip())

, который удаляет все начальные пробелы до , передавая строку методу sub(). Таким образом, регулярное выражение никогда не видит никаких строк, начинающихся с пробела.

Чтобы исправить это, необходимо вызвать метод strip() после того, как вызван метод sub():

line = regex.sub('', line).strip()

Обратите внимание, что вся причина strip() заключается в том, что завершающие символы новой строки удаляются, устанавливая line в пустую строку для строк, которые следует игнорировать. Для этого можно использовать простой тест, поскольку пустые строки являются ложными.

В качестве альтернативы этот вызов может быть опущен, и вместо этого регулярное выражение может быть изменено для удаления новых строк. (Это можно сделать, заменив все «конечные» .* на [\s\S]*.)


Вторая ошибка в вашем регулярном выражении, которое просто совпадает с первой частью пробела в строке, а не со всей строкой. Это приводит к тому, что метод sub() существенно удаляет начальные пробелы!
Демо 1 ? 1

regex = re.compile(r'^(?:\s+|[;#$@].*)|.*IN\s+(?:MX|TXT|SRV|NS).*|.*\s+TXT.*|\s.+')
                         ↑_↑
                          |
  only matches the leading white-space part, not the whole line


Быстрое решение состоит в том, чтобы продвинуться вперед закрывающей скобки не захватывающей группы:
Демо 2 ? 1

regex = re.compile(r'^(?:\s+|[;#$@]).*|.*IN\s+(?:MX|TXT|SRV|NS).*|.*\s+TXT.*|\s.+')
                                   ↑ ↓
                                    ←


Обратите внимание, что более простое регулярное выражение можно создать, осознав, что метасимвол пробела \s может быть перемещен внутри класса символов, и что нам нужно проверить только первый символ строки:
Демо 3 ? 1

regex = re.compile(r'^[\s;#$@].*|.*IN\s+(?:MX|TXT|SRV|NS).*|.*\s+TXT.*|\s.+')


Наконец, дальнейшее упрощение может быть достигнуто путем сопоставления каждой строки без пробелов, которая не является лидирующим пробелом и которая не указывает на запись CNAME или A, с использованием отрицательного взгляда, а не путем явного и исчерпывающего сопоставления. строки, которые указывают на записи не-CNAME / не-A:
Демо 4 ? 1

regex = re.compile(r'^(?:[\s;#$@]|(?!.*IN\s+[AC])).*|\s.+')

Или, если вы предпочитаете меньше вложенности (плюс на один символ короче ;-)):
Демо 5 ? 1

regex = re.compile(r'^[\s;#$@].*|^(?!.*IN\s+[AC]).*|\s.+')


Это полная рабочая версия вашего кода с использованием последнего регулярного выражения:

import re

regex = re.compile(r'^[\s;#$@].*|^(?!.*IN\s+[AC]).*|\s.+')
with open('1.txt', 'r',encoding='UTF8') as dns:
    with open('2.txt', 'w',encoding='UTF8') as output:
        for line in dns:
            if line.strip():
                line = regex.sub('', line).strip()
                if line:
                    output.write("{}.example.com\n".format(line))

1 Все демонстрационные регулярные выражения были подправлены (последний метасимвол пробела \s был заменен пробелом), чтобы можно было использовать многострочный флаг для отображения все полученные строки с выполненными заменами (в поле «ЗАМЕНА»). Это не влияет на функциональность регулярных выражений, так как тестовая строка содержит только пробелы и символы новой строки и никаких других пробелов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...