Перейти к основному содержимому

mudfish_dns_module.h

Скачайте mudfish_dns_module.h и поместите его в один каталог с исходником модуля на C. Ниже приведён полный заголовочный файл Mudfish DNS, включая объявления совместимости. Для модулей из этого руководства используйте C ABI v2.

Раздел «Пример policy.c» содержит команды сборки и примеры работы DNS. Загрузку модулей, поведение хуков и правила владения буферами см. в разделе «Нативные модули».

Типы, используемые модулями v2​

ТипНазначение
mudfish_dns_spanУказатель и длина заимствованных входных данных либо заменяющего ответа, принадлежащего модулю. Строки не завершаются NUL.
mudfish_dns_eventСетевые данные DNS-запроса и ответа, источник ответа, исходный адрес назначения и состояние существующей политики доменов.
mudfish_dns_web_eventВеб-данные, Host/SNI, адрес назначения, протокол, направление и состояние существующей политики доменов. Данные HTTPS остаются зашифрованными.
mudfish_dns_resultДействие DNS и необязательные адреса ответа, TTL или заменяющий ответ.
mudfish_dns_module_v2Контекст модуля, необязательные обратные вызовы DNS и веб-обработки, обратный вызов очистки.

Экспортируйте mudfish_dns_module_init_v2() со следующей сигнатурой. Изначально хост задаёт всем полям модуля NULL. Перед записью полей проверьте версию ABI и размер структуры. Оставьте неиспользуемые хуки равными NULL и при успехе верните 0.

Если инициализация не удалась, самостоятельно освободите выделенные ресурсы. После успешной инициализации, когда модуль больше не нужен, хост один раз вызывает destroy() перед выгрузкой библиотеки. Здесь остановите потоки, принадлежащие модулю, и дождитесь их завершения.

Полный заголовочный файл​

mudfish_dns_module.h
#ifndef MUDFISH_DNS_MODULE_H
#define MUDFISH_DNS_MODULE_H

#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

#define MUDFISH_DNS_MODULE_ABI_V1 1
#define MUDFISH_DNS_MODULE_ABI_V2 2
#define MUDFISH_DNS_CONTINUE 0
#define MUDFISH_DNS_REJECT 1
#define MUDFISH_DNS_BLOCK MUDFISH_DNS_REJECT
#define MUDFISH_DNS_ALLOW 2
#define MUDFISH_DNS_DROP 3
#define MUDFISH_DNS_ANSWER 4
#define MUDFISH_DNS_REPLACE 5

#define MUDFISH_DNS_IPV4 4
#define MUDFISH_DNS_IPV6 6

#define MUDFISH_DNS_SOURCE_QUERY 0
#define MUDFISH_DNS_SOURCE_UPSTREAM 1
#define MUDFISH_DNS_SOURCE_CACHE 2
#define MUDFISH_DNS_SOURCE_ORIGINAL 3
#define MUDFISH_DNS_SOURCE_ERROR 4
#define MUDFISH_DNS_SOURCE_MODULE 5

#define MUDFISH_DNS_WEB_UNKNOWN 0
#define MUDFISH_DNS_WEB_HTTP 1
#define MUDFISH_DNS_WEB_HTTPS 2
#define MUDFISH_DNS_TO_SERVER 1
#define MUDFISH_DNS_TO_CLIENT 2

/* Input spans are borrowed for this callback only; strings are not NUL terminated.
* Empty spans have length zero and must not be dereferenced. Never mutate, free,
* or retain any host pointer. DNS messages use wire format without TCP framing.
*/
struct mudfish_dns_span {
const uint8_t *data;
size_t len;
};

struct mudfish_dns_event {
struct mudfish_dns_span query;
struct mudfish_dns_span response; /* Empty in on_dns_query. */
struct mudfish_dns_span original_destination; /* IP:port, empty for loopback. */
uint32_t source;
uint32_t applied; /* Existing domain policy selects protected resolution. */
};

struct mudfish_dns_web_event {
struct mudfish_dns_span data;
struct mudfish_dns_span hostname; /* Normalized Host/SNI, or empty. */
struct mudfish_dns_span destination; /* IP:port. */
uint32_t protocol;
uint32_t direction;
uint32_t applied; /* Existing domain policy selects web protection. */
};

