Buffer.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  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: 2025-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. _l = l;
  77. }
  78. template<unsigned int C2>
  79. Buffer(const Buffer<C2> &b)
  80. {
  81. *this = b;
  82. }
  83. Buffer(const void *b,unsigned int l)
  84. {
  85. copyFrom(b,l);
  86. }
  87. template<unsigned int C2>
  88. inline Buffer &operator=(const Buffer<C2> &b)
  89. {
  90. if (unlikely(b._l > C))
  91. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  92. if (C2 == C) {
  93. memcpy(this,&b,sizeof(Buffer<C>));
  94. } else {
  95. memcpy(_b,b._b,_l = b._l);
  96. }
  97. return *this;
  98. }
  99. inline void copyFrom(const void *b,unsigned int l)
  100. {
  101. if (unlikely(l > C))
  102. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  103. memcpy(_b,b,l);
  104. _l = l;
  105. }
  106. unsigned char operator[](const unsigned int i) const
  107. {
  108. if (unlikely(i >= _l))
  109. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  110. return (unsigned char)_b[i];
  111. }
  112. unsigned char &operator[](const unsigned int i)
  113. {
  114. if (unlikely(i >= _l))
  115. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  116. return ((unsigned char *)_b)[i];
  117. }
  118. /**
  119. * Get a raw pointer to a field with bounds checking
  120. *
  121. * This isn't perfectly safe in that the caller could still overflow
  122. * the pointer, but its use provides both a sanity check and
  123. * documentation / reminder to the calling code to treat the returned
  124. * pointer as being of size [l].
  125. *
  126. * @param i Index of field in buffer
  127. * @param l Length of field in bytes
  128. * @return Pointer to field data
  129. * @throws std::out_of_range Field extends beyond data size
  130. */
  131. unsigned char *field(unsigned int i,unsigned int l)
  132. {
  133. if (unlikely((i + l) > _l))
  134. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  135. return (unsigned char *)(_b + i);
  136. }
  137. const unsigned char *field(unsigned int i,unsigned int l) const
  138. {
  139. if (unlikely((i + l) > _l))
  140. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  141. return (const unsigned char *)(_b + i);
  142. }
  143. /**
  144. * Place a primitive integer value at a given position
  145. *
  146. * @param i Index to place value
  147. * @param v Value
  148. * @tparam T Integer type (e.g. uint16_t, int64_t)
  149. */
  150. template<typename T>
  151. inline void setAt(unsigned int i,const T v)
  152. {
  153. if (unlikely((i + sizeof(T)) > _l))
  154. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  155. #ifdef ZT_NO_TYPE_PUNNING
  156. uint8_t *p = reinterpret_cast<uint8_t *>(_b + i);
  157. for(unsigned int x=1;x<=sizeof(T);++x)
  158. *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));
  159. #else
  160. T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T *>(_b + i);
  161. *p = Utils::hton(v);
  162. #endif
  163. }
  164. /**
  165. * Get a primitive integer value at a given position
  166. *
  167. * @param i Index to get integer
  168. * @tparam T Integer type (e.g. uint16_t, int64_t)
  169. * @return Integer value
  170. */
  171. template<typename T>
  172. inline T at(unsigned int i) const
  173. {
  174. if (unlikely((i + sizeof(T)) > _l))
  175. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  176. #ifdef ZT_NO_TYPE_PUNNING
  177. T v = 0;
  178. const uint8_t *p = reinterpret_cast<const uint8_t *>(_b + i);
  179. for(unsigned int x=0;x<sizeof(T);++x) {
  180. v <<= 8;
  181. v |= (T)*(p++);
  182. }
  183. return v;
  184. #else
  185. const T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<const T *>(_b + i);
  186. return Utils::ntoh(*p);
  187. #endif
  188. }
  189. /**
  190. * Append an integer type to this buffer
  191. *
  192. * @param v Value to append
  193. * @tparam T Integer type (e.g. uint16_t, int64_t)
  194. * @throws std::out_of_range Attempt to append beyond capacity
  195. */
  196. template<typename T>
  197. inline void append(const T v)
  198. {
  199. if (unlikely((_l + sizeof(T)) > C))
  200. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  201. #ifdef ZT_NO_TYPE_PUNNING
  202. uint8_t *p = reinterpret_cast<uint8_t *>(_b + _l);
  203. for(unsigned int x=1;x<=sizeof(T);++x)
  204. *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));
  205. #else
  206. T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T *>(_b + _l);
  207. *p = Utils::hton(v);
  208. #endif
  209. _l += sizeof(T);
  210. }
  211. /**
  212. * Append a run of bytes
  213. *
  214. * @param c Character value to append
  215. * @param n Number of times to append
  216. * @throws std::out_of_range Attempt to append beyond capacity
  217. */
  218. inline void append(unsigned char c,unsigned int n)
  219. {
  220. if (unlikely((_l + n) > C))
  221. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  222. for(unsigned int i=0;i<n;++i)
  223. _b[_l++] = (char)c;
  224. }
  225. /**
  226. * Append secure random bytes
  227. *
  228. * @param n Number of random bytes to append
  229. */
  230. inline void appendRandom(unsigned int n)
  231. {
  232. if (unlikely((_l + n) > C))
  233. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  234. Utils::getSecureRandom(_b + _l,n);
  235. _l += n;
  236. }
  237. /**
  238. * Append a C-array of bytes
  239. *
  240. * @param b Data
  241. * @param l Length
  242. * @throws std::out_of_range Attempt to append beyond capacity
  243. */
  244. inline void append(const void *b,unsigned int l)
  245. {
  246. if (unlikely((_l + l) > C))
  247. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  248. memcpy(_b + _l,b,l);
  249. _l += l;
  250. }
  251. /**
  252. * Append a C string including null termination byte
  253. *
  254. * @param s C string
  255. * @throws std::out_of_range Attempt to append beyond capacity
  256. */
  257. inline void appendCString(const char *s)
  258. {
  259. for(;;) {
  260. if (unlikely(_l >= C))
  261. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  262. if (!(_b[_l++] = *(s++)))
  263. break;
  264. }
  265. }
  266. /**
  267. * Append a buffer
  268. *
  269. * @param b Buffer to append
  270. * @tparam C2 Capacity of second buffer (typically inferred)
  271. * @throws std::out_of_range Attempt to append beyond capacity
  272. */
  273. template<unsigned int C2>
  274. inline void append(const Buffer<C2> &b)
  275. {
  276. append(b._b,b._l);
  277. }
  278. /**
  279. * Increment size and return pointer to field of specified size
  280. *
  281. * Nothing is actually written to the memory. This is a shortcut
  282. * for addSize() followed by field() to reference the previous
  283. * position and the new size.
  284. *
  285. * @param l Length of field to append
  286. * @return Pointer to beginning of appended field of length 'l'
  287. */
  288. inline char *appendField(unsigned int l)
  289. {
  290. if (unlikely((_l + l) > C))
  291. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  292. char *r = _b + _l;
  293. _l += l;
  294. return r;
  295. }
  296. /**
  297. * Increment size by a given number of bytes
  298. *
  299. * The contents of new space are undefined.
  300. *
  301. * @param i Bytes to increment
  302. * @throws std::out_of_range Capacity exceeded
  303. */
  304. inline void addSize(unsigned int i)
  305. {
  306. if (unlikely((i + _l) > C))
  307. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  308. _l += i;
  309. }
  310. /**
  311. * Set size of data in buffer
  312. *
  313. * The contents of new space are undefined.
  314. *
  315. * @param i New size
  316. * @throws std::out_of_range Size larger than capacity
  317. */
  318. inline void setSize(const unsigned int i)
  319. {
  320. if (unlikely(i > C))
  321. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  322. _l = i;
  323. }
  324. /**
  325. * Move everything after 'at' to the buffer's front and truncate
  326. *
  327. * @param at Truncate before this position
  328. * @throws std::out_of_range Position is beyond size of buffer
  329. */
  330. inline void behead(const unsigned int at)
  331. {
  332. if (!at)
  333. return;
  334. if (unlikely(at > _l))
  335. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  336. ::memmove(_b,_b + at,_l -= at);
  337. }
  338. /**
  339. * Erase something from the middle of the buffer
  340. *
  341. * @param start Starting position
  342. * @param length Length of block to erase
  343. * @throws std::out_of_range Position plus length is beyond size of buffer
  344. */
  345. inline void erase(const unsigned int at,const unsigned int length)
  346. {
  347. const unsigned int endr = at + length;
  348. if (unlikely(endr > _l))
  349. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  350. ::memmove(_b + at,_b + endr,_l - endr);
  351. _l -= length;
  352. }
  353. /**
  354. * Set buffer data length to zero
  355. */
  356. inline void clear() { _l = 0; }
  357. /**
  358. * Zero buffer up to size()
  359. */
  360. inline void zero() { memset(_b,0,_l); }
  361. /**
  362. * Zero unused capacity area
  363. */
  364. inline void zeroUnused() { memset(_b + _l,0,C - _l); }
  365. /**
  366. * Unconditionally and securely zero buffer's underlying memory
  367. */
  368. inline void burn() { Utils::burn(_b,sizeof(_b)); }
  369. /**
  370. * @return Constant pointer to data in buffer
  371. */
  372. inline const void *data() const { return _b; }
  373. /**
  374. * @return Non-constant pointer to data in buffer
  375. */
  376. inline void *unsafeData() { return _b; }
  377. /**
  378. * @return Size of data in buffer
  379. */
  380. inline unsigned int size() const { return _l; }
  381. /**
  382. * @return Capacity of buffer
  383. */
  384. inline unsigned int capacity() const { return C; }
  385. template<unsigned int C2>
  386. inline bool operator==(const Buffer<C2> &b) const
  387. {
  388. return ((_l == b._l)&&(!memcmp(_b,b._b,_l)));
  389. }
  390. template<unsigned int C2>
  391. inline bool operator!=(const Buffer<C2> &b) const
  392. {
  393. return ((_l != b._l)||(memcmp(_b,b._b,_l)));
  394. }
  395. template<unsigned int C2>
  396. inline bool operator<(const Buffer<C2> &b) const
  397. {
  398. return (memcmp(_b,b._b,std::min(_l,b._l)) < 0);
  399. }
  400. template<unsigned int C2>
  401. inline bool operator>(const Buffer<C2> &b) const
  402. {
  403. return (b < *this);
  404. }
  405. template<unsigned int C2>
  406. inline bool operator<=(const Buffer<C2> &b) const
  407. {
  408. return !(b < *this);
  409. }
  410. template<unsigned int C2>
  411. inline bool operator>=(const Buffer<C2> &b) const
  412. {
  413. return !(*this < b);
  414. }
  415. private:
  416. char ZT_VAR_MAY_ALIAS _b[C];
  417. unsigned int _l;
  418. };
  419. } // namespace ZeroTier
  420. #endif