Kea: client_attribute.cc Source File

| Kea 3.2.0-git

client_attribute.cc
Go to the documentation of this file.
1// Copyright (C) 2023-2026 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <client_attribute.h>
10#include <radius_log.h>
11#include <util/encode/encode.h>
12#include <util/str.h>
13#include <boost/lexical_cast.hpp>
14#include <cctype>
15#include <limits>
16#include <sstream>
17
18using namespace isc;
19using namespace isc::asiolink;
20using namespace isc::data;
21using namespace isc::util;
22using namespace std;
23
24namespace isc {
25namespace radius {
26
27 AttributePtr
28Attribute::fromText(const AttrDefPtr& def, const string& value) {
29 if (!def) {
30 isc_throw(BadValue, "null attribute definition");
31 }
32 if (value.empty()) {
33 isc_throw(BadValue, "empty attribute value");
34 }
35 AttributePtr attr = fromText0(def, value);
36 if (def->vendor_ == 0) {
37 return (attr);
38 }
39 // Encapsulate into a Vendor-Specific attribute.
40 const vector<uint8_t> vsa_data = attr->toBytes();
41 return (fromVsa(PW_VENDOR_SPECIFIC, def->vendor_, vsa_data));
42}
43
44 AttributePtr
45Attribute::fromText0(const AttrDefPtr& def, const string& value) {
46 switch (static_cast<uint8_t>(def->value_type_)) {
47 case PW_TYPE_STRING:
48 return (AttrString::fromText(def->type_, value));
49 case PW_TYPE_INTEGER:
50 if (!isdigit(value[0])) {
51 IntCstDefPtr ic_def =
52 AttrDefs::instance().getByName(def->type_, value,
53 def->vendor_);
54 if (ic_def) {
55 return (fromInt(def->type_, ic_def->value_));
56 }
57 }
58 return (AttrInt::fromText(def->type_, value));
59 case PW_TYPE_IPADDR:
60 return (AttrIpAddr::fromText(def->type_, value));
61 case PW_TYPE_IPV6ADDR:
62 return (AttrIpv6Addr::fromText(def->type_, value));
63 case PW_TYPE_IPV6PREFIX:
64 return (AttrIpv6Prefix::fromText(def->type_, value));
65 case PW_TYPE_VSA:
66 return (AttrVsa::fromText(def->type_, value));
67 default:
68 // Impossible case.
69 isc_throw(OutOfRange, "unknown value type "
70 << static_cast<unsigned>(def->value_type_));
71 }
72}
73
74 AttributePtr
75Attribute::fromBytes(const vector<uint8_t>& bytes) {
76 // Checked by caller.
77 if (bytes.size() < 2) {
78 isc_throw(BadValue, "too short byte argument");
79 }
80 uint8_t type = bytes[0];
81 uint8_t len = bytes[1];
82 // Checked by caller.
83 if (len != bytes.size()) {
84 isc_throw(BadValue, "bad byte argument length " << bytes.size()
85 << " != " << static_cast<unsigned>(len));
86 }
87 vector<uint8_t> value;
88 value.resize(len - 2);
89 if (value.size() > 0) {
90 memmove(&value[0], &bytes[2], value.size());
91 }
92 AttrDefPtr def = AttrDefs::instance().getByType(type);
93 if (!def) {
94 return (AttributePtr());
95 }
96 return (Attribute::fromBytes(def, value));
97}
98
99 AttributePtr
100 Attribute::fromBytes(const AttrDefPtr& def, const vector<uint8_t>& value) {
101 if (!def) {
102 isc_throw(BadValue, "null attribute definition");
103 }
104 if (value.empty()) {
105 isc_throw(BadValue, "empty attribute value");
106 }
107 AttributePtr attr = fromBytes0(def, value);
108 if (def->vendor_ == 0) {
109 return (attr);
110 }
111 // Encapsulate into a Vendor-Specific attribute.
112 const vector<uint8_t> vsa_data = attr->toBytes();
113 return (fromVsa(PW_VENDOR_SPECIFIC, def->vendor_, vsa_data));
114}
115
116 AttributePtr
117Attribute::fromBytes0(const AttrDefPtr& def, const vector<uint8_t>& value) {
118 switch (static_cast<uint8_t>(def->value_type_)) {
119 case PW_TYPE_STRING:
120 return (AttrString::fromBytes(def->type_, value));
121 case PW_TYPE_INTEGER:
122 return (AttrInt::fromBytes(def->type_, value));
123 case PW_TYPE_IPADDR:
124 return (AttrIpAddr::fromBytes(def->type_, value));
125 case PW_TYPE_IPV6ADDR:
126 return (AttrIpv6Addr::fromBytes(def->type_, value));
127 case PW_TYPE_IPV6PREFIX:
128 return (AttrIpv6Prefix::fromBytes(def->type_, value));
129 case PW_TYPE_VSA:
130 return (AttrVsa::fromBytes(def->type_, value));
131 default:
132 // Impossible case.
133 isc_throw(OutOfRange, "unknown value type "
134 << static_cast<unsigned>(def->value_type_));
135 }
136}
137
138 AttributePtr
139Attribute::fromString(const uint8_t type, const string& value) {
140 if (value.empty()) {
141 isc_throw(BadValue, "empty attribute value");
142 }
143 return (AttributePtr(new AttrString(type, value)));
144}
145
146 AttributePtr
147Attribute::fromBinary(const uint8_t type, const vector<uint8_t>& value) {
148 if (value.empty()) {
149 isc_throw(BadValue, "empty attribute value");
150 }
151 return (AttributePtr(new AttrString(type, value)));
152}
153
154 AttributePtr
155Attribute::fromInt(const uint8_t type, const uint32_t value) {
156 return (AttributePtr(new AttrInt(type, value)));
157}
158
159 AttributePtr
160Attribute::fromIpAddr(const uint8_t type, const IOAddress& value) {
161 return (AttributePtr(new AttrIpAddr(type, value)));
162}
163
164 AttributePtr
165Attribute::fromIpv6Addr(const uint8_t type, const IOAddress& value) {
166 return (AttributePtr(new AttrIpv6Addr(type, value)));
167}
168
169 AttributePtr
170Attribute::fromIpv6Prefix(const uint8_t type, const uint8_t len,
171 const IOAddress& value) {
172 return (AttributePtr(new AttrIpv6Prefix(type, len, value)));
173}
174
175 AttributePtr
176Attribute::fromVsa(const uint8_t type, const uint32_t vendor,
177 const std::string& value) {
178 return (AttributePtr(new AttrVsa(type, vendor, value)));
179}
180
181 AttributePtr
182 Attribute::fromVsa(const uint8_t type, const uint32_t vendor,
183 const std::vector<uint8_t>& value) {
184 return (AttributePtr(new AttrVsa(type, vendor, value)));
185}
186
187string
188Attribute::toString() const {
189 isc_throw(TypeError, "the attribute value type must be string, not "
190 << attrValueTypeToText(getValueType()));
191}
192
193vector<uint8_t>
194Attribute::toBinary() const {
195 isc_throw(TypeError, "the attribute value type must be string, not "
196 << attrValueTypeToText(getValueType()));
197}
198
199uint32_t
200Attribute::toInt() const {
201 isc_throw(TypeError, "the attribute value type must be integer, not "
202 << attrValueTypeToText(getValueType()));
203}
204
205 IOAddress
206Attribute::toIpAddr() const {
207 isc_throw(TypeError, "the attribute value type must be ipaddr, not "
208 << attrValueTypeToText(getValueType()));
209}
210
211 IOAddress
212Attribute::toIpv6Addr() const {
213 isc_throw(TypeError, "the attribute value type must be ipv6addr, not "
214 << attrValueTypeToText(getValueType()));
215}
216
217 IOAddress
218Attribute::toIpv6Prefix() const {
219 isc_throw(TypeError, "the attribute value type must be ipv6prefix, not "
220 << attrValueTypeToText(getValueType()));
221}
222
223uint8_t
224Attribute::toIpv6PrefixLen() const {
225 isc_throw(TypeError, "the attribute value type must be ipv6prefix, not "
226 << attrValueTypeToText(getValueType()));
227}
228
229uint32_t
230Attribute::toVendorId() const {
231 isc_throw(TypeError, "the attribute value type must be vsa, not "
232 << attrValueTypeToText(getValueType()));
233}
234
235std::vector<uint8_t>
236Attribute::toVsaData() const {
237 isc_throw(TypeError, "the attribute value type must be vsa, not "
238 << attrValueTypeToText(getValueType()));
239}
240
241 AttrString::AttrString(const uint8_t type, const vector<uint8_t>& value)
242 : Attribute(type), value_() {
243 if (value.empty()) {
244 isc_throw(BadValue, "value is empty");
245 }
246 if (value.size() > MAX_STRING_LEN) {
247 isc_throw(BadValue, "value is too large " << value.size()
248 << " > " << MAX_STRING_LEN);
249 }
250 value_.resize(value.size());
251 memmove(&value_[0], &value[0], value_.size());
252}
253
254 AttributePtr
255AttrString::fromText(const uint8_t type, const string& repr) {
256 if (repr.empty()) {
257 isc_throw(BadValue, "empty attribute value");
258 }
259 if (repr.size() > MAX_STRING_LEN) {
260 isc_throw(BadValue, "value is too large " << repr.size()
261 << " > " << MAX_STRING_LEN);
262 }
263 return (AttributePtr(new AttrString(type, repr)));
264}
265
266 AttributePtr
267AttrString::fromBytes(const uint8_t type, const vector<uint8_t>& bytes) {
268 if (bytes.empty()) {
269 isc_throw(BadValue, "empty attribute value");
270 }
271 if (bytes.size() > MAX_STRING_LEN) {
272 isc_throw(BadValue, "value is too large " << bytes.size()
273 << " > " << MAX_STRING_LEN);
274 }
275 return (AttributePtr(new AttrString(type, bytes)));
276}
277
278string
279AttrString::toText(size_t indent) const {
280 ostringstream output;
281 for (size_t i = 0; i < indent; i++) {
282 output << " ";
283 }
284 output << AttrDefs::instance().getName(getType()) << '=';
285 if (str::isPrintable(value_)) {
286 output << "'" << value_ << "'";
287 } else {
288 vector<uint8_t> binary;
289 binary.resize(value_.size());
290 if (binary.size() > 0) {
291 memmove(&binary[0], value_.c_str(), binary.size());
292 }
293 output << "0x" << encode::encodeHex(binary);
294 }
295 return (output.str());
296}
297
298vector<uint8_t>
299AttrString::toBytes() const {
300 vector<uint8_t> output;
301 output.resize(2 + getValueLen());
302 output[0] = getType();
303 output[1] = 2 + getValueLen();
304 if (output.size() > 2) {
305 memmove(&output[2], &value_[0], output.size() - 2);
306 }
307 return (output);
308}
309
310vector<uint8_t>
311AttrString::toBinary() const {
312 vector<uint8_t> binary;
313 binary.resize(getValueLen());
314 if (binary.size() > 0) {
315 memmove(&binary[0], &value_[0], binary.size());
316 }
317 return (binary);
318}
319
320 ElementPtr
321AttrString::toElement() const {
322 ElementPtr output = Element::createMap();
323 AttrDefPtr def = AttrDefs::instance().getByType(getType());
324 if (def) {
325 output->set("name", Element::create(def->name_));
326 }
327 output->set("type", Element::create(static_cast<int>(getType())));
328 if (str::isPrintable(value_)) {
329 output->set("data", Element::create(value_));
330 } else {
331 vector<uint8_t> binary;
332 binary.resize(value_.size());
333 if (binary.size() > 0) {
334 memmove(&binary[0], value_.c_str(), binary.size());
335 }
336 string raw = encode::encodeHex(binary);
337 output->set("raw", Element::create(raw));
338 }
339 return (output);
340}
341
342 AttributePtr
343AttrInt::fromText(const uint8_t type, const string& repr) {
344 if (repr.empty()) {
345 isc_throw(BadValue, "empty attribute value");
346 }
347 try {
348 int64_t val = boost::lexical_cast<int64_t>(repr);
349 if ((val < numeric_limits<int32_t>::min()) ||
350 (val > numeric_limits<uint32_t>::max())) {
351 isc_throw(BadValue, "not 32 bit " << repr);
352 }
353 return (AttributePtr(new AttrInt(type, static_cast<uint32_t>(val))));
354 } catch (...) {
355 LOG_ERROR(radius_logger, RADIUS_INTEGER_ATTRIBUTE_FROM_TEXT_FAILED)
356 .arg(unsigned(type))
357 .arg(AttrDefs::instance().getName(type))
358 .arg(repr);
359 throw;
360 }
361}
362
363 AttributePtr
364AttrInt::fromBytes(const uint8_t type, const vector<uint8_t>& bytes) {
365 if (bytes.size() != 4) {
366 ostringstream msg;
367 msg << "bad value length " << bytes.size() << " != 4";
368 LOG_ERROR(radius_logger, RADIUS_INTEGER_ATTRIBUTE_FROM_BYTES_FAILED)
369 .arg(unsigned(type))
370 .arg(AttrDefs::instance().getName(type))
371 .arg(msg.str());
372 isc_throw(BadValue, msg.str());
373 }
374 int32_t val = (static_cast<int32_t>(bytes[0])) << 24;
375 val |= (static_cast<int32_t>(bytes[1])) << 16;
376 val |= (static_cast<int32_t>(bytes[2])) << 8;
377 val |= static_cast<int32_t>(bytes[3]);
378 return (AttributePtr(new AttrInt(type, val)));
379}
380
381string
382AttrInt::toText(size_t indent) const {
383 ostringstream output;
384 for (size_t i = 0; i < indent; i++) {
385 output << " ";
386 }
387 output << AttrDefs::instance().getName(getType()) << '=';
388 IntCstDefPtr ic_def = AttrDefs::instance().getByValue(getType(), value_);
389 if (ic_def) {
390 output << ic_def->name_;
391 } else {
392 output << value_;
393 }
394 return (output.str());
395}
396
397vector<uint8_t>
398AttrInt::toBytes() const {
399 vector<uint8_t> output;
400 output.resize(6);
401 output[0] = getType();
402 output[1] = 6;
403 output[2] = static_cast<uint8_t>((value_ & 0xff000000U) >> 24);
404 output[3] = static_cast<uint8_t>((value_ & 0xff0000U) >> 16);
405 output[4] = static_cast<uint8_t>((value_ & 0xff00U) >> 8);
406 output[5] = static_cast<uint8_t>(value_ & 0xffU);
407 return (output);
408}
409
410 ElementPtr
411AttrInt::toElement() const {
412 ElementPtr output = Element::createMap();
413 AttrDefPtr def = AttrDefs::instance().getByType(getType());
414 if (def) {
415 output->set("name", Element::create(def->name_));
416 }
417 output->set("type", Element::create(static_cast<int>(getType())));
418 ostringstream val;
419 val << value_;
420 output->set("data", Element::create(val.str()));
421 return (output);
422}
423
424 AttributePtr
425AttrIpAddr::fromText(const uint8_t type, const string& repr) {
426 try {
427 IOAddress val(repr);
428 return (AttributePtr(new AttrIpAddr(type, val)));
429 } catch (...) {
430 LOG_ERROR(radius_logger, RADIUS_IPADDR_ATTRIBUTE_FROM_TEXT_FAILED)
431 .arg(unsigned(type))
432 .arg(AttrDefs::instance().getName(type))
433 .arg(repr);
434 throw;
435 }
436}
437
438 AttributePtr
439AttrIpAddr::fromBytes(const uint8_t type, const vector<uint8_t>& bytes) {
440 if (bytes.size() != 4) {
441 ostringstream msg;
442 msg << "bad value length " << bytes.size() << " != 4";
443 LOG_ERROR(radius_logger, RADIUS_IPADDR_ATTRIBUTE_FROM_BYTES_FAILED)
444 .arg(unsigned(type))
445 .arg(AttrDefs::instance().getName(type))
446 .arg(msg.str());
447 isc_throw(BadValue, msg.str());
448 }
449 IOAddress val = IOAddress::fromBytes(AF_INET, &bytes[0]);
450 return (AttributePtr(new AttrIpAddr(type, val)));
451}
452
453string
454AttrIpAddr::toText(size_t indent) const {
455 ostringstream output;
456 for (size_t i = 0; i < indent; i++) {
457 output << " ";
458 }
459 output << AttrDefs::instance().getName(getType()) << '='
460 << value_.toText();
461 return (output.str());
462}
463
464vector<uint8_t>
465AttrIpAddr::toBytes() const {
466 vector<uint8_t> output;
467 output.resize(6);
468 output[0] = getType();
469 output[1] = 6;
470 vector<uint8_t> binary = value_.toBytes();
471 memmove(&output[2], &binary[0], output.size() - 2);
472 return (output);
473}
474
475 ElementPtr
476AttrIpAddr::toElement() const {
477 ElementPtr output = Element::createMap();
478 AttrDefPtr def = AttrDefs::instance().getByType(getType());
479 if (def) {
480 output->set("name", Element::create(def->name_));
481 }
482 output->set("type", Element::create(static_cast<int>(getType())));
483 ostringstream val;
484 val << value_.toText();
485 output->set("data", Element::create(val.str()));
486 return (output);
487}
488
489 AttributePtr
490AttrIpv6Addr::fromText(const uint8_t type, const string& repr) {
491 try {
492 IOAddress val(repr);
493 return (AttributePtr(new AttrIpv6Addr(type, val)));
494 } catch (...) {
495 LOG_ERROR(radius_logger, RADIUS_IPV6ADDR_ATTRIBUTE_FROM_TEXT_FAILED)
496 .arg(unsigned(type))
497 .arg(AttrDefs::instance().getName(type))
498 .arg(repr);
499 throw;
500 }
501}
502
503 AttributePtr
504AttrIpv6Addr::fromBytes(const uint8_t type, const vector<uint8_t>& bytes) {
505 if (bytes.size() != 16) {
506 ostringstream msg;
507 msg << "bad value length " << bytes.size() << " != 16";
508 LOG_ERROR(radius_logger, RADIUS_IPV6ADDR_ATTRIBUTE_FROM_BYTES_FAILED)
509 .arg(unsigned(type))
510 .arg(AttrDefs::instance().getName(type))
511 .arg(msg.str());
512 isc_throw(BadValue, msg.str());
513 }
514 IOAddress val = IOAddress::fromBytes(AF_INET6, &bytes[0]);
515 return (AttributePtr(new AttrIpv6Addr(type, val)));
516}
517
518string
519AttrIpv6Addr::toText(size_t indent) const {
520 ostringstream output;
521 for (size_t i = 0; i < indent; i++) {
522 output << " ";
523 }
524 output << AttrDefs::instance().getName(getType()) << '='
525 << value_.toText();
526 return (output.str());
527}
528
529vector<uint8_t>
530AttrIpv6Addr::toBytes() const {
531 vector<uint8_t> output;
532 output.resize(18);
533 output[0] = getType();
534 output[1] = 18;
535 vector<uint8_t> binary = value_.toBytes();
536 memmove(&output[2], &binary[0], output.size() - 2);
537 return (output);
538}
539
540 ElementPtr
541AttrIpv6Addr::toElement() const {
542 ElementPtr output = Element::createMap();
543 AttrDefPtr def = AttrDefs::instance().getByType(getType());
544 if (def) {
545 output->set("name", Element::create(def->name_));
546 }
547 output->set("type", Element::create(static_cast<int>(getType())));
548 ostringstream val;
549 val << value_.toText();
550 output->set("data", Element::create(val.str()));
551 return (output);
552}
553
554 AttributePtr
555AttrIpv6Prefix::fromText(const uint8_t type, const string& repr) {
556 try {
557 auto pos = repr.find('/');
558 if ((pos == string::npos) ||
559 (pos == repr.size() - 1) ||
560 (pos == 0)) {
561 isc_throw(BadValue, "unable to parse prefix " << repr);
562 }
563 IOAddress val(repr.substr(0, pos));
564 int len = boost::lexical_cast<int>(repr.substr(pos + 1));
565 if ((len < numeric_limits<uint8_t>::min()) ||
566 (len > numeric_limits<uint8_t>::max())) {
567 isc_throw(BadValue, "not 8 bit prefix length " << repr);
568 }
569 return (AttributePtr(new AttrIpv6Prefix(type,
570 static_cast<uint8_t>(len),
571 val)));
572 } catch (...) {
573 LOG_ERROR(radius_logger, RADIUS_IPV6PREFIX_ATTRIBUTE_FROM_TEXT_FAILED)
574 .arg(unsigned(type))
575 .arg(AttrDefs::instance().getName(type))
576 .arg(repr);
577 throw;
578 }
579}
580
581 AttributePtr
582AttrIpv6Prefix::fromBytes(const uint8_t type, const vector<uint8_t>& bytes) {
584 ostringstream msg;
585 if (bytes.size() < 2) {
586 msg << "bad value length " << bytes.size() << " < 2";
587 } else if (bytes.size() > 18) {
588 msg << "bad value length " << bytes.size() << " > 18";
589 } else if (bytes[1] > 128) {
590 msg << "bad prefix length " << static_cast<unsigned>(bytes[1]) << " > 128";
591 }
592 string const msg_str(msg.str());
593 if (!msg_str.empty()) {
594 LOG_ERROR(radius_logger, RADIUS_IPV6PREFIX_ATTRIBUTE_FROM_BYTES_FAILED)
595 .arg(static_cast<unsigned>(type))
596 .arg(AttrDefs::instance().getName(type))
597 .arg(msg.str());
598 isc_throw(BadValue, msg_str);
599 }
600 uint8_t len = bytes[1];
601 vector<uint8_t> prefix(16);
602 if (bytes.size() > 2) {
603 memmove(&prefix[0], &bytes[2], bytes.size() - 2);
604 }
605 IOAddress val = IOAddress::fromBytes(AF_INET6, &prefix[0]);
606 return (AttributePtr(new AttrIpv6Prefix(type, len, val)));
607}
608
609string
610AttrIpv6Prefix::toText(size_t indent) const {
611 ostringstream output;
612 for (size_t i = 0; i < indent; i++) {
613 output << " ";
614 }
615 output << AttrDefs::instance().getName(getType()) << '='
616 << value_.toText() << "/" << static_cast<unsigned>(len_);
617 return (output.str());
618}
619
620vector<uint8_t>
621AttrIpv6Prefix::toBytes() const {
622 vector<uint8_t> output;
623 // type(1) + length(1) + reserved(1) + prefix_len(1) + prefix(16)
624 output.resize(20);
625 output[0] = getType();
626 output[1] = 20;
627 output[2] = 0;
628 output[3] = len_;
629 vector<uint8_t> binary = value_.toBytes();
630 memmove(&output[4], &binary[0], output.size() - 4);
631 return (output);
632}
633
634 ElementPtr
635AttrIpv6Prefix::toElement() const {
636 ElementPtr output = Element::createMap();
637 AttrDefPtr def = AttrDefs::instance().getByType(getType());
638 if (def) {
639 output->set("name", Element::create(def->name_));
640 }
641 output->set("type", Element::create(static_cast<int>(getType())));
642 ostringstream val;
643 val << value_.toText() << "/" << static_cast<unsigned>(len_);
644 output->set("data", Element::create(val.str()));
645 return (output);
646}
647
648 AttrVsa::AttrVsa(const uint8_t type, const uint32_t vendor,
649 const vector<uint8_t>& value)
650 : Attribute(type), vendor_(vendor), value_() {
651 if (value.empty()) {
652 isc_throw(BadValue, "value is empty");
653 }
654 if (value.size() > MAX_VSA_DATA_LEN) {
655 isc_throw(BadValue, "value is too large " << value.size()
656 << " > " << MAX_VSA_DATA_LEN);
657 }
658 value_.resize(value.size());
659 memmove(&value_[0], &value[0], value_.size());
660}
661
662 AttributePtr
663AttrVsa::fromText(const uint8_t /* type */, const string& /* repr */) {
664 isc_throw(NotImplemented, "can't decode vsa from text");
665}
666
667 AttributePtr
668AttrVsa::fromBytes(const uint8_t type, const vector<uint8_t>& bytes) {
669 if (bytes.empty()) {
670 isc_throw(BadValue, "empty attribute value");
671 }
672 if (bytes.size() < 5) {
673 isc_throw(BadValue, "value is too small " << bytes.size() << " < 5");
674 } else if (bytes.size() > MAX_STRING_LEN) {
675 isc_throw(BadValue, "value is too large " << bytes.size()
676 << " > " << MAX_STRING_LEN);
677 }
678 uint32_t vendor = bytes[0] << 24;
679 vendor |= bytes[1] << 16;
680 vendor |= bytes[2] << 8;
681 vendor |= bytes[3];
682 vector<uint8_t> value;
683 value.resize(bytes.size() - 4);
684 if (value.size() > 0) {
685 memmove(&value[0], &bytes[4], value.size());
686 }
687 return (AttributePtr(new AttrVsa(type, vendor, value)));
688}
689
690string
691AttrVsa::toText(size_t indent) const {
692 ostringstream output;
693 for (size_t i = 0; i < indent; i++) {
694 output << " ";
695 }
696 output << AttrDefs::instance().getName(getType()) << "=["
697 << vendor_ << "]";
698 vector<uint8_t> binary;
699 binary.resize(value_.size());
700 if (binary.size() > 0) {
701 memmove(&binary[0], value_.c_str(), binary.size());
702 }
703 output << "0x" << encode::encodeHex(binary);
704 return (output.str());
705}
706
707std::vector<uint8_t>
708AttrVsa::toBytes() const {
709 vector<uint8_t> output;
710 output.resize(2 + getValueLen());
711 output[0] = getType();
712 output[1] = 2 + getValueLen();
713 output[2] = (vendor_ & 0xff000000U) >> 24;
714 output[3] = (vendor_ & 0xff0000U) >> 16;
715 output[4] = (vendor_ & 0xff00U) >> 8;
716 output[5] = vendor_ & 0xffU;
717 if (output.size() > 6) {
718 memmove(&output[6], &value_[0], output.size() - 6);
719 }
720 return (output);
721}
722
723std::vector<uint8_t>
724AttrVsa::toVsaData() const {
725 vector<uint8_t> binary;
726 binary.resize(value_.size());
727 if (binary.size() > 0) {
728 memmove(&binary[0], &value_[0], binary.size());
729 }
730 return (binary);
731}
732
733 ElementPtr
734AttrVsa::toElement() const {
735 ElementPtr output = Element::createMap();
736 AttrDefPtr def = AttrDefs::instance().getByType(getType());
737 if (def) {
738 output->set("name", Element::create(def->name_));
739 }
740 output->set("type", Element::create(static_cast<int>(getType())));
741 ostringstream vendor;
742 vendor << vendor_;
743 output->set("vendor", Element::create(vendor.str()));
744 vector<uint8_t> binary;
745 binary.resize(value_.size());
746 if (binary.size() > 0) {
747 memmove(&binary[0], value_.c_str(), binary.size());
748 }
749 string raw = encode::encodeHex(binary);
750 output->set("vsa-raw", Element::create(raw));
751 return (output);
752}
753
754void
755Attributes::add(const ConstAttributePtr& attr, bool back) {
756 if (!attr) {
757 return;
758 }
759 if (back) {
760 static_cast<void>(container_.push_back(attr));
761 } else {
762 static_cast<void>(container_.push_front(attr));
763 }
764}
765
766bool
767Attributes::del(const uint8_t type) {
768 auto& idx = container_.get<1>();
769 auto it = idx.find(type);
770 if (it != idx.end()) {
771 idx.erase(it);
772 return (true);
773 }
774 return (false);
775}
776
777void
778Attributes::append(const Attributes& other) {
779 for (auto const& it : other) {
780 add(it);
781 }
782}
783
784size_t
785Attributes::count(const uint8_t type) const {
786 auto const& idx = container_.get<1>();
787 return (idx.count(type));
788}
789
790 ConstAttributePtr
791Attributes::get(const uint8_t type) const {
792 auto const& idx = container_.get<1>();
793 auto it = idx.find(type);
794 if (it != idx.end()) {
795 return (*it);
796 } else {
797 return(ConstAttributePtr());
798 }
799}
800
801string
802Attributes::toText(size_t indent) const {
803 ostringstream output;
804 bool first = true;
805 for (auto const& it : *this) {
806 if (!first) {
807 output << ",\n";
808 } else {
809 first = false;
810 }
811 output << it->toText(indent);
812 }
813 return (output.str());
814}
815
816 ElementPtr
817Attributes::toElement() const {
818 ElementPtr output = Element::createList();
819 for (auto const& it : *this) {
820 output->add(it->toElement());
821 }
822 return (output);
823}
824
825 Attributes
826Attributes::fromElement(const ConstElementPtr& attr_list) {
827 Attributes attrs;
828 if (!attr_list || (attr_list->getType() != Element::list)) {
829 return (attrs);
830 }
831 for (auto const& entry : attr_list->listValue()) {
832 if (!entry || (entry->getType() != Element::map)) {
833 continue;
834 }
835 ConstElementPtr attr_type = entry->get("type");
836 if (!attr_type || (attr_type->getType() != Element::integer)) {
837 continue;
838 }
839 AttrDefPtr def = AttrDefs::instance().getByType(attr_type->intValue());
840 if (!def) {
841 continue;
842 }
843 if (def->value_type_ == PW_TYPE_STRING) {
844 ConstElementPtr raw = entry->get("raw");
845 if (raw && (raw->getType() == Element::string) &&
846 (!raw->stringValue().empty())) {
847 try {
848 vector<uint8_t> binary;
849 encode::decodeHex(raw->stringValue(), binary);
850 AttributePtr attr = Attribute::fromBytes(def, binary);
851 attrs.add(attr);
852 continue;
853 } catch (...) {
854 continue;
855 }
856 }
857 }
858 ConstElementPtr data = entry->get("data");
859 if (data && (data->getType() == Element::string) &&
860 (!data->stringValue().empty())) {
861 AttributePtr attr = Attribute::fromText(def, data->stringValue());
862 attrs.add(attr);
863 continue;
864 }
865 }
866 return (attrs);
867}
868
869} // end of namespace isc::radius
870} // end of namespace isc
Element::create
static ElementPtr create(const Position &pos=ZERO_POSITION())
Create a NullElement.
Definition data.cc:299
Element::map
@ map
Definition data.h:160
Element::integer
@ integer
Definition data.h:153
Element::list
@ list
Definition data.h:159
Element::string
@ string
Definition data.h:157
Element::createMap
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:354
Element::createList
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition data.cc:349
isc::BadValue
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Definition exceptions/exceptions.h:132
isc::NotImplemented
A generic exception that is thrown when a function is not implemented.
Definition exceptions/exceptions.h:166
isc::OutOfRange
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
Definition exceptions/exceptions.h:115
isc::asiolink::IOAddress
The IOAddress class represents an IP addresses (version agnostic).
Definition io_address.h:53
isc::asiolink::IOAddress::fromBytes
static IOAddress fromBytes(short family, const uint8_t *data)
Creates an address from over wire data.
Definition io_address.cc:65
isc::data::TypeError
A standard Data module exception that is thrown if a function is called for an Element that has a wro...
Definition data.h:37
isc::radius::AttrDefs::instance
static AttrDefs & instance()
Returns a single instance.
Definition client_dictionary.cc:65
isc::radius::AttrDefs::getByValue
IntCstDefPtr getByValue(const uint8_t type, const uint32_t value, const uint32_t vendor=0) const
Get integer constant definition by attribute type and value.
Definition client_dictionary.cc:168
isc::radius::AttrDefs::getName
std::string getName(const uint8_t type, const uint32_t vendor=0) const
Get attribute name.
Definition client_dictionary.cc:146
isc::radius::AttrDefs::getByName
AttrDefPtr getByName(const std::string &name, const uint32_t vendor=0) const
Get attribute definition by name and vendor.
Definition client_dictionary.cc:81
isc::radius::AttrDefs::getByType
AttrDefPtr getByType(const uint8_t type, const uint32_t vendor=0) const
Get attribute definition by type and vendor.
Definition client_dictionary.cc:71
isc::radius::AttrInt
RADIUS attribute holding integers.
Definition client_attribute.h:389
isc::radius::AttrInt::fromText
static AttributePtr fromText(const uint8_t type, const std::string &repr)
From text.
Definition client_attribute.cc:343
isc::radius::AttrInt::toBytes
virtual std::vector< uint8_t > toBytes() const override
To bytes.
Definition client_attribute.cc:398
isc::radius::AttrInt::toElement
virtual data::ElementPtr toElement() const override
Unparse attribute.
Definition client_attribute.cc:411
isc::radius::AttrInt::toText
virtual std::string toText(size_t indent=0) const override
Returns text representation of the attribute.
Definition client_attribute.cc:382
isc::radius::AttrInt::AttrInt
AttrInt(const uint8_t type, const int32_t value)
Constructor (signed).
Definition client_attribute.h:396
isc::radius::AttrInt::fromBytes
static AttributePtr fromBytes(const uint8_t type, const std::vector< uint8_t > &bytes)
From bytes.
Definition client_attribute.cc:364
isc::radius::AttrIpAddr
RADIUS attribute holding IPv4 addresses.
Definition client_attribute.h:471
isc::radius::AttrIpAddr::AttrIpAddr
AttrIpAddr(const uint8_t type, const asiolink::IOAddress &value)
Constructor.
Definition client_attribute.h:478
isc::radius::AttrIpAddr::toElement
virtual data::ElementPtr toElement() const override
Unparse attribute.
Definition client_attribute.cc:476
isc::radius::AttrIpAddr::toBytes
virtual std::vector< uint8_t > toBytes() const override
To bytes.
Definition client_attribute.cc:465
isc::radius::AttrIpAddr::fromText
static AttributePtr fromText(const uint8_t type, const std::string &repr)
From text.
Definition client_attribute.cc:425
isc::radius::AttrIpAddr::fromBytes
static AttributePtr fromBytes(const uint8_t type, const std::vector< uint8_t > &bytes)
From bytes.
Definition client_attribute.cc:439
isc::radius::AttrIpAddr::toText
virtual std::string toText(size_t indent=0) const override
Returns text representation of the attribute.
Definition client_attribute.cc:454
isc::radius::AttrIpv6Addr
RADIUS attribute holding IPv6 addresses.
Definition client_attribute.h:547
isc::radius::AttrIpv6Addr::toText
virtual std::string toText(size_t indent=0) const override
Returns text representation of the attribute.
Definition client_attribute.cc:519
isc::radius::AttrIpv6Addr::fromBytes
static AttributePtr fromBytes(const uint8_t type, const std::vector< uint8_t > &bytes)
From bytes.
Definition client_attribute.cc:504
isc::radius::AttrIpv6Addr::toBytes
virtual std::vector< uint8_t > toBytes() const override
To bytes.
Definition client_attribute.cc:530
isc::radius::AttrIpv6Addr::fromText
static AttributePtr fromText(const uint8_t type, const std::string &repr)
From text.
Definition client_attribute.cc:490
isc::radius::AttrIpv6Addr::AttrIpv6Addr
AttrIpv6Addr(const uint8_t type, const asiolink::IOAddress &value)
Constructor.
Definition client_attribute.h:554
isc::radius::AttrIpv6Addr::toElement
virtual data::ElementPtr toElement() const override
Unparse attribute.
Definition client_attribute.cc:541
isc::radius::AttrIpv6Prefix
RADIUS attribute holding IPv6 prefixes.
Definition client_attribute.h:624
isc::radius::AttrIpv6Prefix::AttrIpv6Prefix
AttrIpv6Prefix(const uint8_t type, const uint8_t len, const asiolink::IOAddress &value)
Constructor.
Definition client_attribute.h:632
isc::radius::AttrIpv6Prefix::toBytes
virtual std::vector< uint8_t > toBytes() const override
To bytes.
Definition client_attribute.cc:621
isc::radius::AttrIpv6Prefix::toElement
virtual data::ElementPtr toElement() const override
Unparse attribute.
Definition client_attribute.cc:635
isc::radius::AttrIpv6Prefix::fromText
static AttributePtr fromText(const uint8_t type, const std::string &repr)
From text.
Definition client_attribute.cc:555
isc::radius::AttrIpv6Prefix::fromBytes
static AttributePtr fromBytes(const uint8_t type, const std::vector< uint8_t > &bytes)
From bytes.
Definition client_attribute.cc:582
isc::radius::AttrIpv6Prefix::toText
virtual std::string toText(size_t indent=0) const override
Returns text representation of the attribute.
Definition client_attribute.cc:610
isc::radius::AttrString
RADIUS attribute derived classes: do not use them directly outside unit tests, instead use Attribute ...
Definition client_attribute.h:298
isc::radius::AttrString::fromBytes
static AttributePtr fromBytes(const uint8_t type, const std::vector< uint8_t > &bytes)
From bytes.
Definition client_attribute.cc:267
isc::radius::AttrString::fromText
static AttributePtr fromText(const uint8_t type, const std::string &repr)
From text.
Definition client_attribute.cc:255
isc::radius::AttrString::toBytes
virtual std::vector< uint8_t > toBytes() const override
To bytes.
Definition client_attribute.cc:299
isc::radius::AttrString::toElement
virtual data::ElementPtr toElement() const override
Unparse attribute.
Definition client_attribute.cc:321
isc::radius::AttrString::toText
virtual std::string toText(size_t indent=0) const override
Returns text representation of the attribute.
Definition client_attribute.cc:279
isc::radius::AttrString::AttrString
AttrString(const uint8_t type, const std::string &value)
Constructor.
Definition client_attribute.h:305
isc::radius::AttrString::toBinary
virtual std::vector< uint8_t > toBinary() const override
To binary.
Definition client_attribute.cc:311
isc::radius::AttrString::getValueLen
virtual size_t getValueLen() const override
Value length.
Definition client_attribute.h:351
isc::radius::AttrString::Attribute
friend class Attribute
Make Attribute a friend class.
Definition client_attribute.h:338
isc::radius::AttrVsa
RADIUS attribute holding vsa.
Definition client_attribute.h:717
isc::radius::AttrVsa::toElement
virtual data::ElementPtr toElement() const override
Unparse attribute.
Definition client_attribute.cc:734
isc::radius::AttrVsa::toText
virtual std::string toText(size_t indent=0) const override
Returns text representation of the attribute.
Definition client_attribute.cc:691
isc::radius::AttrVsa::fromBytes
static AttributePtr fromBytes(const uint8_t type, const std::vector< uint8_t > &bytes)
From bytes.
Definition client_attribute.cc:668
isc::radius::AttrVsa::Attribute
friend class Attribute
Make Attribute a friend class.
Definition client_attribute.h:762
isc::radius::AttrVsa::fromText
static AttributePtr fromText(const uint8_t type, const std::string &repr)
From text.
Definition client_attribute.cc:663
isc::radius::AttrVsa::toVsaData
virtual std::vector< uint8_t > toVsaData() const override
To vsa data.
Definition client_attribute.cc:724
isc::radius::AttrVsa::AttrVsa
AttrVsa(const uint8_t type, const uint32_t vendor, const std::string &value)
Constructor.
Definition client_attribute.h:725
isc::radius::AttrVsa::getValueLen
virtual size_t getValueLen() const override
Value length.
Definition client_attribute.h:776
isc::radius::AttrVsa::toBytes
virtual std::vector< uint8_t > toBytes() const override
To bytes.
Definition client_attribute.cc:708
isc::radius::Attribute::fromBytes
static AttributePtr fromBytes(const std::vector< uint8_t > &bytes)
Generic factories.
Definition client_attribute.cc:75
isc::radius::Attribute::toString
virtual std::string toString() const
Specific get methods.
Definition client_attribute.cc:188
isc::radius::Attribute::fromInt
static AttributePtr fromInt(const uint8_t type, const uint32_t value)
From integer with type.
Definition client_attribute.cc:155
isc::radius::Attribute::fromIpAddr
static AttributePtr fromIpAddr(const uint8_t type, const asiolink::IOAddress &value)
From IPv4 address with type.
Definition client_attribute.cc:160
isc::radius::Attribute::toInt
virtual uint32_t toInt() const
To integer.
Definition client_attribute.cc:200
isc::radius::Attribute::toVendorId
virtual uint32_t toVendorId() const
To vendor id.
Definition client_attribute.cc:230
isc::radius::Attribute::fromString
static AttributePtr fromString(const uint8_t type, const std::string &value)
From type specific factories.
Definition client_attribute.cc:139
isc::radius::Attribute::getType
uint8_t getType() const
Get type.
Definition client_attribute.h:61
isc::radius::Attribute::toIpAddr
virtual asiolink::IOAddress toIpAddr() const
To IPv4 address.
Definition client_attribute.cc:206
isc::radius::Attribute::toIpv6Addr
virtual asiolink::IOAddress toIpv6Addr() const
To IPv6 address.
Definition client_attribute.cc:212
isc::radius::Attribute::fromBinary
static AttributePtr fromBinary(const uint8_t type, const std::vector< uint8_t > &value)
From binary with type.
Definition client_attribute.cc:147
isc::radius::Attribute::fromText
static AttributePtr fromText(const AttrDefPtr &def, const std::string &value)
From definition generic factories.
Definition client_attribute.cc:28
isc::radius::Attribute::toIpv6PrefixLen
virtual uint8_t toIpv6PrefixLen() const
To IPv6 prefix length.
Definition client_attribute.cc:224
isc::radius::Attribute::fromIpv6Prefix
static AttributePtr fromIpv6Prefix(const uint8_t type, const uint8_t len, const asiolink::IOAddress &value)
From IPv6 prefix with type.
Definition client_attribute.cc:170
isc::radius::Attribute::fromIpv6Addr
static AttributePtr fromIpv6Addr(const uint8_t type, const asiolink::IOAddress &value)
From IPv6 address with type.
Definition client_attribute.cc:165
isc::radius::Attribute::toIpv6Prefix
virtual asiolink::IOAddress toIpv6Prefix() const
To IPv6 prefix.
Definition client_attribute.cc:218
isc::radius::Attribute::getValueType
virtual AttrValueType getValueType() const =0
Get value type.
isc::radius::Attribute::toBinary
virtual std::vector< uint8_t > toBinary() const
To binary.
Definition client_attribute.cc:194
isc::radius::Attribute::fromVsa
static AttributePtr fromVsa(const uint8_t type, const uint32_t vendor, const std::string &value)
From Vendor ID and string data with type.
Definition client_attribute.cc:176
isc::radius::Attribute::toVsaData
virtual std::vector< uint8_t > toVsaData() const
To vsa data.
Definition client_attribute.cc:236
isc::radius::Attributes
Collection of attributes.
Definition client_attribute.h:819
isc::radius::Attributes::container_
AttributeContainer container_
The container.
Definition client_attribute.h:959
isc::radius::Attributes::toText
std::string toText(size_t indent=0) const
Returns text representation of the collection.
Definition client_attribute.cc:802
isc::radius::Attributes::Attributes
Attributes()
constructor.
Definition client_attribute.h:840
isc::radius::Attributes::append
void append(const Attributes &other)
Append another collection.
Definition client_attribute.cc:778
isc::radius::Attributes::count
size_t count(const uint8_t type) const
Counts instance of the attribute in the collection.
Definition client_attribute.cc:785
isc::radius::Attributes::get
ConstAttributePtr get(const uint8_t type) const
Get instance of the attribute in the collection.
Definition client_attribute.cc:791
isc::radius::Attributes::toElement
data::ElementPtr toElement() const override
Unparse collection.
Definition client_attribute.cc:817
isc::radius::Attributes::add
void add(const ConstAttributePtr &attr, bool back=true)
Adds instance of the attribute to the collection.
Definition client_attribute.cc:755
isc::radius::Attributes::del
bool del(const uint8_t type)
Deletes an attribute from the collection.
Definition client_attribute.cc:767
isc::radius::Attributes::fromElement
static Attributes fromElement(const data::ConstElementPtr &attr_list)
Parse collection.
Definition client_attribute.cc:826
client_attribute.h
if
if(!(yy_init))
Definition d2_lexer.cc:1515
encode.h
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition exceptions/exceptions.h:210
LOG_ERROR
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition macros.h:32
isc::asiolink
Definition addr_utilities.cc:170
isc::data
Definition base_stamped_element.cc:12
isc::data::ConstElementPtr
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:30
isc::data::ElementPtr
boost::shared_ptr< Element > ElementPtr
Definition data.h:29
isc::radius
Definition cfg_attribute.cc:21
isc::radius::IntCstDefPtr
boost::shared_ptr< IntCstDef > IntCstDefPtr
Shared pointers to Integer constant definition.
Definition client_dictionary.h:141
isc::radius::PW_VENDOR_SPECIFIC
@ PW_VENDOR_SPECIFIC
string.
Definition hooks/dhcp/radius/client.h:43
isc::radius::RADIUS_IPV6PREFIX_ATTRIBUTE_FROM_BYTES_FAILED
const isc::log::MessageID RADIUS_IPV6PREFIX_ATTRIBUTE_FROM_BYTES_FAILED
Definition radius_messages.h:73
isc::radius::ConstAttributePtr
boost::shared_ptr< const Attribute > ConstAttributePtr
Definition client_attribute.h:40
isc::radius::RADIUS_IPADDR_ATTRIBUTE_FROM_BYTES_FAILED
const isc::log::MessageID RADIUS_IPADDR_ATTRIBUTE_FROM_BYTES_FAILED
Definition radius_messages.h:69
isc::radius::RADIUS_IPV6PREFIX_ATTRIBUTE_FROM_TEXT_FAILED
const isc::log::MessageID RADIUS_IPV6PREFIX_ATTRIBUTE_FROM_TEXT_FAILED
Definition radius_messages.h:74
isc::radius::PW_TYPE_INTEGER
@ PW_TYPE_INTEGER
Definition client_dictionary.h:31
isc::radius::PW_TYPE_IPV6PREFIX
@ PW_TYPE_IPV6PREFIX
Definition client_dictionary.h:34
isc::radius::PW_TYPE_IPV6ADDR
@ PW_TYPE_IPV6ADDR
Definition client_dictionary.h:33
isc::radius::PW_TYPE_VSA
@ PW_TYPE_VSA
Definition client_dictionary.h:35
isc::radius::PW_TYPE_IPADDR
@ PW_TYPE_IPADDR
Definition client_dictionary.h:32
isc::radius::PW_TYPE_STRING
@ PW_TYPE_STRING
Definition client_dictionary.h:30
isc::radius::AttrDefPtr
boost::shared_ptr< AttrDef > AttrDefPtr
Shared pointers to Attribute definition.
Definition client_dictionary.h:81
isc::radius::attrValueTypeToText
string attrValueTypeToText(const AttrValueType value)
AttrValueType value -> name function.
Definition client_dictionary.cc:25
isc::radius::AttributePtr
boost::shared_ptr< Attribute > AttributePtr
Definition client_attribute.h:39
isc::radius::RADIUS_IPV6ADDR_ATTRIBUTE_FROM_TEXT_FAILED
const isc::log::MessageID RADIUS_IPV6ADDR_ATTRIBUTE_FROM_TEXT_FAILED
Definition radius_messages.h:72
isc::radius::radius_logger
isc::log::Logger radius_logger("radius-hooks")
Radius Logger.
Definition radius_log.h:35
isc::radius::RADIUS_INTEGER_ATTRIBUTE_FROM_TEXT_FAILED
const isc::log::MessageID RADIUS_INTEGER_ATTRIBUTE_FROM_TEXT_FAILED
Definition radius_messages.h:68
isc::radius::RADIUS_INTEGER_ATTRIBUTE_FROM_BYTES_FAILED
const isc::log::MessageID RADIUS_INTEGER_ATTRIBUTE_FROM_BYTES_FAILED
Definition radius_messages.h:67
isc::radius::RADIUS_IPADDR_ATTRIBUTE_FROM_TEXT_FAILED
const isc::log::MessageID RADIUS_IPADDR_ATTRIBUTE_FROM_TEXT_FAILED
Definition radius_messages.h:70
isc::radius::RADIUS_IPV6ADDR_ATTRIBUTE_FROM_BYTES_FAILED
const isc::log::MessageID RADIUS_IPV6ADDR_ATTRIBUTE_FROM_BYTES_FAILED
Definition radius_messages.h:71
isc::util::encode::decodeHex
void decodeHex(const string &encoded_str, vector< uint8_t > &output)
Decode a base16 encoded string into binary data.
Definition encode.cc:367
isc::util::encode::encodeHex
string encodeHex(const vector< uint8_t > &binary)
Encode binary data in the base16 format.
Definition encode.cc:361
isc::util::str::isPrintable
bool isPrintable(const string &content)
Check if a string is printable.
Definition str.cc:310
isc::util
Definition time_utils.cc:43
isc
Defines the logger used by the top-level component of kea-lfc.
Definition check_exists_add.cc:18
radius_log.h
str.h