2 Linux DNS client library implementation
4 Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
5 Copyright (C) 2006 Gerald Carter <jerry@samba.org>
7 ** NOTE! The following LGPL license applies to the libaddns
8 ** library. This does NOT imply that all of Samba is released
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.
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.
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
31 static int destroy_dns_connection(struct dns_connection
*conn
)
33 return close(conn
->s
);
36 /********************************************************************
37 ********************************************************************/
39 static DNS_ERROR
dns_tcp_open( const char *nameserver
,
41 struct dns_connection
**result
)
44 struct hostent
*pHost
;
45 struct sockaddr_in s_in
;
46 struct dns_connection
*conn
;
49 if (!(conn
= talloc(mem_ctx
, struct dns_connection
))) {
50 return ERROR_DNS_NO_MEMORY
;
53 if ( (ulAddress
= inet_addr( nameserver
)) == INADDR_NONE
) {
54 if ( (pHost
= gethostbyname( nameserver
)) == NULL
) {
56 return ERROR_DNS_INVALID_NAME_SERVER
;
58 memcpy( &ulAddress
, pHost
->h_addr
, pHost
->h_length
);
61 conn
->s
= socket( PF_INET
, SOCK_STREAM
, 0 );
64 return ERROR_DNS_CONNECTION_FAILED
;
67 talloc_set_destructor(conn
, destroy_dns_connection
);
69 s_in
.sin_family
= AF_INET
;
70 s_in
.sin_addr
.s_addr
= ulAddress
;
71 s_in
.sin_port
= htons( DNS_TCP_PORT
);
73 res
= connect(conn
->s
, (struct sockaddr
*)&s_in
, sizeof( s_in
));
76 return ERROR_DNS_CONNECTION_FAILED
;
79 conn
->hType
= DNS_TCP
;
82 return ERROR_DNS_SUCCESS
;
85 /********************************************************************
86 ********************************************************************/
88 static DNS_ERROR
dns_udp_open( const char *nameserver
,
90 struct dns_connection
**result
)
92 unsigned long ulAddress
;
93 struct hostent
*pHost
;
94 struct sockaddr_in RecvAddr
;
95 struct dns_connection
*conn
;
97 if (!(conn
= talloc(NULL
, struct dns_connection
))) {
98 return ERROR_DNS_NO_MEMORY
;
101 if ( (ulAddress
= inet_addr( nameserver
)) == INADDR_NONE
) {
102 if ( (pHost
= gethostbyname( nameserver
)) == NULL
) {
104 return ERROR_DNS_INVALID_NAME_SERVER
;
106 memcpy( &ulAddress
, pHost
->h_addr
, pHost
->h_length
);
109 /* Create a socket for sending data */
111 conn
->s
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
114 return ERROR_DNS_CONNECTION_FAILED
;
117 talloc_set_destructor(conn
, destroy_dns_connection
);
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. */
123 RecvAddr
.sin_family
= AF_INET
;
124 RecvAddr
.sin_port
= htons( DNS_UDP_PORT
);
125 RecvAddr
.sin_addr
.s_addr
= ulAddress
;
127 conn
->hType
= DNS_UDP
;
128 memcpy( &conn
->RecvAddr
, &RecvAddr
, sizeof( struct sockaddr_in
) );
131 return ERROR_DNS_SUCCESS
;
134 /********************************************************************
135 ********************************************************************/
137 DNS_ERROR
dns_open_connection( const char *nameserver
, int32 dwType
,
139 struct dns_connection
**conn
)
143 return dns_tcp_open( nameserver
, mem_ctx
, conn
);
145 return dns_udp_open( nameserver
, mem_ctx
, conn
);
148 return ERROR_DNS_INVALID_PARAMETER
;
151 static DNS_ERROR
write_all(int fd
, uint8
*data
, size_t len
)
155 while (total
< len
) {
157 ssize_t ret
= write(fd
, data
+ total
, len
- total
);
163 return ERROR_DNS_SOCKET_ERROR
;
169 return ERROR_DNS_SUCCESS
;
172 static DNS_ERROR
dns_send_tcp(struct dns_connection
*conn
,
173 const struct dns_buffer
*buf
)
175 uint16 len
= htons(buf
->offset
);
178 err
= write_all(conn
->s
, (uint8
*)&len
, sizeof(len
));
179 if (!ERR_DNS_IS_OK(err
)) return err
;
181 return write_all(conn
->s
, buf
->data
, buf
->offset
);
184 static DNS_ERROR
dns_send_udp(struct dns_connection
*conn
,
185 const struct dns_buffer
*buf
)
189 ret
= sendto(conn
->s
, buf
->data
, buf
->offset
, 0,
190 (struct sockaddr
*)&conn
->RecvAddr
,
191 sizeof(conn
->RecvAddr
));
193 if (ret
!= buf
->offset
) {
194 return ERROR_DNS_SOCKET_ERROR
;
197 return ERROR_DNS_SUCCESS
;
200 DNS_ERROR
dns_send(struct dns_connection
*conn
, const struct dns_buffer
*buf
)
202 if (conn
->hType
== DNS_TCP
) {
203 return dns_send_tcp(conn
, buf
);
206 if (conn
->hType
== DNS_UDP
) {
207 return dns_send_udp(conn
, buf
);
210 return ERROR_DNS_INVALID_PARAMETER
;
213 static DNS_ERROR
read_all(int fd
, uint8
*data
, size_t len
)
219 while (total
< len
) {
226 /* 10 second timeout */
230 fd_ready
= select( fd
+1, &rfds
, NULL
, NULL
, &tv
);
231 if ( fd_ready
== 0 ) {
233 return ERROR_DNS_SOCKET_ERROR
;
236 ret
= read(fd
, data
+ total
, len
- total
);
239 return ERROR_DNS_SOCKET_ERROR
;
245 return ERROR_DNS_SUCCESS
;
248 static DNS_ERROR
dns_receive_tcp(TALLOC_CTX
*mem_ctx
,
249 struct dns_connection
*conn
,
250 struct dns_buffer
**presult
)
252 struct dns_buffer
*buf
;
256 if (!(buf
= TALLOC_ZERO_P(mem_ctx
, struct dns_buffer
))) {
257 return ERROR_DNS_NO_MEMORY
;
260 err
= read_all(conn
->s
, (uint8
*)&len
, sizeof(len
));
261 if (!ERR_DNS_IS_OK(err
)) {
265 buf
->size
= ntohs(len
);
268 if (!(buf
->data
= TALLOC_ARRAY(buf
, uint8
, buf
->size
))) {
270 return ERROR_DNS_NO_MEMORY
;
276 err
= read_all(conn
->s
, buf
->data
, buf
->size
);
277 if (!ERR_DNS_IS_OK(err
)) {
283 return ERROR_DNS_SUCCESS
;
286 static DNS_ERROR
dns_receive_udp(TALLOC_CTX
*mem_ctx
,
287 struct dns_connection
*conn
,
288 struct dns_buffer
**presult
)
290 struct dns_buffer
*buf
;
293 if (!(buf
= TALLOC_ZERO_P(mem_ctx
, struct dns_buffer
))) {
294 return ERROR_DNS_NO_MEMORY
;
298 * UDP based DNS can only be 512 bytes
301 if (!(buf
->data
= TALLOC_ARRAY(buf
, uint8
, 512))) {
303 return ERROR_DNS_NO_MEMORY
;
306 received
= recv(conn
->s
, (void *)buf
->data
, 512, 0);
308 if (received
== -1) {
310 return ERROR_DNS_SOCKET_ERROR
;
313 if (received
> 512) {
315 return ERROR_DNS_BAD_RESPONSE
;
318 buf
->size
= received
;
322 return ERROR_DNS_SUCCESS
;
325 DNS_ERROR
dns_receive(TALLOC_CTX
*mem_ctx
, struct dns_connection
*conn
,
326 struct dns_buffer
**presult
)
328 if (conn
->hType
== DNS_TCP
) {
329 return dns_receive_tcp(mem_ctx
, conn
, presult
);
332 if (conn
->hType
== DNS_UDP
) {
333 return dns_receive_udp(mem_ctx
, conn
, presult
);
336 return ERROR_DNS_INVALID_PARAMETER
;
339 DNS_ERROR
dns_transaction(TALLOC_CTX
*mem_ctx
, struct dns_connection
*conn
,
340 const struct dns_request
*req
,
341 struct dns_request
**resp
)
343 struct dns_buffer
*buf
= NULL
;
346 err
= dns_marshall_request(conn
, req
, &buf
);
347 if (!ERR_DNS_IS_OK(err
)) goto error
;
349 err
= dns_send(conn
, buf
);
350 if (!ERR_DNS_IS_OK(err
)) goto error
;
353 err
= dns_receive(mem_ctx
, conn
, &buf
);
354 if (!ERR_DNS_IS_OK(err
)) goto error
;
356 err
= dns_unmarshall_request(mem_ctx
, buf
, resp
);
363 DNS_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
)
368 struct dns_request
*resp
;
371 err
= dns_transaction(mem_ctx
, conn
, dns_update2request(up_req
),
374 if (!ERR_DNS_IS_OK(err
)) return err
;
376 *up_resp
= dns_request2update(resp
);
377 return ERROR_DNS_SUCCESS
;