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, see <http://www.gnu.org/licenses/>.
29 static int destroy_dns_connection(struct dns_connection
*conn
)
31 return close(conn
->s
);
34 /********************************************************************
35 ********************************************************************/
37 static DNS_ERROR
dns_tcp_open( const char *nameserver
,
39 struct dns_connection
**result
)
42 struct hostent
*pHost
;
43 struct sockaddr_in s_in
;
44 struct dns_connection
*conn
;
47 if (!(conn
= talloc(mem_ctx
, struct dns_connection
))) {
48 return ERROR_DNS_NO_MEMORY
;
51 if ( (ulAddress
= inet_addr( nameserver
)) == INADDR_NONE
) {
52 if ( (pHost
= gethostbyname( nameserver
)) == NULL
) {
54 return ERROR_DNS_INVALID_NAME_SERVER
;
56 memcpy( &ulAddress
, pHost
->h_addr
, pHost
->h_length
);
59 conn
->s
= socket( PF_INET
, SOCK_STREAM
, 0 );
62 return ERROR_DNS_CONNECTION_FAILED
;
65 talloc_set_destructor(conn
, destroy_dns_connection
);
67 s_in
.sin_family
= AF_INET
;
68 s_in
.sin_addr
.s_addr
= ulAddress
;
69 s_in
.sin_port
= htons( DNS_TCP_PORT
);
71 res
= connect(conn
->s
, (struct sockaddr
*)&s_in
, sizeof( s_in
));
74 return ERROR_DNS_CONNECTION_FAILED
;
77 conn
->hType
= DNS_TCP
;
80 return ERROR_DNS_SUCCESS
;
83 /********************************************************************
84 ********************************************************************/
86 static DNS_ERROR
dns_udp_open( const char *nameserver
,
88 struct dns_connection
**result
)
90 unsigned long ulAddress
;
91 struct hostent
*pHost
;
92 struct sockaddr_in RecvAddr
;
93 struct dns_connection
*conn
;
95 if (!(conn
= talloc(NULL
, struct dns_connection
))) {
96 return ERROR_DNS_NO_MEMORY
;
99 if ( (ulAddress
= inet_addr( nameserver
)) == INADDR_NONE
) {
100 if ( (pHost
= gethostbyname( nameserver
)) == NULL
) {
102 return ERROR_DNS_INVALID_NAME_SERVER
;
104 memcpy( &ulAddress
, pHost
->h_addr
, pHost
->h_length
);
107 /* Create a socket for sending data */
109 conn
->s
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
112 return ERROR_DNS_CONNECTION_FAILED
;
115 talloc_set_destructor(conn
, destroy_dns_connection
);
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. */
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
;
126 conn
->hType
= DNS_UDP
;
127 memcpy( &conn
->RecvAddr
, &RecvAddr
, sizeof( struct sockaddr_in
) );
130 return ERROR_DNS_SUCCESS
;
133 /********************************************************************
134 ********************************************************************/
136 DNS_ERROR
dns_open_connection( const char *nameserver
, int32 dwType
,
138 struct dns_connection
**conn
)
142 return dns_tcp_open( nameserver
, mem_ctx
, conn
);
144 return dns_udp_open( nameserver
, mem_ctx
, conn
);
147 return ERROR_DNS_INVALID_PARAMETER
;
150 static DNS_ERROR
write_all(int fd
, uint8
*data
, size_t len
)
154 while (total
< len
) {
156 ssize_t ret
= write(fd
, data
+ total
, len
- total
);
162 return ERROR_DNS_SOCKET_ERROR
;
168 return ERROR_DNS_SUCCESS
;
171 static DNS_ERROR
dns_send_tcp(struct dns_connection
*conn
,
172 const struct dns_buffer
*buf
)
174 uint16 len
= htons(buf
->offset
);
177 err
= write_all(conn
->s
, (uint8
*)&len
, sizeof(len
));
178 if (!ERR_DNS_IS_OK(err
)) return err
;
180 return write_all(conn
->s
, buf
->data
, buf
->offset
);
183 static DNS_ERROR
dns_send_udp(struct dns_connection
*conn
,
184 const struct dns_buffer
*buf
)
188 ret
= sendto(conn
->s
, buf
->data
, buf
->offset
, 0,
189 (struct sockaddr
*)&conn
->RecvAddr
,
190 sizeof(conn
->RecvAddr
));
192 if (ret
!= buf
->offset
) {
193 return ERROR_DNS_SOCKET_ERROR
;
196 return ERROR_DNS_SUCCESS
;
199 DNS_ERROR
dns_send(struct dns_connection
*conn
, const struct dns_buffer
*buf
)
201 if (conn
->hType
== DNS_TCP
) {
202 return dns_send_tcp(conn
, buf
);
205 if (conn
->hType
== DNS_UDP
) {
206 return dns_send_udp(conn
, buf
);
209 return ERROR_DNS_INVALID_PARAMETER
;
212 static DNS_ERROR
read_all(int fd
, uint8
*data
, size_t len
)
218 while (total
< len
) {
222 if (fd
< 0 || fd
>= FD_SETSIZE
) {
224 return ERROR_DNS_SOCKET_ERROR
;
230 /* 10 second timeout */
234 fd_ready
= select( fd
+1, &rfds
, NULL
, NULL
, &tv
);
235 if ( fd_ready
== 0 ) {
237 return ERROR_DNS_SOCKET_ERROR
;
240 ret
= read(fd
, data
+ total
, len
- total
);
243 return ERROR_DNS_SOCKET_ERROR
;
249 return ERROR_DNS_SUCCESS
;
252 static DNS_ERROR
dns_receive_tcp(TALLOC_CTX
*mem_ctx
,
253 struct dns_connection
*conn
,
254 struct dns_buffer
**presult
)
256 struct dns_buffer
*buf
;
260 if (!(buf
= TALLOC_ZERO_P(mem_ctx
, struct dns_buffer
))) {
261 return ERROR_DNS_NO_MEMORY
;
264 err
= read_all(conn
->s
, (uint8
*)&len
, sizeof(len
));
265 if (!ERR_DNS_IS_OK(err
)) {
269 buf
->size
= ntohs(len
);
272 if (!(buf
->data
= TALLOC_ARRAY(buf
, uint8
, buf
->size
))) {
274 return ERROR_DNS_NO_MEMORY
;
280 err
= read_all(conn
->s
, buf
->data
, buf
->size
);
281 if (!ERR_DNS_IS_OK(err
)) {
287 return ERROR_DNS_SUCCESS
;
290 static DNS_ERROR
dns_receive_udp(TALLOC_CTX
*mem_ctx
,
291 struct dns_connection
*conn
,
292 struct dns_buffer
**presult
)
294 struct dns_buffer
*buf
;
297 if (!(buf
= TALLOC_ZERO_P(mem_ctx
, struct dns_buffer
))) {
298 return ERROR_DNS_NO_MEMORY
;
302 * UDP based DNS can only be 512 bytes
305 if (!(buf
->data
= TALLOC_ARRAY(buf
, uint8
, 512))) {
307 return ERROR_DNS_NO_MEMORY
;
310 received
= recv(conn
->s
, (void *)buf
->data
, 512, 0);
312 if (received
== -1) {
314 return ERROR_DNS_SOCKET_ERROR
;
317 if (received
> 512) {
319 return ERROR_DNS_BAD_RESPONSE
;
322 buf
->size
= received
;
326 return ERROR_DNS_SUCCESS
;
329 DNS_ERROR
dns_receive(TALLOC_CTX
*mem_ctx
, struct dns_connection
*conn
,
330 struct dns_buffer
**presult
)
332 if (conn
->hType
== DNS_TCP
) {
333 return dns_receive_tcp(mem_ctx
, conn
, presult
);
336 if (conn
->hType
== DNS_UDP
) {
337 return dns_receive_udp(mem_ctx
, conn
, presult
);
340 return ERROR_DNS_INVALID_PARAMETER
;
343 DNS_ERROR
dns_transaction(TALLOC_CTX
*mem_ctx
, struct dns_connection
*conn
,
344 const struct dns_request
*req
,
345 struct dns_request
**resp
)
347 struct dns_buffer
*buf
= NULL
;
350 err
= dns_marshall_request(conn
, req
, &buf
);
351 if (!ERR_DNS_IS_OK(err
)) goto error
;
353 err
= dns_send(conn
, buf
);
354 if (!ERR_DNS_IS_OK(err
)) goto error
;
357 err
= dns_receive(mem_ctx
, conn
, &buf
);
358 if (!ERR_DNS_IS_OK(err
)) goto error
;
360 err
= dns_unmarshall_request(mem_ctx
, buf
, resp
);
367 DNS_ERROR
dns_update_transaction(TALLOC_CTX
*mem_ctx
,
368 struct dns_connection
*conn
,
369 struct dns_update_request
*up_req
,
370 struct dns_update_request
**up_resp
)
372 struct dns_request
*resp
;
375 err
= dns_transaction(mem_ctx
, conn
, dns_update2request(up_req
),
378 if (!ERR_DNS_IS_OK(err
)) return err
;
380 *up_resp
= dns_request2update(resp
);
381 return ERROR_DNS_SUCCESS
;