Fork me on GitHub

The WebDevil

Enjoy development

В PowerDNS есть пара плюшек, которые я раньше не замечал. Одну из них – записи “URL” я сегодня попробовал, настроил и остался вполне доволен.

Что же такое URL-запись? Это фича PowerDNS, при помощи которой можно делать редирект домена на заданный URL.
Например, запись выглядит как

some.domain.com URL http://other.domain.com/some_domain_com

На самом деле в поле со значением записи может быть ссылка куда угодно.
В конфиге сервера нужно указать

...
fancy-records=yes
urlredirector=77.120.99.180
...

Когда приходит запрос к DNS’у для домена some.domain.com отдается 77.120.99.180, указанный в конфиге, как если бы это была обычная “А”-запись.
Браузер отрезолвив имя идет на http://some.domain.com. На этом адресе висит http-сервер (я повесил lighttpd), у которого скрипт лезет в БД и для указанного домена ищет соответствующую ему URL-запись и редиректит браузер туда. Все просто и тривиально.

Для lighttpd у меня конфиг дополнился такими строками:

$SERVER["socket"] == "77.120.99.180:80" {
    $HTTP["host"] =~ "(.*)" {
        magnet.attract-raw-url-to = ("/var/www/lighttpd/pdns-url-redirector.lua")
    }
}

То есть все что приходит незамедлительно обрабатывается упомянутым lua-скриптом. Почему lua? С ним работает mod_magnet, и мне было интересно написать этот скриптик. Вот он:

require "luasql.mysql"
env = assert (luasql.mysql())
con = assert (env:connect("dnsdb", "dns_user", "dns_pass_for_readonly_records_table", "localhost"))
domain = lighty.request["Host"]

mysql_replacements = {
  ["\0"] = "\\0",
  ["\n"] = "\\n",
  ["\r"] = "\\r",
  ["\'"] = "\\'",
  ["\""] = "\\\"",
  ["\026"] = "\\Z",
  ["\b"] = "\\b",
  ["\t"] = "\\t",
}

function fixsql (s)
  return (string.gsub (tostring (s), "[%z\n\r\'\"\026\b\t]",
    function (str)
        return mysql_replacements [str] or str
    end ))
end -- fixsql

cur = assert (con:execute( string.format("SELECT content FROM records WHERE `type` = 'URL' AND `name` = '%s'", fixsql(domain) ) ) )
result = cur:fetch()
if result then
    redirect_to = string.format("%s", result)
else
    redirect_to = "http://daemons.org.ua/"
end

cur:close()
con:close()
env:close()

--lighty.content = { string.format("SELECT content FROM records WHERE `type` = 'URL' AND `name` = '%s'", fixsql(domain) )  }
--lighty.header["Content-Type"] = "text/plain"
--return 200

lighty.header["Location"] = redirect_to
return 301

Комментарий начинается с “–”. Закоментарены строки для отладки скрипта.
Для соединения с мускулем из lua доставил пакет liblua5.1-sql-mysql-2.

Скрипт писал долго, но это было интересно. И небесполезно =)


UPD: во избежание DoS/DDoS атаки на мускуль возможны два варианта апгрейда метода:
1. По крону раз в 5 минут генерить sqlite-БД состоящую из одной таблицы из двух полей – domain, target
2. Раз в 5 минут генерить сам скрипт с вынесенными в него в виде хеша записями. Тогда скрипт вообще никуда подглядывать не будет.

One Response to “PowerDNS URL records and redirector”

  1. Для интереса заглянул(:)Что ж – неплохо весьма:)

    Олександр