aboutsummaryrefslogtreecommitdiff
path: root/src/gns/gns_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gns/gns_util.c')
-rw-r--r--src/gns/gns_util.c196
1 files changed, 196 insertions, 0 deletions
diff --git a/src/gns/gns_util.c b/src/gns/gns_util.c
new file mode 100644
index 000000000..b2f5e1f38
--- /dev/null
+++ b/src/gns/gns_util.c
@@ -0,0 +1,196 @@
1#include "gns.h"
2
3/**
4 * Add a DNS name to the buffer at the given location.
5 *
6 * @param dst where to write the name
7 * @param dst_len number of bytes in dst
8 * @param off pointer to offset where to write the name (increment by bytes used)
9 * must not be changed if there is an error
10 * @param name name to write
11 * @return GNUNET_SYSERR if 'name' is invalid
12 * GNUNET_NO if 'name' did not fit
13 * GNUNET_OK if 'name' was added to 'dst'
14 */
15static int
16add_name (char *dst,
17 size_t dst_len,
18 size_t *off,
19 const char *name)
20{
21 const char *dot;
22 size_t start;
23 size_t pos;
24 size_t len;
25
26 if (NULL == name)
27 return GNUNET_SYSERR;
28 start = *off;
29 if (start + strlen (name) + 2 > dst_len)
30 return GNUNET_NO;
31 pos = start;
32 do
33 {
34 dot = strchr (name, '.');
35 if (NULL == dot)
36 len = strlen (name);
37 else
38 len = dot - name;
39 if ( (len >= 64) || (len == 0) )
40 return GNUNET_NO; /* segment too long or empty */
41 dst[pos++] = (char) (uint8_t) len;
42 memcpy (&dst[pos], name, len);
43 pos += len;
44 name += len + 1; /* also skip dot */
45 }
46 while (NULL != dot);
47 dst[pos++] = '\0'; /* terminator */
48 *off = pos;
49 return GNUNET_OK;
50}
51
52/**
53 * Add an MX record to the buffer at the given location.
54 *
55 * @param dst where to write the mx record
56 * @param dst_len number of bytes in dst
57 * @param off pointer to offset where to write the mx information (increment by bytes used);
58 * can also change if there was an error
59 * @param mx mx information to write
60 * @return GNUNET_SYSERR if 'mx' is invalid
61 * GNUNET_NO if 'mx' did not fit
62 * GNUNET_OK if 'mx' was added to 'dst'
63 */
64static int
65add_mx (char *dst,
66 size_t dst_len,
67 size_t *off,
68 const struct GNUNET_DNSPARSER_MxRecord *mx)
69{
70 uint16_t mxpref;
71
72 if (*off + sizeof (uint16_t) > dst_len)
73 return GNUNET_NO;
74 mxpref = htons (mx->preference);
75 memcpy (&dst[*off], &mxpref, sizeof (mxpref));
76 (*off) += sizeof (mxpref);
77 return add_name (dst, dst_len, off, mx->mxhost);
78}
79
80
81/**
82 * Add an SOA record to the buffer at the given location.
83 *
84 * @param dst where to write the SOA record
85 * @param dst_len number of bytes in dst
86 * @param off pointer to offset where to write the SOA information (increment by bytes used)
87 * can also change if there was an error
88 * @param soa SOA information to write
89 * @return GNUNET_SYSERR if 'soa' is invalid
90 * GNUNET_NO if 'soa' did not fit
91 * GNUNET_OK if 'soa' was added to 'dst'
92 */
93static int
94add_soa (char *dst,
95 size_t dst_len,
96 size_t *off,
97 const struct GNUNET_DNSPARSER_SoaRecord *soa)
98{
99 struct soa_data sd;
100 int ret;
101
102 if ( (GNUNET_OK != (ret = add_name (dst,
103 dst_len,
104 off,
105 soa->mname))) ||
106 (GNUNET_OK != (ret = add_name (dst,
107 dst_len,
108 off,
109 soa->rname)) ) )
110 return ret;
111 if (*off + sizeof (struct soa_data) > dst_len)
112 return GNUNET_NO;
113 sd.serial = htonl (soa->serial);
114 sd.refresh = htonl (soa->refresh);
115 sd.retry = htonl (soa->retry);
116 sd.expire = htonl (soa->expire);
117 sd.minimum = htonl (soa->minimum_ttl);
118 memcpy (&dst[*off], &sd, sizeof (sd));
119 (*off) += sizeof (sd);
120 return GNUNET_OK;
121}
122
123/**
124 * Add a DNS record to the buffer at the given location.
125 *
126 * @param dst where to write the record
127 * @param dst_len number of bytes in dst
128 * @param off pointer to offset where to write the query (increment by bytes used)
129 * must not be changed if there is an error
130 * @param record record to write
131 * @return GNUNET_SYSERR if 'record' is invalid
132 * GNUNET_NO if 'record' did not fit
133 * GNUNET_OK if 'record' was added to 'dst'
134 */
135static int
136parse_record (char *dst,
137 size_t dst_len,
138 size_t *off,
139 const struct GNUNET_GNS_Record *record)
140{
141 int ret;
142 size_t start;
143 size_t pos;
144 struct record_line rl;
145
146 start = *off;
147 ret = add_name (dst, dst_len - sizeof (struct record_line), off, record->name);
148 if (ret != GNUNET_OK)
149 return ret;
150 /* '*off' is now the position where we will need to write the record line */
151
152 pos = *off + sizeof (struct record_line);
153 switch (record->type)
154 {
155 case GNUNET_DNSPARSER_TYPE_MX:
156 ret = add_mx (dst, dst_len, &pos, record->data.mx);
157 break;
158 case GNUNET_DNSPARSER_TYPE_SOA:
159 ret = add_soa (dst, dst_len, &pos, record->data.soa);
160 break;
161 case GNUNET_DNSPARSER_TYPE_NS:
162 case GNUNET_DNSPARSER_TYPE_CNAME:
163 case GNUNET_DNSPARSER_TYPE_PTR:
164 ret = add_name (dst, dst_len, &pos, record->data.hostname);
165 break;
166 default:
167 if (pos + record->data.raw.data_len > dst_len)
168 {
169 ret = GNUNET_NO;
170 break;
171 }
172 memcpy (&dst[pos], record->data.raw.data, record->data.raw.data_len);
173 pos += record->data.raw.data_len;
174 ret = GNUNET_OK;
175 break;
176 }
177 if (ret != GNUNET_OK)
178 {
179 *off = start;
180 return GNUNET_NO;
181 }
182
183 if (pos - (*off + sizeof (struct record_line)) > UINT16_MAX)
184 {
185 /* record data too long */
186 *off = start;
187 return GNUNET_NO;
188 }
189 rl.type = htons (record->type);
190 rl.class = htons (record->class);
191 rl.ttl = htonl (GNUNET_TIME_absolute_get_remaining (record->expiration_time).rel_value / 1000); /* in seconds */
192 rl.data_len = htons ((uint16_t) (pos - (*off + sizeof (struct record_line))));
193 memcpy (&dst[*off], &rl, sizeof (struct record_line));
194 *off = pos;
195 return GNUNET_OK;
196}