update NSS plugin to hijack non-gnu/zkey tlds as well
[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 General Public License as published
8     by the Free Software Foundation; either version 3 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
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 "nss_gns_query.h"
34
35 #include <arpa/inet.h>
36
37 /** macro to align idx to 32bit boundary */
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
43
44 /**
45  * The gethostbyname hook executed by nsswitch
46  *
47  * @param name the name to resolve
48  * @param af the address family to resolve
49  * @param result the result hostent
50  * @param buffer the result buffer
51  * @param buflen length of the buffer
52  * @param errnop idk
53  * @param h_errnop idk
54  * @return a nss_status code
55  */
56 enum nss_status
57 _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
71     if (af == AF_UNSPEC)
72 #ifdef NSS_IPV6_ONLY
73         af = AF_INET6;
74 #else
75         af = AF_INET;
76 #endif
77
78 #ifdef NSS_IPV4_ONLY
79     if (af != AF_INET)
80 #elif NSS_IPV6_ONLY
81     if (af != AF_INET6)
82 #else
83     if (af != AF_INET && af != AF_INET6)
84 #endif
85     {
86         *errnop = EINVAL;
87         *h_errnop = NO_RECOVERY;
88
89         goto finish;
90     }
91
92     address_length = af == AF_INET ? sizeof(ipv4_address_t) : sizeof(ipv6_address_t);
93     if (buflen <
94         sizeof(char*)+    /* alias names */
95         strlen(name)+1)  {   /* official name */
96
97         *errnop = ERANGE;
98         *h_errnop = NO_RECOVERY;
99         status = NSS_STATUS_TRYAGAIN;
100
101         goto finish;
102     }
103
104     u.count = 0;
105     u.data_len = 0;
106
107     i = gns_resolve_name(af, name, &u);
108     if (-3 == i)
109       {
110         status = NSS_STATUS_NOTFOUND;
111         goto finish;
112       }
113     if (-2 == i)
114       {
115         status = NSS_STATUS_UNAVAIL;
116         goto finish;
117       }
118     if ( (-1 == i) ||
119          (u.count == 0) )
120       {
121         *errnop = ETIMEDOUT;
122         *h_errnop = HOST_NOT_FOUND;
123         status = NSS_STATUS_NOTFOUND;
124         goto finish;
125       }
126
127
128     /* Alias names */
129     *((char**) buffer) = NULL;
130     result->h_aliases = (char**) buffer;
131     idx = sizeof(char*);
132
133     /* Official name */
134     strcpy(buffer+idx, name);
135     result->h_name = buffer+idx;
136     idx += strlen(name)+1;
137
138     ALIGN(idx);
139
140     result->h_addrtype = af;
141     result->h_length = address_length;
142
143     /* Check if there's enough space for the addresses */
144     if (buflen < idx+u.data_len+sizeof(char*)*(u.count+1)) {
145         *errnop = ERANGE;
146         *h_errnop = NO_RECOVERY;
147         status = NSS_STATUS_TRYAGAIN;
148         goto finish;
149     }
150
151     /* Addresses */
152     astart = idx;
153     l = u.count*address_length;
154     if (0 != l)
155       memcpy(buffer+astart, &u.data, l);
156     /* address_length is a multiple of 32bits, so idx is still aligned
157      * correctly */
158     idx += l;
159
160     /* Address array address_lenght is always a multiple of 32bits */
161     for (i = 0; i < u.count; i++)
162         ((char**) (buffer+idx))[i] = buffer+astart+address_length*i;
163     ((char**) (buffer+idx))[i] = NULL;
164     result->h_addr_list = (char**) (buffer+idx);
165
166     status = NSS_STATUS_SUCCESS;
167
168 finish:
169     return status;
170 }
171
172 /**
173  * The gethostbyname hook executed by nsswitch
174  *
175  * @param name the name to resolve
176  * @param result the result hostent
177  * @param buffer the result buffer
178  * @param buflen length of the buffer
179  * @param errnop idk
180  * @param h_errnop idk
181  * @return a nss_status code
182  */
183 enum nss_status
184 _nss_gns_gethostbyname_r (
185     const char *name,
186     struct hostent *result,
187     char *buffer,
188     size_t buflen,
189     int *errnop,
190     int *h_errnop) {
191
192     return _nss_gns_gethostbyname2_r(
193         name,
194         AF_UNSPEC,
195         result,
196         buffer,
197         buflen,
198         errnop,
199         h_errnop);
200 }
201
202 /**
203  * The gethostbyaddr hook executed by nsswitch
204  * We can't do this so we always return NSS_STATUS_UNAVAIL
205  *
206  * @param addr the address to resolve
207  * @param len the length of the address
208  * @param af the address family of the address
209  * @param result the result hostent
210  * @param buffer the result buffer
211  * @param buflen length of the buffer
212  * @param errnop idk
213  * @param h_errnop idk
214  * @return NSS_STATUS_UNAVAIL
215  */
216 enum nss_status
217 _nss_gns_gethostbyaddr_r(
218     const void* addr,
219     int len,
220     int af,
221     struct hostent *result,
222     char *buffer,
223     size_t buflen,
224     int *errnop,
225     int *h_errnop) {
226
227     *errnop = EINVAL;
228     *h_errnop = NO_RECOVERY;
229     //NOTE we allow to leak this into DNS so no NOTFOUND
230     return NSS_STATUS_UNAVAIL;
231 }