aboutsummaryrefslogtreecommitdiff
path: root/src/gns
diff options
context:
space:
mode:
authorMartin Schanzenbach <mschanzenbach@posteo.de>2012-04-23 13:24:57 +0000
committerMartin Schanzenbach <mschanzenbach@posteo.de>2012-04-23 13:24:57 +0000
commitf40d79e6ce855f141d935915f637614cd5824b48 (patch)
treea49a548b5403c72d2f49936813737bb589472fd3 /src/gns
parent0aa07516b001eed4b156ee53eea1f6fdf26e0cb9 (diff)
downloadgnunet-f40d79e6ce855f141d935915f637614cd5824b48.tar.gz
gnunet-f40d79e6ce855f141d935915f637614cd5824b48.zip
-start nss
Diffstat (limited to 'src/gns')
-rw-r--r--src/gns/nss/nss_gns.c286
1 files changed, 286 insertions, 0 deletions
diff --git a/src/gns/nss/nss_gns.c b/src/gns/nss/nss_gns.c
new file mode 100644
index 000000000..054f20b13
--- /dev/null
+++ b/src/gns/nss/nss_gns.c
@@ -0,0 +1,286 @@
1/***
2 This file is part of nss-gns.
3
4 Parts taken from: nss.c in nss-mdns
5***/
6
7#ifdef HAVE_CONFIG_H
8#include <config.h>
9#endif
10
11#include <unistd.h>
12#include <errno.h>
13#include <string.h>
14#include <assert.h>
15#include <netdb.h>
16#include <sys/socket.h>
17#include <nss.h>
18#include <stdio.h>
19#include <stdlib.h>
20
21#elif defined(NSS_IPV4_ONLY)
22#define _nss_mdns_gethostbyname2_r _nss_gns4_minimal_gethostbyname2_r
23#define _nss_mdns_gethostbyname_r _nss_gns4_minimal_gethostbyname_r
24#define _nss_mdns_gethostbyaddr_r _nss_gns4_minimal_gethostbyaddr_r
25#elif defined(NSS_IPV6_ONLY)
26#define _nss_mdns_gethostbyname2_r _nss_gns6_gethostbyname2_r
27#define _nss_mdns_gethostbyname_r _nss_gns6_gethostbyname_r
28#define _nss_mdns_gethostbyaddr_r _nss_gns6_gethostbyaddr_r
29#else
30#define _nss_mdns_gethostbyname2_r _nss_gns_gethostbyname2_r
31#define _nss_mdns_gethostbyname_r _nss_gns_gethostbyname_r
32#define _nss_mdns_gethostbyaddr_r _nss_gns_gethostbyaddr_r
33#endif
34
35/* Maximum number of entries to return */
36#define MAX_ENTRIES 16
37
38#define ALIGN(idx) do { \
39 if (idx % sizeof(void*)) \
40 idx += (sizeof(void*) - idx % sizeof(void*)); /* Align on 32 bit boundary */ \
41} while(0)
42
43struct userdata {
44 int count;
45 int data_len; /* only valid when doing reverse lookup */
46 union {
47 ipv4_address_t ipv4[MAX_ENTRIES];
48 ipv6_address_t ipv6[MAX_ENTRIES];
49 char *name[MAX_ENTRIES];
50 } data;
51};
52
53#ifndef NSS_IPV6_ONLY
54static void ipv4_callback(const ipv4_address_t *ipv4, void *userdata) {
55 struct userdata *u = userdata;
56 assert(ipv4 && userdata);
57
58 if (u->count >= MAX_ENTRIES)
59 return;
60
61 u->data.ipv4[u->count++] = *ipv4;
62 u->data_len += sizeof(ipv4_address_t);
63}
64#endif
65
66#ifndef NSS_IPV4_ONLY
67static void ipv6_callback(const ipv6_address_t *ipv6, void *userdata) {
68 struct userdata *u = userdata;
69 assert(ipv6 && userdata);
70
71 if (u->count >= MAX_ENTRIES)
72 return;
73
74 u->data.ipv6[u->count++] = *ipv6;
75 u->data_len += sizeof(ipv6_address_t);
76}
77#endif
78
79static void name_callback(const char*name, void *userdata) {
80 struct userdata *u = userdata;
81 assert(name && userdata);
82
83 if (u->count >= MAX_ENTRIES)
84 return;
85
86 u->data.name[u->count++] = strdup(name);
87 u->data_len += strlen(name)+1;
88}
89
90static int ends_with(const char *name, const char* suffix) {
91 size_t ln, ls;
92 assert(name);
93 assert(suffix);
94
95 if ((ls = strlen(suffix)) > (ln = strlen(name)))
96 return 0;
97
98 return strcasecmp(name+ln-ls, suffix) == 0;
99}
100
101static int verify_name_allowed(const char *name) {
102 return ends_with(name, ".gnunet") || ends_with(name, ".zkey");
103}
104
105enum nss_status _nss_gns_gethostbyname2_r(
106 const char *name,
107 int af,
108 struct hostent * result,
109 char *buffer,
110 size_t buflen,
111 int *errnop,
112 int *h_errnop) {
113
114 struct userdata u;
115 enum nss_status status = NSS_STATUS_UNAVAIL;
116 int i;
117 size_t address_length, l, idx, astart;
118 void (*ipv4_func)(const ipv4_address_t *ipv4, void *userdata);
119 void (*ipv6_func)(const ipv6_address_t *ipv6, void *userdata);
120 int name_allowed;
121
122 if (af == AF_UNSPEC)
123#ifdef NSS_IPV6_ONLY
124 af = AF_INET6;
125#else
126 af = AF_INET;
127#endif
128
129#ifdef NSS_IPV4_ONLY
130 if (af != AF_INET)
131#elif NSS_IPV6_ONLY
132 if (af != AF_INET6)
133#else
134 if (af != AF_INET && af != AF_INET6)
135#endif
136 {
137 *errnop = EINVAL;
138 *h_errnop = NO_RECOVERY;
139
140 goto finish;
141 }
142
143 address_length = af == AF_INET ? sizeof(ipv4_address_t) : sizeof(ipv6_address_t);
144 if (buflen <
145 sizeof(char*)+ /* alias names */
146 strlen(name)+1) { /* official name */
147
148 *errnop = ERANGE;
149 *h_errnop = NO_RECOVERY;
150 status = NSS_STATUS_TRYAGAIN;
151
152 goto finish;
153 }
154
155 u.count = 0;
156 u.data_len = 0;
157
158#ifdef NSS_IPV6_ONLY
159 ipv4_func = NULL;
160#else
161 ipv4_func = af == AF_INET ? ipv4_callback : NULL;
162#endif
163
164#ifdef NSS_IPV4_ONLY
165 ipv6_func = NULL;
166#else
167 ipv6_func = af == AF_INET6 ? ipv6_callback : NULL;
168#endif
169
170#ifdef ENABLE_GNS
171 name_allowed = verify_name_allowed(name);
172
173 if (gns_works && name_allowed) {
174 int r;
175
176 if ((r = gns_resolve_name(af, name, data)) < 0)
177 gns_works = 0;
178 else if (r == 0) {
179 if (af == AF_INET && ipv4_func)
180 ipv4_func((ipv4_address_t*) data, &u);
181 if (af == AF_INET6 && ipv6_func)
182 ipv6_func((ipv6_address_t*)data, &u);
183 } else
184 status = NSS_STATUS_NOTFOUND;
185 }
186
187#endif /* ENABLE_GNS */
188
189 if (u.count == 0) {
190 *errnop = ETIMEDOUT;
191 *h_errnop = HOST_NOT_FOUND;
192 goto finish;
193 }
194
195 /* Alias names */
196 *((char**) buffer) = NULL;
197 result->h_aliases = (char**) buffer;
198 idx = sizeof(char*);
199
200 /* Official name */
201 strcpy(buffer+idx, name);
202 result->h_name = buffer+idx;
203 idx += strlen(name)+1;
204
205 ALIGN(idx);
206
207 result->h_addrtype = af;
208 result->h_length = address_length;
209
210 /* Check if there's enough space for the addresses */
211 if (buflen < idx+u.data_len+sizeof(char*)*(u.count+1)) {
212 *errnop = ERANGE;
213 *h_errnop = NO_RECOVERY;
214 status = NSS_STATUS_TRYAGAIN;
215 goto finish;
216 }
217
218 /* Addresses */
219 astart = idx;
220 l = u.count*address_length;
221 memcpy(buffer+astart, &u.data, l);
222 /* address_length is a multiple of 32bits, so idx is still aligned
223 * correctly */
224 idx += l;
225
226 /* Address array address_lenght is always a multiple of 32bits */
227 for (i = 0; i < u.count; i++)
228 ((char**) (buffer+idx))[i] = buffer+astart+address_length*i;
229 ((char**) (buffer+idx))[i] = NULL;
230 result->h_addr_list = (char**) (buffer+idx);
231
232 status = NSS_STATUS_SUCCESS;
233
234finish:
235 return status;
236}
237
238enum nss_status _nss_gns_gethostbyname_r (
239 const char *name,
240 struct hostent *result,
241 char *buffer,
242 size_t buflen,
243 int *errnop,
244 int *h_errnop) {
245
246 return _nss_gns_gethostbyname2_r(
247 name,
248 AF_UNSPEC,
249 result,
250 buffer,
251 buflen,
252 errnop,
253 h_errnop);
254}
255
256enum nss_status _nss_gns_gethostbyaddr_r(
257 const void* addr,
258 int len,
259 int af,
260 struct hostent *result,
261 char *buffer,
262 size_t buflen,
263 int *errnop,
264 int *h_errnop) {
265
266 /* we dont do this */
267
268 struct userdata u;
269 enum nss_status status = NSS_STATUS_UNAVAIL;
270 int r;
271 size_t address_length, idx, astart;
272
273 *errnop = EINVAL;
274 *h_errnop = NO_RECOVERY;
275
276 u.count = 0;
277 u.data_len = 0;
278
279 /* Check for address types */
280
281 *h_errnop = NO_RECOVERY;
282
283 status = NSS_STATUS_NOTFOUND;
284 return status;
285}
286