supla-device
Loading...
Searching...
No Matches
netif_config.h
1/*
2 Copyright (C) AC SOFTWARE SP. Z O.O.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17*/
18
19#ifndef SRC_SUPLA_NETWORK_NETIF_CONFIG_H_
20#define SRC_SUPLA_NETWORK_NETIF_CONFIG_H_
21
22#include <stddef.h>
23#include <stdint.h>
24#include <stdio.h>
25#include <string.h>
26
27namespace Supla {
28
29enum class NetifIpMode : uint8_t {
30 DHCP = 0,
31 Static = 1,
32};
33
34constexpr uint8_t NETIF_CONFIG_BLOB_VERSION = 1;
35
36#pragma pack(push, 1)
38 uint8_t version = NETIF_CONFIG_BLOB_VERSION;
39 uint8_t ipMode = static_cast<uint8_t>(NetifIpMode::DHCP);
40 uint8_t reserved[2] = {};
41 uint32_t ip = 0; // Stored in network byte order.
42 uint32_t netmask = 0; // Stored in network byte order.
43 uint32_t gateway = 0; // Stored in network byte order.
44 uint32_t dns1 = 0; // Stored in network byte order.
45 uint32_t dns2 = 0; // Stored in network byte order.
46};
47#pragma pack(pop)
48
49static_assert(sizeof(NetifConfigBlob) == 24,
50 "Unexpected NetifConfigBlob size");
51
52inline bool parseUnsignedDecimal(const char* text,
53 uint32_t* result,
54 uint32_t maxValue) {
55 if (text == nullptr || result == nullptr || text[0] == '\0') {
56 return false;
57 }
58
59 uint32_t value = 0;
60 for (const char* ptr = text; *ptr; ++ptr) {
61 if (*ptr < '0' || *ptr > '9') {
62 return false;
63 }
64 uint32_t digit = static_cast<uint32_t>(*ptr - '0');
65 if (value > (UINT32_MAX - digit) / 10) {
66 return false;
67 }
68 value = value * 10 + digit;
69 if (value > maxValue) {
70 return false;
71 }
72 }
73
74 *result = value;
75 return true;
76}
77
78inline bool parseUnsignedDecimalRange(const char* begin,
79 const char* end,
80 uint32_t* result,
81 uint32_t maxValue) {
82 if (begin == nullptr || end == nullptr || result == nullptr ||
83 begin >= end) {
84 return false;
85 }
86
87 uint32_t value = 0;
88 for (const char* ptr = begin; ptr < end; ++ptr) {
89 if (*ptr < '0' || *ptr > '9') {
90 return false;
91 }
92 uint32_t digit = static_cast<uint32_t>(*ptr - '0');
93 if (value > (UINT32_MAX - digit) / 10) {
94 return false;
95 }
96 value = value * 10 + digit;
97 if (value > maxValue) {
98 return false;
99 }
100 }
101
102 *result = value;
103 return true;
104}
105
106inline bool parseIpv4Address(const char* text, uint32_t* result) {
107 if (text == nullptr || result == nullptr) {
108 return false;
109 }
110
111 uint32_t ip = 0;
112 const char* ptr = text;
113 for (int i = 0; i < 4; i++) {
114 const char* end = (i < 3) ? strchr(ptr, '.') : ptr + strlen(ptr);
115 if (end == nullptr) {
116 return false;
117 }
118 uint32_t value = 0;
119 if (!parseUnsignedDecimalRange(ptr, end, &value, 255)) {
120 return false;
121 }
122 if (i < 3) {
123 if (*end != '.') {
124 return false;
125 }
126 ptr = end + 1;
127 if (*ptr == '\0') {
128 return false;
129 }
130 } else if (*end != '\0') {
131 return false;
132 }
133 if (i == 0) {
134 ip = value << 24;
135 } else if (i == 1) {
136 ip |= value << 16;
137 } else if (i == 2) {
138 ip |= value << 8;
139 } else {
140 ip |= value;
141 }
142 }
143 *result = ip;
144 return true;
145}
146
147inline bool formatIpv4Address(uint32_t ip, char* out, size_t outSize) {
148 if (out == nullptr || outSize == 0) {
149 return false;
150 }
151
152 int size = snprintf(out,
153 outSize,
154 "%u.%u.%u.%u",
155 static_cast<unsigned int>((ip >> 24) & 0xFF),
156 static_cast<unsigned int>((ip >> 16) & 0xFF),
157 static_cast<unsigned int>((ip >> 8) & 0xFF),
158 static_cast<unsigned int>(ip & 0xFF));
159 return size > 0 && static_cast<size_t>(size) < outSize;
160}
161
162inline bool isValidNetmask(uint32_t netmask) {
163 if (netmask == 0) {
164 return false;
165 }
166
167 uint32_t inverted = ~netmask;
168 return (inverted & (inverted + 1)) == 0;
169}
170
171inline bool isValidIpv4Address(uint32_t ip) {
172 uint8_t firstOctet = static_cast<uint8_t>((ip >> 24) & 0xFF);
173 if (ip == 0 || ip == 0xFFFFFFFFu) {
174 return false;
175 }
176 if (firstOctet == 127) {
177 return false;
178 }
179 if (firstOctet >= 224) {
180 return false;
181 }
182 return true;
183}
184
185inline bool isSameSubnet(uint32_t ip, uint32_t netmask, uint32_t gateway) {
186 return (ip & netmask) == (gateway & netmask);
187}
188
189inline bool isUsableSubnetHostAddress(uint32_t ip, uint32_t netmask) {
190 uint32_t hostMask = ~netmask;
191 if (hostMask == 0) {
192 return true;
193 }
194
195 uint32_t hostPart = ip & hostMask;
196 return hostPart != 0 && hostPart != hostMask;
197}
198
199inline bool parseNetmaskOrPrefix(const char* text, uint32_t* result) {
200 if (text == nullptr || result == nullptr) {
201 return false;
202 }
203
204 if (text[0] == '/') {
205 ++text;
206 }
207
208 if (strchr(text, '.') != nullptr) {
209 if (!parseIpv4Address(text, result)) {
210 return false;
211 }
212 return isValidNetmask(*result);
213 }
214
215 uint32_t prefix = 0;
216 if (!parseUnsignedDecimal(text, &prefix, 32)) {
217 return false;
218 }
219 if (prefix == 0 || prefix > 32) {
220 return false;
221 }
222
223 if (prefix == 32) {
224 *result = 0xFFFFFFFFu;
225 } else {
226 *result = 0xFFFFFFFFu << (32 - prefix);
227 }
228 return isValidNetmask(*result);
229}
230
231inline void normalizeDhcpNetifConfig(NetifConfigBlob* cfg) {
232 if (cfg == nullptr) {
233 return;
234 }
235
236 cfg->version = NETIF_CONFIG_BLOB_VERSION;
237 cfg->ipMode = static_cast<uint8_t>(NetifIpMode::DHCP);
238 cfg->reserved[0] = 0;
239 cfg->reserved[1] = 0;
240 cfg->ip = 0;
241 cfg->netmask = 0;
242 cfg->gateway = 0;
243 cfg->dns1 = 0;
244 cfg->dns2 = 0;
245}
246
247inline bool isValidStaticNetifConfig(const NetifConfigBlob& cfg) {
248 if (cfg.version != NETIF_CONFIG_BLOB_VERSION) {
249 return false;
250 }
251 if (cfg.ipMode != static_cast<uint8_t>(NetifIpMode::Static)) {
252 return false;
253 }
254
255 if (!isValidIpv4Address(cfg.ip) || !isValidNetmask(cfg.netmask) ||
256 !isUsableSubnetHostAddress(cfg.ip, cfg.netmask) ||
257 !isValidIpv4Address(cfg.gateway) ||
258 !isUsableSubnetHostAddress(cfg.gateway, cfg.netmask) ||
259 !isSameSubnet(cfg.ip, cfg.netmask, cfg.gateway) ||
260 cfg.ip == cfg.gateway ||
261 !isValidIpv4Address(cfg.dns1)) {
262 return false;
263 }
264
265 if (cfg.dns2 != 0 && !isValidIpv4Address(cfg.dns2)) {
266 return false;
267 }
268
269 return true;
270}
271
272inline bool isValidNetifConfigBlob(const NetifConfigBlob& cfg) {
273 if (cfg.version != NETIF_CONFIG_BLOB_VERSION) {
274 return false;
275 }
276 if (cfg.ipMode == static_cast<uint8_t>(NetifIpMode::DHCP)) {
277 return true;
278 }
279 if (cfg.ipMode == static_cast<uint8_t>(NetifIpMode::Static)) {
280 return isValidStaticNetifConfig(cfg);
281 }
282 return false;
283}
284
285} // namespace Supla
286
287#endif // SRC_SUPLA_NETWORK_NETIF_CONFIG_H_
Definition netif_config.h:37