-make doxygen happy
[oweals/gnunet.git] / src / gns / nss / nss_gns.c
1 /***
2     This file is part of nss-gns.
3
4     Parts taken from: nss.c in nss-mdns
5
6     nss-mdns is free software; you can redistribute it and/or modify
7     it under the terms of the GNU Lesser General Public License as published
8     by the Free Software Foundation; either version 2 of the License,
9     or (at your option) any later version.
10  
11     nss-mdns is distributed in the hope that it will be useful, but1
12     WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14     General Public License for more details.
15  
16     You should have received a copy of the GNU Lesser General Public License
17     along with nss-mdns; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19     USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <unistd.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <assert.h>
30 #include <netdb.h>
31 #include <sys/socket.h>
32 #include <nss.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35
36 #ifdef NSS_IPV4_ONLY
37 #define _nss_mdns_gethostbyname2_r _nss_gns4_minimal_gethostbyname2_r
38 #define _nss_mdns_gethostbyname_r  _nss_gns4_minimal_gethostbyname_r
39 #define _nss_mdns_gethostbyaddr_r  _nss_gns4_minimal_gethostbyaddr_r
40 #endif
41
42 #ifdef NSS_IPV6_ONLY
43 #define _nss_mdns_gethostbyname2_r _nss_gns6_gethostbyname2_r
44 #define _nss_mdns_gethostbyname_r  _nss_gns6_gethostbyname_r
45 #define _nss_mdns_gethostbyaddr_r  _nss_gns6_gethostbyaddr_r
46 #endif
47
48 #ifndef NSS_IPV4_ONLY
49 #ifndef NSS_IPV6_ONLY
50 #define _nss_mdns_gethostbyname2_r _nss_gns_gethostbyname2_r
51 #define _nss_mdns_gethostbyname_r  _nss_gns_gethostbyname_r
52 #define _nss_mdns_gethostbyaddr_r  _nss_gns_gethostbyaddr_r
53 #endif
54 #endif
55
56 /* Maximum number of entries to return */
57 #define MAX_ENTRIES 16
58
59 #define ALIGN(idx) do { \
60   if (idx % sizeof(void*)) \
61     idx += (sizeof(void*) - idx % sizeof(void*)); /* Align on 32 bit boundary */ \
62 } while(0)
63
64 struct userdata {
65     int count;
66     int data_len; /* only valid when doing reverse lookup */
67     union  {
68         ipv4_address_t ipv4[MAX_ENTRIES];
69         ipv6_address_t ipv6[MAX_ENTRIES];
70         char *name[MAX_ENTRIES];
71     } data;
72 };
73
74 #ifndef NSS_IPV6_ONLY
75 static void ipv4_callback(const ipv4_address_t *ipv4, void *userdata) {
76     struct userdata *u = userdata;
77     assert(ipv4 && userdata);
78
79     if (u->count >= MAX_ENTRIES)
80         return;
81
82     u->data.ipv4[u->count++] = *ipv4;
83     u->data_len += sizeof(ipv4_address_t);
84 }
85 #endif
86
87 #ifndef NSS_IPV4_ONLY
88 static void ipv6_callback(const ipv6_address_t *ipv6, void *userdata) {
89     struct userdata *u = userdata;
90     assert(ipv6 && userdata);
91
92     if (u->count >= MAX_ENTRIES)
93         return;
94
95     u->data.ipv6[u->count++] = *ipv6;
96     u->data_len += sizeof(ipv6_address_t);
97 }
98 #endif
99
100 static void name_callback(const char*name, void *userdata) {
101     struct userdata *u = userdata;
102     assert(name && userdata);
103
104     if (u->count >= MAX_ENTRIES)
105         return;
106
107     u->data.name[u->count++] = strdup(name);
108     u->data_len += strlen(name)+1;
109 }
110
111 static int ends_with(const char *name, const char* suffix) {
112     size_t ln, ls;
113     assert(name);
114     assert(suffix);
115
116     if ((ls = strlen(suffix)) > (ln = strlen(name)))
117         return 0;
118
119     return strcasecmp(name+ln-ls, suffix) == 0;
120 }
121
122 static int verify_name_allowed(const char *name) {
123     return ends_with(name, ".gnunet") || ends_with(name, ".zkey"); 
124 }
125
126 enum nss_status _nss_gns_gethostbyname2_r(
127     const char *name,
128     int af,
129     struct hostent * result,
130     char *buffer,
131     size_t buflen,
132     int *errnop,
133     int *h_errnop) {
134
135     struct userdata u;
136     enum nss_status status = NSS_STATUS_UNAVAIL;
137     int i;
138     size_t address_length, l, idx, astart;
139     void (*ipv4_func)(const ipv4_address_t *ipv4, void *userdata);
140     void (*ipv6_func)(const ipv6_address_t *ipv6, void *userdata);
141     int name_allowed;
142
143     if (af == AF_UNSPEC)
144 #ifdef NSS_IPV6_ONLY
145         af = AF_INET6;
146 #else
147         af = AF_INET;
148 #endif
149
150 #ifdef NSS_IPV4_ONLY
151     if (af != AF_INET) 
152 #elif NSS_IPV6_ONLY
153     if (af != AF_INET6)
154 #else        
155     if (af != AF_INET && af != AF_INET6)
156 #endif        
157     {    
158         *errnop = EINVAL;
159         *h_errnop = NO_RECOVERY;
160
161         goto finish;
162     }
163
164     address_length = af == AF_INET ? sizeof(ipv4_address_t) : sizeof(ipv6_address_t);
165     if (buflen <
166         sizeof(char*)+    /* alias names */
167         strlen(name)+1)  {   /* official name */
168         
169         *errnop = ERANGE;
170         *h_errnop = NO_RECOVERY;
171         status = NSS_STATUS_TRYAGAIN;
172         
173         goto finish;
174     }
175     
176     u.count = 0;
177     u.data_len = 0;
178
179 #ifdef NSS_IPV6_ONLY
180     ipv4_func = NULL;
181 #else
182     ipv4_func = af == AF_INET ? ipv4_callback : NULL;
183 #endif
184
185 #ifdef NSS_IPV4_ONLY
186     ipv6_func = NULL;
187 #else
188     ipv6_func = af == AF_INET6 ? ipv6_callback : NULL;
189 #endif
190
191 #ifdef ENABLE_GNS
192     name_allowed = verify_name_allowed(name);
193     
194     if (gns_works && name_allowed) {
195         int r;
196
197         if ((r = gns_resolve_name(af, name, data)) < 0)
198             gns_works = 0;
199         else if (r == 0) {
200             if (af == AF_INET && ipv4_func)
201                 ipv4_func((ipv4_address_t*) data, &u);
202             if (af == AF_INET6 && ipv6_func)
203                 ipv6_func((ipv6_address_t*)data, &u);
204         } else
205             status = NSS_STATUS_NOTFOUND;
206     }
207
208 #endif /* ENABLE_GNS */
209
210     if (u.count == 0) {
211         *errnop = ETIMEDOUT;
212         *h_errnop = HOST_NOT_FOUND;
213         goto finish;
214     }
215     
216     /* Alias names */
217     *((char**) buffer) = NULL;
218     result->h_aliases = (char**) buffer;
219     idx = sizeof(char*);
220     
221     /* Official name */
222     strcpy(buffer+idx, name); 
223     result->h_name = buffer+idx;
224     idx += strlen(name)+1;
225
226     ALIGN(idx);
227     
228     result->h_addrtype = af;
229     result->h_length = address_length;
230     
231     /* Check if there's enough space for the addresses */
232     if (buflen < idx+u.data_len+sizeof(char*)*(u.count+1)) {
233         *errnop = ERANGE;
234         *h_errnop = NO_RECOVERY;
235         status = NSS_STATUS_TRYAGAIN;
236         goto finish;
237     }
238
239     /* Addresses */
240     astart = idx;
241     l = u.count*address_length;
242     memcpy(buffer+astart, &u.data, l);
243     /* address_length is a multiple of 32bits, so idx is still aligned
244      * correctly */
245     idx += l;
246
247     /* Address array address_lenght is always a multiple of 32bits */
248     for (i = 0; i < u.count; i++)
249         ((char**) (buffer+idx))[i] = buffer+astart+address_length*i;
250     ((char**) (buffer+idx))[i] = NULL;
251     result->h_addr_list = (char**) (buffer+idx);
252
253     status = NSS_STATUS_SUCCESS;
254     
255 finish:
256     return status;
257 }
258
259 enum nss_status _nss_gns_gethostbyname_r (
260     const char *name,
261     struct hostent *result,
262     char *buffer,
263     size_t buflen,
264     int *errnop,
265     int *h_errnop) {
266
267     return _nss_gns_gethostbyname2_r(
268         name,
269         AF_UNSPEC,
270         result,
271         buffer,
272         buflen,
273         errnop,
274         h_errnop);
275 }
276
277 enum nss_status _nss_gns_gethostbyaddr_r(
278     const void* addr,
279     int len,
280     int af,
281     struct hostent *result,
282     char *buffer,
283     size_t buflen,
284     int *errnop,
285     int *h_errnop) {
286
287     /* we dont do this */
288     
289     struct userdata u;
290     enum nss_status status = NSS_STATUS_UNAVAIL;
291     int r;
292     size_t address_length, idx, astart;
293     
294     *errnop = EINVAL;
295     *h_errnop = NO_RECOVERY;
296
297     u.count = 0;
298     u.data_len = 0;
299
300     /* Check for address types */
301
302     *h_errnop = NO_RECOVERY;
303
304     status = NSS_STATUS_NOTFOUND;
305     return status;
306 }
307