Moduli ya sera ya DNS (v2)
Mfano huu wa Linux C ABI v2 unaonyesha kudhibiti maswali na kubadilisha majibu ya DNS.
Hutumia libresolv kuchanganua ujumbe na kuhifadhi majibu yaliyobadilishwa katika bafa inayomilikiwa na moduli.
Tabia ya mfano
| Jina la swali | Matokeo |
|---|---|
allow.test | Humaliza mnyororo wa hook za maswali na kuendelea na utafutaji wa kawaida. |
block.test | Hurudisha REFUSED bila kuuliza seva ya juu. |
drop.test | Hutupa swali bila kuuliza seva ya juu au kutoa jibu. |
redirect.test | Hurudisha 192.0.2.42 kwa A na 2001:db8::42 kwa AAAA, kwa TTL ya sekunde 60. |
rewrite.test | Hubadilisha anwani ya rekodi A ya jibu lisilosainiwa kuwa 203.0.113.7 na TTL kuwa sekunde 60. |
| Majina mengine | Huendelea kwa moduli inayofuata na uchakataji wa kawaida. |
Sanidi seva ya majaribio itoe majibu kwa allow.test na rewrite.test.
Mfano hautengenezi rekodi za juu. Jibu la rewrite.test lisipokuwa na rekodi A inayolingana
au likiwa na rekodi za sahihi, hurudishwa bila kubadilishwa.
ALLOW humaliza mnyororo wa sasa tu. Haikwepi kanuni za vikoa au ukaguzi wa njia,
na matokeo yanaweza kubadilika kwenye hook ya majibu.
Soma kanuni za vitendo vya DNS.
Kupakua na kujenga
Pakua policy.c na mudfish_dns_module.h katika saraka moja. Unaweza kusoma header kamili katika kivinjari kwenye mwongozo wa header.
Katika Linux, sakinisha kompaila ya C na header za ukuzaji za maktaba ya kawaida ya C na libresolv.
Katika saraka uliyopakua, endesha:
cc -std=c11 -shared -fPIC -Wall -Wextra -Werror -I. \
policy.c -lresolv -o policy.so
Sakinisha policy.so kulingana na Kupakia moduli, kisha anzisha huduma upya.
Anzisha DNS katika programu kabla ya kujaribu maswali.
Kwa jaribio la ndani linalotumia anwani ya msingi ya kusikiliza DNS, maswali haya
hukagua kuzuia na kutengeneza majibu. dig lazima iwe imesakinishwa.
dig @127.0.0.1 block.test A
dig @127.0.0.1 redirect.test A
dig @127.0.0.1 redirect.test AAAA
Swali la kwanza lirudishe REFUSED; mengine mawili yarudishe anwani katika jedwali.
Ukibadilisha anwani au port ya kusikiliza, rekebisha amri ipasavyo.
drop.test kwa makusudi haitumi jibu, hivyo itafikia muda wa kusubiri.
Jinsi inavyofanya kazi
Callback za swali na jibu hurudisha 0 zikifanikiwa, na huweka kitendo katika result->action.
Hazirudishi konstanti za vitendo moja kwa moja.
Wakati wa uanzishaji, moduli hutenga bafa ya majibu katika context yake.
Hook ya majibu hunakili jibu lililoazimwa humo kabla ya kulibadilisha, na destroy() huachilia context.
Kwa kanuni za umiliki wa bafa,
bafa mbadala hubaki halali hata baada ya callback kurudi.
Hook haibadilishi ujumbe uliosainiwa. Haithibitishi wala kusaini upya DNSSEC. Majibu yaliyotengenezwa au kubadilishwa hayahifadhiwi kwenye akiba ya host.
Msimbo kamili
#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);
}