DNS и Go
Перевод статьи "Go DNS package".
Пакет Go DNS реализует интерфейс для управления DNS с помощью Go. По сути, это либа которая позволяет делать и принимать DNS запросы. Весь код лицензируется так же как и код самого Go.
Основная цель создания этого инструмента - предоставить простой и мощный инструмент.
Что поддерживает эта библиотека:
- Все типы RR;
- Синхронные и асинхронные запросы и ответы:
- DNSSEC - валидация, подписи, генерация ключей, чтение файлов .private:
- (Скоро) отправка/получение/отображение пакетов и RR;
- Полный контроль в буквальном смысле:
- Перенос зон, EDNS0, TSIG, NSID;
- Возможности полноценного сервера имен:
- (Скоро) чтение зон/RR из файлов и строк:
Код
Сам код пакета находится на github.
Примеры использования пакета можно найти в специальном пакете, все на том же github.
Чуть больше о использовании
Вывод MX записей
Маленький лайвхак, как выводить MX записи используя Go DNS.
Попробуем написать простую программу, которая отображает MX записи для домена. Это будет выглядеть вот так:
% mx miek.nl
miek.nl. 86400 IN MX 10 elektron.atoom.net.
Или так:
% mx microsoft.com
microsoft.com. 3600 IN MX 10 mail.messaging.microsoft.com.
Начнем со списка используемых пакетов:
package main
import (
"os"
"net"
"fmt"
"log"
"github.com/miekg/dns"
)
Теперь мы можем создать небольшой локальный сервер имен:
config, _ := dns.ClientConfigFromFile("/etc/resolv.conf")
Теперь создадим клиент dns.Client
для выполнения наших запросов:
c := new(dns.Client)
В этом примере мы пропустили обработку ошибок и считаем, что зона уже указана. Для продолжения нам нужно еще несколько вещей:
- создать пакет экземпляр пакета(
(dns.Msg)
); - установить некоторые заголовочные биты;
- указать секцию запроса;
- заполнить секцию запроса: считаем, что в
os.Args[1]
содержится имя зоны:
В итоге получится вот так:
m := new(dns.Msg)
m.SetQuestion(dns.Fqdn(os.Args[1]), dns.TypeMX)
m.RecursionDesired = true
В конце всего мы должны выполнить наш запрос. Для этого нужно вызвать метод Exchange()
. Пропущенное возвращенное значение - это rtt (round trip time).
r, _, err := c.Exchange(m, net.JoinHostPort(config.Servers[0], config.Port))
Ниже представлен кусок кода, который выводит в консоль ответ от сервера. В случае ошибки просто прерываем выполнение:
if r == nil {
log.Fatalf("*** error: %s\n", err.Error())
}
if r.Rcode != dns.RcodeSuccess {
log.Fatalf(" *** invalid answer name %s after MX query for %s\n", os.Args[1], os.Args[1])
}
// Весь результат должен быть в поле Answer
for _, a := range r.Answer {
fmt.Printf("%v\n", a)
}
И на этом, собственно, все. Полный код примера:
package main
import (
"net"
"os"
"log"
"fmt"
"github.com/miekg/dns"
)
func main() {
config, _ := dns.ClientConfigFromFile("/etc/resolv.conf")
c := new(dns.Client)
m := new(dns.Msg)
m.SetQuestion(dns.Fqdn(os.Args[1]), dns.TypeMX)
m.RecursionDesired = true
r, _, err := c.Exchange(m,
net.JoinHostPort(config.Servers[0], config.Port))
if r == nil {
log.Fatalf("*** error: %s\n", err.Error())
}
if r.Rcode != dns.RcodeSuccess {
log.Fatalf(" *** invalid answer name %s after MX query for %s\n",
os.Args[1], os.Args[1])
}
// Весь результат должен быть в поле Answer
for _, a := range r.Answer {
fmt.Printf("%v\n", a)
}
}