/* Return CONTINUE or REJECT. Any other value fails the request/connection.
* Hooks run in load order and stop at the first non-CONTINUE result.
* Calls for one module instance are serialized, but may use different threads.
* Hooks must finish promptly, must not unwind/longjmp across the ABI, and must
* not call back into the host. HTTPS data is encrypted; no TLS termination.
*/
struct mudfish_dns_module_v1 {
void *context;
int32_t (*on_dns_query)(void *, const struct mudfish_dns_event *);
int32_t (*on_dns_response)(void *, const struct mudfish_dns_event *);
int32_t (*on_web_hello)(void *, const struct mudfish_dns_web_event *);
int32_t (*on_web_data)(void *, const struct mudfish_dns_web_event *);
void (*destroy)(void *);
};

/* Export this exact symbol. The host initializes all fields to NULL.
* Check abi_version and module_size before writing. NULL hooks are optional.
* The output pointer is valid only during init. Return zero on success.
* On failure, clean up your own resources; the host will not call destroy.
* On success, destroy runs once after all users finish, before dlclose. Any
* module-owned threads must stop/join in destroy. Module code runs with the
* service's privileges and must satisfy this contract, including constructors.
*/
int32_t mudfish_dns_module_init_v1(uint32_t abi_version, size_t module_size,
struct mudfish_dns_module_v1 *module);

/* DNS v2 hooks return zero on success, nonzero on error (SERVFAIL).
* The host zeroes result before each call. Set action to:
* CONTINUE: consult the next module, then use the existing resolution/response.
* ALLOW: stop this hook chain and use the existing resolution/response.
* BLOCK: stop this hook chain and return REFUSED.
* DROP: discard this query/response without sending any DNS response.
* ANSWER: replace the response with the IP below, without upstream resolution
* when used in on_dns_query. IPv4 produces A, IPv6 produces AAAA.
* Other question types/classes get empty NOERROR (including an address
* family mismatch); IN/ANY gets the selected address record.
* REPLACE: use result.response as the complete DNS wire response. Valid in
* either DNS hook. The ID, opcode and question must match the query.
* Unknown actions or invalid ANSWER address families fail with SERVFAIL.
* Query results except DROP still pass through the response hook chain.
* Response decisions are final and never invoke response hooks recursively.
* Synthetic/replaced responses are not stored in the host cache.
* The host clears AD on replacements; modules must remove stale DNSSEC records
* when modifying signed data. The host does not re-sign or validate DNSSEC.
* DROP leaves TCP open for subsequent queries, subject to the normal timeout.
* ALLOW does not change domain policy, upstream selection or transport checks.
* All v1 lifetime/threading rules apply; result is writable only during the
* callback and must not be retained. Web hooks retain v1 return semantics.
*/
struct mudfish_dns_result {
uint32_t action;
uint32_t ttl; /* ANSWER: seconds, zero is allowed. */
uint32_t address_family; /* ANSWER: MUDFISH_DNS_IPV4 or MUDFISH_DNS_IPV6. */
uint8_t address[16]; /* Network byte order; IPv4 uses the first 4 bytes. */
/* REPLACE: module-owned wire response (12..65535 bytes, no TCP framing).
* Must remain valid and unchanged until the next callback on this instance
* or destroy; do not return stack memory or an event's borrowed pointer.
* The host copies before unlocking the instance and never frees this span.
*/
struct mudfish_dns_span response;
};

struct mudfish_dns_module_v2 {
void *context;
int32_t (*on_dns_query)(void *, const struct mudfish_dns_event *,
struct mudfish_dns_result *);
int32_t (*on_dns_response)(void *, const struct mudfish_dns_event *,
struct mudfish_dns_result *);
int32_t (*on_web_hello)(void *, const struct mudfish_dns_web_event *);
int32_t (*on_web_data)(void *, const struct mudfish_dns_web_event *);
void (*destroy)(void *);
};

/* Same initialization contract as v1, with ABI_V2 and sizeof(module_v2).
* The host prefers v2 if exported, otherwise loads v1. A failed v2 init is fatal
* and does not fall back to v1. Existing v1 modules need no changes.
*/
int32_t mudfish_dns_module_init_v2(uint32_t abi_version, size_t module_size,
struct mudfish_dns_module_v2 *module);

#ifdef __cplusplus
}
#endif
#endif