supla-device
Loading...
Searching...
No Matches
web_host.h
1// SPDX-FileCopyrightText: AC SOFTWARE SP. Z O.O.
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#ifndef SRC_SUPLA_NETWORK_WEB_HOST_H_
5#define SRC_SUPLA_NETWORK_WEB_HOST_H_
6
7#include <stddef.h>
8#include <stdint.h>
9#include <string.h>
10
11namespace Supla {
12
13// Bounded HTTP authority parser. IPv6 syntax is checked by the platform's
14// address parser; no DNS lookup is involved in matching a Host.
15struct WebHost {
16 char name[254] = {};
17 uint16_t port = 0;
18 bool hasPort = false;
19 bool ipv6 = false;
20 bool ipv4 = false;
21 uint8_t address[4] = {};
22
23 bool parse(const char *value) {
24 *this = WebHost{};
25 if (value == nullptr) {
26 return false;
27 }
28 const size_t length = strnlen(value, 262);
29 if (length == 0 || length >= 262) {
30 return false;
31 }
32 const char *begin = value;
33 const char *end = nullptr;
34 const char *portText = nullptr;
35 if (value[0] == '[') {
36 ipv6 = true;
37 begin++;
38 end = strchr(begin, ']');
39 if (end == nullptr || end == begin) {
40 return false;
41 }
42 if (end[1] != '\0') {
43 if (end[1] != ':') {
44 return false;
45 }
46 portText = end + 2;
47 }
48 } else {
49 end = strchr(value, ':');
50 if (end != nullptr) {
51 portText = end + 1;
52 } else {
53 end = value + length;
54 }
55 }
56 size_t size = end - begin;
57 if (size == 0 || size >= sizeof(name)) {
58 return false;
59 }
60 if (portText != nullptr) {
61 hasPort = true;
62 if (*portText == '\0') {
63 return false;
64 }
65 uint32_t number = 0;
66 for (const char *p = portText; *p; p++) {
67 if (*p < '0' || *p > '9') {
68 return false;
69 }
70 number = number * 10 + (*p - '0');
71 if (number > 65535) {
72 return false;
73 }
74 }
75 if (number == 0) {
76 return false;
77 }
78 port = number;
79 }
80 memcpy(name, begin, size);
81 name[size] = '\0';
82 if (ipv6) {
83 for (size_t i = 0; i < size; i++) {
84 const char c = name[i];
85 if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
86 (c >= 'A' && c <= 'F') || c == ':' || c == '.')) {
87 return false;
88 }
89 }
90 return true;
91 }
92 // A single terminal root dot is valid for a DNS name.
93 const bool rootDot = name[size - 1] == '.';
94 if (rootDot) {
95 name[--size] = '\0';
96 }
97 if (size == 0) {
98 return false;
99 }
100 bool numeric = true;
101 for (size_t i = 0; i < size; i++) {
102 const char c = name[i];
103 if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
104 (c >= 'A' && c <= 'Z') || c == '-' || c == '_' || c == '.')) {
105 return false;
106 }
107 if (c == '.' && (i == 0 || name[i - 1] == '.')) {
108 return false;
109 }
110 if (c != '.' && (c < '0' || c > '9')) {
111 numeric = false;
112 }
113 }
114 if (!numeric) {
115 return name[size - 1] != '.';
116 }
117 if (rootDot) {
118 return false;
119 }
120 // Require four decimal octets, without octal/shortened representations.
121 ipv4 = true;
122 const char *p = name;
123 for (int i = 0; i < 4; i++) {
124 const char *start = p;
125 unsigned int number = 0;
126 while (*p >= '0' && *p <= '9') {
127 number = number * 10 + (*p++ - '0');
128 if (number > 255 || p - start > 3) {
129 return false;
130 }
131 }
132 if (p == start || (p - start > 1 && *start == '0')) {
133 return false;
134 }
135 address[i] = number;
136 if (i < 3) {
137 if (*p++ != '.') {
138 return false;
139 }
140 } else if (*p != '\0') {
141 return false;
142 }
143 }
144 return true;
145 }
146
147 bool matchesName(const char *hostname) const {
148 if (ipv4 || ipv6 || hostname == nullptr || hostname[0] == '\0') {
149 return false;
150 }
151 size_t i = 0;
152 while (name[i] && hostname[i]) {
153 if (lower(name[i]) != lower(hostname[i])) {
154 return false;
155 }
156 i++;
157 }
158 if (hostname[i] != '\0') {
159 return false;
160 }
161 const char *suffix = name + i;
162 if (*suffix == '\0') {
163 return true;
164 }
165 const char *local = ".local";
166 while (*suffix && *local && lower(*suffix) == *local) {
167 suffix++;
168 local++;
169 }
170 return *suffix == '\0' && *local == '\0';
171 }
172
173 private:
174 static char lower(char c) {
175 return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
176 }
177};
178
179} // namespace Supla
180
181#endif // SRC_SUPLA_NETWORK_WEB_HOST_H_
Definition web_host.h:15