~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/libaddns/dnssock.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
29
static int destroy_dns_connection(struct dns_connection *conn)
 
30
{
 
31
        return close(conn->s);
 
32
}
 
33
 
 
34
/********************************************************************
 
35
********************************************************************/
 
36
 
 
37
static 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
 
 
86
static 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
 
 
136
DNS_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
 
 
150
static 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
 
 
171
static 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
 
 
183
static 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
 
 
199
DNS_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
 
 
212
static 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
                FD_ZERO( &rfds );
 
223
                FD_SET( fd, &rfds );
 
224
 
 
225
                /* 10 second timeout */
 
226
                tv.tv_sec = 10;
 
227
                tv.tv_usec = 0;
 
228
                
 
229
                fd_ready = select( fd+1, &rfds, NULL, NULL, &tv );
 
230
                if ( fd_ready == 0 ) {
 
231
                        /* read timeout */
 
232
                        return ERROR_DNS_SOCKET_ERROR;
 
233
                }
 
234
 
 
235
                ret = read(fd, data + total, len - total);
 
236
                if (ret <= 0) {
 
237
                        /* EOF or error */
 
238
                        return ERROR_DNS_SOCKET_ERROR;
 
239
                }
 
240
 
 
241
                total += ret;
 
242
        }
 
243
 
 
244
        return ERROR_DNS_SUCCESS;
 
245
}
 
246
 
 
247
static DNS_ERROR dns_receive_tcp(TALLOC_CTX *mem_ctx,
 
248
                                 struct dns_connection *conn,
 
249
                                 struct dns_buffer **presult)
 
250
{
 
251
        struct dns_buffer *buf;
 
252
        DNS_ERROR err;
 
253
        uint16 len;
 
254
 
 
255
        if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
 
256
                return ERROR_DNS_NO_MEMORY;
 
257
        }
 
258
 
 
259
        err = read_all(conn->s, (uint8 *)&len, sizeof(len));
 
260
        if (!ERR_DNS_IS_OK(err)) {
 
261
                return err;
 
262
        }
 
263
 
 
264
        buf->size = ntohs(len);
 
265
 
 
266
        if (buf->size) {
 
267
                if (!(buf->data = TALLOC_ARRAY(buf, uint8, buf->size))) {
 
268
                        TALLOC_FREE(buf);
 
269
                        return ERROR_DNS_NO_MEMORY;
 
270
                }
 
271
        } else {
 
272
                buf->data = NULL;
 
273
        }
 
274
 
 
275
        err = read_all(conn->s, buf->data, buf->size);
 
276
        if (!ERR_DNS_IS_OK(err)) {
 
277
                TALLOC_FREE(buf);
 
278
                return err;
 
279
        }
 
280
 
 
281
        *presult = buf;
 
282
        return ERROR_DNS_SUCCESS;
 
283
}
 
284
 
 
285
static DNS_ERROR dns_receive_udp(TALLOC_CTX *mem_ctx,
 
286
                                 struct dns_connection *conn,
 
287
                                 struct dns_buffer **presult)
 
288
{
 
289
        struct dns_buffer *buf;
 
290
        ssize_t received;
 
291
 
 
292
        if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
 
293
                return ERROR_DNS_NO_MEMORY;
 
294
        }
 
295
 
 
296
        /*
 
297
         * UDP based DNS can only be 512 bytes
 
298
         */
 
299
 
 
300
        if (!(buf->data = TALLOC_ARRAY(buf, uint8, 512))) {
 
301
                TALLOC_FREE(buf);
 
302
                return ERROR_DNS_NO_MEMORY;
 
303
        }
 
304
 
 
305
        received = recv(conn->s, (void *)buf->data, 512, 0);
 
306
 
 
307
        if (received == -1) {
 
308
                TALLOC_FREE(buf);
 
309
                return ERROR_DNS_SOCKET_ERROR;
 
310
        }
 
311
 
 
312
        if (received > 512) {
 
313
                TALLOC_FREE(buf);
 
314
                return ERROR_DNS_BAD_RESPONSE;
 
315
        }
 
316
 
 
317
        buf->size = received;
 
318
        buf->offset = 0;
 
319
 
 
320
        *presult = buf;
 
321
        return ERROR_DNS_SUCCESS;
 
322
}
 
323
 
 
324
DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
 
325
                      struct dns_buffer **presult)
 
326
{
 
327
        if (conn->hType == DNS_TCP) {
 
328
                return dns_receive_tcp(mem_ctx, conn, presult);
 
329
        }
 
330
 
 
331
        if (conn->hType == DNS_UDP) {
 
332
                return dns_receive_udp(mem_ctx, conn, presult);
 
333
        }
 
334
 
 
335
        return ERROR_DNS_INVALID_PARAMETER;
 
336
}
 
337
 
 
338
DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
 
339
                          const struct dns_request *req,
 
340
                          struct dns_request **resp)
 
341
{
 
342
        struct dns_buffer *buf = NULL;
 
343
        DNS_ERROR err;
 
344
 
 
345
        err = dns_marshall_request(conn, req, &buf);
 
346
        if (!ERR_DNS_IS_OK(err)) goto error;
 
347
 
 
348
        err = dns_send(conn, buf);
 
349
        if (!ERR_DNS_IS_OK(err)) goto error;
 
350
        TALLOC_FREE(buf);
 
351
 
 
352
        err = dns_receive(mem_ctx, conn, &buf);
 
353
        if (!ERR_DNS_IS_OK(err)) goto error;
 
354
 
 
355
        err = dns_unmarshall_request(mem_ctx, buf, resp);
 
356
 
 
357
 error:
 
358
        TALLOC_FREE(buf);
 
359
        return err;
 
360
}
 
361
 
 
362
DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
 
363
                                 struct dns_connection *conn,
 
364
                                 struct dns_update_request *up_req,
 
365
                                 struct dns_update_request **up_resp)
 
366
{
 
367
        struct dns_request *resp;
 
368
        DNS_ERROR err;
 
369
 
 
370
        err = dns_transaction(mem_ctx, conn, dns_update2request(up_req),
 
371
                              &resp);
 
372
 
 
373
        if (!ERR_DNS_IS_OK(err)) return err;
 
374
 
 
375
        *up_resp = dns_request2update(resp);
 
376
        return ERROR_DNS_SUCCESS;
 
377
}