diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/acl.c | 137 | ||||
-rw-r--r-- | src/common/descriptor.c | 49 | ||||
-rw-r--r-- | src/common/descriptor.h | 33 | ||||
-rw-r--r-- | src/common/errcode.c | 2 | ||||
-rw-r--r-- | src/common/errcode.h | 2 |
5 files changed, 147 insertions, 76 deletions
diff --git a/src/common/acl.c b/src/common/acl.c index 26d3847..fa20d62 100644 --- a/src/common/acl.c +++ b/src/common/acl.c @@ -19,88 +19,99 @@ #include <assert.h> #include <sys/types.h> #include <sys/socket.h> +#include <limits.h> #include "common/acl.h" +#include "libknot/util/endian.h" -static inline uint32_t acl_sa_ipv4(sockaddr_t *a) { +static inline uint32_t ipv4_chunk(sockaddr_t *a) +{ + /* Stored as big end first. */ return a->addr4.sin_addr.s_addr; } -static inline uint32_t acl_fill_mask32(short c) { - /*! \todo Consider optimizing using LUT. */ - assert(c >= 0 && c <= 32); - unsigned r = 0; - /*! This actually builds big-endian mask - * as we will match against addresses in - * network byte-order (big-endian). - * Otherwise it should be built from - * HO bit -> LO bit. - */ - for (char i = 0; i < c; ++i) { - r |= (1 << i); - } - return r; +static inline uint32_t ipv6_chunk(sockaddr_t *a, uint8_t idx) +{ + /* Is byte array, 4x 32bit value. */ + return ((uint32_t *)&a->addr6.sin6_addr)[idx]; } -static int acl_compare(void *k1, void *k2) +static inline uint32_t ip_chunk(sockaddr_t *a, uint8_t idx) { - sockaddr_t* a1 = (sockaddr_t *)k1; - sockaddr_t* a2 = (sockaddr_t *)k2; + if (sockaddr_family(a) == AF_INET) + return ipv4_chunk(a); - /* Check different length, IPv4 goes first. */ - int ldiff = a1->len - a2->len; - if (ldiff != 0) { - return ldiff < 0 ? -1 : 1; - } + return ipv6_chunk(a, idx); +} - /* Compare integers if IPv4. */ - if (sockaddr_family(a1) == AF_INET) { +/*! \brief Compare chunks using given mask. */ +static int cmp_chunk(sockaddr_t *a, sockaddr_t *b, uint8_t idx, uint32_t mask) +{ + const uint32_t c1 = ip_chunk(a, idx) & mask; + const uint32_t c2 = ip_chunk(b, idx) & mask; - /* Compute mask .*/ - uint32_t mask = acl_fill_mask32(a1->prefix); + if (c1 > c2) + return 1; + if (c1 < c2) + return -1; + return 0; +} - /* Compare address. */ - int cmp1 = (acl_sa_ipv4(a1) & mask); - int cmp2 = (acl_sa_ipv4(a2) & mask); - if (cmp1 > cmp2) return 1; - if (cmp1 < cmp2) return -1; - return 0; +/*! + * \brief Calculate bitmask for byte array from the MSB. + * + * \note i.e. 8 means top 8 bits set, 11111111000000000000000000000000 + * + * \param nbits number of bits set to 1 + * \return mask + */ +static uint32_t acl_fill_mask32(short nbits) +{ + assert(nbits >= 0 && nbits <= 32); + uint32_t r = 0; + for (char i = 0; i < nbits; ++i) { + r |= 1 << (31 - i); } - /* IPv6 matching. */ -#ifndef DISABLE_IPV6 - if (sockaddr_family(a1) == AF_INET6) { - - /* Get mask .*/ - short chunk = a1->prefix; - - /* Compare address by 32bit chunks. */ - uint32_t* a1p = (uint32_t *)(&a1->addr6.sin6_addr); - uint32_t* a2p = (uint32_t *)(&a2->addr6.sin6_addr); - - /* Mask 0 = 0 bits to compare from LO->HO (in big-endian). - * Mask 128 = 128 bits to compare. - */ - while (chunk > 0) { - uint32_t mask = 0xffffffff; - if ((size_t)chunk > sizeof(mask) << 3) { - chunk -= sizeof(mask) << 3; - } else { - mask = acl_fill_mask32(chunk); - chunk = 0; - } - - int cmp1 = (*(a1p++) & mask); - int cmp2 = (*(a2p++) & mask); - if (cmp1 > cmp2) return 1; - if (cmp1 < cmp2) return -1; + /* Make sure the mask is in network byte order. */ + return htonl(r); +} + +static int acl_compare(void *k1, void *k2) +{ + int ret = 0; + sockaddr_t* a1 = (sockaddr_t *)k1; + sockaddr_t* a2 = (sockaddr_t *)k2; + uint32_t mask = 0xffffffff; + short mask_bits = a1->prefix; + const short chunk_bits = sizeof(mask) * CHAR_BIT; + + /* Check different length, IPv4 goes first. */ + if (a1->len != a2->len) { + if (a1->len < a2->len) + return -1; + else + return 1; + } + + /* At most 4xchunk_bits for IPv6 */ + unsigned i = 0; + while (ret == 0 && mask_bits > 0) { + /* Compute mask for current chunk. */ + if (mask_bits <= chunk_bits) { + mask = acl_fill_mask32(mask_bits); + mask_bits = 0; /* Last chunk */ + } else { + mask_bits -= chunk_bits; } - return 0; + /* Empty mask - shortcut, we're done. */ + if (mask > 0) + ret = cmp_chunk(a1, a2, i, mask); + ++i; } -#endif - return 0; + return ret; } acl_t *acl_new(acl_rule_t default_rule, const char *name) diff --git a/src/common/descriptor.c b/src/common/descriptor.c index 233a995..5f2af94 100644 --- a/src/common/descriptor.c +++ b/src/common/descriptor.c @@ -76,12 +76,12 @@ static const rdata_descriptor_t rdata_descriptors[] = { KNOT_RDATA_WF_END }, "KEY" }, [KNOT_RRTYPE_AAAA] = { { 16, KNOT_RDATA_WF_END }, "AAAA" }, [KNOT_RRTYPE_LOC] = { { 16, KNOT_RDATA_WF_END }, "LOC" }, - [KNOT_RRTYPE_SRV] = { { 6, KNOT_RDATA_WF_UNCOMPRESSED_DNAME, + [KNOT_RRTYPE_SRV] = { { 6, KNOT_RDATA_WF_COMPRESSED_DNAME, KNOT_RDATA_WF_END }, "SRV" }, [KNOT_RRTYPE_NAPTR] = { { KNOT_RDATA_WF_NAPTR_HEADER, - KNOT_RDATA_WF_UNCOMPRESSED_DNAME, + KNOT_RDATA_WF_COMPRESSED_DNAME, KNOT_RDATA_WF_END }, "NAPTR" }, - [KNOT_RRTYPE_KX] = { { 2, KNOT_RDATA_WF_COMPRESSED_DNAME, + [KNOT_RRTYPE_KX] = { { 2, KNOT_RDATA_WF_UNCOMPRESSED_DNAME, KNOT_RDATA_WF_END }, "KX" }, [KNOT_RRTYPE_CERT] = { { KNOT_RDATA_WF_REMAINDER, KNOT_RDATA_WF_END }, "CERT" }, @@ -97,10 +97,10 @@ static const rdata_descriptor_t rdata_descriptors[] = { KNOT_RDATA_WF_END }, "SSHFP" }, [KNOT_RRTYPE_IPSECKEY] = { { KNOT_RDATA_WF_REMAINDER, KNOT_RDATA_WF_END }, "IPSECKEY" }, - [KNOT_RRTYPE_RRSIG] = { { 18, KNOT_RDATA_WF_LITERAL_DNAME, + [KNOT_RRTYPE_RRSIG] = { { 18, KNOT_RDATA_WF_UNCOMPRESSED_DNAME, KNOT_RDATA_WF_REMAINDER, KNOT_RDATA_WF_END }, "RRSIG" }, - [KNOT_RRTYPE_NSEC] = { { KNOT_RDATA_WF_LITERAL_DNAME, + [KNOT_RRTYPE_NSEC] = { { KNOT_RDATA_WF_UNCOMPRESSED_DNAME, KNOT_RDATA_WF_REMAINDER, KNOT_RDATA_WF_END }, "NSEC" }, [KNOT_RRTYPE_DNSKEY] = { { KNOT_RDATA_WF_REMAINDER, @@ -118,7 +118,7 @@ static const rdata_descriptor_t rdata_descriptors[] = { [KNOT_RRTYPE_NID] = { { 10 }, "NID" }, [KNOT_RRTYPE_L32] = { { 6 }, "L32" }, [KNOT_RRTYPE_L64] = { { 10 }, "L64" }, - [KNOT_RRTYPE_LP] = { { 2, KNOT_RDATA_WF_COMPRESSED_DNAME }, + [KNOT_RRTYPE_LP] = { { 2, KNOT_RDATA_WF_UNCOMPRESSED_DNAME }, "LP" }, [KNOT_RRTYPE_EUI48] = { { 6, KNOT_RDATA_WF_END }, "EUI48" }, [KNOT_RRTYPE_EUI64] = { { 8, KNOT_RDATA_WF_END }, "EUI64" }, @@ -136,6 +136,30 @@ static const rdata_descriptor_t rdata_descriptors[] = { KNOT_RDATA_WF_END }, "ANY" }, }; +/*! + * \brief Some (OBSOLETE) RR type descriptors. + */ +static const rdata_descriptor_t obsolete_rdata_descriptors[] = { + [0] = { { KNOT_RDATA_WF_REMAINDER, + KNOT_RDATA_WF_END }, NULL }, + [KNOT_RRTYPE_MD] = { { KNOT_RDATA_WF_COMPRESSED_DNAME, + KNOT_RDATA_WF_END }, "MD" }, + [KNOT_RRTYPE_MF] = { { KNOT_RDATA_WF_COMPRESSED_DNAME, + KNOT_RDATA_WF_END }, "MF" }, + [KNOT_RRTYPE_MB] = { { KNOT_RDATA_WF_COMPRESSED_DNAME, + KNOT_RDATA_WF_END }, "MB" }, + [KNOT_RRTYPE_MG] = { { KNOT_RDATA_WF_COMPRESSED_DNAME, + KNOT_RDATA_WF_END }, "MG" }, + [KNOT_RRTYPE_MR] = { { KNOT_RDATA_WF_COMPRESSED_DNAME, + KNOT_RDATA_WF_END }, "MR" }, + [KNOT_RRTYPE_PX] = { { 2, KNOT_RDATA_WF_COMPRESSED_DNAME, + KNOT_RDATA_WF_COMPRESSED_DNAME, + KNOT_RDATA_WF_END }, "PX" }, + [KNOT_RRTYPE_NXT] = { { KNOT_RDATA_WF_COMPRESSED_DNAME, + KNOT_RDATA_WF_REMAINDER, + KNOT_RDATA_WF_END }, "NXT" }, +}; + const rdata_descriptor_t *get_rdata_descriptor(const uint16_t type) { if (type <= KNOT_RRTYPE_ANY && rdata_descriptors[type].type_name != 0) { @@ -145,6 +169,16 @@ const rdata_descriptor_t *get_rdata_descriptor(const uint16_t type) } } +const rdata_descriptor_t *get_obsolete_rdata_descriptor(const uint16_t type) +{ + if (type <= KNOT_RRTYPE_NXT && + obsolete_rdata_descriptors[type].type_name != 0) { + return &obsolete_rdata_descriptors[type]; + } else { + return &obsolete_rdata_descriptors[0]; + } +} + int knot_rrtype_to_string(const uint16_t rrtype, char *out, const size_t out_len) @@ -251,8 +285,7 @@ int knot_rrclass_from_string(const char *name, uint16_t *num) int descriptor_item_is_dname(const int item) { - return item == KNOT_RDATA_WF_LITERAL_DNAME || - item == KNOT_RDATA_WF_COMPRESSED_DNAME || + return item == KNOT_RDATA_WF_COMPRESSED_DNAME || item == KNOT_RDATA_WF_UNCOMPRESSED_DNAME; } diff --git a/src/common/descriptor.h b/src/common/descriptor.h index d7938cb..f7c2327 100644 --- a/src/common/descriptor.h +++ b/src/common/descriptor.h @@ -110,6 +110,25 @@ enum knot_rr_type { }; /*! + * \brief Some (OBSOLETE) resource record type constants. + * + * http://www.iana.org/assignments/dns-parameters/dns-parameters.xml + * + * \note These records can contain compressed domain name in rdata so + * it is important to know the position of it during transfers. + * See RFC 3597#4. + */ +enum knot_obsolete_rr_type { + KNOT_RRTYPE_MD = 3, + KNOT_RRTYPE_MF = 4, + KNOT_RRTYPE_MB = 7, + KNOT_RRTYPE_MG = 8, + KNOT_RRTYPE_MR = 9, + KNOT_RRTYPE_PX = 26, + KNOT_RRTYPE_NXT = 30 +}; + +/*! * \brief Constants characterising the wire format of RDATA items. */ enum knot_rdata_wireformat { @@ -117,8 +136,6 @@ enum knot_rdata_wireformat { KNOT_RDATA_WF_COMPRESSED_DNAME = -10, /*!< Uncompressed dname. */ KNOT_RDATA_WF_UNCOMPRESSED_DNAME, - /*!< Dname with preserved letter cases. */ - KNOT_RDATA_WF_LITERAL_DNAME, /*!< Initial part of NAPTR record before dname. */ KNOT_RDATA_WF_NAPTR_HEADER, /*!< Uninteresting final part of a record. */ @@ -140,7 +157,7 @@ typedef struct { /*! * \brief Gets rdata descriptor for given RR name. * - * \param name Mnemonic of RR type whose descriptor should be retvaled. + * \param name Mnemonic of RR type whose descriptor should be returned. * * \retval RR descriptor for given name, NULL descriptor if * unknown type. @@ -148,6 +165,16 @@ typedef struct { const rdata_descriptor_t *get_rdata_descriptor(const uint16_t type); /*! + * \brief Gets rdata descriptor for given RR name (obsolete version). + * + * \param name Mnemonic of RR type whose descriptor should be returned. + * + * \retval RR descriptor for given name, NULL descriptor if + * unknown type. + */ +const rdata_descriptor_t *get_obsolete_rdata_descriptor(const uint16_t type); + +/*! * \brief Converts numeric type representation to mnemonic string. * * \param rrtype Type RR type code to be converted. diff --git a/src/common/errcode.c b/src/common/errcode.c index b555805..50b37dd 100644 --- a/src/common/errcode.c +++ b/src/common/errcode.c @@ -52,7 +52,7 @@ const error_table_t knot_error_msgs[] = { { KNOT_ECRYPTO, "Error in crypto library." }, { KNOT_ENSEC3PAR, "Missing or wrong NSEC3PARAM record." }, { KNOT_ENSEC3CHAIN, "Missing or wrong NSEC3 chain in the zone." }, - { KNOT_EBADZONE, "Name does not belong to the zone." }, + { KNOT_EOUTOFZONE, "Name does not belong to the zone." }, { KNOT_EHASH, "Error in hash table." }, { KNOT_EZONEINVAL, "Invalid zone file." }, { KNOT_ENOZONE, "No such zone found." }, diff --git a/src/common/errcode.h b/src/common/errcode.h index 69f6ed5..c29a433 100644 --- a/src/common/errcode.h +++ b/src/common/errcode.h @@ -71,7 +71,7 @@ enum knot_error { KNOT_ECRYPTO, /*!< Error in crypto library. */ KNOT_ENSEC3PAR, /*!< Missing or wrong NSEC3PARAM record. */ KNOT_ENSEC3CHAIN, /*!< Missing or wrong NSEC3 chain in the zone. */ - KNOT_EBADZONE, /*!< Domain name does not belong to the zone. */ + KNOT_EOUTOFZONE, /*!< Domain name does not belong to the zone. */ KNOT_EHASH, /*!< Error in hash table. */ KNOT_EZONEINVAL, /*!< Invalid zone file. */ KNOT_ENOZONE, /*!< No such zone found. */ |