OpenVPN 3 Core Library
Loading...
Searching...
No Matches
addrpair.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12#ifndef OPENVPN_ADDR_ADDRPAIR_H
13#define OPENVPN_ADDR_ADDRPAIR_H
14
15#include <charconv>
16#include <sstream>
17#include <string_view>
18#include <system_error>
19
23#include <openvpn/addr/ip.hpp>
24
25namespace openvpn::IP {
26
27// AddrMaskPair is basically an object that combines an IP address (v4 or v6)
28// with a netmask or prefix length.
30{
31 public:
32 OPENVPN_EXCEPTION(addr_pair_mask_parse_error);
33
35 {
36 public:
37 OPENVPN_SIMPLE_EXCEPTION(addr_pair_string_error);
38
40 : size_(0)
41 {
42 }
43
44 explicit StringPair(const std::string &s1)
45 : size_(1)
46 {
47 data[0] = s1;
48 }
49
50 explicit StringPair(const std::string &s1, const std::string &s2)
51 : size_(2)
52 {
53 data[0] = s1;
54 data[1] = s2;
55 }
56
57 void push_back(const std::string &s)
58 {
59 if (size_ < 2)
60 data[size_++] = s;
61 else
62 throw addr_pair_string_error();
63 }
64
65 const std::string &operator[](const size_t i) const
66 {
67 if (i >= 2)
68 throw addr_pair_string_error();
69 return data[i];
70 }
71
72 std::string &operator[](const size_t i)
73 {
74 if (i >= 2)
75 throw addr_pair_string_error();
76 return data[i];
77 }
78
79 size_t size() const
80 {
81 return size_;
82 }
83
84 std::string render() const
85 {
86 switch (size_)
87 {
88 case 1:
89 return data[0];
90 case 2:
91 return data[0] + "/" + data[1];
92 default:
93 return "";
94 }
95 }
96
97 private:
98 std::string data[2];
99 unsigned int size_;
100 };
101
102 static AddrMaskPair from_string(const std::string &s1, const std::string &s2, const char *title = nullptr)
103 {
104 try
105 {
106 if (s2.empty())
107 {
108 const auto pair = Split::by_char<StringPair, NullLex, Split::NullLimit>(s1, '/');
109 return from_string_impl(pair, title);
110 }
111
112 const StringPair pair(s1, s2);
113 return from_string_impl(pair, title);
114 }
115 catch (const std::exception &e)
116 {
117 const StringPair pair(s1, s2);
118 error(e, pair.render(), title);
119 }
120 return {}; // NOTREACHED
121 }
122
123 static AddrMaskPair from_string(const std::string &s, const char *title = nullptr)
124 {
125 try
126 {
127 const auto pair = Split::by_char<StringPair, NullLex, Split::NullLimit>(s, '/');
128 return from_string_impl(pair, title);
129 }
130 catch (const std::exception &e)
131 {
132 error(e, s, title);
133 }
134 return {}; // NOTREACHED
135 }
136
137 static AddrMaskPair from_string(const StringPair &pair, const char *title = nullptr)
138 {
139 try
140 {
141 return from_string_impl(pair, title);
142 }
143 catch (const std::exception &e)
144 {
145 error(e, pair.render(), title);
146 }
147 return {}; // NOTREACHED
148 }
149
150 std::string to_string(const bool netmask_form = false) const
151 {
152 return netmask_form ? addr.to_string() + '/' + netmask.to_string()
153 : addr.to_string() + '/' + std::to_string(netmask.prefix_len());
154 }
155
156 bool is_canonical() const
157 {
158 return (addr & netmask) == addr;
159 }
160
162 {
163 return addr.version() == netmask.version() ? addr.version() : Addr::UNSPEC;
164 }
165
168
169 private:
170 static void error(const std::exception &e, const std::string &s, const char *title)
171 {
172 if (!title)
173 title = "";
174 OPENVPN_THROW(addr_pair_mask_parse_error, "AddrMaskPair parse error '" << title << "': " << s << " : " << e.what());
175 }
176
183 static unsigned int parse_prefix_len_throw(std::string_view s)
184 {
185 unsigned int val = 0;
186 const auto [ptr, ec] = std::from_chars(s.data(), s.data() + s.size(), val);
187
188 // ec catches overflow (result_out_of_range) and invalid format (invalid_argument);
189 // ptr check ensures complete string consumption. The widest-address bound keeps the
190 // parse away from the overflow that defeats netmask_from_prefix_len's own range guard,
191 // which still applies the per-version bound.
192 if (ec != std::errc{} || ptr != s.data() + s.size() || val > Addr::V6_SIZE)
193 {
194 throw number_parse_exception("prefix length");
195 }
196 return val;
197 }
198
199 static AddrMaskPair from_string_impl(const StringPair &pair, const char *title = nullptr)
200 {
201 AddrMaskPair ret;
202 if (pair.size() == 1 || pair.size() == 2)
203 {
204 ret.addr = Addr::from_string(pair[0], title);
205 if (pair.size() == 2 && !pair[1].empty())
206 {
207 if (is_number(pair[1].c_str()))
209 parse_prefix_len_throw(pair[1]));
210 else
211 ret.netmask = Addr::from_string(pair[1]);
212 ret.netmask.prefix_len(); // verify that netmask is ok
213 }
214 else
217 }
218 else
219 throw addr_pair_mask_parse_error("only one or two address terms allowed");
220 return ret;
221 }
222};
223OPENVPN_OSTREAM(AddrMaskPair, to_string)
224} // namespace openvpn::IP
225
226#endif
std::string & operator[](const size_t i)
Definition addrpair.hpp:72
void push_back(const std::string &s)
Definition addrpair.hpp:57
OPENVPN_SIMPLE_EXCEPTION(addr_pair_string_error)
StringPair(const std::string &s1)
Definition addrpair.hpp:44
const std::string & operator[](const size_t i) const
Definition addrpair.hpp:65
StringPair(const std::string &s1, const std::string &s2)
Definition addrpair.hpp:50
static Addr from_string(const std::string &ipstr, const TITLE &title, const Version required_version)
Definition ip.hpp:105
Version version() const
Definition ip.hpp:895
void verify_version_consistency(const Addr &other) const
Definition ip.hpp:954
std::string to_string() const
Definition ip.hpp:528
static Addr netmask_from_prefix_len(Version v, const unsigned int prefix_len)
Definition ip.hpp:502
unsigned int prefix_len() const
Definition ip.hpp:968
static Addr from_zero_complement(const Version v)
Definition ip.hpp:478
#define OPENVPN_THROW(exc, stuff)
bool is_number(std::string_view str)
Definition number.hpp:124
#define OPENVPN_OSTREAM(TYPE, METH)
Definition ostream.hpp:21
static AddrMaskPair from_string(const StringPair &pair, const char *title=nullptr)
Definition addrpair.hpp:137
static void error(const std::exception &e, const std::string &s, const char *title)
Definition addrpair.hpp:170
std::string to_string(const bool netmask_form=false) const
Definition addrpair.hpp:150
OPENVPN_EXCEPTION(addr_pair_mask_parse_error)
static AddrMaskPair from_string(const std::string &s1, const std::string &s2, const char *title=nullptr)
Definition addrpair.hpp:102
static AddrMaskPair from_string_impl(const StringPair &pair, const char *title=nullptr)
Definition addrpair.hpp:199
static AddrMaskPair from_string(const std::string &s, const char *title=nullptr)
Definition addrpair.hpp:123
Addr::Version version() const
Definition addrpair.hpp:161
static unsigned int parse_prefix_len_throw(std::string_view s)
Parses an IP prefix length from a string view.
Definition addrpair.hpp:183