source: branches/samba-3.0/source/libaddns/dnssock.c@ 311

Last change on this file since 311 was 39, checked in by Paul Smedley, 18 years ago

Upgrade source to 3.0.25a

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, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 02110-1301 USA
25*/
26
27#include "dns.h"
28#include <sys/time.h>
29#include <unistd.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 RecvAddr.sin_family = AF_INET;
124 RecvAddr.sin_port = htons( DNS_UDP_PORT );
125 RecvAddr.sin_addr.s_addr = ulAddress;
126
127 conn->hType = DNS_UDP;
128 memcpy( &conn->RecvAddr, &RecvAddr, sizeof( struct sockaddr_in ) );
129
130 *result = conn;
131 return ERROR_DNS_SUCCESS;
132}
133
134/********************************************************************
135********************************************************************/
136
137DNS_ERROR dns_open_connection( const char *nameserver, int32 dwType,
138 TALLOC_CTX *mem_ctx,
139 struct dns_connection **conn )
140{
141 switch ( dwType ) {
142 case DNS_TCP:
143 return dns_tcp_open( nameserver, mem_ctx, conn );
144 case DNS_UDP:
145 return dns_udp_open( nameserver, mem_ctx, conn );
146 }
147
148 return ERROR_DNS_INVALID_PARAMETER;
149}
150
151static DNS_ERROR write_all(int fd, uint8 *data, size_t len)
152{
153 size_t total = 0;
154
155 while (total < len) {
156
157 ssize_t ret = write(fd, data + total, len - total);
158
159 if (ret <= 0) {
160 /*
161 * EOF or error
162 */
163 return ERROR_DNS_SOCKET_ERROR;
164 }
165
166 total += ret;
167 }
168
169 return ERROR_DNS_SUCCESS;
170}
171
172static DNS_ERROR dns_send_tcp(struct dns_connection *conn,
173 const struct dns_buffer *buf)
174{
175 uint16 len = htons(buf->offset);
176 DNS_ERROR err;
177
178 err = write_all(conn->s, (uint8 *)&len, sizeof(len));
179 if (!ERR_DNS_IS_OK(err)) return err;
180
181 return write_all(conn->s, buf->data, buf->offset);
182}
183
184static DNS_ERROR dns_send_udp(struct dns_connection *conn,
185 const struct dns_buffer *buf)
186{
187 ssize_t ret;
188
189 ret = sendto(conn->s, buf->data, buf->offset, 0,
190 (struct sockaddr *)&conn->RecvAddr,
191 sizeof(conn->RecvAddr));
192
193 if (ret != buf->offset) {
194 return ERROR_DNS_SOCKET_ERROR;
195 }
196
197 return ERROR_DNS_SUCCESS;
198}
199
200DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf)
201{
202 if (conn->hType == DNS_TCP) {
203 return dns_send_tcp(conn, buf);
204 }
205
206 if (conn->hType == DNS_UDP) {
207 return dns_send_udp(conn, buf);
208 }
209
210 return ERROR_DNS_INVALID_PARAMETER;
211}
212
213static DNS_ERROR read_all(int fd, uint8 *data, size_t len)
214{
215 size_t total = 0;
216 fd_set rfds;
217 struct timeval tv;
218
219 while (total < len) {
220 ssize_t ret;
221 int fd_ready;
222
223 FD_ZERO( &rfds );
224 FD_SET( fd, &rfds );
225
226 /* 10 second timeout */
227 tv.tv_sec = 10;
228 tv.tv_usec = 0;
229
230 fd_ready = select( fd+1, &rfds, NULL, NULL, &tv );
231 if ( fd_ready == 0 ) {
232 /* read timeout */
233 return ERROR_DNS_SOCKET_ERROR;
234 }
235
236 ret = read(fd, data + total, len - total);
237 if (ret <= 0) {
238 /* EOF or error */
239 return ERROR_DNS_SOCKET_ERROR;
240 }
241
242 total += ret;
243 }
244
245 return ERROR_DNS_SUCCESS;
246}
247
248static DNS_ERROR dns_receive_tcp(TALLOC_CTX *mem_ctx,
249 struct dns_connection *conn,
250 struct dns_buffer **presult)
251{
252 struct dns_buffer *buf;
253 DNS_ERROR err;
254 uint16 len;
255
256 if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
257 return ERROR_DNS_NO_MEMORY;
258 }
259
260 err = read_all(conn->s, (uint8 *)&len, sizeof(len));
261 if (!ERR_DNS_IS_OK(err)) {
262 return err;
263 }
264
265 buf->size = ntohs(len);
266
267 if (buf->size) {
268 if (!(buf->data = TALLOC_ARRAY(buf, uint8, buf->size))) {
269 TALLOC_FREE(buf);
270 return ERROR_DNS_NO_MEMORY;
271 }
272 } else {
273 buf->data = NULL;
274 }
275
276 err = read_all(conn->s, buf->data, buf->size);
277 if (!ERR_DNS_IS_OK(err)) {
278 TALLOC_FREE(buf);
279 return err;
280 }
281
282 *presult = buf;
283 return ERROR_DNS_SUCCESS;
284}
285
286static DNS_ERROR dns_receive_udp(TALLOC_CTX *mem_ctx,
287 struct dns_connection *conn,
288 struct dns_buffer **presult)
289{
290 struct dns_buffer *buf;
291 ssize_t received;
292
293 if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
294 return ERROR_DNS_NO_MEMORY;
295 }
296
297 /*
298 * UDP based DNS can only be 512 bytes
299 */
300
301 if (!(buf->data = TALLOC_ARRAY(buf, uint8, 512))) {
302 TALLOC_FREE(buf);
303 return ERROR_DNS_NO_MEMORY;
304 }
305
306 received = recv(conn->s, (void *)buf->data, 512, 0);
307
308 if (received == -1) {
309 TALLOC_FREE(buf);
310 return ERROR_DNS_SOCKET_ERROR;
311 }
312
313 if (received > 512) {
314 TALLOC_FREE(buf);
315 return ERROR_DNS_BAD_RESPONSE;
316 }
317
318 buf->size = received;
319 buf->offset = 0;
320
321 *presult = buf;
322 return ERROR_DNS_SUCCESS;
323}
324
325DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
326 struct dns_buffer **presult)
327{
328 if (conn->hType == DNS_TCP) {
329 return dns_receive_tcp(mem_ctx, conn, presult);
330 }
331
332 if (conn->hType == DNS_UDP) {
333 return dns_receive_udp(mem_ctx, conn, presult);
334 }
335
336 return ERROR_DNS_INVALID_PARAMETER;
337}
338
339DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
340 const struct dns_request *req,
341 struct dns_request **resp)
342{
343 struct dns_buffer *buf = NULL;
344 DNS_ERROR err;
345
346 err = dns_marshall_request(conn, req, &buf);
347 if (!ERR_DNS_IS_OK(err)) goto error;
348
349 err = dns_send(conn, buf);
350 if (!ERR_DNS_IS_OK(err)) goto error;
351 TALLOC_FREE(buf);
352
353 err = dns_receive(mem_ctx, conn, &buf);
354 if (!ERR_DNS_IS_OK(err)) goto error;
355
356 err = dns_unmarshall_request(mem_ctx, buf, resp);
357
358 error:
359 TALLOC_FREE(buf);
360 return err;
361}
362
363DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
364 struct dns_connection *conn,
365 struct dns_update_request *up_req,
366 struct dns_update_request **up_resp)
367{
368 struct dns_request *resp;
369 DNS_ERROR err;
370
371 err = dns_transaction(mem_ctx, conn, dns_update2request(up_req),
372 &resp);
373
374 if (!ERR_DNS_IS_OK(err)) return err;
375
376 *up_resp = dns_request2update(resp);
377 return ERROR_DNS_SUCCESS;
378}
Note: See TracBrowser for help on using the repository browser.