-preliminary nss plugin AKA works for me
[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 #include <gnunet_config.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <assert.h>
27 #include <netdb.h>
28 #include <sys/socket.h>
29 #include <nss.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 #include "query.h"
34
35 #include <arpa/inet.h>
36
37 #define ALIGN(idx) do { \
38   if (idx % sizeof(void*)) \
39     idx += (sizeof(void*) - idx % sizeof(void*)); /* Align on 32 bit boundary */ \
40 } while(0)
41
42 #ifndef NSS_IPV6_ONLY
43 static void ipv4_callback(const ipv4_address_t *ipv4, void *userdata) {
44     struct userdata *u = userdata;
45     
46     /*test!*/
47     ipv4_address_t *ipv4_test;
48     struct in_addr testaddr;
49     inet_pton(AF_INET, "5.5.5.5", &testaddr);
50     ipv4_test = (ipv4_address_t *)&testaddr;
51     /*test!*/
52     /*assert(ipv4 && userdata);*/
53
54     if (u->count >= MAX_ENTRIES)
55         return;
56
57     u->data.ipv4[u->count++] = *ipv4_test;
58     u->data_len += sizeof(ipv4_address_t);
59 }
60 #endif
61
62 #ifndef NSS_IPV4_ONLY
63 static void ipv6_callback(const ipv6_address_t *ipv6, void *userdata) {
64     struct userdata *u = userdata;
65     assert(ipv6 && userdata);
66
67     if (u->count >= MAX_ENTRIES)
68         return;
69
70     u->data.ipv6[u->count++] = *ipv6;
71     u->data_len += sizeof(ipv6_address_t);
72 }
73 #endif
74
75 static void name_callback(const char*name, void *userdata) {
76     struct userdata *u = userdata;
77     assert(name && userdata);
78
79     if (u->count >= MAX_ENTRIES)
80         return;
81
82     u->data.name[u->count++] = strdup(name);
83     u->data_len += strlen(name)+1;
84 }
85
86 static int ends_with(const char *name, const char* suffix) {
87     size_t ln, ls;
88     assert(name);
89     assert(suffix);
90
91     if ((ls = strlen(suffix)) > (ln = strlen(name)))
92         return 0;
93
94     return strcasecmp(name+ln-ls, suffix) == 0;
95 }
96
97 static int verify_name_allowed(const char *name) {
98     return ends_with(name, ".gnunet") || ends_with(name, ".zkey"); 
99 }
100
101 enum nss_status _nss_gns_gethostbyname2_r(
102     const char *name,
103     int af,
104     struct hostent * result,
105     char *buffer,
106     size_t buflen,
107     int *errnop,
108     int *h_errnop) {
109
110     struct userdata u;
111     enum nss_status status = NSS_STATUS_UNAVAIL;
112     int i;
113     size_t address_length, l, idx, astart;
114     int name_allowed;
115     
116     printf("v6: %d\n", af == AF_INET6);
117
118     if (af == AF_UNSPEC)
119 #ifdef NSS_IPV6_ONLY
120         af = AF_INET6;
121 #else
122         af = AF_INET;
123 #endif
124
125 #ifdef NSS_IPV4_ONLY
126     if (af != AF_INET) 
127 #elif NSS_IPV6_ONLY
128     if (af != AF_INET6)
129 #else        
130     if (af != AF_INET && af != AF_INET6)
131 #endif        
132     {    
133         *errnop = EINVAL;
134         *h_errnop = NO_RECOVERY;
135
136         goto finish;
137     }
138
139     address_length = af == AF_INET ? sizeof(ipv4_address_t) : sizeof(ipv6_address_t);
140     if (buflen <
141         sizeof(char*)+    /* alias names */
142         strlen(name)+1)  {   /* official name */
143         
144         *errnop = ERANGE;
145         *h_errnop = NO_RECOVERY;
146         status = NSS_STATUS_TRYAGAIN;
147         
148         goto finish;
149     }
150     
151     u.count = 0;
152     u.data_len = 0;
153
154     name_allowed = verify_name_allowed(name);
155     
156     if (name_allowed) {
157
158         if (gns_resolve_name(af, name, &u) == 0)
159         {
160             printf("GNS success\n");
161         } else
162             status = NSS_STATUS_NOTFOUND;
163     }
164
165     if (u.count == 0) {
166         *errnop = ETIMEDOUT;
167         *h_errnop = HOST_NOT_FOUND;
168         printf("not found\n");
169         goto finish;
170     }
171
172         
173     /* Alias names */
174     *((char**) buffer) = NULL;
175     result->h_aliases = (char**) buffer;
176     idx = sizeof(char*);
177     
178     /* Official name */
179     strcpy(buffer+idx, name); 
180     result->h_name = buffer+idx;
181     idx += strlen(name)+1;
182
183     ALIGN(idx);
184     
185     result->h_addrtype = af;
186     result->h_length = address_length;
187     
188     /* Check if there's enough space for the addresses */
189     if (buflen < idx+u.data_len+sizeof(char*)*(u.count+1)) {
190         *errnop = ERANGE;
191         *h_errnop = NO_RECOVERY;
192         status = NSS_STATUS_TRYAGAIN;
193         goto finish;
194     }
195
196     /* Addresses */
197     astart = idx;
198     l = u.count*address_length;
199     memcpy(buffer+astart, &u.data, l);
200     /* address_length is a multiple of 32bits, so idx is still aligned
201      * correctly */
202     idx += l;
203
204     /* Address array address_lenght is always a multiple of 32bits */
205     for (i = 0; i < u.count; i++)
206         ((char**) (buffer+idx))[i] = buffer+astart+address_length*i;
207     ((char**) (buffer+idx))[i] = NULL;
208     result->h_addr_list = (char**) (buffer+idx);
209
210     status = NSS_STATUS_SUCCESS;
211     
212 finish:
213     return status;
214 }
215
216 enum nss_status _nss_gns_gethostbyname_r (
217     const char *name,
218     struct hostent *result,
219     char *buffer,
220     size_t buflen,
221     int *errnop,
222     int *h_errnop) {
223
224     return _nss_gns_gethostbyname2_r(
225         name,
226         AF_UNSPEC,
227         result,
228         buffer,
229         buflen,
230         errnop,
231         h_errnop);
232 }
233
234 enum nss_status _nss_gns_gethostbyaddr_r(
235     const void* addr,
236     int len,
237     int af,
238     struct hostent *result,
239     char *buffer,
240     size_t buflen,
241     int *errnop,
242     int *h_errnop) {
243
244     /* we dont do this */
245     
246     enum nss_status status = NSS_STATUS_UNAVAIL;
247     
248     *errnop = EINVAL;
249     *h_errnop = NO_RECOVERY;
250
251     /* Check for address types */
252
253     *h_errnop = NO_RECOVERY;
254
255     status = NSS_STATUS_NOTFOUND;
256     return status;
257 }
258