forked from OpenVPN/openvpn3
-
Notifications
You must be signed in to change notification settings - Fork 0
/
peerinfo.hpp
170 lines (149 loc) · 5.08 KB
/
peerinfo.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2022 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
// These objects are primary concerned with generating the Peer Info on the
// client side before transmission to server. For the reverse case (parsing
// the Peer Info on the server) we normally use an OptionList.
#ifndef OPENVPN_SSL_PEERINFO_H
#define OPENVPN_SSL_PEERINFO_H
#include <string>
#include <vector>
#include <openvpn/common/rc.hpp>
#include <openvpn/common/string.hpp>
#include <openvpn/common/file.hpp>
#include <openvpn/common/split.hpp>
#include <openvpn/common/unicode.hpp>
#include <openvpn/common/jsonlib.hpp>
#ifdef HAVE_JSON
#include <openvpn/common/jsonhelper.hpp>
#endif
namespace openvpn {
namespace PeerInfo {
OPENVPN_EXCEPTION(peer_info_error);
struct KeyValue
{
KeyValue(const std::string &key_arg, const std::string &value_arg)
: key(key_arg),
value(value_arg)
{
}
std::string key;
std::string value;
std::string to_string() const
{
return key + '=' + value;
}
};
struct Set : public std::vector<KeyValue>, public RCCopyable<thread_unsafe_refcount>
{
typedef RCPtr<Set> Ptr;
template <typename SET>
static Ptr new_from_foreign_set(const SET &other)
{
Ptr sp = new Set();
for (const auto &kv : other)
sp->emplace_back(kv.key, kv.value);
return sp;
}
template <typename SET>
void append_foreign_set_ptr(const SET *other)
{
if (other)
for (const auto &kv : *other)
emplace_back(kv.key, kv.value);
}
template <typename SET>
void append_foreign_set_ref(const SET &other)
{
for (const auto &kv : other)
emplace_back(kv.key, kv.value);
}
Ptr copy() const
{
return new Set(*this);
}
// src may be comma-separated key=value pairs or @filename, where
// filename contains a JSON dictionary of key/value pairs.
template <typename SET>
static void parse_flexible(const std::string &src, SET &dest)
{
if (src.length() >= 1 && src[0] == '@')
{
const std::string fn = src.substr(1);
#ifdef OPENVPN_JSON_INTERNAL
const Json::Value root = json::parse_from_file(fn);
parse_json(root, dest, fn);
#else
OPENVPN_THROW(peer_info_error, fn << ": JSON library not available");
#endif
}
else
parse_csv(src, dest);
}
// Parse src in the form K1=V1,K2=V2,...
template <typename SET>
static void parse_csv(const std::string &src, SET &dest)
{
if (!string::is_empty(src))
{
if (string::is_multiline(src))
OPENVPN_THROW(peer_info_error, "key/value list must be a single line: " << Unicode::utf8_printable(src, 256));
const auto list = Split::by_char<std::vector<std::string>, StandardLex, Split::NullLimit>(src, ',', Split::TRIM_LEADING_SPACES | Split::TRIM_SPECIAL);
for (const auto &kvstr : list)
{
const auto kv = Split::by_char<std::vector<std::string>, StandardLex, Split::NullLimit>(kvstr, '=', 0, 1);
if (kv.size() == 2)
dest.emplace_back(kv[0], kv[1]);
else
OPENVPN_THROW(peer_info_error, "key/value must be in the form K=V, not: " << Unicode::utf8_printable(kvstr, 256));
}
}
}
#ifdef OPENVPN_JSON_INTERNAL
template <typename SET>
static void parse_json(const Json::Value &src, SET &dest, const std::string &title)
{
if (!src.isObject())
OPENVPN_THROW(peer_info_error, title << ": top level JSON object must be a dictionary");
auto m = src.asObject();
for (auto &e : m)
{
if (e.second.isString())
dest.emplace_back(e.first, e.second.asStringRef());
else
dest.emplace_back(e.first, e.second.toCompactString());
}
}
#endif
std::string to_string() const
{
std::string ret;
ret.reserve(256);
for (const auto &kv : *this)
{
ret += kv.to_string();
ret += '\n';
}
return ret;
}
};
} // namespace PeerInfo
} // namespace openvpn
#endif