cutelyst  4.8.0
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-2023 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 
52 bool ValidatorIp::validate(const QString &value, Constraints constraints)
53 {
54  bool valid = true;
55 
56  // simple check for an IPv4 address with four parts, because QHostAddress also tolerates
57  // addresses like 192.168.2 and fills them with 0 somewhere
58  if (!value.contains(QLatin1Char(':')) && !value.contains(ValidatorIpPrivate::regex)) {
59 
60  valid = false;
61 
62  } else {
63 
64  // private IPv4 subnets
65  static const std::vector<std::pair<QHostAddress, int>> ipv4Private(
66  {// Used for local communications within a private network
67  // https://tools.ietf.org/html/rfc1918
68  {QHostAddress(QStringLiteral("10.0.0.0")), 8},
69 
70  // Used for link-local addresses between two hosts on a single link when no IP address
71  // is otherwise specified, such as would have normally been retrieved from a DHCP
72  // server https://tools.ietf.org/html/rfc3927
73  {QHostAddress(QStringLiteral("169.254.0.0")), 16},
74 
75  // Used for local communications within a private network
76  // https://tools.ietf.org/html/rfc1918
77  {QHostAddress(QStringLiteral("172.16.0.0")), 12},
78 
79  // Used for local communications within a private network
80  // https://tools.ietf.org/html/rfc1918
81  {QHostAddress(QStringLiteral("192.168.0.0")), 12}});
82 
83  // reserved IPv4 subnets
84  static const std::vector<std::pair<QHostAddress, int>> ipv4Reserved(
85  {// Used for broadcast messages to the current ("this")
86  // https://tools.ietf.org/html/rfc1700
87  {QHostAddress(QStringLiteral("0.0.0.0")), 8},
88 
89  // Used for communications between a service provider and its subscribers when using a
90  // carrier-grade NAT https://tools.ietf.org/html/rfc6598
91  {QHostAddress(QStringLiteral("100.64.0.0")), 10},
92 
93  // Used for loopback addresses to the local host
94  // https://tools.ietf.org/html/rfc990
95  {QHostAddress(QStringLiteral("127.0.0.1")), 8},
96 
97  // Used for the IANA IPv4 Special Purpose Address Registry
98  // https://tools.ietf.org/html/rfc5736
99  {QHostAddress(QStringLiteral("192.0.0.0")), 24},
100 
101  // Assigned as "TEST-NET" for use in documentation and examples. It should not be used
102  // publicly. https://tools.ietf.org/html/rfc5737
103  {QHostAddress(QStringLiteral("192.0.2.0")), 24},
104 
105  // Used by 6to4 anycast relays
106  // https://tools.ietf.org/html/rfc3068
107  {QHostAddress(QStringLiteral("192.88.99.0")), 24},
108 
109  // Used for testing of inter-network communications between two separate subnets
110  // https://tools.ietf.org/html/rfc2544
111  {QHostAddress(QStringLiteral("198.18.0.0")), 15},
112 
113  // Assigned as "TEST-NET-2" for use in documentation and examples. It should not be
114  // used publicly. https://tools.ietf.org/html/rfc5737
115  {QHostAddress(QStringLiteral("198.51.100.0")), 24},
116 
117  // Assigned as "TEST-NET-3" for use in documentation and examples. It should not be
118  // used publicly. https://tools.ietf.org/html/rfc5737
119  {QHostAddress(QStringLiteral("203.0.113.0")), 24},
120 
121  // Reserved for future use
122  // https://tools.ietf.org/html/rfc6890
123  {QHostAddress(QStringLiteral("240.0.0.0")), 4},
124 
125  // Reserved for the "limited broadcast" destination address
126  // https://tools.ietf.org/html/rfc6890
127  {QHostAddress(QStringLiteral("255.255.255.255")), 32}});
128 
129  // private IPv6 subnets
130  static const std::vector<std::pair<QHostAddress, int>> ipv6Private(
131  {// unique local address
132  {QHostAddress(QStringLiteral("fc00::")), 7},
133 
134  // link-local address
135  {QHostAddress(QStringLiteral("fe80::")), 10}});
136 
137  // reserved IPv6 subnets
138  static const std::vector<std::pair<QHostAddress, int>> ipv6Reserved(
139  {// unspecified address
140  {QHostAddress(QStringLiteral("::")), 128},
141 
142  // loopback address to the loca host
143  {QHostAddress(QStringLiteral("::1")), 128},
144 
145  // IPv4 mapped addresses
146  {QHostAddress(QStringLiteral("::ffff:0:0")), 96},
147 
148  // discard prefix
149  // https://tools.ietf.org/html/rfc6666
150  {QHostAddress(QStringLiteral("100::")), 64},
151 
152  // IPv4/IPv6 translation
153  // https://tools.ietf.org/html/rfc6052
154  {QHostAddress(QStringLiteral("64:ff9b::")), 96},
155 
156  // Teredo tunneling
157  {QHostAddress(QStringLiteral("2001::")), 32},
158 
159  // deprected (previously ORCHID)
160  {QHostAddress(QStringLiteral("2001:10::")), 28},
161 
162  // ORCHIDv2
163  {QHostAddress(QStringLiteral("2001:20::")), 28},
164 
165  // addresses used in documentation and example source code
166  {QHostAddress(QStringLiteral("2001:db8::")), 32},
167 
168  // 6to4
169  {QHostAddress(QStringLiteral("2002::")), 16}});
170 
171  QHostAddress a;
172 
173  if (a.setAddress(value)) {
174 
175  if (!constraints.testFlag(NoConstraint)) {
176 
177  if (a.protocol() == QAbstractSocket::IPv4Protocol) {
178 
179  if (constraints.testFlag(IPv6Only)) {
180  valid = false;
181  }
182 
183  if (valid && (constraints.testFlag(NoPrivateRange) ||
184  constraints.testFlag(PublicOnly))) {
185 
186  for (const std::pair<QHostAddress, int> &subnet : ipv4Private) {
187  if (a.isInSubnet(subnet.first, subnet.second)) {
188  valid = false;
189  break;
190  }
191  }
192  }
193 
194  if (valid && (constraints.testFlag(NoReservedRange) ||
195  constraints.testFlag(PublicOnly))) {
196 
197  for (const std::pair<QHostAddress, int> &subnet : ipv4Reserved) {
198  if (a.isInSubnet(subnet.first, subnet.second)) {
199  valid = false;
200  break;
201  }
202  }
203  }
204 
205  if (valid &&
206  (constraints.testFlag(NoMultiCast) || constraints.testFlag(PublicOnly))) {
207  if (a.isInSubnet(QHostAddress(QStringLiteral("224.0.0.0")), 4)) {
208  valid = false;
209  }
210  }
211 
212  } else {
213 
214  if (constraints.testFlag(IPv4Only)) {
215  valid = false;
216  }
217 
218  if (valid && (constraints.testFlag(NoPrivateRange) ||
219  constraints.testFlag(PublicOnly))) {
220 
221  for (const std::pair<QHostAddress, int> &subnet : ipv6Private) {
222  if (a.isInSubnet(subnet.first, subnet.second)) {
223  valid = false;
224  break;
225  }
226  }
227  }
228 
229  if (valid && (constraints.testFlag(NoReservedRange) ||
230  constraints.testFlag(PublicOnly))) {
231 
232  for (const std::pair<QHostAddress, int> &subnet : ipv6Reserved) {
233  if (a.isInSubnet(subnet.first, subnet.second)) {
234  valid = false;
235  break;
236  }
237  }
238  }
239 
240  if (valid &&
241  (constraints.testFlag(NoMultiCast) || constraints.testFlag(PublicOnly))) {
242  if (a.isInSubnet(QHostAddress(QStringLiteral("ff00::")), 8)) {
243  valid = false;
244  }
245  }
246  }
247  }
248 
249  } else {
250  valid = false;
251  }
252  }
253 
254  return valid;
255 }
256 
258 {
259  Q_UNUSED(errorData)
260  const QString _label = label(c);
261  if (_label.isEmpty()) {
262  //% "IP address is invalid or not acceptable."
263  return c->qtTrId("cutelyst-valip-genvalerr");
264  } else {
265  //: %1 will be replaced by the field label
266  //% "The IP address in the “%1” field is invalid or not acceptable."
267  return c->qtTrId("cutelyst-valip-genvalerr-label").arg(_label);
268  }
269 }
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.
Base class for all validator rules.
ValidatorIp(const QString &field, Constraints constraints=NoConstraint, const ValidatorMessages &messages=ValidatorMessages(), const QString &defValKey=QString())
Definition: validatorip.cpp:18
QString label(Context *c) const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString value(const ParamsMultiMap &params) const
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:52
QString qtTrId(const char *id, int n=-1) const
Definition: context.h:657
Contains the result of a single input parameter validation.
Definition: validatorrule.h:49
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)