diff options
author | Martin Schanzenbach <mschanzenbach@posteo.de> | 2012-04-23 13:24:57 +0000 |
---|---|---|
committer | Martin Schanzenbach <mschanzenbach@posteo.de> | 2012-04-23 13:24:57 +0000 |
commit | f40d79e6ce855f141d935915f637614cd5824b48 (patch) | |
tree | a49a548b5403c72d2f49936813737bb589472fd3 /src/gns | |
parent | 0aa07516b001eed4b156ee53eea1f6fdf26e0cb9 (diff) | |
download | gnunet-f40d79e6ce855f141d935915f637614cd5824b48.tar.gz gnunet-f40d79e6ce855f141d935915f637614cd5824b48.zip |
-start nss
Diffstat (limited to 'src/gns')
-rw-r--r-- | src/gns/nss/nss_gns.c | 286 |
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 | |||
43 | struct 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 | ||
54 | static 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 | ||
67 | static 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 | |||
79 | static 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 | |||
90 | static 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 | |||
101 | static int verify_name_allowed(const char *name) { | ||
102 | return ends_with(name, ".gnunet") || ends_with(name, ".zkey"); | ||
103 | } | ||
104 | |||
105 | enum 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 | |||
234 | finish: | ||
235 | return status; | ||
236 | } | ||
237 | |||
238 | enum 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 | |||
256 | enum 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 | |||