/* Copyright (C) CZ.NIC, z.s.p.o. * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "kresconfig.h" #include "lib/defines.h" #include "lib/utils.h" /** Layer processing states. Only one value at a time (but see TODO). * * Each state represents the state machine transition, * and determines readiness for the next action. * See struct kr_layer_api for the actions. * * TODO: the cookie module sometimes sets (_FAIL | _DONE) on purpose (!) */ enum kr_layer_state { KR_STATE_CONSUME = 1 << 0, /*!< Consume data. */ KR_STATE_PRODUCE = 1 << 1, /*!< Produce data. */ /*! Finished successfully or a special case: in CONSUME phase this can * be used (by iterator) to do a transition to PRODUCE phase again, * in which case the packet wasn't accepted for some reason. */ KR_STATE_DONE = 1 << 2, KR_STATE_FAIL = 1 << 3, /*!< Error. */ KR_STATE_YIELD = 1 << 4, /*!< Paused, waiting for a sub-query. */ }; /** Check that a kr_layer_state makes sense. We're not very strict ATM. */ static inline bool kr_state_consistent(enum kr_layer_state s) { #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" #pragma clang diagnostic ignored "-Wtautological-unsigned-enum-zero-compare" #endif return s >= 0 && s < (1 << 5); #ifdef __clang__ #pragma clang diagnostic pop #endif } /* Forward declarations. */ struct kr_layer_api; /** Packet processing context. */ typedef struct kr_layer { int state; /*!< The current state; bitmap of enum kr_layer_state. */ struct kr_request *req; /*!< The corresponding request. */ const struct kr_layer_api *api; knot_pkt_t *pkt; /*!< In glue for lua kr_layer_api it's used to pass the parameter. */ struct sockaddr *dst; /*!< In glue for checkout layer it's used to pass the parameter. */ bool is_stream; /*!< In glue for checkout layer it's used to pass the parameter. */ } kr_layer_t; /** Packet processing module API. All functions return the new kr_layer_state. * * Lua modules are allowed to return nil/nothing, meaning the state shall not change. */ struct kr_layer_api { /** Start of processing the DNS request. */ int (*begin)(kr_layer_t *ctx); int (*reset)(kr_layer_t *ctx); /** Paired to begin, called both on successes and failures. */ int (*finish)(kr_layer_t *ctx); /** Process an answer from upstream or from cache. * Lua API: call is omitted iff (state & KR_STATE_FAIL). */ int (*consume)(kr_layer_t *ctx, knot_pkt_t *pkt); /** Produce either an answer to the request or a query for upstream (or fail). * Lua API: call is omitted iff (state & KR_STATE_FAIL). */ int (*produce)(kr_layer_t *ctx, knot_pkt_t *pkt); /** Finalises the outbound query packet with the knowledge of the IP addresses. * The checkout layer doesn't persist the state, so canceled subrequests * don't affect the resolution or rest of the processing. * Lua API: call is omitted iff (state & KR_STATE_FAIL). */ int (*checkout)(kr_layer_t *ctx, knot_pkt_t *packet, struct sockaddr *dst, int type); /** Finalises the answer. * Last chance to affect what will get into the answer, including EDNS. * Not called if the packet is being dropped. */ int (*answer_finalize)(kr_layer_t *ctx); /** The C module can store anything in here. */ void *data; /** Internal to ./daemon/ffimodule.c. */ int cb_slots[]; }; typedef struct kr_layer_api kr_layer_api_t; /** Pickled layer state (api, input, state). */ struct kr_layer_pickle { struct kr_layer_pickle *next; const struct kr_layer_api *api; knot_pkt_t *pkt; unsigned state; };