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