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