gnsrecord_serialization.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2009-2013 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file gnsrecord/gnsrecord_serialization.c
  18. * @brief API to serialize and deserialize GNS records
  19. * @author Martin Schanzenbach
  20. * @author Matthias Wachs
  21. * @author Christian Grothoff
  22. */
  23. #include "platform.h"
  24. #include "gnunet_util_lib.h"
  25. #include "gnunet_constants.h"
  26. #include "gnunet_signatures.h"
  27. #include "gnunet_arm_service.h"
  28. #include "gnunet_gnsrecord_lib.h"
  29. #include "gnunet_dnsparser_lib.h"
  30. #include "gnunet_tun_lib.h"
  31. #define LOG(kind,...) GNUNET_log_from (kind, "gnsrecord",__VA_ARGS__)
  32. /**
  33. * Set to 1 to check that all records are well-formed (can be converted
  34. * to string) during serialization/deserialization.
  35. */
  36. #define DEBUG_GNSRECORDS 0
  37. GNUNET_NETWORK_STRUCT_BEGIN
  38. /**
  39. * Internal format of a record in the serialized form.
  40. */
  41. struct NetworkRecord
  42. {
  43. /**
  44. * Expiration time for the DNS record; relative or absolute depends
  45. * on @e flags, network byte order.
  46. */
  47. uint64_t expiration_time GNUNET_PACKED;
  48. /**
  49. * Number of bytes in 'data', network byte order.
  50. */
  51. uint32_t data_size GNUNET_PACKED;
  52. /**
  53. * Type of the GNS/DNS record, network byte order.
  54. */
  55. uint32_t record_type GNUNET_PACKED;
  56. /**
  57. * Flags for the record, network byte order.
  58. */
  59. uint32_t flags GNUNET_PACKED;
  60. };
  61. GNUNET_NETWORK_STRUCT_END
  62. /**
  63. * Calculate how many bytes we will need to serialize the given
  64. * records.
  65. *
  66. * @param rd_count number of records in the rd array
  67. * @param rd array of #GNUNET_GNSRECORD_Data with @a rd_count elements
  68. * @return the required size to serialize, -1 on error
  69. */
  70. ssize_t
  71. GNUNET_GNSRECORD_records_get_size (unsigned int rd_count,
  72. const struct GNUNET_GNSRECORD_Data *rd)
  73. {
  74. size_t ret;
  75. if (0 == rd_count)
  76. return 0;
  77. ret = sizeof (struct NetworkRecord) * rd_count;
  78. for (unsigned int i=0;i<rd_count;i++)
  79. {
  80. if ((ret + rd[i].data_size) < ret)
  81. {
  82. GNUNET_break (0);
  83. return -1;
  84. }
  85. ret += rd[i].data_size;
  86. #if DEBUG_GNSRECORDS
  87. {
  88. char *str;
  89. str = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
  90. rd[i].data,
  91. rd[i].data_size);
  92. if (NULL == str)
  93. {
  94. GNUNET_break_op (0);
  95. return -1;
  96. }
  97. GNUNET_free (str);
  98. }
  99. #endif
  100. }
  101. if (ret > SSIZE_MAX)
  102. {
  103. GNUNET_break (0);
  104. return -1;
  105. }
  106. //Do not pad PKEY
  107. if (GNUNET_GNSRECORD_TYPE_PKEY == rd->record_type)
  108. return ret;
  109. /**
  110. * Efficiently round up to the next
  111. * power of 2 for padding
  112. * https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
  113. */
  114. ret--;
  115. ret |= ret >> 1;
  116. ret |= ret >> 2;
  117. ret |= ret >> 4;
  118. ret |= ret >> 8;
  119. ret |= ret >> 16;
  120. ret++;
  121. return (ssize_t) ret;
  122. }
  123. /**
  124. * Serialize the given records to the given destination buffer.
  125. *
  126. * @param rd_count number of records in the rd array
  127. * @param rd array of #GNUNET_GNSRECORD_Data with @a rd_count elements
  128. * @param dest_size size of the destination array
  129. * @param dest where to write the result
  130. * @return the size of serialized records, -1 if records do not fit
  131. */
  132. ssize_t
  133. GNUNET_GNSRECORD_records_serialize (unsigned int rd_count,
  134. const struct GNUNET_GNSRECORD_Data *rd,
  135. size_t dest_size,
  136. char *dest)
  137. {
  138. struct NetworkRecord rec;
  139. size_t off;
  140. off = 0;
  141. for (unsigned int i=0;i<rd_count;i++)
  142. {
  143. LOG (GNUNET_ERROR_TYPE_DEBUG,
  144. "Serializing record %u with flags %d and expiration time %llu\n",
  145. i,
  146. rd[i].flags,
  147. (unsigned long long) rd[i].expiration_time);
  148. rec.expiration_time = GNUNET_htonll (rd[i].expiration_time);
  149. rec.data_size = htonl ((uint32_t) rd[i].data_size);
  150. rec.record_type = htonl (rd[i].record_type);
  151. rec.flags = htonl (rd[i].flags);
  152. if ( (off + sizeof (rec) > dest_size) ||
  153. (off + sizeof (rec) < off) )
  154. {
  155. GNUNET_break (0);
  156. return -1;
  157. }
  158. GNUNET_memcpy (&dest[off],
  159. &rec,
  160. sizeof (rec));
  161. off += sizeof (rec);
  162. if ( (off + rd[i].data_size > dest_size) ||
  163. (off + rd[i].data_size < off) )
  164. {
  165. GNUNET_break (0);
  166. return -1;
  167. }
  168. GNUNET_memcpy (&dest[off],
  169. rd[i].data,
  170. rd[i].data_size);
  171. off += rd[i].data_size;
  172. #if DEBUG_GNSRECORDS
  173. {
  174. char *str;
  175. str = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
  176. rd[i].data,
  177. rd[i].data_size);
  178. if (NULL == str)
  179. {
  180. GNUNET_break_op (0);
  181. return -1;
  182. }
  183. GNUNET_free (str);
  184. }
  185. #endif
  186. }
  187. memset (&dest[off],
  188. 0,
  189. dest_size-off);
  190. return dest_size;
  191. }
  192. /**
  193. * Deserialize the given records to the given destination.
  194. *
  195. * @param len size of the serialized record data
  196. * @param src the serialized record data
  197. * @param rd_count number of records in the rd array
  198. * @param dest where to put the data
  199. * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  200. */
  201. int
  202. GNUNET_GNSRECORD_records_deserialize (size_t len,
  203. const char *src,
  204. unsigned int rd_count,
  205. struct GNUNET_GNSRECORD_Data *dest)
  206. {
  207. struct NetworkRecord rec;
  208. size_t off;
  209. off = 0;
  210. for (unsigned int i=0;i<rd_count;i++)
  211. {
  212. if ( (off + sizeof (rec) > len) ||
  213. (off + sizeof (rec) < off) )
  214. {
  215. GNUNET_break_op (0);
  216. return GNUNET_SYSERR;
  217. }
  218. GNUNET_memcpy (&rec,
  219. &src[off],
  220. sizeof (rec));
  221. dest[i].expiration_time = GNUNET_ntohll (rec.expiration_time);
  222. dest[i].data_size = ntohl ((uint32_t) rec.data_size);
  223. dest[i].record_type = ntohl (rec.record_type);
  224. dest[i].flags = ntohl (rec.flags);
  225. off += sizeof (rec);
  226. if ( (off + dest[i].data_size > len) ||
  227. (off + dest[i].data_size < off) )
  228. {
  229. GNUNET_break_op (0);
  230. return GNUNET_SYSERR;
  231. }
  232. dest[i].data = &src[off];
  233. off += dest[i].data_size;
  234. #if GNUNET_EXTRA_LOGGING
  235. {
  236. char *str;
  237. str = GNUNET_GNSRECORD_value_to_string (dest[i].record_type,
  238. dest[i].data,
  239. dest[i].data_size);
  240. if (NULL == str)
  241. {
  242. GNUNET_break_op (0);
  243. return GNUNET_SYSERR;
  244. }
  245. GNUNET_free (str);
  246. }
  247. #endif
  248. LOG (GNUNET_ERROR_TYPE_DEBUG,
  249. "Deserialized record %u with flags %d and expiration time %llu\n",
  250. i,
  251. dest[i].flags,
  252. (unsigned long long) dest[i].expiration_time);
  253. }
  254. return GNUNET_OK;
  255. }
  256. /* end of gnsrecord_serialization.c */