DNS siyasəti modulu (v2)
Bu Linux C ABI v2 nümunəsi DNS sorğularını idarə etməyi və DNS cavablarını əvəzləməyi
göstərir. DNS mesajlarını libresolv ilə təhlil edir və dəyişdirilmiş cavabı modulun
sahib olduğu buferdə saxlayır.
Nümunənin davranışı
| Sorğu adı | Nəticə |
|---|---|
allow.test | Sorğu hook zəncirini bitirir və adi DNS sorğusunu davam etdirir. |
block.test | Yuxarı serverə sorğu göndərmədən REFUSED qaytarır. |
drop.test | Yuxarı serverə sorğu göndərmədən və DNS cavabı vermədən sorğunu atır. |
redirect.test | A sorğusuna 192.0.2.42, AAAA sorğusuna 2001:db8::42 ünvanını 60 saniyə TTL ilə qaytarır. |
rewrite.test | İmzalanmamış cavabın A qeydinin ünvanını 203.0.113.7 edir və TTL-i 60 saniyəyə təyin edir. |
| Digər adlar | Növbəti modulla və adi emalla davam edir. |
Sınaq DNS serverini allow.test və rewrite.test adları üçün cavab verəcək şəkildə
sazlayın. Nümunə yuxarı serverdə qeydlər yaratmır. rewrite.test cavabında uyğun A
qeydi yoxdursa və ya imza qeydi varsa, cavab dəyişdirilmədən qaytarılır.
ALLOW yalnız cari hook zəncirini bitirir. Domen qaydalarını və ya rabitə üsulu
yoxlamalarını keçmir; cavab hook funksiyası da nəticəni dəyişə bilər.
DNS əməliyyatı qaydalarına baxın.
Endirmə və yığma
policy.c və mudfish_dns_module.h fayllarını eyni qovluğa endirin. Başlıq faylı təlimatında tam başlıq faylını brauzerdə oxuya bilərsiniz.
Linux-da C kompilyatorunu, standart C kitabxanasının və libresolv kitabxanasının
hazırlama üçün başlıq fayllarını quraşdırın. Faylları endirdiyiniz qovluqda aşağıdakı
əmri icra edin.
cc -std=c11 -shared -fPIC -Wall -Wextra -Werror -I. \
policy.c -lresolv -o policy.so
Modul yükləmək təlimatına uyğun olaraq policy.so
faylını quraşdırın və xidməti yenidən başladın. Sorğuları sınamazdan əvvəl tətbiqdə
DNS-i başladın.
Standart DNS dinləmə ünvanı ilə yerli sınaqda aşağıdakı sorğularla bloklamanı və
ünvan cavablarının yaradılmasını yoxlaya bilərsiniz. dig quraşdırılmış olmalıdır.
dig @127.0.0.1 block.test A
dig @127.0.0.1 redirect.test A
dig @127.0.0.1 redirect.test AAAA
İlk sorğu REFUSED, digər iki sorğu isə cədvəldə göstərilən ünvanları qaytarmalıdır.
Dinləmə ünvanını və ya portunu dəyişmisinizsə, əmrləri də uyğunlaşdırın.
drop.test sorğusuna qəsdən cavab göndərilmədiyinə görə gözləmə müddəti bitir.
İş prinsipi
Sorğu və cavab geri çağırışları uğur zamanı 0 qaytarır, əməliyyat isə
result->action sahəsində təyin edilir. Əməliyyat sabitləri birbaşa qaytarılmır.
Başlanğıc sazlanması zamanı modul kontekstində cavab buferi ayrılır. Cavab hook
funksiyası götürülmüş cavabı bu buferə köçürüb dəyişir, destroy() isə konteksti
azad edir. Bufer sahibliyi qaydalarına
uyğun olaraq geri çağırış qayıtdıqdan sonra da əvəzləyici bufer etibarlı qalır.
Cavab hook funksiyası imzalanmış mesajları dəyişmir. DNSSEC məlumatlarını yoxlamır və yenidən imzalamır. Yaradılmış və ya əvəzlənmiş cavablar hostun keşində saxlanmır.
Tam mənbə kodu
#include "mudfish_dns_module.h"
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
struct policy {
uint8_t response[65535];
};
static int
question(const struct mudfish_dns_event *event, ns_rr *rr)
{
ns_msg message;
if (event->query.len > 65535 ||
ns_initparse(event->query.data, (int)event->query.len, &message) < 0)
return (-1);
return (ns_parserr(&message, ns_s_qd, 0, rr));
}
static int32_t
dns_query(void *context, const struct mudfish_dns_event *event,
struct mudfish_dns_result *result)
{
ns_rr rr;
(void)context;
if (question(event, &rr) < 0)
return (-1);
if (strcasecmp(ns_rr_name(rr), "allow.test") == 0)
result->action = MUDFISH_DNS_ALLOW;
else if (strcasecmp(ns_rr_name(rr), "block.test") == 0)
result->action = MUDFISH_DNS_BLOCK;
else if (strcasecmp(ns_rr_name(rr), "drop.test") == 0)
result->action = MUDFISH_DNS_DROP;
else if (strcasecmp(ns_rr_name(rr), "redirect.test") == 0) {
result->action = MUDFISH_DNS_ANSWER;
result->ttl = 60;
if (ns_rr_type(rr) == ns_t_aaaa) {
result->address_family = MUDFISH_DNS_IPV6;
inet_pton(AF_INET6, "2001:db8::42", result->address);
} else {
result->address_family = MUDFISH_DNS_IPV4;
inet_pton(AF_INET, "192.0.2.42", result->address);
}
}
return (0);
}
static int32_t
dns_response(void *context, const struct mudfish_dns_event *event,
struct mudfish_dns_result *result)
{
struct policy *policy = context;
ns_msg message;
ns_rr rr;
uint8_t *rdata;
int section, i, changed = 0;
if (question(event, &rr) < 0)
return (-1);
if (strcasecmp(ns_rr_name(rr), "rewrite.test") != 0)
return (0);
if (event->response.len > sizeof(policy->response))
return (-1);
memcpy(policy->response, event->response.data, event->response.len);
if (ns_initparse(policy->response, (int)event->response.len, &message) < 0)
return (-1);
/* This example only edits unsigned answers. A policy that edits signed
* data must also rebuild/remove the affected signatures.
*/
for (section = ns_s_an; section <= ns_s_ar; section++) {
for (i = 0; i < ns_msg_count(message, section); i++) {
if (ns_parserr(&message, (ns_sect)section, i, &rr) < 0)
return (-1);
if (ns_rr_type(rr) == ns_t_rrsig || ns_rr_type(rr) == ns_t_sig ||
ns_rr_type(rr) == ns_t_tsig)
return (0);
}
}
for (i = 0; i < ns_msg_count(message, ns_s_an); i++) {
if (ns_parserr(&message, ns_s_an, i, &rr) < 0)
return (-1);
if (ns_rr_class(rr) != ns_c_in || ns_rr_type(rr) != ns_t_a ||
ns_rr_rdlen(rr) != 4)
continue;
/* rdata belongs to our copy. TTL precedes RDLENGTH (2 bytes). */
rdata = policy->response + (ns_rr_rdata(rr) - policy->response);
inet_pton(AF_INET, "203.0.113.7", rdata);
ns_put32(60, rdata - 6);
changed = 1;
}
if (changed) {
result->action = MUDFISH_DNS_REPLACE;
result->response.data = policy->response;
result->response.len = event->response.len;
}
return (0);
}
static void
destroy(void *context)
{
free(context);
}
int32_t
mudfish_dns_module_init_v2(uint32_t abi_version, size_t module_size,
struct mudfish_dns_module_v2 *module)
{
if (abi_version != MUDFISH_DNS_MODULE_ABI_V2 || module_size != sizeof(*module))
return (-1);
module->context = calloc(1, sizeof(struct policy));
if (module->context == NULL)
return (-1);
module->on_dns_query = dns_query;
module->on_dns_response = dns_response;
module->destroy = destroy;
return (0);
}