Buffer.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. /*
  2. * Copyright (c)2019 ZeroTier, Inc.
  3. *
  4. * Use of this software is governed by the Business Source License included
  5. * in the LICENSE.TXT file in the project's root directory.
  6. *
  7. * Change Date: 2026-01-01
  8. *
  9. * On the date above, in accordance with the Business Source License, use
  10. * of this software will be governed by version 2.0 of the Apache License.
  11. */
  12. /****/
  13. #ifndef ZT_BUFFER_HPP
  14. #define ZT_BUFFER_HPP
  15. #include <string.h>
  16. #include <stdint.h>
  17. #include <stdexcept>
  18. #include <string>
  19. #include <algorithm>
  20. #include <utility>
  21. #include "Constants.hpp"
  22. #include "Utils.hpp"
  23. #if defined(__GNUC__) && (!defined(ZT_NO_TYPE_PUNNING))
  24. #define ZT_VAR_MAY_ALIAS __attribute__((__may_alias__))
  25. #else
  26. #define ZT_VAR_MAY_ALIAS
  27. #endif
  28. namespace ZeroTier {
  29. /**
  30. * A variable length but statically allocated buffer
  31. *
  32. * Bounds-checking is done everywhere, since this is used in security
  33. * critical code. This supports construction and assignment from buffers
  34. * of differing capacities, provided the data actually in them fits.
  35. * It throws std::out_of_range on any boundary violation.
  36. *
  37. * The at(), append(), etc. methods encode integers larger than 8-bit in
  38. * big-endian (network) byte order.
  39. *
  40. * @tparam C Total capacity
  41. */
  42. template<unsigned int C>
  43. class Buffer
  44. {
  45. // I love me!
  46. template <unsigned int C2> friend class Buffer;
  47. public:
  48. // STL container idioms
  49. typedef unsigned char value_type;
  50. typedef unsigned char * pointer;
  51. typedef const char * const_pointer;
  52. typedef char & reference;
  53. typedef const char & const_reference;
  54. typedef char * iterator;
  55. typedef const char * const_iterator;
  56. typedef unsigned int size_type;
  57. typedef int difference_type;
  58. typedef std::reverse_iterator<iterator> reverse_iterator;
  59. typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
  60. inline iterator begin() { return _b; }
  61. inline iterator end() { return (_b + _l); }
  62. inline const_iterator begin() const { return _b; }
  63. inline const_iterator end() const { return (_b + _l); }
  64. inline reverse_iterator rbegin() { return reverse_iterator(begin()); }
  65. inline reverse_iterator rend() { return reverse_iterator(end()); }
  66. inline const_reverse_iterator rbegin() const { return const_reverse_iterator(begin()); }
  67. inline const_reverse_iterator rend() const { return const_reverse_iterator(end()); }
  68. Buffer() :
  69. _l(0)
  70. {
  71. }
  72. Buffer(unsigned int l)
  73. {
  74. if (l > C) {
  75. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  76. }
  77. _l = l;
  78. }
  79. template<unsigned int C2>
  80. Buffer(const Buffer<C2> &b)
  81. {
  82. *this = b;
  83. }
  84. Buffer(const void *b,unsigned int l)
  85. {
  86. copyFrom(b,l);
  87. }
  88. template<unsigned int C2>
  89. inline Buffer &operator=(const Buffer<C2> &b)
  90. {
  91. if (unlikely(b._l > C)) {
  92. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  93. }
  94. if (C2 == C) {
  95. memcpy(this,&b,sizeof(Buffer<C>));
  96. } else {
  97. memcpy(_b,b._b,_l = b._l);
  98. }
  99. return *this;
  100. }
  101. inline void copyFrom(const void *b,unsigned int l)
  102. {
  103. if (unlikely(l > C)) {
  104. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  105. }
  106. memcpy(_b,b,l);
  107. _l = l;
  108. }
  109. unsigned char operator[](const unsigned int i) const
  110. {
  111. if (unlikely(i >= _l)) {
  112. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  113. }
  114. return (unsigned char)_b[i];
  115. }
  116. unsigned char &operator[](const unsigned int i)
  117. {
  118. if (unlikely(i >= _l)) {
  119. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  120. }
  121. return ((unsigned char *)_b)[i];
  122. }
  123. /**
  124. * Get a raw pointer to a field with bounds checking
  125. *
  126. * This isn't perfectly safe in that the caller could still overflow
  127. * the pointer, but its use provides both a sanity check and
  128. * documentation / reminder to the calling code to treat the returned
  129. * pointer as being of size [l].
  130. *
  131. * @param i Index of field in buffer
  132. * @param l Length of field in bytes
  133. * @return Pointer to field data
  134. * @throws std::out_of_range Field extends beyond data size
  135. */
  136. unsigned char *field(unsigned int i,unsigned int l)
  137. {
  138. if (unlikely((i + l) > _l)) {
  139. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  140. }
  141. return (unsigned char *)(_b + i);
  142. }
  143. const unsigned char *field(unsigned int i,unsigned int l) const
  144. {
  145. if (unlikely((i + l) > _l)) {
  146. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  147. }
  148. return (const unsigned char *)(_b + i);
  149. }
  150. /**
  151. * Place a primitive integer value at a given position
  152. *
  153. * @param i Index to place value
  154. * @param v Value
  155. * @tparam T Integer type (e.g. uint16_t, int64_t)
  156. */
  157. template<typename T>
  158. inline void setAt(unsigned int i,const T v)
  159. {
  160. if (unlikely((i + sizeof(T)) > _l)) {
  161. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  162. }
  163. #ifdef ZT_NO_TYPE_PUNNING
  164. uint8_t *p = reinterpret_cast<uint8_t *>(_b + i);
  165. for(unsigned int x=1;x<=sizeof(T);++x) {
  166. *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));
  167. }
  168. #else
  169. T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T *>(_b + i);
  170. *p = Utils::hton(v);
  171. #endif
  172. }
  173. /**
  174. * Get a primitive integer value at a given position
  175. *
  176. * @param i Index to get integer
  177. * @tparam T Integer type (e.g. uint16_t, int64_t)
  178. * @return Integer value
  179. */
  180. template<typename T>
  181. inline T at(unsigned int i) const
  182. {
  183. if (unlikely((i + sizeof(T)) > _l)) {
  184. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  185. }
  186. #ifdef ZT_NO_TYPE_PUNNING
  187. T v = 0;
  188. const uint8_t *p = reinterpret_cast<const uint8_t *>(_b + i);
  189. for(unsigned int x=0;x<sizeof(T);++x) {
  190. v <<= 8;
  191. v |= (T)*(p++);
  192. }
  193. return v;
  194. #else
  195. const T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<const T *>(_b + i);
  196. return Utils::ntoh(*p);
  197. #endif
  198. }
  199. /**
  200. * Append an integer type to this buffer
  201. *
  202. * @param v Value to append
  203. * @tparam T Integer type (e.g. uint16_t, int64_t)
  204. * @throws std::out_of_range Attempt to append beyond capacity
  205. */
  206. template<typename T>
  207. inline void append(const T v)
  208. {
  209. if (unlikely((_l + sizeof(T)) > C)) {
  210. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  211. }
  212. #ifdef ZT_NO_TYPE_PUNNING
  213. uint8_t *p = reinterpret_cast<uint8_t *>(_b + _l);
  214. for(unsigned int x=1;x<=sizeof(T);++x) {
  215. *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));
  216. }
  217. #else
  218. T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T *>(_b + _l);
  219. *p = Utils::hton(v);
  220. #endif
  221. _l += sizeof(T);
  222. }
  223. /**
  224. * Append a run of bytes
  225. *
  226. * @param c Character value to append
  227. * @param n Number of times to append
  228. * @throws std::out_of_range Attempt to append beyond capacity
  229. */
  230. inline void append(unsigned char c,unsigned int n)
  231. {
  232. if (unlikely((_l + n) > C)) {
  233. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  234. }
  235. for(unsigned int i=0;i<n;++i) {
  236. _b[_l++] = (char)c;
  237. }
  238. }
  239. /**
  240. * Append secure random bytes
  241. *
  242. * @param n Number of random bytes to append
  243. */
  244. inline void appendRandom(unsigned int n)
  245. {
  246. if (unlikely((_l + n) > C)) {
  247. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  248. }
  249. Utils::getSecureRandom(_b + _l,n);
  250. _l += n;
  251. }
  252. /**
  253. * Append a C-array of bytes
  254. *
  255. * @param b Data
  256. * @param l Length
  257. * @throws std::out_of_range Attempt to append beyond capacity
  258. */
  259. inline void append(const void *b,unsigned int l)
  260. {
  261. if (unlikely((_l + l) > C)) {
  262. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  263. }
  264. memcpy(_b + _l,b,l);
  265. _l += l;
  266. }
  267. /**
  268. * Append a C string including null termination byte
  269. *
  270. * @param s C string
  271. * @throws std::out_of_range Attempt to append beyond capacity
  272. */
  273. inline void appendCString(const char *s)
  274. {
  275. for(;;) {
  276. if (unlikely(_l >= C)) {
  277. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  278. }
  279. if (!(_b[_l++] = *(s++))) {
  280. break;
  281. }
  282. }
  283. }
  284. /**
  285. * Append a buffer
  286. *
  287. * @param b Buffer to append
  288. * @tparam C2 Capacity of second buffer (typically inferred)
  289. * @throws std::out_of_range Attempt to append beyond capacity
  290. */
  291. template<unsigned int C2>
  292. inline void append(const Buffer<C2> &b)
  293. {
  294. append(b._b,b._l);
  295. }
  296. /**
  297. * Increment size and return pointer to field of specified size
  298. *
  299. * Nothing is actually written to the memory. This is a shortcut
  300. * for addSize() followed by field() to reference the previous
  301. * position and the new size.
  302. *
  303. * @param l Length of field to append
  304. * @return Pointer to beginning of appended field of length 'l'
  305. */
  306. inline char *appendField(unsigned int l)
  307. {
  308. if (unlikely((_l + l) > C)) {
  309. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  310. }
  311. char *r = _b + _l;
  312. _l += l;
  313. return r;
  314. }
  315. /**
  316. * Increment size by a given number of bytes
  317. *
  318. * The contents of new space are undefined.
  319. *
  320. * @param i Bytes to increment
  321. * @throws std::out_of_range Capacity exceeded
  322. */
  323. inline void addSize(unsigned int i)
  324. {
  325. if (unlikely((i + _l) > C)) {
  326. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  327. }
  328. _l += i;
  329. }
  330. /**
  331. * Set size of data in buffer
  332. *
  333. * The contents of new space are undefined.
  334. *
  335. * @param i New size
  336. * @throws std::out_of_range Size larger than capacity
  337. */
  338. inline void setSize(const unsigned int i)
  339. {
  340. if (unlikely(i > C)) {
  341. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  342. }
  343. _l = i;
  344. }
  345. /**
  346. * Move everything after 'at' to the buffer's front and truncate
  347. *
  348. * @param at Truncate before this position
  349. * @throws std::out_of_range Position is beyond size of buffer
  350. */
  351. inline void behead(const unsigned int at)
  352. {
  353. if (!at) {
  354. return;
  355. }
  356. if (unlikely(at > _l)) {
  357. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  358. }
  359. ::memmove(_b,_b + at,_l -= at);
  360. }
  361. /**
  362. * Erase something from the middle of the buffer
  363. *
  364. * @param start Starting position
  365. * @param length Length of block to erase
  366. * @throws std::out_of_range Position plus length is beyond size of buffer
  367. */
  368. inline void erase(const unsigned int at,const unsigned int length)
  369. {
  370. const unsigned int endr = at + length;
  371. if (unlikely(endr > _l)) {
  372. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  373. }
  374. ::memmove(_b + at,_b + endr,_l - endr);
  375. _l -= length;
  376. }
  377. /**
  378. * Set buffer data length to zero
  379. */
  380. inline void clear() { _l = 0; }
  381. /**
  382. * Zero buffer up to size()
  383. */
  384. inline void zero() { memset(_b,0,_l); }
  385. /**
  386. * Zero unused capacity area
  387. */
  388. inline void zeroUnused() { memset(_b + _l,0,C - _l); }
  389. /**
  390. * Unconditionally and securely zero buffer's underlying memory
  391. */
  392. inline void burn() { Utils::burn(_b,sizeof(_b)); }
  393. /**
  394. * @return Constant pointer to data in buffer
  395. */
  396. inline const void *data() const { return _b; }
  397. /**
  398. * @return Non-constant pointer to data in buffer
  399. */
  400. inline void *unsafeData() { return _b; }
  401. /**
  402. * @return Size of data in buffer
  403. */
  404. inline unsigned int size() const { return _l; }
  405. /**
  406. * @return Capacity of buffer
  407. */
  408. inline unsigned int capacity() const { return C; }
  409. template<unsigned int C2>
  410. inline bool operator==(const Buffer<C2> &b) const
  411. {
  412. return ((_l == b._l)&&(!memcmp(_b,b._b,_l)));
  413. }
  414. template<unsigned int C2>
  415. inline bool operator!=(const Buffer<C2> &b) const
  416. {
  417. return ((_l != b._l)||(memcmp(_b,b._b,_l)));
  418. }
  419. template<unsigned int C2>
  420. inline bool operator<(const Buffer<C2> &b) const
  421. {
  422. return (memcmp(_b,b._b,std::min(_l,b._l)) < 0);
  423. }
  424. template<unsigned int C2>
  425. inline bool operator>(const Buffer<C2> &b) const
  426. {
  427. return (b < *this);
  428. }
  429. template<unsigned int C2>
  430. inline bool operator<=(const Buffer<C2> &b) const
  431. {
  432. return !(b < *this);
  433. }
  434. template<unsigned int C2>
  435. inline bool operator>=(const Buffer<C2> &b) const
  436. {
  437. return !(*this < b);
  438. }
  439. private:
  440. char ZT_VAR_MAY_ALIAS _b[C];
  441. unsigned int _l;
  442. };
  443. } // namespace ZeroTier
  444. #endif