DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
ip.h
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file ip.h
6 * @brief Layer 3 (Network) - a family-tagged IP address (IPv4 or IPv6) with RFC-faithful
7 * text parsing, canonical formatting, and scope classification.
8 *
9 * One representation for both address families so the rest of the stack can carry a peer
10 * address without caring whether it is v4 or v6. The address bytes are stored in network
11 * (big-endian, left-to-right) order: a v4 address uses bytes[0..3], a v6 address bytes[0..15].
12 *
13 * Pure and host-testable - no lwIP, no Arduino, no heap, no stdlib parsing. The parser
14 * implements RFC 4291 §2.2 text forms (dotted-quad v4; v6 with `::` zero-compression and the
15 * embedded-v4 `::ffff:a.b.c.d` tail); the formatter emits the RFC 5952 canonical form
16 * (lower-case, no leading zeros, the longest zero run compressed to `::`, v4-mapped shown as
17 * dotted). ESP32 dual-stack bring-up (enabling IPv6 on the netif) lives in the physical layer
18 * behind DETWS_ENABLE_IPV6; the TCP/UDP listeners already bind IPADDR_TYPE_ANY, so the server
19 * accepts v6 connections the moment the interface has a v6 address.
20 *
21 * @author Douglas Quigg (dstroy0)
22 * @date 2026
23 */
24
25#ifndef DETERMINISTICESPASYNCWEBSERVER_DET_IP_H
26#define DETERMINISTICESPASYNCWEBSERVER_DET_IP_H
27
28#include <stddef.h>
29#include <stdint.h>
30
31/** @brief Address family tag. */
32enum class DetIpFamily : uint8_t
33{
34 DET_IP_NONE = 0, ///< empty / unparsed
35 DET_IP_V4 = 4, ///< IPv4 (bytes[0..3])
36 DET_IP_V6 = 6, ///< IPv6 (bytes[0..15])
37};
38
39/** @brief Address scope, in rough order of reachability (used for allow/deny policy + logging). */
40enum class DetIpScope : uint8_t
41{
42 DET_IP_SCOPE_UNSPECIFIED = 0, ///< 0.0.0.0 / ::
43 DET_IP_SCOPE_LOOPBACK, ///< 127.0.0.0/8 / ::1
44 DET_IP_SCOPE_LINK_LOCAL, ///< 169.254.0.0/16 / fe80::/10
45 DET_IP_SCOPE_PRIVATE, ///< RFC1918 (10/8, 172.16/12, 192.168/16) / ULA fc00::/7
46 DET_IP_SCOPE_MULTICAST, ///< 224.0.0.0/4 / ff00::/8
47 DET_IP_SCOPE_GLOBAL, ///< globally routable unicast
48};
49
50/** @brief A v4 or v6 address in network (big-endian) byte order. */
51struct DetIp
52{
53 DetIpFamily family; ///< address family tag
54 uint8_t bytes[16]; ///< network order; v4 uses the first 4
55};
56
57/** @brief Longest text an ::det_ip_format can produce, including the NUL (RFC 5952 v4-mapped). */
58#define DET_IP_STR_MAX 46
59
60/**
61 * @brief Parse an IPv4 or IPv6 textual address (RFC 4291 §2.2) into @p out.
62 * @return true on success (@p out->family set to DetIpFamily::DET_IP_V4/V6), false if @p s is malformed.
63 */
64bool det_ip_parse(const char *s, DetIp *out);
65
66/**
67 * @brief Format @p ip into @p out as its RFC 5952 canonical text.
68 * @return the length written (excluding the NUL), or 0 if @p ip is empty or @p cap is too small
69 * (need up to ::DET_IP_STR_MAX).
70 */
71size_t det_ip_format(const DetIp *ip, char *out, size_t cap);
72
73/** @brief Classify @p ip into a ::DetIpScope. */
75
76/** @brief True if @p a and @p b are the same family and address. */
77bool det_ip_equal(const DetIp *a, const DetIp *b);
78
79/** @brief True if @p ip is an IPv4-mapped IPv6 address (::ffff:a.b.c.d, RFC 4291 §2.5.5.2). */
80bool det_ip_is_v4_mapped(const DetIp *ip);
81
82/**
83 * @brief Build a v4 ::DetIp from four octets (a.b.c.d).
84 */
85DetIp det_ip_from_v4_octets(uint8_t a, uint8_t b, uint8_t c, uint8_t d);
86
87/**
88 * @brief Build a v6 ::DetIp from 16 address bytes in network (big-endian) order.
89 */
90DetIp det_ip_from_v6_bytes(const uint8_t bytes[16]);
91
92/**
93 * @brief The v4 address as a big-endian (network-order) uint32 (a<<24 | b<<16 | c<<8 | d).
94 * @return 0 if @p ip is not a v4 (or v4-mapped) address.
95 */
96uint32_t det_ip_to_v4_be(const DetIp *ip);
97
98/** @brief True if @p ip is empty (DetIpFamily::DET_IP_NONE) or the all-zero unspecified address (0.0.0.0 / ::). */
99bool det_ip_is_unspecified(const DetIp *ip);
100
101/**
102 * @brief CIDR containment: is @p addr inside the @p net / @p prefix_len block?
103 *
104 * The two must be the same family. @p prefix_len is 0..32 for v4, 0..128 for v6; the top
105 * @p prefix_len bits of the address bytes must match @p net (a prefix of 0 matches everything).
106 * This is the standard v4/v6 allowlist match.
107 * @return true if @p addr is covered; false on a family mismatch or an out-of-range prefix.
108 */
109bool det_ip_prefix_match(const DetIp *addr, const DetIp *net, uint8_t prefix_len);
110
111#endif // DETERMINISTICESPASYNCWEBSERVER_DET_IP_H
uint32_t det_ip_to_v4_be(const DetIp *ip)
The v4 address as a big-endian (network-order) uint32 (a<<24 | b<<16 | c<<8 | d).
Definition ip.cpp:493
DetIpScope det_ip_classify(const DetIp *ip)
Classify ip into a DetIpScope.
Definition ip.cpp:448
bool det_ip_prefix_match(const DetIp *addr, const DetIp *net, uint8_t prefix_len)
CIDR containment: is addr inside the net / prefix_len block?
Definition ip.cpp:516
bool det_ip_is_unspecified(const DetIp *ip)
True if ip is empty (DetIpFamily::DET_IP_NONE) or the all-zero unspecified address (0....
Definition ip.cpp:505
size_t det_ip_format(const DetIp *ip, char *out, size_t cap)
Format ip into out as its RFC 5952 canonical text.
Definition ip.cpp:388
bool det_ip_is_v4_mapped(const DetIp *ip)
True if ip is an IPv4-mapped IPv6 address (::ffff:a.b.c.d, RFC 4291 §2.5.5.2).
Definition ip.cpp:443
DetIpFamily
Address family tag.
Definition ip.h:33
@ DET_IP_V4
IPv4 (bytes[0..3])
@ DET_IP_V6
IPv6 (bytes[0..15])
@ DET_IP_NONE
empty / unparsed
bool det_ip_equal(const DetIp *a, const DetIp *b)
True if a and b are the same family and address.
Definition ip.cpp:459
bool det_ip_parse(const char *s, DetIp *out)
Parse an IPv4 or IPv6 textual address (RFC 4291 §2.2) into out.
Definition ip.cpp:350
DetIp det_ip_from_v6_bytes(const uint8_t bytes[16])
Build a v6 DetIp from 16 address bytes in network (big-endian) order.
Definition ip.cpp:485
DetIpScope
Address scope, in rough order of reachability (used for allow/deny policy + logging).
Definition ip.h:41
@ DET_IP_SCOPE_GLOBAL
globally routable unicast
@ DET_IP_SCOPE_LOOPBACK
127.0.0.0/8 / ::1
@ DET_IP_SCOPE_PRIVATE
RFC1918 (10/8, 172.16/12, 192.168/16) / ULA fc00::/7.
@ DET_IP_SCOPE_UNSPECIFIED
0.0.0.0 / ::
@ DET_IP_SCOPE_MULTICAST
224.0.0.0/4 / ff00::/8
@ DET_IP_SCOPE_LINK_LOCAL
169.254.0.0/16 / fe80::/10
DetIp det_ip_from_v4_octets(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
Build a v4 DetIp from four octets (a.b.c.d).
Definition ip.cpp:473
A v4 or v6 address in network (big-endian) byte order.
Definition ip.h:52
uint8_t bytes[16]
network order; v4 uses the first 4
Definition ip.h:54
DetIpFamily family
address family tag
Definition ip.h:53