source: branches/samba-3.3.x/source/libaddns/dnssock.c@ 578

Last change on this file since 578 was 578, checked in by Herwig Bauernfeind, 14 years ago

Update Samba 3.3 to 3.3.15 (security update)

File size: 9.0 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 "dns.h"
26#include <sys/time.h>
27#include <unistd.h>
28
29static int destroy_dns_connection(struct dns_connection *conn)
30{
31 return close(conn->s);
32}
33
34/********************************************************************
35********************************************************************/
36
37static DNS_ERROR dns_tcp_open( const char *nameserver,
38 TALLOC_CTX *mem_ctx,
39 struct dns_connection **result )
40{
41 uint32_t ulAddress;
42 struct hostent *pHost;
43 struct sockaddr_in s_in;
44 struct dns_connection *conn;
45 int res;
46
47 if (!(conn = talloc(mem_ctx, struct dns_connection))) {
48 return ERROR_DNS_NO_MEMORY;
49 }
50
51 if ( (ulAddress = inet_addr( nameserver )) == INADDR_NONE ) {
52 if ( (pHost = gethostbyname( nameserver )) == NULL ) {
53 TALLOC_FREE(conn);
54 return ERROR_DNS_INVALID_NAME_SERVER;
55 }
56 memcpy( &ulAddress, pHost->h_addr, pHost->h_length );
57 }
58
59 conn->s = socket( PF_INET, SOCK_STREAM, 0 );
60 if (conn->s == -1) {
61 TALLOC_FREE(conn);
62 return ERROR_DNS_CONNECTION_FAILED;
63 }
64
65 talloc_set_destructor(conn, destroy_dns_connection);
66
67 s_in.sin_family = AF_INET;
68 s_in.sin_addr.s_addr = ulAddress;
69 s_in.sin_port = htons( DNS_TCP_PORT );
70
71 res = connect(conn->s, (struct sockaddr*)&s_in, sizeof( s_in ));
72 if (res == -1) {
73 TALLOC_FREE(conn);
74 return ERROR_DNS_CONNECTION_FAILED;
75 }
76
77 conn->hType = DNS_TCP;
78
79 *result = conn;
80 return ERROR_DNS_SUCCESS;
81}
82
83/********************************************************************
84********************************************************************/
85
86static DNS_ERROR dns_udp_open( const char *nameserver,
87 TALLOC_CTX *mem_ctx,
88 struct dns_connection **result )
89{
90 unsigned long ulAddress;
91 struct hostent *pHost;
92 struct sockaddr_in RecvAddr;
93 struct dns_connection *conn;
94
95 if (!(conn = talloc(NULL, struct dns_connection))) {
96 return ERROR_DNS_NO_MEMORY;
97 }
98
99 if ( (ulAddress = inet_addr( nameserver )) == INADDR_NONE ) {
100 if ( (pHost = gethostbyname( nameserver )) == NULL ) {
101 TALLOC_FREE(conn);
102 return ERROR_DNS_INVALID_NAME_SERVER;
103 }
104 memcpy( &ulAddress, pHost->h_addr, pHost->h_length );
105 }
106
107 /* Create a socket for sending data */
108
109 conn->s = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
110 if (conn->s == -1) {
111 TALLOC_FREE(conn);
112 return ERROR_DNS_CONNECTION_FAILED;
113 }
114
115 talloc_set_destructor(conn, destroy_dns_connection);
116
117 /* Set up the RecvAddr structure with the IP address of
118 the receiver (in this example case "123.456.789.1")
119 and the specified port number. */
120
121 ZERO_STRUCT(RecvAddr);
122 RecvAddr.sin_family = AF_INET;
123 RecvAddr.sin_port = htons( DNS_UDP_PORT );
124 RecvAddr.sin_addr.s_addr = ulAddress;
125
126 conn->hType = DNS_UDP;
127 memcpy( &conn->RecvAddr, &RecvAddr, sizeof( struct sockaddr_in ) );
128
129 *result = conn;
130 return ERROR_DNS_SUCCESS;
131}
132
133/********************************************************************
134********************************************************************/
135
136DNS_ERROR dns_open_connection( const char *nameserver, int32 dwType,
137 TALLOC_CTX *mem_ctx,
138 struct dns_connection **conn )
139{
140 switch ( dwType ) {
141 case DNS_TCP:
142 return dns_tcp_open( nameserver, mem_ctx, conn );
143 case DNS_UDP:
144 return dns_udp_open( nameserver, mem_ctx, conn );
145 }
146
147 return ERROR_DNS_INVALID_PARAMETER;
148}
149
150static DNS_ERROR write_all(int fd, uint8 *data, size_t len)
151{
152 size_t total = 0;
153
154 while (total < len) {
155
156 ssize_t ret = write(fd, data + total, len - total);
157
158 if (ret <= 0) {
159 /*
160 * EOF or error
161 */
162 return ERROR_DNS_SOCKET_ERROR;
163 }
164
165 total += ret;
166 }
167
168 return ERROR_DNS_SUCCESS;
169}
170
171static DNS_ERROR dns_send_tcp(struct dns_connection *conn,
172 const struct dns_buffer *buf)
173{
174 uint16 len = htons(buf->offset);
175 DNS_ERROR err;
176
177 err = write_all(conn->s, (uint8 *)&len, sizeof(len));
178 if (!ERR_DNS_IS_OK(err)) return err;
179
180 return write_all(conn->s, buf->data, buf->offset);
181}
182
183static DNS_ERROR dns_send_udp(struct dns_connection *conn,
184 const struct dns_buffer *buf)
185{
186 ssize_t ret;
187
188 ret = sendto(conn->s, buf->data, buf->offset, 0,
189 (struct sockaddr *)&conn->RecvAddr,
190 sizeof(conn->RecvAddr));
191
192 if (ret != buf->offset) {
193 return ERROR_DNS_SOCKET_ERROR;
194 }
195
196 return ERROR_DNS_SUCCESS;
197}
198
199DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf)
200{
201 if (conn->hType == DNS_TCP) {
202 return dns_send_tcp(conn, buf);
203 }
204
205 if (conn->hType == DNS_UDP) {
206 return dns_send_udp(conn, buf);
207 }
208
209 return ERROR_DNS_INVALID_PARAMETER;
210}
211
212static DNS_ERROR read_all(int fd, uint8 *data, size_t len)
213{
214 size_t total = 0;
215 fd_set rfds;
216 struct timeval tv;
217
218 while (total < len) {
219 ssize_t ret;
220 int fd_ready;
221
222 if (fd < 0 || fd >= FD_SETSIZE) {
223 return ERROR_DNS_SOCKET_ERROR;
224 }
225
226 FD_ZERO( &rfds );
227 FD_SET( fd, &rfds );
228
229 /* 10 second timeout */
230 tv.tv_sec = 10;
231 tv.tv_usec = 0;
232
233 fd_ready = select( fd+1, &rfds, NULL, NULL, &tv );
234 if ( fd_ready == 0 ) {
235 /* read timeout */
236 return ERROR_DNS_SOCKET_ERROR;
237 }
238
239 ret = read(fd, data + total, len - total);
240 if (ret <= 0) {
241 /* EOF or error */
242 return ERROR_DNS_SOCKET_ERROR;
243 }
244
245 total += ret;
246 }
247
248 return ERROR_DNS_SUCCESS;
249}
250
251static DNS_ERROR dns_receive_tcp(TALLOC_CTX *mem_ctx,
252 struct dns_connection *conn,
253 struct dns_buffer **presult)
254{
255 struct dns_buffer *buf;
256 DNS_ERROR err;
257 uint16 len;
258
259 if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
260 return ERROR_DNS_NO_MEMORY;
261 }
262
263 err = read_all(conn->s, (uint8 *)&len, sizeof(len));
264 if (!ERR_DNS_IS_OK(err)) {
265 return err;
266 }
267
268 buf->size = ntohs(len);
269
270 if (buf->size) {
271 if (!(buf->data = TALLOC_ARRAY(buf, uint8, buf->size))) {
272 TALLOC_FREE(buf);
273 return ERROR_DNS_NO_MEMORY;
274 }
275 } else {
276 buf->data = NULL;
277 }
278
279 err = read_all(conn->s, buf->data, buf->size);
280 if (!ERR_DNS_IS_OK(err)) {
281 TALLOC_FREE(buf);
282 return err;
283 }
284
285 *presult = buf;
286 return ERROR_DNS_SUCCESS;
287}
288
289static DNS_ERROR dns_receive_udp(TALLOC_CTX *mem_ctx,
290 struct dns_connection *conn,
291 struct dns_buffer **presult)
292{
293 struct dns_buffer *buf;
294 ssize_t received;
295
296 if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
297 return ERROR_DNS_NO_MEMORY;
298 }
299
300 /*
301 * UDP based DNS can only be 512 bytes
302 */
303
304 if (!(buf->data = TALLOC_ARRAY(buf, uint8, 512))) {
305 TALLOC_FREE(buf);
306 return ERROR_DNS_NO_MEMORY;
307 }
308
309 received = recv(conn->s, (void *)buf->data, 512, 0);
310
311 if (received == -1) {
312 TALLOC_FREE(buf);
313 return ERROR_DNS_SOCKET_ERROR;
314 }
315
316 if (received > 512) {
317 TALLOC_FREE(buf);
318 return ERROR_DNS_BAD_RESPONSE;
319 }
320
321 buf->size = received;
322 buf->offset = 0;
323
324 *presult = buf;
325 return ERROR_DNS_SUCCESS;
326}
327
328DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
329 struct dns_buffer **presult)
330{
331 if (conn->hType == DNS_TCP) {
332 return dns_receive_tcp(mem_ctx, conn, presult);
333 }
334
335 if (conn->hType == DNS_UDP) {
336 return dns_receive_udp(mem_ctx, conn, presult);
337 }
338
339 return ERROR_DNS_INVALID_PARAMETER;
340}
341
342DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
343 const struct dns_request *req,
344 struct dns_request **resp)
345{
346 struct dns_buffer *buf = NULL;
347 DNS_ERROR err;
348
349 err = dns_marshall_request(conn, req, &buf);
350 if (!ERR_DNS_IS_OK(err)) goto error;
351
352 err = dns_send(conn, buf);
353 if (!ERR_DNS_IS_OK(err)) goto error;
354 TALLOC_FREE(buf);
355
356 err = dns_receive(mem_ctx, conn, &buf);
357 if (!ERR_DNS_IS_OK(err)) goto error;
358
359 err = dns_unmarshall_request(mem_ctx, buf, resp);
360
361 error:
362 TALLOC_FREE(buf);
363 return err;
364}
365
366DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
367 struct dns_connection *conn,
368 struct dns_update_request *up_req,
369 struct dns_update_request **up_resp)
370{
371 struct dns_request *resp;
372 DNS_ERROR err;
373
374 err = dns_transaction(mem_ctx, conn, dns_update2request(up_req),
375 &resp);
376
377 if (!ERR_DNS_IS_OK(err)) return err;
378
379 *up_resp = dns_request2update(resp);
380 return ERROR_DNS_SUCCESS;
381}
Note: See TracBrowser for help on using the repository browser.