source: trunk/server/lib/addns/dnssock.c@ 812

Last change on this file since 812 was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 8.9 KB
Line 
1/*
2 Linux DNS client library implementation
3
4 Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
5 Copyright (C) 2006 Gerald Carter <jerry@samba.org>
6
7 ** NOTE! The following LGPL license applies to the libaddns
8 ** library. This does NOT imply that all of Samba is released
9 ** under the LGPL
10
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 2.1 of the License, or (at your option) any later version.
15
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
20
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, see <http://www.gnu.org/licenses/>.
23*/
24
25#include "replace.h"
26#include "dns.h"
27#include <sys/time.h>
28#include <unistd.h>
29#include "system/select.h"
30
31static int destroy_dns_connection(struct dns_connection *conn)
32{
33 return close(conn->s);
34}
35
36/********************************************************************
37********************************************************************/
38
39static DNS_ERROR dns_tcp_open( const char *nameserver,
40 TALLOC_CTX *mem_ctx,
41 struct dns_connection **result )
42{
43 uint32_t ulAddress;
44 struct hostent *pHost;
45 struct sockaddr_in s_in;
46 struct dns_connection *conn;
47 int res;
48
49 if (!(conn = talloc(mem_ctx, struct dns_connection))) {
50 return ERROR_DNS_NO_MEMORY;
51 }
52
53 if ( (ulAddress = inet_addr( nameserver )) == INADDR_NONE ) {
54 if ( (pHost = gethostbyname( nameserver )) == NULL ) {
55 TALLOC_FREE(conn);
56 return ERROR_DNS_INVALID_NAME_SERVER;
57 }
58 memcpy( &ulAddress, pHost->h_addr, pHost->h_length );
59 }
60
61 conn->s = socket( PF_INET, SOCK_STREAM, 0 );
62 if (conn->s == -1) {
63 TALLOC_FREE(conn);
64 return ERROR_DNS_CONNECTION_FAILED;
65 }
66
67 talloc_set_destructor(conn, destroy_dns_connection);
68
69 s_in.sin_family = AF_INET;
70 s_in.sin_addr.s_addr = ulAddress;
71 s_in.sin_port = htons( DNS_TCP_PORT );
72
73 res = connect(conn->s, (struct sockaddr*)&s_in, sizeof( s_in ));
74 if (res == -1) {
75 TALLOC_FREE(conn);
76 return ERROR_DNS_CONNECTION_FAILED;
77 }
78
79 conn->hType = DNS_TCP;
80
81 *result = conn;
82 return ERROR_DNS_SUCCESS;
83}
84
85/********************************************************************
86********************************************************************/
87
88static DNS_ERROR dns_udp_open( const char *nameserver,
89 TALLOC_CTX *mem_ctx,
90 struct dns_connection **result )
91{
92 unsigned long ulAddress;
93 struct hostent *pHost;
94 struct sockaddr_in RecvAddr;
95 struct dns_connection *conn;
96
97 if (!(conn = talloc(NULL, struct dns_connection))) {
98 return ERROR_DNS_NO_MEMORY;
99 }
100
101 if ( (ulAddress = inet_addr( nameserver )) == INADDR_NONE ) {
102 if ( (pHost = gethostbyname( nameserver )) == NULL ) {
103 TALLOC_FREE(conn);
104 return ERROR_DNS_INVALID_NAME_SERVER;
105 }
106 memcpy( &ulAddress, pHost->h_addr, pHost->h_length );
107 }
108
109 /* Create a socket for sending data */
110
111 conn->s = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
112 if (conn->s == -1) {
113 TALLOC_FREE(conn);
114 return ERROR_DNS_CONNECTION_FAILED;
115 }
116
117 talloc_set_destructor(conn, destroy_dns_connection);
118
119 /* Set up the RecvAddr structure with the IP address of
120 the receiver (in this example case "123.456.789.1")
121 and the specified port number. */
122
123 ZERO_STRUCT(RecvAddr);
124 RecvAddr.sin_family = AF_INET;
125 RecvAddr.sin_port = htons( DNS_UDP_PORT );
126 RecvAddr.sin_addr.s_addr = ulAddress;
127
128 conn->hType = DNS_UDP;
129 memcpy( &conn->RecvAddr, &RecvAddr, sizeof( struct sockaddr_in ) );
130
131 *result = conn;
132 return ERROR_DNS_SUCCESS;
133}
134
135/********************************************************************
136********************************************************************/
137
138DNS_ERROR dns_open_connection( const char *nameserver, int32 dwType,
139 TALLOC_CTX *mem_ctx,
140 struct dns_connection **conn )
141{
142 switch ( dwType ) {
143 case DNS_TCP:
144 return dns_tcp_open( nameserver, mem_ctx, conn );
145 case DNS_UDP:
146 return dns_udp_open( nameserver, mem_ctx, conn );
147 }
148
149 return ERROR_DNS_INVALID_PARAMETER;
150}
151
152static DNS_ERROR write_all(int fd, uint8 *data, size_t len)
153{
154 size_t total = 0;
155
156 while (total < len) {
157
158 ssize_t ret = write(fd, data + total, len - total);
159
160 if (ret <= 0) {
161 /*
162 * EOF or error
163 */
164 return ERROR_DNS_SOCKET_ERROR;
165 }
166
167 total += ret;
168 }
169
170 return ERROR_DNS_SUCCESS;
171}
172
173static DNS_ERROR dns_send_tcp(struct dns_connection *conn,
174 const struct dns_buffer *buf)
175{
176 uint16 len = htons(buf->offset);
177 DNS_ERROR err;
178
179 err = write_all(conn->s, (uint8 *)&len, sizeof(len));
180 if (!ERR_DNS_IS_OK(err)) return err;
181
182 return write_all(conn->s, buf->data, buf->offset);
183}
184
185static DNS_ERROR dns_send_udp(struct dns_connection *conn,
186 const struct dns_buffer *buf)
187{
188 ssize_t ret;
189
190 ret = sendto(conn->s, buf->data, buf->offset, 0,
191 (struct sockaddr *)&conn->RecvAddr,
192 sizeof(conn->RecvAddr));
193
194 if (ret != buf->offset) {
195 return ERROR_DNS_SOCKET_ERROR;
196 }
197
198 return ERROR_DNS_SUCCESS;
199}
200
201DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf)
202{
203 if (conn->hType == DNS_TCP) {
204 return dns_send_tcp(conn, buf);
205 }
206
207 if (conn->hType == DNS_UDP) {
208 return dns_send_udp(conn, buf);
209 }
210
211 return ERROR_DNS_INVALID_PARAMETER;
212}
213
214static DNS_ERROR read_all(int fd, uint8 *data, size_t len)
215{
216 size_t total = 0;
217
218 while (total < len) {
219 struct pollfd pfd;
220 ssize_t ret;
221 int fd_ready;
222
223 ZERO_STRUCT(pfd);
224 pfd.fd = fd;
225 pfd.events = POLLIN|POLLHUP;
226
227 fd_ready = poll(&pfd, 1, 10000);
228 if ( fd_ready == 0 ) {
229 /* read timeout */
230 return ERROR_DNS_SOCKET_ERROR;
231 }
232
233 ret = read(fd, data + total, len - total);
234 if (ret <= 0) {
235 /* EOF or error */
236 return ERROR_DNS_SOCKET_ERROR;
237 }
238
239 total += ret;
240 }
241
242 return ERROR_DNS_SUCCESS;
243}
244
245static DNS_ERROR dns_receive_tcp(TALLOC_CTX *mem_ctx,
246 struct dns_connection *conn,
247 struct dns_buffer **presult)
248{
249 struct dns_buffer *buf;
250 DNS_ERROR err;
251 uint16 len;
252
253 if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
254 return ERROR_DNS_NO_MEMORY;
255 }
256
257 err = read_all(conn->s, (uint8 *)&len, sizeof(len));
258 if (!ERR_DNS_IS_OK(err)) {
259 return err;
260 }
261
262 buf->size = ntohs(len);
263
264 if (buf->size) {
265 if (!(buf->data = TALLOC_ARRAY(buf, uint8, buf->size))) {
266 TALLOC_FREE(buf);
267 return ERROR_DNS_NO_MEMORY;
268 }
269 } else {
270 buf->data = NULL;
271 }
272
273 err = read_all(conn->s, buf->data, buf->size);
274 if (!ERR_DNS_IS_OK(err)) {
275 TALLOC_FREE(buf);
276 return err;
277 }
278
279 *presult = buf;
280 return ERROR_DNS_SUCCESS;
281}
282
283static DNS_ERROR dns_receive_udp(TALLOC_CTX *mem_ctx,
284 struct dns_connection *conn,
285 struct dns_buffer **presult)
286{
287 struct dns_buffer *buf;
288 ssize_t received;
289
290 if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
291 return ERROR_DNS_NO_MEMORY;
292 }
293
294 /*
295 * UDP based DNS can only be 512 bytes
296 */
297
298 if (!(buf->data = TALLOC_ARRAY(buf, uint8, 512))) {
299 TALLOC_FREE(buf);
300 return ERROR_DNS_NO_MEMORY;
301 }
302
303 received = recv(conn->s, (void *)buf->data, 512, 0);
304
305 if (received == -1) {
306 TALLOC_FREE(buf);
307 return ERROR_DNS_SOCKET_ERROR;
308 }
309
310 if (received > 512) {
311 TALLOC_FREE(buf);
312 return ERROR_DNS_BAD_RESPONSE;
313 }
314
315 buf->size = received;
316 buf->offset = 0;
317
318 *presult = buf;
319 return ERROR_DNS_SUCCESS;
320}
321
322DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
323 struct dns_buffer **presult)
324{
325 if (conn->hType == DNS_TCP) {
326 return dns_receive_tcp(mem_ctx, conn, presult);
327 }
328
329 if (conn->hType == DNS_UDP) {
330 return dns_receive_udp(mem_ctx, conn, presult);
331 }
332
333 return ERROR_DNS_INVALID_PARAMETER;
334}
335
336DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
337 const struct dns_request *req,
338 struct dns_request **resp)
339{
340 struct dns_buffer *buf = NULL;
341 DNS_ERROR err;
342
343 err = dns_marshall_request(conn, req, &buf);
344 if (!ERR_DNS_IS_OK(err)) goto error;
345
346 err = dns_send(conn, buf);
347 if (!ERR_DNS_IS_OK(err)) goto error;
348 TALLOC_FREE(buf);
349
350 err = dns_receive(mem_ctx, conn, &buf);
351 if (!ERR_DNS_IS_OK(err)) goto error;
352
353 err = dns_unmarshall_request(mem_ctx, buf, resp);
354
355 error:
356 TALLOC_FREE(buf);
357 return err;
358}
359
360DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
361 struct dns_connection *conn,
362 struct dns_update_request *up_req,
363 struct dns_update_request **up_resp)
364{
365 struct dns_request *resp;
366 DNS_ERROR err;
367
368 err = dns_transaction(mem_ctx, conn, dns_update2request(up_req),
369 &resp);
370
371 if (!ERR_DNS_IS_OK(err)) return err;
372
373 *up_resp = dns_request2update(resp);
374 return ERROR_DNS_SUCCESS;
375}
Note: See TracBrowser for help on using the repository browser.