Liigu põhisisu juurde

DNS-poliitika moodul (v2)

See Linuxi C ABI v2 näide näitab DNS-päringute juhtimist ja DNS-vastuste asendamist. DNS-teateid parsitakse teegiga libresolv ning muudetud vastused salvestatakse mooduli omandis olevasse puhvrisse.

Näite käitumine​

Päringu nimiTulemus
allow.testLõpetab päringuhaakide ahela ja jätkab tavalist DNS-päringut.
block.testTagastab REFUSED ülesvoolu serverilt pärimata.
drop.testHülgab päringu ülesvoolu päringut tegemata ja DNS-vastust saatmata.
redirect.testTagastab A-päringule 192.0.2.42 ja AAAA-päringule 2001:db8::42, TTL-iga 60 sekundit.
rewrite.testMuudab allkirjastamata vastuse A-kirje aadressiks 203.0.113.7 ja TTL-iks 60 sekundit.
Muud nimedJätkab järgmise mooduli ja tavapärase töötlusega.

Seadistage testimiseks kasutatav DNS-server pakkuma nimede allow.test ja rewrite.test vastuseid. Näide ei loo ülesvoolu kirjeid. Kui rewrite.test vastuses pole sobivat A-kirjet või selles on allkirjakirje, tagastatakse vastus muutmata.

ALLOW lõpetab ainult praeguse haagiahela. See ei lähe mööda domeenireeglitest ega ühendusviisi kontrollidest ning vastusehaak võib tulemust muuta. Vaadake DNS-toimingute reegleid.

Allalaadimine ja ehitamine​

Laadige policy.c ja mudfish_dns_module.h samasse kataloogi. Päise juhendis saate kogu päist brauseris lugeda.

Paigaldage Linuxis C-kompilaator ning standardse C-teegi ja libresolv arenduspäised. Käivitage allalaaditud failide kataloogis järgmine käsk.

cc -std=c11 -shared -fPIC -Wall -Wextra -Werror -I. \
policy.c -lresolv -o policy.so

Paigaldage policy.so mooduli laadimise juhiste järgi ja taaskäivitage teenus. Enne päringute testimist käivitage rakenduses DNS.

Vaikimisi DNS-i kuulamisaadressiga kohalikus testis saate blokeerimist ja aadressivastuste loomist kontrollida järgmiste päringutega. dig peab olema paigaldatud.

dig @127.0.0.1 block.test A
dig @127.0.0.1 redirect.test A
dig @127.0.0.1 redirect.test AAAA

Esimene päring peaks tagastama REFUSED, ülejäänud kaks tabelis toodud aadressid. Kui muutsite kuulamisaadressi või porti, kohandage vastavalt ka käske. drop.test päring aegub, sest sellele ei saadeta tahtlikult vastust.

Tööpõhimõte​

Päringu- ja vastusetagasikutsed tagastavad õnnestumisel 0 ning määravad toimingu väljal result->action. Toimingukonstanti otse ei tagastata.

Lähtestamisel eraldatakse mooduli konteksti vastusepuhver. Vastusehaak kopeerib laenatud vastuse sellesse puhvrisse ja muudab seda; destroy() vabastab konteksti. Puhvri omandi reeglite järgi jääb asenduspuhver kehtivaks ka pärast tagasikutse tagastamist.

Vastusehaak ei muuda allkirjastatud teateid ega kontrolli või allkirjasta DNSSEC-andmeid uuesti. Loodud või asendatud vastuseid hosti vahemällu ei salvestata.

Täielik lähtekood​

policy.c
#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);
}