source: trunk/samba-3.0.25pre1/source/libaddns/dnssock.c@ 1

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

Initial code import

File size: 8.5 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->data = TALLOC_ARRAY(buf, uint8, buf->size))) {
268 TALLOC_FREE(buf);
269 return ERROR_DNS_NO_MEMORY;
270 }
271
272 err = read_all(conn->s, buf->data, buf->size);
273 if (!ERR_DNS_IS_OK(err)) {
274 TALLOC_FREE(buf);
275 return err;
276 }
277
278 *presult = buf;
279 return ERROR_DNS_SUCCESS;
280}
281
282static DNS_ERROR dns_receive_udp(TALLOC_CTX *mem_ctx,
283 struct dns_connection *conn,
284 struct dns_buffer **presult)
285{
286 struct dns_buffer *buf;
287 ssize_t received;
288
289 if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
290 return ERROR_DNS_NO_MEMORY;
291 }
292
293 /*
294 * UDP based DNS can only be 512 bytes
295 */
296
297 if (!(buf->data = TALLOC_ARRAY(buf, uint8, 512))) {
298 TALLOC_FREE(buf);
299 return ERROR_DNS_NO_MEMORY;
300 }
301
302 received = recv(conn->s, (void *)buf->data, 512, 0);
303
304 if (received == -1) {
305 TALLOC_FREE(buf);
306 return ERROR_DNS_SOCKET_ERROR;
307 }
308
309 if (received > 512) {
310 TALLOC_FREE(buf);
311 return ERROR_DNS_BAD_RESPONSE;
312 }
313
314 buf->size = received;
315 buf->offset = 0;
316
317 *presult = buf;
318 return ERROR_DNS_SUCCESS;
319}
320
321DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
322 struct dns_buffer **presult)
323{
324 if (conn->hType == DNS_TCP) {
325 return dns_receive_tcp(mem_ctx, conn, presult);
326 }
327
328 if (conn->hType == DNS_UDP) {
329 return dns_receive_udp(mem_ctx, conn, presult);
330 }
331
332 return ERROR_DNS_INVALID_PARAMETER;
333}
334
335DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
336 const struct dns_request *req,
337 struct dns_request **resp)
338{
339 struct dns_buffer *buf = NULL;
340 DNS_ERROR err;
341
342 err = dns_marshall_request(conn, req, &buf);
343 if (!ERR_DNS_IS_OK(err)) goto error;
344
345 err = dns_send(conn, buf);
346 if (!ERR_DNS_IS_OK(err)) goto error;
347 TALLOC_FREE(buf);
348
349 err = dns_receive(mem_ctx, conn, &buf);
350 if (!ERR_DNS_IS_OK(err)) goto error;
351
352 err = dns_unmarshall_request(mem_ctx, buf, resp);
353
354 error:
355 TALLOC_FREE(buf);
356 return err;
357}
358
359DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
360 struct dns_connection *conn,
361 struct dns_update_request *up_req,
362 struct dns_update_request **up_resp)
363{
364 struct dns_request *resp;
365 DNS_ERROR err;
366
367 err = dns_transaction(mem_ctx, conn, dns_update2request(up_req),
368 &resp);
369
370 if (!ERR_DNS_IS_OK(err)) return err;
371
372 *up_resp = dns_request2update(resp);
373 return ERROR_DNS_SUCCESS;
374}
Note: See TracBrowser for help on using the repository browser.