error handling
[oweals/gnunet.git] / src / gnsrecord / gnsrecord_misc.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009-2013 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
22  * @file gnsrecord/gnsrecord_misc.c
23  * @brief MISC functions related to GNS records
24  * @author Martin Schanzenbach
25  * @author Matthias Wachs
26  * @author Christian Grothoff
27  */
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_signatures.h"
32 #include "gnunet_arm_service.h"
33 #include "gnunet_gnsrecord_lib.h"
34 #include "gnunet_dnsparser_lib.h"
35 #include "gnunet_tun_lib.h"
36
37
38 #define LOG(kind, ...) GNUNET_log_from (kind, "gnsrecord", __VA_ARGS__)
39
40 /**
41  * Convert a UTF-8 string to UTF-8 lowercase
42  * @param src source string
43  * @return converted result
44  */
45 char *
46 GNUNET_GNSRECORD_string_to_lowercase (const char *src)
47 {
48   char *res;
49
50   res = GNUNET_strdup (src);
51   GNUNET_STRINGS_utf8_tolower (src, res);
52   return res;
53 }
54
55
56 /**
57  * Convert a zone key to a string (for printing debug messages).
58  * This is one of the very few calls in the entire API that is
59  * NOT reentrant!
60  *
61  * @param z the zone key
62  * @return string form; will be overwritten by next call to #GNUNET_GNSRECORD_z2s
63  */
64 const char *
65 GNUNET_GNSRECORD_z2s (const struct GNUNET_CRYPTO_EcdsaPublicKey *z)
66 {
67   static char buf[sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey) * 8];
68   char *end;
69
70   end = GNUNET_STRINGS_data_to_string ((const unsigned char *) z,
71                                        sizeof(struct
72                                               GNUNET_CRYPTO_EcdsaPublicKey),
73                                        buf, sizeof(buf));
74   if (NULL == end)
75   {
76     GNUNET_break (0);
77     return NULL;
78   }
79   *end = '\0';
80   return buf;
81 }
82
83
84 /**
85  * Compares if two records are equal (ignoring flags such
86  * as authority, private and pending, but not relative vs.
87  * absolute expiration time).
88  *
89  * @param a record
90  * @param b record
91  * @return #GNUNET_YES if the records are equal or #GNUNET_NO if they are not
92  */
93 int
94 GNUNET_GNSRECORD_records_cmp (const struct GNUNET_GNSRECORD_Data *a,
95                               const struct GNUNET_GNSRECORD_Data *b)
96 {
97   LOG (GNUNET_ERROR_TYPE_DEBUG,
98        "Comparing records\n");
99   if (a->record_type != b->record_type)
100   {
101     LOG (GNUNET_ERROR_TYPE_DEBUG,
102          "Record type %lu != %lu\n", a->record_type, b->record_type);
103     return GNUNET_NO;
104   }
105   if ((a->expiration_time != b->expiration_time) &&
106       ((a->expiration_time != 0) && (b->expiration_time != 0)))
107   {
108     LOG (GNUNET_ERROR_TYPE_DEBUG,
109          "Expiration time %llu != %llu\n",
110          a->expiration_time,
111          b->expiration_time);
112     return GNUNET_NO;
113   }
114   if ((a->flags & GNUNET_GNSRECORD_RF_RCMP_FLAGS)
115       != (b->flags & GNUNET_GNSRECORD_RF_RCMP_FLAGS))
116   {
117     LOG (GNUNET_ERROR_TYPE_DEBUG,
118          "Flags %lu (%lu) != %lu (%lu)\n", a->flags,
119          a->flags & GNUNET_GNSRECORD_RF_RCMP_FLAGS, b->flags,
120          b->flags & GNUNET_GNSRECORD_RF_RCMP_FLAGS);
121     return GNUNET_NO;
122   }
123   if (a->data_size != b->data_size)
124   {
125     LOG (GNUNET_ERROR_TYPE_DEBUG,
126          "Data size %lu != %lu\n",
127          a->data_size,
128          b->data_size);
129     return GNUNET_NO;
130   }
131   if (0 != memcmp (a->data, b->data, a->data_size))
132   {
133     LOG (GNUNET_ERROR_TYPE_DEBUG,
134          "Data contents do not match\n");
135     return GNUNET_NO;
136   }
137   LOG (GNUNET_ERROR_TYPE_DEBUG,
138        "Records are equal\n");
139   return GNUNET_YES;
140 }
141
142
143 /**
144  * Returns the expiration time of the given block of records. The block
145  * expiration time is the expiration time of the record with smallest
146  * expiration time.
147  *
148  * @param rd_count number of records given in @a rd
149  * @param rd array of records
150  * @return absolute expiration time
151  */
152 struct GNUNET_TIME_Absolute
153 GNUNET_GNSRECORD_record_get_expiration_time (unsigned int rd_count,
154                                              const struct
155                                              GNUNET_GNSRECORD_Data *rd)
156 {
157   struct GNUNET_TIME_Absolute expire;
158   struct GNUNET_TIME_Absolute at;
159   struct GNUNET_TIME_Relative rt;
160   struct GNUNET_TIME_Absolute at_shadow;
161   struct GNUNET_TIME_Relative rt_shadow;
162
163   if (NULL == rd)
164     return GNUNET_TIME_UNIT_ZERO_ABS;
165   expire = GNUNET_TIME_UNIT_FOREVER_ABS;
166   for (unsigned int c = 0; c < rd_count; c++)
167   {
168     if (0 != (rd[c].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
169     {
170       rt.rel_value_us = rd[c].expiration_time;
171       at = GNUNET_TIME_relative_to_absolute (rt);
172     }
173     else
174     {
175       at.abs_value_us = rd[c].expiration_time;
176     }
177
178     for (unsigned int c2 = 0; c2 < rd_count; c2++)
179     {
180       /* Check for shadow record */
181       if ((c == c2) ||
182           (rd[c].record_type != rd[c2].record_type) ||
183           (0 == (rd[c2].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD)))
184         continue;
185       /* We have a shadow record */
186       if (0 != (rd[c2].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
187       {
188         rt_shadow.rel_value_us = rd[c2].expiration_time;
189         at_shadow = GNUNET_TIME_relative_to_absolute (rt_shadow);
190       }
191       else
192       {
193         at_shadow.abs_value_us = rd[c2].expiration_time;
194       }
195       at = GNUNET_TIME_absolute_max (at,
196                                      at_shadow);
197     }
198     expire = GNUNET_TIME_absolute_min (at,
199                                        expire);
200   }
201   LOG (GNUNET_ERROR_TYPE_DEBUG,
202        "Determined expiration time for block with %u records to be %s\n",
203        rd_count,
204        GNUNET_STRINGS_absolute_time_to_string (expire));
205   return expire;
206 }
207
208
209 /**
210  * Test if a given record is expired.
211  *
212  * @return #GNUNET_YES if the record is expired,
213  *         #GNUNET_NO if not
214  */
215 int
216 GNUNET_GNSRECORD_is_expired (const struct GNUNET_GNSRECORD_Data *rd)
217 {
218   struct GNUNET_TIME_Absolute at;
219
220   if (0 != (rd->flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
221     return GNUNET_NO;
222   at.abs_value_us = rd->expiration_time;
223   return (0 == GNUNET_TIME_absolute_get_remaining (at).rel_value_us) ?
224          GNUNET_YES : GNUNET_NO;
225 }
226
227
228 /**
229  * Convert public key to the respective absolute domain name in the
230  * ".zkey" pTLD.
231  * This is one of the very few calls in the entire API that is
232  * NOT reentrant!
233  *
234  * @param pkey a public key with a point on the eliptic curve
235  * @return string "X.zkey" where X is the public
236  *         key in an encoding suitable for DNS labels.
237  */
238 const char *
239 GNUNET_GNSRECORD_pkey_to_zkey (const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
240 {
241   static char ret[128];
242   char *pkeys;
243
244   pkeys = GNUNET_CRYPTO_ecdsa_public_key_to_string (pkey);
245   GNUNET_snprintf (ret,
246                    sizeof(ret),
247                    "%s",
248                    pkeys);
249   GNUNET_free (pkeys);
250   return ret;
251 }
252
253
254 /**
255  * Convert an absolute domain name to the
256  * respective public key.
257  *
258  * @param zkey string encoding the coordinates of the public
259  *         key in an encoding suitable for DNS labels.
260  * @param pkey set to a public key on the eliptic curve
261  * @return #GNUNET_SYSERR if @a zkey has the wrong syntax
262  */
263 int
264 GNUNET_GNSRECORD_zkey_to_pkey (const char *zkey,
265                                struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
266 {
267   if (GNUNET_OK !=
268       GNUNET_CRYPTO_ecdsa_public_key_from_string (zkey,
269                                                   strlen (zkey),
270                                                   pkey))
271     return GNUNET_SYSERR;
272   return GNUNET_OK;
273 }
274
275
276 /* end of gnsrecord_misc.c */