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 RecvAddr
.sin_family
= AF_INET
;
122 RecvAddr
.sin_port
= htons( DNS_UDP_PORT
);
123 RecvAddr
.sin_addr
.s_addr
= ulAddress
;
125 conn
->hType
= DNS_UDP
;
126 memcpy( &conn
->RecvAddr
, &RecvAddr
, sizeof( struct sockaddr_in
) );
129 return ERROR_DNS_SUCCESS
;
132 /********************************************************************
133 ********************************************************************/
135 DNS_ERROR
dns_open_connection( const char *nameserver
, int32 dwType
,
137 struct dns_connection
**conn
)
141 return dns_tcp_open( nameserver
, mem_ctx
, conn
);
143 return dns_udp_open( nameserver
, mem_ctx
, conn
);
146 return ERROR_DNS_INVALID_PARAMETER
;
149 static DNS_ERROR
write_all(int fd
, uint8
*data
, size_t len
)
153 while (total
< len
) {
155 ssize_t ret
= write(fd
, data
+ total
, len
- total
);
161 return ERROR_DNS_SOCKET_ERROR
;
167 return ERROR_DNS_SUCCESS
;
170 static DNS_ERROR
dns_send_tcp(struct dns_connection
*conn
,
171 const struct dns_buffer
*buf
)
173 uint16 len
= htons(buf
->offset
);
176 err
= write_all(conn
->s
, (uint8
*)&len
, sizeof(len
));
177 if (!ERR_DNS_IS_OK(err
)) return err
;
179 return write_all(conn
->s
, buf
->data
, buf
->offset
);
182 static DNS_ERROR
dns_send_udp(struct dns_connection
*conn
,
183 const struct dns_buffer
*buf
)
187 ret
= sendto(conn
->s
, buf
->data
, buf
->offset
, 0,
188 (struct sockaddr
*)&conn
->RecvAddr
,
189 sizeof(conn
->RecvAddr
));
191 if (ret
!= buf
->offset
) {
192 return ERROR_DNS_SOCKET_ERROR
;
195 return ERROR_DNS_SUCCESS
;
198 DNS_ERROR
dns_send(struct dns_connection
*conn
, const struct dns_buffer
*buf
)
200 if (conn
->hType
== DNS_TCP
) {
201 return dns_send_tcp(conn
, buf
);
204 if (conn
->hType
== DNS_UDP
) {
205 return dns_send_udp(conn
, buf
);
208 return ERROR_DNS_INVALID_PARAMETER
;
211 static DNS_ERROR
read_all(int fd
, uint8
*data
, size_t len
)
217 while (total
< len
) {
224 /* 10 second timeout */
228 fd_ready
= select( fd
+1, &rfds
, NULL
, NULL
, &tv
);
229 if ( fd_ready
== 0 ) {
231 return ERROR_DNS_SOCKET_ERROR
;
234 ret
= read(fd
, data
+ total
, len
- total
);
237 return ERROR_DNS_SOCKET_ERROR
;
243 return ERROR_DNS_SUCCESS
;
246 static DNS_ERROR
dns_receive_tcp(TALLOC_CTX
*mem_ctx
,
247 struct dns_connection
*conn
,
248 struct dns_buffer
**presult
)
250 struct dns_buffer
*buf
;
254 if (!(buf
= TALLOC_ZERO_P(mem_ctx
, struct dns_buffer
))) {
255 return ERROR_DNS_NO_MEMORY
;
258 err
= read_all(conn
->s
, (uint8
*)&len
, sizeof(len
));
259 if (!ERR_DNS_IS_OK(err
)) {
263 buf
->size
= ntohs(len
);
266 if (!(buf
->data
= TALLOC_ARRAY(buf
, uint8
, buf
->size
))) {
268 return ERROR_DNS_NO_MEMORY
;
274 err
= read_all(conn
->s
, buf
->data
, buf
->size
);
275 if (!ERR_DNS_IS_OK(err
)) {
281 return ERROR_DNS_SUCCESS
;
284 static DNS_ERROR
dns_receive_udp(TALLOC_CTX
*mem_ctx
,
285 struct dns_connection
*conn
,
286 struct dns_buffer
**presult
)
288 struct dns_buffer
*buf
;
291 if (!(buf
= TALLOC_ZERO_P(mem_ctx
, struct dns_buffer
))) {
292 return ERROR_DNS_NO_MEMORY
;
296 * UDP based DNS can only be 512 bytes
299 if (!(buf
->data
= TALLOC_ARRAY(buf
, uint8
, 512))) {
301 return ERROR_DNS_NO_MEMORY
;
304 received
= recv(conn
->s
, (void *)buf
->data
, 512, 0);
306 if (received
== -1) {
308 return ERROR_DNS_SOCKET_ERROR
;
311 if (received
> 512) {
313 return ERROR_DNS_BAD_RESPONSE
;
316 buf
->size
= received
;
320 return ERROR_DNS_SUCCESS
;
323 DNS_ERROR
dns_receive(TALLOC_CTX
*mem_ctx
, struct dns_connection
*conn
,
324 struct dns_buffer
**presult
)
326 if (conn
->hType
== DNS_TCP
) {
327 return dns_receive_tcp(mem_ctx
, conn
, presult
);
330 if (conn
->hType
== DNS_UDP
) {
331 return dns_receive_udp(mem_ctx
, conn
, presult
);
334 return ERROR_DNS_INVALID_PARAMETER
;
337 DNS_ERROR
dns_transaction(TALLOC_CTX
*mem_ctx
, struct dns_connection
*conn
,
338 const struct dns_request
*req
,
339 struct dns_request
**resp
)
341 struct dns_buffer
*buf
= NULL
;
344 err
= dns_marshall_request(conn
, req
, &buf
);
345 if (!ERR_DNS_IS_OK(err
)) goto error
;
347 err
= dns_send(conn
, buf
);
348 if (!ERR_DNS_IS_OK(err
)) goto error
;
351 err
= dns_receive(mem_ctx
, conn
, &buf
);
352 if (!ERR_DNS_IS_OK(err
)) goto error
;
354 err
= dns_unmarshall_request(mem_ctx
, buf
, resp
);
361 DNS_ERROR
dns_update_transaction(TALLOC_CTX
*mem_ctx
,
362 struct dns_connection
*conn
,
363 struct dns_update_request
*up_req
,
364 struct dns_update_request
**up_resp
)
366 struct dns_request
*resp
;
369 err
= dns_transaction(mem_ctx
, conn
, dns_update2request(up_req
),
372 if (!ERR_DNS_IS_OK(err
)) return err
;
374 *up_resp
= dns_request2update(resp
);
375 return ERROR_DNS_SUCCESS
;