-cleanup
[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 static int ends_with(const char *name, const char* suffix) {
43     size_t ln, ls;
44     assert(name);
45     assert(suffix);
46
47     if ((ls = strlen(suffix)) > (ln = strlen(name)))
48         return 0;
49
50     return strcasecmp(name+ln-ls, suffix) == 0;
51 }
52
53 static int verify_name_allowed(const char *name) {
54     return ends_with(name, ".gnunet") || ends_with(name, ".zkey"); 
55 }
56
57 enum nss_status _nss_gns_gethostbyname2_r(
58     const char *name,
59     int af,
60     struct hostent * result,
61     char *buffer,
62     size_t buflen,
63     int *errnop,
64     int *h_errnop) {
65
66     struct userdata u;
67     enum nss_status status = NSS_STATUS_UNAVAIL;
68     int i;
69     size_t address_length, l, idx, astart;
70     int name_allowed;
71     
72     if (af == AF_UNSPEC)
73 #ifdef NSS_IPV6_ONLY
74         af = AF_INET6;
75 #else
76         af = AF_INET;
77 #endif
78
79 #ifdef NSS_IPV4_ONLY
80     if (af != AF_INET) 
81 #elif NSS_IPV6_ONLY
82     if (af != AF_INET6)
83 #else        
84     if (af != AF_INET && af != AF_INET6)
85 #endif        
86     {    
87         *errnop = EINVAL;
88         *h_errnop = NO_RECOVERY;
89
90         goto finish;
91     }
92
93     address_length = af == AF_INET ? sizeof(ipv4_address_t) : sizeof(ipv6_address_t);
94     if (buflen <
95         sizeof(char*)+    /* alias names */
96         strlen(name)+1)  {   /* official name */
97         
98         *errnop = ERANGE;
99         *h_errnop = NO_RECOVERY;
100         status = NSS_STATUS_TRYAGAIN;
101         
102         goto finish;
103     }
104     
105     u.count = 0;
106     u.data_len = 0;
107
108     name_allowed = verify_name_allowed(name);
109     
110     if (name_allowed) {
111
112         if (!gns_resolve_name(af, name, &u) == 0)
113         {
114           status = NSS_STATUS_NOTFOUND;
115         }
116     }
117
118     if (u.count == 0) {
119         *errnop = ETIMEDOUT;
120         *h_errnop = HOST_NOT_FOUND;
121         printf("not found\n");
122         goto finish;
123     }
124
125         
126     /* Alias names */
127     *((char**) buffer) = NULL;
128     result->h_aliases = (char**) buffer;
129     idx = sizeof(char*);
130     
131     /* Official name */
132     strcpy(buffer+idx, name); 
133     result->h_name = buffer+idx;
134     idx += strlen(name)+1;
135
136     ALIGN(idx);
137     
138     result->h_addrtype = af;
139     result->h_length = address_length;
140     
141     /* Check if there's enough space for the addresses */
142     if (buflen < idx+u.data_len+sizeof(char*)*(u.count+1)) {
143         *errnop = ERANGE;
144         *h_errnop = NO_RECOVERY;
145         status = NSS_STATUS_TRYAGAIN;
146         goto finish;
147     }
148
149     /* Addresses */
150     astart = idx;
151     l = u.count*address_length;
152     memcpy(buffer+astart, &u.data, l);
153     /* address_length is a multiple of 32bits, so idx is still aligned
154      * correctly */
155     idx += l;
156
157     /* Address array address_lenght is always a multiple of 32bits */
158     for (i = 0; i < u.count; i++)
159         ((char**) (buffer+idx))[i] = buffer+astart+address_length*i;
160     ((char**) (buffer+idx))[i] = NULL;
161     result->h_addr_list = (char**) (buffer+idx);
162
163     status = NSS_STATUS_SUCCESS;
164     
165 finish:
166     return status;
167 }
168
169 enum nss_status _nss_gns_gethostbyname_r (
170     const char *name,
171     struct hostent *result,
172     char *buffer,
173     size_t buflen,
174     int *errnop,
175     int *h_errnop) {
176
177     return _nss_gns_gethostbyname2_r(
178         name,
179         AF_UNSPEC,
180         result,
181         buffer,
182         buflen,
183         errnop,
184         h_errnop);
185 }
186
187 enum nss_status _nss_gns_gethostbyaddr_r(
188     const void* addr,
189     int len,
190     int af,
191     struct hostent *result,
192     char *buffer,
193     size_t buflen,
194     int *errnop,
195     int *h_errnop) {
196
197     /* we dont do this */
198     
199     enum nss_status status = NSS_STATUS_UNAVAIL;
200     
201     *errnop = EINVAL;
202     *h_errnop = NO_RECOVERY;
203
204     /* Check for address types */
205
206     *h_errnop = NO_RECOVERY;
207
208     status = NSS_STATUS_NOTFOUND;
209     return status;
210 }
211