cutelyst  5.0.1
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
validatorip.cpp
1 /*
2  * SPDX-FileCopyrightText: (C) 2017-2025 Matthias Fehring <mf@huessenbergnetz.de>
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 
6 #include "validatorip_p.h"
7 
8 #include <utility>
9 
10 #include <QHostAddress>
11 
12 using namespace Cutelyst;
13 using namespace Qt::Literals::StringLiterals;
14 
15 const QRegularExpression ValidatorIpPrivate::regex{
16  u"^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$"_s};
17 
19  Constraints constraints,
20  const Cutelyst::ValidatorMessages &messages,
21  const QString &defValKey)
22  : ValidatorRule(*new ValidatorIpPrivate(field, constraints, messages, defValKey))
23 {
24 }
25 
26 ValidatorIp::~ValidatorIp() = default;
27 
29 {
30  ValidatorReturnType result;
31 
32  Q_D(const ValidatorIp);
33 
34  const QString v = value(params);
35 
36  if (!v.isEmpty()) {
37 
38  if (ValidatorIp::validate(v, d->constraints)) {
39  result.value.setValue(v);
40  } else {
41  result.errorMessage = validationError(c);
42  qCDebug(C_VALIDATOR).noquote() << "Not a valid IP address";
43  }
44 
45  } else {
46  defaultValue(c, &result);
47  }
48 
49  return result;
50 }
51 
53 {
54  cb(validate(c, params));
55 }
56 
57 bool ValidatorIp::validate(const QString &value, Constraints constraints)
58 {
59  bool valid = true;
60 
61  // simple check for an IPv4 address with four parts, because QHostAddress also tolerates
62  // addresses like 192.168.2 and fills them with 0 somewhere
63  if (!value.contains(u':') && !value.contains(ValidatorIpPrivate::regex)) {
64 
65  valid = false;
66 
67  } else {
68 
69  // private IPv4 subnets
70  static const std::vector<std::pair<QHostAddress, int>> ipv4Private(
71  {// Used for local communications within a private network
72  // https://tools.ietf.org/html/rfc1918
73  {QHostAddress(u"10.0.0.0"_s), 8},
74 
75  // Used for link-local addresses between two hosts on a single link when no IP address
76  // is otherwise specified, such as would have normally been retrieved from a DHCP
77  // server https://tools.ietf.org/html/rfc3927
78  {QHostAddress(u"169.254.0.0"_s), 16},
79 
80  // Used for local communications within a private network
81  // https://tools.ietf.org/html/rfc1918
82  {QHostAddress(u"172.16.0.0"_s), 12},
83 
84  // Used for local communications within a private network
85  // https://tools.ietf.org/html/rfc1918
86  {QHostAddress(u"192.168.0.0"_s), 12}});
87 
88  // reserved IPv4 subnets
89  static const std::vector<std::pair<QHostAddress, int>> ipv4Reserved(
90  {// Used for broadcast messages to the current ("this")
91  // https://tools.ietf.org/html/rfc1700
92  {QHostAddress(u"0.0.0.0"_s), 8},
93 
94  // Used for communications between a service provider and its subscribers when using a
95  // carrier-grade NAT https://tools.ietf.org/html/rfc6598
96  {QHostAddress(u"100.64.0.0"_s), 10},
97 
98  // Used for loopback addresses to the local host
99  // https://tools.ietf.org/html/rfc990
100  {QHostAddress(u"127.0.0.1"_s), 8},
101 
102  // Used for the IANA IPv4 Special Purpose Address Registry
103  // https://tools.ietf.org/html/rfc5736
104  {QHostAddress(u"192.0.0.0"_s), 24},
105 
106  // Assigned as "TEST-NET" for use in documentation and examples. It should not be used
107  // publicly. https://tools.ietf.org/html/rfc5737
108  {QHostAddress(u"192.0.2.0"_s), 24},
109 
110  // Used by 6to4 anycast relays
111  // https://tools.ietf.org/html/rfc3068
112  {QHostAddress(u"192.88.99.0"_s), 24},
113 
114  // Used for testing of inter-network communications between two separate subnets
115  // https://tools.ietf.org/html/rfc2544
116  {QHostAddress(u"198.18.0.0"_s), 15},
117 
118  // Assigned as "TEST-NET-2" for use in documentation and examples. It should not be
119  // used publicly. https://tools.ietf.org/html/rfc5737
120  {QHostAddress(u"198.51.100.0"_s), 24},
121 
122  // Assigned as "TEST-NET-3" for use in documentation and examples. It should not be
123  // used publicly. https://tools.ietf.org/html/rfc5737
124  {QHostAddress(u"203.0.113.0"_s), 24},
125 
126  // Reserved for future use
127  // https://tools.ietf.org/html/rfc6890
128  {QHostAddress(u"240.0.0.0"_s), 4},
129 
130  // Reserved for the "limited broadcast" destination address
131  // https://tools.ietf.org/html/rfc6890
132  {QHostAddress(u"255.255.255.255"_s), 32}});
133 
134  // private IPv6 subnets
135  static const std::vector<std::pair<QHostAddress, int>> ipv6Private(
136  {// unique local address
137  {QHostAddress(u"fc00::"_s), 7},
138 
139  // link-local address
140  {QHostAddress(u"fe80::"_s), 10}});
141 
142  // reserved IPv6 subnets
143  static const std::vector<std::pair<QHostAddress, int>> ipv6Reserved(
144  {// unspecified address
145  {QHostAddress(u"::"_s), 128},
146 
147  // loopback address to the local host
148  {QHostAddress(u"::1"_s), 128},
149 
150  // IPv4 mapped addresses
151  {QHostAddress(u"::ffff:0:0"_s), 96},
152 
153  // discard prefix
154  // https://tools.ietf.org/html/rfc6666
155  {QHostAddress(u"100::"_s), 64},
156 
157  // IPv4/IPv6 translation
158  // https://tools.ietf.org/html/rfc6052
159  {QHostAddress(u"64:ff9b::"_s), 96},
160 
161  // Teredo tunneling
162  {QHostAddress(u"2001::"_s), 32},
163 
164  // deprected (previously ORCHID)
165  {QHostAddress(u"2001:10::"_s), 28},
166 
167  // ORCHIDv2
168  {QHostAddress(u"2001:20::"_s), 28},
169 
170  // addresses used in documentation and example source code
171  {QHostAddress(u"2001:db8::"_s), 32},
172 
173  // 6to4
174  {QHostAddress(u"2002::"_s), 16}});
175 
176  QHostAddress a;
177 
178  if (a.setAddress(value)) {
179 
180  if (!constraints.testFlag(NoConstraint)) {
181 
182  if (a.protocol() == QAbstractSocket::IPv4Protocol) {
183 
184  if (constraints.testFlag(IPv6Only)) {
185  valid = false;
186  }
187 
188  if (valid && constraints.testFlag(NoPrivateRange)) {
189  valid = !std::ranges::any_of(
190  ipv4Private, [&a](const std::pair<QHostAddress, int> &subnet) {
191  return a.isInSubnet(subnet.first, subnet.second);
192  });
193  }
194 
195  if (valid && constraints.testFlag(NoReservedRange)) {
196  valid = !std::ranges::any_of(
197  ipv4Reserved, [&a](const std::pair<QHostAddress, int> &subnet) {
198  return a.isInSubnet(subnet.first, subnet.second);
199  });
200  }
201 
202  if (valid && constraints.testFlag(NoMultiCast)) {
203  if (a.isInSubnet(QHostAddress(u"224.0.0.0"_s), 4)) {
204  valid = false;
205  }
206  }
207 
208  } else {
209 
210  if (constraints.testFlag(IPv4Only)) {
211  valid = false;
212  }
213 
214  if (valid && constraints.testFlag(NoPrivateRange)) {
215  valid = !std::ranges::any_of(
216  ipv6Private, [&a](const std::pair<QHostAddress, int> &subnet) {
217  return a.isInSubnet(subnet.first, subnet.second);
218  });
219  }
220 
221  if (valid && constraints.testFlag(NoReservedRange)) {
222  valid = !std::ranges::any_of(
223  ipv6Reserved, [&a](const std::pair<QHostAddress, int> &subnet) {
224  return a.isInSubnet(subnet.first, subnet.second);
225  });
226  }
227 
228  if (valid && constraints.testFlag(NoMultiCast)) {
229  if (a.isInSubnet(QHostAddress(u"ff00::"_s), 8)) {
230  valid = false;
231  }
232  }
233  }
234  }
235 
236  } else {
237  valid = false;
238  }
239  }
240 
241  return valid;
242 }
243 
245 {
246  Q_UNUSED(errorData)
247  const QString _label = label(c);
248  if (_label.isEmpty()) {
249  //% "IP address is invalid or not acceptable."
250  return c->qtTrId("cutelyst-valip-genvalerr");
251  } else {
252  //: %1 will be replaced by the field label
253  //% "The IP address in the “%1” field is invalid or not acceptable."
254  return c->qtTrId("cutelyst-valip-genvalerr-label").arg(_label);
255  }
256 }
Stores custom error messages and the input field label.
The Cutelyst Context.
Definition: context.h:42
void defaultValue(Context *c, ValidatorReturnType *result) const
bool isEmpty() const const
The Cutelyst namespace holds all public Cutelyst API.
ValidatorIp(const QString &field, Constraints constraints=NoConstraint, const ValidatorMessages &messages={}, const QString &defValKey={})
Definition: validatorip.cpp:18
Base class for all validator rules.
void validateCb(Context *c, const ParamsMultiMap &params, ValidatorRtFn cb) const override
Definition: validatorip.cpp:52
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString value(const ParamsMultiMap &params) const
QString label(const Context *c) const
std::function< void(ValidatorReturnType &&result)> ValidatorRtFn
Void callback function for validator rules that processes the ValidatorReturnType.
Definition: validatorrule.h:82
QString validationError(Context *c, const QVariant &errorData={}) const
static bool validate(const QString &value, Constraints constraints=NoConstraint)
Returns true if value is a valid IP address within the constraints.
Definition: validatorip.cpp:57
QString qtTrId(const char *id, int n=-1) const
Definition: context.h:658
Contains the result of a single input parameter validation.
Definition: validatorrule.h:52
Checks if the field value is a valid IP address.
Definition: validatorip.h:34
QString arg(Args &&... args) const const
QString genericValidationError(Context *c, const QVariant &errorData=QVariant()) const override
void setValue(QVariant &&value)